From 3f59fc8b771625aca9c3aefe03cf1038d8461963 Mon Sep 17 00:00:00 2001 From: Franklin Wei Date: Sun, 7 Jul 2019 22:00:20 -0400 Subject: Wolfenstein 3-D! This is a port of Wolf4SDL, which is derived from the original id software source release. The port runs on top of the SDL plugin runtime and is loaded as an overlay. Licensing of the game code is not an issue, as discussed below (essentially, the Debian project treats Wolf4SDL as GPLv2, with an email from John Carmack backing it up): http://forums.rockbox.org/index.php?topic=52872 Included is a copy of MAME's Yamaha OPL sound chip emulator (fmopl_gpl.c). This file was not part of the original Wolf4SDL source (which includes a non-GPL'd version), but was rather rebased from from a later MAME source which had been relicensed to GPLv2. Change-Id: I64c2ba035e0be7e2f49252f40640641416613439 --- apps/plugins/sdl/progs/wolf3d/id_sd.c | 1578 +++++++++++++++++++++++++++++++++ 1 file changed, 1578 insertions(+) create mode 100644 apps/plugins/sdl/progs/wolf3d/id_sd.c (limited to 'apps/plugins/sdl/progs/wolf3d/id_sd.c') diff --git a/apps/plugins/sdl/progs/wolf3d/id_sd.c b/apps/plugins/sdl/progs/wolf3d/id_sd.c new file mode 100644 index 0000000000..a528caa606 --- /dev/null +++ b/apps/plugins/sdl/progs/wolf3d/id_sd.c @@ -0,0 +1,1578 @@ +// +// 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 "fmopl.h" + +#include "fixedpoint.h" + +#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 +static 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) +{ +#ifdef SOUND_ENABLE + SoundNumber = (soundnames)0; + SoundPriority = 0; +#endif +} + + +#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 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 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) +{ +#ifdef SOUND_ENABLE + 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; + } +#endif +} + +int SD_GetChannelForDigi(int which) +{ +#ifdef SOUND_ENABLE + 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; +#endif + return 0; +} + +void SD_SetPosition(int channel, int leftpos, int rightpos) +{ +#ifdef SOUND_ENABLE + 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; + } +#endif +} + +#define FP_FLOOR(x, fracbits) (x & (~((1<<(fracbits))-1))) + +/* more precise than original samples */ +#define FRACBITS 10 +#define FP_MATH + +#ifdef FP_MATH +/* Looks to be some sort of interpolation - FW19 */ +Sint16 GetSample(long csample_fp, byte *samples, int size) +{ + //float s0=0, s1=0, s2=0; + long s0_fp = 0, s1_fp = 0, s2_fp = 0; + long cursample_fp = FP_FLOOR(csample_fp, FRACBITS); + long sf_fp = csample_fp - cursample_fp; + const long one = 1 << FRACBITS; + + int cursample = cursample_fp >> FRACBITS; + + if(cursample-1 >= 0) s0_fp = (samples[cursample-1] - 128) << FRACBITS; + s1_fp = (samples[cursample] - 128) << FRACBITS; + if(cursample+1 < size) s2_fp = (samples[cursample+1] - 128) << FRACBITS; + + //float val = s0*sf*(sf-1)/2 - s1*(sf*sf-1) + s2*(sf+1)*sf/2; + + long val_fp = fp_mul(s0_fp, fp_mul(sf_fp, sf_fp - one, FRACBITS), FRACBITS) / 2 - + fp_mul(s1_fp, fp_mul(sf_fp, sf_fp, FRACBITS) - one, FRACBITS) + + fp_mul(s2_fp, fp_mul(sf_fp + one, sf_fp, FRACBITS), FRACBITS) / 2; + + int32_t intval = (int32_t) (val_fp * 256) >> FRACBITS; + if(intval < -32768) intval = -32768; + else if(intval > 32767) intval = 32767; + return (Sint16) intval; +} +#else +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; +} +#endif + +void SD_PrepareSound(int which) +{ +#ifdef SOUND_ENABLE +#ifdef FP_MATH + 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); + + /* this is fine to keep as floating-point */ + 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 size %d %d %d %d!\n", which, destsamples, size, param_samplerate, ORIGSAMPLERATE); + + 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)); + + long scale_fac_fp = fp_div(size << FRACBITS, destsamples << FRACBITS, FRACBITS); + + for(int i=0; i= 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; +#endif + return 0; +} + +void SD_ChannelFinished(int channel) +{ +#ifdef SOUND_ENABLE + channelSoundPos[channel].valid = 0; +#endif +} + +void +SD_SetDigiDevice(SDSMode mode) +{ +#ifdef SOUND_ENABLE + 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 + } +#endif +} + +void +SDL_SetupDigi(void) +{ +#ifdef SOUND_ENABLE + // 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; + } +#endif +} + +// AdLib Code + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_ALStopSound() - Turns off any sound effects playing through the +// AdLib card +// +/////////////////////////////////////////////////////////////////////////// +static void +SDL_ALStopSound(void) +{ +#ifdef SOUND_ENABLE + alSound = 0; + alOut(alFreqH + 0, 0); +#endif +} + +static void +SDL_AlSetFXInst(Instrument *inst) +{ +#ifdef SOUND_ENABLE + 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); +#endif +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_ALPlaySound() - Plays the specified sound on the AdLib card +// +/////////////////////////////////////////////////////////////////////////// +static void +SDL_ALPlaySound(AdLibSound *sound) +{ +#ifdef SOUND_ENABLE + 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; +#endif +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_ShutAL() - Shuts down the AdLib card for sound effects +// +/////////////////////////////////////////////////////////////////////////// +static void +SDL_ShutAL(void) +{ +#ifdef SOUND_ENABLE + alSound = 0; + alOut(alEffects,0); + alOut(alFreqH + 0,0); + SDL_AlSetFXInst(&alZeroInst); +#endif +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_CleanAL() - Totally shuts down the AdLib card +// +/////////////////////////////////////////////////////////////////////////// +static void +SDL_CleanAL(void) +{ +#ifdef SOUND_ENABLE + int i; + + alOut(alEffects,0); + for (i = 1; i < 0xf5; i++) + alOut(i, 0); +#endif +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_StartAL() - Starts up the AdLib card for sound effects +// +/////////////////////////////////////////////////////////////////////////// +static void +SDL_StartAL(void) +{ +#ifdef SOUND_ENABLE + alOut(alEffects, 0); + SDL_AlSetFXInst(&alZeroInst); +#endif +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_DetectAdLib() - Determines if there's an AdLib (or SoundBlaster +// emulating an AdLib) present +// +/////////////////////////////////////////////////////////////////////////// +static boolean +SDL_DetectAdLib(void) +{ +#ifdef SOUND_ENABLE + 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; +#endif +} + +//////////////////////////////////////////////////////////////////////////// +// +// SDL_ShutDevice() - turns off whatever device was being used for sound fx +// +//////////////////////////////////////////////////////////////////////////// +static void +SDL_ShutDevice(void) +{ +#ifdef SOUND_ENABLE + switch (SoundMode) + { + case sdm_PC: +// SDL_ShutPC(); + break; + case sdm_AdLib: + SDL_ShutAL(); + break; + } + SoundMode = sdm_Off; +#endif +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_CleanDevice() - totally shuts down all sound devices +// +/////////////////////////////////////////////////////////////////////////// +static void +SDL_CleanDevice(void) +{ +#ifdef SOUND_ENABLE + if ((SoundMode == sdm_AdLib) || (MusicMode == smm_AdLib)) + SDL_CleanAL(); +#endif +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_StartDevice() - turns on whatever device is to be used for sound fx +// +/////////////////////////////////////////////////////////////////////////// +static void +SDL_StartDevice(void) +{ +#ifdef SOUND_ENABLE + switch (SoundMode) + { + case sdm_AdLib: + SDL_StartAL(); + break; + } + SoundNumber = (soundnames) 0; + SoundPriority = 0; +#endif +} + +// Public routines + +/////////////////////////////////////////////////////////////////////////// +// +// SD_SetSoundMode() - Sets which sound hardware to use for sound effects +// +/////////////////////////////////////////////////////////////////////////// +boolean +SD_SetSoundMode(SDMode mode) +{ +#ifdef SOUND_ENABLE + 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); +#endif + return true; +} + +/////////////////////////////////////////////////////////////////////////// +// +// SD_SetMusicMode() - sets the device to use for background music +// +/////////////////////////////////////////////////////////////////////////// +boolean +SD_SetMusicMode(SMMode mode) +{ +#ifdef SOUND_ENABLE + boolean result = false; + + SD_FadeOutMusic(); + while (SD_MusicPlaying()) + SDL_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); +#endif +} + +int numreadysamples = 0; +byte *curAlSound = 0; +byte *curAlSoundPtr = 0; +longword curAlLengthLeft = 0; +int soundTimeCounter = 5; +int samplesPerMusicTick; + +void *OPL_ptr = NULL; + +void SDL_IMFMusicPlayer(void *udata, Uint8 *stream, int len) +{ +#ifdef SOUND_ENABLE + 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; + } +#endif +} + +/////////////////////////////////////////////////////////////////////////// +// +// SD_Startup() - starts up the Sound Mgr +// Detects all additional sound hardware and installs my ISR +// +/////////////////////////////////////////////////////////////////////////// +void +SD_Startup(void) +{ +#ifdef SOUND_ENABLE + 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(!(OPL_ptr = YM3812Init((void*)1,3579545,param_samplerate))) + { + //printf("Unable to create virtual OPL!!\n"); + } + + for(i=1;i<0xf6;i++) + YM3812Write(OPL_ptr,i,0); + + YM3812Write(OPL_ptr,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; +#endif +} + +/////////////////////////////////////////////////////////////////////////// +// +// SD_Shutdown() - shuts down the Sound Mgr +// Removes sound ISR and turns off whatever sound hardware was active +// +/////////////////////////////////////////////////////////////////////////// +void +SD_Shutdown(void) +{ +#ifdef SOUND_ENABLE + 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; +#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) +{ +#ifdef SOUND_ENABLE + LeftPosition = leftvol; + RightPosition = rightvol; + nextsoundpos = true; +#endif +} + +/////////////////////////////////////////////////////////////////////////// +// +// SD_PlaySound() - plays the specified sound on the appropriate hardware +// +/////////////////////////////////////////////////////////////////////////// +boolean +SD_PlaySound(soundnames sound) +{ +#ifdef SOUND_ENABLE + 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; +#endif + return 0; +} + +/////////////////////////////////////////////////////////////////////////// +// +// SD_SoundPlaying() - returns the sound number that's playing, or 0 if +// no sound is playing +// +/////////////////////////////////////////////////////////////////////////// +word +SD_SoundPlaying(void) +{ +#ifdef SOUND_ENABLE + 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); +#endif + return false; +} + +/////////////////////////////////////////////////////////////////////////// +// +// SD_StopSound() - if a sound is playing, stops it +// +/////////////////////////////////////////////////////////////////////////// +void +SD_StopSound(void) +{ +#ifdef SOUND_ENABLE + if (DigiPlaying) + SD_StopDigitized(); + + switch (SoundMode) + { + case sdm_PC: +// SDL_PCStopSound(); + break; + case sdm_AdLib: + SDL_ALStopSound(); + break; + } + + SoundPositioned = false; + + SDL_SoundFinished(); +#endif +} + +/////////////////////////////////////////////////////////////////////////// +// +// SD_WaitSoundDone() - waits until the current sound is done playing +// +/////////////////////////////////////////////////////////////////////////// +void +SD_WaitSoundDone(void) +{ +#ifdef SOUND_ENABLE + while (SD_SoundPlaying()) + SDL_Delay(5); +#endif +} + +/////////////////////////////////////////////////////////////////////////// +// +// SD_MusicOn() - turns on the sequencer +// +/////////////////////////////////////////////////////////////////////////// +void +SD_MusicOn(void) +{ +#ifdef SOUND_ENABLE + sqActive = true; +#endif +} + +/////////////////////////////////////////////////////////////////////////// +// +// SD_MusicOff() - turns off the sequencer and any playing notes +// returns the last music offset for music continue +// +/////////////////////////////////////////////////////////////////////////// +int +SD_MusicOff(void) +{ +#ifdef SOUND_ENABLE + 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); +#endif +} + +/////////////////////////////////////////////////////////////////////////// +// +// SD_StartMusic() - starts playing the music pointed to +// +/////////////////////////////////////////////////////////////////////////// +void +SD_StartMusic(int chunk) +{ +#ifdef SOUND_ENABLE + 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(); + } +#endif +} + +void +SD_ContinueMusic(int chunk, int startoffs) +{ +#ifdef SOUND_ENABLE + 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(); + } +#endif +} + +/////////////////////////////////////////////////////////////////////////// +// +// SD_FadeOutMusic() - starts fading out the music. Call SD_MusicPlaying() +// to see if the fadeout is complete +// +/////////////////////////////////////////////////////////////////////////// +void +SD_FadeOutMusic(void) +{ +#ifdef SOUND_ENABLE + switch (MusicMode) + { + case smm_AdLib: + // DEBUG - quick hack to turn the music off + SD_MusicOff(); + break; + } +#endif +} + +/////////////////////////////////////////////////////////////////////////// +// +// SD_MusicPlaying() - returns true if music is currently playing, false if +// not +// +/////////////////////////////////////////////////////////////////////////// +boolean +SD_MusicPlaying(void) +{ +#ifdef SOUND_ENABLE + boolean result; + + switch (MusicMode) + { + case smm_AdLib: + result = sqActive; + break; + default: + result = false; + break; + } + + return(result); +#endif + return false; +} -- cgit v1.2.3