diff options
Diffstat (limited to 'games/eduke32/files/patch-source__jaudiolib__unixvoc.c')
-rw-r--r-- | games/eduke32/files/patch-source__jaudiolib__unixvoc.c | 2880 |
1 files changed, 2880 insertions, 0 deletions
diff --git a/games/eduke32/files/patch-source__jaudiolib__unixvoc.c b/games/eduke32/files/patch-source__jaudiolib__unixvoc.c new file mode 100644 index 000000000000..eb475a196596 --- /dev/null +++ b/games/eduke32/files/patch-source__jaudiolib__unixvoc.c @@ -0,0 +1,2880 @@ +--- ./source/jaudiolib/unixvoc.c.orig Wed Aug 2 00:35:30 2006 ++++ ./source/jaudiolib/unixvoc.c Wed Aug 2 00:35:30 2006 +@@ -0,0 +1,2877 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++ou should have received a copy of the GNU General Public License ++long with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: MULTIVOC.C ++ ++ author: James R. Dose ++ date: December 20, 1993 ++ ++ Routines to provide multichannel digitized sound playback for ++ Sound Blaster compatible sound cards. ++ ++ (c) Copyright 1993 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++#include <time.h> ++ ++#include "util.h" ++#include "dpmi.h" ++#include "usrhooks.h" ++#include "interrup.h" ++#include "dma.h" ++#include "linklist.h" ++#include "dsl.h" ++ ++#include "pitch.h" ++#include "multivoc.h" ++#include "_multivc.h" ++#include "debugio.h" ++ ++// platform.h is from the build engine, but I need the byteswapping macros... --ryan. ++#include "platform.h" ++ ++#define RoundFixed( fixedval, bits ) \ ++ ( \ ++ ( \ ++ (fixedval) + ( 1 << ( (bits) - 1 ) )\ ++ ) >> (bits) \ ++ ) ++ ++#define IS_QUIET( ptr ) ( ( void * )( ptr ) == ( void * )&MV_VolumeTable[ 0 ] ) ++ ++static int MV_ReverbLevel; ++static int MV_ReverbDelay; ++static VOLUME16 *MV_ReverbTable = NULL; ++ ++//static signed short MV_VolumeTable[ MV_MaxVolume + 1 ][ 256 ]; ++static signed short MV_VolumeTable[ 63 + 1 ][ 256 ]; ++ ++//static Pan MV_PanTable[ MV_NumPanPositions ][ MV_MaxVolume + 1 ]; ++static Pan MV_PanTable[ MV_NumPanPositions ][ 63 + 1 ]; ++ ++static int MV_Installed = FALSE; ++static int MV_SoundCard = 1; ++static int MV_TotalVolume = MV_MaxTotalVolume; ++static int MV_MaxVoices = 1; ++static int MV_Recording; ++ ++static int MV_BufferSize = MixBufferSize; ++static int MV_BufferLength; ++ ++static int MV_NumberOfBuffers = NumberOfBuffers; ++ ++static int MV_MixMode = MONO_8BIT; ++static int MV_Channels = 1; ++static int MV_Bits = 8; ++ ++static int MV_Silence = SILENCE_8BIT; ++static int MV_SwapLeftRight = FALSE; ++ ++static int MV_RequestedMixRate; ++static int MV_MixRate; ++ ++static int MV_DMAChannel = -1; ++static int MV_BuffShift; ++ ++static int MV_TotalMemory; ++ ++static int MV_BufferDescriptor; ++static int MV_BufferEmpty[ NumberOfBuffers ]; ++char *MV_MixBuffer[ NumberOfBuffers + 1 ]; ++ ++static VoiceNode *MV_Voices = NULL; ++ ++static volatile VoiceNode VoiceList; ++static volatile VoiceNode VoicePool; ++ ++/*static*/ int MV_MixPage = 0; ++static int MV_VoiceHandle = MV_MinVoiceHandle; ++ ++static void ( *MV_CallBackFunc )( unsigned long ) = NULL; ++static void ( *MV_RecordFunc )( char *ptr, int length ) = NULL; ++static void ( *MV_MixFunction )( VoiceNode *voice, int buffer ); ++ ++static int MV_MaxVolume = 63; ++ ++char *MV_HarshClipTable; ++char *MV_MixDestination; ++short *MV_LeftVolume; ++short *MV_RightVolume; ++int MV_SampleSize = 1; ++int MV_RightChannelOffset; ++ ++unsigned long MV_MixPosition; ++ ++int MV_ErrorCode = MV_Ok; ++ ++#define MV_SetErrorCode( status ) \ ++ MV_ErrorCode = ( status ); ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_ErrorString ++ ++ Returns a pointer to the error message associated with an error ++ number. A -1 returns a pointer the current error. ++---------------------------------------------------------------------*/ ++ ++char *MV_ErrorString ++ ( ++ int ErrorNumber ++ ) ++ ++ { ++ char *ErrorString; ++ ++ switch( ErrorNumber ) ++ { ++ case MV_Warning : ++ case MV_Error : ++ ErrorString = MV_ErrorString( MV_ErrorCode ); ++ break; ++ ++ case MV_Ok : ++ ErrorString = "Multivoc ok."; ++ break; ++ ++ case MV_UnsupportedCard : ++ ErrorString = "Selected sound card is not supported by Multivoc."; ++ break; ++ ++ case MV_NotInstalled : ++ ErrorString = "Multivoc not installed."; ++ break; ++ ++ case MV_NoVoices : ++ ErrorString = "No free voices available to Multivoc."; ++ break; ++ ++ case MV_NoMem : ++ ErrorString = "Out of memory in Multivoc."; ++ break; ++ ++ case MV_VoiceNotFound : ++ ErrorString = "No voice with matching handle found."; ++ break; ++ ++ case MV_DPMI_Error : ++ ErrorString = "DPMI Error in Multivoc."; ++ break; ++ ++ case MV_InvalidVOCFile : ++ ErrorString = "Invalid VOC file passed in to Multivoc."; ++ break; ++ ++ case MV_InvalidWAVFile : ++ ErrorString = "Invalid WAV file passed in to Multivoc."; ++ break; ++ ++ case MV_InvalidMixMode : ++ ErrorString = "Invalid mix mode request in Multivoc."; ++ break; ++ ++ case MV_IrqFailure : ++ ErrorString = "Playback failed, possibly due to an invalid or conflicting IRQ."; ++ break; ++ ++ case MV_DMAFailure : ++ ErrorString = "Playback failed, possibly due to an invalid or conflicting DMA channel."; ++ break; ++ ++ case MV_DMA16Failure : ++ ErrorString = "Playback failed, possibly due to an invalid or conflicting DMA channel. \n" ++ "Make sure the 16-bit DMA channel is correct."; ++ break; ++ ++ case MV_NullRecordFunction : ++ ErrorString = "Null record function passed to MV_StartRecording."; ++ break; ++ ++ default : ++ ErrorString = "Unknown Multivoc error code."; ++ break; ++ } ++ ++ return( ErrorString ); ++ } ++ ++ ++/********************************************************************** ++ ++ Memory locked functions: ++ ++**********************************************************************/ ++ ++ ++#define MV_LockStart MV_Mix ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_Mix ++ ++ Mixes the sound into the buffer. ++---------------------------------------------------------------------*/ ++ ++static void MV_Mix ++ ( ++ VoiceNode *voice, ++ int buffer ++ ) ++ ++ { ++ char *start; ++ int length; ++ long voclength; ++ unsigned long position; ++ unsigned long rate; ++ unsigned long FixedPointBufferSize; ++ ++ if ( ( voice->length == 0 ) && ++ ( voice->GetSound != NULL ) && ++ ( voice->GetSound( voice ) != KeepPlaying ) ) ++ { ++ return; ++ } ++ ++ length = MixBufferSize; ++ FixedPointBufferSize = voice->FixedPointBufferSize; ++ ++ MV_MixDestination = MV_MixBuffer[ buffer ]; ++ MV_LeftVolume = voice->LeftVolume; ++ MV_RightVolume = voice->RightVolume; ++ ++ if ( ( MV_Channels == 2 ) && ( IS_QUIET( MV_LeftVolume ) ) ) ++ { ++ MV_LeftVolume = MV_RightVolume; ++ MV_MixDestination += MV_RightChannelOffset; ++ } ++ ++ // Add this voice to the mix ++ while( length > 0 ) ++ { ++ start = voice->sound; ++ rate = voice->RateScale; ++ position = voice->position; ++ ++ // Check if the last sample in this buffer would be ++ // beyond the length of the sample block ++ if ( ( position + FixedPointBufferSize ) >= voice->length ) ++ { ++ if ( position < voice->length ) ++ { ++ voclength = ( voice->length - position + rate - 1 ) / rate; ++ } ++ else ++ { ++ voice->GetSound( voice ); ++ return; ++ } ++ } ++ else ++ { ++ voclength = length; ++ } ++ ++ voice->mix( position, rate, start, voclength ); ++ ++ if ( voclength & 1 ) ++ { ++ MV_MixPosition += rate; ++ voclength -= 1; ++ } ++ voice->position = MV_MixPosition; ++ ++ length -= voclength; ++ ++ if ( voice->position >= voice->length ) ++ { ++ // Get the next block of sound ++ if ( voice->GetSound( voice ) != KeepPlaying ) ++ { ++ return; ++ } ++ ++ if ( length > 0 ) ++ { ++ // Get the position of the last sample in the buffer ++ FixedPointBufferSize = voice->RateScale * ( length - 1 ); ++ } ++ } ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_PlayVoice ++ ++ Adds a voice to the play list. ++---------------------------------------------------------------------*/ ++ ++void MV_PlayVoice ++ ( ++ VoiceNode *voice ++ ) ++ ++ { ++ unsigned flags; ++ ++ flags = DisableInterrupts(); ++ LL_SortedInsertion( &VoiceList, voice, prev, next, VoiceNode, priority ); ++ ++ RestoreInterrupts( flags ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_StopVoice ++ ++ Removes the voice from the play list and adds it to the free list. ++---------------------------------------------------------------------*/ ++ ++void MV_StopVoice ++ ( ++ VoiceNode *voice ++ ) ++ ++ { ++ unsigned flags; ++ ++ flags = DisableInterrupts(); ++ ++ // move the voice from the play list to the free list ++ LL_Remove( voice, next, prev ); ++ LL_Add( (VoiceNode *)&VoicePool, voice, next, prev ); ++ ++ RestoreInterrupts( flags ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_ServiceVoc ++ ++ Starts playback of the waiting buffer and mixes the next one. ++---------------------------------------------------------------------*/ ++ ++// static int backcolor = 1; ++ ++static int MV_ServiceVoc(int dummy_arg) ++ { ++ VoiceNode *voice; ++ VoiceNode *next; ++ char *buffer; ++ ++ // Toggle which buffer we'll mix next ++ MV_MixPage++; ++ if ( MV_MixPage >= MV_NumberOfBuffers ) ++ { ++ MV_MixPage -= MV_NumberOfBuffers; ++ } ++ ++ if ( MV_ReverbLevel == 0 ) ++ { ++ // Initialize buffer ++ //Commented out so that the buffer is always cleared. ++ //This is so the guys at Echo Speech can mix into the ++ //buffer even when no sounds are playing. ++ //if ( !MV_BufferEmpty[ MV_MixPage ] ) ++ { ++ ClearBuffer_DW( MV_MixBuffer[ MV_MixPage ], MV_Silence, MV_BufferSize >> 2 ); ++ MV_BufferEmpty[ MV_MixPage ] = TRUE; ++ } ++ } ++ else ++ { ++ char *end; ++ char *source; ++ char *dest; ++ int count; ++ int length; ++ ++ end = MV_MixBuffer[ 0 ] + MV_BufferLength;; ++ dest = MV_MixBuffer[ MV_MixPage ]; ++ source = MV_MixBuffer[ MV_MixPage ] - MV_ReverbDelay; ++ if ( source < MV_MixBuffer[ 0 ] ) ++ { ++ source += MV_BufferLength; ++ } ++ ++ length = MV_BufferSize; ++ while( length > 0 ) ++ { ++ count = length; ++ if ( source + count > end ) ++ { ++ count = end - source; ++ } ++ ++ if ( MV_Bits == 16 ) ++ { ++ if ( MV_ReverbTable != NULL ) ++ MV_16BitReverb( source, dest, (const VOLUME16 *)MV_ReverbTable, count / 2 ); ++ else ++ MV_16BitReverbFast( source, dest, count / 2, MV_ReverbLevel ); ++ } ++ else ++ { ++ if ( MV_ReverbTable != NULL ) ++ MV_8BitReverb( source, dest, (const VOLUME16 *)MV_ReverbTable, count ); ++ else ++ MV_8BitReverbFast( source, dest, count, MV_ReverbLevel ); ++ } ++ ++ // if we go through the loop again, it means that we've wrapped around the buffer ++ source = MV_MixBuffer[ 0 ]; ++ dest += count; ++ length -= count; ++ } ++ } ++ ++ // Play any waiting voices ++ for( voice = VoiceList.next; voice != &VoiceList; voice = next ) ++ { ++// if ( ( voice < &MV_Voices[ 0 ] ) || ( voice > &MV_Voices[ 8 ] ) ) ++// { ++// SetBorderColor(backcolor++); ++// break; ++// } ++ ++ MV_BufferEmpty[ MV_MixPage ] = FALSE; ++ ++ if (MV_MixFunction != NULL) ++ MV_MixFunction( voice, MV_MixPage ); ++ ++ next = voice->next; ++ ++ // Is this voice done? ++ if ( !voice->Playing ) ++ { ++ MV_StopVoice( voice ); ++ ++ if ( MV_CallBackFunc ) ++ { ++ MV_CallBackFunc( voice->callbackval ); ++ } ++ } ++ } ++ } ++ ++ ++int leftpage = -1; ++int rightpage = -1; ++ ++void MV_ServiceGus( char **ptr, unsigned long *length ) ++ { ++ if ( leftpage == MV_MixPage ) ++ { ++ MV_ServiceVoc(0); ++ } ++ ++ leftpage = MV_MixPage; ++ ++ *ptr = MV_MixBuffer[ MV_MixPage ]; ++ *length = MV_BufferSize; ++ } ++ ++void MV_ServiceRightGus( char **ptr, unsigned long *length ) ++ { ++ if ( rightpage == MV_MixPage ) ++ { ++ MV_ServiceVoc(0); ++ } ++ ++ rightpage = MV_MixPage; ++ ++ *ptr = MV_MixBuffer[ MV_MixPage ] + MV_RightChannelOffset; ++ *length = MV_BufferSize; ++ } ++ ++/*--------------------------------------------------------------------- ++ Function: MV_GetNextVOCBlock ++ ++ Interperate the information of a VOC format sound file. ++---------------------------------------------------------------------*/ ++static __inline unsigned int get_le32(void *p0) ++{ ++ //unsigned char *p = p0; ++ //return p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24); ++ unsigned int val = *((unsigned int *) p0); ++ return(BUILDSWAP_INTEL32(val)); ++} ++ ++static __inline unsigned int get_le16(void *p0) ++{ ++ //unsigned char *p = p0; ++ //return p[0] | (p[1]<<8); ++ unsigned short val = *((unsigned short *) p0); ++ return( (unsigned int) (BUILDSWAP_INTEL16(val)) ); ++} ++ ++playbackstatus MV_GetNextVOCBlock ++ ( ++ VoiceNode *voice ++ ) ++ ++ { ++ unsigned char *ptr; ++ int blocktype=0; ++ int lastblocktype=0; ++ unsigned long blocklength=0l; ++ unsigned long samplespeed=0l; ++ unsigned int tc=0; ++ int packtype=0; ++ int voicemode=0; ++ int done=0; ++ unsigned BitsPerSample; ++ unsigned Channels; ++ unsigned Format; ++ ++ if ( voice->BlockLength > 0 ) ++ { ++ voice->position -= voice->length; ++ voice->sound += voice->length >> 16; ++ if ( voice->bits == 16 ) ++ { ++ voice->sound += voice->length >> 16; ++ } ++ voice->length = min( voice->BlockLength, 0x8000 ); ++ voice->BlockLength -= voice->length; ++ voice->length <<= 16; ++ return( KeepPlaying ); ++ } ++ ++ if ( ( voice->length > 0 ) && ( voice->LoopEnd != NULL ) && ++ ( voice->LoopStart != NULL ) ) ++ { ++ voice->BlockLength = voice->LoopSize; ++ voice->sound = voice->LoopStart; ++ voice->position = 0; ++ voice->length = min( voice->BlockLength, 0x8000 ); ++ voice->BlockLength -= voice->length; ++ voice->length <<= 16; ++ return( KeepPlaying ); ++ } ++ ++ ptr = ( unsigned char * )voice->NextBlock; ++ ++ voice->Playing = TRUE; ++ ++ voicemode = 0; ++ lastblocktype = 0; ++ packtype = 0; ++ ++ done = FALSE; ++ while( !done ) ++ { ++ // Stop playing if we get a NULL pointer ++ if ( ptr == NULL ) ++ { ++ voice->Playing = FALSE; ++ done = TRUE; ++ break; ++ } ++ ++ { ++ unsigned tmp = get_le32(ptr); ++ blocktype = tmp&255; ++ blocklength = tmp>>8; ++ } ++ ptr += 4; ++ ++ switch( blocktype ) ++ { ++ case 0 : ++ // End of data ++ if ( ( voice->LoopStart == NULL ) || ++ ( (unsigned char *)voice->LoopStart >= ( ptr - 4 ) ) ) ++ { ++ voice->Playing = FALSE; ++ done = TRUE; ++ } ++ else ++ { ++ voice->BlockLength = ( ptr - 4 ) - (unsigned char *)voice->LoopStart; ++ voice->sound = voice->LoopStart; ++ voice->position = 0; ++ voice->length = min( voice->BlockLength, 0x8000 ); ++ voice->BlockLength -= voice->length; ++ voice->length <<= 16; ++ return( KeepPlaying ); ++ } ++ break; ++ ++ case 1 : ++ // Sound data block ++ voice->bits = 8; ++ if ( lastblocktype != 8 ) ++ { ++ tc = ( unsigned int )*ptr << 8; ++ packtype = *( ptr + 1 ); ++ } ++ ++ ptr += 2; ++ blocklength -= 2; ++ ++ samplespeed = 256000000L / ( 65536 - tc ); ++ ++ // Skip packed or stereo data ++ if ( ( packtype != 0 ) || ( voicemode != 0 ) ) ++ { ++ ptr += blocklength; ++ } ++ else ++ { ++ done = TRUE; ++ } ++ voicemode = 0; ++ break; ++ ++ case 2 : ++ // Sound continuation block ++ samplespeed = voice->SamplingRate; ++ done = TRUE; ++ break; ++ ++ case 3 : ++ // Silence ++ // Not implimented. ++ ptr += blocklength; ++ break; ++ ++ case 4 : ++ // Marker ++ // Not implimented. ++ ptr += blocklength; ++ break; ++ ++ case 5 : ++ // ASCII string ++ // Not implimented. ++ ptr += blocklength; ++ break; ++ ++ case 6 : ++ // Repeat begin ++ if ( voice->LoopEnd == NULL ) ++ { ++ voice->LoopCount = get_le16(ptr); ++ voice->LoopStart = ptr + blocklength; ++ } ++ ptr += blocklength; ++ break; ++ ++ case 7 : ++ // Repeat end ++ ptr += blocklength; ++ if ( lastblocktype == 6 ) ++ { ++ voice->LoopCount = 0; ++ } ++ else ++ { ++ if ( ( voice->LoopCount > 0 ) && ( voice->LoopStart != NULL ) ) ++ { ++ ptr = voice->LoopStart; ++ if ( voice->LoopCount < 0xffff ) ++ { ++ voice->LoopCount--; ++ if ( voice->LoopCount == 0 ) ++ { ++ voice->LoopStart = NULL; ++ } ++ } ++ } ++ } ++ break; ++ ++ case 8 : ++ // Extended block ++ voice->bits = 8; ++ tc = get_le16(ptr); ++ packtype = *( ptr + 2 ); ++ voicemode = *( ptr + 3 ); ++ ptr += blocklength; ++ break; ++ ++ case 9 : ++ // New sound data block ++ samplespeed = get_le32(ptr); ++ BitsPerSample = ptr[4]; ++ Channels = ptr[5]; ++ Format = get_le16(ptr+6); ++ ++ if ( ( BitsPerSample == 8 ) && ( Channels == 1 ) && ++ ( Format == VOC_8BIT ) ) ++ { ++ ptr += 12; ++ blocklength -= 12; ++ voice->bits = 8; ++ done = TRUE; ++ } ++ else if ( ( BitsPerSample == 16 ) && ( Channels == 1 ) && ++ ( Format == VOC_16BIT ) ) ++ { ++ ptr += 12; ++ blocklength -= 12; ++ voice->bits = 16; ++ done = TRUE; ++ } ++ else ++ { ++ ptr += blocklength; ++ } ++ break; ++ ++ default : ++ // Unknown data. Probably not a VOC file. ++ voice->Playing = FALSE; ++ done = TRUE; ++ break; ++ } ++ ++ lastblocktype = blocktype; ++ } ++ ++ if ( voice->Playing ) ++ { ++ voice->NextBlock = ptr + blocklength; ++ voice->sound = ptr; ++ ++ voice->SamplingRate = samplespeed; ++ voice->RateScale = ( voice->SamplingRate * voice->PitchScale ) / MV_MixRate; ++ ++ // Multiply by MixBufferSize - 1 ++ voice->FixedPointBufferSize = ( voice->RateScale * MixBufferSize ) - ++ voice->RateScale; ++ ++ if ( voice->LoopEnd != NULL ) ++ { ++ if ( blocklength > ( unsigned long )voice->LoopEnd ) ++ { ++ blocklength = ( unsigned long )voice->LoopEnd; ++ } ++ else ++ { ++ voice->LoopEnd = ( char * )blocklength; ++ } ++ ++ voice->LoopStart = voice->sound + ( unsigned long )voice->LoopStart; ++ voice->LoopEnd = voice->sound + ( unsigned long )voice->LoopEnd; ++ voice->LoopSize = voice->LoopEnd - voice->LoopStart; ++ } ++ ++ if ( voice->bits == 16 ) ++ { ++ blocklength /= 2; ++ } ++ ++ voice->position = 0; ++ voice->length = min( blocklength, 0x8000 ); ++ voice->BlockLength = blocklength - voice->length; ++ voice->length <<= 16; ++ ++ MV_SetVoiceMixMode( voice ); ++ ++ return( KeepPlaying ); ++ } ++ ++ return( NoMoreData ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_GetNextDemandFeedBlock ++ ++ Controls playback of demand fed data. ++---------------------------------------------------------------------*/ ++ ++playbackstatus MV_GetNextDemandFeedBlock ++ ( ++ VoiceNode *voice ++ ) ++ ++ { ++ if ( voice->BlockLength > 0 ) ++ { ++ voice->position -= voice->length; ++ voice->sound += voice->length >> 16; ++ voice->length = min( voice->BlockLength, 0x8000 ); ++ voice->BlockLength -= voice->length; ++ voice->length <<= 16; ++ ++ return( KeepPlaying ); ++ } ++ ++ if ( voice->DemandFeed == NULL ) ++ { ++ return( NoMoreData ); ++ } ++ ++ voice->position = 0; ++ ( voice->DemandFeed )( &voice->sound, &voice->BlockLength ); ++ voice->length = min( voice->BlockLength, 0x8000 ); ++ voice->BlockLength -= voice->length; ++ voice->length <<= 16; ++ ++ if ( ( voice->length > 0 ) && ( voice->sound != NULL ) ) ++ { ++ return( KeepPlaying ); ++ } ++ return( NoMoreData ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_GetNextRawBlock ++ ++ Controls playback of demand fed data. ++---------------------------------------------------------------------*/ ++ ++playbackstatus MV_GetNextRawBlock ++ ( ++ VoiceNode *voice ++ ) ++ ++ { ++ if ( voice->BlockLength <= 0 ) ++ { ++ if ( voice->LoopStart == NULL ) ++ { ++ voice->Playing = FALSE; ++ return( NoMoreData ); ++ } ++ ++ voice->BlockLength = voice->LoopSize; ++ voice->NextBlock = voice->LoopStart; ++ voice->length = 0; ++ voice->position = 0; ++ } ++ ++ voice->sound = voice->NextBlock; ++ voice->position -= voice->length; ++ voice->length = min( voice->BlockLength, 0x8000 ); ++ voice->NextBlock += voice->length; ++ if ( voice->bits == 16 ) ++ { ++ voice->NextBlock += voice->length; ++ } ++ voice->BlockLength -= voice->length; ++ voice->length <<= 16; ++ ++ return( KeepPlaying ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_GetNextWAVBlock ++ ++ Controls playback of demand fed data. ++---------------------------------------------------------------------*/ ++ ++playbackstatus MV_GetNextWAVBlock ++ ( ++ VoiceNode *voice ++ ) ++ ++ { ++ if ( voice->BlockLength <= 0 ) ++ { ++ if ( voice->LoopStart == NULL ) ++ { ++ voice->Playing = FALSE; ++ return( NoMoreData ); ++ } ++ ++ voice->BlockLength = voice->LoopSize; ++ voice->NextBlock = voice->LoopStart; ++ voice->length = 0; ++ voice->position = 0; ++ } ++ ++ voice->sound = voice->NextBlock; ++ voice->position -= voice->length; ++ voice->length = min( voice->BlockLength, 0x8000 ); ++ voice->NextBlock += voice->length; ++ if ( voice->bits == 16 ) ++ { ++ voice->NextBlock += voice->length; ++ } ++ voice->BlockLength -= voice->length; ++ voice->length <<= 16; ++ ++ return( KeepPlaying ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_ServiceRecord ++ ++ Starts recording of the waiting buffer. ++---------------------------------------------------------------------*/ ++ ++static void MV_ServiceRecord ++ ( ++ void ++ ) ++ ++ { ++ if ( MV_RecordFunc ) ++ { ++ MV_RecordFunc( MV_MixBuffer[ 0 ] + MV_MixPage * MixBufferSize, ++ MixBufferSize ); ++ } ++ ++ // Toggle which buffer we'll mix next ++ MV_MixPage++; ++ if ( MV_MixPage >= NumberOfBuffers ) ++ { ++ MV_MixPage = 0; ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_GetVoice ++ ++ Locates the voice with the specified handle. ++---------------------------------------------------------------------*/ ++ ++VoiceNode *MV_GetVoice ++ ( ++ int handle ++ ) ++ ++ { ++ VoiceNode *voice; ++ unsigned flags; ++ ++ flags = DisableInterrupts(); ++ ++ for( voice = VoiceList.next; voice != &VoiceList; voice = voice->next ) ++ { ++ if ( handle == voice->handle ) ++ { ++ break; ++ } ++ } ++ ++ RestoreInterrupts( flags ); ++ ++ if ( voice == &VoiceList ) ++ { ++ MV_SetErrorCode( MV_VoiceNotFound ); ++ ++ // SBF - should this return null? ++ return NULL; ++ } ++ ++ return( voice ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_VoicePlaying ++ ++ Checks if the voice associated with the specified handle is ++ playing. ++---------------------------------------------------------------------*/ ++ ++int MV_VoicePlaying ++ ( ++ int handle ++ ) ++ ++ { ++ VoiceNode *voice; ++ ++ if ( !MV_Installed ) ++ { ++ MV_SetErrorCode( MV_NotInstalled ); ++ return( FALSE ); ++ } ++ ++ voice = MV_GetVoice( handle ); ++ ++ if ( voice == NULL ) ++ { ++ return( FALSE ); ++ } ++ ++ return( TRUE ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_KillAllVoices ++ ++ Stops output of all currently active voices. ++---------------------------------------------------------------------*/ ++ ++int MV_KillAllVoices ++ ( ++ void ++ ) ++ ++ { ++ if ( !MV_Installed ) ++ { ++ MV_SetErrorCode( MV_NotInstalled ); ++ return( MV_Error ); ++ } ++ ++ // Remove all the voices from the list ++ while( VoiceList.next != &VoiceList ) ++ { ++ MV_Kill( VoiceList.next->handle ); ++ } ++ ++ return( MV_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_Kill ++ ++ Stops output of the voice associated with the specified handle. ++---------------------------------------------------------------------*/ ++ ++int MV_Kill ++ ( ++ int handle ++ ) ++ ++ { ++ VoiceNode *voice; ++ unsigned flags; ++ unsigned long callbackval; ++ ++ if ( !MV_Installed ) ++ { ++ MV_SetErrorCode( MV_NotInstalled ); ++ return( MV_Error ); ++ } ++ ++ flags = DisableInterrupts(); ++ ++ voice = MV_GetVoice( handle ); ++ if ( voice == NULL ) ++ { ++ RestoreInterrupts( flags ); ++ MV_SetErrorCode( MV_VoiceNotFound ); ++ return( MV_Error ); ++ } ++ ++ callbackval = voice->callbackval; ++ ++ MV_StopVoice( voice ); ++ ++ RestoreInterrupts( flags ); ++ ++ if ( MV_CallBackFunc ) ++ { ++ MV_CallBackFunc( callbackval ); ++ } ++ ++ return( MV_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_VoicesPlaying ++ ++ Determines the number of currently active voices. ++---------------------------------------------------------------------*/ ++ ++int MV_VoicesPlaying ++ ( ++ void ++ ) ++ ++ { ++ VoiceNode *voice; ++ int NumVoices = 0; ++ unsigned flags; ++ ++ if ( !MV_Installed ) ++ { ++ MV_SetErrorCode( MV_NotInstalled ); ++ return( 0 ); ++ } ++ ++ flags = DisableInterrupts(); ++ ++ for( voice = VoiceList.next; voice != &VoiceList; voice = voice->next ) ++ { ++ NumVoices++; ++ } ++ ++ RestoreInterrupts( flags ); ++ ++ return( NumVoices ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_AllocVoice ++ ++ Retrieve an inactive or lower priority voice for output. ++---------------------------------------------------------------------*/ ++ ++VoiceNode *MV_AllocVoice ++ ( ++ int priority ++ ) ++ ++ { ++ VoiceNode *voice; ++ VoiceNode *node; ++ unsigned flags; ++ ++//return( NULL ); ++ if ( MV_Recording ) ++ { ++ return( NULL ); ++ } ++ ++ flags = DisableInterrupts(); ++ ++ // Check if we have any free voices ++ if ( LL_Empty( &VoicePool, next, prev ) ) ++ { ++ // check if we have a higher priority than a voice that is playing. ++ voice = VoiceList.next; ++ for( node = voice->next; node != &VoiceList; node = node->next ) ++ { ++ if ( node->priority < voice->priority ) ++ { ++ voice = node; ++ } ++ } ++ ++ if ( priority >= voice->priority ) ++ { ++ MV_Kill( voice->handle ); ++ } ++ } ++ ++ // Check if any voices are in the voice pool ++ if ( LL_Empty( &VoicePool, next, prev ) ) ++ { ++ // No free voices ++ RestoreInterrupts( flags ); ++ return( NULL ); ++ } ++ ++ voice = VoicePool.next; ++ LL_Remove( voice, next, prev ); ++ RestoreInterrupts( flags ); ++ ++ // Find a free voice handle ++ do ++ { ++ MV_VoiceHandle++; ++ if ( MV_VoiceHandle < MV_MinVoiceHandle ) ++ { ++ MV_VoiceHandle = MV_MinVoiceHandle; ++ } ++ } ++ while( MV_VoicePlaying( MV_VoiceHandle ) ); ++ ++ voice->handle = MV_VoiceHandle; ++ ++ return( voice ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_VoiceAvailable ++ ++ Checks if a voice can be play at the specified priority. ++---------------------------------------------------------------------*/ ++ ++int MV_VoiceAvailable ++ ( ++ int priority ++ ) ++ ++ { ++ VoiceNode *voice; ++ VoiceNode *node; ++ unsigned flags; ++ ++ // Check if we have any free voices ++ if ( !LL_Empty( &VoicePool, next, prev ) ) ++ { ++ return( TRUE ); ++ } ++ ++ flags = DisableInterrupts(); ++ ++ // check if we have a higher priority than a voice that is playing. ++ voice = VoiceList.next; ++ for( node = VoiceList.next; node != &VoiceList; node = node->next ) ++ { ++ if ( node->priority < voice->priority ) ++ { ++ voice = node; ++ } ++ } ++ ++ RestoreInterrupts( flags ); ++ ++ if ( ( voice != &VoiceList ) && ( priority >= voice->priority ) ) ++ { ++ return( TRUE ); ++ } ++ ++ return( FALSE ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_SetVoicePitch ++ ++ Sets the pitch for the specified voice. ++---------------------------------------------------------------------*/ ++ ++void MV_SetVoicePitch ++ ( ++ VoiceNode *voice, ++ unsigned long rate, ++ int pitchoffset ++ ) ++ ++ { ++ voice->SamplingRate = rate; ++ voice->PitchScale = PITCH_GetScale( pitchoffset ); ++ voice->RateScale = ( rate * voice->PitchScale ) / MV_MixRate; ++ ++ // Multiply by MixBufferSize - 1 ++ voice->FixedPointBufferSize = ( voice->RateScale * MixBufferSize ) - ++ voice->RateScale; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_SetPitch ++ ++ Sets the pitch for the voice associated with the specified handle. ++---------------------------------------------------------------------*/ ++ ++int MV_SetPitch ++ ( ++ int handle, ++ int pitchoffset ++ ) ++ ++ { ++ VoiceNode *voice; ++ ++ if ( !MV_Installed ) ++ { ++ MV_SetErrorCode( MV_NotInstalled ); ++ return( MV_Error ); ++ } ++ ++ voice = MV_GetVoice( handle ); ++ if ( voice == NULL ) ++ { ++ MV_SetErrorCode( MV_VoiceNotFound ); ++ return( MV_Error ); ++ } ++ ++ MV_SetVoicePitch( voice, voice->SamplingRate, pitchoffset ); ++ ++ return( MV_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_SetFrequency ++ ++ Sets the frequency for the voice associated with the specified handle. ++---------------------------------------------------------------------*/ ++ ++int MV_SetFrequency ++ ( ++ int handle, ++ int frequency ++ ) ++ ++ { ++ VoiceNode *voice; ++ ++ if ( !MV_Installed ) ++ { ++ MV_SetErrorCode( MV_NotInstalled ); ++ return( MV_Error ); ++ } ++ ++ voice = MV_GetVoice( handle ); ++ if ( voice == NULL ) ++ { ++ MV_SetErrorCode( MV_VoiceNotFound ); ++ return( MV_Error ); ++ } ++ ++ MV_SetVoicePitch( voice, frequency, 0 ); ++ ++ return( MV_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_GetVolumeTable ++ ++ Returns a pointer to the volume table associated with the specified ++ volume. ++---------------------------------------------------------------------*/ ++ ++static short *MV_GetVolumeTable ++ ( ++ int vol ++ ) ++ ++ { ++ int volume; ++ short *table; ++ ++ volume = MIX_VOLUME( vol ); ++ ++ table = (short *)&MV_VolumeTable[ volume ]; ++ ++ return( table ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_SetVoiceMixMode ++ ++ Selects which method should be used to mix the voice. ++---------------------------------------------------------------------*/ ++ ++static void MV_SetVoiceMixMode ++ ( ++ VoiceNode *voice ++ ) ++ ++ { ++ unsigned flags; ++ int test; ++ ++ flags = DisableInterrupts(); ++ ++ test = T_DEFAULT; ++ if ( MV_Bits == 8 ) ++ { ++ test |= T_8BITS; ++ } ++ ++ if ( voice->bits == 16 ) ++ { ++ test |= T_16BITSOURCE; ++ } ++ ++ if ( MV_Channels == 1 ) ++ { ++ test |= T_MONO; ++ } ++ else ++ { ++ if ( IS_QUIET( voice->RightVolume ) ) ++ { ++ test |= T_RIGHTQUIET; ++ } ++ else if ( IS_QUIET( voice->LeftVolume ) ) ++ { ++ test |= T_LEFTQUIET; ++ } ++ } ++ ++ // Default case ++ voice->mix = MV_Mix8BitMono; ++ ++ switch( test ) ++ { ++ case T_8BITS | T_MONO | T_16BITSOURCE : ++ voice->mix = MV_Mix8BitMono16; ++ break; ++ ++ case T_8BITS | T_MONO : ++ voice->mix = MV_Mix8BitMono; ++ break; ++ ++ case T_8BITS | T_16BITSOURCE | T_LEFTQUIET : ++ MV_LeftVolume = MV_RightVolume; ++ voice->mix = MV_Mix8BitMono16; ++ break; ++ ++ case T_8BITS | T_LEFTQUIET : ++ MV_LeftVolume = MV_RightVolume; ++ voice->mix = MV_Mix8BitMono; ++ break; ++ ++ case T_8BITS | T_16BITSOURCE | T_RIGHTQUIET : ++ voice->mix = MV_Mix8BitMono16; ++ break; ++ ++ case T_8BITS | T_RIGHTQUIET : ++ voice->mix = MV_Mix8BitMono; ++ break; ++ ++ case T_8BITS | T_16BITSOURCE : ++ voice->mix = MV_Mix8BitStereo16; ++ break; ++ ++ case T_8BITS : ++ voice->mix = MV_Mix8BitStereo; ++ break; ++ ++ case T_MONO | T_16BITSOURCE : ++ voice->mix = MV_Mix16BitMono16; ++ break; ++ ++ case T_MONO : ++ voice->mix = MV_Mix16BitMono; ++ break; ++ ++ case T_16BITSOURCE | T_LEFTQUIET : ++ MV_LeftVolume = MV_RightVolume; ++ voice->mix = MV_Mix16BitMono16; ++ break; ++ ++ case T_LEFTQUIET : ++ MV_LeftVolume = MV_RightVolume; ++ voice->mix = MV_Mix16BitMono; ++ break; ++ ++ case T_16BITSOURCE | T_RIGHTQUIET : ++ voice->mix = MV_Mix16BitMono16; ++ break; ++ ++ case T_RIGHTQUIET : ++ voice->mix = MV_Mix16BitMono; ++ break; ++ ++ case T_16BITSOURCE : ++ voice->mix = MV_Mix16BitStereo16; ++ break; ++ ++ case T_SIXTEENBIT_STEREO : ++ voice->mix = MV_Mix16BitStereo; ++ break; ++ ++ default : ++ voice->mix = MV_Mix8BitMono; ++ } ++ ++ RestoreInterrupts( flags ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_SetVoiceVolume ++ ++ Sets the stereo and mono volume level of the voice associated ++ with the specified handle. ++---------------------------------------------------------------------*/ ++ ++void MV_SetVoiceVolume ++ ( ++ VoiceNode *voice, ++ int vol, ++ int left, ++ int right ++ ) ++ ++ { ++ if ( MV_Channels == 1 ) ++ { ++ left = vol; ++ right = vol; ++ } ++ ++ if ( MV_SwapLeftRight ) ++ { ++ // SBPro uses reversed panning ++ voice->LeftVolume = MV_GetVolumeTable( right ); ++ voice->RightVolume = MV_GetVolumeTable( left ); ++ } ++ else ++ { ++ voice->LeftVolume = MV_GetVolumeTable( left ); ++ voice->RightVolume = MV_GetVolumeTable( right ); ++ } ++ ++ MV_SetVoiceMixMode( voice ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_EndLooping ++ ++ Stops the voice associated with the specified handle from looping ++ without stoping the sound. ++---------------------------------------------------------------------*/ ++ ++int MV_EndLooping ++ ( ++ int handle ++ ) ++ ++ { ++ VoiceNode *voice; ++ unsigned flags; ++ ++ if ( !MV_Installed ) ++ { ++ MV_SetErrorCode( MV_NotInstalled ); ++ return( MV_Error ); ++ } ++ ++ flags = DisableInterrupts(); ++ ++ voice = MV_GetVoice( handle ); ++ if ( voice == NULL ) ++ { ++ RestoreInterrupts( flags ); ++ MV_SetErrorCode( MV_VoiceNotFound ); ++ return( MV_Warning ); ++ } ++ ++ voice->LoopCount = 0; ++ voice->LoopStart = NULL; ++ voice->LoopEnd = NULL; ++ ++ RestoreInterrupts( flags ); ++ ++ return( MV_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_SetPan ++ ++ Sets the stereo and mono volume level of the voice associated ++ with the specified handle. ++---------------------------------------------------------------------*/ ++ ++int MV_SetPan ++ ( ++ int handle, ++ int vol, ++ int left, ++ int right ++ ) ++ ++ { ++ VoiceNode *voice; ++ ++ if ( !MV_Installed ) ++ { ++ MV_SetErrorCode( MV_NotInstalled ); ++ return( MV_Error ); ++ } ++ ++ voice = MV_GetVoice( handle ); ++ if ( voice == NULL ) ++ { ++ MV_SetErrorCode( MV_VoiceNotFound ); ++ return( MV_Warning ); ++ } ++ ++ MV_SetVoiceVolume( voice, vol, left, right ); ++ ++ return( MV_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_Pan3D ++ ++ Set the angle and distance from the listener of the voice associated ++ with the specified handle. ++---------------------------------------------------------------------*/ ++ ++int MV_Pan3D ++ ( ++ int handle, ++ int angle, ++ int distance ++ ) ++ ++ { ++ int left; ++ int right; ++ int mid; ++ int volume; ++ int status; ++ ++ if ( distance < 0 ) ++ { ++ distance = -distance; ++ angle += MV_NumPanPositions / 2; ++ } ++ ++ volume = MIX_VOLUME( distance ); ++ ++ // Ensure angle is within 0 - 31 ++ angle &= MV_MaxPanPosition; ++ ++ left = MV_PanTable[ angle ][ volume ].left; ++ right = MV_PanTable[ angle ][ volume ].right; ++ mid = max( 0, 255 - distance ); ++ ++ status = MV_SetPan( handle, mid, left, right ); ++ ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_SetReverb ++ ++ Sets the level of reverb to add to mix. ++---------------------------------------------------------------------*/ ++ ++void MV_SetReverb ++ ( ++ int reverb ++ ) ++ ++ { ++ MV_ReverbLevel = MIX_VOLUME( reverb ); ++ MV_ReverbTable = &MV_VolumeTable[ MV_ReverbLevel ]; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_SetFastReverb ++ ++ Sets the level of reverb to add to mix. ++---------------------------------------------------------------------*/ ++ ++void MV_SetFastReverb ++ ( ++ int reverb ++ ) ++ ++ { ++ MV_ReverbLevel = max( 0, min( 16, reverb ) ); ++ MV_ReverbTable = NULL; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_GetMaxReverbDelay ++ ++ Returns the maximum delay time for reverb. ++---------------------------------------------------------------------*/ ++ ++int MV_GetMaxReverbDelay ++ ( ++ void ++ ) ++ ++ { ++ int maxdelay; ++ ++ maxdelay = MixBufferSize * MV_NumberOfBuffers; ++ ++ return maxdelay; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_GetReverbDelay ++ ++ Returns the current delay time for reverb. ++---------------------------------------------------------------------*/ ++ ++int MV_GetReverbDelay ++ ( ++ void ++ ) ++ ++ { ++ return MV_ReverbDelay / MV_SampleSize; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_SetReverbDelay ++ ++ Sets the delay level of reverb to add to mix. ++---------------------------------------------------------------------*/ ++ ++void MV_SetReverbDelay ++ ( ++ int delay ++ ) ++ ++ { ++ int maxdelay; ++ ++ maxdelay = MV_GetMaxReverbDelay(); ++ MV_ReverbDelay = max( MixBufferSize, min( delay, maxdelay ) ); ++ MV_ReverbDelay *= MV_SampleSize; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_SetMixMode ++ ++ Prepares Multivoc to play stereo of mono digitized sounds. ++---------------------------------------------------------------------*/ ++ ++int MV_SetMixMode ++ ( ++ int numchannels, ++ int samplebits ++ ) ++ ++ { ++ int mode; ++ ++ if ( !MV_Installed ) ++ { ++ MV_SetErrorCode( MV_NotInstalled ); ++ return( MV_Error ); ++ } ++ ++ mode = 0; ++ if ( numchannels == 2 ) ++ { ++ mode |= STEREO; ++ } ++ if ( samplebits == 16 ) ++ { ++ mode |= SIXTEEN_BIT; ++ } ++ ++ MV_MixMode = mode; ++ ++ MV_Channels = 1; ++ if ( MV_MixMode & STEREO ) ++ { ++ MV_Channels = 2; ++ } ++ ++ MV_Bits = 8; ++ if ( MV_MixMode & SIXTEEN_BIT ) ++ { ++ MV_Bits = 16; ++ } ++ ++ MV_BuffShift = 7 + MV_Channels; ++ MV_SampleSize = sizeof( MONO8 ) * MV_Channels; ++ ++ if ( MV_Bits == 8 ) ++ { ++ MV_Silence = SILENCE_8BIT; ++ } ++ else ++ { ++ MV_Silence = SILENCE_16BIT; ++ MV_BuffShift += 1; ++ MV_SampleSize *= 2; ++ } ++ ++ MV_BufferSize = MixBufferSize * MV_SampleSize; ++ MV_NumberOfBuffers = TotalBufferSize / MV_BufferSize; ++ MV_BufferLength = TotalBufferSize; ++ ++ MV_RightChannelOffset = MV_SampleSize / 2; ++ ++ return( MV_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_StartPlayback ++ ++ Starts the sound playback engine. ++---------------------------------------------------------------------*/ ++ ++int MV_StartPlayback ++ ( ++ void ++ ) ++ ++ { ++ int status; ++ int buffer; ++ ++ // Initialize the buffers ++ ClearBuffer_DW( MV_MixBuffer[ 0 ], MV_Silence, TotalBufferSize >> 2 ); ++ for( buffer = 0; buffer < MV_NumberOfBuffers; buffer++ ) ++ { ++ MV_BufferEmpty[ buffer ] = TRUE; ++ } ++ ++ // Set the mix buffer variables ++ MV_MixPage = 1; ++ ++ MV_MixFunction = MV_Mix; ++ ++ status = DSL_BeginBufferedPlayback( MV_MixBuffer[ 0 ], ++ TotalBufferSize, MV_NumberOfBuffers, ++ MV_RequestedMixRate, MV_MixMode, MV_ServiceVoc ); ++ ++ if ( status != DSL_Ok ) ++ { ++ MV_SetErrorCode( MV_BlasterError ); ++ return( MV_Error ); ++ } ++ ++ MV_MixRate = DSL_GetPlaybackRate(); ++ ++ return( MV_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_StopPlayback ++ ++ Stops the sound playback engine. ++---------------------------------------------------------------------*/ ++ ++void MV_StopPlayback ++ ( ++ void ++ ) ++ ++ { ++ VoiceNode *voice; ++ VoiceNode *next; ++ unsigned flags; ++ ++ DSL_StopPlayback(); ++ ++ // Make sure all callbacks are done. ++ flags = DisableInterrupts(); ++ ++ for( voice = VoiceList.next; voice != &VoiceList; voice = next ) ++ { ++ next = voice->next; ++ ++ MV_StopVoice( voice ); ++ ++ if ( MV_CallBackFunc ) ++ { ++ MV_CallBackFunc( voice->callbackval ); ++ } ++ } ++ ++ RestoreInterrupts( flags ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_StartRecording ++ ++ Starts the sound recording engine. ++---------------------------------------------------------------------*/ ++ ++int MV_StartRecording ++ ( ++ int MixRate, ++ void ( *function )( char *ptr, int length ) ++ ) ++ ++ { ++ MV_SetErrorCode( MV_UnsupportedCard ); ++ return( MV_Error ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_StopRecord ++ ++ Stops the sound record engine. ++---------------------------------------------------------------------*/ ++ ++void MV_StopRecord ++ ( ++ void ++ ) ++ ++ { ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_StartDemandFeedPlayback ++ ++ Plays a digitized sound from a user controlled buffering system. ++---------------------------------------------------------------------*/ ++ ++int MV_StartDemandFeedPlayback ++ ( ++ void ( *function )( char **ptr, unsigned long *length ), ++ int rate, ++ int pitchoffset, ++ int vol, ++ int left, ++ int right, ++ int priority, ++ unsigned long callbackval ++ ) ++ ++ { ++ VoiceNode *voice; ++ ++ if ( !MV_Installed ) ++ { ++ MV_SetErrorCode( MV_NotInstalled ); ++ return( MV_Error ); ++ } ++ ++ // Request a voice from the voice pool ++ voice = MV_AllocVoice( priority ); ++ if ( voice == NULL ) ++ { ++ MV_SetErrorCode( MV_NoVoices ); ++ return( MV_Error ); ++ } ++ ++ voice->wavetype = DemandFeed; ++ voice->bits = 8; ++ voice->GetSound = MV_GetNextDemandFeedBlock; ++ voice->NextBlock = NULL; ++ voice->DemandFeed = function; ++ voice->LoopStart = NULL; ++ voice->LoopCount = 0; ++ voice->BlockLength = 0; ++ voice->position = 0; ++ voice->sound = NULL; ++ voice->length = 0; ++ voice->BlockLength = 0; ++ voice->Playing = TRUE; ++ voice->next = NULL; ++ voice->prev = NULL; ++ voice->priority = priority; ++ voice->callbackval = callbackval; ++ ++ MV_SetVoicePitch( voice, rate, pitchoffset ); ++ MV_SetVoiceVolume( voice, vol, left, right ); ++ MV_PlayVoice( voice ); ++ ++ return( voice->handle ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_PlayRaw ++ ++ Begin playback of sound data with the given sound levels and ++ priority. ++---------------------------------------------------------------------*/ ++ ++int MV_PlayRaw ++ ( ++ char *ptr, ++ unsigned long length, ++ unsigned rate, ++ int pitchoffset, ++ int vol, ++ int left, ++ int right, ++ int priority, ++ unsigned long callbackval ++ ) ++ ++ { ++ int status; ++ ++ status = MV_PlayLoopedRaw( ptr, length, NULL, NULL, rate, pitchoffset, ++ vol, left, right, priority, callbackval ); ++ ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_PlayLoopedRaw ++ ++ Begin playback of sound data with the given sound levels and ++ priority. ++---------------------------------------------------------------------*/ ++ ++int MV_PlayLoopedRaw ++ ( ++ char *ptr, ++ long length, ++ char *loopstart, ++ char *loopend, ++ unsigned rate, ++ int pitchoffset, ++ int vol, ++ int left, ++ int right, ++ int priority, ++ unsigned long callbackval ++ ) ++ ++ { ++ VoiceNode *voice; ++ ++ if ( !MV_Installed ) ++ { ++ MV_SetErrorCode( MV_NotInstalled ); ++ return( MV_Error ); ++ } ++ ++ // Request a voice from the voice pool ++ voice = MV_AllocVoice( priority ); ++ if ( voice == NULL ) ++ { ++ MV_SetErrorCode( MV_NoVoices ); ++ return( MV_Error ); ++ } ++ ++ voice->wavetype = Raw; ++ voice->bits = 8; ++ voice->GetSound = MV_GetNextRawBlock; ++ voice->Playing = TRUE; ++ voice->NextBlock = ptr; ++ voice->position = 0; ++ voice->BlockLength = length; ++ voice->length = 0; ++ voice->next = NULL; ++ voice->prev = NULL; ++ voice->priority = priority; ++ voice->callbackval = callbackval; ++ voice->LoopStart = loopstart; ++ voice->LoopEnd = loopend; ++ voice->LoopSize = ( voice->LoopEnd - voice->LoopStart ) + 1; ++ ++ MV_SetVoicePitch( voice, rate, pitchoffset ); ++ MV_SetVoiceVolume( voice, vol, left, right ); ++ MV_PlayVoice( voice ); ++ ++ return( voice->handle ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_PlayWAV ++ ++ Begin playback of sound data with the given sound levels and ++ priority. ++---------------------------------------------------------------------*/ ++ ++int MV_PlayWAV ++ ( ++ char *ptr, ++ int pitchoffset, ++ int vol, ++ int left, ++ int right, ++ int priority, ++ unsigned long callbackval ++ ) ++ ++ { ++ int status; ++ ++ status = MV_PlayLoopedWAV( ptr, -1, -1, pitchoffset, vol, left, right, ++ priority, callbackval ); ++ ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_PlayWAV3D ++ ++ Begin playback of sound data at specified angle and distance ++ from listener. ++---------------------------------------------------------------------*/ ++ ++int MV_PlayWAV3D ++ ( ++ char *ptr, ++ int pitchoffset, ++ int angle, ++ int distance, ++ int priority, ++ unsigned long callbackval ++ ) ++ ++ { ++ int left; ++ int right; ++ int mid; ++ int volume; ++ int status; ++ ++ if ( !MV_Installed ) ++ { ++ MV_SetErrorCode( MV_NotInstalled ); ++ return( MV_Error ); ++ } ++ ++ if ( distance < 0 ) ++ { ++ distance = -distance; ++ angle += MV_NumPanPositions / 2; ++ } ++ ++ volume = MIX_VOLUME( distance ); ++ ++ // Ensure angle is within 0 - 31 ++ angle &= MV_MaxPanPosition; ++ ++ left = MV_PanTable[ angle ][ volume ].left; ++ right = MV_PanTable[ angle ][ volume ].right; ++ mid = max( 0, 255 - distance ); ++ ++ status = MV_PlayWAV( ptr, pitchoffset, mid, left, right, priority, ++ callbackval ); ++ ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_PlayLoopedWAV ++ ++ Begin playback of sound data with the given sound levels and ++ priority. ++---------------------------------------------------------------------*/ ++ ++int MV_PlayLoopedWAV ++ ( ++ char *ptr, ++ long loopstart, ++ long loopend, ++ int pitchoffset, ++ int vol, ++ int left, ++ int right, ++ int priority, ++ unsigned long callbackval ++ ) ++ ++ { ++ riff_header *riff; ++ format_header *format; ++ data_header *data; ++ VoiceNode *voice; ++ int length; ++ int absloopend; ++ int absloopstart; ++ ++ if ( !MV_Installed ) ++ { ++ MV_SetErrorCode( MV_NotInstalled ); ++ return( MV_Error ); ++ } ++ ++ riff = ( riff_header * )ptr; ++ ++ if ( ( strncmp( riff->RIFF, "RIFF", 4 ) != 0 ) || ++ ( strncmp( riff->WAVE, "WAVE", 4 ) != 0 ) || ++ ( strncmp( riff->fmt, "fmt ", 4) != 0 ) ) ++ { ++ MV_SetErrorCode( MV_InvalidWAVFile ); ++ return( MV_Error ); ++ } ++ ++ format = ( format_header * )( riff + 1 ); ++ data = ( data_header * )( ( ( char * )format ) + riff->format_size ); ++ ++ // Check if it's PCM data. ++ if ( format->wFormatTag != 1 ) ++ { ++ MV_SetErrorCode( MV_InvalidWAVFile ); ++ return( MV_Error ); ++ } ++ ++ if ( format->nChannels != 1 ) ++ { ++ MV_SetErrorCode( MV_InvalidWAVFile ); ++ return( MV_Error ); ++ } ++ ++ if ( ( format->nBitsPerSample != 8 ) && ++ ( format->nBitsPerSample != 16 ) ) ++ { ++ MV_SetErrorCode( MV_InvalidWAVFile ); ++ return( MV_Error ); ++ } ++ ++ if ( strncmp( data->DATA, "data", 4 ) != 0 ) ++ { ++ MV_SetErrorCode( MV_InvalidWAVFile ); ++ return( MV_Error ); ++ } ++ ++ // Request a voice from the voice pool ++ voice = MV_AllocVoice( priority ); ++ if ( voice == NULL ) ++ { ++ MV_SetErrorCode( MV_NoVoices ); ++ return( MV_Error ); ++ } ++ ++ voice->wavetype = WAV; ++ voice->bits = format->nBitsPerSample; ++ voice->GetSound = MV_GetNextWAVBlock; ++ ++ length = data->size; ++ absloopstart = loopstart; ++ absloopend = loopend; ++ if ( voice->bits == 16 ) ++ { ++ loopstart *= 2; ++ data->size &= ~1; ++ loopend *= 2; ++ length /= 2; ++ } ++ ++ loopend = min( loopend, (long)data->size ); ++ absloopend = min( absloopend, length ); ++ ++ voice->Playing = TRUE; ++ voice->DemandFeed = NULL; ++ voice->LoopStart = NULL; ++ voice->LoopCount = 0; ++ voice->position = 0; ++ voice->length = 0; ++ voice->BlockLength = absloopend; ++ voice->NextBlock = ( char * )( data + 1 ); ++ voice->next = NULL; ++ voice->prev = NULL; ++ voice->priority = priority; ++ voice->callbackval = callbackval; ++ voice->LoopStart = voice->NextBlock + loopstart; ++ voice->LoopEnd = voice->NextBlock + loopend; ++ voice->LoopSize = absloopend - absloopstart; ++ ++ if ( ( loopstart >= (long)data->size ) || ( loopstart < 0 ) ) ++ { ++ voice->LoopStart = NULL; ++ voice->LoopEnd = NULL; ++ voice->BlockLength = length; ++ } ++ ++ MV_SetVoicePitch( voice, format->nSamplesPerSec, pitchoffset ); ++ MV_SetVoiceVolume( voice, vol, left, right ); ++ MV_PlayVoice( voice ); ++ ++ return( voice->handle ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_PlayVOC3D ++ ++ Begin playback of sound data at specified angle and distance ++ from listener. ++---------------------------------------------------------------------*/ ++ ++int MV_PlayVOC3D ++ ( ++ char *ptr, ++ int pitchoffset, ++ int angle, ++ int distance, ++ int priority, ++ unsigned long callbackval ++ ) ++ ++ { ++ int left; ++ int right; ++ int mid; ++ int volume; ++ int status; ++ ++ if ( !MV_Installed ) ++ { ++ MV_SetErrorCode( MV_NotInstalled ); ++ return( MV_Error ); ++ } ++ ++ if ( distance < 0 ) ++ { ++ distance = -distance; ++ angle += MV_NumPanPositions / 2; ++ } ++ ++ volume = MIX_VOLUME( distance ); ++ ++ // Ensure angle is within 0 - 31 ++ angle &= MV_MaxPanPosition; ++ ++ left = MV_PanTable[ angle ][ volume ].left; ++ right = MV_PanTable[ angle ][ volume ].right; ++ mid = max( 0, 255 - distance ); ++ ++ status = MV_PlayVOC( ptr, pitchoffset, mid, left, right, priority, ++ callbackval ); ++ ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_PlayVOC ++ ++ Begin playback of sound data with the given sound levels and ++ priority. ++---------------------------------------------------------------------*/ ++ ++int MV_PlayVOC ++ ( ++ char *ptr, ++ int pitchoffset, ++ int vol, ++ int left, ++ int right, ++ int priority, ++ unsigned long callbackval ++ ) ++ ++ { ++ int status; ++ ++ status = MV_PlayLoopedVOC( ptr, -1, -1, pitchoffset, vol, left, right, ++ priority, callbackval ); ++ ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_PlayLoopedVOC ++ ++ Begin playback of sound data with the given sound levels and ++ priority. ++---------------------------------------------------------------------*/ ++ ++int MV_PlayLoopedVOC ++ ( ++ char *ptr, ++ long loopstart, ++ long loopend, ++ int pitchoffset, ++ int vol, ++ int left, ++ int right, ++ int priority, ++ unsigned long callbackval ++ ) ++ ++ { ++ VoiceNode *voice; ++ int status; ++ unsigned short nextpos; ++ ++ if ( !MV_Installed ) ++ { ++ MV_SetErrorCode( MV_NotInstalled ); ++ return( MV_Error ); ++ } ++ ++ // Make sure it's a valid VOC file. ++ status = strncmp( ptr, "Creative Voice File", 19 ); ++ if ( status != 0 ) ++ { ++ MV_SetErrorCode( MV_InvalidVOCFile ); ++ return( MV_Error ); ++ } ++ ++ // Request a voice from the voice pool ++ voice = MV_AllocVoice( priority ); ++ if ( voice == NULL ) ++ { ++ MV_SetErrorCode( MV_NoVoices ); ++ return( MV_Error ); ++ } ++ ++ voice->wavetype = VOC; ++ voice->bits = 8; ++ voice->GetSound = MV_GetNextVOCBlock; ++ ++ nextpos = *( unsigned short * )( ptr + 0x14 ); ++ voice->NextBlock = ptr + BUILDSWAP_INTEL16(nextpos); ++ ++ voice->DemandFeed = NULL; ++ voice->LoopStart = NULL; ++ voice->LoopCount = 0; ++ voice->BlockLength = 0; ++ voice->PitchScale = PITCH_GetScale( pitchoffset ); ++ voice->length = 0; ++ voice->next = NULL; ++ voice->prev = NULL; ++ voice->priority = priority; ++ voice->callbackval = callbackval; ++ voice->LoopStart = ( char * )loopstart; ++ voice->LoopEnd = ( char * )loopend; ++ voice->LoopSize = loopend - loopstart + 1; ++ ++ if ( loopstart < 0 ) ++ { ++ voice->LoopStart = NULL; ++ voice->LoopEnd = NULL; ++ } ++ ++ MV_SetVoiceVolume( voice, vol, left, right ); ++ MV_PlayVoice( voice ); ++ ++ return( voice->handle ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_LockEnd ++ ++ Used for determining the length of the functions to lock in memory. ++---------------------------------------------------------------------*/ ++ ++static void MV_LockEnd ++ ( ++ void ++ ) ++ ++ { ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_CreateVolumeTable ++ ++ Create the table used to convert sound data to a specific volume ++ level. ++---------------------------------------------------------------------*/ ++ ++void MV_CreateVolumeTable ++ ( ++ int index, ++ int volume, ++ int MaxVolume ++ ) ++ ++ { ++ int val; ++ int level; ++ int i; ++ ++ level = ( volume * MaxVolume ) / MV_MaxTotalVolume; ++ if ( MV_Bits == 16 ) ++ { ++ for( i = 0; i < 65536; i += 256 ) ++ { ++ val = i - 0x8000; ++ val *= level; ++ val /= MV_MaxVolume; ++ MV_VolumeTable[ index ][ i / 256 ] = val; ++ } ++ } ++ else ++ { ++ for( i = 0; i < 256; i++ ) ++ { ++ val = i - 0x80; ++ val *= level; ++ val /= MV_MaxVolume; ++ MV_VolumeTable[ volume ][ i ] = val; ++ } ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_CalcVolume ++ ++ Create the table used to convert sound data to a specific volume ++ level. ++---------------------------------------------------------------------*/ ++ ++void MV_CalcVolume ++ ( ++ int MaxVolume ++ ) ++ ++ { ++ int volume; ++ ++ for( volume = 0; volume < 128; volume++ ) ++ { ++ MV_HarshClipTable[ volume ] = 0; ++ MV_HarshClipTable[ volume + 384 ] = 255; ++ } ++ for( volume = 0; volume < 256; volume++ ) ++ { ++ MV_HarshClipTable[ volume + 128 ] = volume; ++ } ++ ++ // For each volume level, create a translation table with the ++ // appropriate volume calculated. ++ for( volume = 0; volume <= MV_MaxVolume; volume++ ) ++ { ++ MV_CreateVolumeTable( volume, volume, MaxVolume ); ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_CalcPanTable ++ ++ Create the table used to determine the stereo volume level of ++ a sound located at a specific angle and distance from the listener. ++---------------------------------------------------------------------*/ ++ ++void MV_CalcPanTable ++ ( ++ void ++ ) ++ ++ { ++ int level; ++ int angle; ++ int distance; ++ int HalfAngle; ++ int ramp; ++ ++ HalfAngle = ( MV_NumPanPositions / 2 ); ++ ++ for( distance = 0; distance <= MV_MaxVolume; distance++ ) ++ { ++ level = ( 255 * ( MV_MaxVolume - distance ) ) / MV_MaxVolume; ++ for( angle = 0; angle <= HalfAngle / 2; angle++ ) ++ { ++ ramp = level - ( ( level * angle ) / ++ ( MV_NumPanPositions / 4 ) ); ++ ++ MV_PanTable[ angle ][ distance ].left = ramp; ++ MV_PanTable[ HalfAngle - angle ][ distance ].left = ramp; ++ MV_PanTable[ HalfAngle + angle ][ distance ].left = level; ++ MV_PanTable[ MV_MaxPanPosition - angle ][ distance ].left = level; ++ ++ MV_PanTable[ angle ][ distance ].right = level; ++ MV_PanTable[ HalfAngle - angle ][ distance ].right = level; ++ MV_PanTable[ HalfAngle + angle ][ distance ].right = ramp; ++ MV_PanTable[ MV_MaxPanPosition - angle ][ distance ].right = ramp; ++ } ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_SetVolume ++ ++ Sets the volume of digitized sound playback. ++---------------------------------------------------------------------*/ ++ ++void MV_SetVolume ++ ( ++ int volume ++ ) ++ ++ { ++ volume = max( 0, volume ); ++ volume = min( volume, MV_MaxTotalVolume ); ++ ++ MV_TotalVolume = volume; ++ ++ // Calculate volume table ++ MV_CalcVolume( volume ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_GetVolume ++ ++ Returns the volume of digitized sound playback. ++---------------------------------------------------------------------*/ ++ ++int MV_GetVolume ++ ( ++ void ++ ) ++ ++ { ++ return( MV_TotalVolume ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_SetCallBack ++ ++ Set the function to call when a voice stops. ++---------------------------------------------------------------------*/ ++ ++void MV_SetCallBack ++ ( ++ void ( *function )( unsigned long ) ++ ) ++ ++ { ++ MV_CallBackFunc = function; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_SetReverseStereo ++ ++ Set the orientation of the left and right channels. ++---------------------------------------------------------------------*/ ++ ++void MV_SetReverseStereo ++ ( ++ int setting ++ ) ++ ++ { ++ MV_SwapLeftRight = setting; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_GetReverseStereo ++ ++ Returns the orientation of the left and right channels. ++---------------------------------------------------------------------*/ ++ ++int MV_GetReverseStereo ++ ( ++ void ++ ) ++ ++ { ++ return( MV_SwapLeftRight ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_TestPlayback ++ ++ Checks if playback has started. ++---------------------------------------------------------------------*/ ++ ++int MV_TestPlayback(void) ++ { ++ return MV_Ok; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_Init ++ ++ Perform the initialization of variables and memory used by ++ Multivoc. ++---------------------------------------------------------------------*/ ++ ++int MV_Init ++ ( ++ int soundcard, ++ int MixRate, ++ int Voices, ++ int numchannels, ++ int samplebits ++ ) ++ ++ { ++ char *ptr; ++ int status; ++ int buffer; ++ int index; ++ ++ if ( MV_Installed ) ++ { ++ MV_Shutdown(); ++ } ++ ++ MV_SetErrorCode( MV_Ok ); ++ ++ MV_TotalMemory = Voices * sizeof( VoiceNode ) + sizeof( HARSH_CLIP_TABLE_8 ); ++ status = USRHOOKS_GetMem( ( void ** )&ptr, MV_TotalMemory ); ++ if ( status != USRHOOKS_Ok ) ++ { ++ MV_SetErrorCode( MV_NoMem ); ++ return( MV_Error ); ++ } ++ ++ MV_Voices = ( VoiceNode * )ptr; ++ MV_HarshClipTable = ptr + ( MV_TotalMemory - sizeof( HARSH_CLIP_TABLE_8 ) ); ++ ++ // Set number of voices before calculating volume table ++ MV_MaxVoices = Voices; ++ ++ LL_Reset( (VoiceNode *)&VoiceList, next, prev ); ++ LL_Reset( (VoiceNode *)&VoicePool, next, prev ); ++ ++ for( index = 0; index < Voices; index++ ) ++ { ++ LL_Add( (VoiceNode *)&VoicePool, &MV_Voices[ index ], next, prev ); ++ } ++ ++ // Allocate mix buffer within 1st megabyte ++ status = DPMI_GetDOSMemory( ( void ** )&ptr, &MV_BufferDescriptor, ++ 2 * TotalBufferSize ); ++ ++ if ( status ) ++ { ++ USRHOOKS_FreeMem( MV_Voices ); ++ MV_Voices = NULL; ++ MV_TotalMemory = 0; ++ ++ MV_SetErrorCode( MV_NoMem ); ++ return( MV_Error ); ++ } ++ ++ MV_SetReverseStereo( FALSE ); ++ ++ // Initialize the sound card ++ status = DSL_Init(); ++ if ( status != DSL_Ok ) ++ { ++ MV_SetErrorCode( MV_BlasterError ); ++ } ++ ++ if ( MV_ErrorCode != MV_Ok ) ++ { ++ status = MV_ErrorCode; ++ ++ USRHOOKS_FreeMem( MV_Voices ); ++ MV_Voices = NULL; ++ MV_TotalMemory = 0; ++ ++ DPMI_FreeDOSMemory( MV_BufferDescriptor ); ++ ++ MV_SetErrorCode( status ); ++ return( MV_Error ); ++ } ++ ++ MV_SoundCard = soundcard; ++ MV_Installed = TRUE; ++ MV_CallBackFunc = NULL; ++ MV_RecordFunc = NULL; ++ MV_Recording = FALSE; ++ MV_ReverbLevel = 0; ++ MV_ReverbTable = NULL; ++ ++ // Set the sampling rate ++ MV_RequestedMixRate = MixRate; ++ ++ // Set Mixer to play stereo digitized sound ++ MV_SetMixMode( numchannels, samplebits ); ++ MV_ReverbDelay = MV_BufferSize * 3; ++ ++ MV_MixBuffer[ MV_NumberOfBuffers ] = ptr; ++ for( buffer = 0; buffer < MV_NumberOfBuffers; buffer++ ) ++ { ++ MV_MixBuffer[ buffer ] = ptr; ++ ptr += MV_BufferSize; ++ } ++ ++ // Calculate pan table ++ MV_CalcPanTable(); ++ ++ MV_SetVolume( MV_MaxTotalVolume ); ++ ++ // Start the playback engine ++ status = MV_StartPlayback(); ++ if ( status != MV_Ok ) ++ { ++ // Preserve error code while we shutdown. ++ status = MV_ErrorCode; ++ MV_Shutdown(); ++ MV_SetErrorCode( status ); ++ return( MV_Error ); ++ } ++ ++ if ( MV_TestPlayback() != MV_Ok ) ++ { ++ status = MV_ErrorCode; ++ MV_Shutdown(); ++ MV_SetErrorCode( status ); ++ return( MV_Error ); ++ } ++ ++ return( MV_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_Shutdown ++ ++ Restore any resources allocated by Multivoc back to the system. ++---------------------------------------------------------------------*/ ++ ++int MV_Shutdown ++ ( ++ void ++ ) ++ ++ { ++ int buffer; ++ unsigned flags; ++ ++ if ( !MV_Installed ) ++ { ++ return( MV_Ok ); ++ } ++ ++ flags = DisableInterrupts(); ++ ++ MV_KillAllVoices(); ++ ++ MV_Installed = FALSE; ++ ++ // Stop the sound recording engine ++ if ( MV_Recording ) ++ { ++ MV_StopRecord(); ++ } ++ ++ // Stop the sound playback engine ++ MV_StopPlayback(); ++ ++ // Shutdown the sound card ++ DSL_Shutdown(); ++ ++ RestoreInterrupts( flags ); ++ ++ // Free any voices we allocated ++ USRHOOKS_FreeMem( MV_Voices ); ++ MV_Voices = NULL; ++ MV_TotalMemory = 0; ++ ++ LL_Reset( (VoiceNode *)&VoiceList, next, prev ); ++ LL_Reset( (VoiceNode *)&VoicePool, next, prev ); ++ ++ MV_MaxVoices = 1; ++ ++ // Release the descriptor from our mix buffer ++ DPMI_FreeDOSMemory( MV_BufferDescriptor ); ++ for( buffer = 0; buffer < NumberOfBuffers; buffer++ ) ++ { ++ MV_MixBuffer[ buffer ] = NULL; ++ } ++ ++ return( MV_Ok ); ++ } |