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
31 // This module handles dealing with generating sound on the appropriate
\r
34 // Depends on: User Mgr (for parm checking)
\r
38 // SoundSourcePresent - Sound Source thingie present?
\r
39 // SoundBlasterPresent - SoundBlaster card present?
\r
40 // AdLibPresent - AdLib card present?
\r
41 // SoundMode - What device is used for sound effects
\r
42 // (Use SM_SetSoundMode() to set)
\r
43 // MusicMode - What device is used for music
\r
44 // (Use SM_SetMusicMode() to set)
\r
45 // DigiMode - What device is used for digitized sound effects
\r
46 // (Use SM_SetDigiDevice() to set)
\r
49 // NeedsDigitized - load digitized sounds?
\r
50 // NeedsMusic - load music?
\r
53 #pragma hdrstop // Wierdo thing with MUSE
\r
57 //#ifdef _MUSE_ // Will be defined in ID_Types.h
\r
58 #include "src/lib/id_sd.h"
\r
60 //#include "ID_HEADS.H"
\r
70 #define SDL_SoundFinished() {SoundNumber = SoundPriority = 0;}
\r
72 // Macros for SoundBlaster stuff
\r
73 #define sbOut(n,b) outportb((n) + sbLocation,b)
\r
74 #define sbIn(n) inportb((n) + sbLocation)
\r
75 #define sbWriteDelay() while (sbIn(sbWriteStat) & 0x80);
\r
76 #define sbReadDelay() while (sbIn(sbDataAvail) & 0x80);
\r
78 // Macros for AdLib stuff
\r
79 #define selreg(n) outportb(alFMAddr,n)
\r
80 #define writereg(n) outportb(alFMData,n)
\r
81 #define readstat() inportb(alFMStatus)
\r
83 // Imports from ID_SD_A.ASM
\r
84 /*extern*/ void SDL_SetDS(void),
\r
85 SDL_IndicatePC(boolean on);
\r
86 /*extern*/ void interrupt SDL_t0ExtremeAsmService(void),
\r
87 SDL_t0FastAsmService(void),
\r
88 SDL_t0SlowAsmService(void);
\r
91 boolean SoundSourcePresent,
\r
93 SoundBlasterPresent,SBProPresent,
\r
94 NeedsDigitized,NeedsMusic,
\r
101 word *SoundTable; // Really * _seg *SoundTable, but that don't work
\r
104 int DigiMap[LASTSOUND];
\r
106 // Internal variables
\r
107 static boolean SD_Started;
\r
108 boolean nextsoundpos;
\r
109 dword TimerDivisor,TimerCount;
\r
110 static char *ParmStrings[] =
\r
122 static void (*SoundUserHook)(void);
\r
123 soundnames SoundNumber,DigiNumber;
\r
124 word SoundPriority,DigiPriority;
\r
125 int LeftPosition,RightPosition;
\r
126 void interrupt (*t0OldService)(void);
\r
130 word NumDigi,DigiLeft,DigiPage;
\r
131 word _seg *DigiList;
\r
132 word DigiLastStart,DigiLastEnd;
\r
133 boolean DigiPlaying;
\r
134 static boolean DigiMissed,DigiLastSegment;
\r
135 static memptr DigiNextAddr;
\r
136 static word DigiNextLen;
\r
138 // SoundBlaster variables
\r
139 static boolean sbNoCheck,sbNoProCheck;
\r
140 static volatile boolean sbSamplePlaying;
\r
141 static byte sbOldIntMask = -1;
\r
142 static volatile byte huge *sbNextSegPtr;
\r
143 static byte sbDMA = 1,
\r
144 sbDMAa1 = 0x83,sbDMAa2 = 2,sbDMAa3 = 3,
\r
145 sba1Vals[] = {0x87,0x83,0,0x82},
\r
146 sba2Vals[] = {0,2,0,6},
\r
147 sba3Vals[] = {1,3,0,7};
\r
148 static int sbLocation = -1,sbInterrupt = 7,sbIntVec = 0xf,
\r
149 sbIntVectors[] = {-1,-1,0xa,0xb,-1,0xd,-1,0xf,-1,-1,-1};
\r
150 static volatile dword sbNextSegLen;
\r
151 static volatile SampledSound huge *sbSamples;
\r
152 static void interrupt (*sbOldIntHand)(void);
\r
153 static byte sbpOldFMMix,sbpOldVOCMix;
\r
155 // SoundSource variables
\r
158 word ssControl,ssStatus,ssData;
\r
160 volatile byte far *ssSample;
\r
161 volatile dword ssLengthLeft;
\r
163 // PC Sound variables
\r
164 volatile byte pcLastSample,far *pcSound;
\r
165 dword pcLengthLeft;
\r
166 word pcSoundLookup[255];
\r
172 dword alLengthLeft;
\r
174 Instrument alZeroInst;
\r
176 // This table maps channel numbers to carrier and modulator op cells
\r
177 static byte carriers[9] = { 3, 4, 5,11,12,13,19,20,21},
\r
178 modifiers[9] = { 0, 1, 2, 8, 9,10,16,17,18},
\r
179 // This table maps percussive voice numbers to op cells
\r
180 pcarriers[5] = {19,0xff,0xff,0xff,0xff},
\r
181 pmodifiers[5] = {16,17,18,20,21};
\r
183 // Sequencer variables
\r
185 static word alFXReg;
\r
186 static ActiveTrack *tracks[sqMaxTracks],
\r
187 mytracks[sqMaxTracks];
\r
188 static word sqMode,sqFadeStep;
\r
189 word far *sqHack,far *sqHackPtr,sqHackLen,sqHackSeqLen;
\r
192 // Internal routines
\r
193 void SDL_DigitizedDone(void);
\r
195 ///////////////////////////////////////////////////////////////////////////
\r
197 // SDL_SetTimer0() - Sets system timer 0 to the specified speed
\r
199 ///////////////////////////////////////////////////////////////////////////
\r
202 SDL_SetTimer0(word speed)
\r
204 #ifndef TPROF // If using Borland's profiling, don't screw with the timer
\r
208 outportb(0x43,0x36); // Change timer 0
\r
209 outportb(0x40,speed);
\r
210 outportb(0x40,speed >> 8);
\r
211 // Kludge to handle special case for digitized PC sounds
\r
212 if (TimerDivisor == (1192030 / (TickBase * 100)))
\r
213 TimerDivisor = (1192030 / (TickBase * 10));
\r
215 TimerDivisor = speed;
\r
219 TimerDivisor = 0x10000;
\r
223 ///////////////////////////////////////////////////////////////////////////
\r
225 // SDL_SetIntsPerSec() - Uses SDL_SetTimer0() to set the number of
\r
226 // interrupts generated by system timer 0 per second
\r
228 ///////////////////////////////////////////////////////////////////////////
\r
230 SDL_SetIntsPerSec(word ints)
\r
233 SDL_SetTimer0(1192030 / ints);
\r
237 SDL_SetTimerSpeed(void)
\r
240 void interrupt (*isr)(void);
\r
242 if ((DigiMode == sds_PC) && DigiPlaying)
\r
244 rate = TickBase * 100;
\r
245 isr = SDL_t0ExtremeAsmService;
\r
249 (MusicMode == smm_AdLib)
\r
250 || ((DigiMode == sds_SoundSource) && DigiPlaying)
\r
253 rate = TickBase * 10;
\r
254 isr = SDL_t0FastAsmService;
\r
258 rate = TickBase * 2;
\r
259 isr = SDL_t0SlowAsmService;
\r
262 if (rate != TimerRate)
\r
265 SDL_SetIntsPerSec(rate);
\r
272 // SoundBlaster code
\r
275 ///////////////////////////////////////////////////////////////////////////
\r
277 // SDL_SBStopSample() - Stops any active sampled sound and causes DMA
\r
278 // requests from the SoundBlaster to cease
\r
280 ///////////////////////////////////////////////////////////////////////////
\r
286 SDL_SBStopSample(void)
\r
293 if (sbSamplePlaying)
\r
295 sbSamplePlaying = false;
\r
298 sbOut(sbWriteCmd,0xd0); // Turn off DSP DMA
\r
300 is = inportb(0x21); // Restore interrupt mask bit
\r
301 if (sbOldIntMask & (1 << sbInterrupt))
\r
302 is |= (1 << sbInterrupt);
\r
304 is &= ~(1 << sbInterrupt);
\r
311 ///////////////////////////////////////////////////////////////////////////
\r
313 // SDL_SBPlaySeg() - Plays a chunk of sampled sound on the SoundBlaster
\r
314 // Insures that the chunk doesn't cross a bank boundary, programs the DMA
\r
315 // controller, and tells the SB to start doing DMA requests for DAC
\r
317 ///////////////////////////////////////////////////////////////////////////
\r
319 SDL_SBPlaySeg(volatile byte huge *data,dword length)
\r
322 dword dataofs,uselen;
\r
325 datapage = FP_SEG(data) >> 12;
\r
326 dataofs = ((FP_SEG(data) & 0xfff) << 4) + FP_OFF(data);
\r
327 if (dataofs >= 0x10000)
\r
330 dataofs -= 0x10000;
\r
333 if (dataofs + uselen > 0x10000)
\r
334 uselen = 0x10000 - dataofs;
\r
338 // Program the DMA controller
\r
341 outportb(0x0a,sbDMA | 4); // Mask off DMA on channel sbDMA
\r
342 outportb(0x0c,0); // Clear byte ptr flip-flop to lower byte
\r
343 outportb(0x0b,0x49); // Set transfer mode for D/A conv
\r
344 outportb(sbDMAa2,(byte)dataofs); // Give LSB of address
\r
345 outportb(sbDMAa2,(byte)(dataofs >> 8)); // Give MSB of address
\r
346 outportb(sbDMAa1,(byte)datapage); // Give page of address
\r
347 outportb(sbDMAa3,(byte)uselen); // Give LSB of length
\r
348 outportb(sbDMAa3,(byte)(uselen >> 8)); // Give MSB of length
\r
349 outportb(0x0a,sbDMA); // Re-enable DMA on channel sbDMA
\r
351 // Start playing the thing
\r
353 sbOut(sbWriteCmd,0x14);
\r
355 sbOut(sbWriteData,(byte)uselen);
\r
357 sbOut(sbWriteData,(byte)(uselen >> 8));
\r
360 return(uselen + 1);
\r
363 ///////////////////////////////////////////////////////////////////////////
\r
365 // SDL_SBService() - Services the SoundBlaster DMA interrupt
\r
367 ///////////////////////////////////////////////////////////////////////////
\r
368 /*static*/ void interrupt
\r
369 SDL_SBService(void)
\r
373 sbIn(sbDataAvail); // Ack interrupt to SB
\r
377 used = SDL_SBPlaySeg(sbNextSegPtr,sbNextSegLen);
\r
378 if (sbNextSegLen <= used)
\r
379 sbNextSegPtr = nil;
\r
382 sbNextSegPtr += used;
\r
383 sbNextSegLen -= used;
\r
388 SDL_SBStopSample();
\r
389 SDL_DigitizedDone();
\r
392 outportb(0x20,0x20); // Ack interrupt
\r
395 ///////////////////////////////////////////////////////////////////////////
\r
397 // SDL_SBPlaySample() - Plays a sampled sound on the SoundBlaster. Sets up
\r
398 // DMA to play the sound
\r
400 ///////////////////////////////////////////////////////////////////////////
\r
406 SDL_SBPlaySample(byte huge *data,dword len)
\r
410 SDL_SBStopSample();
\r
415 used = SDL_SBPlaySeg(data,len);
\r
417 sbNextSegPtr = nil;
\r
420 sbNextSegPtr = data + used;
\r
421 sbNextSegLen = len - used;
\r
424 // Save old interrupt status and unmask ours
\r
425 sbOldIntMask = inportb(0x21);
\r
426 outportb(0x21,sbOldIntMask & ~(1 << sbInterrupt));
\r
429 sbOut(sbWriteCmd,0xd4); // Make sure DSP DMA is enabled
\r
431 sbSamplePlaying = true;
\r
436 ///////////////////////////////////////////////////////////////////////////
\r
438 // SDL_PositionSBP() - Sets the attenuation levels for the left and right
\r
439 // channels by using the mixer chip on the SB Pro. This hits a hole in
\r
440 // the address map for normal SBs.
\r
442 ///////////////////////////////////////////////////////////////////////////
\r
444 SDL_PositionSBP(int leftpos,int rightpos)
\r
451 leftpos = 15 - leftpos;
\r
452 rightpos = 15 - rightpos;
\r
453 v = ((leftpos & 0x0f) << 4) | (rightpos & 0x0f);
\r
458 sbOut(sbpMixerAddr,sbpmVoiceVol);
\r
459 sbOut(sbpMixerData,v);
\r
464 ///////////////////////////////////////////////////////////////////////////
\r
466 // SDL_CheckSB() - Checks to see if a SoundBlaster resides at a
\r
467 // particular I/O location
\r
469 ///////////////////////////////////////////////////////////////////////////
\r
471 SDL_CheckSB(int port)
\r
475 sbLocation = port << 4; // Initialize stuff for later use
\r
477 sbOut(sbReset,true); // Reset the SoundBlaster DSP
\r
478 asm mov dx,0x388 // Wait >4usec
\r
489 sbOut(sbReset,false); // Turn off sb DSP reset
\r
490 asm mov dx,0x388 // Wait >100usec
\r
502 for (i = 0;i < 100;i++)
\r
504 if (sbIn(sbDataAvail) & 0x80) // If data is available...
\r
506 if (sbIn(sbReadData) == 0xaa) // If it matches correct value
\r
510 sbLocation = -1; // Otherwise not a SoundBlaster
\r
515 sbLocation = -1; // Retry count exceeded - fail
\r
519 ///////////////////////////////////////////////////////////////////////////
\r
521 // Checks to see if a SoundBlaster is in the system. If the port passed is
\r
522 // -1, then it scans through all possible I/O locations. If the port
\r
523 // passed is 0, then it uses the default (2). If the port is >0, then
\r
524 // it just passes it directly to SDL_CheckSB()
\r
526 ///////////////////////////////////////////////////////////////////////////
\r
528 SDL_DetectSoundBlaster(int port)
\r
532 if (port == 0) // If user specifies default, use 2
\r
536 if (SDL_CheckSB(2)) // Check default before scanning
\r
539 if (SDL_CheckSB(4)) // Check other SB Pro location before scan
\r
542 for (i = 1;i <= 6;i++) // Scan through possible SB locations
\r
544 if ((i == 2) || (i == 4))
\r
547 if (SDL_CheckSB(i)) // If found at this address,
\r
548 return(true); // return success
\r
550 return(false); // All addresses failed, return failure
\r
553 return(SDL_CheckSB(port)); // User specified address or default
\r
556 ///////////////////////////////////////////////////////////////////////////
\r
558 // SDL_SBSetDMA() - Sets the DMA channel to be used by the SoundBlaster
\r
559 // code. Sets up sbDMA, and sbDMAa1-sbDMAa3 (used by SDL_SBPlaySeg()).
\r
561 ///////////////////////////////////////////////////////////////////////////
\r
563 SDL_SBSetDMA(byte channel)
\r
566 Quit("SDL_SBSetDMA() - invalid SoundBlaster DMA channel");
\r
569 sbDMAa1 = sba1Vals[channel];
\r
570 sbDMAa2 = sba2Vals[channel];
\r
571 sbDMAa3 = sba3Vals[channel];
\r
574 ///////////////////////////////////////////////////////////////////////////
\r
576 // SDL_StartSB() - Turns on the SoundBlaster
\r
578 ///////////////////////////////////////////////////////////////////////////
\r
582 byte timevalue,test;
\r
584 sbIntVec = sbIntVectors[sbInterrupt];
\r
586 Quit("SDL_StartSB: Illegal or unsupported interrupt number for SoundBlaster");
\r
588 sbOldIntHand = getvect(sbIntVec); // Get old interrupt handler
\r
589 setvect(sbIntVec,SDL_SBService); // Set mine
\r
592 sbOut(sbWriteCmd,0xd1); // Turn on DSP speaker
\r
594 // Set the SoundBlaster DAC time constant for 7KHz
\r
595 timevalue = 256 - (1000000 / 7000);
\r
597 sbOut(sbWriteCmd,0x40);
\r
599 sbOut(sbWriteData,timevalue);
\r
601 SBProPresent = false;
\r
605 // Check to see if this is a SB Pro
\r
606 sbOut(sbpMixerAddr,sbpmFMVol);
\r
607 sbpOldFMMix = sbIn(sbpMixerData);
\r
608 sbOut(sbpMixerData,0xbb);
\r
609 test = sbIn(sbpMixerData);
\r
612 // Boost FM output levels to be equivilent with digitized output
\r
613 sbOut(sbpMixerData,0xff);
\r
614 test = sbIn(sbpMixerData);
\r
617 SBProPresent = true;
\r
619 // Save old Voice output levels (SB Pro)
\r
620 sbOut(sbpMixerAddr,sbpmVoiceVol);
\r
621 sbpOldVOCMix = sbIn(sbpMixerData);
\r
623 // Turn SB Pro stereo DAC off
\r
624 sbOut(sbpMixerAddr,sbpmControl);
\r
625 sbOut(sbpMixerData,0); // 0=off,2=on
\r
630 ///////////////////////////////////////////////////////////////////////////
\r
632 // SDL_ShutSB() - Turns off the SoundBlaster
\r
634 ///////////////////////////////////////////////////////////////////////////
\r
638 SDL_SBStopSample();
\r
642 // Restore FM output levels (SB Pro)
\r
643 sbOut(sbpMixerAddr,sbpmFMVol);
\r
644 sbOut(sbpMixerData,sbpOldFMMix);
\r
646 // Restore Voice output levels (SB Pro)
\r
647 sbOut(sbpMixerAddr,sbpmVoiceVol);
\r
648 sbOut(sbpMixerData,sbpOldVOCMix);
\r
651 setvect(sbIntVec,sbOldIntHand); // Set vector back
\r
655 // Sound Source Code
\r
657 ///////////////////////////////////////////////////////////////////////////
\r
659 // SDL_SSStopSample() - Stops a sample playing on the Sound Source
\r
661 ///////////////////////////////////////////////////////////////////////////
\r
667 SDL_SSStopSample(void)
\r
672 (long)ssSample = 0;
\r
677 ///////////////////////////////////////////////////////////////////////////
\r
679 // SDL_SSService() - Handles playing the next sample on the Sound Source
\r
681 ///////////////////////////////////////////////////////////////////////////
\r
683 SDL_SSService(void)
\r
686 boolean doneflag=false;
\r
692 mov dx,[ssStatus] // Check to see if FIFO is currently empty
\r
695 jnz done // Nope - don't push any more data out
\r
697 #ifdef __BORLANDC__
\r
701 #ifdef __BORLANDC__
\r
705 #ifdef __BORLANDC__
\r
715 if (!(--ssLengthLeft))
\r
717 (long)ssSample = 0;
\r
718 SDL_DigitizedDone();
\r
722 mov dx,[ssData] // Pump the value out
\r
726 mov dx,[ssControl] // Pulse printer select
\r
734 push ax // Delay a short while
\r
744 ///////////////////////////////////////////////////////////////////////////
\r
746 // SDL_SSPlaySample() - Plays the specified sample on the Sound Source
\r
748 ///////////////////////////////////////////////////////////////////////////
\r
754 SDL_SSPlaySample(byte huge *data,dword len)
\r
759 ssLengthLeft = len;
\r
760 ssSample = (volatile byte far *)data;
\r
765 ///////////////////////////////////////////////////////////////////////////
\r
767 // SDL_StartSS() - Sets up for and turns on the Sound Source
\r
769 ///////////////////////////////////////////////////////////////////////////
\r
774 ssControl = 0x27a; // If using LPT3
\r
775 else if (ssPort == 2)
\r
776 ssControl = 0x37a; // If using LPT2
\r
778 ssControl = 0x3be; // If using LPT1
\r
779 ssStatus = ssControl - 1;
\r
780 ssData = ssStatus - 1;
\r
784 ssOff = 0x0e; // Tandy wierdness
\r
786 ssOff = 0x0c; // For normal machines
\r
788 outportb(ssControl,ssOn); // Enable SS
\r
791 ///////////////////////////////////////////////////////////////////////////
\r
793 // SDL_ShutSS() - Turns off the Sound Source
\r
795 ///////////////////////////////////////////////////////////////////////////
\r
799 outportb(ssControl,ssOff);
\r
802 ///////////////////////////////////////////////////////////////////////////
\r
804 // SDL_CheckSS() - Checks to see if a Sound Source is present at the
\r
805 // location specified by the sound source variables
\r
807 ///////////////////////////////////////////////////////////////////////////
\r
811 boolean present = false, chkdone=0;
\r
814 // Turn the Sound Source on and wait awhile (4 ticks)
\r
817 lasttime = TimeCount;
\r
818 while (TimeCount < lasttime + 4)
\r
822 mov dx,[ssStatus] // Check to see if FIFO is currently empty
\r
825 jnz checkdone // Nope - Sound Source not here
\r
827 mov cx,32 // Force FIFO overflow (FIFO is 16 bytes)
\r
828 #ifdef __BORLANDC__
\r
832 #ifdef __BORLANDC__
\r
835 mov dx,[ssData] // Pump a neutral value out
\r
839 mov dx,[ssControl] // Pulse printer select
\r
847 push ax // Delay a short while before we do this again
\r
854 mov dx,[ssStatus] // Is FIFO overflowed now?
\r
857 jz checkdone // Nope, still not - Sound Source not here
\r
859 #ifdef __BORLANDC__
\r
863 #ifdef __BORLANDC__
\r
867 #ifdef __BORLANDC__
\r
875 if(!chkdone) present = true; // Yes - it's here!
\r
883 SDL_DetectSoundSource(void)
\r
885 for (ssPort = 1;ssPort <= 3;ssPort++)
\r
895 ///////////////////////////////////////////////////////////////////////////
\r
897 // SDL_PCPlaySample() - Plays the specified sample on the PC speaker
\r
899 ///////////////////////////////////////////////////////////////////////////
\r
905 SDL_PCPlaySample(byte huge *data,dword len)
\r
910 SDL_IndicatePC(true);
\r
912 pcLengthLeft = len;
\r
913 pcSound = (volatile byte far *)data;
\r
918 ///////////////////////////////////////////////////////////////////////////
\r
920 // SDL_PCStopSample() - Stops a sample playing on the PC speaker
\r
922 ///////////////////////////////////////////////////////////////////////////
\r
928 SDL_PCStopSample(void)
\r
935 SDL_IndicatePC(false);
\r
937 asm in al,0x61 // Turn the speaker off
\r
938 asm and al,0xfd // ~2
\r
944 ///////////////////////////////////////////////////////////////////////////
\r
946 // SDL_PCPlaySound() - Plays the specified sound on the PC speaker
\r
948 ///////////////////////////////////////////////////////////////////////////
\r
954 SDL_PCPlaySound(PCSound far *sound)
\r
960 pcLengthLeft = sound->common.length;
\r
961 pcSound = sound->data;
\r
966 ///////////////////////////////////////////////////////////////////////////
\r
968 // SDL_PCStopSound() - Stops the current sound playing on the PC Speaker
\r
970 ///////////////////////////////////////////////////////////////////////////
\r
976 SDL_PCStopSound(void)
\r
983 asm in al,0x61 // Turn the speaker off
\r
984 asm and al,0xfd // ~2
\r
991 ///////////////////////////////////////////////////////////////////////////
\r
993 // SDL_PCService() - Handles playing the next sample in a PC sound
\r
995 ///////////////////////////////////////////////////////////////////////////
\r
997 SDL_PCService(void)
\r
1005 if (s != pcLastSample)
\r
1011 if (s) // We have a frequency!
\r
1013 t = pcSoundLookup[s];
\r
1016 asm mov al,0xb6 // Write to channel 2 (speaker) timer
\r
1019 asm out 42h,al // Low byte
\r
1021 asm out 42h,al // High byte
\r
1023 asm in al,0x61 // Turn the speaker & gate on
\r
1027 else // Time for some silence
\r
1029 asm in al,0x61 // Turn the speaker & gate off
\r
1030 asm and al,0xfc // ~3
\r
1037 if (!(--pcLengthLeft))
\r
1039 SDL_PCStopSound();
\r
1040 SDL_SoundFinished();
\r
1046 ///////////////////////////////////////////////////////////////////////////
\r
1048 // SDL_ShutPC() - Turns off the pc speaker
\r
1050 ///////////////////////////////////////////////////////////////////////////
\r
1059 asm in al,0x61 // Turn the speaker & gate off
\r
1060 asm and al,0xfc // ~3
\r
1067 // Stuff for digitized sounds
\r
1070 SDL_LoadDigiSegment(word page)
\r
1074 #if 0 // for debugging
\r
1075 asm mov dx,STATUS_REGISTER_1
\r
1077 asm mov dx,ATR_INDEX
\r
1078 asm mov al,ATR_OVERSCAN
\r
1080 asm mov al,10 // bright green
\r
1084 addr = PM_GetSoundPage(page, gvar);
\r
1085 PM_SetPageLock(PMSoundStart + page,pml_Locked);
\r
1087 #if 0 // for debugging
\r
1088 asm mov dx,STATUS_REGISTER_1
\r
1090 asm mov dx,ATR_INDEX
\r
1091 asm mov al,ATR_OVERSCAN
\r
1093 asm mov al,3 // blue
\r
1095 asm mov al,0x20 // normal
\r
1103 SDL_PlayDigiSegment(memptr addr,word len)
\r
1108 SDL_PCPlaySample(addr,len);
\r
1110 case sds_SoundSource:
\r
1111 SDL_SSPlaySample(addr,len);
\r
1113 case sds_SoundBlaster:
\r
1114 SDL_SBPlaySample(addr,len);
\r
1120 SD_StopDigitized(void)
\r
1128 DigiNextAddr = nil;
\r
1130 DigiMissed = false;
\r
1131 DigiPlaying = false;
\r
1132 DigiNumber = DigiPriority = 0;
\r
1133 SoundPositioned = false;
\r
1134 if ((DigiMode == sds_PC) && (SoundMode == sdm_PC))
\r
1135 SDL_SoundFinished();
\r
1140 SDL_PCStopSample();
\r
1142 case sds_SoundSource:
\r
1143 SDL_SSStopSample();
\r
1145 case sds_SoundBlaster:
\r
1146 SDL_SBStopSample();
\r
1152 for (i = DigiLastStart;i < DigiLastEnd;i++)
\r
1153 PM_SetPageLock(i + PMSoundStart,pml_Unlocked);
\r
1154 DigiLastStart = 1;
\r
1161 if (DigiLeft && !DigiNextAddr)
\r
1163 DigiNextLen = (DigiLeft >= PMPageSize)? PMPageSize : (DigiLeft % PMPageSize);
\r
1164 DigiLeft -= DigiNextLen;
\r
1166 DigiLastSegment = true;
\r
1167 DigiNextAddr = SDL_LoadDigiSegment(DigiPage++);
\r
1169 if (DigiMissed && DigiNextAddr)
\r
1171 SDL_PlayDigiSegment(DigiNextAddr,DigiNextLen);
\r
1172 DigiNextAddr = nil;
\r
1173 DigiMissed = false;
\r
1174 if (DigiLastSegment)
\r
1176 DigiPlaying = false;
\r
1177 DigiLastSegment = false;
\r
1180 SDL_SetTimerSpeed();
\r
1184 SD_SetPosition(int leftpos,int rightpos)
\r
1191 || (rightpos > 15)
\r
1192 || ((leftpos == 15) && (rightpos == 15))
\r
1194 Quit("SD_SetPosition: Illegal position");
\r
1198 case sds_SoundBlaster:
\r
1199 SDL_PositionSBP(leftpos,rightpos);
\r
1205 SD_PlayDigitized(word which,int leftpos,int rightpos)
\r
1213 SD_StopDigitized();
\r
1214 if (which >= NumDigi)
\r
1215 Quit("SD_PlayDigitized: bad sound number");
\r
1217 SD_SetPosition(leftpos,rightpos);
\r
1219 DigiPage = DigiList[(which * 2) + 0];
\r
1220 DigiLeft = DigiList[(which * 2) + 1];
\r
1222 DigiLastStart = DigiPage;
\r
1223 DigiLastEnd = DigiPage + ((DigiLeft + (PMPageSize - 1)) / PMPageSize);
\r
1225 len = (DigiLeft >= PMPageSize)? PMPageSize : (DigiLeft % PMPageSize);
\r
1226 addr = SDL_LoadDigiSegment(DigiPage++);
\r
1228 DigiPlaying = true;
\r
1229 DigiLastSegment = false;
\r
1231 SDL_PlayDigiSegment(addr,len);
\r
1234 DigiLastSegment = true;
\r
1240 SDL_DigitizedDone(void)
\r
1244 SDL_PlayDigiSegment(DigiNextAddr,DigiNextLen);
\r
1245 DigiNextAddr = nil;
\r
1246 DigiMissed = false;
\r
1250 if (DigiLastSegment)
\r
1252 DigiPlaying = false;
\r
1253 DigiLastSegment = false;
\r
1254 if ((DigiMode == sds_PC) && (SoundMode == sdm_PC))
\r
1256 SDL_SoundFinished();
\r
1259 DigiNumber = DigiPriority = 0;
\r
1260 SoundPositioned = false;
\r
1263 DigiMissed = true;
\r
1268 SD_SetDigiDevice(SDSMode mode)
\r
1270 boolean devicenotpresent;
\r
1272 if (mode == DigiMode)
\r
1275 SD_StopDigitized();
\r
1277 devicenotpresent = false;
\r
1280 case sds_SoundBlaster:
\r
1281 if (!SoundBlasterPresent)
\r
1283 if (SoundSourcePresent)
\r
1284 mode = sds_SoundSource;
\r
1286 devicenotpresent = true;
\r
1289 case sds_SoundSource:
\r
1290 if (!SoundSourcePresent)
\r
1291 devicenotpresent = true;
\r
1295 if (!devicenotpresent)
\r
1297 if (DigiMode == sds_SoundSource)
\r
1302 if (mode == sds_SoundSource)
\r
1305 SDL_SetTimerSpeed();
\r
1310 SDL_SetupDigi(void)
\r
1317 PM_UnlockMainMem();
\r
1318 MM_GetPtr(&list,PMPageSize);
\r
1319 PM_CheckMainMem();
\r
1320 p = (word far *)MK_FP(PM_GetPage(ChunksInFile - 1),0);
\r
1321 _fmemcpy((void far *)list,(void far *)p,PMPageSize);
\r
1322 pg = PMSoundStart;
\r
1323 for (i = 0;i < PMPageSize / (sizeof(word) * 2);i++,p += 2)
\r
1325 if (pg >= ChunksInFile - 1)
\r
1327 pg += (p[1] + (PMPageSize - 1)) / PMPageSize;
\r
1329 PM_UnlockMainMem();
\r
1330 MM_GetPtr((memptr *)&DigiList,i * sizeof(word) * 2);
\r
1331 _fmemcpy((void far *)DigiList,(void far *)list,i * sizeof(word) * 2);
\r
1332 MM_FreePtr(&list);
\r
1335 for (i = 0;i < LASTSOUND;i++)
\r
1341 ///////////////////////////////////////////////////////////////////////////
\r
1343 // alOut(n,b) - Puts b in AdLib card register n
\r
1345 ///////////////////////////////////////////////////////////////////////////
\r
1347 alOut(byte n,byte b)
\r
1409 ///////////////////////////////////////////////////////////////////////////
\r
1411 // SDL_SetInstrument() - Puts an instrument into a generator
\r
1413 ///////////////////////////////////////////////////////////////////////////
\r
1415 SDL_SetInstrument(int track,int which,Instrument far *inst,boolean percussive)
\r
1421 c = pcarriers[which];
\r
1422 m = pmodifiers[which];
\r
1426 c = carriers[which];
\r
1427 m = modifiers[which];
\r
1430 tracks[track - 1]->inst = *inst;
\r
1431 tracks[track - 1]->percussive = percussive;
\r
1433 alOut(m + alChar,inst->mChar);
\r
1434 alOut(m + alScale,inst->mScale);
\r
1435 alOut(m + alAttack,inst->mAttack);
\r
1436 alOut(m + alSus,inst->mSus);
\r
1437 alOut(m + alWave,inst->mWave);
\r
1439 // Most percussive instruments only use one cell
\r
1442 alOut(c + alChar,inst->cChar);
\r
1443 alOut(c + alScale,inst->cScale);
\r
1444 alOut(c + alAttack,inst->cAttack);
\r
1445 alOut(c + alSus,inst->cSus);
\r
1446 alOut(c + alWave,inst->cWave);
\r
1449 alOut(which + alFeedCon,inst->nConn); // DEBUG - I think this is right
\r
1453 ///////////////////////////////////////////////////////////////////////////
\r
1455 // SDL_ALStopSound() - Turns off any sound effects playing through the
\r
1458 ///////////////////////////////////////////////////////////////////////////
\r
1464 SDL_ALStopSound(void)
\r
1469 (long)alSound = 0;
\r
1470 alOut(alFreqH + 0,0);
\r
1476 SDL_AlSetFXInst(Instrument far *inst)
\r
1482 alOut(m + alChar,inst->mChar);
\r
1483 alOut(m + alScale,inst->mScale);
\r
1484 alOut(m + alAttack,inst->mAttack);
\r
1485 alOut(m + alSus,inst->mSus);
\r
1486 alOut(m + alWave,inst->mWave);
\r
1487 alOut(c + alChar,inst->cChar);
\r
1488 alOut(c + alScale,inst->cScale);
\r
1489 alOut(c + alAttack,inst->cAttack);
\r
1490 alOut(c + alSus,inst->cSus);
\r
1491 alOut(c + alWave,inst->cWave);
\r
1493 // Note: Switch commenting on these lines for old MUSE compatibility
\r
1494 // alOut(alFeedCon,inst->nConn);
\r
1495 alOut(alFeedCon,0);
\r
1498 ///////////////////////////////////////////////////////////////////////////
\r
1500 // SDL_ALPlaySound() - Plays the specified sound on the AdLib card
\r
1502 ///////////////////////////////////////////////////////////////////////////
\r
1508 SDL_ALPlaySound(AdLibSound far *sound)
\r
1510 Instrument far *inst;
\r
1513 SDL_ALStopSound();
\r
1518 alLengthLeft = sound->common.length;
\r
1519 data = sound->data;
\r
1522 alSound = (byte far *)data;
\r
1523 alBlock = ((sound->block & 7) << 2) | 0x20;
\r
1524 inst = &sound->inst;
\r
1526 if (!(inst->mSus | inst->cSus))
\r
1529 Quit("SDL_ALPlaySound() - Bad instrument");
\r
1532 SDL_AlSetFXInst(&alZeroInst); // DEBUG
\r
1533 SDL_AlSetFXInst(inst);
\r
1539 ///////////////////////////////////////////////////////////////////////////
\r
1541 // SDL_ALSoundService() - Plays the next sample out through the AdLib card
\r
1543 ///////////////////////////////////////////////////////////////////////////
\r
1546 SDL_ALSoundService(void)
\r
1554 alOut(alFreqH + 0,0);
\r
1557 alOut(alFreqL + 0,s);
\r
1558 alOut(alFreqH + 0,alBlock);
\r
1561 if (!(--alLengthLeft))
\r
1563 (long)alSound = 0;
\r
1564 alOut(alFreqH + 0,0);
\r
1565 SDL_SoundFinished();
\r
1573 SDL_ALService(void)
\r
1581 while (sqHackLen && (sqHackTime <= alTimeCount))
\r
1584 sqHackTime = alTimeCount + *sqHackPtr++;
\r
1594 sqHackPtr = (word far *)sqHack;
\r
1595 sqHackLen = sqHackSeqLen;
\r
1596 alTimeCount = sqHackTime = 0;
\r
1601 ///////////////////////////////////////////////////////////////////////////
\r
1603 // SDL_ShutAL() - Shuts down the AdLib card for sound effects
\r
1605 ///////////////////////////////////////////////////////////////////////////
\r
1612 alOut(alEffects,0);
\r
1613 alOut(alFreqH + 0,0);
\r
1614 SDL_AlSetFXInst(&alZeroInst);
\r
1620 ///////////////////////////////////////////////////////////////////////////
\r
1622 // SDL_CleanAL() - Totally shuts down the AdLib card
\r
1624 ///////////////////////////////////////////////////////////////////////////
\r
1633 alOut(alEffects,0);
\r
1634 for (i = 1;i < 0xf5;i++)
\r
1640 ///////////////////////////////////////////////////////////////////////////
\r
1642 // SDL_StartAL() - Starts up the AdLib card for sound effects
\r
1644 ///////////////////////////////////////////////////////////////////////////
\r
1649 alOut(alEffects,alFXReg);
\r
1650 SDL_AlSetFXInst(&alZeroInst);
\r
1653 ///////////////////////////////////////////////////////////////////////////
\r
1655 // SDL_DetectAdLib() - Determines if there's an AdLib (or SoundBlaster
\r
1656 // emulating an AdLib) present
\r
1658 ///////////////////////////////////////////////////////////////////////////
\r
1660 SDL_DetectAdLib(void)
\r
1662 byte status1,status2;
\r
1665 alOut(4,0x60); // Reset T1 & T2
\r
1666 alOut(4,0x80); // Reset IRQ
\r
1667 status1 = readstat();
\r
1668 alOut(2,0xff); // Set timer 1
\r
1669 alOut(4,0x21); // Start timer 1
\r
1671 SDL_Delay(TimerDelay100);
\r
1676 #ifdef __BORLANDC__
\r
1680 #ifdef __BORLANDC__
\r
1688 status2 = readstat();
\r
1692 if (((status1 & 0xe0) == 0x00) && ((status2 & 0xe0) == 0xc0))
\r
1694 for (i = 1;i <= 0xf5;i++) // Zero all the registers
\r
1697 alOut(1,0x20); // Set WSE=1
\r
1698 alOut(8,0); // Set CSM=0 & SEL=0
\r
1707 ///////////////////////////////////////////////////////////////////////////
\r
1709 // SDL_t0Service() - My timer 0 ISR which handles the different timings and
\r
1710 // dispatches to whatever other routines are appropriate
\r
1712 ///////////////////////////////////////////////////////////////////////////
\r
1713 static void interrupt
\r
1714 SDL_t0Service(void)
\r
1716 static word count = 1;
\r
1718 #if 1 // for debugging
\r
1719 asm mov dx,STATUS_REGISTER_1
\r
1721 asm mov dx,ATR_INDEX
\r
1722 asm mov al,ATR_OVERSCAN
\r
1724 asm mov al,4 // red
\r
1730 if ((MusicMode == smm_AdLib) || (DigiMode == sds_SoundSource))
\r
1734 // if (!(++count & 7))
\r
1735 if (!(++count % 10))
\r
1739 if (SoundUserHook)
\r
1742 // if (!(count & 3))
\r
1745 switch (SoundMode)
\r
1751 SDL_ALSoundService();
\r
1758 if (!(++count & 1))
\r
1762 if (SoundUserHook)
\r
1765 switch (SoundMode)
\r
1771 SDL_ALSoundService();
\r
1776 asm mov ax,[WORD PTR TimerCount]
\r
1777 asm add ax,[WORD PTR TimerDivisor]
\r
1778 asm mov [WORD PTR TimerCount],ax
\r
1780 t0OldService(); // If we overflow a word, time to call old int handler
\r
1783 outportb(0x20,0x20); // Ack the interrupt
\r
1786 #if 1 // for debugging
\r
1787 asm mov dx,STATUS_REGISTER_1
\r
1789 asm mov dx,ATR_INDEX
\r
1790 asm mov al,ATR_OVERSCAN
\r
1792 asm mov al,3 // blue
\r
1794 asm mov al,0x20 // normal
\r
1800 ////////////////////////////////////////////////////////////////////////////
\r
1802 // SDL_ShutDevice() - turns off whatever device was being used for sound fx
\r
1804 ////////////////////////////////////////////////////////////////////////////
\r
1806 SDL_ShutDevice(void)
\r
1808 switch (SoundMode)
\r
1817 SoundMode = sdm_Off;
\r
1820 ///////////////////////////////////////////////////////////////////////////
\r
1822 // SDL_CleanDevice() - totally shuts down all sound devices
\r
1824 ///////////////////////////////////////////////////////////////////////////
\r
1826 SDL_CleanDevice(void)
\r
1828 if ((SoundMode == sdm_AdLib) || (MusicMode == smm_AdLib))
\r
1832 ///////////////////////////////////////////////////////////////////////////
\r
1834 // SDL_StartDevice() - turns on whatever device is to be used for sound fx
\r
1836 ///////////////////////////////////////////////////////////////////////////
\r
1838 SDL_StartDevice(void)
\r
1840 switch (SoundMode)
\r
1846 SoundNumber = SoundPriority = 0;
\r
1849 // Public routines
\r
1851 ///////////////////////////////////////////////////////////////////////////
\r
1853 // SD_SetSoundMode() - Sets which sound hardware to use for sound effects
\r
1855 ///////////////////////////////////////////////////////////////////////////
\r
1857 SD_SetSoundMode(SDMode mode)
\r
1859 boolean result = false;
\r
1865 if ((mode == sdm_AdLib) && !AdLibPresent)
\r
1871 NeedsDigitized = false;
\r
1875 tableoffset = STARTPCSOUNDS;
\r
1876 NeedsDigitized = false;
\r
1882 tableoffset = STARTADLIBSOUNDS;
\r
1883 NeedsDigitized = false;
\r
1892 if (result && (mode != SoundMode))
\r
1897 SoundTable = (word *)(&audiosegs[tableoffset]);
\r
1899 SDL_StartDevice();
\r
1902 SDL_SetTimerSpeed();
\r
1907 ///////////////////////////////////////////////////////////////////////////
\r
1909 // SD_SetMusicMode() - sets the device to use for background music
\r
1911 ///////////////////////////////////////////////////////////////////////////
\r
1913 SD_SetMusicMode(SMMode mode)
\r
1915 boolean result = false;
\r
1917 SD_FadeOutMusic();
\r
1918 while (SD_MusicPlaying())
\r
1924 NeedsMusic = false;
\r
1930 NeedsMusic = true;
\r
1939 SDL_SetTimerSpeed();
\r
1944 ///////////////////////////////////////////////////////////////////////////
\r
1946 // SD_Startup() - starts up the Sound Mgr
\r
1947 // Detects all additional sound hardware and installs my ISR
\r
1949 ///////////////////////////////////////////////////////////////////////////
\r
1960 ssIsTandy = false;
\r
1961 ssNoCheck = false;
\r
1962 alNoCheck = false;
\r
1963 sbNoCheck = false;
\r
1964 sbNoProCheck = false;
\r
1966 for (i = 1;i < _argc;i++)
\r
1968 switch (US_CheckParm(_argv[i],ParmStrings))
\r
1970 case 0: // No AdLib detection
\r
1973 case 1: // No SoundBlaster detection
\r
1976 case 2: // No SoundBlaster Pro detection
\r
1977 sbNoProCheck = true;
\r
1980 ssNoCheck = true; // No Sound Source detection
\r
1982 case 4: // Tandy Sound Source handling
\r
1985 case 5: // Sound Source present at LPT1
\r
1987 ssNoCheck = SoundSourcePresent = true;
\r
1989 case 6: // Sound Source present at LPT2
\r
1991 ssNoCheck = SoundSourcePresent = true;
\r
1993 case 7: // Sound Source present at LPT3
\r
1995 ssNoCheck = SoundSourcePresent = true;
\r
2001 SoundUserHook = 0;
\r
2003 t0OldService = getvect(8); // Get old timer 0 ISR
\r
2005 LocalTime = TimeCount = alTimeCount = 0;
\r
2007 SD_SetSoundMode(sdm_Off);
\r
2008 SD_SetMusicMode(smm_Off);
\r
2011 SoundSourcePresent = SDL_DetectSoundSource();
\r
2015 AdLibPresent = SDL_DetectAdLib();
\r
2016 if (AdLibPresent && !sbNoCheck)
\r
2019 char *env = getenv("BLASTER");
\r
2025 while (isspace(*env))
\r
2028 switch (toupper(*env))
\r
2031 temp = strtol(env + 1,&env,16);
\r
2035 && (temp <= 0x260)
\r
2036 && (!(temp & 0x00f))
\r
2038 port = (temp - 0x200) >> 4;
\r
2040 Quit("SD_Startup: Unsupported address value in BLASTER");
\r
2043 temp = strtol(env + 1,&env,10);
\r
2048 && (sbIntVectors[temp] != -1)
\r
2051 sbInterrupt = temp;
\r
2052 sbIntVec = sbIntVectors[sbInterrupt];
\r
2055 Quit("SD_Startup: Unsupported interrupt value in BLASTER");
\r
2058 temp = strtol(env + 1,&env,10);
\r
2059 if ((temp == 0) || (temp == 1) || (temp == 3))
\r
2060 SDL_SBSetDMA(temp);
\r
2062 Quit("SD_Startup: Unsupported DMA value in BLASTER");
\r
2065 while (isspace(*env))
\r
2067 while (*env && !isspace(*env))
\r
2073 SoundBlasterPresent = SDL_DetectSoundBlaster(port);
\r
2077 for (i = 0;i < 255;i++)
\r
2078 pcSoundLookup[i] = i * 60;
\r
2080 if (SoundBlasterPresent)
\r
2085 SD_Started = true;
\r
2088 ///////////////////////////////////////////////////////////////////////////
\r
2090 // SD_Default() - Sets up the default behaviour for the Sound Mgr whether
\r
2091 // the config file was present or not.
\r
2093 ///////////////////////////////////////////////////////////////////////////
\r
2095 SD_Default(boolean gotit,SDMode sd,SMMode sm)
\r
2097 boolean gotsd,gotsm;
\r
2099 gotsd = gotsm = gotit;
\r
2101 if (gotsd) // Make sure requested sound hardware is available
\r
2106 gotsd = AdLibPresent;
\r
2117 if (sd != SoundMode)
\r
2118 SD_SetSoundMode(sd);
\r
2121 if (gotsm) // Make sure requested music hardware is available
\r
2126 gotsm = AdLibPresent;
\r
2135 if (sm != MusicMode)
\r
2136 SD_SetMusicMode(sm);
\r
2139 ///////////////////////////////////////////////////////////////////////////
\r
2141 // SD_Shutdown() - shuts down the Sound Mgr
\r
2142 // Removes sound ISR and turns off whatever sound hardware was active
\r
2144 ///////////////////////////////////////////////////////////////////////////
\r
2154 SDL_CleanDevice();
\r
2156 if (SoundBlasterPresent)
\r
2159 if (SoundSourcePresent)
\r
2167 setvect(8,t0OldService);
\r
2171 SD_Started = false;
\r
2174 ///////////////////////////////////////////////////////////////////////////
\r
2176 // SD_SetUserHook() - sets the routine that the Sound Mgr calls every 1/70th
\r
2177 // of a second from its timer 0 ISR
\r
2179 ///////////////////////////////////////////////////////////////////////////
\r
2181 SD_SetUserHook(void (* hook)(void))
\r
2183 SoundUserHook = hook;
\r
2186 ///////////////////////////////////////////////////////////////////////////
\r
2188 // SD_PositionSound() - Sets up a stereo imaging location for the next
\r
2189 // sound to be played. Each channel ranges from 0 to 15.
\r
2191 ///////////////////////////////////////////////////////////////////////////
\r
2193 SD_PositionSound(int leftvol,int rightvol)
\r
2195 LeftPosition = leftvol;
\r
2196 RightPosition = rightvol;
\r
2197 nextsoundpos = true;
\r
2200 ///////////////////////////////////////////////////////////////////////////
\r
2202 // SD_PlaySound() - plays the specified sound on the appropriate hardware
\r
2204 ///////////////////////////////////////////////////////////////////////////
\r
2206 SD_PlaySound(soundnames sound)
\r
2209 SoundCommon far *s;
\r
2212 lp = LeftPosition;
\r
2213 rp = RightPosition;
\r
2215 RightPosition = 0;
\r
2217 ispos = nextsoundpos;
\r
2218 nextsoundpos = false;
\r
2223 s = MK_FP(SoundTable[sound],0);
\r
2224 if ((SoundMode != sdm_Off) && !s)
\r
2225 Quit("SD_PlaySound() - Uncached sound");
\r
2227 if ((DigiMode != sds_Off) && (DigiMap[sound] != -1))
\r
2229 if ((DigiMode == sds_PC) && (SoundMode == sdm_PC))
\r
2231 if (s->priority < SoundPriority)
\r
2234 SDL_PCStopSound();
\r
2236 SD_PlayDigitized(DigiMap[sound],lp,rp);
\r
2237 SoundPositioned = ispos;
\r
2238 SoundNumber = sound;
\r
2239 SoundPriority = s->priority;
\r
2245 if (DigiPriority && !DigiNumber)
\r
2248 Quit("SD_PlaySound: Priority without a sound");
\r
2252 if (s->priority < DigiPriority)
\r
2255 SD_PlayDigitized(DigiMap[sound],lp,rp);
\r
2256 SoundPositioned = ispos;
\r
2257 DigiNumber = sound;
\r
2258 DigiPriority = s->priority;
\r
2264 if (SoundMode == sdm_Off)
\r
2267 Quit("SD_PlaySound() - Zero length sound");
\r
2268 if (s->priority < SoundPriority)
\r
2271 switch (SoundMode)
\r
2274 SDL_PCPlaySound((void far *)s);
\r
2277 SDL_ALPlaySound((void far *)s);
\r
2281 SoundNumber = sound;
\r
2282 SoundPriority = s->priority;
\r
2287 ///////////////////////////////////////////////////////////////////////////
\r
2289 // SD_SoundPlaying() - returns the sound number that's playing, or 0 if
\r
2290 // no sound is playing
\r
2292 ///////////////////////////////////////////////////////////////////////////
\r
2294 SD_SoundPlaying(void)
\r
2296 boolean result = false;
\r
2298 switch (SoundMode)
\r
2301 result = pcSound? true : false;
\r
2304 result = alSound? true : false;
\r
2309 return(SoundNumber);
\r
2314 ///////////////////////////////////////////////////////////////////////////
\r
2316 // SD_StopSound() - if a sound is playing, stops it
\r
2318 ///////////////////////////////////////////////////////////////////////////
\r
2320 SD_StopSound(void)
\r
2323 SD_StopDigitized();
\r
2325 switch (SoundMode)
\r
2328 SDL_PCStopSound();
\r
2331 SDL_ALStopSound();
\r
2335 SoundPositioned = false;
\r
2337 SDL_SoundFinished();
\r
2340 ///////////////////////////////////////////////////////////////////////////
\r
2342 // SD_WaitSoundDone() - waits until the current sound is done playing
\r
2344 ///////////////////////////////////////////////////////////////////////////
\r
2346 SD_WaitSoundDone(void)
\r
2348 while (SD_SoundPlaying())
\r
2352 ///////////////////////////////////////////////////////////////////////////
\r
2354 // SD_MusicOn() - turns on the sequencer
\r
2356 ///////////////////////////////////////////////////////////////////////////
\r
2363 ///////////////////////////////////////////////////////////////////////////
\r
2365 // SD_MusicOff() - turns off the sequencer and any playing notes
\r
2367 ///////////////////////////////////////////////////////////////////////////
\r
2374 switch (MusicMode)
\r
2378 alOut(alEffects,0);
\r
2379 for (i = 0;i < sqMaxTracks;i++)
\r
2380 alOut(alFreqH + i + 1,0);
\r
2386 ///////////////////////////////////////////////////////////////////////////
\r
2388 // SD_StartMusic() - starts playing the music pointed to
\r
2390 ///////////////////////////////////////////////////////////////////////////
\r
2392 SD_StartMusic(MusicGroup far *music)
\r
2398 if (MusicMode == smm_AdLib)
\r
2400 sqHackPtr = sqHack = music->values;
\r
2401 sqHackSeqLen = sqHackLen = music->length;
\r
2410 ///////////////////////////////////////////////////////////////////////////
\r
2412 // SD_FadeOutMusic() - starts fading out the music. Call SD_MusicPlaying()
\r
2413 // to see if the fadeout is complete
\r
2415 ///////////////////////////////////////////////////////////////////////////
\r
2417 SD_FadeOutMusic(void)
\r
2419 switch (MusicMode)
\r
2422 // DEBUG - quick hack to turn the music off
\r
2428 ///////////////////////////////////////////////////////////////////////////
\r
2430 // SD_MusicPlaying() - returns true if music is currently playing, false if
\r
2433 ///////////////////////////////////////////////////////////////////////////
\r
2435 SD_MusicPlaying(void)
\r
2439 switch (MusicMode)
\r
2443 // DEBUG - not written
\r
2462 void SDL_turnOnPCSpeaker(word timerval)
\r
2478 void SDL_turnOffPCSpeaker()
\r
2487 void SDL_setPCSpeaker(byte val)
\r
2502 if(*pcSound!=pcLastSample)
\r
2504 pcLastSample=*pcSound;
\r
2507 SDL_turnOnPCSpeaker(pcLastSample*60);
\r
2509 SDL_turnOffPCSpeaker();
\r
2516 SoundNumber=(soundnames)0;
\r
2518 SDL_turnOffPCSpeaker();
\r
2522 if(alSound && !alNoIRQ)
\r
2526 alOutInIRQ(alFreqL,*alSound);
\r
2527 alOutInIRQ(alFreqH,alBlock);
\r
2529 else alOutInIRQ(alFreqH,0);
\r
2535 SoundNumber=(soundnames)0;
\r
2537 alOutInIRQ(alFreqH,0);
\r
2560 if(sqActive && !alNoIRQ)
\r
2566 if(sqHackTime>alTimeCount) break;
\r
2567 sqHackTime=alTimeCount+*(sqHackPtr+1);
\r
2568 alOutInIRQ(*(byte *)sqHackPtr,*(((byte *)sqHackPtr)+1));
\r
2578 sqHackLen=sqHackSeqLen;
\r
2586 if(!(inp(ssStatus)&0x40))
\r
2588 outp(ssData,*ssSample++);
\r
2589 outp(ssControl,ssOff);
\r
2592 outp(ssControl,ssOn);
\r
2599 SDL_DigitizedDoneInIRQ();
\r
2604 TimerCount+=TimerDivisor;
\r
2605 if(*((word *)&TimerCount+1))
\r
2607 *((word *)&TimerCount+1)=0;
\r
2616 // Timer 0 ISR for 7000Hz interrupts
\r
2617 void interrupt SDL_t0ExtremeAsmService(void)
\r
2623 SDL_setPCSpeaker(((*pcSound++)&0x80)>>6);
\r
2628 SDL_turnOffPCSpeaker();
\r
2629 SDL_DigitizedDoneInIRQ();
\r
2643 // Timer 0 ISR for 7000Hz interrupts
\r
2644 void interrupt __SDL_t0ExtremeAsmService()
\r
2650 SDL_setPCSpeaker(((*pcSound++)&0x80)>>6);
\r
2655 SDL_turnOffPCSpeaker();
\r
2656 SDL_DigitizedDoneInIRQ();
\r
2670 // Timer 0 ISR for 700Hz interrupts
\r
2671 void interrupt SDL_t0FastAsmService(void)
\r
2676 // Timer 0 ISR for 140Hz interrupts
\r
2677 void interrupt SDL_t0SlowAsmService(void)
\r
2688 TimerCount+=TimerDivisor;
\r
2689 if(*((word *)&TimerCount+1))
\r
2691 *((word *)&TimerCount+1)=0;
\r
2698 void SDL_IndicatePC(boolean ind)
\r
2704 SDL_DigitizedDoneInIRQ(void)
\r
2708 SDL_PlayDigiSegment(DigiNextAddr,DigiNextLen/*,true*/);
\r
2709 DigiNextAddr = nil;
\r
2710 DigiMissed = false;
\r
2714 if (DigiLastSegment)
\r
2716 DigiPlaying = false;
\r
2717 DigiLastSegment = false;
\r
2718 if ((DigiMode == sds_PC) && (SoundMode == sdm_PC))
\r
2720 SDL_SoundFinished();
\r
2724 DigiNumber = (soundnames) 0;
\r
2727 SoundPositioned = false;
\r
2730 DigiMissed = true;
\r
2734 // Inside an interrupt handler interrupts should already be disabled
\r
2735 // so don't disable them again and cause V86 exceptions which cost
\r
2736 // aprox. 300 processor tics!
\r
2739 void alOutInIRQ(byte n,byte b)
\r