// // ID Engine // ID_SD.c - Sound Manager for Wolfenstein 3D // v1.2 // By Jason Blochowiak // // // This module handles dealing with generating sound on the appropriate // hardware // // Depends on: User Mgr (for parm checking) // // Globals: // For User Mgr: // SoundBlasterPresent - SoundBlaster card present? // AdLibPresent - AdLib card present? // SoundMode - What device is used for sound effects // (Use SM_SetSoundMode() to set) // MusicMode - What device is used for music // (Use SM_SetMusicMode() to set) // DigiMode - What device is used for digitized sound effects // (Use SM_SetDigiDevice() to set) // // For Cache Mgr: // NeedsDigitized - load digitized sounds? // NeedsMusic - load music? // #include "wl_def.h" #include "SDL_mixer/SDL_mixer.h" #if defined(GP2X_940) #include "gp2x/fmopl.h" #else #include "mame/fmopl.h" #endif #pragma hdrstop #define ORIGSAMPLERATE 7042 typedef struct { char RIFF[4]; longword filelenminus8; char WAVE[4]; char fmt_[4]; longword formatlen; word val0x0001; word channels; longword samplerate; longword bytespersec; word bytespersample; word bitspersample; } headchunk; typedef struct { char chunkid[4]; longword chunklength; } wavechunk; typedef struct { uint32_t startpage; uint32_t length; } digiinfo; static Mix_Chunk *SoundChunks[ STARTMUSIC - STARTDIGISOUNDS]; static byte *SoundBuffers[STARTMUSIC - STARTDIGISOUNDS]; globalsoundpos channelSoundPos[MIX_CHANNELS]; // Global variables boolean AdLibPresent, SoundBlasterPresent,SBProPresent, SoundPositioned; SDMode SoundMode; SMMode MusicMode; SDSMode DigiMode; static byte **SoundTable; int DigiMap[LASTSOUND]; int DigiChannel[STARTMUSIC - STARTDIGISOUNDS]; // Internal variables boolean SD_Started; static boolean nextsoundpos; static soundnames SoundNumber; static soundnames DigiNumber; static word SoundPriority; static word DigiPriority; static int LeftPosition; static int RightPosition; word NumDigi; static digiinfo *DigiList; static boolean DigiPlaying; // PC Sound variables static volatile byte pcLastSample; static byte * volatile pcSound; static longword pcLengthLeft; // AdLib variables static byte * volatile alSound; static byte alBlock; static longword alLengthLeft; static longword alTimeCount; static Instrument alZeroInst; // Sequencer variables static volatile boolean sqActive; static word *sqHack; static word *sqHackPtr; static int sqHackLen; static int sqHackSeqLen; static longword sqHackTime; static void SDL_SoundFinished(void) { SoundNumber = (soundnames)0; SoundPriority = 0; } #ifdef NOTYET void SDL_turnOnPCSpeaker(word timerval); #pragma aux SDL_turnOnPCSpeaker = \ "mov al,0b6h" \ "out 43h,al" \ "mov al,bl" \ "out 42h,al" \ "mov al,bh" \ "out 42h,al" \ "in al,61h" \ "or al,3" \ "out 61h,al" \ parm [bx] \ modify exact [al] void SDL_turnOffPCSpeaker(); #pragma aux SDL_turnOffPCSpeaker = \ "in al,61h" \ "and al,0fch" \ "out 61h,al" \ modify exact [al] void SDL_setPCSpeaker(byte val); #pragma aux SDL_setPCSpeaker = \ "in al,61h" \ "and al,0fch" \ "or al,ah" \ "out 61h,al" \ parm [ah] \ modify exact [al] void inline SDL_DoFX() { if(pcSound) { if(*pcSound!=pcLastSample) { pcLastSample=*pcSound; if(pcLastSample) SDL_turnOnPCSpeaker(pcLastSample*60); else SDL_turnOffPCSpeaker(); } pcSound++; pcLengthLeft--; if(!pcLengthLeft) { pcSound=0; SoundNumber=(soundnames)0; SoundPriority=0; SDL_turnOffPCSpeaker(); } } // [adlib sound stuff removed...] } static void SDL_DigitizedDoneInIRQ(void); void inline SDL_DoFast() { count_fx++; if(count_fx>=5) { count_fx=0; SDL_DoFX(); count_time++; if(count_time>=2) { TimeCount++; count_time=0; } } // [adlib music and soundsource stuff removed...] TimerCount+=TimerDivisor; if(*((word *)&TimerCount+1)) { *((word *)&TimerCount+1)=0; t0OldService(); } else { outp(0x20,0x20); } } // Timer 0 ISR for 7000Hz interrupts void __interrupt SDL_t0ExtremeAsmService(void) { if(pcindicate) { if(pcSound) { SDL_setPCSpeaker(((*pcSound++)&0x80)>>6); pcLengthLeft--; if(!pcLengthLeft) { pcSound=0; SDL_turnOffPCSpeaker(); SDL_DigitizedDoneInIRQ(); } } } extreme++; if(extreme>=10) { extreme=0; SDL_DoFast(); } else outp(0x20,0x20); } // Timer 0 ISR for 700Hz interrupts void __interrupt SDL_t0FastAsmService(void) { SDL_DoFast(); } // Timer 0 ISR for 140Hz interrupts void __interrupt SDL_t0SlowAsmService(void) { count_time++; if(count_time>=2) { TimeCount++; count_time=0; } SDL_DoFX(); TimerCount+=TimerDivisor; if(*((word *)&TimerCount+1)) { *((word *)&TimerCount+1)=0; t0OldService(); } else outp(0x20,0x20); } void SDL_IndicatePC(boolean ind) { pcindicate=ind; } /////////////////////////////////////////////////////////////////////////// // // SDL_SetTimer0() - Sets system timer 0 to the specified speed // /////////////////////////////////////////////////////////////////////////// static void SDL_SetTimer0(word speed) { #ifndef TPROF // If using Borland's profiling, don't screw with the timer // _asm pushfd _asm cli outp(0x43,0x36); // Change timer 0 outp(0x40,(byte)speed); outp(0x40,speed >> 8); // Kludge to handle special case for digitized PC sounds if (TimerDivisor == (1192030 / (TickBase * 100))) TimerDivisor = (1192030 / (TickBase * 10)); else TimerDivisor = speed; // _asm popfd _asm sti #else TimerDivisor = 0x10000; #endif } /////////////////////////////////////////////////////////////////////////// // // SDL_SetIntsPerSec() - Uses SDL_SetTimer0() to set the number of // interrupts generated by system timer 0 per second // /////////////////////////////////////////////////////////////////////////// static void SDL_SetIntsPerSec(word ints) { TimerRate = ints; SDL_SetTimer0(1192030 / ints); } static void SDL_SetTimerSpeed(void) { word rate; void (_interrupt *isr)(void); if ((DigiMode == sds_PC) && DigiPlaying) { rate = TickBase * 100; isr = SDL_t0ExtremeAsmService; } else if ((MusicMode == smm_AdLib) || ((DigiMode == sds_SoundSource) && DigiPlaying) ) { rate = TickBase * 10; isr = SDL_t0FastAsmService; } else { rate = TickBase * 2; isr = SDL_t0SlowAsmService; } if (rate != TimerRate) { _dos_setvect(8,isr); SDL_SetIntsPerSec(rate); TimerRate = rate; } } // // PC Sound code // /////////////////////////////////////////////////////////////////////////// // // SDL_PCPlaySample() - Plays the specified sample on the PC speaker // /////////////////////////////////////////////////////////////////////////// #ifdef _MUSE_ void #else static void #endif SDL_PCPlaySample(byte *data,longword len,boolean inIRQ) { if(!inIRQ) { // _asm pushfd _asm cli } SDL_IndicatePC(true); pcLengthLeft = len; pcSound = (volatile byte *)data; if(!inIRQ) { // _asm popfd _asm sti } } /////////////////////////////////////////////////////////////////////////// // // SDL_PCStopSample() - Stops a sample playing on the PC speaker // /////////////////////////////////////////////////////////////////////////// #ifdef _MUSE_ void #else static void #endif SDL_PCStopSampleInIRQ(void) { pcSound = 0; SDL_IndicatePC(false); _asm in al,0x61 // Turn the speaker off _asm and al,0xfd // ~2 _asm out 0x61,al } /////////////////////////////////////////////////////////////////////////// // // SDL_PCPlaySound() - Plays the specified sound on the PC speaker // /////////////////////////////////////////////////////////////////////////// #ifdef _MUSE_ void #else static void #endif SDL_PCPlaySound(PCSound *sound) { // _asm pushfd _asm cli pcLastSample = -1; pcLengthLeft = sound->common.length; pcSound = sound->data; // _asm popfd _asm sti } /////////////////////////////////////////////////////////////////////////// // // SDL_PCStopSound() - Stops the current sound playing on the PC Speaker // /////////////////////////////////////////////////////////////////////////// #ifdef _MUSE_ void #else static void #endif SDL_PCStopSound(void) { // _asm pushfd _asm cli pcSound = 0; _asm in al,0x61 // Turn the speaker off _asm and al,0xfd // ~2 _asm out 0x61,al // _asm popfd _asm sti } /////////////////////////////////////////////////////////////////////////// // // SDL_ShutPC() - Turns off the pc speaker // /////////////////////////////////////////////////////////////////////////// static void SDL_ShutPC(void) { // _asm pushfd _asm cli pcSound = 0; _asm in al,0x61 // Turn the speaker & gate off _asm and al,0xfc // ~3 _asm out 0x61,al // _asm popfd _asm sti } #endif void SD_StopDigitized(void) { DigiPlaying = false; DigiNumber = (soundnames) 0; DigiPriority = 0; SoundPositioned = false; if ((DigiMode == sds_PC) && (SoundMode == sdm_PC)) SDL_SoundFinished(); switch (DigiMode) { case sds_PC: // SDL_PCStopSampleInIRQ(); break; case sds_SoundBlaster: // SDL_SBStopSampleInIRQ(); Mix_HaltChannel(-1); break; } } int SD_GetChannelForDigi(int which) { if(DigiChannel[which] != -1) return DigiChannel[which]; int channel = Mix_GroupAvailable(1); if(channel == -1) channel = Mix_GroupOldest(1); if(channel == -1) // All sounds stopped in the meantime? return Mix_GroupAvailable(1); return channel; } void SD_SetPosition(int channel, int leftpos, int rightpos) { if((leftpos < 0) || (leftpos > 15) || (rightpos < 0) || (rightpos > 15) || ((leftpos == 15) && (rightpos == 15))) Quit("SD_SetPosition: Illegal position"); switch (DigiMode) { case sds_SoundBlaster: // SDL_PositionSBP(leftpos,rightpos); Mix_SetPanning(channel, ((15 - leftpos) << 4) + 15, ((15 - rightpos) << 4) + 15); break; } } Sint16 GetSample(float csample, byte *samples, int size) { float s0=0, s1=0, s2=0; int cursample = (int) csample; float sf = csample - (float) cursample; if(cursample-1 >= 0) s0 = (float) (samples[cursample-1] - 128); s1 = (float) (samples[cursample] - 128); if(cursample+1 < size) s2 = (float) (samples[cursample+1] - 128); float val = s0*sf*(sf-1)/2 - s1*(sf*sf-1) + s2*(sf+1)*sf/2; int32_t intval = (int32_t) (val * 256); if(intval < -32768) intval = -32768; else if(intval > 32767) intval = 32767; return (Sint16) intval; } void SD_PrepareSound(int which) { if(DigiList == NULL) Quit("SD_PrepareSound(%i): DigiList not initialized!\n", which); int page = DigiList[which].startpage; int size = DigiList[which].length; byte *origsamples = PM_GetSound(page); if(origsamples + size >= PM_GetEnd()) Quit("SD_PrepareSound(%i): Sound reaches out of page file!\n", which); int destsamples = (int) ((float) size * (float) param_samplerate / (float) ORIGSAMPLERATE); byte *wavebuffer = (byte *) malloc(sizeof(headchunk) + sizeof(wavechunk) + destsamples * 2); // dest are 16-bit samples if(wavebuffer == NULL) Quit("Unable to allocate wave buffer for sound %i!\n", which); headchunk head = {{'R','I','F','F'}, 0, {'W','A','V','E'}, {'f','m','t',' '}, 0x10, 0x0001, 1, param_samplerate, param_samplerate*2, 2, 16}; wavechunk dhead = {{'d', 'a', 't', 'a'}, destsamples*2}; head.filelenminus8 = sizeof(head) + destsamples*2; // (sizeof(dhead)-8 = 0) memcpy(wavebuffer, &head, sizeof(head)); memcpy(wavebuffer+sizeof(head), &dhead, sizeof(dhead)); // alignment is correct, as wavebuffer comes from malloc // and sizeof(headchunk) % 4 == 0 and sizeof(wavechunk) % 4 == 0 Sint16 *newsamples = (Sint16 *)(void *) (wavebuffer + sizeof(headchunk) + sizeof(wavechunk)); float cursample = 0.F; float samplestep = (float) ORIGSAMPLERATE / (float) param_samplerate; for(int i=0; i= NumDigi) Quit("SD_PlayDigitized: bad sound number %i", which); int channel = SD_GetChannelForDigi(which); SD_SetPosition(channel, leftpos,rightpos); DigiPlaying = true; Mix_Chunk *sample = SoundChunks[which]; if(sample == NULL) { printf("SoundChunks[%i] is NULL!\n", which); return 0; } if(Mix_PlayChannel(channel, sample, 0) == -1) { printf("Unable to play sound: %s\n", Mix_GetError()); return 0; } return channel; } void SD_ChannelFinished(int channel) { channelSoundPos[channel].valid = 0; } void SD_SetDigiDevice(SDSMode mode) { boolean devicenotpresent; if (mode == DigiMode) return; SD_StopDigitized(); devicenotpresent = false; switch (mode) { case sds_SoundBlaster: if (!SoundBlasterPresent) devicenotpresent = true; break; } if (!devicenotpresent) { DigiMode = mode; #ifdef NOTYET SDL_SetTimerSpeed(); #endif } } void SDL_SetupDigi(void) { // Correct padding enforced by PM_Startup() word *soundInfoPage = (word *) (void *) PM_GetPage(ChunksInFile-1); NumDigi = (word) PM_GetPageSize(ChunksInFile - 1) / 4; DigiList = (digiinfo *) malloc(NumDigi * sizeof(digiinfo)); int i; for(i = 0; i < NumDigi; i++) { // Calculate the size of the digi from the sizes of the pages between // the start page and the start page of the next sound DigiList[i].startpage = soundInfoPage[i * 2]; if((int) DigiList[i].startpage >= ChunksInFile - 1) { NumDigi = i; break; } int lastPage; if(i < NumDigi - 1) { lastPage = soundInfoPage[i * 2 + 2]; if(lastPage == 0 || lastPage + PMSoundStart > ChunksInFile - 1) lastPage = ChunksInFile - 1; else lastPage += PMSoundStart; } else lastPage = ChunksInFile - 1; int size = 0; for(int page = PMSoundStart + DigiList[i].startpage; page < lastPage; page++) size += PM_GetPageSize(page); // Don't include padding of sound info page, if padding was added if(lastPage == ChunksInFile - 1 && PMSoundInfoPagePadded) size--; // Patch lower 16-bit of size with size from sound info page. // The original VSWAP contains padding which is included in the page size, // but not included in the 16-bit size. So we use the more precise value. if((size & 0xffff0000) != 0 && (size & 0xffff) < soundInfoPage[i * 2 + 1]) size -= 0x10000; size = (size & 0xffff0000) | soundInfoPage[i * 2 + 1]; DigiList[i].length = size; } for(i = 0; i < LASTSOUND; i++) { DigiMap[i] = -1; DigiChannel[i] = -1; } } // AdLib Code /////////////////////////////////////////////////////////////////////////// // // SDL_ALStopSound() - Turns off any sound effects playing through the // AdLib card // /////////////////////////////////////////////////////////////////////////// static void SDL_ALStopSound(void) { alSound = 0; alOut(alFreqH + 0, 0); } static void SDL_AlSetFXInst(Instrument *inst) { byte c,m; m = 0; // modulator cell for channel 0 c = 3; // carrier cell for channel 0 alOut(m + alChar,inst->mChar); alOut(m + alScale,inst->mScale); alOut(m + alAttack,inst->mAttack); alOut(m + alSus,inst->mSus); alOut(m + alWave,inst->mWave); alOut(c + alChar,inst->cChar); alOut(c + alScale,inst->cScale); alOut(c + alAttack,inst->cAttack); alOut(c + alSus,inst->cSus); alOut(c + alWave,inst->cWave); // Note: Switch commenting on these lines for old MUSE compatibility // alOutInIRQ(alFeedCon,inst->nConn); alOut(alFeedCon,0); } /////////////////////////////////////////////////////////////////////////// // // SDL_ALPlaySound() - Plays the specified sound on the AdLib card // /////////////////////////////////////////////////////////////////////////// static void SDL_ALPlaySound(AdLibSound *sound) { Instrument *inst; byte *data; SDL_ALStopSound(); alLengthLeft = sound->common.length; data = sound->data; alBlock = ((sound->block & 7) << 2) | 0x20; inst = &sound->inst; if (!(inst->mSus | inst->cSus)) { Quit("SDL_ALPlaySound() - Bad instrument"); } SDL_AlSetFXInst(inst); alSound = (byte *)data; } /////////////////////////////////////////////////////////////////////////// // // SDL_ShutAL() - Shuts down the AdLib card for sound effects // /////////////////////////////////////////////////////////////////////////// static void SDL_ShutAL(void) { alSound = 0; alOut(alEffects,0); alOut(alFreqH + 0,0); SDL_AlSetFXInst(&alZeroInst); } /////////////////////////////////////////////////////////////////////////// // // SDL_CleanAL() - Totally shuts down the AdLib card // /////////////////////////////////////////////////////////////////////////// static void SDL_CleanAL(void) { int i; alOut(alEffects,0); for (i = 1; i < 0xf5; i++) alOut(i, 0); } /////////////////////////////////////////////////////////////////////////// // // SDL_StartAL() - Starts up the AdLib card for sound effects // /////////////////////////////////////////////////////////////////////////// static void SDL_StartAL(void) { alOut(alEffects, 0); SDL_AlSetFXInst(&alZeroInst); } /////////////////////////////////////////////////////////////////////////// // // SDL_DetectAdLib() - Determines if there's an AdLib (or SoundBlaster // emulating an AdLib) present // /////////////////////////////////////////////////////////////////////////// static boolean SDL_DetectAdLib(void) { for (int i = 1; i <= 0xf5; i++) // Zero all the registers alOut(i, 0); alOut(1, 0x20); // Set WSE=1 // alOut(8, 0); // Set CSM=0 & SEL=0 return true; } //////////////////////////////////////////////////////////////////////////// // // SDL_ShutDevice() - turns off whatever device was being used for sound fx // //////////////////////////////////////////////////////////////////////////// static void SDL_ShutDevice(void) { switch (SoundMode) { case sdm_PC: // SDL_ShutPC(); break; case sdm_AdLib: SDL_ShutAL(); break; } SoundMode = sdm_Off; } /////////////////////////////////////////////////////////////////////////// // // SDL_CleanDevice() - totally shuts down all sound devices // /////////////////////////////////////////////////////////////////////////// static void SDL_CleanDevice(void) { if ((SoundMode == sdm_AdLib) || (MusicMode == smm_AdLib)) SDL_CleanAL(); } /////////////////////////////////////////////////////////////////////////// // // SDL_StartDevice() - turns on whatever device is to be used for sound fx // /////////////////////////////////////////////////////////////////////////// static void SDL_StartDevice(void) { switch (SoundMode) { case sdm_AdLib: SDL_StartAL(); break; } SoundNumber = (soundnames) 0; SoundPriority = 0; } // Public routines /////////////////////////////////////////////////////////////////////////// // // SD_SetSoundMode() - Sets which sound hardware to use for sound effects // /////////////////////////////////////////////////////////////////////////// boolean SD_SetSoundMode(SDMode mode) { boolean result = false; word tableoffset; SD_StopSound(); if ((mode == sdm_AdLib) && !AdLibPresent) mode = sdm_PC; switch (mode) { case sdm_Off: tableoffset = STARTADLIBSOUNDS; result = true; break; case sdm_PC: tableoffset = STARTPCSOUNDS; result = true; break; case sdm_AdLib: tableoffset = STARTADLIBSOUNDS; if (AdLibPresent) result = true; break; default: Quit("SD_SetSoundMode: Invalid sound mode %i", mode); return false; } SoundTable = &audiosegs[tableoffset]; if (result && (mode != SoundMode)) { SDL_ShutDevice(); SoundMode = mode; SDL_StartDevice(); } return(result); } /////////////////////////////////////////////////////////////////////////// // // SD_SetMusicMode() - sets the device to use for background music // /////////////////////////////////////////////////////////////////////////// boolean SD_SetMusicMode(SMMode mode) { boolean result = false; SD_FadeOutMusic(); while (SD_MusicPlaying()) uSDL_Delay(5); switch (mode) { case smm_Off: result = true; break; case smm_AdLib: if (AdLibPresent) result = true; break; } if (result) MusicMode = mode; // SDL_SetTimerSpeed(); return(result); } int numreadysamples = 0; byte *curAlSound = 0; byte *curAlSoundPtr = 0; longword curAlLengthLeft = 0; int soundTimeCounter = 5; int samplesPerMusicTick; void SDL_IMFMusicPlayer(void *udata, Uint8 *stream, int len) { int stereolen = len>>1; int sampleslen = stereolen>>1; INT16 *stream16 = (INT16 *) (void *) stream; // expect correct alignment while(1) { if(numreadysamples) { if(numreadysamples alTimeCount) break; sqHackTime = alTimeCount + *(sqHackPtr+1); alOut(*(byte *) sqHackPtr, *(((byte *) sqHackPtr)+1)); sqHackPtr += 2; sqHackLen -= 4; } while(sqHackLen>0); alTimeCount++; if(!sqHackLen) { sqHackPtr = sqHack; sqHackLen = sqHackSeqLen; sqHackTime = 0; alTimeCount = 0; } } numreadysamples = samplesPerMusicTick; } } /////////////////////////////////////////////////////////////////////////// // // SD_Startup() - starts up the Sound Mgr // Detects all additional sound hardware and installs my ISR // /////////////////////////////////////////////////////////////////////////// void SD_Startup(void) { int i; if (SD_Started) return; if(Mix_OpenAudio(param_samplerate, AUDIO_S16, 2, param_audiobuffer)) { printf("Unable to open audio: %s\n", Mix_GetError()); return; } Mix_ReserveChannels(2); // reserve player and boss weapon channels Mix_GroupChannels(2, MIX_CHANNELS-1, 1); // group remaining channels // Init music samplesPerMusicTick = param_samplerate / 700; // SDL_t0FastAsmService played at 700Hz if(YM3812Init(1,3579545,param_samplerate)) { printf("Unable to create virtual OPL!!\n"); } for(i=1;i<0xf6;i++) YM3812Write(0,i,0); YM3812Write(0,1,0x20); // Set WSE=1 // YM3812Write(0,8,0); // Set CSM=0 & SEL=0 // already set in for statement Mix_HookMusic(SDL_IMFMusicPlayer, 0); Mix_ChannelFinished(SD_ChannelFinished); AdLibPresent = true; SoundBlasterPresent = true; alTimeCount = 0; SD_SetSoundMode(sdm_Off); SD_SetMusicMode(smm_Off); SDL_SetupDigi(); SD_Started = true; } /////////////////////////////////////////////////////////////////////////// // // SD_Shutdown() - shuts down the Sound Mgr // Removes sound ISR and turns off whatever sound hardware was active // /////////////////////////////////////////////////////////////////////////// void SD_Shutdown(void) { if (!SD_Started) return; SD_MusicOff(); SD_StopSound(); for(int i = 0; i < STARTMUSIC - STARTDIGISOUNDS; i++) { if(SoundChunks[i]) Mix_FreeChunk(SoundChunks[i]); if(SoundBuffers[i]) free(SoundBuffers[i]); } free(DigiList); SD_Started = false; #ifdef _KOLIBRI Mix_CloseAudio(); #endif } /////////////////////////////////////////////////////////////////////////// // // SD_PositionSound() - Sets up a stereo imaging location for the next // sound to be played. Each channel ranges from 0 to 15. // /////////////////////////////////////////////////////////////////////////// void SD_PositionSound(int leftvol,int rightvol) { LeftPosition = leftvol; RightPosition = rightvol; nextsoundpos = true; } /////////////////////////////////////////////////////////////////////////// // // SD_PlaySound() - plays the specified sound on the appropriate hardware // /////////////////////////////////////////////////////////////////////////// boolean SD_PlaySound(soundnames sound) { boolean ispos; SoundCommon *s; int lp,rp; lp = LeftPosition; rp = RightPosition; LeftPosition = 0; RightPosition = 0; ispos = nextsoundpos; nextsoundpos = false; if (sound == -1 || (DigiMode == sds_Off && SoundMode == sdm_Off)) return 0; s = (SoundCommon *) SoundTable[sound]; if ((SoundMode != sdm_Off) && !s) Quit("SD_PlaySound() - Uncached sound"); if ((DigiMode != sds_Off) && (DigiMap[sound] != -1)) { if ((DigiMode == sds_PC) && (SoundMode == sdm_PC)) { #ifdef NOTYET if (s->priority < SoundPriority) return 0; SDL_PCStopSound(); SD_PlayDigitized(DigiMap[sound],lp,rp); SoundPositioned = ispos; SoundNumber = sound; SoundPriority = s->priority; #else return 0; #endif } else { #ifdef NOTYET if (s->priority < DigiPriority) return(false); #endif int channel = SD_PlayDigitized(DigiMap[sound], lp, rp); SoundPositioned = ispos; DigiNumber = sound; DigiPriority = s->priority; return channel + 1; } return(true); } if (SoundMode == sdm_Off) return 0; if (!s->length) Quit("SD_PlaySound() - Zero length sound"); if (s->priority < SoundPriority) return 0; switch (SoundMode) { case sdm_PC: // SDL_PCPlaySound((PCSound *)s); break; case sdm_AdLib: SDL_ALPlaySound((AdLibSound *)s); break; } SoundNumber = sound; SoundPriority = s->priority; return 0; } /////////////////////////////////////////////////////////////////////////// // // SD_SoundPlaying() - returns the sound number that's playing, or 0 if // no sound is playing // /////////////////////////////////////////////////////////////////////////// word SD_SoundPlaying(void) { boolean result = false; switch (SoundMode) { case sdm_PC: result = pcSound? true : false; break; case sdm_AdLib: result = alSound? true : false; break; } if (result) return(SoundNumber); else return(false); } /////////////////////////////////////////////////////////////////////////// // // SD_StopSound() - if a sound is playing, stops it // /////////////////////////////////////////////////////////////////////////// void SD_StopSound(void) { if (DigiPlaying) SD_StopDigitized(); switch (SoundMode) { case sdm_PC: // SDL_PCStopSound(); break; case sdm_AdLib: SDL_ALStopSound(); break; } SoundPositioned = false; SDL_SoundFinished(); } /////////////////////////////////////////////////////////////////////////// // // SD_WaitSoundDone() - waits until the current sound is done playing // /////////////////////////////////////////////////////////////////////////// void SD_WaitSoundDone(void) { while (SD_SoundPlaying()) uSDL_Delay(5); } /////////////////////////////////////////////////////////////////////////// // // SD_MusicOn() - turns on the sequencer // /////////////////////////////////////////////////////////////////////////// void SD_MusicOn(void) { sqActive = true; } /////////////////////////////////////////////////////////////////////////// // // SD_MusicOff() - turns off the sequencer and any playing notes // returns the last music offset for music continue // /////////////////////////////////////////////////////////////////////////// int SD_MusicOff(void) { word i; sqActive = false; switch (MusicMode) { case smm_AdLib: alOut(alEffects, 0); for (i = 0;i < sqMaxTracks;i++) alOut(alFreqH + i + 1, 0); break; } return (int) (sqHackPtr-sqHack); } /////////////////////////////////////////////////////////////////////////// // // SD_StartMusic() - starts playing the music pointed to // /////////////////////////////////////////////////////////////////////////// void SD_StartMusic(int chunk) { SD_MusicOff(); if (MusicMode == smm_AdLib) { int32_t chunkLen = CA_CacheAudioChunk(chunk); sqHack = (word *)(void *) audiosegs[chunk]; // alignment is correct if(*sqHack == 0) sqHackLen = sqHackSeqLen = chunkLen; else sqHackLen = sqHackSeqLen = *sqHack++; sqHackPtr = sqHack; sqHackTime = 0; alTimeCount = 0; SD_MusicOn(); } } void SD_ContinueMusic(int chunk, int startoffs) { SD_MusicOff(); if (MusicMode == smm_AdLib) { int32_t chunkLen = CA_CacheAudioChunk(chunk); sqHack = (word *)(void *) audiosegs[chunk]; // alignment is correct if(*sqHack == 0) sqHackLen = sqHackSeqLen = chunkLen; else sqHackLen = sqHackSeqLen = *sqHack++; sqHackPtr = sqHack; if(startoffs >= sqHackLen) { Quit("SD_StartMusic: Illegal startoffs provided!"); } // fast forward to correct position // (needed to reconstruct the instruments) for(int i = 0; i < startoffs; i += 2) { byte reg = *(byte *)sqHackPtr; byte val = *(((byte *)sqHackPtr) + 1); if(reg >= 0xb1 && reg <= 0xb8) val &= 0xdf; // disable play note flag else if(reg == 0xbd) val &= 0xe0; // disable drum flags alOut(reg,val); sqHackPtr += 2; sqHackLen -= 4; } sqHackTime = 0; alTimeCount = 0; SD_MusicOn(); } } /////////////////////////////////////////////////////////////////////////// // // SD_FadeOutMusic() - starts fading out the music. Call SD_MusicPlaying() // to see if the fadeout is complete // /////////////////////////////////////////////////////////////////////////// void SD_FadeOutMusic(void) { switch (MusicMode) { case smm_AdLib: // DEBUG - quick hack to turn the music off SD_MusicOff(); break; } } /////////////////////////////////////////////////////////////////////////// // // SD_MusicPlaying() - returns true if music is currently playing, false if // not // /////////////////////////////////////////////////////////////////////////// boolean SD_MusicPlaying(void) { boolean result; switch (MusicMode) { case smm_AdLib: result = sqActive; break; default: result = false; break; } return(result); }