]> 4ch.mooo.com Git - 16.git/blob - 16/wf3d8086/id_sd.c
reference to the bbocg
[16.git] / 16 / wf3d8086 / id_sd.c
1 //\r
2 //      ID Engine\r
3 //      ID_SD.c - Sound Manager for Wolfenstein 3D\r
4 //      v1.2\r
5 //      By Jason Blochowiak\r
6 //\r
7 \r
8 //\r
9 //      This module handles dealing with generating sound on the appropriate\r
10 //              hardware\r
11 //\r
12 //      Depends on: User Mgr (for parm checking)\r
13 //\r
14 //      Globals:\r
15 //              For User Mgr:\r
16 //                      SoundSourcePresent - Sound Source thingie present?\r
17 //                      SoundBlasterPresent - SoundBlaster card present?\r
18 //                      AdLibPresent - AdLib card present?\r
19 //                      SoundMode - What device is used for sound effects\r
20 //                              (Use SM_SetSoundMode() to set)\r
21 //                      MusicMode - What device is used for music\r
22 //                              (Use SM_SetMusicMode() to set)\r
23 //                      DigiMode - What device is used for digitized sound effects\r
24 //                              (Use SM_SetDigiDevice() to set)\r
25 //\r
26 //              For Cache Mgr:\r
27 //                      NeedsDigitized - load digitized sounds?\r
28 //                      NeedsMusic - load music?\r
29 //\r
30 \r
31 #pragma hdrstop         // Wierdo thing with MUSE\r
32 \r
33 #include <dos.h>\r
34 \r
35 #ifdef  _MUSE_      // Will be defined in ID_Types.h\r
36 #include "ID_SD.h"\r
37 #else\r
38 #include "ID_HEADS.H"\r
39 #endif\r
40 #pragma hdrstop\r
41 #pragma warn    -pia\r
42 \r
43 #ifdef  nil\r
44 #undef  nil\r
45 #endif\r
46 #define nil     0\r
47 \r
48 #define SDL_SoundFinished()     {SoundNumber = SoundPriority = 0;}\r
49 \r
50 // Macros for SoundBlaster stuff\r
51 #define sbOut(n,b)      outportb((n) + sbLocation,b)\r
52 #define sbIn(n)         inportb((n) + sbLocation)\r
53 #define sbWriteDelay()  while (sbIn(sbWriteStat) & 0x80);\r
54 #define sbReadDelay()   while (sbIn(sbDataAvail) & 0x80);\r
55 \r
56 // Macros for AdLib stuff\r
57 #define selreg(n)       outportb(alFMAddr,n)\r
58 #define writereg(n)     outportb(alFMData,n)\r
59 #define readstat()      inportb(alFMStatus)\r
60 \r
61 //      Imports from ID_SD_A.ASM\r
62 extern  void                    SDL_SetDS(void),\r
63                                                 SDL_IndicatePC(boolean on);\r
64 extern  void interrupt  SDL_t0ExtremeAsmService(void),\r
65                                                 SDL_t0FastAsmService(void),\r
66                                                 SDL_t0SlowAsmService(void);\r
67 \r
68 //      Global variables\r
69         boolean         SoundSourcePresent,\r
70                                 AdLibPresent,\r
71                                 SoundBlasterPresent,SBProPresent,\r
72                                 NeedsDigitized,NeedsMusic,\r
73                                 SoundPositioned;\r
74         SDMode          SoundMode;\r
75         SMMode          MusicMode;\r
76         SDSMode         DigiMode;\r
77         longword        TimeCount;\r
78         word            HackCount;\r
79         word            *SoundTable;    // Really * _seg *SoundTable, but that don't work\r
80         boolean         ssIsTandy;\r
81         word            ssPort = 2;\r
82         int                     DigiMap[LASTSOUND];\r
83 \r
84 //      Internal variables\r
85 static  boolean                 SD_Started;\r
86                 boolean                 nextsoundpos;\r
87                 longword                TimerDivisor,TimerCount;\r
88 static  char                    *ParmStrings[] =\r
89                                                 {\r
90                                                         "noal",\r
91                                                         "nosb",\r
92                                                         "nopro",\r
93                                                         "noss",\r
94                                                         "sst",\r
95                                                         "ss1",\r
96                                                         "ss2",\r
97                                                         "ss3",\r
98                                                         nil\r
99                                                 };\r
100 static  void                    (*SoundUserHook)(void);\r
101                 soundnames              SoundNumber,DigiNumber;\r
102                 word                    SoundPriority,DigiPriority;\r
103                 int                             LeftPosition,RightPosition;\r
104                 void interrupt  (*t0OldService)(void);\r
105                 long                    LocalTime;\r
106                 word                    TimerRate;\r
107 \r
108                 word                    NumDigi,DigiLeft,DigiPage;\r
109                 word                    _seg *DigiList;\r
110                 word                    DigiLastStart,DigiLastEnd;\r
111                 boolean                 DigiPlaying;\r
112 static  boolean                 DigiMissed,DigiLastSegment;\r
113 static  memptr                  DigiNextAddr;\r
114 static  word                    DigiNextLen;\r
115 \r
116 //      SoundBlaster variables\r
117 static  boolean                                 sbNoCheck,sbNoProCheck;\r
118 static  volatile boolean                sbSamplePlaying;\r
119 static  byte                                    sbOldIntMask = -1;\r
120 static  volatile byte                   huge *sbNextSegPtr;\r
121 static  byte                                    sbDMA = 1,\r
122                                                                 sbDMAa1 = 0x83,sbDMAa2 = 2,sbDMAa3 = 3,\r
123                                                                 sba1Vals[] = {0x87,0x83,0,0x82},\r
124                                                                 sba2Vals[] = {0,2,0,6},\r
125                                                                 sba3Vals[] = {1,3,0,7};\r
126 static  int                                             sbLocation = -1,sbInterrupt = 7,sbIntVec = 0xf,\r
127                                                                 sbIntVectors[] = {-1,-1,0xa,0xb,-1,0xd,-1,0xf,-1,-1,-1};\r
128 static  volatile longword               sbNextSegLen;\r
129 static  volatile SampledSound   huge *sbSamples;\r
130 static  void interrupt                  (*sbOldIntHand)(void);\r
131 static  byte                                    sbpOldFMMix,sbpOldVOCMix;\r
132 \r
133 //      SoundSource variables\r
134                 boolean                         ssNoCheck;\r
135                 boolean                         ssActive;\r
136                 word                            ssControl,ssStatus,ssData;\r
137                 byte                            ssOn,ssOff;\r
138                 volatile byte           far *ssSample;\r
139                 volatile longword       ssLengthLeft;\r
140 \r
141 //      PC Sound variables\r
142                 volatile byte   pcLastSample,far *pcSound;\r
143                 longword                pcLengthLeft;\r
144                 word                    pcSoundLookup[255];\r
145 \r
146 //      AdLib variables\r
147                 boolean                 alNoCheck;\r
148                 byte                    far *alSound;\r
149                 word                    alBlock;\r
150                 longword                alLengthLeft;\r
151                 longword                alTimeCount;\r
152                 Instrument              alZeroInst;\r
153 \r
154 // This table maps channel numbers to carrier and modulator op cells\r
155 static  byte                    carriers[9] =  { 3, 4, 5,11,12,13,19,20,21},\r
156                                                 modifiers[9] = { 0, 1, 2, 8, 9,10,16,17,18},\r
157 // This table maps percussive voice numbers to op cells\r
158                                                 pcarriers[5] = {19,0xff,0xff,0xff,0xff},\r
159                                                 pmodifiers[5] = {16,17,18,20,21};\r
160 \r
161 //      Sequencer variables\r
162                 boolean                 sqActive;\r
163 static  word                    alFXReg;\r
164 static  ActiveTrack             *tracks[sqMaxTracks],\r
165                                                 mytracks[sqMaxTracks];\r
166 static  word                    sqMode,sqFadeStep;\r
167                 word                    far *sqHack,far *sqHackPtr,sqHackLen,sqHackSeqLen;\r
168                 long                    sqHackTime;\r
169 \r
170 //      Internal routines\r
171                 void                    SDL_DigitizedDone(void);\r
172 \r
173 ///////////////////////////////////////////////////////////////////////////\r
174 //\r
175 //      SDL_SetTimer0() - Sets system timer 0 to the specified speed\r
176 //\r
177 ///////////////////////////////////////////////////////////////////////////\r
178 #pragma argsused\r
179 static void\r
180 SDL_SetTimer0(word speed)\r
181 {\r
182 #ifndef TPROF   // If using Borland's profiling, don't screw with the timer\r
183 asm     pushf\r
184 asm     cli\r
185 \r
186         outportb(0x43,0x36);                            // Change timer 0\r
187         outportb(0x40,speed);\r
188         outportb(0x40,speed >> 8);\r
189         // Kludge to handle special case for digitized PC sounds\r
190         if (TimerDivisor == (1192030 / (TickBase * 100)))\r
191                 TimerDivisor = (1192030 / (TickBase * 10));\r
192         else\r
193                 TimerDivisor = speed;\r
194 \r
195 asm     popf\r
196 #else\r
197         TimerDivisor = 0x10000;\r
198 #endif\r
199 }\r
200 \r
201 ///////////////////////////////////////////////////////////////////////////\r
202 //\r
203 //      SDL_SetIntsPerSec() - Uses SDL_SetTimer0() to set the number of\r
204 //              interrupts generated by system timer 0 per second\r
205 //\r
206 ///////////////////////////////////////////////////////////////////////////\r
207 static void\r
208 SDL_SetIntsPerSec(word ints)\r
209 {\r
210         TimerRate = ints;\r
211         SDL_SetTimer0(1192030 / ints);\r
212 }\r
213 \r
214 static void\r
215 SDL_SetTimerSpeed(void)\r
216 {\r
217         word    rate;\r
218         void interrupt  (*isr)(void);\r
219 \r
220         if ((DigiMode == sds_PC) && DigiPlaying)\r
221         {\r
222                 rate = TickBase * 100;\r
223                 isr = SDL_t0ExtremeAsmService;\r
224         }\r
225         else if\r
226         (\r
227                 (MusicMode == smm_AdLib)\r
228         ||      ((DigiMode == sds_SoundSource) && DigiPlaying)\r
229         )\r
230         {\r
231                 rate = TickBase * 10;\r
232                 isr = SDL_t0FastAsmService;\r
233         }\r
234         else\r
235         {\r
236                 rate = TickBase * 2;\r
237                 isr = SDL_t0SlowAsmService;\r
238         }\r
239 \r
240         if (rate != TimerRate)\r
241         {\r
242                 setvect(8,isr);\r
243                 SDL_SetIntsPerSec(rate);\r
244                 TimerRate = rate;\r
245         }\r
246 }\r
247 \r
248 //\r
249 //      SoundBlaster code\r
250 //\r
251 \r
252 ///////////////////////////////////////////////////////////////////////////\r
253 //\r
254 //      SDL_SBStopSample() - Stops any active sampled sound and causes DMA\r
255 //              requests from the SoundBlaster to cease\r
256 //\r
257 ///////////////////////////////////////////////////////////////////////////\r
258 #ifdef  _MUSE_\r
259 void\r
260 #else\r
261 static void\r
262 #endif\r
263 SDL_SBStopSample(void)\r
264 {\r
265         byte    is;\r
266 \r
267 asm     pushf\r
268 asm     cli\r
269 \r
270         if (sbSamplePlaying)\r
271         {\r
272                 sbSamplePlaying = false;\r
273 \r
274                 sbWriteDelay();\r
275                 sbOut(sbWriteCmd,0xd0); // Turn off DSP DMA\r
276 \r
277                 is = inportb(0x21);     // Restore interrupt mask bit\r
278                 if (sbOldIntMask & (1 << sbInterrupt))\r
279                         is |= (1 << sbInterrupt);\r
280                 else\r
281                         is &= ~(1 << sbInterrupt);\r
282                 outportb(0x21,is);\r
283         }\r
284 \r
285 asm     popf\r
286 }\r
287 \r
288 ///////////////////////////////////////////////////////////////////////////\r
289 //\r
290 //      SDL_SBPlaySeg() - Plays a chunk of sampled sound on the SoundBlaster\r
291 //      Insures that the chunk doesn't cross a bank boundary, programs the DMA\r
292 //       controller, and tells the SB to start doing DMA requests for DAC\r
293 //\r
294 ///////////////////////////////////////////////////////////////////////////\r
295 static longword\r
296 SDL_SBPlaySeg(volatile byte huge *data,longword length)\r
297 {\r
298         unsigned                datapage;\r
299         longword                dataofs,uselen;\r
300 \r
301         uselen = length;\r
302         datapage = FP_SEG(data) >> 12;\r
303         dataofs = ((FP_SEG(data) & 0xfff) << 4) + FP_OFF(data);\r
304         if (dataofs >= 0x10000)\r
305         {\r
306                 datapage++;\r
307                 dataofs -= 0x10000;\r
308         }\r
309 \r
310         if (dataofs + uselen > 0x10000)\r
311                 uselen = 0x10000 - dataofs;\r
312 \r
313         uselen--;\r
314 \r
315         // Program the DMA controller\r
316 asm     pushf\r
317 asm     cli\r
318         outportb(0x0a,sbDMA | 4);                                       // Mask off DMA on channel sbDMA\r
319         outportb(0x0c,0);                                                       // Clear byte ptr flip-flop to lower byte\r
320         outportb(0x0b,0x49);                                            // Set transfer mode for D/A conv\r
321         outportb(sbDMAa2,(byte)dataofs);                        // Give LSB of address\r
322         outportb(sbDMAa2,(byte)(dataofs >> 8));         // Give MSB of address\r
323         outportb(sbDMAa1,(byte)datapage);                       // Give page of address\r
324         outportb(sbDMAa3,(byte)uselen);                         // Give LSB of length\r
325         outportb(sbDMAa3,(byte)(uselen >> 8));          // Give MSB of length\r
326         outportb(0x0a,sbDMA);                                           // Re-enable DMA on channel sbDMA\r
327 \r
328         // Start playing the thing\r
329         sbWriteDelay();\r
330         sbOut(sbWriteCmd,0x14);\r
331         sbWriteDelay();\r
332         sbOut(sbWriteData,(byte)uselen);\r
333         sbWriteDelay();\r
334         sbOut(sbWriteData,(byte)(uselen >> 8));\r
335 asm     popf\r
336 \r
337         return(uselen + 1);\r
338 }\r
339 \r
340 ///////////////////////////////////////////////////////////////////////////\r
341 //\r
342 //      SDL_SBService() - Services the SoundBlaster DMA interrupt\r
343 //\r
344 ///////////////////////////////////////////////////////////////////////////\r
345 static void interrupt\r
346 SDL_SBService(void)\r
347 {\r
348         longword        used;\r
349 \r
350         sbIn(sbDataAvail);      // Ack interrupt to SB\r
351 \r
352         if (sbNextSegPtr)\r
353         {\r
354                 used = SDL_SBPlaySeg(sbNextSegPtr,sbNextSegLen);\r
355                 if (sbNextSegLen <= used)\r
356                         sbNextSegPtr = nil;\r
357                 else\r
358                 {\r
359                         sbNextSegPtr += used;\r
360                         sbNextSegLen -= used;\r
361                 }\r
362         }\r
363         else\r
364         {\r
365                 SDL_SBStopSample();\r
366                 SDL_DigitizedDone();\r
367         }\r
368 \r
369         outportb(0x20,0x20);    // Ack interrupt\r
370 }\r
371 \r
372 ///////////////////////////////////////////////////////////////////////////\r
373 //\r
374 //      SDL_SBPlaySample() - Plays a sampled sound on the SoundBlaster. Sets up\r
375 //              DMA to play the sound\r
376 //\r
377 ///////////////////////////////////////////////////////////////////////////\r
378 #ifdef  _MUSE_\r
379 void\r
380 #else\r
381 static void\r
382 #endif\r
383 SDL_SBPlaySample(byte huge *data,longword len)\r
384 {\r
385         longword        used;\r
386 \r
387         SDL_SBStopSample();\r
388 \r
389 asm     pushf\r
390 asm     cli\r
391 \r
392         used = SDL_SBPlaySeg(data,len);\r
393         if (len <= used)\r
394                 sbNextSegPtr = nil;\r
395         else\r
396         {\r
397                 sbNextSegPtr = data + used;\r
398                 sbNextSegLen = len - used;\r
399         }\r
400 \r
401         // Save old interrupt status and unmask ours\r
402         sbOldIntMask = inportb(0x21);\r
403         outportb(0x21,sbOldIntMask & ~(1 << sbInterrupt));\r
404 \r
405         sbWriteDelay();\r
406         sbOut(sbWriteCmd,0xd4);                                         // Make sure DSP DMA is enabled\r
407 \r
408         sbSamplePlaying = true;\r
409 \r
410 asm     popf\r
411 }\r
412 \r
413 ///////////////////////////////////////////////////////////////////////////\r
414 //\r
415 //      SDL_PositionSBP() - Sets the attenuation levels for the left and right\r
416 //              channels by using the mixer chip on the SB Pro. This hits a hole in\r
417 //              the address map for normal SBs.\r
418 //\r
419 ///////////////////////////////////////////////////////////////////////////\r
420 static void\r
421 SDL_PositionSBP(int leftpos,int rightpos)\r
422 {\r
423         byte    v;\r
424 \r
425         if (!SBProPresent)\r
426                 return;\r
427 \r
428         leftpos = 15 - leftpos;\r
429         rightpos = 15 - rightpos;\r
430         v = ((leftpos & 0x0f) << 4) | (rightpos & 0x0f);\r
431 \r
432 asm     pushf\r
433 asm     cli\r
434 \r
435         sbOut(sbpMixerAddr,sbpmVoiceVol);\r
436         sbOut(sbpMixerData,v);\r
437 \r
438 asm     popf\r
439 }\r
440 \r
441 ///////////////////////////////////////////////////////////////////////////\r
442 //\r
443 //      SDL_CheckSB() - Checks to see if a SoundBlaster resides at a\r
444 //              particular I/O location\r
445 //\r
446 ///////////////////////////////////////////////////////////////////////////\r
447 static boolean\r
448 SDL_CheckSB(int port)\r
449 {\r
450         int     i;\r
451 \r
452         sbLocation = port << 4;         // Initialize stuff for later use\r
453 \r
454         sbOut(sbReset,true);            // Reset the SoundBlaster DSP\r
455 asm     mov     dx,0x388                                // Wait >4usec\r
456 asm     in      al, dx\r
457 asm     in      al, dx\r
458 asm     in      al, dx\r
459 asm     in      al, dx\r
460 asm     in      al, dx\r
461 asm     in      al, dx\r
462 asm     in      al, dx\r
463 asm     in      al, dx\r
464 asm     in      al, dx\r
465 \r
466         sbOut(sbReset,false);           // Turn off sb DSP reset\r
467 asm     mov     dx,0x388                                // Wait >100usec\r
468 asm     mov     cx,100\r
469 usecloop:\r
470 asm     in      al,dx\r
471 asm     loop usecloop\r
472 \r
473         for (i = 0;i < 100;i++)\r
474         {\r
475                 if (sbIn(sbDataAvail) & 0x80)           // If data is available...\r
476                 {\r
477                         if (sbIn(sbReadData) == 0xaa)   // If it matches correct value\r
478                                 return(true);\r
479                         else\r
480                         {\r
481                                 sbLocation = -1;                        // Otherwise not a SoundBlaster\r
482                                 return(false);\r
483                         }\r
484                 }\r
485         }\r
486         sbLocation = -1;                                                // Retry count exceeded - fail\r
487         return(false);\r
488 }\r
489 \r
490 ///////////////////////////////////////////////////////////////////////////\r
491 //\r
492 //      Checks to see if a SoundBlaster is in the system. If the port passed is\r
493 //              -1, then it scans through all possible I/O locations. If the port\r
494 //              passed is 0, then it uses the default (2). If the port is >0, then\r
495 //              it just passes it directly to SDL_CheckSB()\r
496 //\r
497 ///////////////////////////////////////////////////////////////////////////\r
498 static boolean\r
499 SDL_DetectSoundBlaster(int port)\r
500 {\r
501         int     i;\r
502 \r
503         if (port == 0)                                  // If user specifies default, use 2\r
504                 port = 2;\r
505         if (port == -1)\r
506         {\r
507                 if (SDL_CheckSB(2))                     // Check default before scanning\r
508                         return(true);\r
509 \r
510                 if (SDL_CheckSB(4))                     // Check other SB Pro location before scan\r
511                         return(true);\r
512 \r
513                 for (i = 1;i <= 6;i++)          // Scan through possible SB locations\r
514                 {\r
515                         if ((i == 2) || (i == 4))\r
516                                 continue;\r
517 \r
518                         if (SDL_CheckSB(i))             // If found at this address,\r
519                                 return(true);           //      return success\r
520                 }\r
521                 return(false);                          // All addresses failed, return failure\r
522         }\r
523         else\r
524                 return(SDL_CheckSB(port));      // User specified address or default\r
525 }\r
526 \r
527 ///////////////////////////////////////////////////////////////////////////\r
528 //\r
529 //      SDL_SBSetDMA() - Sets the DMA channel to be used by the SoundBlaster\r
530 //              code. Sets up sbDMA, and sbDMAa1-sbDMAa3 (used by SDL_SBPlaySeg()).\r
531 //\r
532 ///////////////////////////////////////////////////////////////////////////\r
533 void\r
534 SDL_SBSetDMA(byte channel)\r
535 {\r
536         if (channel > 3)\r
537                 Quit("SDL_SBSetDMA() - invalid SoundBlaster DMA channel");\r
538 \r
539         sbDMA = channel;\r
540         sbDMAa1 = sba1Vals[channel];\r
541         sbDMAa2 = sba2Vals[channel];\r
542         sbDMAa3 = sba3Vals[channel];\r
543 }\r
544 \r
545 ///////////////////////////////////////////////////////////////////////////\r
546 //\r
547 //      SDL_StartSB() - Turns on the SoundBlaster\r
548 //\r
549 ///////////////////////////////////////////////////////////////////////////\r
550 static void\r
551 SDL_StartSB(void)\r
552 {\r
553         byte    timevalue,test;\r
554 \r
555         sbIntVec = sbIntVectors[sbInterrupt];\r
556         if (sbIntVec < 0)\r
557                 Quit("SDL_StartSB: Illegal or unsupported interrupt number for SoundBlaster");\r
558 \r
559         sbOldIntHand = getvect(sbIntVec);       // Get old interrupt handler\r
560         setvect(sbIntVec,SDL_SBService);        // Set mine\r
561 \r
562         sbWriteDelay();\r
563         sbOut(sbWriteCmd,0xd1);                         // Turn on DSP speaker\r
564 \r
565         // Set the SoundBlaster DAC time constant for 7KHz\r
566         timevalue = 256 - (1000000 / 7000);\r
567         sbWriteDelay();\r
568         sbOut(sbWriteCmd,0x40);\r
569         sbWriteDelay();\r
570         sbOut(sbWriteData,timevalue);\r
571 \r
572         SBProPresent = false;\r
573         if (sbNoProCheck)\r
574                 return;\r
575 \r
576         // Check to see if this is a SB Pro\r
577         sbOut(sbpMixerAddr,sbpmFMVol);\r
578         sbpOldFMMix = sbIn(sbpMixerData);\r
579         sbOut(sbpMixerData,0xbb);\r
580         test = sbIn(sbpMixerData);\r
581         if (test == 0xbb)\r
582         {\r
583                 // Boost FM output levels to be equivilent with digitized output\r
584                 sbOut(sbpMixerData,0xff);\r
585                 test = sbIn(sbpMixerData);\r
586                 if (test == 0xff)\r
587                 {\r
588                         SBProPresent = true;\r
589 \r
590                         // Save old Voice output levels (SB Pro)\r
591                         sbOut(sbpMixerAddr,sbpmVoiceVol);\r
592                         sbpOldVOCMix = sbIn(sbpMixerData);\r
593 \r
594                         // Turn SB Pro stereo DAC off\r
595                         sbOut(sbpMixerAddr,sbpmControl);\r
596                         sbOut(sbpMixerData,0);                          // 0=off,2=on\r
597                 }\r
598         }\r
599 }\r
600 \r
601 ///////////////////////////////////////////////////////////////////////////\r
602 //\r
603 //      SDL_ShutSB() - Turns off the SoundBlaster\r
604 //\r
605 ///////////////////////////////////////////////////////////////////////////\r
606 static void\r
607 SDL_ShutSB(void)\r
608 {\r
609         SDL_SBStopSample();\r
610 \r
611         if (SBProPresent)\r
612         {\r
613                 // Restore FM output levels (SB Pro)\r
614                 sbOut(sbpMixerAddr,sbpmFMVol);\r
615                 sbOut(sbpMixerData,sbpOldFMMix);\r
616 \r
617                 // Restore Voice output levels (SB Pro)\r
618                 sbOut(sbpMixerAddr,sbpmVoiceVol);\r
619                 sbOut(sbpMixerData,sbpOldVOCMix);\r
620         }\r
621 \r
622         setvect(sbIntVec,sbOldIntHand);         // Set vector back\r
623 }\r
624 \r
625 //      Sound Source Code\r
626 \r
627 ///////////////////////////////////////////////////////////////////////////\r
628 //\r
629 //      SDL_SSStopSample() - Stops a sample playing on the Sound Source\r
630 //\r
631 ///////////////////////////////////////////////////////////////////////////\r
632 #ifdef  _MUSE_\r
633 void\r
634 #else\r
635 static void\r
636 #endif\r
637 SDL_SSStopSample(void)\r
638 {\r
639 asm     pushf\r
640 asm     cli\r
641 \r
642         (long)ssSample = 0;\r
643 \r
644 asm     popf\r
645 }\r
646 \r
647 ///////////////////////////////////////////////////////////////////////////\r
648 //\r
649 //      SDL_SSService() - Handles playing the next sample on the Sound Source\r
650 //\r
651 ///////////////////////////////////////////////////////////////////////////\r
652 static void\r
653 SDL_SSService(void)\r
654 {\r
655         boolean gotit;\r
656         byte    v;\r
657 \r
658         while (ssSample)\r
659         {\r
660         asm     mov             dx,[ssStatus]   // Check to see if FIFO is currently empty\r
661         asm     in              al,dx\r
662         asm     test    al,0x40\r
663         asm     jnz             done                    // Nope - don't push any more data out\r
664 \r
665                 v = *ssSample++;\r
666                 if (!(--ssLengthLeft))\r
667                 {\r
668                         (long)ssSample = 0;\r
669                         SDL_DigitizedDone();\r
670                 }\r
671 \r
672         asm     mov             dx,[ssData]             // Pump the value out\r
673         asm     mov             al,[v]\r
674         asm     out             dx,al\r
675 \r
676         asm     mov             dx,[ssControl]  // Pulse printer select\r
677         asm     mov             al,[ssOff]\r
678         asm     out             dx,al\r
679         asm     push    ax\r
680         asm     pop             ax\r
681         asm     mov             al,[ssOn]\r
682         asm     out             dx,al\r
683 \r
684         asm     push    ax                              // Delay a short while\r
685         asm     pop             ax\r
686         asm     push    ax\r
687         asm     pop             ax\r
688         }\r
689 done:;\r
690 }\r
691 \r
692 ///////////////////////////////////////////////////////////////////////////\r
693 //\r
694 //      SDL_SSPlaySample() - Plays the specified sample on the Sound Source\r
695 //\r
696 ///////////////////////////////////////////////////////////////////////////\r
697 #ifdef  _MUSE_\r
698 void\r
699 #else\r
700 static void\r
701 #endif\r
702 SDL_SSPlaySample(byte huge *data,longword len)\r
703 {\r
704 asm     pushf\r
705 asm     cli\r
706 \r
707         ssLengthLeft = len;\r
708         ssSample = (volatile byte far *)data;\r
709 \r
710 asm     popf\r
711 }\r
712 \r
713 ///////////////////////////////////////////////////////////////////////////\r
714 //\r
715 //      SDL_StartSS() - Sets up for and turns on the Sound Source\r
716 //\r
717 ///////////////////////////////////////////////////////////////////////////\r
718 static void\r
719 SDL_StartSS(void)\r
720 {\r
721         if (ssPort == 3)\r
722                 ssControl = 0x27a;      // If using LPT3\r
723         else if (ssPort == 2)\r
724                 ssControl = 0x37a;      // If using LPT2\r
725         else\r
726                 ssControl = 0x3be;      // If using LPT1\r
727         ssStatus = ssControl - 1;\r
728         ssData = ssStatus - 1;\r
729 \r
730         ssOn = 0x04;\r
731         if (ssIsTandy)\r
732                 ssOff = 0x0e;                           // Tandy wierdness\r
733         else\r
734                 ssOff = 0x0c;                           // For normal machines\r
735 \r
736         outportb(ssControl,ssOn);               // Enable SS\r
737 }\r
738 \r
739 ///////////////////////////////////////////////////////////////////////////\r
740 //\r
741 //      SDL_ShutSS() - Turns off the Sound Source\r
742 //\r
743 ///////////////////////////////////////////////////////////////////////////\r
744 static void\r
745 SDL_ShutSS(void)\r
746 {\r
747         outportb(ssControl,ssOff);\r
748 }\r
749 \r
750 ///////////////////////////////////////////////////////////////////////////\r
751 //\r
752 //      SDL_CheckSS() - Checks to see if a Sound Source is present at the\r
753 //              location specified by the sound source variables\r
754 //\r
755 ///////////////////////////////////////////////////////////////////////////\r
756 static boolean\r
757 SDL_CheckSS(void)\r
758 {\r
759         boolean         present = false;\r
760         longword        lasttime;\r
761 \r
762         // Turn the Sound Source on and wait awhile (4 ticks)\r
763         SDL_StartSS();\r
764 \r
765         lasttime = TimeCount;\r
766         while (TimeCount < lasttime + 4)\r
767                 ;\r
768 \r
769 asm     mov             dx,[ssStatus]   // Check to see if FIFO is currently empty\r
770 asm     in              al,dx\r
771 asm     test    al,0x40\r
772 asm     jnz             checkdone               // Nope - Sound Source not here\r
773 \r
774 asm     mov             cx,32                   // Force FIFO overflow (FIFO is 16 bytes)\r
775 outloop:\r
776 asm     mov             dx,[ssData]             // Pump a neutral value out\r
777 asm     mov             al,0x80\r
778 asm     out             dx,al\r
779 \r
780 asm     mov             dx,[ssControl]  // Pulse printer select\r
781 asm     mov             al,[ssOff]\r
782 asm     out             dx,al\r
783 asm     push    ax\r
784 asm     pop             ax\r
785 asm     mov             al,[ssOn]\r
786 asm     out             dx,al\r
787 \r
788 asm     push    ax                              // Delay a short while before we do this again\r
789 asm     pop             ax\r
790 asm     push    ax\r
791 asm     pop             ax\r
792 \r
793 asm     loop    outloop\r
794 \r
795 asm     mov             dx,[ssStatus]   // Is FIFO overflowed now?\r
796 asm     in              al,dx\r
797 asm     test    al,0x40\r
798 asm     jz              checkdone               // Nope, still not - Sound Source not here\r
799 \r
800         present = true;                 // Yes - it's here!\r
801 \r
802 checkdone:\r
803         SDL_ShutSS();\r
804         return(present);\r
805 }\r
806 \r
807 static boolean\r
808 SDL_DetectSoundSource(void)\r
809 {\r
810         for (ssPort = 1;ssPort <= 3;ssPort++)\r
811                 if (SDL_CheckSS())\r
812                         return(true);\r
813         return(false);\r
814 }\r
815 \r
816 //\r
817 //      PC Sound code\r
818 //\r
819 \r
820 ///////////////////////////////////////////////////////////////////////////\r
821 //\r
822 //      SDL_PCPlaySample() - Plays the specified sample on the PC speaker\r
823 //\r
824 ///////////////////////////////////////////////////////////////////////////\r
825 #ifdef  _MUSE_\r
826 void\r
827 #else\r
828 static void\r
829 #endif\r
830 SDL_PCPlaySample(byte huge *data,longword len)\r
831 {\r
832 asm     pushf\r
833 asm     cli\r
834 \r
835         SDL_IndicatePC(true);\r
836 \r
837         pcLengthLeft = len;\r
838         pcSound = (volatile byte far *)data;\r
839 \r
840 asm     popf\r
841 }\r
842 \r
843 ///////////////////////////////////////////////////////////////////////////\r
844 //\r
845 //      SDL_PCStopSample() - Stops a sample playing on the PC speaker\r
846 //\r
847 ///////////////////////////////////////////////////////////////////////////\r
848 #ifdef  _MUSE_\r
849 void\r
850 #else\r
851 static void\r
852 #endif\r
853 SDL_PCStopSample(void)\r
854 {\r
855 asm     pushf\r
856 asm     cli\r
857 \r
858         (long)pcSound = 0;\r
859 \r
860         SDL_IndicatePC(false);\r
861 \r
862 asm     in      al,0x61                 // Turn the speaker off\r
863 asm     and     al,0xfd                 // ~2\r
864 asm     out     0x61,al\r
865 \r
866 asm     popf\r
867 }\r
868 \r
869 ///////////////////////////////////////////////////////////////////////////\r
870 //\r
871 //      SDL_PCPlaySound() - Plays the specified sound on the PC speaker\r
872 //\r
873 ///////////////////////////////////////////////////////////////////////////\r
874 #ifdef  _MUSE_\r
875 void\r
876 #else\r
877 static void\r
878 #endif\r
879 SDL_PCPlaySound(PCSound far *sound)\r
880 {\r
881 asm     pushf\r
882 asm     cli\r
883 \r
884         pcLastSample = -1;\r
885         pcLengthLeft = sound->common.length;\r
886         pcSound = sound->data;\r
887 \r
888 asm     popf\r
889 }\r
890 \r
891 ///////////////////////////////////////////////////////////////////////////\r
892 //\r
893 //      SDL_PCStopSound() - Stops the current sound playing on the PC Speaker\r
894 //\r
895 ///////////////////////////////////////////////////////////////////////////\r
896 #ifdef  _MUSE_\r
897 void\r
898 #else\r
899 static void\r
900 #endif\r
901 SDL_PCStopSound(void)\r
902 {\r
903 asm     pushf\r
904 asm     cli\r
905 \r
906         (long)pcSound = 0;\r
907 \r
908 asm     in      al,0x61                 // Turn the speaker off\r
909 asm     and     al,0xfd                 // ~2\r
910 asm     out     0x61,al\r
911 \r
912 asm     popf\r
913 }\r
914 \r
915 #if 0\r
916 ///////////////////////////////////////////////////////////////////////////\r
917 //\r
918 //      SDL_PCService() - Handles playing the next sample in a PC sound\r
919 //\r
920 ///////////////////////////////////////////////////////////////////////////\r
921 static void\r
922 SDL_PCService(void)\r
923 {\r
924         byte    s;\r
925         word    t;\r
926 \r
927         if (pcSound)\r
928         {\r
929                 s = *pcSound++;\r
930                 if (s != pcLastSample)\r
931                 {\r
932                 asm     pushf\r
933                 asm     cli\r
934 \r
935                         pcLastSample = s;\r
936                         if (s)                                  // We have a frequency!\r
937                         {\r
938                                 t = pcSoundLookup[s];\r
939                         asm     mov     bx,[t]\r
940 \r
941                         asm     mov     al,0xb6                 // Write to channel 2 (speaker) timer\r
942                         asm     out     43h,al\r
943                         asm     mov     al,bl\r
944                         asm     out     42h,al                  // Low byte\r
945                         asm     mov     al,bh\r
946                         asm     out     42h,al                  // High byte\r
947 \r
948                         asm     in      al,0x61                 // Turn the speaker & gate on\r
949                         asm     or      al,3\r
950                         asm     out     0x61,al\r
951                         }\r
952                         else                                    // Time for some silence\r
953                         {\r
954                         asm     in      al,0x61                 // Turn the speaker & gate off\r
955                         asm     and     al,0xfc                 // ~3\r
956                         asm     out     0x61,al\r
957                         }\r
958 \r
959                 asm     popf\r
960                 }\r
961 \r
962                 if (!(--pcLengthLeft))\r
963                 {\r
964                         SDL_PCStopSound();\r
965                         SDL_SoundFinished();\r
966                 }\r
967         }\r
968 }\r
969 #endif\r
970 \r
971 ///////////////////////////////////////////////////////////////////////////\r
972 //\r
973 //      SDL_ShutPC() - Turns off the pc speaker\r
974 //\r
975 ///////////////////////////////////////////////////////////////////////////\r
976 static void\r
977 SDL_ShutPC(void)\r
978 {\r
979 asm     pushf\r
980 asm     cli\r
981 \r
982         pcSound = 0;\r
983 \r
984 asm     in      al,0x61                 // Turn the speaker & gate off\r
985 asm     and     al,0xfc                 // ~3\r
986 asm     out     0x61,al\r
987 \r
988 asm     popf\r
989 }\r
990 \r
991 //\r
992 //      Stuff for digitized sounds\r
993 //\r
994 memptr\r
995 SDL_LoadDigiSegment(word page)\r
996 {\r
997         memptr  addr;\r
998 \r
999 #if 0   // for debugging\r
1000 asm     mov     dx,STATUS_REGISTER_1\r
1001 asm     in      al,dx\r
1002 asm     mov     dx,ATR_INDEX\r
1003 asm     mov     al,ATR_OVERSCAN\r
1004 asm     out     dx,al\r
1005 asm     mov     al,10   // bright green\r
1006 asm     out     dx,al\r
1007 #endif\r
1008 \r
1009         addr = PM_GetSoundPage(page);\r
1010         PM_SetPageLock(PMSoundStart + page,pml_Locked);\r
1011 \r
1012 #if 0   // for debugging\r
1013 asm     mov     dx,STATUS_REGISTER_1\r
1014 asm     in      al,dx\r
1015 asm     mov     dx,ATR_INDEX\r
1016 asm     mov     al,ATR_OVERSCAN\r
1017 asm     out     dx,al\r
1018 asm     mov     al,3    // blue\r
1019 asm     out     dx,al\r
1020 asm     mov     al,0x20 // normal\r
1021 asm     out     dx,al\r
1022 #endif\r
1023 \r
1024         return(addr);\r
1025 }\r
1026 \r
1027 void\r
1028 SDL_PlayDigiSegment(memptr addr,word len)\r
1029 {\r
1030         switch (DigiMode)\r
1031         {\r
1032         case sds_PC:\r
1033         SDL_PCPlaySample(addr,len);\r
1034                 break;\r
1035         case sds_SoundSource:\r
1036                 SDL_SSPlaySample(addr,len);\r
1037                 break;\r
1038         case sds_SoundBlaster:\r
1039                 SDL_SBPlaySample(addr,len);\r
1040                 break;\r
1041         }\r
1042 }\r
1043 \r
1044 void\r
1045 SD_StopDigitized(void)\r
1046 {\r
1047         int     i;\r
1048 \r
1049 asm     pushf\r
1050 asm     cli\r
1051 \r
1052         DigiLeft = 0;\r
1053         DigiNextAddr = nil;\r
1054         DigiNextLen = 0;\r
1055         DigiMissed = false;\r
1056         DigiPlaying = false;\r
1057         DigiNumber = DigiPriority = 0;\r
1058         SoundPositioned = false;\r
1059         if ((DigiMode == sds_PC) && (SoundMode == sdm_PC))\r
1060                 SDL_SoundFinished();\r
1061 \r
1062         switch (DigiMode)\r
1063         {\r
1064         case sds_PC:\r
1065                 SDL_PCStopSample();\r
1066                 break;\r
1067         case sds_SoundSource:\r
1068                 SDL_SSStopSample();\r
1069                 break;\r
1070         case sds_SoundBlaster:\r
1071                 SDL_SBStopSample();\r
1072                 break;\r
1073         }\r
1074 \r
1075 asm     popf\r
1076 \r
1077         for (i = DigiLastStart;i < DigiLastEnd;i++)\r
1078                 PM_SetPageLock(i + PMSoundStart,pml_Unlocked);\r
1079         DigiLastStart = 1;\r
1080         DigiLastEnd = 0;\r
1081 }\r
1082 \r
1083 void\r
1084 SD_Poll(void)\r
1085 {\r
1086         if (DigiLeft && !DigiNextAddr)\r
1087         {\r
1088                 DigiNextLen = (DigiLeft >= PMPageSize)? PMPageSize : (DigiLeft % PMPageSize);\r
1089                 DigiLeft -= DigiNextLen;\r
1090                 if (!DigiLeft)\r
1091                         DigiLastSegment = true;\r
1092                 DigiNextAddr = SDL_LoadDigiSegment(DigiPage++);\r
1093         }\r
1094         if (DigiMissed && DigiNextAddr)\r
1095         {\r
1096                 SDL_PlayDigiSegment(DigiNextAddr,DigiNextLen);\r
1097                 DigiNextAddr = nil;\r
1098                 DigiMissed = false;\r
1099                 if (DigiLastSegment)\r
1100                 {\r
1101                         DigiPlaying = false;\r
1102                         DigiLastSegment = false;\r
1103                 }\r
1104         }\r
1105         SDL_SetTimerSpeed();\r
1106 }\r
1107 \r
1108 void\r
1109 SD_SetPosition(int leftpos,int rightpos)\r
1110 {\r
1111         if\r
1112         (\r
1113                 (leftpos < 0)\r
1114         ||      (leftpos > 15)\r
1115         ||      (rightpos < 0)\r
1116         ||      (rightpos > 15)\r
1117         ||      ((leftpos == 15) && (rightpos == 15))\r
1118         )\r
1119                 Quit("SD_SetPosition: Illegal position");\r
1120 \r
1121         switch (DigiMode)\r
1122         {\r
1123         case sds_SoundBlaster:\r
1124                 SDL_PositionSBP(leftpos,rightpos);\r
1125                 break;\r
1126         }\r
1127 }\r
1128 \r
1129 void\r
1130 SD_PlayDigitized(word which,int leftpos,int rightpos)\r
1131 {\r
1132         word    len;\r
1133         memptr  addr;\r
1134 \r
1135         if (!DigiMode)\r
1136                 return;\r
1137 \r
1138         SD_StopDigitized();\r
1139         if (which >= NumDigi)\r
1140                 Quit("SD_PlayDigitized: bad sound number");\r
1141 \r
1142         SD_SetPosition(leftpos,rightpos);\r
1143 \r
1144         DigiPage = DigiList[(which * 2) + 0];\r
1145         DigiLeft = DigiList[(which * 2) + 1];\r
1146 \r
1147         DigiLastStart = DigiPage;\r
1148         DigiLastEnd = DigiPage + ((DigiLeft + (PMPageSize - 1)) / PMPageSize);\r
1149 \r
1150         len = (DigiLeft >= PMPageSize)? PMPageSize : (DigiLeft % PMPageSize);\r
1151         addr = SDL_LoadDigiSegment(DigiPage++);\r
1152 \r
1153         DigiPlaying = true;\r
1154         DigiLastSegment = false;\r
1155 \r
1156         SDL_PlayDigiSegment(addr,len);\r
1157         DigiLeft -= len;\r
1158         if (!DigiLeft)\r
1159                 DigiLastSegment = true;\r
1160 \r
1161         SD_Poll();\r
1162 }\r
1163 \r
1164 void\r
1165 SDL_DigitizedDone(void)\r
1166 {\r
1167         if (DigiNextAddr)\r
1168         {\r
1169                 SDL_PlayDigiSegment(DigiNextAddr,DigiNextLen);\r
1170                 DigiNextAddr = nil;\r
1171                 DigiMissed = false;\r
1172         }\r
1173         else\r
1174         {\r
1175                 if (DigiLastSegment)\r
1176                 {\r
1177                         DigiPlaying = false;\r
1178                         DigiLastSegment = false;\r
1179                         if ((DigiMode == sds_PC) && (SoundMode == sdm_PC))\r
1180                         {\r
1181                                 SDL_SoundFinished();\r
1182                         }\r
1183                         else\r
1184                                 DigiNumber = DigiPriority = 0;\r
1185                         SoundPositioned = false;\r
1186                 }\r
1187                 else\r
1188                         DigiMissed = true;\r
1189         }\r
1190 }\r
1191 \r
1192 void\r
1193 SD_SetDigiDevice(SDSMode mode)\r
1194 {\r
1195         boolean devicenotpresent;\r
1196 \r
1197         if (mode == DigiMode)\r
1198                 return;\r
1199 \r
1200         SD_StopDigitized();\r
1201 \r
1202         devicenotpresent = false;\r
1203         switch (mode)\r
1204         {\r
1205         case sds_SoundBlaster:\r
1206                 if (!SoundBlasterPresent)\r
1207                 {\r
1208                         if (SoundSourcePresent)\r
1209                                 mode = sds_SoundSource;\r
1210                         else\r
1211                                 devicenotpresent = true;\r
1212                 }\r
1213                 break;\r
1214         case sds_SoundSource:\r
1215                 if (!SoundSourcePresent)\r
1216                         devicenotpresent = true;\r
1217                 break;\r
1218         }\r
1219 \r
1220         if (!devicenotpresent)\r
1221         {\r
1222                 if (DigiMode == sds_SoundSource)\r
1223                         SDL_ShutSS();\r
1224 \r
1225                 DigiMode = mode;\r
1226 \r
1227                 if (mode == sds_SoundSource)\r
1228                         SDL_StartSS();\r
1229 \r
1230                 SDL_SetTimerSpeed();\r
1231         }\r
1232 }\r
1233 \r
1234 void\r
1235 SDL_SetupDigi(void)\r
1236 {\r
1237         memptr  list;\r
1238         word    far *p,\r
1239                         pg;\r
1240         int             i;\r
1241 \r
1242         PM_UnlockMainMem();\r
1243         MM_GetPtr(&list,PMPageSize);\r
1244         PM_CheckMainMem();\r
1245         p = (word far *)MK_FP(PM_GetPage(ChunksInFile - 1),0);\r
1246         _fmemcpy((void far *)list,(void far *)p,PMPageSize);\r
1247         pg = PMSoundStart;\r
1248         for (i = 0;i < PMPageSize / (sizeof(word) * 2);i++,p += 2)\r
1249         {\r
1250                 if (pg >= ChunksInFile - 1)\r
1251                         break;\r
1252                 pg += (p[1] + (PMPageSize - 1)) / PMPageSize;\r
1253         }\r
1254         PM_UnlockMainMem();\r
1255         MM_GetPtr((memptr *)&DigiList,i * sizeof(word) * 2);\r
1256         _fmemcpy((void far *)DigiList,(void far *)list,i * sizeof(word) * 2);\r
1257         MM_FreePtr(&list);\r
1258         NumDigi = i;\r
1259 \r
1260         for (i = 0;i < LASTSOUND;i++)\r
1261                 DigiMap[i] = -1;\r
1262 }\r
1263 \r
1264 //      AdLib Code\r
1265 \r
1266 ///////////////////////////////////////////////////////////////////////////\r
1267 //\r
1268 //      alOut(n,b) - Puts b in AdLib card register n\r
1269 //\r
1270 ///////////////////////////////////////////////////////////////////////////\r
1271 void\r
1272 alOut(byte n,byte b)\r
1273 {\r
1274 asm     pushf\r
1275 asm     cli\r
1276 \r
1277 asm     mov     dx,0x388\r
1278 asm     mov     al,[n]\r
1279 asm     out     dx,al\r
1280 asm     in      al,dx\r
1281 asm     in      al,dx\r
1282 asm     in      al,dx\r
1283 asm     in      al,dx\r
1284 asm     in      al,dx\r
1285 asm     in      al,dx\r
1286 asm     inc     dx\r
1287 asm     mov     al,[b]\r
1288 asm     out     dx,al\r
1289 \r
1290 asm     popf\r
1291 \r
1292 asm     dec     dx\r
1293 asm     in      al,dx\r
1294 asm     in      al,dx\r
1295 asm     in      al,dx\r
1296 asm     in      al,dx\r
1297 asm     in      al,dx\r
1298 asm     in      al,dx\r
1299 asm     in      al,dx\r
1300 asm     in      al,dx\r
1301 asm     in      al,dx\r
1302 asm     in      al,dx\r
1303 \r
1304 asm     in      al,dx\r
1305 asm     in      al,dx\r
1306 asm     in      al,dx\r
1307 asm     in      al,dx\r
1308 asm     in      al,dx\r
1309 asm     in      al,dx\r
1310 asm     in      al,dx\r
1311 asm     in      al,dx\r
1312 asm     in      al,dx\r
1313 asm     in      al,dx\r
1314 \r
1315 asm     in      al,dx\r
1316 asm     in      al,dx\r
1317 asm     in      al,dx\r
1318 asm     in      al,dx\r
1319 asm     in      al,dx\r
1320 asm     in      al,dx\r
1321 asm     in      al,dx\r
1322 asm     in      al,dx\r
1323 asm     in      al,dx\r
1324 asm     in      al,dx\r
1325 \r
1326 asm     in      al,dx\r
1327 asm     in      al,dx\r
1328 asm     in      al,dx\r
1329 asm     in      al,dx\r
1330 asm     in      al,dx\r
1331 }\r
1332 \r
1333 #if 0\r
1334 ///////////////////////////////////////////////////////////////////////////\r
1335 //\r
1336 //      SDL_SetInstrument() - Puts an instrument into a generator\r
1337 //\r
1338 ///////////////////////////////////////////////////////////////////////////\r
1339 static void\r
1340 SDL_SetInstrument(int track,int which,Instrument far *inst,boolean percussive)\r
1341 {\r
1342         byte            c,m;\r
1343 \r
1344         if (percussive)\r
1345         {\r
1346                 c = pcarriers[which];\r
1347                 m = pmodifiers[which];\r
1348         }\r
1349         else\r
1350         {\r
1351                 c = carriers[which];\r
1352                 m = modifiers[which];\r
1353         }\r
1354 \r
1355         tracks[track - 1]->inst = *inst;\r
1356         tracks[track - 1]->percussive = percussive;\r
1357 \r
1358         alOut(m + alChar,inst->mChar);\r
1359         alOut(m + alScale,inst->mScale);\r
1360         alOut(m + alAttack,inst->mAttack);\r
1361         alOut(m + alSus,inst->mSus);\r
1362         alOut(m + alWave,inst->mWave);\r
1363 \r
1364         // Most percussive instruments only use one cell\r
1365         if (c != 0xff)\r
1366         {\r
1367                 alOut(c + alChar,inst->cChar);\r
1368                 alOut(c + alScale,inst->cScale);\r
1369                 alOut(c + alAttack,inst->cAttack);\r
1370                 alOut(c + alSus,inst->cSus);\r
1371                 alOut(c + alWave,inst->cWave);\r
1372         }\r
1373 \r
1374         alOut(which + alFeedCon,inst->nConn);   // DEBUG - I think this is right\r
1375 }\r
1376 #endif\r
1377 \r
1378 ///////////////////////////////////////////////////////////////////////////\r
1379 //\r
1380 //      SDL_ALStopSound() - Turns off any sound effects playing through the\r
1381 //              AdLib card\r
1382 //\r
1383 ///////////////////////////////////////////////////////////////////////////\r
1384 #ifdef  _MUSE_\r
1385 void\r
1386 #else\r
1387 static void\r
1388 #endif\r
1389 SDL_ALStopSound(void)\r
1390 {\r
1391 asm     pushf\r
1392 asm     cli\r
1393 \r
1394         (long)alSound = 0;\r
1395         alOut(alFreqH + 0,0);\r
1396 \r
1397 asm     popf\r
1398 }\r
1399 \r
1400 static void\r
1401 SDL_AlSetFXInst(Instrument far *inst)\r
1402 {\r
1403         byte            c,m;\r
1404 \r
1405         m = modifiers[0];\r
1406         c = carriers[0];\r
1407         alOut(m + alChar,inst->mChar);\r
1408         alOut(m + alScale,inst->mScale);\r
1409         alOut(m + alAttack,inst->mAttack);\r
1410         alOut(m + alSus,inst->mSus);\r
1411         alOut(m + alWave,inst->mWave);\r
1412         alOut(c + alChar,inst->cChar);\r
1413         alOut(c + alScale,inst->cScale);\r
1414         alOut(c + alAttack,inst->cAttack);\r
1415         alOut(c + alSus,inst->cSus);\r
1416         alOut(c + alWave,inst->cWave);\r
1417 \r
1418         // Note: Switch commenting on these lines for old MUSE compatibility\r
1419 //      alOut(alFeedCon,inst->nConn);\r
1420         alOut(alFeedCon,0);\r
1421 }\r
1422 \r
1423 ///////////////////////////////////////////////////////////////////////////\r
1424 //\r
1425 //      SDL_ALPlaySound() - Plays the specified sound on the AdLib card\r
1426 //\r
1427 ///////////////////////////////////////////////////////////////////////////\r
1428 #ifdef  _MUSE_\r
1429 void\r
1430 #else\r
1431 static void\r
1432 #endif\r
1433 SDL_ALPlaySound(AdLibSound far *sound)\r
1434 {\r
1435         Instrument      far *inst;\r
1436         byte            huge *data;\r
1437 \r
1438         SDL_ALStopSound();\r
1439 \r
1440 asm     pushf\r
1441 asm     cli\r
1442 \r
1443         alLengthLeft = sound->common.length;\r
1444         data = sound->data;\r
1445         data++;\r
1446         data--;\r
1447         alSound = (byte far *)data;\r
1448         alBlock = ((sound->block & 7) << 2) | 0x20;\r
1449         inst = &sound->inst;\r
1450 \r
1451         if (!(inst->mSus | inst->cSus))\r
1452         {\r
1453         asm     popf\r
1454                 Quit("SDL_ALPlaySound() - Bad instrument");\r
1455         }\r
1456 \r
1457         SDL_AlSetFXInst(&alZeroInst);   // DEBUG\r
1458         SDL_AlSetFXInst(inst);\r
1459 \r
1460 asm     popf\r
1461 }\r
1462 \r
1463 #if 0\r
1464 ///////////////////////////////////////////////////////////////////////////\r
1465 //\r
1466 //      SDL_ALSoundService() - Plays the next sample out through the AdLib card\r
1467 //\r
1468 ///////////////////////////////////////////////////////////////////////////\r
1469 //static void\r
1470 void\r
1471 SDL_ALSoundService(void)\r
1472 {\r
1473         byte    s;\r
1474 \r
1475         if (alSound)\r
1476         {\r
1477                 s = *alSound++;\r
1478                 if (!s)\r
1479                         alOut(alFreqH + 0,0);\r
1480                 else\r
1481                 {\r
1482                         alOut(alFreqL + 0,s);\r
1483                         alOut(alFreqH + 0,alBlock);\r
1484                 }\r
1485 \r
1486                 if (!(--alLengthLeft))\r
1487                 {\r
1488                         (long)alSound = 0;\r
1489                         alOut(alFreqH + 0,0);\r
1490                         SDL_SoundFinished();\r
1491                 }\r
1492         }\r
1493 }\r
1494 #endif\r
1495 \r
1496 #if 0\r
1497 void\r
1498 SDL_ALService(void)\r
1499 {\r
1500         byte    a,v;\r
1501         word    w;\r
1502 \r
1503         if (!sqActive)\r
1504                 return;\r
1505 \r
1506         while (sqHackLen && (sqHackTime <= alTimeCount))\r
1507         {\r
1508                 w = *sqHackPtr++;\r
1509                 sqHackTime = alTimeCount + *sqHackPtr++;\r
1510         asm     mov     dx,[w]\r
1511         asm     mov     [a],dl\r
1512         asm     mov     [v],dh\r
1513                 alOut(a,v);\r
1514                 sqHackLen -= 4;\r
1515         }\r
1516         alTimeCount++;\r
1517         if (!sqHackLen)\r
1518         {\r
1519                 sqHackPtr = (word far *)sqHack;\r
1520                 sqHackLen = sqHackSeqLen;\r
1521                 alTimeCount = sqHackTime = 0;\r
1522         }\r
1523 }\r
1524 #endif\r
1525 \r
1526 ///////////////////////////////////////////////////////////////////////////\r
1527 //\r
1528 //      SDL_ShutAL() - Shuts down the AdLib card for sound effects\r
1529 //\r
1530 ///////////////////////////////////////////////////////////////////////////\r
1531 static void\r
1532 SDL_ShutAL(void)\r
1533 {\r
1534 asm     pushf\r
1535 asm     cli\r
1536 \r
1537         alOut(alEffects,0);\r
1538         alOut(alFreqH + 0,0);\r
1539         SDL_AlSetFXInst(&alZeroInst);\r
1540         alSound = 0;\r
1541 \r
1542 asm     popf\r
1543 }\r
1544 \r
1545 ///////////////////////////////////////////////////////////////////////////\r
1546 //\r
1547 //      SDL_CleanAL() - Totally shuts down the AdLib card\r
1548 //\r
1549 ///////////////////////////////////////////////////////////////////////////\r
1550 static void\r
1551 SDL_CleanAL(void)\r
1552 {\r
1553         int     i;\r
1554 \r
1555 asm     pushf\r
1556 asm     cli\r
1557 \r
1558         alOut(alEffects,0);\r
1559         for (i = 1;i < 0xf5;i++)\r
1560                 alOut(i,0);\r
1561 \r
1562 asm     popf\r
1563 }\r
1564 \r
1565 ///////////////////////////////////////////////////////////////////////////\r
1566 //\r
1567 //      SDL_StartAL() - Starts up the AdLib card for sound effects\r
1568 //\r
1569 ///////////////////////////////////////////////////////////////////////////\r
1570 static void\r
1571 SDL_StartAL(void)\r
1572 {\r
1573         alFXReg = 0;\r
1574         alOut(alEffects,alFXReg);\r
1575         SDL_AlSetFXInst(&alZeroInst);\r
1576 }\r
1577 \r
1578 ///////////////////////////////////////////////////////////////////////////\r
1579 //\r
1580 //      SDL_DetectAdLib() - Determines if there's an AdLib (or SoundBlaster\r
1581 //              emulating an AdLib) present\r
1582 //\r
1583 ///////////////////////////////////////////////////////////////////////////\r
1584 static boolean\r
1585 SDL_DetectAdLib(void)\r
1586 {\r
1587         byte    status1,status2;\r
1588         int             i;\r
1589 \r
1590         alOut(4,0x60);  // Reset T1 & T2\r
1591         alOut(4,0x80);  // Reset IRQ\r
1592         status1 = readstat();\r
1593         alOut(2,0xff);  // Set timer 1\r
1594         alOut(4,0x21);  // Start timer 1\r
1595 #if 0\r
1596         SDL_Delay(TimerDelay100);\r
1597 #else\r
1598 asm     mov     dx,0x388\r
1599 asm     mov     cx,100\r
1600 usecloop:\r
1601 asm     in      al,dx\r
1602 asm     loop usecloop\r
1603 #endif\r
1604 \r
1605         status2 = readstat();\r
1606         alOut(4,0x60);\r
1607         alOut(4,0x80);\r
1608 \r
1609         if (((status1 & 0xe0) == 0x00) && ((status2 & 0xe0) == 0xc0))\r
1610         {\r
1611                 for (i = 1;i <= 0xf5;i++)       // Zero all the registers\r
1612                         alOut(i,0);\r
1613 \r
1614                 alOut(1,0x20);  // Set WSE=1\r
1615                 alOut(8,0);             // Set CSM=0 & SEL=0\r
1616 \r
1617                 return(true);\r
1618         }\r
1619         else\r
1620                 return(false);\r
1621 }\r
1622 \r
1623 #if 0\r
1624 ///////////////////////////////////////////////////////////////////////////\r
1625 //\r
1626 //      SDL_t0Service() - My timer 0 ISR which handles the different timings and\r
1627 //              dispatches to whatever other routines are appropriate\r
1628 //\r
1629 ///////////////////////////////////////////////////////////////////////////\r
1630 static void interrupt\r
1631 SDL_t0Service(void)\r
1632 {\r
1633 static  word    count = 1;\r
1634 \r
1635 #if 1   // for debugging\r
1636 asm     mov     dx,STATUS_REGISTER_1\r
1637 asm     in      al,dx\r
1638 asm     mov     dx,ATR_INDEX\r
1639 asm     mov     al,ATR_OVERSCAN\r
1640 asm     out     dx,al\r
1641 asm     mov     al,4    // red\r
1642 asm     out     dx,al\r
1643 #endif\r
1644 \r
1645         HackCount++;\r
1646 \r
1647         if ((MusicMode == smm_AdLib) || (DigiMode == sds_SoundSource))\r
1648         {\r
1649                 SDL_ALService();\r
1650                 SDL_SSService();\r
1651 //              if (!(++count & 7))\r
1652                 if (!(++count % 10))\r
1653                 {\r
1654                         LocalTime++;\r
1655                         TimeCount++;\r
1656                         if (SoundUserHook)\r
1657                                 SoundUserHook();\r
1658                 }\r
1659 //              if (!(count & 3))\r
1660                 if (!(count % 5))\r
1661                 {\r
1662                         switch (SoundMode)\r
1663                         {\r
1664                         case sdm_PC:\r
1665                                 SDL_PCService();\r
1666                                 break;\r
1667                         case sdm_AdLib:\r
1668                                 SDL_ALSoundService();\r
1669                                 break;\r
1670                         }\r
1671                 }\r
1672         }\r
1673         else\r
1674         {\r
1675                 if (!(++count & 1))\r
1676                 {\r
1677                         LocalTime++;\r
1678                         TimeCount++;\r
1679                         if (SoundUserHook)\r
1680                                 SoundUserHook();\r
1681                 }\r
1682                 switch (SoundMode)\r
1683                 {\r
1684                 case sdm_PC:\r
1685                         SDL_PCService();\r
1686                         break;\r
1687                 case sdm_AdLib:\r
1688                         SDL_ALSoundService();\r
1689                         break;\r
1690                 }\r
1691         }\r
1692 \r
1693 asm     mov     ax,[WORD PTR TimerCount]\r
1694 asm     add     ax,[WORD PTR TimerDivisor]\r
1695 asm     mov     [WORD PTR TimerCount],ax\r
1696 asm     jnc     myack\r
1697         t0OldService();                 // If we overflow a word, time to call old int handler\r
1698 asm     jmp     olddone\r
1699 myack:;\r
1700         outportb(0x20,0x20);    // Ack the interrupt\r
1701 olddone:;\r
1702 \r
1703 #if 1   // for debugging\r
1704 asm     mov     dx,STATUS_REGISTER_1\r
1705 asm     in      al,dx\r
1706 asm     mov     dx,ATR_INDEX\r
1707 asm     mov     al,ATR_OVERSCAN\r
1708 asm     out     dx,al\r
1709 asm     mov     al,3    // blue\r
1710 asm     out     dx,al\r
1711 asm     mov     al,0x20 // normal\r
1712 asm     out     dx,al\r
1713 #endif\r
1714 }\r
1715 #endif\r
1716 \r
1717 ////////////////////////////////////////////////////////////////////////////\r
1718 //\r
1719 //      SDL_ShutDevice() - turns off whatever device was being used for sound fx\r
1720 //\r
1721 ////////////////////////////////////////////////////////////////////////////\r
1722 static void\r
1723 SDL_ShutDevice(void)\r
1724 {\r
1725         switch (SoundMode)\r
1726         {\r
1727         case sdm_PC:\r
1728                 SDL_ShutPC();\r
1729                 break;\r
1730         case sdm_AdLib:\r
1731                 SDL_ShutAL();\r
1732                 break;\r
1733         }\r
1734         SoundMode = sdm_Off;\r
1735 }\r
1736 \r
1737 ///////////////////////////////////////////////////////////////////////////\r
1738 //\r
1739 //      SDL_CleanDevice() - totally shuts down all sound devices\r
1740 //\r
1741 ///////////////////////////////////////////////////////////////////////////\r
1742 static void\r
1743 SDL_CleanDevice(void)\r
1744 {\r
1745         if ((SoundMode == sdm_AdLib) || (MusicMode == smm_AdLib))\r
1746                 SDL_CleanAL();\r
1747 }\r
1748 \r
1749 ///////////////////////////////////////////////////////////////////////////\r
1750 //\r
1751 //      SDL_StartDevice() - turns on whatever device is to be used for sound fx\r
1752 //\r
1753 ///////////////////////////////////////////////////////////////////////////\r
1754 static void\r
1755 SDL_StartDevice(void)\r
1756 {\r
1757         switch (SoundMode)\r
1758         {\r
1759         case sdm_AdLib:\r
1760                 SDL_StartAL();\r
1761                 break;\r
1762         }\r
1763         SoundNumber = SoundPriority = 0;\r
1764 }\r
1765 \r
1766 //      Public routines\r
1767 \r
1768 ///////////////////////////////////////////////////////////////////////////\r
1769 //\r
1770 //      SD_SetSoundMode() - Sets which sound hardware to use for sound effects\r
1771 //\r
1772 ///////////////////////////////////////////////////////////////////////////\r
1773 boolean\r
1774 SD_SetSoundMode(SDMode mode)\r
1775 {\r
1776         boolean result = false;\r
1777         word    tableoffset;\r
1778 \r
1779         SD_StopSound();\r
1780 \r
1781 #ifndef _MUSE_\r
1782         if ((mode == sdm_AdLib) && !AdLibPresent)\r
1783                 mode = sdm_PC;\r
1784 \r
1785         switch (mode)\r
1786         {\r
1787         case sdm_Off:\r
1788                 NeedsDigitized = false;\r
1789                 result = true;\r
1790                 break;\r
1791         case sdm_PC:\r
1792                 tableoffset = STARTPCSOUNDS;\r
1793                 NeedsDigitized = false;\r
1794                 result = true;\r
1795                 break;\r
1796         case sdm_AdLib:\r
1797                 if (AdLibPresent)\r
1798                 {\r
1799                         tableoffset = STARTADLIBSOUNDS;\r
1800                         NeedsDigitized = false;\r
1801                         result = true;\r
1802                 }\r
1803                 break;\r
1804         }\r
1805 #else\r
1806         result = true;\r
1807 #endif\r
1808 \r
1809         if (result && (mode != SoundMode))\r
1810         {\r
1811                 SDL_ShutDevice();\r
1812                 SoundMode = mode;\r
1813 #ifndef _MUSE_\r
1814                 SoundTable = (word *)(&audiosegs[tableoffset]);\r
1815 #endif\r
1816                 SDL_StartDevice();\r
1817         }\r
1818 \r
1819         SDL_SetTimerSpeed();\r
1820 \r
1821         return(result);\r
1822 }\r
1823 \r
1824 ///////////////////////////////////////////////////////////////////////////\r
1825 //\r
1826 //      SD_SetMusicMode() - sets the device to use for background music\r
1827 //\r
1828 ///////////////////////////////////////////////////////////////////////////\r
1829 boolean\r
1830 SD_SetMusicMode(SMMode mode)\r
1831 {\r
1832         boolean result = false;\r
1833 \r
1834         SD_FadeOutMusic();\r
1835         while (SD_MusicPlaying())\r
1836                 ;\r
1837 \r
1838         switch (mode)\r
1839         {\r
1840         case smm_Off:\r
1841                 NeedsMusic = false;\r
1842                 result = true;\r
1843                 break;\r
1844         case smm_AdLib:\r
1845                 if (AdLibPresent)\r
1846                 {\r
1847                         NeedsMusic = true;\r
1848                         result = true;\r
1849                 }\r
1850                 break;\r
1851         }\r
1852 \r
1853         if (result)\r
1854                 MusicMode = mode;\r
1855 \r
1856         SDL_SetTimerSpeed();\r
1857 \r
1858         return(result);\r
1859 }\r
1860 \r
1861 ///////////////////////////////////////////////////////////////////////////\r
1862 //\r
1863 //      SD_Startup() - starts up the Sound Mgr\r
1864 //              Detects all additional sound hardware and installs my ISR\r
1865 //\r
1866 ///////////////////////////////////////////////////////////////////////////\r
1867 void\r
1868 SD_Startup(void)\r
1869 {\r
1870         int     i;\r
1871 \r
1872         if (SD_Started)\r
1873                 return;\r
1874 \r
1875         SDL_SetDS();\r
1876 \r
1877         ssIsTandy = false;\r
1878         ssNoCheck = false;\r
1879         alNoCheck = false;\r
1880         sbNoCheck = false;\r
1881         sbNoProCheck = false;\r
1882 #ifndef _MUSE_\r
1883         for (i = 1;i < _argc;i++)\r
1884         {\r
1885                 switch (US_CheckParm(_argv[i],ParmStrings))\r
1886                 {\r
1887                 case 0:                                         // No AdLib detection\r
1888                         alNoCheck = true;\r
1889                         break;\r
1890                 case 1:                                         // No SoundBlaster detection\r
1891                         sbNoCheck = true;\r
1892                         break;\r
1893                 case 2:                                         // No SoundBlaster Pro detection\r
1894                         sbNoProCheck = true;\r
1895                         break;\r
1896                 case 3:\r
1897                         ssNoCheck = true;               // No Sound Source detection\r
1898                         break;\r
1899                 case 4:                                         // Tandy Sound Source handling\r
1900                         ssIsTandy = true;\r
1901                         break;\r
1902                 case 5:                                         // Sound Source present at LPT1\r
1903                         ssPort = 1;\r
1904                         ssNoCheck = SoundSourcePresent = true;\r
1905                         break;\r
1906                 case 6:                     // Sound Source present at LPT2\r
1907                         ssPort = 2;\r
1908                         ssNoCheck = SoundSourcePresent = true;\r
1909                         break;\r
1910                 case 7:                     // Sound Source present at LPT3\r
1911                         ssPort = 3;\r
1912                         ssNoCheck = SoundSourcePresent = true;\r
1913                         break;\r
1914                 }\r
1915         }\r
1916 #endif\r
1917 \r
1918         SoundUserHook = 0;\r
1919 \r
1920         t0OldService = getvect(8);      // Get old timer 0 ISR\r
1921 \r
1922         LocalTime = TimeCount = alTimeCount = 0;\r
1923 \r
1924         SD_SetSoundMode(sdm_Off);\r
1925         SD_SetMusicMode(smm_Off);\r
1926 \r
1927         if (!ssNoCheck)\r
1928                 SoundSourcePresent = SDL_DetectSoundSource();\r
1929 \r
1930         if (!alNoCheck)\r
1931         {\r
1932                 AdLibPresent = SDL_DetectAdLib();\r
1933                 if (AdLibPresent && !sbNoCheck)\r
1934                 {\r
1935                         int port = -1;\r
1936                         char *env = getenv("BLASTER");\r
1937                         if (env)\r
1938                         {\r
1939                                 long temp;\r
1940                                 while (*env)\r
1941                                 {\r
1942                                         while (isspace(*env))\r
1943                                                 env++;\r
1944 \r
1945                                         switch (toupper(*env))\r
1946                                         {\r
1947                                         case 'A':\r
1948                                                 temp = strtol(env + 1,&env,16);\r
1949                                                 if\r
1950                                                 (\r
1951                                                         (temp >= 0x210)\r
1952                                                 &&      (temp <= 0x260)\r
1953                                                 &&      (!(temp & 0x00f))\r
1954                                                 )\r
1955                                                         port = (temp - 0x200) >> 4;\r
1956                                                 else\r
1957                                                         Quit("SD_Startup: Unsupported address value in BLASTER");\r
1958                                                 break;\r
1959                                         case 'I':\r
1960                                                 temp = strtol(env + 1,&env,10);\r
1961                                                 if\r
1962                                                 (\r
1963                                                         (temp >= 0)\r
1964                                                 &&      (temp <= 10)\r
1965                                                 &&      (sbIntVectors[temp] != -1)\r
1966                                                 )\r
1967                                                 {\r
1968                                                         sbInterrupt = temp;\r
1969                                                         sbIntVec = sbIntVectors[sbInterrupt];\r
1970                                                 }\r
1971                                                 else\r
1972                                                         Quit("SD_Startup: Unsupported interrupt value in BLASTER");\r
1973                                                 break;\r
1974                                         case 'D':\r
1975                                                 temp = strtol(env + 1,&env,10);\r
1976                                                 if ((temp == 0) || (temp == 1) || (temp == 3))\r
1977                                                         SDL_SBSetDMA(temp);\r
1978                                                 else\r
1979                                                         Quit("SD_Startup: Unsupported DMA value in BLASTER");\r
1980                                                 break;\r
1981                                         default:\r
1982                                                 while (isspace(*env))\r
1983                                                         env++;\r
1984                                                 while (*env && !isspace(*env))\r
1985                                                         env++;\r
1986                                                 break;\r
1987                                         }\r
1988                                 }\r
1989                         }\r
1990                         SoundBlasterPresent = SDL_DetectSoundBlaster(port);\r
1991                 }\r
1992         }\r
1993 \r
1994         for (i = 0;i < 255;i++)\r
1995                 pcSoundLookup[i] = i * 60;\r
1996 \r
1997         if (SoundBlasterPresent)\r
1998                 SDL_StartSB();\r
1999 \r
2000         SDL_SetupDigi();\r
2001 \r
2002         SD_Started = true;\r
2003 }\r
2004 \r
2005 ///////////////////////////////////////////////////////////////////////////\r
2006 //\r
2007 //      SD_Default() - Sets up the default behaviour for the Sound Mgr whether\r
2008 //              the config file was present or not.\r
2009 //\r
2010 ///////////////////////////////////////////////////////////////////////////\r
2011 void\r
2012 SD_Default(boolean gotit,SDMode sd,SMMode sm)\r
2013 {\r
2014         boolean gotsd,gotsm;\r
2015 \r
2016         gotsd = gotsm = gotit;\r
2017 \r
2018         if (gotsd)      // Make sure requested sound hardware is available\r
2019         {\r
2020                 switch (sd)\r
2021                 {\r
2022                 case sdm_AdLib:\r
2023                         gotsd = AdLibPresent;\r
2024                         break;\r
2025                 }\r
2026         }\r
2027         if (!gotsd)\r
2028         {\r
2029                 if (AdLibPresent)\r
2030                         sd = sdm_AdLib;\r
2031                 else\r
2032                         sd = sdm_PC;\r
2033         }\r
2034         if (sd != SoundMode)\r
2035                 SD_SetSoundMode(sd);\r
2036 \r
2037 \r
2038         if (gotsm)      // Make sure requested music hardware is available\r
2039         {\r
2040                 switch (sm)\r
2041                 {\r
2042                 case sdm_AdLib:\r
2043                         gotsm = AdLibPresent;\r
2044                         break;\r
2045                 }\r
2046         }\r
2047         if (!gotsm)\r
2048         {\r
2049                 if (AdLibPresent)\r
2050                         sm = smm_AdLib;\r
2051         }\r
2052         if (sm != MusicMode)\r
2053                 SD_SetMusicMode(sm);\r
2054 }\r
2055 \r
2056 ///////////////////////////////////////////////////////////////////////////\r
2057 //\r
2058 //      SD_Shutdown() - shuts down the Sound Mgr\r
2059 //              Removes sound ISR and turns off whatever sound hardware was active\r
2060 //\r
2061 ///////////////////////////////////////////////////////////////////////////\r
2062 void\r
2063 SD_Shutdown(void)\r
2064 {\r
2065         if (!SD_Started)\r
2066                 return;\r
2067 \r
2068         SD_MusicOff();\r
2069         SD_StopSound();\r
2070         SDL_ShutDevice();\r
2071         SDL_CleanDevice();\r
2072 \r
2073         if (SoundBlasterPresent)\r
2074                 SDL_ShutSB();\r
2075 \r
2076         if (SoundSourcePresent)\r
2077                 SDL_ShutSS();\r
2078 \r
2079         asm     pushf\r
2080         asm     cli\r
2081 \r
2082         SDL_SetTimer0(0);\r
2083 \r
2084         setvect(8,t0OldService);\r
2085 \r
2086         asm     popf\r
2087 \r
2088         SD_Started = false;\r
2089 }\r
2090 \r
2091 ///////////////////////////////////////////////////////////////////////////\r
2092 //\r
2093 //      SD_SetUserHook() - sets the routine that the Sound Mgr calls every 1/70th\r
2094 //              of a second from its timer 0 ISR\r
2095 //\r
2096 ///////////////////////////////////////////////////////////////////////////\r
2097 void\r
2098 SD_SetUserHook(void (* hook)(void))\r
2099 {\r
2100         SoundUserHook = hook;\r
2101 }\r
2102 \r
2103 ///////////////////////////////////////////////////////////////////////////\r
2104 //\r
2105 //      SD_PositionSound() - Sets up a stereo imaging location for the next\r
2106 //              sound to be played. Each channel ranges from 0 to 15.\r
2107 //\r
2108 ///////////////////////////////////////////////////////////////////////////\r
2109 void\r
2110 SD_PositionSound(int leftvol,int rightvol)\r
2111 {\r
2112         LeftPosition = leftvol;\r
2113         RightPosition = rightvol;\r
2114         nextsoundpos = true;\r
2115 }\r
2116 \r
2117 ///////////////////////////////////////////////////////////////////////////\r
2118 //\r
2119 //      SD_PlaySound() - plays the specified sound on the appropriate hardware\r
2120 //\r
2121 ///////////////////////////////////////////////////////////////////////////\r
2122 boolean\r
2123 SD_PlaySound(soundnames sound)\r
2124 {\r
2125         boolean         ispos;\r
2126         SoundCommon     far *s;\r
2127         int     lp,rp;\r
2128 \r
2129         lp = LeftPosition;\r
2130         rp = RightPosition;\r
2131         LeftPosition = 0;\r
2132         RightPosition = 0;\r
2133 \r
2134         ispos = nextsoundpos;\r
2135         nextsoundpos = false;\r
2136 \r
2137         if (sound == -1)\r
2138                 return(false);\r
2139 \r
2140         s = MK_FP(SoundTable[sound],0);\r
2141         if ((SoundMode != sdm_Off) && !s)\r
2142                 Quit("SD_PlaySound() - Uncached sound");\r
2143 \r
2144         if ((DigiMode != sds_Off) && (DigiMap[sound] != -1))\r
2145         {\r
2146                 if ((DigiMode == sds_PC) && (SoundMode == sdm_PC))\r
2147                 {\r
2148                         if (s->priority < SoundPriority)\r
2149                                 return(false);\r
2150 \r
2151                         SDL_PCStopSound();\r
2152 \r
2153                         SD_PlayDigitized(DigiMap[sound],lp,rp);\r
2154                         SoundPositioned = ispos;\r
2155                         SoundNumber = sound;\r
2156                         SoundPriority = s->priority;\r
2157                 }\r
2158                 else\r
2159                 {\r
2160                 asm     pushf\r
2161                 asm     cli\r
2162                         if (DigiPriority && !DigiNumber)\r
2163                         {\r
2164                         asm     popf\r
2165                                 Quit("SD_PlaySound: Priority without a sound");\r
2166                         }\r
2167                 asm     popf\r
2168 \r
2169                         if (s->priority < DigiPriority)\r
2170                                 return(false);\r
2171 \r
2172                         SD_PlayDigitized(DigiMap[sound],lp,rp);\r
2173                         SoundPositioned = ispos;\r
2174                         DigiNumber = sound;\r
2175                         DigiPriority = s->priority;\r
2176                 }\r
2177 \r
2178                 return(true);\r
2179         }\r
2180 \r
2181         if (SoundMode == sdm_Off)\r
2182                 return(false);\r
2183         if (!s->length)\r
2184                 Quit("SD_PlaySound() - Zero length sound");\r
2185         if (s->priority < SoundPriority)\r
2186                 return(false);\r
2187 \r
2188         switch (SoundMode)\r
2189         {\r
2190         case sdm_PC:\r
2191                 SDL_PCPlaySound((void far *)s);\r
2192                 break;\r
2193         case sdm_AdLib:\r
2194                 SDL_ALPlaySound((void far *)s);\r
2195                 break;\r
2196         }\r
2197 \r
2198         SoundNumber = sound;\r
2199         SoundPriority = s->priority;\r
2200 \r
2201         return(false);\r
2202 }\r
2203 \r
2204 ///////////////////////////////////////////////////////////////////////////\r
2205 //\r
2206 //      SD_SoundPlaying() - returns the sound number that's playing, or 0 if\r
2207 //              no sound is playing\r
2208 //\r
2209 ///////////////////////////////////////////////////////////////////////////\r
2210 word\r
2211 SD_SoundPlaying(void)\r
2212 {\r
2213         boolean result = false;\r
2214 \r
2215         switch (SoundMode)\r
2216         {\r
2217         case sdm_PC:\r
2218                 result = pcSound? true : false;\r
2219                 break;\r
2220         case sdm_AdLib:\r
2221                 result = alSound? true : false;\r
2222                 break;\r
2223         }\r
2224 \r
2225         if (result)\r
2226                 return(SoundNumber);\r
2227         else\r
2228                 return(false);\r
2229 }\r
2230 \r
2231 ///////////////////////////////////////////////////////////////////////////\r
2232 //\r
2233 //      SD_StopSound() - if a sound is playing, stops it\r
2234 //\r
2235 ///////////////////////////////////////////////////////////////////////////\r
2236 void\r
2237 SD_StopSound(void)\r
2238 {\r
2239         if (DigiPlaying)\r
2240                 SD_StopDigitized();\r
2241 \r
2242         switch (SoundMode)\r
2243         {\r
2244         case sdm_PC:\r
2245                 SDL_PCStopSound();\r
2246                 break;\r
2247         case sdm_AdLib:\r
2248                 SDL_ALStopSound();\r
2249                 break;\r
2250         }\r
2251 \r
2252         SoundPositioned = false;\r
2253 \r
2254         SDL_SoundFinished();\r
2255 }\r
2256 \r
2257 ///////////////////////////////////////////////////////////////////////////\r
2258 //\r
2259 //      SD_WaitSoundDone() - waits until the current sound is done playing\r
2260 //\r
2261 ///////////////////////////////////////////////////////////////////////////\r
2262 void\r
2263 SD_WaitSoundDone(void)\r
2264 {\r
2265         while (SD_SoundPlaying())\r
2266                 ;\r
2267 }\r
2268 \r
2269 ///////////////////////////////////////////////////////////////////////////\r
2270 //\r
2271 //      SD_MusicOn() - turns on the sequencer\r
2272 //\r
2273 ///////////////////////////////////////////////////////////////////////////\r
2274 void\r
2275 SD_MusicOn(void)\r
2276 {\r
2277         sqActive = true;\r
2278 }\r
2279 \r
2280 ///////////////////////////////////////////////////////////////////////////\r
2281 //\r
2282 //      SD_MusicOff() - turns off the sequencer and any playing notes\r
2283 //\r
2284 ///////////////////////////////////////////////////////////////////////////\r
2285 void\r
2286 SD_MusicOff(void)\r
2287 {\r
2288         word    i;\r
2289 \r
2290 \r
2291         switch (MusicMode)\r
2292         {\r
2293         case smm_AdLib:\r
2294                 alFXReg = 0;\r
2295                 alOut(alEffects,0);\r
2296                 for (i = 0;i < sqMaxTracks;i++)\r
2297                         alOut(alFreqH + i + 1,0);\r
2298                 break;\r
2299         }\r
2300         sqActive = false;\r
2301 }\r
2302 \r
2303 ///////////////////////////////////////////////////////////////////////////\r
2304 //\r
2305 //      SD_StartMusic() - starts playing the music pointed to\r
2306 //\r
2307 ///////////////////////////////////////////////////////////////////////////\r
2308 void\r
2309 SD_StartMusic(MusicGroup far *music)\r
2310 {\r
2311         SD_MusicOff();\r
2312 asm     pushf\r
2313 asm     cli\r
2314 \r
2315         if (MusicMode == smm_AdLib)\r
2316         {\r
2317                 sqHackPtr = sqHack = music->values;\r
2318                 sqHackSeqLen = sqHackLen = music->length;\r
2319                 sqHackTime = 0;\r
2320                 alTimeCount = 0;\r
2321                 SD_MusicOn();\r
2322         }\r
2323 \r
2324 asm     popf\r
2325 }\r
2326 \r
2327 ///////////////////////////////////////////////////////////////////////////\r
2328 //\r
2329 //      SD_FadeOutMusic() - starts fading out the music. Call SD_MusicPlaying()\r
2330 //              to see if the fadeout is complete\r
2331 //\r
2332 ///////////////////////////////////////////////////////////////////////////\r
2333 void\r
2334 SD_FadeOutMusic(void)\r
2335 {\r
2336         switch (MusicMode)\r
2337         {\r
2338         case smm_AdLib:\r
2339                 // DEBUG - quick hack to turn the music off\r
2340                 SD_MusicOff();\r
2341                 break;\r
2342         }\r
2343 }\r
2344 \r
2345 ///////////////////////////////////////////////////////////////////////////\r
2346 //\r
2347 //      SD_MusicPlaying() - returns true if music is currently playing, false if\r
2348 //              not\r
2349 //\r
2350 ///////////////////////////////////////////////////////////////////////////\r
2351 boolean\r
2352 SD_MusicPlaying(void)\r
2353 {\r
2354         boolean result;\r
2355 \r
2356         switch (MusicMode)\r
2357         {\r
2358         case smm_AdLib:\r
2359                 result = false;\r
2360                 // DEBUG - not written\r
2361                 break;\r
2362         default:\r
2363                 result = false;\r
2364         }\r
2365 \r
2366         return(result);\r
2367 }\r