From: sparky4 Date: Wed, 15 Jul 2015 12:36:31 +0000 (-0500) Subject: ok.... damn.... X-Git-Url: http://4ch.mooo.com/gitweb/?a=commitdiff_plain;h=dcbe6cfe6b0cceeedcf97b66049d56379908e6b6;p=16.git ok.... damn.... new file: 16/ID_SD.C new file: 16/ID_SD.EQU new file: 16/ID_SD.H new file: 16/ID_SD_A.ASM new file: 16/ID_SD_A.BAK --- diff --git a/16/ID_SD.C b/16/ID_SD.C new file mode 100644 index 00000000..60136b74 --- /dev/null +++ b/16/ID_SD.C @@ -0,0 +1,2367 @@ +// +// 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: +// SoundSourcePresent - Sound Source thingie present? +// 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? +// + +#pragma hdrstop // Wierdo thing with MUSE + +#include + +#ifdef _MUSE_ // Will be defined in ID_Types.h +#include "ID_SD.h" +#else +#include "ID_HEADS.H" +#endif +#pragma hdrstop +#pragma warn -pia + +#ifdef nil +#undef nil +#endif +#define nil 0 + +#define SDL_SoundFinished() {SoundNumber = SoundPriority = 0;} + +// Macros for SoundBlaster stuff +#define sbOut(n,b) outportb((n) + sbLocation,b) +#define sbIn(n) inportb((n) + sbLocation) +#define sbWriteDelay() while (sbIn(sbWriteStat) & 0x80); +#define sbReadDelay() while (sbIn(sbDataAvail) & 0x80); + +// Macros for AdLib stuff +#define selreg(n) outportb(alFMAddr,n) +#define writereg(n) outportb(alFMData,n) +#define readstat() inportb(alFMStatus) + +// Imports from ID_SD_A.ASM +extern void SDL_SetDS(void), + SDL_IndicatePC(boolean on); +extern void interrupt SDL_t0ExtremeAsmService(void), + SDL_t0FastAsmService(void), + SDL_t0SlowAsmService(void); + +// Global variables + boolean SoundSourcePresent, + AdLibPresent, + SoundBlasterPresent,SBProPresent, + NeedsDigitized,NeedsMusic, + SoundPositioned; + SDMode SoundMode; + SMMode MusicMode; + SDSMode DigiMode; + longword TimeCount; + word HackCount; + word *SoundTable; // Really * _seg *SoundTable, but that don't work + boolean ssIsTandy; + word ssPort = 2; + int DigiMap[LASTSOUND]; + +// Internal variables +static boolean SD_Started; + boolean nextsoundpos; + longword TimerDivisor,TimerCount; +static char *ParmStrings[] = + { + "noal", + "nosb", + "nopro", + "noss", + "sst", + "ss1", + "ss2", + "ss3", + nil + }; +static void (*SoundUserHook)(void); + soundnames SoundNumber,DigiNumber; + word SoundPriority,DigiPriority; + int LeftPosition,RightPosition; + void interrupt (*t0OldService)(void); + long LocalTime; + word TimerRate; + + word NumDigi,DigiLeft,DigiPage; + word _seg *DigiList; + word DigiLastStart,DigiLastEnd; + boolean DigiPlaying; +static boolean DigiMissed,DigiLastSegment; +static memptr DigiNextAddr; +static word DigiNextLen; + +// SoundBlaster variables +static boolean sbNoCheck,sbNoProCheck; +static volatile boolean sbSamplePlaying; +static byte sbOldIntMask = -1; +static volatile byte huge *sbNextSegPtr; +static byte sbDMA = 1, + sbDMAa1 = 0x83,sbDMAa2 = 2,sbDMAa3 = 3, + sba1Vals[] = {0x87,0x83,0,0x82}, + sba2Vals[] = {0,2,0,6}, + sba3Vals[] = {1,3,0,7}; +static int sbLocation = -1,sbInterrupt = 7,sbIntVec = 0xf, + sbIntVectors[] = {-1,-1,0xa,0xb,-1,0xd,-1,0xf,-1,-1,-1}; +static volatile longword sbNextSegLen; +static volatile SampledSound huge *sbSamples; +static void interrupt (*sbOldIntHand)(void); +static byte sbpOldFMMix,sbpOldVOCMix; + +// SoundSource variables + boolean ssNoCheck; + boolean ssActive; + word ssControl,ssStatus,ssData; + byte ssOn,ssOff; + volatile byte far *ssSample; + volatile longword ssLengthLeft; + +// PC Sound variables + volatile byte pcLastSample,far *pcSound; + longword pcLengthLeft; + word pcSoundLookup[255]; + +// AdLib variables + boolean alNoCheck; + byte far *alSound; + word alBlock; + longword alLengthLeft; + longword alTimeCount; + Instrument alZeroInst; + +// This table maps channel numbers to carrier and modulator op cells +static byte carriers[9] = { 3, 4, 5,11,12,13,19,20,21}, + modifiers[9] = { 0, 1, 2, 8, 9,10,16,17,18}, +// This table maps percussive voice numbers to op cells + pcarriers[5] = {19,0xff,0xff,0xff,0xff}, + pmodifiers[5] = {16,17,18,20,21}; + +// Sequencer variables + boolean sqActive; +static word alFXReg; +static ActiveTrack *tracks[sqMaxTracks], + mytracks[sqMaxTracks]; +static word sqMode,sqFadeStep; + word far *sqHack,far *sqHackPtr,sqHackLen,sqHackSeqLen; + long sqHackTime; + +// Internal routines + void SDL_DigitizedDone(void); + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_SetTimer0() - Sets system timer 0 to the specified speed +// +/////////////////////////////////////////////////////////////////////////// +#pragma argsused +static void +SDL_SetTimer0(word speed) +{ +#ifndef TPROF // If using Borland's profiling, don't screw with the timer +asm pushf +asm cli + + outportb(0x43,0x36); // Change timer 0 + outportb(0x40,speed); + outportb(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 popf +#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) + { + setvect(8,isr); + SDL_SetIntsPerSec(rate); + TimerRate = rate; + } +} + +// +// SoundBlaster code +// + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_SBStopSample() - Stops any active sampled sound and causes DMA +// requests from the SoundBlaster to cease +// +/////////////////////////////////////////////////////////////////////////// +#ifdef _MUSE_ +void +#else +static void +#endif +SDL_SBStopSample(void) +{ + byte is; + +asm pushf +asm cli + + if (sbSamplePlaying) + { + sbSamplePlaying = false; + + sbWriteDelay(); + sbOut(sbWriteCmd,0xd0); // Turn off DSP DMA + + is = inportb(0x21); // Restore interrupt mask bit + if (sbOldIntMask & (1 << sbInterrupt)) + is |= (1 << sbInterrupt); + else + is &= ~(1 << sbInterrupt); + outportb(0x21,is); + } + +asm popf +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_SBPlaySeg() - Plays a chunk of sampled sound on the SoundBlaster +// Insures that the chunk doesn't cross a bank boundary, programs the DMA +// controller, and tells the SB to start doing DMA requests for DAC +// +/////////////////////////////////////////////////////////////////////////// +static longword +SDL_SBPlaySeg(volatile byte huge *data,longword length) +{ + unsigned datapage; + longword dataofs,uselen; + + uselen = length; + datapage = FP_SEG(data) >> 12; + dataofs = ((FP_SEG(data) & 0xfff) << 4) + FP_OFF(data); + if (dataofs >= 0x10000) + { + datapage++; + dataofs -= 0x10000; + } + + if (dataofs + uselen > 0x10000) + uselen = 0x10000 - dataofs; + + uselen--; + + // Program the DMA controller +asm pushf +asm cli + outportb(0x0a,sbDMA | 4); // Mask off DMA on channel sbDMA + outportb(0x0c,0); // Clear byte ptr flip-flop to lower byte + outportb(0x0b,0x49); // Set transfer mode for D/A conv + outportb(sbDMAa2,(byte)dataofs); // Give LSB of address + outportb(sbDMAa2,(byte)(dataofs >> 8)); // Give MSB of address + outportb(sbDMAa1,(byte)datapage); // Give page of address + outportb(sbDMAa3,(byte)uselen); // Give LSB of length + outportb(sbDMAa3,(byte)(uselen >> 8)); // Give MSB of length + outportb(0x0a,sbDMA); // Re-enable DMA on channel sbDMA + + // Start playing the thing + sbWriteDelay(); + sbOut(sbWriteCmd,0x14); + sbWriteDelay(); + sbOut(sbWriteData,(byte)uselen); + sbWriteDelay(); + sbOut(sbWriteData,(byte)(uselen >> 8)); +asm popf + + return(uselen + 1); +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_SBService() - Services the SoundBlaster DMA interrupt +// +/////////////////////////////////////////////////////////////////////////// +static void interrupt +SDL_SBService(void) +{ + longword used; + + sbIn(sbDataAvail); // Ack interrupt to SB + + if (sbNextSegPtr) + { + used = SDL_SBPlaySeg(sbNextSegPtr,sbNextSegLen); + if (sbNextSegLen <= used) + sbNextSegPtr = nil; + else + { + sbNextSegPtr += used; + sbNextSegLen -= used; + } + } + else + { + SDL_SBStopSample(); + SDL_DigitizedDone(); + } + + outportb(0x20,0x20); // Ack interrupt +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_SBPlaySample() - Plays a sampled sound on the SoundBlaster. Sets up +// DMA to play the sound +// +/////////////////////////////////////////////////////////////////////////// +#ifdef _MUSE_ +void +#else +static void +#endif +SDL_SBPlaySample(byte huge *data,longword len) +{ + longword used; + + SDL_SBStopSample(); + +asm pushf +asm cli + + used = SDL_SBPlaySeg(data,len); + if (len <= used) + sbNextSegPtr = nil; + else + { + sbNextSegPtr = data + used; + sbNextSegLen = len - used; + } + + // Save old interrupt status and unmask ours + sbOldIntMask = inportb(0x21); + outportb(0x21,sbOldIntMask & ~(1 << sbInterrupt)); + + sbWriteDelay(); + sbOut(sbWriteCmd,0xd4); // Make sure DSP DMA is enabled + + sbSamplePlaying = true; + +asm popf +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_PositionSBP() - Sets the attenuation levels for the left and right +// channels by using the mixer chip on the SB Pro. This hits a hole in +// the address map for normal SBs. +// +/////////////////////////////////////////////////////////////////////////// +static void +SDL_PositionSBP(int leftpos,int rightpos) +{ + byte v; + + if (!SBProPresent) + return; + + leftpos = 15 - leftpos; + rightpos = 15 - rightpos; + v = ((leftpos & 0x0f) << 4) | (rightpos & 0x0f); + +asm pushf +asm cli + + sbOut(sbpMixerAddr,sbpmVoiceVol); + sbOut(sbpMixerData,v); + +asm popf +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_CheckSB() - Checks to see if a SoundBlaster resides at a +// particular I/O location +// +/////////////////////////////////////////////////////////////////////////// +static boolean +SDL_CheckSB(int port) +{ + int i; + + sbLocation = port << 4; // Initialize stuff for later use + + sbOut(sbReset,true); // Reset the SoundBlaster DSP +asm mov dx,0x388 // Wait >4usec +asm in al, dx +asm in al, dx +asm in al, dx +asm in al, dx +asm in al, dx +asm in al, dx +asm in al, dx +asm in al, dx +asm in al, dx + + sbOut(sbReset,false); // Turn off sb DSP reset +asm mov dx,0x388 // Wait >100usec +asm mov cx,100 +usecloop: +asm in al,dx +asm loop usecloop + + for (i = 0;i < 100;i++) + { + if (sbIn(sbDataAvail) & 0x80) // If data is available... + { + if (sbIn(sbReadData) == 0xaa) // If it matches correct value + return(true); + else + { + sbLocation = -1; // Otherwise not a SoundBlaster + return(false); + } + } + } + sbLocation = -1; // Retry count exceeded - fail + return(false); +} + +/////////////////////////////////////////////////////////////////////////// +// +// Checks to see if a SoundBlaster is in the system. If the port passed is +// -1, then it scans through all possible I/O locations. If the port +// passed is 0, then it uses the default (2). If the port is >0, then +// it just passes it directly to SDL_CheckSB() +// +/////////////////////////////////////////////////////////////////////////// +static boolean +SDL_DetectSoundBlaster(int port) +{ + int i; + + if (port == 0) // If user specifies default, use 2 + port = 2; + if (port == -1) + { + if (SDL_CheckSB(2)) // Check default before scanning + return(true); + + if (SDL_CheckSB(4)) // Check other SB Pro location before scan + return(true); + + for (i = 1;i <= 6;i++) // Scan through possible SB locations + { + if ((i == 2) || (i == 4)) + continue; + + if (SDL_CheckSB(i)) // If found at this address, + return(true); // return success + } + return(false); // All addresses failed, return failure + } + else + return(SDL_CheckSB(port)); // User specified address or default +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_SBSetDMA() - Sets the DMA channel to be used by the SoundBlaster +// code. Sets up sbDMA, and sbDMAa1-sbDMAa3 (used by SDL_SBPlaySeg()). +// +/////////////////////////////////////////////////////////////////////////// +void +SDL_SBSetDMA(byte channel) +{ + if (channel > 3) + Quit("SDL_SBSetDMA() - invalid SoundBlaster DMA channel"); + + sbDMA = channel; + sbDMAa1 = sba1Vals[channel]; + sbDMAa2 = sba2Vals[channel]; + sbDMAa3 = sba3Vals[channel]; +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_StartSB() - Turns on the SoundBlaster +// +/////////////////////////////////////////////////////////////////////////// +static void +SDL_StartSB(void) +{ + byte timevalue,test; + + sbIntVec = sbIntVectors[sbInterrupt]; + if (sbIntVec < 0) + Quit("SDL_StartSB: Illegal or unsupported interrupt number for SoundBlaster"); + + sbOldIntHand = getvect(sbIntVec); // Get old interrupt handler + setvect(sbIntVec,SDL_SBService); // Set mine + + sbWriteDelay(); + sbOut(sbWriteCmd,0xd1); // Turn on DSP speaker + + // Set the SoundBlaster DAC time constant for 7KHz + timevalue = 256 - (1000000 / 7000); + sbWriteDelay(); + sbOut(sbWriteCmd,0x40); + sbWriteDelay(); + sbOut(sbWriteData,timevalue); + + SBProPresent = false; + if (sbNoProCheck) + return; + + // Check to see if this is a SB Pro + sbOut(sbpMixerAddr,sbpmFMVol); + sbpOldFMMix = sbIn(sbpMixerData); + sbOut(sbpMixerData,0xbb); + test = sbIn(sbpMixerData); + if (test == 0xbb) + { + // Boost FM output levels to be equivilent with digitized output + sbOut(sbpMixerData,0xff); + test = sbIn(sbpMixerData); + if (test == 0xff) + { + SBProPresent = true; + + // Save old Voice output levels (SB Pro) + sbOut(sbpMixerAddr,sbpmVoiceVol); + sbpOldVOCMix = sbIn(sbpMixerData); + + // Turn SB Pro stereo DAC off + sbOut(sbpMixerAddr,sbpmControl); + sbOut(sbpMixerData,0); // 0=off,2=on + } + } +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_ShutSB() - Turns off the SoundBlaster +// +/////////////////////////////////////////////////////////////////////////// +static void +SDL_ShutSB(void) +{ + SDL_SBStopSample(); + + if (SBProPresent) + { + // Restore FM output levels (SB Pro) + sbOut(sbpMixerAddr,sbpmFMVol); + sbOut(sbpMixerData,sbpOldFMMix); + + // Restore Voice output levels (SB Pro) + sbOut(sbpMixerAddr,sbpmVoiceVol); + sbOut(sbpMixerData,sbpOldVOCMix); + } + + setvect(sbIntVec,sbOldIntHand); // Set vector back +} + +// Sound Source Code + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_SSStopSample() - Stops a sample playing on the Sound Source +// +/////////////////////////////////////////////////////////////////////////// +#ifdef _MUSE_ +void +#else +static void +#endif +SDL_SSStopSample(void) +{ +asm pushf +asm cli + + (long)ssSample = 0; + +asm popf +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_SSService() - Handles playing the next sample on the Sound Source +// +/////////////////////////////////////////////////////////////////////////// +static void +SDL_SSService(void) +{ + boolean gotit; + byte v; + + while (ssSample) + { + asm mov dx,[ssStatus] // Check to see if FIFO is currently empty + asm in al,dx + asm test al,0x40 + asm jnz done // Nope - don't push any more data out + + v = *ssSample++; + if (!(--ssLengthLeft)) + { + (long)ssSample = 0; + SDL_DigitizedDone(); + } + + asm mov dx,[ssData] // Pump the value out + asm mov al,[v] + asm out dx,al + + asm mov dx,[ssControl] // Pulse printer select + asm mov al,[ssOff] + asm out dx,al + asm push ax + asm pop ax + asm mov al,[ssOn] + asm out dx,al + + asm push ax // Delay a short while + asm pop ax + asm push ax + asm pop ax + } +done:; +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_SSPlaySample() - Plays the specified sample on the Sound Source +// +/////////////////////////////////////////////////////////////////////////// +#ifdef _MUSE_ +void +#else +static void +#endif +SDL_SSPlaySample(byte huge *data,longword len) +{ +asm pushf +asm cli + + ssLengthLeft = len; + ssSample = (volatile byte far *)data; + +asm popf +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_StartSS() - Sets up for and turns on the Sound Source +// +/////////////////////////////////////////////////////////////////////////// +static void +SDL_StartSS(void) +{ + if (ssPort == 3) + ssControl = 0x27a; // If using LPT3 + else if (ssPort == 2) + ssControl = 0x37a; // If using LPT2 + else + ssControl = 0x3be; // If using LPT1 + ssStatus = ssControl - 1; + ssData = ssStatus - 1; + + ssOn = 0x04; + if (ssIsTandy) + ssOff = 0x0e; // Tandy wierdness + else + ssOff = 0x0c; // For normal machines + + outportb(ssControl,ssOn); // Enable SS +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_ShutSS() - Turns off the Sound Source +// +/////////////////////////////////////////////////////////////////////////// +static void +SDL_ShutSS(void) +{ + outportb(ssControl,ssOff); +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_CheckSS() - Checks to see if a Sound Source is present at the +// location specified by the sound source variables +// +/////////////////////////////////////////////////////////////////////////// +static boolean +SDL_CheckSS(void) +{ + boolean present = false; + longword lasttime; + + // Turn the Sound Source on and wait awhile (4 ticks) + SDL_StartSS(); + + lasttime = TimeCount; + while (TimeCount < lasttime + 4) + ; + +asm mov dx,[ssStatus] // Check to see if FIFO is currently empty +asm in al,dx +asm test al,0x40 +asm jnz checkdone // Nope - Sound Source not here + +asm mov cx,32 // Force FIFO overflow (FIFO is 16 bytes) +outloop: +asm mov dx,[ssData] // Pump a neutral value out +asm mov al,0x80 +asm out dx,al + +asm mov dx,[ssControl] // Pulse printer select +asm mov al,[ssOff] +asm out dx,al +asm push ax +asm pop ax +asm mov al,[ssOn] +asm out dx,al + +asm push ax // Delay a short while before we do this again +asm pop ax +asm push ax +asm pop ax + +asm loop outloop + +asm mov dx,[ssStatus] // Is FIFO overflowed now? +asm in al,dx +asm test al,0x40 +asm jz checkdone // Nope, still not - Sound Source not here + + present = true; // Yes - it's here! + +checkdone: + SDL_ShutSS(); + return(present); +} + +static boolean +SDL_DetectSoundSource(void) +{ + for (ssPort = 1;ssPort <= 3;ssPort++) + if (SDL_CheckSS()) + return(true); + return(false); +} + +// +// PC Sound code +// + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_PCPlaySample() - Plays the specified sample on the PC speaker +// +/////////////////////////////////////////////////////////////////////////// +#ifdef _MUSE_ +void +#else +static void +#endif +SDL_PCPlaySample(byte huge *data,longword len) +{ +asm pushf +asm cli + + SDL_IndicatePC(true); + + pcLengthLeft = len; + pcSound = (volatile byte far *)data; + +asm popf +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_PCStopSample() - Stops a sample playing on the PC speaker +// +/////////////////////////////////////////////////////////////////////////// +#ifdef _MUSE_ +void +#else +static void +#endif +SDL_PCStopSample(void) +{ +asm pushf +asm cli + + (long)pcSound = 0; + + SDL_IndicatePC(false); + +asm in al,0x61 // Turn the speaker off +asm and al,0xfd // ~2 +asm out 0x61,al + +asm popf +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_PCPlaySound() - Plays the specified sound on the PC speaker +// +/////////////////////////////////////////////////////////////////////////// +#ifdef _MUSE_ +void +#else +static void +#endif +SDL_PCPlaySound(PCSound far *sound) +{ +asm pushf +asm cli + + pcLastSample = -1; + pcLengthLeft = sound->common.length; + pcSound = sound->data; + +asm popf +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_PCStopSound() - Stops the current sound playing on the PC Speaker +// +/////////////////////////////////////////////////////////////////////////// +#ifdef _MUSE_ +void +#else +static void +#endif +SDL_PCStopSound(void) +{ +asm pushf +asm cli + + (long)pcSound = 0; + +asm in al,0x61 // Turn the speaker off +asm and al,0xfd // ~2 +asm out 0x61,al + +asm popf +} + +#if 0 +/////////////////////////////////////////////////////////////////////////// +// +// SDL_PCService() - Handles playing the next sample in a PC sound +// +/////////////////////////////////////////////////////////////////////////// +static void +SDL_PCService(void) +{ + byte s; + word t; + + if (pcSound) + { + s = *pcSound++; + if (s != pcLastSample) + { + asm pushf + asm cli + + pcLastSample = s; + if (s) // We have a frequency! + { + t = pcSoundLookup[s]; + asm mov bx,[t] + + asm mov al,0xb6 // Write to channel 2 (speaker) timer + asm out 43h,al + asm mov al,bl + asm out 42h,al // Low byte + asm mov al,bh + asm out 42h,al // High byte + + asm in al,0x61 // Turn the speaker & gate on + asm or al,3 + asm out 0x61,al + } + else // Time for some silence + { + asm in al,0x61 // Turn the speaker & gate off + asm and al,0xfc // ~3 + asm out 0x61,al + } + + asm popf + } + + if (!(--pcLengthLeft)) + { + SDL_PCStopSound(); + SDL_SoundFinished(); + } + } +} +#endif + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_ShutPC() - Turns off the pc speaker +// +/////////////////////////////////////////////////////////////////////////// +static void +SDL_ShutPC(void) +{ +asm pushf +asm cli + + pcSound = 0; + +asm in al,0x61 // Turn the speaker & gate off +asm and al,0xfc // ~3 +asm out 0x61,al + +asm popf +} + +// +// Stuff for digitized sounds +// +memptr +SDL_LoadDigiSegment(word page) +{ + memptr addr; + +#if 0 // for debugging +asm mov dx,STATUS_REGISTER_1 +asm in al,dx +asm mov dx,ATR_INDEX +asm mov al,ATR_OVERSCAN +asm out dx,al +asm mov al,10 // bright green +asm out dx,al +#endif + + addr = PM_GetSoundPage(page); + PM_SetPageLock(PMSoundStart + page,pml_Locked); + +#if 0 // for debugging +asm mov dx,STATUS_REGISTER_1 +asm in al,dx +asm mov dx,ATR_INDEX +asm mov al,ATR_OVERSCAN +asm out dx,al +asm mov al,3 // blue +asm out dx,al +asm mov al,0x20 // normal +asm out dx,al +#endif + + return(addr); +} + +void +SDL_PlayDigiSegment(memptr addr,word len) +{ + switch (DigiMode) + { + case sds_PC: + SDL_PCPlaySample(addr,len); + break; + case sds_SoundSource: + SDL_SSPlaySample(addr,len); + break; + case sds_SoundBlaster: + SDL_SBPlaySample(addr,len); + break; + } +} + +void +SD_StopDigitized(void) +{ + int i; + +asm pushf +asm cli + + DigiLeft = 0; + DigiNextAddr = nil; + DigiNextLen = 0; + DigiMissed = false; + DigiPlaying = false; + DigiNumber = DigiPriority = 0; + SoundPositioned = false; + if ((DigiMode == sds_PC) && (SoundMode == sdm_PC)) + SDL_SoundFinished(); + + switch (DigiMode) + { + case sds_PC: + SDL_PCStopSample(); + break; + case sds_SoundSource: + SDL_SSStopSample(); + break; + case sds_SoundBlaster: + SDL_SBStopSample(); + break; + } + +asm popf + + for (i = DigiLastStart;i < DigiLastEnd;i++) + PM_SetPageLock(i + PMSoundStart,pml_Unlocked); + DigiLastStart = 1; + DigiLastEnd = 0; +} + +void +SD_Poll(void) +{ + if (DigiLeft && !DigiNextAddr) + { + DigiNextLen = (DigiLeft >= PMPageSize)? PMPageSize : (DigiLeft % PMPageSize); + DigiLeft -= DigiNextLen; + if (!DigiLeft) + DigiLastSegment = true; + DigiNextAddr = SDL_LoadDigiSegment(DigiPage++); + } + if (DigiMissed && DigiNextAddr) + { + SDL_PlayDigiSegment(DigiNextAddr,DigiNextLen); + DigiNextAddr = nil; + DigiMissed = false; + if (DigiLastSegment) + { + DigiPlaying = false; + DigiLastSegment = false; + } + } + SDL_SetTimerSpeed(); +} + +void +SD_SetPosition(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); + break; + } +} + +void +SD_PlayDigitized(word which,int leftpos,int rightpos) +{ + word len; + memptr addr; + + if (!DigiMode) + return; + + SD_StopDigitized(); + if (which >= NumDigi) + Quit("SD_PlayDigitized: bad sound number"); + + SD_SetPosition(leftpos,rightpos); + + DigiPage = DigiList[(which * 2) + 0]; + DigiLeft = DigiList[(which * 2) + 1]; + + DigiLastStart = DigiPage; + DigiLastEnd = DigiPage + ((DigiLeft + (PMPageSize - 1)) / PMPageSize); + + len = (DigiLeft >= PMPageSize)? PMPageSize : (DigiLeft % PMPageSize); + addr = SDL_LoadDigiSegment(DigiPage++); + + DigiPlaying = true; + DigiLastSegment = false; + + SDL_PlayDigiSegment(addr,len); + DigiLeft -= len; + if (!DigiLeft) + DigiLastSegment = true; + + SD_Poll(); +} + +void +SDL_DigitizedDone(void) +{ + if (DigiNextAddr) + { + SDL_PlayDigiSegment(DigiNextAddr,DigiNextLen); + DigiNextAddr = nil; + DigiMissed = false; + } + else + { + if (DigiLastSegment) + { + DigiPlaying = false; + DigiLastSegment = false; + if ((DigiMode == sds_PC) && (SoundMode == sdm_PC)) + { + SDL_SoundFinished(); + } + else + DigiNumber = DigiPriority = 0; + SoundPositioned = false; + } + else + DigiMissed = true; + } +} + +void +SD_SetDigiDevice(SDSMode mode) +{ + boolean devicenotpresent; + + if (mode == DigiMode) + return; + + SD_StopDigitized(); + + devicenotpresent = false; + switch (mode) + { + case sds_SoundBlaster: + if (!SoundBlasterPresent) + { + if (SoundSourcePresent) + mode = sds_SoundSource; + else + devicenotpresent = true; + } + break; + case sds_SoundSource: + if (!SoundSourcePresent) + devicenotpresent = true; + break; + } + + if (!devicenotpresent) + { + if (DigiMode == sds_SoundSource) + SDL_ShutSS(); + + DigiMode = mode; + + if (mode == sds_SoundSource) + SDL_StartSS(); + + SDL_SetTimerSpeed(); + } +} + +void +SDL_SetupDigi(void) +{ + memptr list; + word far *p, + pg; + int i; + + PM_UnlockMainMem(); + MM_GetPtr(&list,PMPageSize); + PM_CheckMainMem(); + p = (word far *)MK_FP(PM_GetPage(ChunksInFile - 1),0); + _fmemcpy((void far *)list,(void far *)p,PMPageSize); + pg = PMSoundStart; + for (i = 0;i < PMPageSize / (sizeof(word) * 2);i++,p += 2) + { + if (pg >= ChunksInFile - 1) + break; + pg += (p[1] + (PMPageSize - 1)) / PMPageSize; + } + PM_UnlockMainMem(); + MM_GetPtr((memptr *)&DigiList,i * sizeof(word) * 2); + _fmemcpy((void far *)DigiList,(void far *)list,i * sizeof(word) * 2); + MM_FreePtr(&list); + NumDigi = i; + + for (i = 0;i < LASTSOUND;i++) + DigiMap[i] = -1; +} + +// AdLib Code + +/////////////////////////////////////////////////////////////////////////// +// +// alOut(n,b) - Puts b in AdLib card register n +// +/////////////////////////////////////////////////////////////////////////// +void +alOut(byte n,byte b) +{ +asm pushf +asm cli + +asm mov dx,0x388 +asm mov al,[n] +asm out dx,al +asm in al,dx +asm in al,dx +asm in al,dx +asm in al,dx +asm in al,dx +asm in al,dx +asm inc dx +asm mov al,[b] +asm out dx,al + +asm popf + +asm dec dx +asm in al,dx +asm in al,dx +asm in al,dx +asm in al,dx +asm in al,dx +asm in al,dx +asm in al,dx +asm in al,dx +asm in al,dx +asm in al,dx + +asm in al,dx +asm in al,dx +asm in al,dx +asm in al,dx +asm in al,dx +asm in al,dx +asm in al,dx +asm in al,dx +asm in al,dx +asm in al,dx + +asm in al,dx +asm in al,dx +asm in al,dx +asm in al,dx +asm in al,dx +asm in al,dx +asm in al,dx +asm in al,dx +asm in al,dx +asm in al,dx + +asm in al,dx +asm in al,dx +asm in al,dx +asm in al,dx +asm in al,dx +} + +#if 0 +/////////////////////////////////////////////////////////////////////////// +// +// SDL_SetInstrument() - Puts an instrument into a generator +// +/////////////////////////////////////////////////////////////////////////// +static void +SDL_SetInstrument(int track,int which,Instrument far *inst,boolean percussive) +{ + byte c,m; + + if (percussive) + { + c = pcarriers[which]; + m = pmodifiers[which]; + } + else + { + c = carriers[which]; + m = modifiers[which]; + } + + tracks[track - 1]->inst = *inst; + tracks[track - 1]->percussive = percussive; + + 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); + + // Most percussive instruments only use one cell + if (c != 0xff) + { + 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); + } + + alOut(which + alFeedCon,inst->nConn); // DEBUG - I think this is right +} +#endif + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_ALStopSound() - Turns off any sound effects playing through the +// AdLib card +// +/////////////////////////////////////////////////////////////////////////// +#ifdef _MUSE_ +void +#else +static void +#endif +SDL_ALStopSound(void) +{ +asm pushf +asm cli + + (long)alSound = 0; + alOut(alFreqH + 0,0); + +asm popf +} + +static void +SDL_AlSetFXInst(Instrument far *inst) +{ + byte c,m; + + m = modifiers[0]; + c = carriers[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 +// alOut(alFeedCon,inst->nConn); + alOut(alFeedCon,0); +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_ALPlaySound() - Plays the specified sound on the AdLib card +// +/////////////////////////////////////////////////////////////////////////// +#ifdef _MUSE_ +void +#else +static void +#endif +SDL_ALPlaySound(AdLibSound far *sound) +{ + Instrument far *inst; + byte huge *data; + + SDL_ALStopSound(); + +asm pushf +asm cli + + alLengthLeft = sound->common.length; + data = sound->data; + data++; + data--; + alSound = (byte far *)data; + alBlock = ((sound->block & 7) << 2) | 0x20; + inst = &sound->inst; + + if (!(inst->mSus | inst->cSus)) + { + asm popf + Quit("SDL_ALPlaySound() - Bad instrument"); + } + + SDL_AlSetFXInst(&alZeroInst); // DEBUG + SDL_AlSetFXInst(inst); + +asm popf +} + +#if 0 +/////////////////////////////////////////////////////////////////////////// +// +// SDL_ALSoundService() - Plays the next sample out through the AdLib card +// +/////////////////////////////////////////////////////////////////////////// +//static void +void +SDL_ALSoundService(void) +{ + byte s; + + if (alSound) + { + s = *alSound++; + if (!s) + alOut(alFreqH + 0,0); + else + { + alOut(alFreqL + 0,s); + alOut(alFreqH + 0,alBlock); + } + + if (!(--alLengthLeft)) + { + (long)alSound = 0; + alOut(alFreqH + 0,0); + SDL_SoundFinished(); + } + } +} +#endif + +#if 0 +void +SDL_ALService(void) +{ + byte a,v; + word w; + + if (!sqActive) + return; + + while (sqHackLen && (sqHackTime <= alTimeCount)) + { + w = *sqHackPtr++; + sqHackTime = alTimeCount + *sqHackPtr++; + asm mov dx,[w] + asm mov [a],dl + asm mov [v],dh + alOut(a,v); + sqHackLen -= 4; + } + alTimeCount++; + if (!sqHackLen) + { + sqHackPtr = (word far *)sqHack; + sqHackLen = sqHackSeqLen; + alTimeCount = sqHackTime = 0; + } +} +#endif + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_ShutAL() - Shuts down the AdLib card for sound effects +// +/////////////////////////////////////////////////////////////////////////// +static void +SDL_ShutAL(void) +{ +asm pushf +asm cli + + alOut(alEffects,0); + alOut(alFreqH + 0,0); + SDL_AlSetFXInst(&alZeroInst); + alSound = 0; + +asm popf +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_CleanAL() - Totally shuts down the AdLib card +// +/////////////////////////////////////////////////////////////////////////// +static void +SDL_CleanAL(void) +{ + int i; + +asm pushf +asm cli + + alOut(alEffects,0); + for (i = 1;i < 0xf5;i++) + alOut(i,0); + +asm popf +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_StartAL() - Starts up the AdLib card for sound effects +// +/////////////////////////////////////////////////////////////////////////// +static void +SDL_StartAL(void) +{ + alFXReg = 0; + alOut(alEffects,alFXReg); + SDL_AlSetFXInst(&alZeroInst); +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_DetectAdLib() - Determines if there's an AdLib (or SoundBlaster +// emulating an AdLib) present +// +/////////////////////////////////////////////////////////////////////////// +static boolean +SDL_DetectAdLib(void) +{ + byte status1,status2; + int i; + + alOut(4,0x60); // Reset T1 & T2 + alOut(4,0x80); // Reset IRQ + status1 = readstat(); + alOut(2,0xff); // Set timer 1 + alOut(4,0x21); // Start timer 1 +#if 0 + SDL_Delay(TimerDelay100); +#else +asm mov dx,0x388 +asm mov cx,100 +usecloop: +asm in al,dx +asm loop usecloop +#endif + + status2 = readstat(); + alOut(4,0x60); + alOut(4,0x80); + + if (((status1 & 0xe0) == 0x00) && ((status2 & 0xe0) == 0xc0)) + { + for (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); + } + else + return(false); +} + +#if 0 +/////////////////////////////////////////////////////////////////////////// +// +// SDL_t0Service() - My timer 0 ISR which handles the different timings and +// dispatches to whatever other routines are appropriate +// +/////////////////////////////////////////////////////////////////////////// +static void interrupt +SDL_t0Service(void) +{ +static word count = 1; + +#if 1 // for debugging +asm mov dx,STATUS_REGISTER_1 +asm in al,dx +asm mov dx,ATR_INDEX +asm mov al,ATR_OVERSCAN +asm out dx,al +asm mov al,4 // red +asm out dx,al +#endif + + HackCount++; + + if ((MusicMode == smm_AdLib) || (DigiMode == sds_SoundSource)) + { + SDL_ALService(); + SDL_SSService(); +// if (!(++count & 7)) + if (!(++count % 10)) + { + LocalTime++; + TimeCount++; + if (SoundUserHook) + SoundUserHook(); + } +// if (!(count & 3)) + if (!(count % 5)) + { + switch (SoundMode) + { + case sdm_PC: + SDL_PCService(); + break; + case sdm_AdLib: + SDL_ALSoundService(); + break; + } + } + } + else + { + if (!(++count & 1)) + { + LocalTime++; + TimeCount++; + if (SoundUserHook) + SoundUserHook(); + } + switch (SoundMode) + { + case sdm_PC: + SDL_PCService(); + break; + case sdm_AdLib: + SDL_ALSoundService(); + break; + } + } + +asm mov ax,[WORD PTR TimerCount] +asm add ax,[WORD PTR TimerDivisor] +asm mov [WORD PTR TimerCount],ax +asm jnc myack + t0OldService(); // If we overflow a word, time to call old int handler +asm jmp olddone +myack:; + outportb(0x20,0x20); // Ack the interrupt +olddone:; + +#if 1 // for debugging +asm mov dx,STATUS_REGISTER_1 +asm in al,dx +asm mov dx,ATR_INDEX +asm mov al,ATR_OVERSCAN +asm out dx,al +asm mov al,3 // blue +asm out dx,al +asm mov al,0x20 // normal +asm out dx,al +#endif +} +#endif + +//////////////////////////////////////////////////////////////////////////// +// +// 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 = 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(); + +#ifndef _MUSE_ + if ((mode == sdm_AdLib) && !AdLibPresent) + mode = sdm_PC; + + switch (mode) + { + case sdm_Off: + NeedsDigitized = false; + result = true; + break; + case sdm_PC: + tableoffset = STARTPCSOUNDS; + NeedsDigitized = false; + result = true; + break; + case sdm_AdLib: + if (AdLibPresent) + { + tableoffset = STARTADLIBSOUNDS; + NeedsDigitized = false; + result = true; + } + break; + } +#else + result = true; +#endif + + if (result && (mode != SoundMode)) + { + SDL_ShutDevice(); + SoundMode = mode; +#ifndef _MUSE_ + SoundTable = (word *)(&audiosegs[tableoffset]); +#endif + SDL_StartDevice(); + } + + SDL_SetTimerSpeed(); + + 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()) + ; + + switch (mode) + { + case smm_Off: + NeedsMusic = false; + result = true; + break; + case smm_AdLib: + if (AdLibPresent) + { + NeedsMusic = true; + result = true; + } + break; + } + + if (result) + MusicMode = mode; + + SDL_SetTimerSpeed(); + + return(result); +} + +/////////////////////////////////////////////////////////////////////////// +// +// 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; + + SDL_SetDS(); + + ssIsTandy = false; + ssNoCheck = false; + alNoCheck = false; + sbNoCheck = false; + sbNoProCheck = false; +#ifndef _MUSE_ + for (i = 1;i < _argc;i++) + { + switch (US_CheckParm(_argv[i],ParmStrings)) + { + case 0: // No AdLib detection + alNoCheck = true; + break; + case 1: // No SoundBlaster detection + sbNoCheck = true; + break; + case 2: // No SoundBlaster Pro detection + sbNoProCheck = true; + break; + case 3: + ssNoCheck = true; // No Sound Source detection + break; + case 4: // Tandy Sound Source handling + ssIsTandy = true; + break; + case 5: // Sound Source present at LPT1 + ssPort = 1; + ssNoCheck = SoundSourcePresent = true; + break; + case 6: // Sound Source present at LPT2 + ssPort = 2; + ssNoCheck = SoundSourcePresent = true; + break; + case 7: // Sound Source present at LPT3 + ssPort = 3; + ssNoCheck = SoundSourcePresent = true; + break; + } + } +#endif + + SoundUserHook = 0; + + t0OldService = getvect(8); // Get old timer 0 ISR + + LocalTime = TimeCount = alTimeCount = 0; + + SD_SetSoundMode(sdm_Off); + SD_SetMusicMode(smm_Off); + + if (!ssNoCheck) + SoundSourcePresent = SDL_DetectSoundSource(); + + if (!alNoCheck) + { + AdLibPresent = SDL_DetectAdLib(); + if (AdLibPresent && !sbNoCheck) + { + int port = -1; + char *env = getenv("BLASTER"); + if (env) + { + long temp; + while (*env) + { + while (isspace(*env)) + env++; + + switch (toupper(*env)) + { + case 'A': + temp = strtol(env + 1,&env,16); + if + ( + (temp >= 0x210) + && (temp <= 0x260) + && (!(temp & 0x00f)) + ) + port = (temp - 0x200) >> 4; + else + Quit("SD_Startup: Unsupported address value in BLASTER"); + break; + case 'I': + temp = strtol(env + 1,&env,10); + if + ( + (temp >= 0) + && (temp <= 10) + && (sbIntVectors[temp] != -1) + ) + { + sbInterrupt = temp; + sbIntVec = sbIntVectors[sbInterrupt]; + } + else + Quit("SD_Startup: Unsupported interrupt value in BLASTER"); + break; + case 'D': + temp = strtol(env + 1,&env,10); + if ((temp == 0) || (temp == 1) || (temp == 3)) + SDL_SBSetDMA(temp); + else + Quit("SD_Startup: Unsupported DMA value in BLASTER"); + break; + default: + while (isspace(*env)) + env++; + while (*env && !isspace(*env)) + env++; + break; + } + } + } + SoundBlasterPresent = SDL_DetectSoundBlaster(port); + } + } + + for (i = 0;i < 255;i++) + pcSoundLookup[i] = i * 60; + + if (SoundBlasterPresent) + SDL_StartSB(); + + SDL_SetupDigi(); + + SD_Started = true; +} + +/////////////////////////////////////////////////////////////////////////// +// +// SD_Default() - Sets up the default behaviour for the Sound Mgr whether +// the config file was present or not. +// +/////////////////////////////////////////////////////////////////////////// +void +SD_Default(boolean gotit,SDMode sd,SMMode sm) +{ + boolean gotsd,gotsm; + + gotsd = gotsm = gotit; + + if (gotsd) // Make sure requested sound hardware is available + { + switch (sd) + { + case sdm_AdLib: + gotsd = AdLibPresent; + break; + } + } + if (!gotsd) + { + if (AdLibPresent) + sd = sdm_AdLib; + else + sd = sdm_PC; + } + if (sd != SoundMode) + SD_SetSoundMode(sd); + + + if (gotsm) // Make sure requested music hardware is available + { + switch (sm) + { + case sdm_AdLib: + gotsm = AdLibPresent; + break; + } + } + if (!gotsm) + { + if (AdLibPresent) + sm = smm_AdLib; + } + if (sm != MusicMode) + SD_SetMusicMode(sm); +} + +/////////////////////////////////////////////////////////////////////////// +// +// 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(); + SDL_ShutDevice(); + SDL_CleanDevice(); + + if (SoundBlasterPresent) + SDL_ShutSB(); + + if (SoundSourcePresent) + SDL_ShutSS(); + + asm pushf + asm cli + + SDL_SetTimer0(0); + + setvect(8,t0OldService); + + asm popf + + SD_Started = false; +} + +/////////////////////////////////////////////////////////////////////////// +// +// SD_SetUserHook() - sets the routine that the Sound Mgr calls every 1/70th +// of a second from its timer 0 ISR +// +/////////////////////////////////////////////////////////////////////////// +void +SD_SetUserHook(void (* hook)(void)) +{ + SoundUserHook = hook; +} + +/////////////////////////////////////////////////////////////////////////// +// +// 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 far *s; + int lp,rp; + + lp = LeftPosition; + rp = RightPosition; + LeftPosition = 0; + RightPosition = 0; + + ispos = nextsoundpos; + nextsoundpos = false; + + if (sound == -1) + return(false); + + s = MK_FP(SoundTable[sound],0); + if ((SoundMode != sdm_Off) && !s) + Quit("SD_PlaySound() - Uncached sound"); + + if ((DigiMode != sds_Off) && (DigiMap[sound] != -1)) + { + if ((DigiMode == sds_PC) && (SoundMode == sdm_PC)) + { + if (s->priority < SoundPriority) + return(false); + + SDL_PCStopSound(); + + SD_PlayDigitized(DigiMap[sound],lp,rp); + SoundPositioned = ispos; + SoundNumber = sound; + SoundPriority = s->priority; + } + else + { + asm pushf + asm cli + if (DigiPriority && !DigiNumber) + { + asm popf + Quit("SD_PlaySound: Priority without a sound"); + } + asm popf + + if (s->priority < DigiPriority) + return(false); + + SD_PlayDigitized(DigiMap[sound],lp,rp); + SoundPositioned = ispos; + DigiNumber = sound; + DigiPriority = s->priority; + } + + return(true); + } + + if (SoundMode == sdm_Off) + return(false); + if (!s->length) + Quit("SD_PlaySound() - Zero length sound"); + if (s->priority < SoundPriority) + return(false); + + switch (SoundMode) + { + case sdm_PC: + SDL_PCPlaySound((void far *)s); + break; + case sdm_AdLib: + SDL_ALPlaySound((void far *)s); + break; + } + + SoundNumber = sound; + SoundPriority = s->priority; + + return(false); +} + +/////////////////////////////////////////////////////////////////////////// +// +// 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()) + ; +} + +/////////////////////////////////////////////////////////////////////////// +// +// SD_MusicOn() - turns on the sequencer +// +/////////////////////////////////////////////////////////////////////////// +void +SD_MusicOn(void) +{ + sqActive = true; +} + +/////////////////////////////////////////////////////////////////////////// +// +// SD_MusicOff() - turns off the sequencer and any playing notes +// +/////////////////////////////////////////////////////////////////////////// +void +SD_MusicOff(void) +{ + word i; + + + switch (MusicMode) + { + case smm_AdLib: + alFXReg = 0; + alOut(alEffects,0); + for (i = 0;i < sqMaxTracks;i++) + alOut(alFreqH + i + 1,0); + break; + } + sqActive = false; +} + +/////////////////////////////////////////////////////////////////////////// +// +// SD_StartMusic() - starts playing the music pointed to +// +/////////////////////////////////////////////////////////////////////////// +void +SD_StartMusic(MusicGroup far *music) +{ + SD_MusicOff(); +asm pushf +asm cli + + if (MusicMode == smm_AdLib) + { + sqHackPtr = sqHack = music->values; + sqHackSeqLen = sqHackLen = music->length; + sqHackTime = 0; + alTimeCount = 0; + SD_MusicOn(); + } + +asm popf +} + +/////////////////////////////////////////////////////////////////////////// +// +// 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 = false; + // DEBUG - not written + break; + default: + result = false; + } + + return(result); +} diff --git a/16/ID_SD.EQU b/16/ID_SD.EQU new file mode 100644 index 00000000..1b1d4e62 --- /dev/null +++ b/16/ID_SD.EQU @@ -0,0 +1,38 @@ +; +; ID_SD.EQU +; Id Sound Manager assembly equates +; + + INCLUDE 'ID_VL.EQU' ; For screen color debugging stuff + +; Modes +sdm_Off = 0 +sdm_PC = 1 +sdm_AdLib = 2 + +smm_Off = 0 +smm_AdLib = 1 + +sds_Off = 0 +sds_SoundSource = 1 +sds_SoundBlaster = 2 + +; Stuff for the PC speaker +pcTimer = 42h +pcTAccess = 43h +pcSpeaker = 61h +pcSpkBits = 3 + +; Stuff for the AdLib +; Operator registers +alChar = 20h +alScale = 40h +alAttack = 60h +alSus = 80h +alWave = 0e0h +; Channel registers +alFreqL = 0a0h +alFreqH = 0b0h +alFeedCon = 0c0h +; Global registers +alEffects = 0bdh diff --git a/16/ID_SD.H b/16/ID_SD.H new file mode 100644 index 00000000..1fa4c16f --- /dev/null +++ b/16/ID_SD.H @@ -0,0 +1,237 @@ +// +// ID Engine +// ID_SD.h - Sound Manager Header +// Version for Wolfenstein +// By Jason Blochowiak +// + +#ifndef __ID_SD__ +#define __ID_SD__ + +void alOut(byte n,byte b); + +#ifdef __DEBUG__ +#define __DEBUG_SoundMgr__ +#endif + +#define TickBase 70 // 70Hz per tick - used as a base for timer 0 + +typedef enum { + sdm_Off, + sdm_PC,sdm_AdLib, + } SDMode; +typedef enum { + smm_Off,smm_AdLib + } SMMode; +typedef enum { + sds_Off,sds_PC,sds_SoundSource,sds_SoundBlaster + } SDSMode; +typedef struct + { + longword length; + word priority; + } SoundCommon; + +// PC Sound stuff +#define pcTimer 0x42 +#define pcTAccess 0x43 +#define pcSpeaker 0x61 + +#define pcSpkBits 3 + +typedef struct + { + SoundCommon common; + byte data[1]; + } PCSound; + +// Registers for the Sound Blaster card - needs to be offset by n0 (0x10,0x20,0x30,0x40,0x50,0x60) +#define sbReset 0x206 // W +#define sbFMStatus 0x208 // R +#define sbFMAddr 0x208 // W +#define sbFMData 0x209 // W +#define sbReadData 0x20a // R +#define sbWriteCmd 0x20c // W +#define sbWriteData 0x20c // W +#define sbWriteStat 0x20c // R +#define sbDataAvail 0x20e // R + +// Registers for the Sound Blaster Pro card - needs to be offset by n0 (0x20 or 0x40) +#define sbpLFMStatus 0x200 // R +#define sbpLFMAddr 0x200 // W +#define sbpLFMData 0x201 // W +#define sbpRFMStatus 0x202 // R +#define sbpRFMAddr 0x202 // W +#define sbpRFMData 0x203 // W +#define sbpMixerAddr 0x204 // W +#define sbpMixerData 0x205 // RW +#define sbpCDData 0x210 // R +#define sbpCDCommand 0x210 // W +#define sbpCDStatus 0x211 // R +#define sbpCDReset 0x212 // W + +// SBPro Mixer addresses +#define sbpmReset 0x00 +#define sbpmVoiceVol 0x04 +#define sbpmMicMix 0x0a +#define sbpmFilterADC 0x0c +#define sbpmControl 0x0e +#define sbpmMasterVol 0x22 +#define sbpmFMVol 0x26 +#define sbpmCDVol 0x28 +#define sbpmLineVol 0x2e + +typedef struct + { + SoundCommon common; + word hertz; + byte bits, + reference, + data[1]; + } SampledSound; + +// Registers for the AdLib card +#define alFMStatus 0x388 // R +#define alFMAddr 0x388 // W +#define alFMData 0x389 // W + +// Register addresses +// Operator stuff +#define alChar 0x20 +#define alScale 0x40 +#define alAttack 0x60 +#define alSus 0x80 +#define alWave 0xe0 +// Channel stuff +#define alFreqL 0xa0 +#define alFreqH 0xb0 +#define alFeedCon 0xc0 +// Global stuff +#define alEffects 0xbd + +typedef struct + { + byte mChar,cChar, + mScale,cScale, + mAttack,cAttack, + mSus,cSus, + mWave,cWave, + nConn, + + // These are only for Muse - these bytes are really unused + voice, + mode, + unused[3]; + } Instrument; + +typedef struct + { + SoundCommon common; + Instrument inst; + byte block, + data[1]; + } AdLibSound; + +// +// Sequencing stuff +// +#define sqMaxTracks 10 +#define sqMaxMoods 1 // DEBUG + +#define sev_Null 0 // Does nothing +#define sev_NoteOff 1 // Turns a note off +#define sev_NoteOn 2 // Turns a note on +#define sev_NotePitch 3 // Sets the pitch of a currently playing note +#define sev_NewInst 4 // Installs a new instrument +#define sev_NewPerc 5 // Installs a new percussive instrument +#define sev_PercOn 6 // Turns a percussive note on +#define sev_PercOff 7 // Turns a percussive note off +#define sev_SeqEnd -1 // Terminates a sequence + +// Flags for MusicGroup.flags +#define sf_Melodic 0 +#define sf_Percussive 1 + +#if 1 +typedef struct + { + word length, + values[1]; + } MusicGroup; +#else +typedef struct + { + word flags, + count, + offsets[1]; + } MusicGroup; +#endif + +typedef struct + { + /* This part needs to be set up by the user */ + word mood,far *moods[sqMaxMoods]; + + /* The rest is set up by the code */ + Instrument inst; + boolean percussive; + word far *seq; + longword nextevent; + } ActiveTrack; + +#define sqmode_Normal 0 +#define sqmode_FadeIn 1 +#define sqmode_FadeOut 2 + +#define sqMaxFade 64 // DEBUG + + +// Global variables +extern boolean AdLibPresent, + SoundSourcePresent, + SoundBlasterPresent, + NeedsMusic, // For Caching Mgr + SoundPositioned; +extern SDMode SoundMode; +extern SDSMode DigiMode; +extern SMMode MusicMode; +extern boolean DigiPlaying; +extern int DigiMap[]; +extern longword TimeCount; // Global time in ticks + +// Function prototypes +extern void SD_Startup(void), + SD_Shutdown(void), + SD_Default(boolean gotit,SDMode sd,SMMode sm), + + SD_PositionSound(int leftvol,int rightvol); +extern boolean SD_PlaySound(soundnames sound); +extern void SD_SetPosition(int leftvol,int rightvol), + SD_StopSound(void), + SD_WaitSoundDone(void), + + SD_StartMusic(MusicGroup far *music), + SD_MusicOn(void), + SD_MusicOff(void), + SD_FadeOutMusic(void), + + SD_SetUserHook(void (*hook)(void)); +extern boolean SD_MusicPlaying(void), + SD_SetSoundMode(SDMode mode), + SD_SetMusicMode(SMMode mode); +extern word SD_SoundPlaying(void); + +extern void SD_SetDigiDevice(SDSMode), + SD_PlayDigitized(word which,int leftpos,int rightpos), + SD_StopDigitized(void), + SD_Poll(void); + +#ifdef _MUSE_ // MUSE Goes directly to the lower level routines +extern void SDL_PCPlaySound(PCSound far *sound), + SDL_PCStopSound(void), + SDL_ALPlaySound(AdLibSound far *sound), + SDL_ALStopSound(void); +#endif + +#endif + diff --git a/16/ID_SD_A.ASM b/16/ID_SD_A.ASM new file mode 100644 index 00000000..2de0ea61 --- /dev/null +++ b/16/ID_SD_A.ASM @@ -0,0 +1,572 @@ +; +; ID_SD_A.ASM +; Id Sound Manager assembly stuff + + .8086 + IDEAL + MODEL MEDIUM,C + JUMPS + + INCLUDE 'ID_SD.EQU' + +DEBUG = 0 + + EXTRN SDL_DigitizedDone:FAR + EXTRN alOut:FAR + +;============================================================================ + +DATASEG + + EXTRN sqActive:WORD + EXTRN ssSample:DWORD + EXTRN ssLengthLeft:WORD + EXTRN ssControl:WORD + EXTRN ssStatus:WORD + EXTRN ssData:WORD + EXTRN ssOn:BYTE + EXTRN ssOff:BYTE + + EXTRN pcSound:DWORD + EXTRN pcLengthLeft:WORD + EXTRN pcLastSample:BYTE + EXTRN pcSoundLookup:WORD + + EXTRN alSound:DWORD + EXTRN alBlock:WORD + EXTRN alLengthLeft:WORD + EXTRN alTimeCount:DWORD + + EXTRN sqHack:DWORD + EXTRN sqHackPtr:DWORD + EXTRN sqHackLen:WORD + EXTRN sqHackSeqLen:WORD + EXTRN sqHackTime:DWORD + + EXTRN HackCount:WORD + EXTRN TimeCount:WORD + EXTRN LocalTime:WORD + + EXTRN TimerCount:WORD + EXTRN TimerDivisor:WORD + EXTRN t0OldService:DWORD + + EXTRN SoundMode:WORD + EXTRN DigiMode:WORD + + EXTRN SoundNumber:WORD + EXTRN SoundPriority:WORD + +count_time dw ? +count_fx dw ? + +pcdtab db 00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b + db 00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b + db 00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b + db 00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b + db 00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b + db 00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b + db 00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b + db 00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b + db 10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b + db 10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b + db 10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b + db 10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b + db 10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b + db 10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b + db 10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b + db 10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b + + +;============================================================================ + +CODESEG + +MyDS dw ? + +pcindicate dw ? +extreme dw ? + + PROC SDL_SetDS + PUBLIC SDL_SetDS + + mov ax,ds + mov [cs:MyDS],ds + ret + + ENDP + +; +; COMMONSTART +; Macro used for common prefix code +; + MACRO COMMONSTART + IF DEBUG + push dx + push ax + mov dx,STATUS_REGISTER_1 + in al,dx + mov dx,ATR_INDEX + mov al,ATR_OVERSCAN + out dx,al + mov al,4 ; red + out dx,al + ENDIF + + push ds + push ax + + mov ds,[cs:MyDS] + inc [HackCount] + ENDM + +; +; DOFX +; Macro used to do the sound effects code +; + MACRO DOFX + les di,[pcSound] ; PC sound effects + mov ax,es + or ax,di + jz @@nopc ; nil pointer - no PC sound effect going + + mov bl,[es:di] ; Get the byte + inc [WORD PTR pcSound] ; Increment pointer + cmp [pcLastSample],bl ; Is this sample the same as last? + jz @@pcsame ; Yep - don't do anything + mov [pcLastSample],bl ; No, save it for next time + + or bl,bl + jz @@pcoff ; If 0, turn sounds off + xor bh,bh + shl bx,1 + mov bx,[pcSoundLookup+bx] ; Use byte as index into frequency table + + mov al,0b6h ; Write to channel 2 (speaker) timer + out pcTAccess,al + mov al,bl + out pcTimer,al ; Low byte + mov al,bh + out pcTimer,al ; High byte + + in al,pcSpeaker ; Turn the speaker & gate on + or al,3 + out pcSpeaker,al + + jmp @@pcsame + +@@pcoff: + in al,pcSpeaker ; Turn the speaker & gate off + and al,0fch ; ~3 + out pcSpeaker,al + +@@pcsame: + dec [pcLengthLeft] ; Decrement length + jnz @@nopc ; If not 0, we're not done with the sound + + mov ax,0 + mov [WORD PTR pcSound],ax ; Zero the pointer + mov [WORD PTR pcSound + 2],ax + mov [SoundNumber],ax ; Indicate no sound + mov [SoundPriority],ax ; with no priority + + in al,pcSpeaker ; Turn the speaker off + and al,0fdh ; ~2 + out pcSpeaker,al +@@nopc: + + les di,[alSound] ; AdLib sound effects + mov ax,es + or ax,di + jz @@noal ; nil pointer - no AdLib effect going + + xor ah,ah + mov al,[es:di] + or al,al + jz @@aldone + + CALL alOut C,alFreqL,ax + mov ax,[alBlock] + +@@aldone: + CALL alOut C,alFreqH,ax + inc [WORD PTR alSound] + dec [alLengthLeft] + jnz @@noal + + mov ax,0 + mov [WORD PTR alSound],ax ; Zero the pointer + mov [WORD PTR alSound + 2],ax + mov [SoundNumber],ax ; Indicate no sound + mov [SoundPriority],ax ; with no priority + CALL alOut C,alFreqH,ax ; Turn off the sound +@@noal: + + ENDM + +; +; +; + MACRO TIME + cmp [count_time],2 + jb @@notime + add [LocalTime],1 + adc [LocalTime+2],0 + add [TimeCount],1 + adc [TimeCount+2],0 + mov [count_time],0 +@@notime: + ENDM + +; +; COMMONEND +; Macro used for common suffix code +; + MACRO COMMONEND +@@fullexit: + pop es + ;popa + pop di + pop si + pop bp + pop [oldsp] + pop bx + pop dx + pop cx + pop ax + +@@nosave: + mov ax,[TimerDivisor] + add [TimerCount],ax + jnc @@myack + + pushf + call [t0OldService] + jmp @@out + +@@myack: + mov al,20h + out 20h,al + +@@out: + pop ax + pop ds + + IF DEBUG + mov dx,STATUS_REGISTER_1 + in al,dx + mov dx,ATR_INDEX + mov al,ATR_OVERSCAN + out dx,al + mov al,3 ; blue + out dx,al + mov al,20h ; normal + out dx,al + pop ax + pop dx + ENDIF + + iret + ENDM + +; +; SDL_IndicatePC +; + PROC SDL_IndicatePC on:WORD + PUBLIC SDL_IndicatePC + + mov ax,[on] + mov [cs:pcindicate],ax + ret + + ENDP + +; +; SDL_t0ExtremeAsmService +; Timer 0 ISR 7000Hz interrupts +; + PROC SDL_t0ExtremeAsmService + PUBLIC SDL_t0ExtremeAsmService + + push ax + mov al,[BYTE PTR cs:pcindicate] + or al,al + jz @@done + + push ds + push es + ;pusha + jmp @@skipme + oldsp dw ? +@@skipme: + mov [oldsp], sp + push ax + push cx + push dx + push bx + push [oldsp] + push bp + push si + push di + + mov ds,[cs:MyDS] + + les di,[pcSound] + mov ax,es + or ax,di + jz @@donereg ; nil pointer + + mov bl,[es:di] ; Get the byte + inc [WORD PTR pcSound] ; Increment pointer + + and bl,11100000b ; Nuke some of the precision (DEBUG - do this in the table) + + xor bh,bh + mov ah,[pcdtab+bx] ; Translate the byte + + in al,pcSpeaker + and al,11111100b + or al,ah + out pcSpeaker,al + + dec [pcLengthLeft] + jnz @@donereg + + mov [WORD PTR pcSound],0 ; We're done with this sample + mov [WORD PTR pcSound+2],0 + + in al,pcSpeaker + and al,11111100b + out pcSpeaker,al + + call SDL_DigitizedDone + +@@donereg: + ;popa + pop di + pop si + pop bp + pop [oldsp] + pop bx + pop dx + pop cx + pop ax + pop es + pop ds + +@@done: + inc [cs:extreme] + cmp [cs:extreme],10 + jae @@tofast + + mov al,20h + out 20h,al + pop ax + iret + +@@tofast: + mov [cs:extreme],0 + pop ax + +; jmp SDL_t0FastAsmService ; Drops through to SDL_t0FastAsmService + + ENDP + +; +; SDL_t0FastAsmService +; Timer 0 ISR for 700Hz interrupts +; + PROC SDL_t0FastAsmService + PUBLIC SDL_t0FastAsmService + + COMMONSTART + + inc [count_fx] ; Time to do PC/AdLib effects & time? + cmp [count_fx],5 + jae @@dofull + + mov ax,[sqActive] ; Is the sequencer active? + or ax,ax + jnz @@dofull + + mov ax,[WORD PTR ssSample] ; Is there a sample for the Sound Src? + or ax,[WORD PTR ssSample+2] + jz @@nosave + +@@dofull: + ;pusha + mov [oldsp], sp + push ax + push cx + push dx + push bx + push [oldsp] + push bp + push si + push di + push es + + cmp [count_fx],5 + jb @@nofx + mov [count_fx],0 + DOFX + + inc [count_time] + TIME +@@nofx: + + mov ax,[sqActive] + or ax,ax + jz @@nosq + + mov ax,[sqHackLen] + or ax,ax + jz @@sqdone + + les di,[sqHackPtr] +@@sqloop: + mov ax,[WORD PTR sqHackTime+2] + cmp ax,[WORD PTR alTimeCount+2] + ja @@sqdone + mov ax,[WORD PTR sqHackTime] + cmp ax,[WORD PTR alTimeCount] + ja @@sqdone + + mov ax,[es:di+2] ; Get time to next event + add ax,[WORD PTR alTimeCount] + mov [WORD PTR sqHackTime],ax + mov ax,[WORD PTR alTimeCount+2] + adc ax,0 + mov [WORD PTR sqHackTime+2],ax + + mov ax,[es:di] ; Get register/value pair + xor bh,bh + mov bl,ah + xor ah,ah + CALL alOut C,ax,bx + + add di,4 + mov [WORD PTR sqHackPtr],di + + sub [sqHackLen],4 + jnz @@sqloop + +@@sqdone: + add [WORD PTR alTimeCount],1 + adc [WORD PTR alTimeCount+2],0 + mov ax,[sqHackLen] + or ax,ax + jnz @@nosq + + mov ax,[WORD PTR sqHack] ; Copy pointer + mov [WORD PTR sqHackPtr],ax + mov ax,[WORD PTR sqHack+2] + mov [WORD PTR sqHackPtr+2],ax + + mov ax,[sqHackSeqLen] ; Copy length + mov [sqHackLen],ax + + mov ax,0 + mov [WORD PTR alTimeCount],ax ; Reset time counts + mov [WORD PTR alTimeCount+2],ax + mov [WORD PTR sqHackTime],ax + mov [WORD PTR sqHackTime+2],ax +@@nosq: + + les di,[ssSample] ; Get pointer to Sound Source sample + mov ax,es + or ax,di + jz @@ssdone ; If nil, skip this + +@@ssloop: + mov dx,[ssStatus] ; Check to see if FIFO has any empty slots + in al,dx + test al,40h + jnz @@ssdone ; Nope - don't push any more data out + + mov dx,[ssData] + mov al,[es:di] ; al = *ssSample + out dx,al ; Pump the value out + + mov dx,[ssControl] ; Pulse printer select + mov al,[ssOff] + out dx,al + push ax + pop ax + mov al,[ssOn] + out dx,al + + push ax ; Delay a short while + pop ax + + inc di + mov [WORD PTR ssSample],di ; ssSample++ + + dec [ssLengthLeft] + jnz @@ssloop + + mov [WORD PTR ssSample],0 ; We're done with this sample + mov [WORD PTR ssSample+2],0 + + call SDL_DigitizedDone +@@ssdone: + + COMMONEND + + ENDP + +; +; SDL_t0SlowAsmService +; Timer 0 ISR for 140Hz interrupts +; + PROC SDL_t0SlowAsmService + PUBLIC SDL_t0SlowAsmService + + IF DEBUG + push dx + push ax + mov dx,STATUS_REGISTER_1 + in al,dx + mov dx,ATR_INDEX + mov al,ATR_OVERSCAN + out dx,al + mov al,4 ; red + out dx,al + ENDIF + + push ds + push ax + + mov ds,[cs:MyDS] + + inc [count_time] + TIME + + mov ax,[WORD PTR pcSound] ; Is there a PC sound effect going? + or ax,[WORD PTR pcSound+2] + jnz @@dofull + + mov ax,[WORD PTR alSound] ; Is there an AdLib sound effect going? + or ax,[WORD PTR alSound+2] + jz @@nosave + +@@dofull: + ;pusha + mov [oldsp], sp + push ax + push cx + push dx + push bx + push [oldsp] + push bp + push si + push di + push es + + DOFX + + COMMONEND + + ENDP + + END diff --git a/16/ID_SD_A.BAK b/16/ID_SD_A.BAK new file mode 100644 index 00000000..34e1ac6f --- /dev/null +++ b/16/ID_SD_A.BAK @@ -0,0 +1,572 @@ +; +; ID_SD_A.ASM +; Id Sound Manager assembly stuff + + .8086 + IDEAL + MODEL MEDIUM,C + JUMPS + + INCLUDE 'ID_SD.EQU' + +DEBUG = 0 + + EXTRN SDL_DigitizedDone:FAR + EXTRN alOut:FAR + +;============================================================================ + +DATASEG + + EXTRN sqActive:WORD + EXTRN ssSample:DWORD + EXTRN ssLengthLeft:WORD + EXTRN ssControl:WORD + EXTRN ssStatus:WORD + EXTRN ssData:WORD + EXTRN ssOn:BYTE + EXTRN ssOff:BYTE + + EXTRN pcSound:DWORD + EXTRN pcLengthLeft:WORD + EXTRN pcLastSample:BYTE + EXTRN pcSoundLookup:WORD + + EXTRN alSound:DWORD + EXTRN alBlock:WORD + EXTRN alLengthLeft:WORD + EXTRN alTimeCount:DWORD + + EXTRN sqHack:DWORD + EXTRN sqHackPtr:DWORD + EXTRN sqHackLen:WORD + EXTRN sqHackSeqLen:WORD + EXTRN sqHackTime:DWORD + + EXTRN HackCount:WORD + EXTRN TimeCount:WORD + EXTRN LocalTime:WORD + + EXTRN TimerCount:WORD + EXTRN TimerDivisor:WORD + EXTRN t0OldService:DWORD + + EXTRN SoundMode:WORD + EXTRN DigiMode:WORD + + EXTRN SoundNumber:WORD + EXTRN SoundPriority:WORD + +count_time dw ? +count_fx dw ? + +pcdtab db 00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b + db 00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b + db 00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b + db 00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b + db 00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b + db 00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b + db 00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b + db 00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b + db 10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b + db 10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b + db 10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b + db 10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b + db 10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b + db 10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b + db 10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b + db 10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b + + +;============================================================================ + +CODESEG + +MyDS dw ? + +pcindicate dw ? +extreme dw ? + + PROC SDL_SetDS + PUBLIC SDL_SetDS + + mov ax,ds + mov [cs:MyDS],ds + ret + + ENDP + +; +; COMMONSTART +; Macro used for common prefix code +; + MACRO COMMONSTART + IF DEBUG + push dx + push ax + mov dx,STATUS_REGISTER_1 + in al,dx + mov dx,ATR_INDEX + mov al,ATR_OVERSCAN + out dx,al + mov al,4 ; red + out dx,al + ENDIF + + push ds + push ax + + mov ds,[cs:MyDS] + inc [HackCount] + ENDM + +; +; DOFX +; Macro used to do the sound effects code +; + MACRO DOFX + les di,[pcSound] ; PC sound effects + mov ax,es + or ax,di + jz @@nopc ; nil pointer - no PC sound effect going + + mov bl,[es:di] ; Get the byte + inc [WORD PTR pcSound] ; Increment pointer + cmp [pcLastSample],bl ; Is this sample the same as last? + jz @@pcsame ; Yep - don't do anything + mov [pcLastSample],bl ; No, save it for next time + + or bl,bl + jz @@pcoff ; If 0, turn sounds off + xor bh,bh + shl bx,1 + mov bx,[pcSoundLookup+bx] ; Use byte as index into frequency table + + mov al,0b6h ; Write to channel 2 (speaker) timer + out pcTAccess,al + mov al,bl + out pcTimer,al ; Low byte + mov al,bh + out pcTimer,al ; High byte + + in al,pcSpeaker ; Turn the speaker & gate on + or al,3 + out pcSpeaker,al + + jmp @@pcsame + +@@pcoff: + in al,pcSpeaker ; Turn the speaker & gate off + and al,0fch ; ~3 + out pcSpeaker,al + +@@pcsame: + dec [pcLengthLeft] ; Decrement length + jnz @@nopc ; If not 0, we're not done with the sound + + mov ax,0 + mov [WORD PTR pcSound],ax ; Zero the pointer + mov [WORD PTR pcSound + 2],ax + mov [SoundNumber],ax ; Indicate no sound + mov [SoundPriority],ax ; with no priority + + in al,pcSpeaker ; Turn the speaker off + and al,0fdh ; ~2 + out pcSpeaker,al +@@nopc: + + les di,[alSound] ; AdLib sound effects + mov ax,es + or ax,di + jz @@noal ; nil pointer - no AdLib effect going + + xor ah,ah + mov al,[es:di] + or al,al + jz @@aldone + + CALL alOut C,alFreqL,ax + mov ax,[alBlock] + +@@aldone: + CALL alOut C,alFreqH,ax + inc [WORD PTR alSound] + dec [alLengthLeft] + jnz @@noal + + mov ax,0 + mov [WORD PTR alSound],ax ; Zero the pointer + mov [WORD PTR alSound + 2],ax + mov [SoundNumber],ax ; Indicate no sound + mov [SoundPriority],ax ; with no priority + CALL alOut C,alFreqH,ax ; Turn off the sound +@@noal: + + ENDM + +; +; +; + MACRO TIME + cmp [count_time],2 + jb @@notime + add [LocalTime],1 + adc [LocalTime+2],0 + add [TimeCount],1 + adc [TimeCount+2],0 + mov [count_time],0 +@@notime: + ENDM + +; +; COMMONEND +; Macro used for common suffix code +; + MACRO COMMONEND +@@fullexit: + pop es + ;popa + pop di + pop si + pop bp + pop [regsp] + pop bx + pop dx + pop cx + pop ax + +@@nosave: + mov ax,[TimerDivisor] + add [TimerCount],ax + jnc @@myack + + pushf + call [t0OldService] + jmp @@out + +@@myack: + mov al,20h + out 20h,al + +@@out: + pop ax + pop ds + + IF DEBUG + mov dx,STATUS_REGISTER_1 + in al,dx + mov dx,ATR_INDEX + mov al,ATR_OVERSCAN + out dx,al + mov al,3 ; blue + out dx,al + mov al,20h ; normal + out dx,al + pop ax + pop dx + ENDIF + + iret + ENDM + +; +; SDL_IndicatePC +; + PROC SDL_IndicatePC on:WORD + PUBLIC SDL_IndicatePC + + mov ax,[on] + mov [cs:pcindicate],ax + ret + + ENDP + +; +; SDL_t0ExtremeAsmService +; Timer 0 ISR 7000Hz interrupts +; + PROC SDL_t0ExtremeAsmService + PUBLIC SDL_t0ExtremeAsmService + + push ax + mov al,[BYTE PTR cs:pcindicate] + or al,al + jz @@done + + push ds + push es + ;pusha + jmp @@skipme + oldsp dw ? +@@skipme: + mov [oldsp], sp + push ax + push cx + push dx + push bx + push [oldsp] + push bp + push si + push di + + mov ds,[cs:MyDS] + + les di,[pcSound] + mov ax,es + or ax,di + jz @@donereg ; nil pointer + + mov bl,[es:di] ; Get the byte + inc [WORD PTR pcSound] ; Increment pointer + + and bl,11100000b ; Nuke some of the precision (DEBUG - do this in the table) + + xor bh,bh + mov ah,[pcdtab+bx] ; Translate the byte + + in al,pcSpeaker + and al,11111100b + or al,ah + out pcSpeaker,al + + dec [pcLengthLeft] + jnz @@donereg + + mov [WORD PTR pcSound],0 ; We're done with this sample + mov [WORD PTR pcSound+2],0 + + in al,pcSpeaker + and al,11111100b + out pcSpeaker,al + + call SDL_DigitizedDone + +@@donereg: + ;popa + pop di + pop si + pop bp + pop [oldsp] + pop bx + pop dx + pop cx + pop ax + pop es + pop ds + +@@done: + inc [cs:extreme] + cmp [cs:extreme],10 + jae @@tofast + + mov al,20h + out 20h,al + pop ax + iret + +@@tofast: + mov [cs:extreme],0 + pop ax + +; jmp SDL_t0FastAsmService ; Drops through to SDL_t0FastAsmService + + ENDP + +; +; SDL_t0FastAsmService +; Timer 0 ISR for 700Hz interrupts +; + PROC SDL_t0FastAsmService + PUBLIC SDL_t0FastAsmService + + COMMONSTART + + inc [count_fx] ; Time to do PC/AdLib effects & time? + cmp [count_fx],5 + jae @@dofull + + mov ax,[sqActive] ; Is the sequencer active? + or ax,ax + jnz @@dofull + + mov ax,[WORD PTR ssSample] ; Is there a sample for the Sound Src? + or ax,[WORD PTR ssSample+2] + jz @@nosave + +@@dofull: + ;pusha + mov [oldsp], sp + push ax + push cx + push dx + push bx + push [oldsp] + push bp + push si + push di + push es + + cmp [count_fx],5 + jb @@nofx + mov [count_fx],0 + DOFX + + inc [count_time] + TIME +@@nofx: + + mov ax,[sqActive] + or ax,ax + jz @@nosq + + mov ax,[sqHackLen] + or ax,ax + jz @@sqdone + + les di,[sqHackPtr] +@@sqloop: + mov ax,[WORD PTR sqHackTime+2] + cmp ax,[WORD PTR alTimeCount+2] + ja @@sqdone + mov ax,[WORD PTR sqHackTime] + cmp ax,[WORD PTR alTimeCount] + ja @@sqdone + + mov ax,[es:di+2] ; Get time to next event + add ax,[WORD PTR alTimeCount] + mov [WORD PTR sqHackTime],ax + mov ax,[WORD PTR alTimeCount+2] + adc ax,0 + mov [WORD PTR sqHackTime+2],ax + + mov ax,[es:di] ; Get register/value pair + xor bh,bh + mov bl,ah + xor ah,ah + CALL alOut C,ax,bx + + add di,4 + mov [WORD PTR sqHackPtr],di + + sub [sqHackLen],4 + jnz @@sqloop + +@@sqdone: + add [WORD PTR alTimeCount],1 + adc [WORD PTR alTimeCount+2],0 + mov ax,[sqHackLen] + or ax,ax + jnz @@nosq + + mov ax,[WORD PTR sqHack] ; Copy pointer + mov [WORD PTR sqHackPtr],ax + mov ax,[WORD PTR sqHack+2] + mov [WORD PTR sqHackPtr+2],ax + + mov ax,[sqHackSeqLen] ; Copy length + mov [sqHackLen],ax + + mov ax,0 + mov [WORD PTR alTimeCount],ax ; Reset time counts + mov [WORD PTR alTimeCount+2],ax + mov [WORD PTR sqHackTime],ax + mov [WORD PTR sqHackTime+2],ax +@@nosq: + + les di,[ssSample] ; Get pointer to Sound Source sample + mov ax,es + or ax,di + jz @@ssdone ; If nil, skip this + +@@ssloop: + mov dx,[ssStatus] ; Check to see if FIFO has any empty slots + in al,dx + test al,40h + jnz @@ssdone ; Nope - don't push any more data out + + mov dx,[ssData] + mov al,[es:di] ; al = *ssSample + out dx,al ; Pump the value out + + mov dx,[ssControl] ; Pulse printer select + mov al,[ssOff] + out dx,al + push ax + pop ax + mov al,[ssOn] + out dx,al + + push ax ; Delay a short while + pop ax + + inc di + mov [WORD PTR ssSample],di ; ssSample++ + + dec [ssLengthLeft] + jnz @@ssloop + + mov [WORD PTR ssSample],0 ; We're done with this sample + mov [WORD PTR ssSample+2],0 + + call SDL_DigitizedDone +@@ssdone: + + COMMONEND + + ENDP + +; +; SDL_t0SlowAsmService +; Timer 0 ISR for 140Hz interrupts +; + PROC SDL_t0SlowAsmService + PUBLIC SDL_t0SlowAsmService + + IF DEBUG + push dx + push ax + mov dx,STATUS_REGISTER_1 + in al,dx + mov dx,ATR_INDEX + mov al,ATR_OVERSCAN + out dx,al + mov al,4 ; red + out dx,al + ENDIF + + push ds + push ax + + mov ds,[cs:MyDS] + + inc [count_time] + TIME + + mov ax,[WORD PTR pcSound] ; Is there a PC sound effect going? + or ax,[WORD PTR pcSound+2] + jnz @@dofull + + mov ax,[WORD PTR alSound] ; Is there an AdLib sound effect going? + or ax,[WORD PTR alSound+2] + jz @@nosave + +@@dofull: + ;pusha + mov [oldsp], sp + push ax + push cx + push dx + push bx + push [oldsp] + push bp + push si + push di + push es + + DOFX + + COMMONEND + + ENDP + + END