1 /* Project 16 Source Code~
\r
2 * Copyright (C) 2012-2017 sparky4 & pngwen & andrius4669 & joncampbell123 & yakui-lover
\r
4 * This file is part of Project 16.
\r
6 * Project 16 is free software; you can redistribute it and/or modify
\r
7 * it under the terms of the GNU General Public License as published by
\r
8 * the Free Software Foundation; either version 3 of the License, or
\r
9 * (at your option) any later version.
\r
11 * Project 16 is distributed in the hope that it will be useful,
\r
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
14 * GNU General Public License for more details.
\r
16 * You should have received a copy of the GNU General Public License
\r
17 * along with this program. If not, see <http://www.gnu.org/licenses/>, or
\r
18 * write to the Free Software Foundation, Inc., 51 Franklin Street,
\r
19 * Fifth Floor, Boston, MA 02110-1301 USA.
\r
25 // ID_SD.c - Sound Manager for Wolfenstein 3D
\r
27 // By Jason Blochowiak
\r
28 // Open Watcom port by sparky4
\r
32 // This module handles dealing with generating sound on the appropriate
\r
35 // Depends on: User Mgr (for parm checking)
\r
39 // SoundSourcePresent - Sound Source thingie present?
\r
40 // SoundBlasterPresent - SoundBlaster card present?
\r
41 // AdLibPresent - AdLib card present?
\r
42 // SoundMode - What device is used for sound effects
\r
43 // (Use SM_SetSoundMode() to set)
\r
44 // MusicMode - What device is used for music
\r
45 // (Use SM_SetMusicMode() to set)
\r
47 // NeedsDigitized - load digitized sounds?
\r
48 // NeedsMusic - load music?
\r
51 #pragma hdrstop // Wierdo thing with MUSE
\r
55 //#ifdef _MUSE_ // Will be defined in ID_Types.h
\r
56 #include "src/lib/id_sd.h"
\r
58 //#include "ID_HEADS.H"
\r
63 #define SDL_SoundFinished() {SoundNumber = SoundPriority = 0;}
\r
65 // Macros for AdLib stuff
\r
66 #define selreg(n) outportb(alFMAddr,n)
\r
67 #define writereg(n) outportb(alFMData,n)
\r
68 #define readstat() inportb(alFMStatus)
\r
70 // Imports from ID_SD_A.ASM
\r
71 /*extern*/ void SDL_SetDS(void),
\r
72 SDL_IndicatePC(boolean on);
\r
73 /*extern*/ void interrupt SDL_t0ExtremeAsmService(void),
\r
74 SDL_t0FastAsmService(void),
\r
75 SDL_t0SlowAsmService(void);
\r
78 boolean SoundSourcePresent,
\r
80 SoundBlasterPresent,SBProPresent,
\r
81 NeedsDigitized,NeedsMusic,
\r
88 word *SoundTable; // Really * _seg *SoundTable, but that don't work
\r
91 int DigiMap[LASTSOUND];
\r
93 // Internal variables
\r
94 static boolean SD_Started;
\r
95 boolean nextsoundpos;
\r
96 dword TimerDivisor,TimerCount;
\r
97 static char *ParmStrings[] =
\r
109 static void (*SoundUserHook)(void);
\r
110 soundnames SoundNumber,DigiNumber;
\r
111 word SoundPriority,DigiPriority;
\r
112 int LeftPosition,RightPosition;
\r
113 void interrupt (*t0OldService)(void);
\r
117 word NumDigi,DigiLeft,DigiPage;
\r
118 word _seg *DigiList;
\r
119 word DigiLastStart,DigiLastEnd;
\r
120 boolean DigiPlaying;
\r
121 static boolean DigiMissed,DigiLastSegment;
\r
122 static memptr DigiNextAddr;
\r
123 static word DigiNextLen;
\r
125 // SoundBlaster variables
\r
126 static boolean sbNoCheck,sbNoProCheck;
\r
127 static volatile boolean sbSamplePlaying;
\r
128 static byte sbOldIntMask = -1;
\r
129 static volatile byte huge *sbNextSegPtr;
\r
130 static byte sbDMA = 1,
\r
131 sbDMAa1 = 0x83,sbDMAa2 = 2,sbDMAa3 = 3,
\r
132 sba1Vals[] = {0x87,0x83,0,0x82},
\r
133 sba2Vals[] = {0,2,0,6},
\r
134 sba3Vals[] = {1,3,0,7};
\r
135 static int sbLocation = -1,sbInterrupt = 7,sbIntVec = 0xf,
\r
136 sbIntVectors[] = {-1,-1,0xa,0xb,-1,0xd,-1,0xf,-1,-1,-1};
\r
137 static volatile dword sbNextSegLen;
\r
138 static volatile SampledSound huge *sbSamples;
\r
139 static void interrupt (*sbOldIntHand)(void);
\r
140 static byte sbpOldFMMix,sbpOldVOCMix;
\r
142 // SoundSource variables
\r
145 word ssControl,ssStatus,ssData;
\r
147 volatile byte far *ssSample;
\r
148 volatile dword ssLengthLeft;
\r
150 // PC Sound variables
\r
151 volatile byte pcLastSample,far *pcSound;
\r
152 dword pcLengthLeft;
\r
153 word pcSoundLookup[255];
\r
159 dword alLengthLeft;
\r
161 Instrument alZeroInst;
\r
163 // This table maps channel numbers to carrier and modulator op cells
\r
164 static byte carriers[9] = { 3, 4, 5,11,12,13,19,20,21},
\r
165 modifiers[9] = { 0, 1, 2, 8, 9,10,16,17,18},
\r
166 // This table maps percussive voice numbers to op cells
\r
167 pcarriers[5] = {19,0xff,0xff,0xff,0xff},
\r
168 pmodifiers[5] = {16,17,18,20,21};
\r
170 // Sequencer variables
\r
172 static word alFXReg;
\r
173 static ActiveTrack *tracks[sqMaxTracks],
\r
174 mytracks[sqMaxTracks];
\r
175 static word sqMode,sqFadeStep;
\r
176 word far *sqHack,far *sqHackPtr,sqHackLen,sqHackSeqLen;
\r
179 // Internal routines
\r
180 void SDL_DigitizedDone(void);
\r
182 ///////////////////////////////////////////////////////////////////////////
\r
184 // SDL_SetTimer0() - Sets system timer 0 to the specified speed
\r
186 ///////////////////////////////////////////////////////////////////////////
\r
189 SDL_SetTimer0(word speed)
\r
191 #ifndef TPROF // If using Borland's profiling, don't screw with the timer
\r
195 outportb(0x43,0x36); // Change timer 0
\r
196 outportb(0x40,speed);
\r
197 outportb(0x40,speed >> 8);
\r
198 // Kludge to handle special case for digitized PC sounds
\r
199 if (TimerDivisor == (1192030 / (TickBase * 100)))
\r
200 TimerDivisor = (1192030 / (TickBase * 10));
\r
202 TimerDivisor = speed;
\r
206 TimerDivisor = 0x10000;
\r
210 ///////////////////////////////////////////////////////////////////////////
\r
212 // SDL_SetIntsPerSec() - Uses SDL_SetTimer0() to set the number of
\r
213 // interrupts generated by system timer 0 per second
\r
215 ///////////////////////////////////////////////////////////////////////////
\r
217 SDL_SetIntsPerSec(word ints)
\r
220 SDL_SetTimer0(1192030 / ints);
\r
224 SDL_SetTimerSpeed(void)
\r
227 void interrupt (*isr)(void);
\r
229 if ((DigiMode == sds_PC) && DigiPlaying)
\r
231 rate = TickBase * 100;
\r
232 isr = SDL_t0ExtremeAsmService;
\r
236 (MusicMode == smm_AdLib)
\r
237 || ((DigiMode == sds_SoundSource) && DigiPlaying)
\r
240 rate = TickBase * 10;
\r
241 isr = SDL_t0FastAsmService;
\r
245 rate = TickBase * 2;
\r
246 isr = SDL_t0SlowAsmService;
\r
249 if (rate != TimerRate)
\r
252 SDL_SetIntsPerSec(rate);
\r
259 // Sound Source Code
\r
261 ///////////////////////////////////////////////////////////////////////////
\r
263 // SDL_SSStopSample() - Stops a sample playing on the Sound Source
\r
265 ///////////////////////////////////////////////////////////////////////////
\r
271 SDL_SSStopSample(void)
\r
276 /*(long)*/ssSample = 0;
\r
281 ///////////////////////////////////////////////////////////////////////////
\r
283 // SDL_SSService() - Handles playing the next sample on the Sound Source
\r
285 ///////////////////////////////////////////////////////////////////////////
\r
287 SDL_SSService(void)
\r
290 boolean doneflag=false;
\r
296 mov dx,[ssStatus] // Check to see if FIFO is currently empty
\r
299 jnz done // Nope - don't push any more data out
\r
301 #ifdef __BORLANDC__
\r
305 #ifdef __BORLANDC__
\r
309 #ifdef __BORLANDC__
\r
319 if (!(--ssLengthLeft))
\r
321 /*(long)*/ssSample = 0;
\r
322 SDL_DigitizedDone();
\r
326 mov dx,[ssData] // Pump the value out
\r
330 mov dx,[ssControl] // Pulse printer select
\r
338 push ax // Delay a short while
\r
348 ///////////////////////////////////////////////////////////////////////////
\r
350 // SDL_SSPlaySample() - Plays the specified sample on the Sound Source
\r
352 ///////////////////////////////////////////////////////////////////////////
\r
358 SDL_SSPlaySample(byte huge *data,dword len)
\r
363 ssLengthLeft = len;
\r
364 ssSample = (volatile byte far *)data;
\r
369 ///////////////////////////////////////////////////////////////////////////
\r
371 // SDL_StartSS() - Sets up for and turns on the Sound Source
\r
373 ///////////////////////////////////////////////////////////////////////////
\r
378 ssControl = 0x27a; // If using LPT3
\r
379 else if (ssPort == 2)
\r
380 ssControl = 0x37a; // If using LPT2
\r
382 ssControl = 0x3be; // If using LPT1
\r
383 ssStatus = ssControl - 1;
\r
384 ssData = ssStatus - 1;
\r
388 ssOff = 0x0e; // Tandy wierdness
\r
390 ssOff = 0x0c; // For normal machines
\r
392 outportb(ssControl,ssOn); // Enable SS
\r
395 ///////////////////////////////////////////////////////////////////////////
\r
397 // SDL_ShutSS() - Turns off the Sound Source
\r
399 ///////////////////////////////////////////////////////////////////////////
\r
403 outportb(ssControl,ssOff);
\r
406 ///////////////////////////////////////////////////////////////////////////
\r
408 // SDL_CheckSS() - Checks to see if a Sound Source is present at the
\r
409 // location specified by the sound source variables
\r
411 ///////////////////////////////////////////////////////////////////////////
\r
415 boolean present = false, chkdone=0;
\r
418 // Turn the Sound Source on and wait awhile (4 ticks)
\r
421 lasttime = TimeCount;
\r
422 while (TimeCount < lasttime + 4)
\r
426 mov dx,[ssStatus] // Check to see if FIFO is currently empty
\r
429 jnz checkdone // Nope - Sound Source not here
\r
431 mov cx,32 // Force FIFO overflow (FIFO is 16 bytes)
\r
432 #ifdef __BORLANDC__
\r
436 #ifdef __BORLANDC__
\r
439 mov dx,[ssData] // Pump a neutral value out
\r
443 mov dx,[ssControl] // Pulse printer select
\r
451 push ax // Delay a short while before we do this again
\r
458 mov dx,[ssStatus] // Is FIFO overflowed now?
\r
461 jz checkdone // Nope, still not - Sound Source not here
\r
463 #ifdef __BORLANDC__
\r
467 #ifdef __BORLANDC__
\r
471 #ifdef __BORLANDC__
\r
479 if(!chkdone) present = true; // Yes - it's here!
\r
487 SDL_DetectSoundSource(void)
\r
489 for (ssPort = 1;ssPort <= 3;ssPort++)
\r
499 ///////////////////////////////////////////////////////////////////////////
\r
501 // SDL_PCPlaySample() - Plays the specified sample on the PC speaker
\r
503 ///////////////////////////////////////////////////////////////////////////
\r
509 SDL_PCPlaySample(byte huge *data,dword len)
\r
514 SDL_IndicatePC(true);
\r
516 pcLengthLeft = len;
\r
517 pcSound = (volatile byte far *)data;
\r
522 ///////////////////////////////////////////////////////////////////////////
\r
524 // SDL_PCStopSample() - Stops a sample playing on the PC speaker
\r
526 ///////////////////////////////////////////////////////////////////////////
\r
532 SDL_PCStopSample(void)
\r
537 /*(long)*/pcSound = 0;
\r
539 SDL_IndicatePC(false);
\r
541 asm in al,0x61 // Turn the speaker off
\r
542 asm and al,0xfd // ~2
\r
548 ///////////////////////////////////////////////////////////////////////////
\r
550 // SDL_PCPlaySound() - Plays the specified sound on the PC speaker
\r
552 ///////////////////////////////////////////////////////////////////////////
\r
558 SDL_PCPlaySound(PCSound far *sound)
\r
564 pcLengthLeft = sound->common.length;
\r
565 pcSound = sound->data;
\r
570 ///////////////////////////////////////////////////////////////////////////
\r
572 // SDL_PCStopSound() - Stops the current sound playing on the PC Speaker
\r
574 ///////////////////////////////////////////////////////////////////////////
\r
580 SDL_PCStopSound(void)
\r
585 /*(long)*/pcSound = 0;
\r
587 asm in al,0x61 // Turn the speaker off
\r
588 asm and al,0xfd // ~2
\r
594 ///////////////////////////////////////////////////////////////////////////
\r
596 // SDL_PCService() - Handles playing the next sample in a PC sound
\r
598 ///////////////////////////////////////////////////////////////////////////
\r
600 SDL_PCService(void)
\r
608 if (s != pcLastSample)
\r
614 if (s) // We have a frequency!
\r
616 t = pcSoundLookup[s];
\r
619 asm mov al,0xb6 // Write to channel 2 (speaker) timer
\r
622 asm out 42h,al // Low byte
\r
624 asm out 42h,al // High byte
\r
626 asm in al,0x61 // Turn the speaker & gate on
\r
630 else // Time for some silence
\r
632 asm in al,0x61 // Turn the speaker & gate off
\r
633 asm and al,0xfc // ~3
\r
640 if (!(--pcLengthLeft))
\r
643 SDL_SoundFinished();
\r
648 ///////////////////////////////////////////////////////////////////////////
\r
650 // SDL_ShutPC() - Turns off the pc speaker
\r
652 ///////////////////////////////////////////////////////////////////////////
\r
661 asm in al,0x61 // Turn the speaker & gate off
\r
662 asm and al,0xfc // ~3
\r
669 // Stuff for digitized sounds
\r
672 SDL_LoadDigiSegment(word page, global_game_variables_t *gvar)
\r
676 #if 0 // for debugging
\r
677 asm mov dx,STATUS_REGISTER_1
\r
679 asm mov dx,ATR_INDEX
\r
680 asm mov al,ATR_OVERSCAN
\r
682 asm mov al,10 // bright green
\r
686 addr = PM_GetSoundPage(page);
\r
687 PM_SetPageLock(gvar->pm.fi.PMSoundStart + page,pml_Locked, gvar);
\r
689 #if 0 // for debugging
\r
690 asm mov dx,STATUS_REGISTER_1
\r
692 asm mov dx,ATR_INDEX
\r
693 asm mov al,ATR_OVERSCAN
\r
695 asm mov al,3 // blue
\r
697 asm mov al,0x20 // normal
\r
705 SDL_PlayDigiSegment(memptr addr,word len)
\r
710 SDL_PCPlaySample(addr,len);
\r
712 case sds_SoundSource:
\r
713 SDL_SSPlaySample(addr,len);
\r
715 case sds_SoundBlaster:
\r
716 SDL_SBPlaySample(addr,len);
\r
722 SD_StopDigitized(global_game_variables_t *gvar)
\r
730 DigiNextAddr = nil;
\r
732 DigiMissed = false;
\r
733 DigiPlaying = false;
\r
734 DigiNumber = DigiPriority = 0;
\r
735 SoundPositioned = false;
\r
736 if ((DigiMode == sds_PC) && (SoundMode == sdm_PC))
\r
737 SDL_SoundFinished();
\r
742 SDL_PCStopSample();
\r
744 case sds_SoundSource:
\r
745 SDL_SSStopSample();
\r
747 case sds_SoundBlaster:
\r
748 SDL_SBStopSample();
\r
754 for (i = DigiLastStart;i < DigiLastEnd;i++)
\r
755 PM_SetPageLock(i + gvar->pm.fi.PMSoundStart,pml_Unlocked, gvar);
\r
763 if (DigiLeft && !DigiNextAddr)
\r
765 DigiNextLen = (DigiLeft >= PMPageSize)? PMPageSize : (DigiLeft % PMPageSize);
\r
766 DigiLeft -= DigiNextLen;
\r
768 DigiLastSegment = true;
\r
769 DigiNextAddr = SDL_LoadDigiSegment(DigiPage++);
\r
771 if (DigiMissed && DigiNextAddr)
\r
773 SDL_PlayDigiSegment(DigiNextAddr,DigiNextLen);
\r
774 DigiNextAddr = nil;
\r
775 DigiMissed = false;
\r
776 if (DigiLastSegment)
\r
778 DigiPlaying = false;
\r
779 DigiLastSegment = false;
\r
782 SDL_SetTimerSpeed();
\r
786 SD_SetPosition(int leftpos,int rightpos, global_game_variables_t *gvar)
\r
794 || ((leftpos == 15) && (rightpos == 15))
\r
796 Quit(gvar, "SD_SetPosition: Illegal position");
\r
800 case sds_SoundBlaster:
\r
801 SDL_PositionSBP(leftpos,rightpos);
\r
807 SD_PlayDigitized(word which,int leftpos,int rightpos, global_game_variables_t *gvar)
\r
815 SD_StopDigitized();
\r
816 if (which >= NumDigi)
\r
817 Quit(gvar, "SD_PlayDigitized: bad sound number");
\r
819 SD_SetPosition(leftpos,rightpos);
\r
821 DigiPage = DigiList[(which * 2) + 0];
\r
822 DigiLeft = DigiList[(which * 2) + 1];
\r
824 DigiLastStart = DigiPage;
\r
825 DigiLastEnd = DigiPage + ((DigiLeft + (PMPageSize - 1)) / PMPageSize);
\r
827 len = (DigiLeft >= PMPageSize)? PMPageSize : (DigiLeft % PMPageSize);
\r
828 addr = SDL_LoadDigiSegment(DigiPage++);
\r
830 DigiPlaying = true;
\r
831 DigiLastSegment = false;
\r
833 SDL_PlayDigiSegment(addr,len);
\r
836 DigiLastSegment = true;
\r
842 SDL_DigitizedDone(void)
\r
846 SDL_PlayDigiSegment(DigiNextAddr,DigiNextLen);
\r
847 DigiNextAddr = nil;
\r
848 DigiMissed = false;
\r
852 if (DigiLastSegment)
\r
854 DigiPlaying = false;
\r
855 DigiLastSegment = false;
\r
856 if ((DigiMode == sds_PC) && (SoundMode == sdm_PC))
\r
858 SDL_SoundFinished();
\r
861 DigiNumber = DigiPriority = 0;
\r
862 SoundPositioned = false;
\r
870 SD_SetDigiDevice(SDSMode mode)
\r
872 boolean devicenotpresent;
\r
874 if (mode == DigiMode)
\r
877 SD_StopDigitized();
\r
879 devicenotpresent = false;
\r
882 case sds_SoundBlaster:
\r
883 if (!SoundBlasterPresent)
\r
885 if (SoundSourcePresent)
\r
886 mode = sds_SoundSource;
\r
888 devicenotpresent = true;
\r
891 case sds_SoundSource:
\r
892 if (!SoundSourcePresent)
\r
893 devicenotpresent = true;
\r
897 if (!devicenotpresent)
\r
899 if (DigiMode == sds_SoundSource)
\r
904 if (mode == sds_SoundSource)
\r
907 SDL_SetTimerSpeed();
\r
912 SDL_SetupDigi(global_game_variables_t *gvar)
\r
919 PM_UnlockMainMem(gvar);
\r
920 MM_GetPtr(&list,PMPageSize, gvar);
\r
921 PM_CheckMainMem(gvar);
\r
922 p = (word far *)MK_FP(PM_GetPage(gvar->pm.fi.ChunksInFile - 1),0,gvar);
\r
923 _fmemcpy((void far *)list,(void far *)p,PMPageSize);
\r
924 pg = gvar->pm.fi.PMSoundStart;
\r
925 for (i = 0;i < PMPageSize / (sizeof(word) * 2);i++,p += 2)
\r
927 if (pg >= ChunksInFile - 1)
\r
929 pg += (p[1] + (PMPageSize - 1)) / PMPageSize;
\r
931 PM_UnlockMainMem();
\r
932 MM_GetPtr((memptr *)&DigiList,i * sizeof(word) * 2);
\r
933 _fmemcpy((void far *)DigiList,(void far *)list,i * sizeof(word) * 2);
\r
937 for (i = 0;i < LASTSOUND;i++)
\r
943 ///////////////////////////////////////////////////////////////////////////
\r
945 // alOut(n,b) - Puts b in AdLib card register n
\r
947 ///////////////////////////////////////////////////////////////////////////
\r
949 alOut(byte n,byte b)
\r
1011 ///////////////////////////////////////////////////////////////////////////
\r
1013 // SDL_SetInstrument() - Puts an instrument into a generator
\r
1015 ///////////////////////////////////////////////////////////////////////////
\r
1017 SDL_SetInstrument(int track,int which,Instrument far *inst,boolean percussive)
\r
1023 c = pcarriers[which];
\r
1024 m = pmodifiers[which];
\r
1028 c = carriers[which];
\r
1029 m = modifiers[which];
\r
1032 tracks[track - 1]->inst = *inst;
\r
1033 tracks[track - 1]->percussive = percussive;
\r
1035 alOut(m + alChar,inst->mChar);
\r
1036 alOut(m + alScale,inst->mScale);
\r
1037 alOut(m + alAttack,inst->mAttack);
\r
1038 alOut(m + alSus,inst->mSus);
\r
1039 alOut(m + alWave,inst->mWave);
\r
1041 // Most percussive instruments only use one cell
\r
1044 alOut(c + alChar,inst->cChar);
\r
1045 alOut(c + alScale,inst->cScale);
\r
1046 alOut(c + alAttack,inst->cAttack);
\r
1047 alOut(c + alSus,inst->cSus);
\r
1048 alOut(c + alWave,inst->cWave);
\r
1051 alOut(which + alFeedCon,inst->nConn); // DEBUG - I think this is right
\r
1055 ///////////////////////////////////////////////////////////////////////////
\r
1057 // SDL_ALStopSound() - Turns off any sound effects playing through the
\r
1060 ///////////////////////////////////////////////////////////////////////////
\r
1066 SDL_ALStopSound(void)
\r
1071 /*(long)*/alSound = 0;
\r
1072 alOut(alFreqH + 0,0);
\r
1078 SDL_AlSetFXInst(Instrument far *inst)
\r
1084 alOut(m + alChar,inst->mChar);
\r
1085 alOut(m + alScale,inst->mScale);
\r
1086 alOut(m + alAttack,inst->mAttack);
\r
1087 alOut(m + alSus,inst->mSus);
\r
1088 alOut(m + alWave,inst->mWave);
\r
1089 alOut(c + alChar,inst->cChar);
\r
1090 alOut(c + alScale,inst->cScale);
\r
1091 alOut(c + alAttack,inst->cAttack);
\r
1092 alOut(c + alSus,inst->cSus);
\r
1093 alOut(c + alWave,inst->cWave);
\r
1095 // Note: Switch commenting on these lines for old MUSE compatibility
\r
1096 // alOut(alFeedCon,inst->nConn);
\r
1097 alOut(alFeedCon,0);
\r
1100 ///////////////////////////////////////////////////////////////////////////
\r
1102 // SDL_ALPlaySound() - Plays the specified sound on the AdLib card
\r
1104 ///////////////////////////////////////////////////////////////////////////
\r
1110 SDL_ALPlaySound(AdLibSound far *sound, global_game_variables_t *gvar)
\r
1112 Instrument far *inst;
\r
1115 SDL_ALStopSound();
\r
1120 alLengthLeft = sound->common.length;
\r
1121 data = sound->data;
\r
1124 alSound = (byte far *)data;
\r
1125 alBlock = ((sound->block & 7) << 2) | 0x20;
\r
1126 inst = &sound->inst;
\r
1128 if (!(inst->mSus | inst->cSus))
\r
1131 Quit(gvar, "SDL_ALPlaySound() - Bad instrument");
\r
1134 SDL_AlSetFXInst(&alZeroInst); // DEBUG
\r
1135 SDL_AlSetFXInst(inst);
\r
1141 ///////////////////////////////////////////////////////////////////////////
\r
1143 // SDL_ALSoundService() - Plays the next sample out through the AdLib card
\r
1145 ///////////////////////////////////////////////////////////////////////////
\r
1148 SDL_ALSoundService(void)
\r
1156 alOut(alFreqH + 0,0);
\r
1159 alOut(alFreqL + 0,s);
\r
1160 alOut(alFreqH + 0,alBlock);
\r
1163 if (!(--alLengthLeft))
\r
1165 (long)alSound = 0;
\r
1166 alOut(alFreqH + 0,0);
\r
1167 SDL_SoundFinished();
\r
1175 SDL_ALService(void)
\r
1183 while (sqHackLen && (sqHackTime <= alTimeCount))
\r
1186 sqHackTime = alTimeCount + *sqHackPtr++;
\r
1196 sqHackPtr = (word far *)sqHack;
\r
1197 sqHackLen = sqHackSeqLen;
\r
1198 alTimeCount = sqHackTime = 0;
\r
1203 ///////////////////////////////////////////////////////////////////////////
\r
1205 // SDL_ShutAL() - Shuts down the AdLib card for sound effects
\r
1207 ///////////////////////////////////////////////////////////////////////////
\r
1214 alOut(alEffects,0);
\r
1215 alOut(alFreqH + 0,0);
\r
1216 SDL_AlSetFXInst(&alZeroInst);
\r
1222 ///////////////////////////////////////////////////////////////////////////
\r
1224 // SDL_CleanAL() - Totally shuts down the AdLib card
\r
1226 ///////////////////////////////////////////////////////////////////////////
\r
1235 alOut(alEffects,0);
\r
1236 for (i = 1;i < 0xf5;i++)
\r
1242 ///////////////////////////////////////////////////////////////////////////
\r
1244 // SDL_StartAL() - Starts up the AdLib card for sound effects
\r
1246 ///////////////////////////////////////////////////////////////////////////
\r
1251 alOut(alEffects,alFXReg);
\r
1252 SDL_AlSetFXInst(&alZeroInst);
\r
1255 ///////////////////////////////////////////////////////////////////////////
\r
1257 // SDL_DetectAdLib() - Determines if there's an AdLib (or SoundBlaster
\r
1258 // emulating an AdLib) present
\r
1260 ///////////////////////////////////////////////////////////////////////////
\r
1262 SDL_DetectAdLib(void)
\r
1264 byte status1,status2;
\r
1267 alOut(4,0x60); // Reset T1 & T2
\r
1268 alOut(4,0x80); // Reset IRQ
\r
1269 status1 = readstat();
\r
1270 alOut(2,0xff); // Set timer 1
\r
1271 alOut(4,0x21); // Start timer 1
\r
1273 SDL_Delay(TimerDelay100);
\r
1278 #ifdef __BORLANDC__
\r
1282 #ifdef __BORLANDC__
\r
1290 status2 = readstat();
\r
1294 if (((status1 & 0xe0) == 0x00) && ((status2 & 0xe0) == 0xc0))
\r
1296 for (i = 1;i <= 0xf5;i++) // Zero all the registers
\r
1299 alOut(1,0x20); // Set WSE=1
\r
1300 alOut(8,0); // Set CSM=0 & SEL=0
\r
1309 ///////////////////////////////////////////////////////////////////////////
\r
1311 // SDL_t0Service() - My timer 0 ISR which handles the different timings and
\r
1312 // dispatches to whatever other routines are appropriate
\r
1314 ///////////////////////////////////////////////////////////////////////////
\r
1315 static void interrupt
\r
1316 SDL_t0Service(void)
\r
1318 static word count = 1;
\r
1320 #if 1 // for debugging
\r
1321 asm mov dx,STATUS_REGISTER_1
\r
1323 asm mov dx,ATR_INDEX
\r
1324 asm mov al,ATR_OVERSCAN
\r
1326 asm mov al,4 // red
\r
1332 if ((MusicMode == smm_AdLib) || (DigiMode == sds_SoundSource))
\r
1336 // if (!(++count & 7))
\r
1337 if (!(++count % 10))
\r
1341 if (SoundUserHook)
\r
1344 // if (!(count & 3))
\r
1347 switch (SoundMode)
\r
1353 SDL_ALSoundService();
\r
1360 if (!(++count & 1))
\r
1364 if (SoundUserHook)
\r
1367 switch (SoundMode)
\r
1373 SDL_ALSoundService();
\r
1378 asm mov ax,[WORD PTR TimerCount]
\r
1379 asm add ax,[WORD PTR TimerDivisor]
\r
1380 asm mov [WORD PTR TimerCount],ax
\r
1382 t0OldService(); // If we overflow a word, time to call old int handler
\r
1385 outportb(0x20,0x20); // Ack the interrupt
\r
1388 #if 1 // for debugging
\r
1389 asm mov dx,STATUS_REGISTER_1
\r
1391 asm mov dx,ATR_INDEX
\r
1392 asm mov al,ATR_OVERSCAN
\r
1394 asm mov al,3 // blue
\r
1396 asm mov al,0x20 // normal
\r
1402 ////////////////////////////////////////////////////////////////////////////
\r
1404 // SDL_ShutDevice() - turns off whatever device was being used for sound fx
\r
1406 ////////////////////////////////////////////////////////////////////////////
\r
1408 SDL_ShutDevice(void)
\r
1410 switch (SoundMode)
\r
1419 SoundMode = sdm_Off;
\r
1422 ///////////////////////////////////////////////////////////////////////////
\r
1424 // SDL_CleanDevice() - totally shuts down all sound devices
\r
1426 ///////////////////////////////////////////////////////////////////////////
\r
1428 SDL_CleanDevice(void)
\r
1430 if ((SoundMode == sdm_AdLib) || (MusicMode == smm_AdLib))
\r
1434 ///////////////////////////////////////////////////////////////////////////
\r
1436 // SDL_StartDevice() - turns on whatever device is to be used for sound fx
\r
1438 ///////////////////////////////////////////////////////////////////////////
\r
1440 SDL_StartDevice(void)
\r
1442 switch (SoundMode)
\r
1448 SoundNumber = SoundPriority = 0;
\r
1451 // Public routines
\r
1453 ///////////////////////////////////////////////////////////////////////////
\r
1455 // SD_SetSoundMode() - Sets which sound hardware to use for sound effects
\r
1457 ///////////////////////////////////////////////////////////////////////////
\r
1459 SD_SetSoundMode(SDMode mode)
\r
1461 boolean result = false;
\r
1467 if ((mode == sdm_AdLib) && !AdLibPresent)
\r
1473 NeedsDigitized = false;
\r
1477 tableoffset = STARTPCSOUNDS;
\r
1478 NeedsDigitized = false;
\r
1484 tableoffset = STARTADLIBSOUNDS;
\r
1485 NeedsDigitized = false;
\r
1494 if (result && (mode != SoundMode))
\r
1499 SoundTable = (word *)(&audiosegs[tableoffset]);
\r
1501 SDL_StartDevice();
\r
1504 SDL_SetTimerSpeed();
\r
1509 ///////////////////////////////////////////////////////////////////////////
\r
1511 // SD_SetMusicMode() - sets the device to use for background music
\r
1513 ///////////////////////////////////////////////////////////////////////////
\r
1515 SD_SetMusicMode(SMMode mode)
\r
1517 boolean result = false;
\r
1519 SD_FadeOutMusic();
\r
1520 while (SD_MusicPlaying())
\r
1526 NeedsMusic = false;
\r
1532 NeedsMusic = true;
\r
1541 SDL_SetTimerSpeed();
\r
1546 ///////////////////////////////////////////////////////////////////////////
\r
1548 // SD_Startup() - starts up the Sound Mgr
\r
1549 // Detects all additional sound hardware and installs my ISR
\r
1551 ///////////////////////////////////////////////////////////////////////////
\r
1553 SD_Startup(global_game_variables_t *gvar)
\r
1562 ssIsTandy = false;
\r
1563 ssNoCheck = false;
\r
1564 alNoCheck = false;
\r
1565 sbNoCheck = false;
\r
1566 sbNoProCheck = false;
\r
1568 for (i = 1;i < _argc;i++)
\r
1570 switch (US_CheckParm(_argv[i],ParmStrings))
\r
1572 case 0: // No AdLib detection
\r
1575 case 1: // No SoundBlaster detection
\r
1578 case 2: // No SoundBlaster Pro detection
\r
1579 sbNoProCheck = true;
\r
1582 ssNoCheck = true; // No Sound Source detection
\r
1584 case 4: // Tandy Sound Source handling
\r
1587 case 5: // Sound Source present at LPT1
\r
1589 ssNoCheck = SoundSourcePresent = true;
\r
1591 case 6: // Sound Source present at LPT2
\r
1593 ssNoCheck = SoundSourcePresent = true;
\r
1595 case 7: // Sound Source present at LPT3
\r
1597 ssNoCheck = SoundSourcePresent = true;
\r
1603 SoundUserHook = 0;
\r
1605 t0OldService = getvect(8); // Get old timer 0 ISR
\r
1607 LocalTime = TimeCount = alTimeCount = 0;
\r
1609 SD_SetSoundMode(sdm_Off);
\r
1610 SD_SetMusicMode(smm_Off);
\r
1613 SoundSourcePresent = SDL_DetectSoundSource();
\r
1617 AdLibPresent = SDL_DetectAdLib();
\r
1618 if (AdLibPresent && !sbNoCheck)
\r
1621 char *env = getenv("BLASTER");
\r
1627 while (isspace(*env))
\r
1630 switch (toupper(*env))
\r
1633 temp = strtol(env + 1,&env,16);
\r
1637 && (temp <= 0x260)
\r
1638 && (!(temp & 0x00f))
\r
1640 port = (temp - 0x200) >> 4;
\r
1642 Quit(gvar, "SD_Startup: Unsupported address value in BLASTER");
\r
1645 temp = strtol(env + 1,&env,10);
\r
1650 && (sbIntVectors[temp] != -1)
\r
1653 sbInterrupt = temp;
\r
1654 sbIntVec = sbIntVectors[sbInterrupt];
\r
1657 Quit(gvar, "SD_Startup: Unsupported interrupt value in BLASTER");
\r
1660 temp = strtol(env + 1,&env,10);
\r
1661 if ((temp == 0) || (temp == 1) || (temp == 3))
\r
1662 SDL_SBSetDMA(temp);
\r
1664 Quit(gvar, "SD_Startup: Unsupported DMA value in BLASTER");
\r
1667 while (isspace(*env))
\r
1669 while (*env && !isspace(*env))
\r
1675 SoundBlasterPresent = SDL_DetectSoundBlaster(port);
\r
1679 for (i = 0;i < 255;i++)
\r
1680 pcSoundLookup[i] = i * 60;
\r
1682 if (SoundBlasterPresent)
\r
1687 SD_Started = true;
\r
1690 ///////////////////////////////////////////////////////////////////////////
\r
1692 // SD_Default() - Sets up the default behaviour for the Sound Mgr whether
\r
1693 // the config file was present or not.
\r
1695 ///////////////////////////////////////////////////////////////////////////
\r
1697 SD_Default(boolean gotit,SDMode sd,SMMode sm)
\r
1699 boolean gotsd,gotsm;
\r
1701 gotsd = gotsm = gotit;
\r
1703 if (gotsd) // Make sure requested sound hardware is available
\r
1708 gotsd = AdLibPresent;
\r
1719 if (sd != SoundMode)
\r
1720 SD_SetSoundMode(sd);
\r
1723 if (gotsm) // Make sure requested music hardware is available
\r
1728 gotsm = AdLibPresent;
\r
1737 if (sm != MusicMode)
\r
1738 SD_SetMusicMode(sm);
\r
1741 ///////////////////////////////////////////////////////////////////////////
\r
1743 // SD_Shutdown() - shuts down the Sound Mgr
\r
1744 // Removes sound ISR and turns off whatever sound hardware was active
\r
1746 ///////////////////////////////////////////////////////////////////////////
\r
1756 SDL_CleanDevice();
\r
1758 if (SoundBlasterPresent)
\r
1761 if (SoundSourcePresent)
\r
1769 setvect(8,t0OldService);
\r
1773 SD_Started = false;
\r
1776 ///////////////////////////////////////////////////////////////////////////
\r
1778 // SD_SetUserHook() - sets the routine that the Sound Mgr calls every 1/70th
\r
1779 // of a second from its timer 0 ISR
\r
1781 ///////////////////////////////////////////////////////////////////////////
\r
1783 SD_SetUserHook(void (* hook)(void))
\r
1785 SoundUserHook = hook;
\r
1788 ///////////////////////////////////////////////////////////////////////////
\r
1790 // SD_PositionSound() - Sets up a stereo imaging location for the next
\r
1791 // sound to be played. Each channel ranges from 0 to 15.
\r
1793 ///////////////////////////////////////////////////////////////////////////
\r
1795 SD_PositionSound(int leftvol,int rightvol)
\r
1797 LeftPosition = leftvol;
\r
1798 RightPosition = rightvol;
\r
1799 nextsoundpos = true;
\r
1802 ///////////////////////////////////////////////////////////////////////////
\r
1804 // SD_PlaySound() - plays the specified sound on the appropriate hardware
\r
1806 ///////////////////////////////////////////////////////////////////////////
\r
1808 SD_PlaySound(soundnames sound, global_game_variables_t *gvar)
\r
1811 SoundCommon far *s;
\r
1814 lp = LeftPosition;
\r
1815 rp = RightPosition;
\r
1817 RightPosition = 0;
\r
1819 ispos = nextsoundpos;
\r
1820 nextsoundpos = false;
\r
1825 s = MK_FP(SoundTable[sound],0);
\r
1826 if ((SoundMode != sdm_Off) && !s)
\r
1827 Quit(gvar, "SD_PlaySound() - Uncached sound");
\r
1829 if ((DigiMode != sds_Off) && (DigiMap[sound] != -1))
\r
1831 if ((DigiMode == sds_PC) && (SoundMode == sdm_PC))
\r
1833 if (s->priority < SoundPriority)
\r
1836 SDL_PCStopSound();
\r
1838 SD_PlayDigitized(DigiMap[sound],lp,rp);
\r
1839 SoundPositioned = ispos;
\r
1840 SoundNumber = sound;
\r
1841 SoundPriority = s->priority;
\r
1847 if (DigiPriority && !DigiNumber)
\r
1850 Quit(gvar, "SD_PlaySound: Priority without a sound");
\r
1854 if (s->priority < DigiPriority)
\r
1857 SD_PlayDigitized(DigiMap[sound],lp,rp);
\r
1858 SoundPositioned = ispos;
\r
1859 DigiNumber = sound;
\r
1860 DigiPriority = s->priority;
\r
1866 if (SoundMode == sdm_Off)
\r
1869 Quit(gvar, "SD_PlaySound() - Zero length sound");
\r
1870 if (s->priority < SoundPriority)
\r
1873 switch (SoundMode)
\r
1876 SDL_PCPlaySound((void far *)s);
\r
1879 SDL_ALPlaySound((void far *)s);
\r
1883 SoundNumber = sound;
\r
1884 SoundPriority = s->priority;
\r
1889 ///////////////////////////////////////////////////////////////////////////
\r
1891 // SD_SoundPlaying() - returns the sound number that's playing, or 0 if
\r
1892 // no sound is playing
\r
1894 ///////////////////////////////////////////////////////////////////////////
\r
1896 SD_SoundPlaying(void)
\r
1898 boolean result = false;
\r
1900 switch (SoundMode)
\r
1903 result = pcSound? true : false;
\r
1906 result = alSound? true : false;
\r
1911 return(SoundNumber);
\r
1916 ///////////////////////////////////////////////////////////////////////////
\r
1918 // SD_StopSound() - if a sound is playing, stops it
\r
1920 ///////////////////////////////////////////////////////////////////////////
\r
1922 SD_StopSound(void)
\r
1925 SD_StopDigitized();
\r
1927 switch (SoundMode)
\r
1930 SDL_PCStopSound();
\r
1933 SDL_ALStopSound();
\r
1937 SoundPositioned = false;
\r
1939 SDL_SoundFinished();
\r
1942 ///////////////////////////////////////////////////////////////////////////
\r
1944 // SD_WaitSoundDone() - waits until the current sound is done playing
\r
1946 ///////////////////////////////////////////////////////////////////////////
\r
1948 SD_WaitSoundDone(void)
\r
1950 while (SD_SoundPlaying())
\r
1954 ///////////////////////////////////////////////////////////////////////////
\r
1956 // SD_MusicOn() - turns on the sequencer
\r
1958 ///////////////////////////////////////////////////////////////////////////
\r
1965 ///////////////////////////////////////////////////////////////////////////
\r
1967 // SD_MusicOff() - turns off the sequencer and any playing notes
\r
1969 ///////////////////////////////////////////////////////////////////////////
\r
1976 switch (MusicMode)
\r
1980 alOut(alEffects,0);
\r
1981 for (i = 0;i < sqMaxTracks;i++)
\r
1982 alOut(alFreqH + i + 1,0);
\r
1988 ///////////////////////////////////////////////////////////////////////////
\r
1990 // SD_StartMusic() - starts playing the music pointed to
\r
1992 ///////////////////////////////////////////////////////////////////////////
\r
1994 SD_StartMusic(MusicGroup far *music)
\r
2000 if (MusicMode == smm_AdLib)
\r
2002 sqHackPtr = sqHack = music->values;
\r
2003 sqHackSeqLen = sqHackLen = music->length;
\r
2012 ///////////////////////////////////////////////////////////////////////////
\r
2014 // SD_FadeOutMusic() - starts fading out the music. Call SD_MusicPlaying()
\r
2015 // to see if the fadeout is complete
\r
2017 ///////////////////////////////////////////////////////////////////////////
\r
2019 SD_FadeOutMusic(void)
\r
2021 switch (MusicMode)
\r
2024 // DEBUG - quick hack to turn the music off
\r
2030 ///////////////////////////////////////////////////////////////////////////
\r
2032 // SD_MusicPlaying() - returns true if music is currently playing, false if
\r
2035 ///////////////////////////////////////////////////////////////////////////
\r
2037 SD_MusicPlaying(void)
\r
2041 switch (MusicMode)
\r
2045 // DEBUG - not written
\r
2064 void SDL_turnOnPCSpeaker(word timerval)
\r
2080 void SDL_turnOffPCSpeaker()
\r
2089 void SDL_setPCSpeaker(byte val)
\r
2104 if(*pcSound!=pcLastSample)
\r
2106 pcLastSample=*pcSound;
\r
2109 SDL_turnOnPCSpeaker(pcLastSample*60);
\r
2111 SDL_turnOffPCSpeaker();
\r
2118 SoundNumber=(soundnames)0;
\r
2120 SDL_turnOffPCSpeaker();
\r
2124 if(alSound && !alNoIRQ)
\r
2128 alOutInIRQ(alFreqL,*alSound);
\r
2129 alOutInIRQ(alFreqH,alBlock);
\r
2131 else alOutInIRQ(alFreqH,0);
\r
2137 SoundNumber=(soundnames)0;
\r
2139 alOutInIRQ(alFreqH,0);
\r
2162 if(sqActive && !alNoIRQ)
\r
2168 if(sqHackTime>alTimeCount) break;
\r
2169 sqHackTime=alTimeCount+*(sqHackPtr+1);
\r
2170 alOutInIRQ(*(byte *)sqHackPtr,*(((byte *)sqHackPtr)+1));
\r
2180 sqHackLen=sqHackSeqLen;
\r
2188 if(!(inp(ssStatus)&0x40))
\r
2190 outp(ssData,*ssSample++);
\r
2191 outp(ssControl,ssOff);
\r
2194 outp(ssControl,ssOn);
\r
2201 SDL_DigitizedDoneInIRQ();
\r
2206 TimerCount+=TimerDivisor;
\r
2207 if(*((word *)&TimerCount+1))
\r
2209 *((word *)&TimerCount+1)=0;
\r
2218 // Timer 0 ISR for 7000Hz interrupts
\r
2219 void interrupt SDL_t0ExtremeAsmService(void)
\r
2225 SDL_setPCSpeaker(((*pcSound++)&0x80)>>6);
\r
2230 SDL_turnOffPCSpeaker();
\r
2231 SDL_DigitizedDoneInIRQ();
\r
2245 // Timer 0 ISR for 7000Hz interrupts
\r
2246 void interrupt __SDL_t0ExtremeAsmService()
\r
2252 SDL_setPCSpeaker(((*pcSound++)&0x80)>>6);
\r
2257 SDL_turnOffPCSpeaker();
\r
2258 SDL_DigitizedDoneInIRQ();
\r
2272 // Timer 0 ISR for 700Hz interrupts
\r
2273 void interrupt SDL_t0FastAsmService(void)
\r
2278 // Timer 0 ISR for 140Hz interrupts
\r
2279 void interrupt SDL_t0SlowAsmService(void)
\r
2290 TimerCount+=TimerDivisor;
\r
2291 if(*((word *)&TimerCount+1))
\r
2293 *((word *)&TimerCount+1)=0;
\r
2300 void SDL_IndicatePC(boolean ind)
\r
2306 SDL_DigitizedDoneInIRQ(void)
\r
2310 SDL_PlayDigiSegment(DigiNextAddr,DigiNextLen/*,true*/);
\r
2311 DigiNextAddr = nil;
\r
2312 DigiMissed = false;
\r
2316 if (DigiLastSegment)
\r
2318 DigiPlaying = false;
\r
2319 DigiLastSegment = false;
\r
2320 if ((DigiMode == sds_PC) && (SoundMode == sdm_PC))
\r
2322 SDL_SoundFinished();
\r
2326 DigiNumber = (soundnames) 0;
\r
2329 SoundPositioned = false;
\r
2332 DigiMissed = true;
\r
2336 // Inside an interrupt handler interrupts should already be disabled
\r
2337 // so don't disable them again and cause V86 exceptions which cost
\r
2338 // aprox. 300 processor tics!
\r
2341 void alOutInIRQ(byte n,byte b)
\r