]> 4ch.mooo.com Git - 16.git/blob - src/lib/id_sd.c
16_sd official port started. but class and work in the way
[16.git] / src / lib / id_sd.c
1 /* Project 16 Source Code~\r
2  * Copyright (C) 2012-2017 sparky4 & pngwen & andrius4669 & joncampbell123 & yakui-lover\r
3  *\r
4  * This file is part of Project 16.\r
5  *\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
10  *\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
15  *\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
20  *\r
21  */\r
22 \r
23 //\r
24 //      ID Engine\r
25 //      ID_SD.c - Sound Manager for Wolfenstein 3D\r
26 //      v1.2\r
27 //      By Jason Blochowiak\r
28 //\r
29 \r
30 //\r
31 //      This module handles dealing with generating sound on the appropriate\r
32 //              hardware\r
33 //\r
34 //      Depends on: User Mgr (for parm checking)\r
35 //\r
36 //      Globals:\r
37 //              For User Mgr:\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
47 //\r
48 //              For Cache Mgr:\r
49 //                      NeedsDigitized - load digitized sounds?\r
50 //                      NeedsMusic - load music?\r
51 //\r
52 \r
53 #pragma hdrstop         // Wierdo thing with MUSE\r
54 \r
55 \r
56 \r
57 //#ifdef        _MUSE_      // Will be defined in ID_Types.h\r
58 #include "src/lib/id_sd.h"\r
59 //#else\r
60 //#include "ID_HEADS.H"\r
61 //#endif\r
62 #pragma hdrstop\r
63 #pragma warn    -pia\r
64 \r
65 #ifdef  nil\r
66 #undef  nil\r
67 #endif\r
68 #define nil     0\r
69 \r
70 #define SDL_SoundFinished()     {SoundNumber = SoundPriority = 0;}\r
71 \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
77 \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
82 \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
89 \r
90 //      Global variables\r
91         boolean         SoundSourcePresent,\r
92                                 AdLibPresent,\r
93                                 SoundBlasterPresent,SBProPresent,\r
94                                 NeedsDigitized,NeedsMusic,\r
95                                 SoundPositioned;\r
96         SDMode          SoundMode;\r
97         SMMode          MusicMode;\r
98         SDSMode         DigiMode;\r
99         dword   TimeCount;\r
100         word            HackCount;\r
101         word            *SoundTable;    // Really * _seg *SoundTable, but that don't work\r
102         boolean         ssIsTandy;\r
103         word            ssPort = 2;\r
104         int                     DigiMap[LASTSOUND];\r
105 \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
111                                                 {\r
112                                                         "noal",\r
113                                                         "nosb",\r
114                                                         "nopro",\r
115                                                         "noss",\r
116                                                         "sst",\r
117                                                         "ss1",\r
118                                                         "ss2",\r
119                                                         "ss3",\r
120                                                         nil\r
121                                                 };\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
127                 long                    LocalTime;\r
128                 word                    TimerRate;\r
129 \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
137 \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
154 \r
155 //      SoundSource variables\r
156                 boolean                         ssNoCheck;\r
157                 boolean                         ssActive;\r
158                 word                            ssControl,ssStatus,ssData;\r
159                 byte                            ssOn,ssOff;\r
160                 volatile byte           far *ssSample;\r
161                 volatile dword  ssLengthLeft;\r
162 \r
163 //      PC Sound variables\r
164                 volatile byte   pcLastSample,far *pcSound;\r
165                 dword           pcLengthLeft;\r
166                 word                    pcSoundLookup[255];\r
167 \r
168 //      AdLib variables\r
169                 boolean                 alNoCheck;\r
170                 byte                    far *alSound;\r
171                 word                    alBlock;\r
172                 dword           alLengthLeft;\r
173                 dword           alTimeCount;\r
174                 Instrument              alZeroInst;\r
175 \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
182 \r
183 //      Sequencer variables\r
184                 boolean                 sqActive;\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
190                 long                    sqHackTime;\r
191 \r
192 //      Internal routines\r
193                 void                    SDL_DigitizedDone(void);\r
194 \r
195 ///////////////////////////////////////////////////////////////////////////\r
196 //\r
197 //      SDL_SetTimer0() - Sets system timer 0 to the specified speed\r
198 //\r
199 ///////////////////////////////////////////////////////////////////////////\r
200 #pragma argsused\r
201 static void\r
202 SDL_SetTimer0(word speed)\r
203 {\r
204 #ifndef TPROF   // If using Borland's profiling, don't screw with the timer\r
205 asm     pushf\r
206 asm     cli\r
207 \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
214         else\r
215                 TimerDivisor = speed;\r
216 \r
217 asm     popf\r
218 #else\r
219         TimerDivisor = 0x10000;\r
220 #endif\r
221 }\r
222 \r
223 ///////////////////////////////////////////////////////////////////////////\r
224 //\r
225 //      SDL_SetIntsPerSec() - Uses SDL_SetTimer0() to set the number of\r
226 //              interrupts generated by system timer 0 per second\r
227 //\r
228 ///////////////////////////////////////////////////////////////////////////\r
229 static void\r
230 SDL_SetIntsPerSec(word ints)\r
231 {\r
232         TimerRate = ints;\r
233         SDL_SetTimer0(1192030 / ints);\r
234 }\r
235 \r
236 static void\r
237 SDL_SetTimerSpeed(void)\r
238 {\r
239         word    rate;\r
240         void interrupt  (*isr)(void);\r
241 \r
242         if ((DigiMode == sds_PC) && DigiPlaying)\r
243         {\r
244                 rate = TickBase * 100;\r
245                 isr = SDL_t0ExtremeAsmService;\r
246         }\r
247         else if\r
248         (\r
249                 (MusicMode == smm_AdLib)\r
250         ||      ((DigiMode == sds_SoundSource) && DigiPlaying)\r
251         )\r
252         {\r
253                 rate = TickBase * 10;\r
254                 isr = SDL_t0FastAsmService;\r
255         }\r
256         else\r
257         {\r
258                 rate = TickBase * 2;\r
259                 isr = SDL_t0SlowAsmService;\r
260         }\r
261 \r
262         if (rate != TimerRate)\r
263         {\r
264                 setvect(8,isr);\r
265                 SDL_SetIntsPerSec(rate);\r
266                 TimerRate = rate;\r
267         }\r
268 }\r
269 \r
270 #if 0\r
271 //\r
272 //      SoundBlaster code\r
273 //\r
274 \r
275 ///////////////////////////////////////////////////////////////////////////\r
276 //\r
277 //      SDL_SBStopSample() - Stops any active sampled sound and causes DMA\r
278 //              requests from the SoundBlaster to cease\r
279 //\r
280 ///////////////////////////////////////////////////////////////////////////\r
281 #ifdef  _MUSE_\r
282 void\r
283 #else\r
284 static void\r
285 #endif\r
286 SDL_SBStopSample(void)\r
287 {\r
288         byte    is;\r
289 \r
290 asm     pushf\r
291 asm     cli\r
292 \r
293         if (sbSamplePlaying)\r
294         {\r
295                 sbSamplePlaying = false;\r
296 \r
297                 sbWriteDelay();\r
298                 sbOut(sbWriteCmd,0xd0); // Turn off DSP DMA\r
299 \r
300                 is = inportb(0x21);     // Restore interrupt mask bit\r
301                 if (sbOldIntMask & (1 << sbInterrupt))\r
302                         is |= (1 << sbInterrupt);\r
303                 else\r
304                         is &= ~(1 << sbInterrupt);\r
305                 outportb(0x21,is);\r
306         }\r
307 \r
308 asm     popf\r
309 }\r
310 \r
311 ///////////////////////////////////////////////////////////////////////////\r
312 //\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
316 //\r
317 ///////////////////////////////////////////////////////////////////////////\r
318 static dword\r
319 SDL_SBPlaySeg(volatile byte huge *data,dword length)\r
320 {\r
321         unsigned                datapage;\r
322         dword           dataofs,uselen;\r
323 \r
324         uselen = length;\r
325         datapage = FP_SEG(data) >> 12;\r
326         dataofs = ((FP_SEG(data) & 0xfff) << 4) + FP_OFF(data);\r
327         if (dataofs >= 0x10000)\r
328         {\r
329                 datapage++;\r
330                 dataofs -= 0x10000;\r
331         }\r
332 \r
333         if (dataofs + uselen > 0x10000)\r
334                 uselen = 0x10000 - dataofs;\r
335 \r
336         uselen--;\r
337 \r
338         // Program the DMA controller\r
339 asm     pushf\r
340 asm     cli\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
350 \r
351         // Start playing the thing\r
352         sbWriteDelay();\r
353         sbOut(sbWriteCmd,0x14);\r
354         sbWriteDelay();\r
355         sbOut(sbWriteData,(byte)uselen);\r
356         sbWriteDelay();\r
357         sbOut(sbWriteData,(byte)(uselen >> 8));\r
358 asm     popf\r
359 \r
360         return(uselen + 1);\r
361 }\r
362 \r
363 ///////////////////////////////////////////////////////////////////////////\r
364 //\r
365 //      SDL_SBService() - Services the SoundBlaster DMA interrupt\r
366 //\r
367 ///////////////////////////////////////////////////////////////////////////\r
368 /*static*/ void interrupt\r
369 SDL_SBService(void)\r
370 {\r
371         dword   used;\r
372 \r
373         sbIn(sbDataAvail);      // Ack interrupt to SB\r
374 \r
375         if (sbNextSegPtr)\r
376         {\r
377                 used = SDL_SBPlaySeg(sbNextSegPtr,sbNextSegLen);\r
378                 if (sbNextSegLen <= used)\r
379                         sbNextSegPtr = nil;\r
380                 else\r
381                 {\r
382                         sbNextSegPtr += used;\r
383                         sbNextSegLen -= used;\r
384                 }\r
385         }\r
386         else\r
387         {\r
388                 SDL_SBStopSample();\r
389                 SDL_DigitizedDone();\r
390         }\r
391 \r
392         outportb(0x20,0x20);    // Ack interrupt\r
393 }\r
394 \r
395 ///////////////////////////////////////////////////////////////////////////\r
396 //\r
397 //      SDL_SBPlaySample() - Plays a sampled sound on the SoundBlaster. Sets up\r
398 //              DMA to play the sound\r
399 //\r
400 ///////////////////////////////////////////////////////////////////////////\r
401 #ifdef  _MUSE_\r
402 void\r
403 #else\r
404 static void\r
405 #endif\r
406 SDL_SBPlaySample(byte huge *data,dword len)\r
407 {\r
408         dword   used;\r
409 \r
410         SDL_SBStopSample();\r
411 \r
412 asm     pushf\r
413 asm     cli\r
414 \r
415         used = SDL_SBPlaySeg(data,len);\r
416         if (len <= used)\r
417                 sbNextSegPtr = nil;\r
418         else\r
419         {\r
420                 sbNextSegPtr = data + used;\r
421                 sbNextSegLen = len - used;\r
422         }\r
423 \r
424         // Save old interrupt status and unmask ours\r
425         sbOldIntMask = inportb(0x21);\r
426         outportb(0x21,sbOldIntMask & ~(1 << sbInterrupt));\r
427 \r
428         sbWriteDelay();\r
429         sbOut(sbWriteCmd,0xd4);                                         // Make sure DSP DMA is enabled\r
430 \r
431         sbSamplePlaying = true;\r
432 \r
433 asm     popf\r
434 }\r
435 \r
436 ///////////////////////////////////////////////////////////////////////////\r
437 //\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
441 //\r
442 ///////////////////////////////////////////////////////////////////////////\r
443 static void\r
444 SDL_PositionSBP(int leftpos,int rightpos)\r
445 {\r
446         byte    v;\r
447 \r
448         if (!SBProPresent)\r
449                 return;\r
450 \r
451         leftpos = 15 - leftpos;\r
452         rightpos = 15 - rightpos;\r
453         v = ((leftpos & 0x0f) << 4) | (rightpos & 0x0f);\r
454 \r
455 asm     pushf\r
456 asm     cli\r
457 \r
458         sbOut(sbpMixerAddr,sbpmVoiceVol);\r
459         sbOut(sbpMixerData,v);\r
460 \r
461 asm     popf\r
462 }\r
463 \r
464 ///////////////////////////////////////////////////////////////////////////\r
465 //\r
466 //      SDL_CheckSB() - Checks to see if a SoundBlaster resides at a\r
467 //              particular I/O location\r
468 //\r
469 ///////////////////////////////////////////////////////////////////////////\r
470 static boolean\r
471 SDL_CheckSB(int port)\r
472 {\r
473         int     i;\r
474 \r
475         sbLocation = port << 4;         // Initialize stuff for later use\r
476 \r
477         sbOut(sbReset,true);            // Reset the SoundBlaster DSP\r
478 asm     mov     dx,0x388                                // Wait >4usec\r
479 asm     in      al, dx\r
480 asm     in      al, dx\r
481 asm     in      al, dx\r
482 asm     in      al, dx\r
483 asm     in      al, dx\r
484 asm     in      al, dx\r
485 asm     in      al, dx\r
486 asm     in      al, dx\r
487 asm     in      al, dx\r
488 \r
489         sbOut(sbReset,false);           // Turn off sb DSP reset\r
490 asm     mov     dx,0x388                                // Wait >100usec\r
491 asm     mov     cx,100\r
492 #ifdef __WATCOMC__\r
493         __asm {\r
494 #endif\r
495 usecloop:\r
496 asm     in      al,dx\r
497 asm     loop usecloop\r
498 #ifdef __WATCOMC__\r
499         }\r
500 #endif\r
501 \r
502         for (i = 0;i < 100;i++)\r
503         {\r
504                 if (sbIn(sbDataAvail) & 0x80)           // If data is available...\r
505                 {\r
506                         if (sbIn(sbReadData) == 0xaa)   // If it matches correct value\r
507                                 return(true);\r
508                         else\r
509                         {\r
510                                 sbLocation = -1;                        // Otherwise not a SoundBlaster\r
511                                 return(false);\r
512                         }\r
513                 }\r
514         }\r
515         sbLocation = -1;                                                // Retry count exceeded - fail\r
516         return(false);\r
517 }\r
518 \r
519 ///////////////////////////////////////////////////////////////////////////\r
520 //\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
525 //\r
526 ///////////////////////////////////////////////////////////////////////////\r
527 static boolean\r
528 SDL_DetectSoundBlaster(int port)\r
529 {\r
530         int     i;\r
531 \r
532         if (port == 0)                                  // If user specifies default, use 2\r
533                 port = 2;\r
534         if (port == -1)\r
535         {\r
536                 if (SDL_CheckSB(2))                     // Check default before scanning\r
537                         return(true);\r
538 \r
539                 if (SDL_CheckSB(4))                     // Check other SB Pro location before scan\r
540                         return(true);\r
541 \r
542                 for (i = 1;i <= 6;i++)          // Scan through possible SB locations\r
543                 {\r
544                         if ((i == 2) || (i == 4))\r
545                                 continue;\r
546 \r
547                         if (SDL_CheckSB(i))             // If found at this address,\r
548                                 return(true);           //      return success\r
549                 }\r
550                 return(false);                          // All addresses failed, return failure\r
551         }\r
552         else\r
553                 return(SDL_CheckSB(port));      // User specified address or default\r
554 }\r
555 \r
556 ///////////////////////////////////////////////////////////////////////////\r
557 //\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
560 //\r
561 ///////////////////////////////////////////////////////////////////////////\r
562 void\r
563 SDL_SBSetDMA(byte channel)\r
564 {\r
565         if (channel > 3)\r
566                 Quit("SDL_SBSetDMA() - invalid SoundBlaster DMA channel");\r
567 \r
568         sbDMA = channel;\r
569         sbDMAa1 = sba1Vals[channel];\r
570         sbDMAa2 = sba2Vals[channel];\r
571         sbDMAa3 = sba3Vals[channel];\r
572 }\r
573 \r
574 ///////////////////////////////////////////////////////////////////////////\r
575 //\r
576 //      SDL_StartSB() - Turns on the SoundBlaster\r
577 //\r
578 ///////////////////////////////////////////////////////////////////////////\r
579 static void\r
580 SDL_StartSB(void)\r
581 {\r
582         byte    timevalue,test;\r
583 \r
584         sbIntVec = sbIntVectors[sbInterrupt];\r
585         if (sbIntVec < 0)\r
586                 Quit("SDL_StartSB: Illegal or unsupported interrupt number for SoundBlaster");\r
587 \r
588         sbOldIntHand = getvect(sbIntVec);       // Get old interrupt handler\r
589         setvect(sbIntVec,SDL_SBService);        // Set mine\r
590 \r
591         sbWriteDelay();\r
592         sbOut(sbWriteCmd,0xd1);                         // Turn on DSP speaker\r
593 \r
594         // Set the SoundBlaster DAC time constant for 7KHz\r
595         timevalue = 256 - (1000000 / 7000);\r
596         sbWriteDelay();\r
597         sbOut(sbWriteCmd,0x40);\r
598         sbWriteDelay();\r
599         sbOut(sbWriteData,timevalue);\r
600 \r
601         SBProPresent = false;\r
602         if (sbNoProCheck)\r
603                 return;\r
604 \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
610         if (test == 0xbb)\r
611         {\r
612                 // Boost FM output levels to be equivilent with digitized output\r
613                 sbOut(sbpMixerData,0xff);\r
614                 test = sbIn(sbpMixerData);\r
615                 if (test == 0xff)\r
616                 {\r
617                         SBProPresent = true;\r
618 \r
619                         // Save old Voice output levels (SB Pro)\r
620                         sbOut(sbpMixerAddr,sbpmVoiceVol);\r
621                         sbpOldVOCMix = sbIn(sbpMixerData);\r
622 \r
623                         // Turn SB Pro stereo DAC off\r
624                         sbOut(sbpMixerAddr,sbpmControl);\r
625                         sbOut(sbpMixerData,0);                          // 0=off,2=on\r
626                 }\r
627         }\r
628 }\r
629 \r
630 ///////////////////////////////////////////////////////////////////////////\r
631 //\r
632 //      SDL_ShutSB() - Turns off the SoundBlaster\r
633 //\r
634 ///////////////////////////////////////////////////////////////////////////\r
635 static void\r
636 SDL_ShutSB(void)\r
637 {\r
638         SDL_SBStopSample();\r
639 \r
640         if (SBProPresent)\r
641         {\r
642                 // Restore FM output levels (SB Pro)\r
643                 sbOut(sbpMixerAddr,sbpmFMVol);\r
644                 sbOut(sbpMixerData,sbpOldFMMix);\r
645 \r
646                 // Restore Voice output levels (SB Pro)\r
647                 sbOut(sbpMixerAddr,sbpmVoiceVol);\r
648                 sbOut(sbpMixerData,sbpOldVOCMix);\r
649         }\r
650 \r
651         setvect(sbIntVec,sbOldIntHand);         // Set vector back\r
652 }\r
653 #endif\r
654 \r
655 //      Sound Source Code\r
656 \r
657 ///////////////////////////////////////////////////////////////////////////\r
658 //\r
659 //      SDL_SSStopSample() - Stops a sample playing on the Sound Source\r
660 //\r
661 ///////////////////////////////////////////////////////////////////////////\r
662 #ifdef  _MUSE_\r
663 void\r
664 #else\r
665 static void\r
666 #endif\r
667 SDL_SSStopSample(void)\r
668 {\r
669 asm     pushf\r
670 asm     cli\r
671 \r
672         (long)ssSample = 0;\r
673 \r
674 asm     popf\r
675 }\r
676 \r
677 ///////////////////////////////////////////////////////////////////////////\r
678 //\r
679 //      SDL_SSService() - Handles playing the next sample on the Sound Source\r
680 //\r
681 ///////////////////////////////////////////////////////////////////////////\r
682 static void\r
683 SDL_SSService(void)\r
684 {\r
685         //boolean       gotit;\r
686         boolean doneflag=false;\r
687         byte    v;\r
688 \r
689         while (ssSample)\r
690         {\r
691         __asm {\r
692                 mov             dx,[ssStatus]   // Check to see if FIFO is currently empty\r
693                 in              al,dx\r
694                 test    al,0x40\r
695                 jnz             done                    // Nope - don't push any more data out\r
696                 jmp end\r
697 #ifdef __BORLANDC__\r
698         }\r
699 #endif\r
700                 done:\r
701 #ifdef __BORLANDC__\r
702         __asm {\r
703 #endif\r
704                 mov     doneflag,1\r
705 #ifdef __BORLANDC__\r
706         }\r
707 #endif\r
708                 end:\r
709 #ifdef __WATCOMC__\r
710         }\r
711 #endif\r
712                 if(!doneflag)\r
713                 {\r
714                         v = *ssSample++;\r
715                         if (!(--ssLengthLeft))\r
716                         {\r
717                                 (long)ssSample = 0;\r
718                                 SDL_DigitizedDone();\r
719                         }\r
720 \r
721                         __asm {\r
722                                 mov             dx,[ssData]             // Pump the value out\r
723                                 mov             al,[v]\r
724                                 out             dx,al\r
725 \r
726                                 mov             dx,[ssControl]  // Pulse printer select\r
727                                 mov             al,[ssOff]\r
728                                 out             dx,al\r
729                                 push    ax\r
730                                 pop             ax\r
731                                 mov             al,[ssOn]\r
732                                 out             dx,al\r
733 \r
734                                 push    ax                              // Delay a short while\r
735                                 pop             ax\r
736                                 push    ax\r
737                                 pop             ax\r
738 done:;\r
739                         }\r
740                 }\r
741         }\r
742 }\r
743 \r
744 ///////////////////////////////////////////////////////////////////////////\r
745 //\r
746 //      SDL_SSPlaySample() - Plays the specified sample on the Sound Source\r
747 //\r
748 ///////////////////////////////////////////////////////////////////////////\r
749 #ifdef  _MUSE_\r
750 void\r
751 #else\r
752 static void\r
753 #endif\r
754 SDL_SSPlaySample(byte huge *data,dword len)\r
755 {\r
756 asm     pushf\r
757 asm     cli\r
758 \r
759         ssLengthLeft = len;\r
760         ssSample = (volatile byte far *)data;\r
761 \r
762 asm     popf\r
763 }\r
764 \r
765 ///////////////////////////////////////////////////////////////////////////\r
766 //\r
767 //      SDL_StartSS() - Sets up for and turns on the Sound Source\r
768 //\r
769 ///////////////////////////////////////////////////////////////////////////\r
770 static void\r
771 SDL_StartSS(void)\r
772 {\r
773         if (ssPort == 3)\r
774                 ssControl = 0x27a;      // If using LPT3\r
775         else if (ssPort == 2)\r
776                 ssControl = 0x37a;      // If using LPT2\r
777         else\r
778                 ssControl = 0x3be;      // If using LPT1\r
779         ssStatus = ssControl - 1;\r
780         ssData = ssStatus - 1;\r
781 \r
782         ssOn = 0x04;\r
783         if (ssIsTandy)\r
784                 ssOff = 0x0e;                           // Tandy wierdness\r
785         else\r
786                 ssOff = 0x0c;                           // For normal machines\r
787 \r
788         outportb(ssControl,ssOn);               // Enable SS\r
789 }\r
790 \r
791 ///////////////////////////////////////////////////////////////////////////\r
792 //\r
793 //      SDL_ShutSS() - Turns off the Sound Source\r
794 //\r
795 ///////////////////////////////////////////////////////////////////////////\r
796 static void\r
797 SDL_ShutSS(void)\r
798 {\r
799         outportb(ssControl,ssOff);\r
800 }\r
801 \r
802 ///////////////////////////////////////////////////////////////////////////\r
803 //\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
806 //\r
807 ///////////////////////////////////////////////////////////////////////////\r
808 static boolean\r
809 SDL_CheckSS(void)\r
810 {\r
811         boolean         present = false, chkdone=0;\r
812         dword   lasttime;\r
813 \r
814         // Turn the Sound Source on and wait awhile (4 ticks)\r
815         SDL_StartSS();\r
816 \r
817         lasttime = TimeCount;\r
818         while (TimeCount < lasttime + 4)\r
819         {}\r
820 \r
821         __asm {\r
822                 mov             dx,[ssStatus]   // Check to see if FIFO is currently empty\r
823                 in              al,dx\r
824                 test    al,0x40\r
825                 jnz             checkdone               // Nope - Sound Source not here\r
826 \r
827                 mov             cx,32                   // Force FIFO overflow (FIFO is 16 bytes)\r
828 #ifdef __BORLANDC__\r
829         }\r
830 #endif\r
831 outloop:\r
832 #ifdef __BORLANDC__\r
833         __asm {\r
834 #endif\r
835                 mov             dx,[ssData]             // Pump a neutral value out\r
836                 mov             al,0x80\r
837                 out             dx,al\r
838 \r
839                 mov             dx,[ssControl]  // Pulse printer select\r
840                 mov             al,[ssOff]\r
841                 out             dx,al\r
842                 push    ax\r
843                 pop             ax\r
844                 mov             al,[ssOn]\r
845                 out             dx,al\r
846 \r
847                 push    ax                              // Delay a short while before we do this again\r
848                 pop             ax\r
849                 push    ax\r
850                 pop             ax\r
851 \r
852                 loop    outloop\r
853 \r
854                 mov             dx,[ssStatus]   // Is FIFO overflowed now?\r
855                 in              al,dx\r
856                 test    al,0x40\r
857                 jz              checkdone               // Nope, still not - Sound Source not here\r
858                 jmp end\r
859 #ifdef __BORLANDC__\r
860         }\r
861 #endif\r
862 checkdone:\r
863 #ifdef __BORLANDC__\r
864         __asm {\r
865 #endif\r
866                 mov     chkdone,1\r
867 #ifdef __BORLANDC__\r
868         }\r
869 #endif\r
870                 end:\r
871 #ifdef __WATCOMC__\r
872         }\r
873 #endif\r
874 \r
875         if(!chkdone) present = true;                    // Yes - it's here!\r
876 \r
877 //checkdone:\r
878         SDL_ShutSS();\r
879         return(present);\r
880 }\r
881 \r
882 static boolean\r
883 SDL_DetectSoundSource(void)\r
884 {\r
885         for (ssPort = 1;ssPort <= 3;ssPort++)\r
886                 if (SDL_CheckSS())\r
887                         return(true);\r
888         return(false);\r
889 }\r
890 \r
891 //\r
892 //      PC Sound code\r
893 //\r
894 \r
895 ///////////////////////////////////////////////////////////////////////////\r
896 //\r
897 //      SDL_PCPlaySample() - Plays the specified sample on the PC speaker\r
898 //\r
899 ///////////////////////////////////////////////////////////////////////////\r
900 #ifdef  _MUSE_\r
901 void\r
902 #else\r
903 static void\r
904 #endif\r
905 SDL_PCPlaySample(byte huge *data,dword len)\r
906 {\r
907 asm     pushf\r
908 asm     cli\r
909 \r
910         SDL_IndicatePC(true);\r
911 \r
912         pcLengthLeft = len;\r
913         pcSound = (volatile byte far *)data;\r
914 \r
915 asm     popf\r
916 }\r
917 \r
918 ///////////////////////////////////////////////////////////////////////////\r
919 //\r
920 //      SDL_PCStopSample() - Stops a sample playing on the PC speaker\r
921 //\r
922 ///////////////////////////////////////////////////////////////////////////\r
923 #ifdef  _MUSE_\r
924 void\r
925 #else\r
926 static void\r
927 #endif\r
928 SDL_PCStopSample(void)\r
929 {\r
930 asm     pushf\r
931 asm     cli\r
932 \r
933         (long)pcSound = 0;\r
934 \r
935         SDL_IndicatePC(false);\r
936 \r
937 asm     in      al,0x61                 // Turn the speaker off\r
938 asm     and     al,0xfd                 // ~2\r
939 asm     out     0x61,al\r
940 \r
941 asm     popf\r
942 }\r
943 \r
944 ///////////////////////////////////////////////////////////////////////////\r
945 //\r
946 //      SDL_PCPlaySound() - Plays the specified sound on the PC speaker\r
947 //\r
948 ///////////////////////////////////////////////////////////////////////////\r
949 #ifdef  _MUSE_\r
950 void\r
951 #else\r
952 static void\r
953 #endif\r
954 SDL_PCPlaySound(PCSound far *sound)\r
955 {\r
956 asm     pushf\r
957 asm     cli\r
958 \r
959         pcLastSample = -1;\r
960         pcLengthLeft = sound->common.length;\r
961         pcSound = sound->data;\r
962 \r
963 asm     popf\r
964 }\r
965 \r
966 ///////////////////////////////////////////////////////////////////////////\r
967 //\r
968 //      SDL_PCStopSound() - Stops the current sound playing on the PC Speaker\r
969 //\r
970 ///////////////////////////////////////////////////////////////////////////\r
971 #ifdef  _MUSE_\r
972 void\r
973 #else\r
974 static void\r
975 #endif\r
976 SDL_PCStopSound(void)\r
977 {\r
978 asm     pushf\r
979 asm     cli\r
980 \r
981         (long)pcSound = 0;\r
982 \r
983 asm     in      al,0x61                 // Turn the speaker off\r
984 asm     and     al,0xfd                 // ~2\r
985 asm     out     0x61,al\r
986 \r
987 asm     popf\r
988 }\r
989 \r
990 #if 0\r
991 ///////////////////////////////////////////////////////////////////////////\r
992 //\r
993 //      SDL_PCService() - Handles playing the next sample in a PC sound\r
994 //\r
995 ///////////////////////////////////////////////////////////////////////////\r
996 static void\r
997 SDL_PCService(void)\r
998 {\r
999         byte    s;\r
1000         word    t;\r
1001 \r
1002         if (pcSound)\r
1003         {\r
1004                 s = *pcSound++;\r
1005                 if (s != pcLastSample)\r
1006                 {\r
1007                 asm     pushf\r
1008                 asm     cli\r
1009 \r
1010                         pcLastSample = s;\r
1011                         if (s)                                  // We have a frequency!\r
1012                         {\r
1013                                 t = pcSoundLookup[s];\r
1014                         asm     mov     bx,[t]\r
1015 \r
1016                         asm     mov     al,0xb6                 // Write to channel 2 (speaker) timer\r
1017                         asm     out     43h,al\r
1018                         asm     mov     al,bl\r
1019                         asm     out     42h,al                  // Low byte\r
1020                         asm     mov     al,bh\r
1021                         asm     out     42h,al                  // High byte\r
1022 \r
1023                         asm     in      al,0x61                 // Turn the speaker & gate on\r
1024                         asm     or      al,3\r
1025                         asm     out     0x61,al\r
1026                         }\r
1027                         else                                    // Time for some silence\r
1028                         {\r
1029                         asm     in      al,0x61                 // Turn the speaker & gate off\r
1030                         asm     and     al,0xfc                 // ~3\r
1031                         asm     out     0x61,al\r
1032                         }\r
1033 \r
1034                 asm     popf\r
1035                 }\r
1036 \r
1037                 if (!(--pcLengthLeft))\r
1038                 {\r
1039                         SDL_PCStopSound();\r
1040                         SDL_SoundFinished();\r
1041                 }\r
1042         }\r
1043 }\r
1044 #endif\r
1045 \r
1046 ///////////////////////////////////////////////////////////////////////////\r
1047 //\r
1048 //      SDL_ShutPC() - Turns off the pc speaker\r
1049 //\r
1050 ///////////////////////////////////////////////////////////////////////////\r
1051 static void\r
1052 SDL_ShutPC(void)\r
1053 {\r
1054 asm     pushf\r
1055 asm     cli\r
1056 \r
1057         pcSound = 0;\r
1058 \r
1059 asm     in      al,0x61                 // Turn the speaker & gate off\r
1060 asm     and     al,0xfc                 // ~3\r
1061 asm     out     0x61,al\r
1062 \r
1063 asm     popf\r
1064 }\r
1065 \r
1066 //\r
1067 //      Stuff for digitized sounds\r
1068 //\r
1069 memptr\r
1070 SDL_LoadDigiSegment(word page)\r
1071 {\r
1072         memptr  addr;\r
1073 \r
1074 #if 0   // for debugging\r
1075 asm     mov     dx,STATUS_REGISTER_1\r
1076 asm     in      al,dx\r
1077 asm     mov     dx,ATR_INDEX\r
1078 asm     mov     al,ATR_OVERSCAN\r
1079 asm     out     dx,al\r
1080 asm     mov     al,10   // bright green\r
1081 asm     out     dx,al\r
1082 #endif\r
1083 \r
1084         addr = PM_GetSoundPage(page, gvar);\r
1085         PM_SetPageLock(PMSoundStart + page,pml_Locked);\r
1086 \r
1087 #if 0   // for debugging\r
1088 asm     mov     dx,STATUS_REGISTER_1\r
1089 asm     in      al,dx\r
1090 asm     mov     dx,ATR_INDEX\r
1091 asm     mov     al,ATR_OVERSCAN\r
1092 asm     out     dx,al\r
1093 asm     mov     al,3    // blue\r
1094 asm     out     dx,al\r
1095 asm     mov     al,0x20 // normal\r
1096 asm     out     dx,al\r
1097 #endif\r
1098 \r
1099         return(addr);\r
1100 }\r
1101 \r
1102 void\r
1103 SDL_PlayDigiSegment(memptr addr,word len)\r
1104 {\r
1105         switch (DigiMode)\r
1106         {\r
1107         case sds_PC:\r
1108         SDL_PCPlaySample(addr,len);\r
1109                 break;\r
1110         case sds_SoundSource:\r
1111                 SDL_SSPlaySample(addr,len);\r
1112                 break;\r
1113         case sds_SoundBlaster:\r
1114                 SDL_SBPlaySample(addr,len);\r
1115                 break;\r
1116         }\r
1117 }\r
1118 \r
1119 void\r
1120 SD_StopDigitized(void)\r
1121 {\r
1122         int     i;\r
1123 \r
1124 asm     pushf\r
1125 asm     cli\r
1126 \r
1127         DigiLeft = 0;\r
1128         DigiNextAddr = nil;\r
1129         DigiNextLen = 0;\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
1136 \r
1137         switch (DigiMode)\r
1138         {\r
1139         case sds_PC:\r
1140                 SDL_PCStopSample();\r
1141                 break;\r
1142         case sds_SoundSource:\r
1143                 SDL_SSStopSample();\r
1144                 break;\r
1145         case sds_SoundBlaster:\r
1146                 SDL_SBStopSample();\r
1147                 break;\r
1148         }\r
1149 \r
1150 asm     popf\r
1151 \r
1152         for (i = DigiLastStart;i < DigiLastEnd;i++)\r
1153                 PM_SetPageLock(i + PMSoundStart,pml_Unlocked);\r
1154         DigiLastStart = 1;\r
1155         DigiLastEnd = 0;\r
1156 }\r
1157 \r
1158 void\r
1159 SD_Poll(void)\r
1160 {\r
1161         if (DigiLeft && !DigiNextAddr)\r
1162         {\r
1163                 DigiNextLen = (DigiLeft >= PMPageSize)? PMPageSize : (DigiLeft % PMPageSize);\r
1164                 DigiLeft -= DigiNextLen;\r
1165                 if (!DigiLeft)\r
1166                         DigiLastSegment = true;\r
1167                 DigiNextAddr = SDL_LoadDigiSegment(DigiPage++);\r
1168         }\r
1169         if (DigiMissed && DigiNextAddr)\r
1170         {\r
1171                 SDL_PlayDigiSegment(DigiNextAddr,DigiNextLen);\r
1172                 DigiNextAddr = nil;\r
1173                 DigiMissed = false;\r
1174                 if (DigiLastSegment)\r
1175                 {\r
1176                         DigiPlaying = false;\r
1177                         DigiLastSegment = false;\r
1178                 }\r
1179         }\r
1180         SDL_SetTimerSpeed();\r
1181 }\r
1182 \r
1183 void\r
1184 SD_SetPosition(int leftpos,int rightpos)\r
1185 {\r
1186         if\r
1187         (\r
1188                 (leftpos < 0)\r
1189         ||      (leftpos > 15)\r
1190         ||      (rightpos < 0)\r
1191         ||      (rightpos > 15)\r
1192         ||      ((leftpos == 15) && (rightpos == 15))\r
1193         )\r
1194                 Quit("SD_SetPosition: Illegal position");\r
1195 \r
1196         switch (DigiMode)\r
1197         {\r
1198         case sds_SoundBlaster:\r
1199                 SDL_PositionSBP(leftpos,rightpos);\r
1200                 break;\r
1201         }\r
1202 }\r
1203 \r
1204 void\r
1205 SD_PlayDigitized(word which,int leftpos,int rightpos)\r
1206 {\r
1207         word    len;\r
1208         memptr  addr;\r
1209 \r
1210         if (!DigiMode)\r
1211                 return;\r
1212 \r
1213         SD_StopDigitized();\r
1214         if (which >= NumDigi)\r
1215                 Quit("SD_PlayDigitized: bad sound number");\r
1216 \r
1217         SD_SetPosition(leftpos,rightpos);\r
1218 \r
1219         DigiPage = DigiList[(which * 2) + 0];\r
1220         DigiLeft = DigiList[(which * 2) + 1];\r
1221 \r
1222         DigiLastStart = DigiPage;\r
1223         DigiLastEnd = DigiPage + ((DigiLeft + (PMPageSize - 1)) / PMPageSize);\r
1224 \r
1225         len = (DigiLeft >= PMPageSize)? PMPageSize : (DigiLeft % PMPageSize);\r
1226         addr = SDL_LoadDigiSegment(DigiPage++);\r
1227 \r
1228         DigiPlaying = true;\r
1229         DigiLastSegment = false;\r
1230 \r
1231         SDL_PlayDigiSegment(addr,len);\r
1232         DigiLeft -= len;\r
1233         if (!DigiLeft)\r
1234                 DigiLastSegment = true;\r
1235 \r
1236         SD_Poll();\r
1237 }\r
1238 \r
1239 void\r
1240 SDL_DigitizedDone(void)\r
1241 {\r
1242         if (DigiNextAddr)\r
1243         {\r
1244                 SDL_PlayDigiSegment(DigiNextAddr,DigiNextLen);\r
1245                 DigiNextAddr = nil;\r
1246                 DigiMissed = false;\r
1247         }\r
1248         else\r
1249         {\r
1250                 if (DigiLastSegment)\r
1251                 {\r
1252                         DigiPlaying = false;\r
1253                         DigiLastSegment = false;\r
1254                         if ((DigiMode == sds_PC) && (SoundMode == sdm_PC))\r
1255                         {\r
1256                                 SDL_SoundFinished();\r
1257                         }\r
1258                         else\r
1259                                 DigiNumber = DigiPriority = 0;\r
1260                         SoundPositioned = false;\r
1261                 }\r
1262                 else\r
1263                         DigiMissed = true;\r
1264         }\r
1265 }\r
1266 \r
1267 void\r
1268 SD_SetDigiDevice(SDSMode mode)\r
1269 {\r
1270         boolean devicenotpresent;\r
1271 \r
1272         if (mode == DigiMode)\r
1273                 return;\r
1274 \r
1275         SD_StopDigitized();\r
1276 \r
1277         devicenotpresent = false;\r
1278         switch (mode)\r
1279         {\r
1280         case sds_SoundBlaster:\r
1281                 if (!SoundBlasterPresent)\r
1282                 {\r
1283                         if (SoundSourcePresent)\r
1284                                 mode = sds_SoundSource;\r
1285                         else\r
1286                                 devicenotpresent = true;\r
1287                 }\r
1288                 break;\r
1289         case sds_SoundSource:\r
1290                 if (!SoundSourcePresent)\r
1291                         devicenotpresent = true;\r
1292                 break;\r
1293         }\r
1294 \r
1295         if (!devicenotpresent)\r
1296         {\r
1297                 if (DigiMode == sds_SoundSource)\r
1298                         SDL_ShutSS();\r
1299 \r
1300                 DigiMode = mode;\r
1301 \r
1302                 if (mode == sds_SoundSource)\r
1303                         SDL_StartSS();\r
1304 \r
1305                 SDL_SetTimerSpeed();\r
1306         }\r
1307 }\r
1308 \r
1309 void\r
1310 SDL_SetupDigi(void)\r
1311 {\r
1312         memptr  list;\r
1313         word    far *p,\r
1314                         pg;\r
1315         int             i;\r
1316 \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
1324         {\r
1325                 if (pg >= ChunksInFile - 1)\r
1326                         break;\r
1327                 pg += (p[1] + (PMPageSize - 1)) / PMPageSize;\r
1328         }\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
1333         NumDigi = i;\r
1334 \r
1335         for (i = 0;i < LASTSOUND;i++)\r
1336                 DigiMap[i] = -1;\r
1337 }\r
1338 \r
1339 //      AdLib Code\r
1340 \r
1341 ///////////////////////////////////////////////////////////////////////////\r
1342 //\r
1343 //      alOut(n,b) - Puts b in AdLib card register n\r
1344 //\r
1345 ///////////////////////////////////////////////////////////////////////////\r
1346 void\r
1347 alOut(byte n,byte b)\r
1348 {\r
1349 asm     pushf\r
1350 asm     cli\r
1351 \r
1352 asm     mov     dx,0x388\r
1353 asm     mov     al,[n]\r
1354 asm     out     dx,al\r
1355 asm     in      al,dx\r
1356 asm     in      al,dx\r
1357 asm     in      al,dx\r
1358 asm     in      al,dx\r
1359 asm     in      al,dx\r
1360 asm     in      al,dx\r
1361 asm     inc     dx\r
1362 asm     mov     al,[b]\r
1363 asm     out     dx,al\r
1364 \r
1365 asm     popf\r
1366 \r
1367 asm     dec     dx\r
1368 asm     in      al,dx\r
1369 asm     in      al,dx\r
1370 asm     in      al,dx\r
1371 asm     in      al,dx\r
1372 asm     in      al,dx\r
1373 asm     in      al,dx\r
1374 asm     in      al,dx\r
1375 asm     in      al,dx\r
1376 asm     in      al,dx\r
1377 asm     in      al,dx\r
1378 \r
1379 asm     in      al,dx\r
1380 asm     in      al,dx\r
1381 asm     in      al,dx\r
1382 asm     in      al,dx\r
1383 asm     in      al,dx\r
1384 asm     in      al,dx\r
1385 asm     in      al,dx\r
1386 asm     in      al,dx\r
1387 asm     in      al,dx\r
1388 asm     in      al,dx\r
1389 \r
1390 asm     in      al,dx\r
1391 asm     in      al,dx\r
1392 asm     in      al,dx\r
1393 asm     in      al,dx\r
1394 asm     in      al,dx\r
1395 asm     in      al,dx\r
1396 asm     in      al,dx\r
1397 asm     in      al,dx\r
1398 asm     in      al,dx\r
1399 asm     in      al,dx\r
1400 \r
1401 asm     in      al,dx\r
1402 asm     in      al,dx\r
1403 asm     in      al,dx\r
1404 asm     in      al,dx\r
1405 asm     in      al,dx\r
1406 }\r
1407 \r
1408 #if 0\r
1409 ///////////////////////////////////////////////////////////////////////////\r
1410 //\r
1411 //      SDL_SetInstrument() - Puts an instrument into a generator\r
1412 //\r
1413 ///////////////////////////////////////////////////////////////////////////\r
1414 static void\r
1415 SDL_SetInstrument(int track,int which,Instrument far *inst,boolean percussive)\r
1416 {\r
1417         byte            c,m;\r
1418 \r
1419         if (percussive)\r
1420         {\r
1421                 c = pcarriers[which];\r
1422                 m = pmodifiers[which];\r
1423         }\r
1424         else\r
1425         {\r
1426                 c = carriers[which];\r
1427                 m = modifiers[which];\r
1428         }\r
1429 \r
1430         tracks[track - 1]->inst = *inst;\r
1431         tracks[track - 1]->percussive = percussive;\r
1432 \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
1438 \r
1439         // Most percussive instruments only use one cell\r
1440         if (c != 0xff)\r
1441         {\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
1447         }\r
1448 \r
1449         alOut(which + alFeedCon,inst->nConn);   // DEBUG - I think this is right\r
1450 }\r
1451 #endif\r
1452 \r
1453 ///////////////////////////////////////////////////////////////////////////\r
1454 //\r
1455 //      SDL_ALStopSound() - Turns off any sound effects playing through the\r
1456 //              AdLib card\r
1457 //\r
1458 ///////////////////////////////////////////////////////////////////////////\r
1459 #ifdef  _MUSE_\r
1460 void\r
1461 #else\r
1462 static void\r
1463 #endif\r
1464 SDL_ALStopSound(void)\r
1465 {\r
1466 asm     pushf\r
1467 asm     cli\r
1468 \r
1469         (long)alSound = 0;\r
1470         alOut(alFreqH + 0,0);\r
1471 \r
1472 asm     popf\r
1473 }\r
1474 \r
1475 static void\r
1476 SDL_AlSetFXInst(Instrument far *inst)\r
1477 {\r
1478         byte            c,m;\r
1479 \r
1480         m = modifiers[0];\r
1481         c = carriers[0];\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
1492 \r
1493         // Note: Switch commenting on these lines for old MUSE compatibility\r
1494 //      alOut(alFeedCon,inst->nConn);\r
1495         alOut(alFeedCon,0);\r
1496 }\r
1497 \r
1498 ///////////////////////////////////////////////////////////////////////////\r
1499 //\r
1500 //      SDL_ALPlaySound() - Plays the specified sound on the AdLib card\r
1501 //\r
1502 ///////////////////////////////////////////////////////////////////////////\r
1503 #ifdef  _MUSE_\r
1504 void\r
1505 #else\r
1506 static void\r
1507 #endif\r
1508 SDL_ALPlaySound(AdLibSound far *sound)\r
1509 {\r
1510         Instrument      far *inst;\r
1511         byte            huge *data;\r
1512 \r
1513         SDL_ALStopSound();\r
1514 \r
1515 asm     pushf\r
1516 asm     cli\r
1517 \r
1518         alLengthLeft = sound->common.length;\r
1519         data = sound->data;\r
1520         data++;\r
1521         data--;\r
1522         alSound = (byte far *)data;\r
1523         alBlock = ((sound->block & 7) << 2) | 0x20;\r
1524         inst = &sound->inst;\r
1525 \r
1526         if (!(inst->mSus | inst->cSus))\r
1527         {\r
1528         asm     popf\r
1529                 Quit("SDL_ALPlaySound() - Bad instrument");\r
1530         }\r
1531 \r
1532         SDL_AlSetFXInst(&alZeroInst);   // DEBUG\r
1533         SDL_AlSetFXInst(inst);\r
1534 \r
1535 asm     popf\r
1536 }\r
1537 \r
1538 #if 0\r
1539 ///////////////////////////////////////////////////////////////////////////\r
1540 //\r
1541 //      SDL_ALSoundService() - Plays the next sample out through the AdLib card\r
1542 //\r
1543 ///////////////////////////////////////////////////////////////////////////\r
1544 //static void\r
1545 void\r
1546 SDL_ALSoundService(void)\r
1547 {\r
1548         byte    s;\r
1549 \r
1550         if (alSound)\r
1551         {\r
1552                 s = *alSound++;\r
1553                 if (!s)\r
1554                         alOut(alFreqH + 0,0);\r
1555                 else\r
1556                 {\r
1557                         alOut(alFreqL + 0,s);\r
1558                         alOut(alFreqH + 0,alBlock);\r
1559                 }\r
1560 \r
1561                 if (!(--alLengthLeft))\r
1562                 {\r
1563                         (long)alSound = 0;\r
1564                         alOut(alFreqH + 0,0);\r
1565                         SDL_SoundFinished();\r
1566                 }\r
1567         }\r
1568 }\r
1569 #endif\r
1570 \r
1571 #if 0\r
1572 void\r
1573 SDL_ALService(void)\r
1574 {\r
1575         byte    a,v;\r
1576         word    w;\r
1577 \r
1578         if (!sqActive)\r
1579                 return;\r
1580 \r
1581         while (sqHackLen && (sqHackTime <= alTimeCount))\r
1582         {\r
1583                 w = *sqHackPtr++;\r
1584                 sqHackTime = alTimeCount + *sqHackPtr++;\r
1585         asm     mov     dx,[w]\r
1586         asm     mov     [a],dl\r
1587         asm     mov     [v],dh\r
1588                 alOut(a,v);\r
1589                 sqHackLen -= 4;\r
1590         }\r
1591         alTimeCount++;\r
1592         if (!sqHackLen)\r
1593         {\r
1594                 sqHackPtr = (word far *)sqHack;\r
1595                 sqHackLen = sqHackSeqLen;\r
1596                 alTimeCount = sqHackTime = 0;\r
1597         }\r
1598 }\r
1599 #endif\r
1600 \r
1601 ///////////////////////////////////////////////////////////////////////////\r
1602 //\r
1603 //      SDL_ShutAL() - Shuts down the AdLib card for sound effects\r
1604 //\r
1605 ///////////////////////////////////////////////////////////////////////////\r
1606 static void\r
1607 SDL_ShutAL(void)\r
1608 {\r
1609 asm     pushf\r
1610 asm     cli\r
1611 \r
1612         alOut(alEffects,0);\r
1613         alOut(alFreqH + 0,0);\r
1614         SDL_AlSetFXInst(&alZeroInst);\r
1615         alSound = 0;\r
1616 \r
1617 asm     popf\r
1618 }\r
1619 \r
1620 ///////////////////////////////////////////////////////////////////////////\r
1621 //\r
1622 //      SDL_CleanAL() - Totally shuts down the AdLib card\r
1623 //\r
1624 ///////////////////////////////////////////////////////////////////////////\r
1625 static void\r
1626 SDL_CleanAL(void)\r
1627 {\r
1628         int     i;\r
1629 \r
1630 asm     pushf\r
1631 asm     cli\r
1632 \r
1633         alOut(alEffects,0);\r
1634         for (i = 1;i < 0xf5;i++)\r
1635                 alOut(i,0);\r
1636 \r
1637 asm     popf\r
1638 }\r
1639 \r
1640 ///////////////////////////////////////////////////////////////////////////\r
1641 //\r
1642 //      SDL_StartAL() - Starts up the AdLib card for sound effects\r
1643 //\r
1644 ///////////////////////////////////////////////////////////////////////////\r
1645 static void\r
1646 SDL_StartAL(void)\r
1647 {\r
1648         alFXReg = 0;\r
1649         alOut(alEffects,alFXReg);\r
1650         SDL_AlSetFXInst(&alZeroInst);\r
1651 }\r
1652 \r
1653 ///////////////////////////////////////////////////////////////////////////\r
1654 //\r
1655 //      SDL_DetectAdLib() - Determines if there's an AdLib (or SoundBlaster\r
1656 //              emulating an AdLib) present\r
1657 //\r
1658 ///////////////////////////////////////////////////////////////////////////\r
1659 static boolean\r
1660 SDL_DetectAdLib(void)\r
1661 {\r
1662         byte    status1,status2;\r
1663         int             i;\r
1664 \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
1670 #if 0\r
1671         SDL_Delay(TimerDelay100);\r
1672 #else\r
1673         __asm {\r
1674                 mov     dx,0x388\r
1675                 mov     cx,100\r
1676 #ifdef __BORLANDC__\r
1677         }\r
1678 #endif\r
1679 usecloop:\r
1680 #ifdef __BORLANDC__\r
1681         __asm {\r
1682 #endif\r
1683         in      al,dx\r
1684         loop usecloop\r
1685         }\r
1686 #endif\r
1687 \r
1688         status2 = readstat();\r
1689         alOut(4,0x60);\r
1690         alOut(4,0x80);\r
1691 \r
1692         if (((status1 & 0xe0) == 0x00) && ((status2 & 0xe0) == 0xc0))\r
1693         {\r
1694                 for (i = 1;i <= 0xf5;i++)       // Zero all the registers\r
1695                         alOut(i,0);\r
1696 \r
1697                 alOut(1,0x20);  // Set WSE=1\r
1698                 alOut(8,0);             // Set CSM=0 & SEL=0\r
1699 \r
1700                 return(true);\r
1701         }\r
1702         else\r
1703                 return(false);\r
1704 }\r
1705 \r
1706 #if 0\r
1707 ///////////////////////////////////////////////////////////////////////////\r
1708 //\r
1709 //      SDL_t0Service() - My timer 0 ISR which handles the different timings and\r
1710 //              dispatches to whatever other routines are appropriate\r
1711 //\r
1712 ///////////////////////////////////////////////////////////////////////////\r
1713 static void interrupt\r
1714 SDL_t0Service(void)\r
1715 {\r
1716 static  word    count = 1;\r
1717 \r
1718 #if 1   // for debugging\r
1719 asm     mov     dx,STATUS_REGISTER_1\r
1720 asm     in      al,dx\r
1721 asm     mov     dx,ATR_INDEX\r
1722 asm     mov     al,ATR_OVERSCAN\r
1723 asm     out     dx,al\r
1724 asm     mov     al,4    // red\r
1725 asm     out     dx,al\r
1726 #endif\r
1727 \r
1728         HackCount++;\r
1729 \r
1730         if ((MusicMode == smm_AdLib) || (DigiMode == sds_SoundSource))\r
1731         {\r
1732                 SDL_ALService();\r
1733                 SDL_SSService();\r
1734 //              if (!(++count & 7))\r
1735                 if (!(++count % 10))\r
1736                 {\r
1737                         LocalTime++;\r
1738                         TimeCount++;\r
1739                         if (SoundUserHook)\r
1740                                 SoundUserHook();\r
1741                 }\r
1742 //              if (!(count & 3))\r
1743                 if (!(count % 5))\r
1744                 {\r
1745                         switch (SoundMode)\r
1746                         {\r
1747                         case sdm_PC:\r
1748                                 SDL_PCService();\r
1749                                 break;\r
1750                         case sdm_AdLib:\r
1751                                 SDL_ALSoundService();\r
1752                                 break;\r
1753                         }\r
1754                 }\r
1755         }\r
1756         else\r
1757         {\r
1758                 if (!(++count & 1))\r
1759                 {\r
1760                         LocalTime++;\r
1761                         TimeCount++;\r
1762                         if (SoundUserHook)\r
1763                                 SoundUserHook();\r
1764                 }\r
1765                 switch (SoundMode)\r
1766                 {\r
1767                 case sdm_PC:\r
1768                         SDL_PCService();\r
1769                         break;\r
1770                 case sdm_AdLib:\r
1771                         SDL_ALSoundService();\r
1772                         break;\r
1773                 }\r
1774         }\r
1775 \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
1779 asm     jnc     myack\r
1780         t0OldService();                 // If we overflow a word, time to call old int handler\r
1781 asm     jmp     olddone\r
1782 myack:;\r
1783         outportb(0x20,0x20);    // Ack the interrupt\r
1784 olddone:;\r
1785 \r
1786 #if 1   // for debugging\r
1787 asm     mov     dx,STATUS_REGISTER_1\r
1788 asm     in      al,dx\r
1789 asm     mov     dx,ATR_INDEX\r
1790 asm     mov     al,ATR_OVERSCAN\r
1791 asm     out     dx,al\r
1792 asm     mov     al,3    // blue\r
1793 asm     out     dx,al\r
1794 asm     mov     al,0x20 // normal\r
1795 asm     out     dx,al\r
1796 #endif\r
1797 }\r
1798 #endif\r
1799 \r
1800 ////////////////////////////////////////////////////////////////////////////\r
1801 //\r
1802 //      SDL_ShutDevice() - turns off whatever device was being used for sound fx\r
1803 //\r
1804 ////////////////////////////////////////////////////////////////////////////\r
1805 static void\r
1806 SDL_ShutDevice(void)\r
1807 {\r
1808         switch (SoundMode)\r
1809         {\r
1810         case sdm_PC:\r
1811                 SDL_ShutPC();\r
1812                 break;\r
1813         case sdm_AdLib:\r
1814                 SDL_ShutAL();\r
1815                 break;\r
1816         }\r
1817         SoundMode = sdm_Off;\r
1818 }\r
1819 \r
1820 ///////////////////////////////////////////////////////////////////////////\r
1821 //\r
1822 //      SDL_CleanDevice() - totally shuts down all sound devices\r
1823 //\r
1824 ///////////////////////////////////////////////////////////////////////////\r
1825 static void\r
1826 SDL_CleanDevice(void)\r
1827 {\r
1828         if ((SoundMode == sdm_AdLib) || (MusicMode == smm_AdLib))\r
1829                 SDL_CleanAL();\r
1830 }\r
1831 \r
1832 ///////////////////////////////////////////////////////////////////////////\r
1833 //\r
1834 //      SDL_StartDevice() - turns on whatever device is to be used for sound fx\r
1835 //\r
1836 ///////////////////////////////////////////////////////////////////////////\r
1837 static void\r
1838 SDL_StartDevice(void)\r
1839 {\r
1840         switch (SoundMode)\r
1841         {\r
1842         case sdm_AdLib:\r
1843                 SDL_StartAL();\r
1844                 break;\r
1845         }\r
1846         SoundNumber = SoundPriority = 0;\r
1847 }\r
1848 \r
1849 //      Public routines\r
1850 \r
1851 ///////////////////////////////////////////////////////////////////////////\r
1852 //\r
1853 //      SD_SetSoundMode() - Sets which sound hardware to use for sound effects\r
1854 //\r
1855 ///////////////////////////////////////////////////////////////////////////\r
1856 boolean\r
1857 SD_SetSoundMode(SDMode mode)\r
1858 {\r
1859         boolean result = false;\r
1860         word    tableoffset;\r
1861 \r
1862         SD_StopSound();\r
1863 \r
1864 #ifndef _MUSE_\r
1865         if ((mode == sdm_AdLib) && !AdLibPresent)\r
1866                 mode = sdm_PC;\r
1867 \r
1868         switch (mode)\r
1869         {\r
1870         case sdm_Off:\r
1871                 NeedsDigitized = false;\r
1872                 result = true;\r
1873                 break;\r
1874         case sdm_PC:\r
1875                 tableoffset = STARTPCSOUNDS;\r
1876                 NeedsDigitized = false;\r
1877                 result = true;\r
1878                 break;\r
1879         case sdm_AdLib:\r
1880                 if (AdLibPresent)\r
1881                 {\r
1882                         tableoffset = STARTADLIBSOUNDS;\r
1883                         NeedsDigitized = false;\r
1884                         result = true;\r
1885                 }\r
1886                 break;\r
1887         }\r
1888 #else\r
1889         result = true;\r
1890 #endif\r
1891 \r
1892         if (result && (mode != SoundMode))\r
1893         {\r
1894                 SDL_ShutDevice();\r
1895                 SoundMode = mode;\r
1896 #ifndef _MUSE_\r
1897                 SoundTable = (word *)(&audiosegs[tableoffset]);\r
1898 #endif\r
1899                 SDL_StartDevice();\r
1900         }\r
1901 \r
1902         SDL_SetTimerSpeed();\r
1903 \r
1904         return(result);\r
1905 }\r
1906 \r
1907 ///////////////////////////////////////////////////////////////////////////\r
1908 //\r
1909 //      SD_SetMusicMode() - sets the device to use for background music\r
1910 //\r
1911 ///////////////////////////////////////////////////////////////////////////\r
1912 boolean\r
1913 SD_SetMusicMode(SMMode mode)\r
1914 {\r
1915         boolean result = false;\r
1916 \r
1917         SD_FadeOutMusic();\r
1918         while (SD_MusicPlaying())\r
1919                 ;\r
1920 \r
1921         switch (mode)\r
1922         {\r
1923         case smm_Off:\r
1924                 NeedsMusic = false;\r
1925                 result = true;\r
1926                 break;\r
1927         case smm_AdLib:\r
1928                 if (AdLibPresent)\r
1929                 {\r
1930                         NeedsMusic = true;\r
1931                         result = true;\r
1932                 }\r
1933                 break;\r
1934         }\r
1935 \r
1936         if (result)\r
1937                 MusicMode = mode;\r
1938 \r
1939         SDL_SetTimerSpeed();\r
1940 \r
1941         return(result);\r
1942 }\r
1943 \r
1944 ///////////////////////////////////////////////////////////////////////////\r
1945 //\r
1946 //      SD_Startup() - starts up the Sound Mgr\r
1947 //              Detects all additional sound hardware and installs my ISR\r
1948 //\r
1949 ///////////////////////////////////////////////////////////////////////////\r
1950 void\r
1951 SD_Startup(void)\r
1952 {\r
1953         int     i;\r
1954 \r
1955         if (SD_Started)\r
1956                 return;\r
1957 \r
1958         SDL_SetDS();\r
1959 \r
1960         ssIsTandy = false;\r
1961         ssNoCheck = false;\r
1962         alNoCheck = false;\r
1963         sbNoCheck = false;\r
1964         sbNoProCheck = false;\r
1965 #ifndef _MUSE_\r
1966         for (i = 1;i < _argc;i++)\r
1967         {\r
1968                 switch (US_CheckParm(_argv[i],ParmStrings))\r
1969                 {\r
1970                 case 0:                                         // No AdLib detection\r
1971                         alNoCheck = true;\r
1972                         break;\r
1973                 case 1:                                         // No SoundBlaster detection\r
1974                         sbNoCheck = true;\r
1975                         break;\r
1976                 case 2:                                         // No SoundBlaster Pro detection\r
1977                         sbNoProCheck = true;\r
1978                         break;\r
1979                 case 3:\r
1980                         ssNoCheck = true;               // No Sound Source detection\r
1981                         break;\r
1982                 case 4:                                         // Tandy Sound Source handling\r
1983                         ssIsTandy = true;\r
1984                         break;\r
1985                 case 5:                                         // Sound Source present at LPT1\r
1986                         ssPort = 1;\r
1987                         ssNoCheck = SoundSourcePresent = true;\r
1988                         break;\r
1989                 case 6:                     // Sound Source present at LPT2\r
1990                         ssPort = 2;\r
1991                         ssNoCheck = SoundSourcePresent = true;\r
1992                         break;\r
1993                 case 7:                     // Sound Source present at LPT3\r
1994                         ssPort = 3;\r
1995                         ssNoCheck = SoundSourcePresent = true;\r
1996                         break;\r
1997                 }\r
1998         }\r
1999 #endif\r
2000 \r
2001         SoundUserHook = 0;\r
2002 \r
2003         t0OldService = getvect(8);      // Get old timer 0 ISR\r
2004 \r
2005         LocalTime = TimeCount = alTimeCount = 0;\r
2006 \r
2007         SD_SetSoundMode(sdm_Off);\r
2008         SD_SetMusicMode(smm_Off);\r
2009 \r
2010         if (!ssNoCheck)\r
2011                 SoundSourcePresent = SDL_DetectSoundSource();\r
2012 \r
2013         if (!alNoCheck)\r
2014         {\r
2015                 AdLibPresent = SDL_DetectAdLib();\r
2016                 if (AdLibPresent && !sbNoCheck)\r
2017                 {\r
2018                         int port = -1;\r
2019                         char *env = getenv("BLASTER");\r
2020                         if (env)\r
2021                         {\r
2022                                 long temp;\r
2023                                 while (*env)\r
2024                                 {\r
2025                                         while (isspace(*env))\r
2026                                                 env++;\r
2027 \r
2028                                         switch (toupper(*env))\r
2029                                         {\r
2030                                         case 'A':\r
2031                                                 temp = strtol(env + 1,&env,16);\r
2032                                                 if\r
2033                                                 (\r
2034                                                         (temp >= 0x210)\r
2035                                                 &&      (temp <= 0x260)\r
2036                                                 &&      (!(temp & 0x00f))\r
2037                                                 )\r
2038                                                         port = (temp - 0x200) >> 4;\r
2039                                                 else\r
2040                                                         Quit("SD_Startup: Unsupported address value in BLASTER");\r
2041                                                 break;\r
2042                                         case 'I':\r
2043                                                 temp = strtol(env + 1,&env,10);\r
2044                                                 if\r
2045                                                 (\r
2046                                                         (temp >= 0)\r
2047                                                 &&      (temp <= 10)\r
2048                                                 &&      (sbIntVectors[temp] != -1)\r
2049                                                 )\r
2050                                                 {\r
2051                                                         sbInterrupt = temp;\r
2052                                                         sbIntVec = sbIntVectors[sbInterrupt];\r
2053                                                 }\r
2054                                                 else\r
2055                                                         Quit("SD_Startup: Unsupported interrupt value in BLASTER");\r
2056                                                 break;\r
2057                                         case 'D':\r
2058                                                 temp = strtol(env + 1,&env,10);\r
2059                                                 if ((temp == 0) || (temp == 1) || (temp == 3))\r
2060                                                         SDL_SBSetDMA(temp);\r
2061                                                 else\r
2062                                                         Quit("SD_Startup: Unsupported DMA value in BLASTER");\r
2063                                                 break;\r
2064                                         default:\r
2065                                                 while (isspace(*env))\r
2066                                                         env++;\r
2067                                                 while (*env && !isspace(*env))\r
2068                                                         env++;\r
2069                                                 break;\r
2070                                         }\r
2071                                 }\r
2072                         }\r
2073                         SoundBlasterPresent = SDL_DetectSoundBlaster(port);\r
2074                 }\r
2075         }\r
2076 \r
2077         for (i = 0;i < 255;i++)\r
2078                 pcSoundLookup[i] = i * 60;\r
2079 \r
2080         if (SoundBlasterPresent)\r
2081                 SDL_StartSB();\r
2082 \r
2083         SDL_SetupDigi();\r
2084 \r
2085         SD_Started = true;\r
2086 }\r
2087 \r
2088 ///////////////////////////////////////////////////////////////////////////\r
2089 //\r
2090 //      SD_Default() - Sets up the default behaviour for the Sound Mgr whether\r
2091 //              the config file was present or not.\r
2092 //\r
2093 ///////////////////////////////////////////////////////////////////////////\r
2094 void\r
2095 SD_Default(boolean gotit,SDMode sd,SMMode sm)\r
2096 {\r
2097         boolean gotsd,gotsm;\r
2098 \r
2099         gotsd = gotsm = gotit;\r
2100 \r
2101         if (gotsd)      // Make sure requested sound hardware is available\r
2102         {\r
2103                 switch (sd)\r
2104                 {\r
2105                 case sdm_AdLib:\r
2106                         gotsd = AdLibPresent;\r
2107                         break;\r
2108                 }\r
2109         }\r
2110         if (!gotsd)\r
2111         {\r
2112                 if (AdLibPresent)\r
2113                         sd = sdm_AdLib;\r
2114                 else\r
2115                         sd = sdm_PC;\r
2116         }\r
2117         if (sd != SoundMode)\r
2118                 SD_SetSoundMode(sd);\r
2119 \r
2120 \r
2121         if (gotsm)      // Make sure requested music hardware is available\r
2122         {\r
2123                 switch (sm)\r
2124                 {\r
2125                 case sdm_AdLib:\r
2126                         gotsm = AdLibPresent;\r
2127                         break;\r
2128                 }\r
2129         }\r
2130         if (!gotsm)\r
2131         {\r
2132                 if (AdLibPresent)\r
2133                         sm = smm_AdLib;\r
2134         }\r
2135         if (sm != MusicMode)\r
2136                 SD_SetMusicMode(sm);\r
2137 }\r
2138 \r
2139 ///////////////////////////////////////////////////////////////////////////\r
2140 //\r
2141 //      SD_Shutdown() - shuts down the Sound Mgr\r
2142 //              Removes sound ISR and turns off whatever sound hardware was active\r
2143 //\r
2144 ///////////////////////////////////////////////////////////////////////////\r
2145 void\r
2146 SD_Shutdown(void)\r
2147 {\r
2148         if (!SD_Started)\r
2149                 return;\r
2150 \r
2151         SD_MusicOff();\r
2152         SD_StopSound();\r
2153         SDL_ShutDevice();\r
2154         SDL_CleanDevice();\r
2155 \r
2156         if (SoundBlasterPresent)\r
2157                 SDL_ShutSB();\r
2158 \r
2159         if (SoundSourcePresent)\r
2160                 SDL_ShutSS();\r
2161 \r
2162         asm     pushf\r
2163         asm     cli\r
2164 \r
2165         SDL_SetTimer0(0);\r
2166 \r
2167         setvect(8,t0OldService);\r
2168 \r
2169         asm     popf\r
2170 \r
2171         SD_Started = false;\r
2172 }\r
2173 \r
2174 ///////////////////////////////////////////////////////////////////////////\r
2175 //\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
2178 //\r
2179 ///////////////////////////////////////////////////////////////////////////\r
2180 void\r
2181 SD_SetUserHook(void (* hook)(void))\r
2182 {\r
2183         SoundUserHook = hook;\r
2184 }\r
2185 \r
2186 ///////////////////////////////////////////////////////////////////////////\r
2187 //\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
2190 //\r
2191 ///////////////////////////////////////////////////////////////////////////\r
2192 void\r
2193 SD_PositionSound(int leftvol,int rightvol)\r
2194 {\r
2195         LeftPosition = leftvol;\r
2196         RightPosition = rightvol;\r
2197         nextsoundpos = true;\r
2198 }\r
2199 \r
2200 ///////////////////////////////////////////////////////////////////////////\r
2201 //\r
2202 //      SD_PlaySound() - plays the specified sound on the appropriate hardware\r
2203 //\r
2204 ///////////////////////////////////////////////////////////////////////////\r
2205 boolean\r
2206 SD_PlaySound(soundnames sound)\r
2207 {\r
2208         boolean         ispos;\r
2209         SoundCommon     far *s;\r
2210         int     lp,rp;\r
2211 \r
2212         lp = LeftPosition;\r
2213         rp = RightPosition;\r
2214         LeftPosition = 0;\r
2215         RightPosition = 0;\r
2216 \r
2217         ispos = nextsoundpos;\r
2218         nextsoundpos = false;\r
2219 \r
2220         if (sound == -1)\r
2221                 return(false);\r
2222 \r
2223         s = MK_FP(SoundTable[sound],0);\r
2224         if ((SoundMode != sdm_Off) && !s)\r
2225                 Quit("SD_PlaySound() - Uncached sound");\r
2226 \r
2227         if ((DigiMode != sds_Off) && (DigiMap[sound] != -1))\r
2228         {\r
2229                 if ((DigiMode == sds_PC) && (SoundMode == sdm_PC))\r
2230                 {\r
2231                         if (s->priority < SoundPriority)\r
2232                                 return(false);\r
2233 \r
2234                         SDL_PCStopSound();\r
2235 \r
2236                         SD_PlayDigitized(DigiMap[sound],lp,rp);\r
2237                         SoundPositioned = ispos;\r
2238                         SoundNumber = sound;\r
2239                         SoundPriority = s->priority;\r
2240                 }\r
2241                 else\r
2242                 {\r
2243                 asm     pushf\r
2244                 asm     cli\r
2245                         if (DigiPriority && !DigiNumber)\r
2246                         {\r
2247                         asm     popf\r
2248                                 Quit("SD_PlaySound: Priority without a sound");\r
2249                         }\r
2250                 asm     popf\r
2251 \r
2252                         if (s->priority < DigiPriority)\r
2253                                 return(false);\r
2254 \r
2255                         SD_PlayDigitized(DigiMap[sound],lp,rp);\r
2256                         SoundPositioned = ispos;\r
2257                         DigiNumber = sound;\r
2258                         DigiPriority = s->priority;\r
2259                 }\r
2260 \r
2261                 return(true);\r
2262         }\r
2263 \r
2264         if (SoundMode == sdm_Off)\r
2265                 return(false);\r
2266         if (!s->length)\r
2267                 Quit("SD_PlaySound() - Zero length sound");\r
2268         if (s->priority < SoundPriority)\r
2269                 return(false);\r
2270 \r
2271         switch (SoundMode)\r
2272         {\r
2273         case sdm_PC:\r
2274                 SDL_PCPlaySound((void far *)s);\r
2275                 break;\r
2276         case sdm_AdLib:\r
2277                 SDL_ALPlaySound((void far *)s);\r
2278                 break;\r
2279         }\r
2280 \r
2281         SoundNumber = sound;\r
2282         SoundPriority = s->priority;\r
2283 \r
2284         return(false);\r
2285 }\r
2286 \r
2287 ///////////////////////////////////////////////////////////////////////////\r
2288 //\r
2289 //      SD_SoundPlaying() - returns the sound number that's playing, or 0 if\r
2290 //              no sound is playing\r
2291 //\r
2292 ///////////////////////////////////////////////////////////////////////////\r
2293 word\r
2294 SD_SoundPlaying(void)\r
2295 {\r
2296         boolean result = false;\r
2297 \r
2298         switch (SoundMode)\r
2299         {\r
2300         case sdm_PC:\r
2301                 result = pcSound? true : false;\r
2302                 break;\r
2303         case sdm_AdLib:\r
2304                 result = alSound? true : false;\r
2305                 break;\r
2306         }\r
2307 \r
2308         if (result)\r
2309                 return(SoundNumber);\r
2310         else\r
2311                 return(false);\r
2312 }\r
2313 \r
2314 ///////////////////////////////////////////////////////////////////////////\r
2315 //\r
2316 //      SD_StopSound() - if a sound is playing, stops it\r
2317 //\r
2318 ///////////////////////////////////////////////////////////////////////////\r
2319 void\r
2320 SD_StopSound(void)\r
2321 {\r
2322         if (DigiPlaying)\r
2323                 SD_StopDigitized();\r
2324 \r
2325         switch (SoundMode)\r
2326         {\r
2327         case sdm_PC:\r
2328                 SDL_PCStopSound();\r
2329                 break;\r
2330         case sdm_AdLib:\r
2331                 SDL_ALStopSound();\r
2332                 break;\r
2333         }\r
2334 \r
2335         SoundPositioned = false;\r
2336 \r
2337         SDL_SoundFinished();\r
2338 }\r
2339 \r
2340 ///////////////////////////////////////////////////////////////////////////\r
2341 //\r
2342 //      SD_WaitSoundDone() - waits until the current sound is done playing\r
2343 //\r
2344 ///////////////////////////////////////////////////////////////////////////\r
2345 void\r
2346 SD_WaitSoundDone(void)\r
2347 {\r
2348         while (SD_SoundPlaying())\r
2349                 ;\r
2350 }\r
2351 \r
2352 ///////////////////////////////////////////////////////////////////////////\r
2353 //\r
2354 //      SD_MusicOn() - turns on the sequencer\r
2355 //\r
2356 ///////////////////////////////////////////////////////////////////////////\r
2357 void\r
2358 SD_MusicOn(void)\r
2359 {\r
2360         sqActive = true;\r
2361 }\r
2362 \r
2363 ///////////////////////////////////////////////////////////////////////////\r
2364 //\r
2365 //      SD_MusicOff() - turns off the sequencer and any playing notes\r
2366 //\r
2367 ///////////////////////////////////////////////////////////////////////////\r
2368 void\r
2369 SD_MusicOff(void)\r
2370 {\r
2371         word    i;\r
2372 \r
2373 \r
2374         switch (MusicMode)\r
2375         {\r
2376         case smm_AdLib:\r
2377                 alFXReg = 0;\r
2378                 alOut(alEffects,0);\r
2379                 for (i = 0;i < sqMaxTracks;i++)\r
2380                         alOut(alFreqH + i + 1,0);\r
2381                 break;\r
2382         }\r
2383         sqActive = false;\r
2384 }\r
2385 \r
2386 ///////////////////////////////////////////////////////////////////////////\r
2387 //\r
2388 //      SD_StartMusic() - starts playing the music pointed to\r
2389 //\r
2390 ///////////////////////////////////////////////////////////////////////////\r
2391 void\r
2392 SD_StartMusic(MusicGroup far *music)\r
2393 {\r
2394         SD_MusicOff();\r
2395 asm     pushf\r
2396 asm     cli\r
2397 \r
2398         if (MusicMode == smm_AdLib)\r
2399         {\r
2400                 sqHackPtr = sqHack = music->values;\r
2401                 sqHackSeqLen = sqHackLen = music->length;\r
2402                 sqHackTime = 0;\r
2403                 alTimeCount = 0;\r
2404                 SD_MusicOn();\r
2405         }\r
2406 \r
2407 asm     popf\r
2408 }\r
2409 \r
2410 ///////////////////////////////////////////////////////////////////////////\r
2411 //\r
2412 //      SD_FadeOutMusic() - starts fading out the music. Call SD_MusicPlaying()\r
2413 //              to see if the fadeout is complete\r
2414 //\r
2415 ///////////////////////////////////////////////////////////////////////////\r
2416 void\r
2417 SD_FadeOutMusic(void)\r
2418 {\r
2419         switch (MusicMode)\r
2420         {\r
2421         case smm_AdLib:\r
2422                 // DEBUG - quick hack to turn the music off\r
2423                 SD_MusicOff();\r
2424                 break;\r
2425         }\r
2426 }\r
2427 \r
2428 ///////////////////////////////////////////////////////////////////////////\r
2429 //\r
2430 //      SD_MusicPlaying() - returns true if music is currently playing, false if\r
2431 //              not\r
2432 //\r
2433 ///////////////////////////////////////////////////////////////////////////\r
2434 boolean\r
2435 SD_MusicPlaying(void)\r
2436 {\r
2437         boolean result;\r
2438 \r
2439         switch (MusicMode)\r
2440         {\r
2441         case smm_AdLib:\r
2442                 result = false;\r
2443                 // DEBUG - not written\r
2444                 break;\r
2445         default:\r
2446                 result = false;\r
2447         }\r
2448 \r
2449         return(result);\r
2450 }\r
2451 \r
2452 // SD ASS!\r
2453 void SDL_SetDS()\r
2454 {\r
2455         __asm {\r
2456                 mov     ax,ds\r
2457                 mov     [cs:MyDS],ds\r
2458                 ret\r
2459         }\r
2460 }\r
2461 \r
2462 void SDL_turnOnPCSpeaker(word timerval)\r
2463 {\r
2464         __asm {\r
2465                 mov     bx,timerval\r
2466                 mov     al,0b6h\r
2467                 out     43h,al\r
2468                 mov     al,bl\r
2469                 out     42h,al\r
2470                 mov     al,bh\r
2471                 out     42h,al\r
2472                 in      al,61h\r
2473                 or      al,3\r
2474                 out     61h,al\r
2475         }\r
2476 }\r
2477 \r
2478 void SDL_turnOffPCSpeaker()\r
2479 {\r
2480         __asm {\r
2481                 in      al,61h\r
2482                 and     al,0fch\r
2483                 out     61h,al\r
2484         }\r
2485 }\r
2486 \r
2487 void SDL_setPCSpeaker(byte val)\r
2488 {\r
2489         __asm {\r
2490                 mov     al,val\r
2491                 in      al,61h\r
2492                 and     al,0fch\r
2493                 or      al,ah\r
2494                 out     61h,al\r
2495         }\r
2496 }\r
2497 \r
2498 void SDL_DoFX()\r
2499 {\r
2500         if(pcSound)\r
2501         {\r
2502                 if(*pcSound!=pcLastSample)\r
2503                 {\r
2504                         pcLastSample=*pcSound;\r
2505 \r
2506                         if(pcLastSample)\r
2507                                 SDL_turnOnPCSpeaker(pcLastSample*60);\r
2508                         else\r
2509                                 SDL_turnOffPCSpeaker();\r
2510                 }\r
2511                 pcSound++;\r
2512                 pcLengthLeft--;\r
2513                 if(!pcLengthLeft)\r
2514                 {\r
2515                         pcSound=0;\r
2516                         SoundNumber=(soundnames)0;\r
2517                         SoundPriority=0;\r
2518                         SDL_turnOffPCSpeaker();\r
2519                 }\r
2520         }\r
2521 \r
2522         if(alSound && !alNoIRQ)\r
2523         {\r
2524                 if(*alSound)\r
2525                 {\r
2526                         alOutInIRQ(alFreqL,*alSound);\r
2527                         alOutInIRQ(alFreqH,alBlock);\r
2528                 }\r
2529                 else alOutInIRQ(alFreqH,0);\r
2530                 alSound++;\r
2531                 alLengthLeft--;\r
2532                 if(!alLengthLeft)\r
2533                 {\r
2534                         alSound=0;\r
2535                         SoundNumber=(soundnames)0;\r
2536                         SoundPriority=0;\r
2537                         alOutInIRQ(alFreqH,0);\r
2538                 }\r
2539         }\r
2540 \r
2541 }\r
2542 \r
2543 void SDL_DoFast()\r
2544 {\r
2545         count_fx++;\r
2546         if(count_fx>=5)\r
2547         {\r
2548                 count_fx=0;\r
2549 \r
2550                 SDL_DoFX();\r
2551 \r
2552                 count_time++;\r
2553                 if(count_time>=2)\r
2554                 {\r
2555                         TimeCount++;\r
2556                         count_time=0;\r
2557                 }\r
2558         }\r
2559 \r
2560         if(sqActive && !alNoIRQ)\r
2561         {\r
2562                 if(sqHackLen)\r
2563                 {\r
2564                         do\r
2565                         {\r
2566                                 if(sqHackTime>alTimeCount) break;\r
2567                                 sqHackTime=alTimeCount+*(sqHackPtr+1);\r
2568                                 alOutInIRQ(*(byte *)sqHackPtr,*(((byte *)sqHackPtr)+1));\r
2569                                 sqHackPtr+=2;\r
2570                                 sqHackLen-=4;\r
2571                         }\r
2572                         while(sqHackLen);\r
2573                 }\r
2574                 alTimeCount++;\r
2575                 if(!sqHackLen)\r
2576                 {\r
2577                         sqHackPtr=sqHack;\r
2578                         sqHackLen=sqHackSeqLen;\r
2579                         alTimeCount=0;\r
2580                         sqHackTime=0;\r
2581                 }\r
2582         }\r
2583 \r
2584         if(ssSample)\r
2585         {\r
2586                 if(!(inp(ssStatus)&0x40))\r
2587                 {\r
2588                         outp(ssData,*ssSample++);\r
2589                         outp(ssControl,ssOff);\r
2590                         __asm push ax\r
2591                         __asm pop ax\r
2592                         outp(ssControl,ssOn);\r
2593                         __asm push ax\r
2594                         __asm pop ax\r
2595                         ssLengthLeft--;\r
2596                         if(!ssLengthLeft)\r
2597                         {\r
2598                                 ssSample=0;\r
2599                                 SDL_DigitizedDoneInIRQ();\r
2600                         }\r
2601                 }\r
2602         }\r
2603 \r
2604         TimerCount+=TimerDivisor;\r
2605         if(*((word *)&TimerCount+1))\r
2606         {\r
2607                 *((word *)&TimerCount+1)=0;\r
2608                 t0OldService();\r
2609         }\r
2610         else\r
2611         {\r
2612                 outp(0x20,0x20);\r
2613         }\r
2614 }\r
2615 \r
2616 // Timer 0 ISR for 7000Hz interrupts\r
2617 void interrupt SDL_t0ExtremeAsmService(void)\r
2618 {\r
2619         if(pcindicate)\r
2620         {\r
2621                 if(pcSound)\r
2622                 {\r
2623                         SDL_setPCSpeaker(((*pcSound++)&0x80)>>6);\r
2624                         pcLengthLeft--;\r
2625                         if(!pcLengthLeft)\r
2626                         {\r
2627                                 pcSound=0;\r
2628                                 SDL_turnOffPCSpeaker();\r
2629                                 SDL_DigitizedDoneInIRQ();\r
2630                         }\r
2631                 }\r
2632         }\r
2633         extreme++;\r
2634         if(extreme>=10)\r
2635         {\r
2636                 extreme=0;\r
2637                 SDL_DoFast();\r
2638         }\r
2639         else\r
2640                 outp(0x20,0x20);\r
2641 }\r
2642 \r
2643 // Timer 0 ISR for 7000Hz interrupts\r
2644 void interrupt __SDL_t0ExtremeAsmService()\r
2645 {\r
2646         if(pcindicate)\r
2647         {\r
2648                 if(pcSound)\r
2649                 {\r
2650                         SDL_setPCSpeaker(((*pcSound++)&0x80)>>6);\r
2651                         pcLengthLeft--;\r
2652                         if(!pcLengthLeft)\r
2653                         {\r
2654                                 pcSound=0;\r
2655                                 SDL_turnOffPCSpeaker();\r
2656                                 SDL_DigitizedDoneInIRQ();\r
2657                         }\r
2658                 }\r
2659         }\r
2660         extreme++;\r
2661         if(extreme>=10)\r
2662         {\r
2663                 extreme=0;\r
2664                 SDL_DoFast();\r
2665         }\r
2666         else\r
2667                 outp(0x20,0x20);\r
2668 }\r
2669 \r
2670 // Timer 0 ISR for 700Hz interrupts\r
2671 void interrupt SDL_t0FastAsmService(void)\r
2672 {\r
2673         SDL_DoFast();\r
2674 }\r
2675 \r
2676 // Timer 0 ISR for 140Hz interrupts\r
2677 void interrupt SDL_t0SlowAsmService(void)\r
2678 {\r
2679         count_time++;\r
2680         if(count_time>=2)\r
2681         {\r
2682                 TimeCount++;\r
2683                 count_time=0;\r
2684         }\r
2685 \r
2686         SDL_DoFX();\r
2687 \r
2688         TimerCount+=TimerDivisor;\r
2689         if(*((word *)&TimerCount+1))\r
2690         {\r
2691                 *((word *)&TimerCount+1)=0;\r
2692                 t0OldService();\r
2693         }\r
2694         else\r
2695                 outp(0x20,0x20);\r
2696 }\r
2697 \r
2698 void SDL_IndicatePC(boolean ind)\r
2699 {\r
2700         pcindicate=ind;\r
2701 }\r
2702 \r
2703 void\r
2704 SDL_DigitizedDoneInIRQ(void)\r
2705 {\r
2706         if (DigiNextAddr)\r
2707         {\r
2708                 SDL_PlayDigiSegment(DigiNextAddr,DigiNextLen/*,true*/);\r
2709                 DigiNextAddr = nil;\r
2710                 DigiMissed = false;\r
2711         }\r
2712         else\r
2713         {\r
2714                 if (DigiLastSegment)\r
2715                 {\r
2716                         DigiPlaying = false;\r
2717                         DigiLastSegment = false;\r
2718                         if ((DigiMode == sds_PC) && (SoundMode == sdm_PC))\r
2719                         {\r
2720                                 SDL_SoundFinished();\r
2721                         }\r
2722                         else\r
2723                         {\r
2724                                 DigiNumber = (soundnames) 0;\r
2725                                 DigiPriority = 0;\r
2726                         }\r
2727                         SoundPositioned = false;\r
2728                 }\r
2729                 else\r
2730                         DigiMissed = true;\r
2731         }\r
2732 }\r
2733 \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
2737 \r
2738 //static\r
2739 void alOutInIRQ(byte n,byte b)\r
2740 {\r
2741         __asm {\r
2742                 mov     dx,0x388\r
2743                 mov     al,[n]\r
2744                 out     dx,al\r
2745                 in      al,dx\r
2746                 in      al,dx\r
2747                 in      al,dx\r
2748                 in      al,dx\r
2749                 in      al,dx\r
2750                 in      al,dx\r
2751                 inc     dx\r
2752                 mov     al,[b]\r
2753                 out     dx,al\r
2754 \r
2755                 dec     dx\r
2756                 in      al,dx\r
2757                 in      al,dx\r
2758                 in      al,dx\r
2759                 in      al,dx\r
2760                 in      al,dx\r
2761                 in      al,dx\r
2762                 in      al,dx\r
2763                 in      al,dx\r
2764                 in      al,dx\r
2765                 in      al,dx\r
2766 \r
2767                 in      al,dx\r
2768                 in      al,dx\r
2769                 in      al,dx\r
2770                 in      al,dx\r
2771                 in      al,dx\r
2772                 in      al,dx\r
2773                 in      al,dx\r
2774                 in      al,dx\r
2775                 in      al,dx\r
2776                 in      al,dx\r
2777 \r
2778                 in      al,dx\r
2779                 in      al,dx\r
2780                 in      al,dx\r
2781                 in      al,dx\r
2782                 in      al,dx\r
2783                 in      al,dx\r
2784                 in      al,dx\r
2785                 in      al,dx\r
2786                 in      al,dx\r
2787                 in      al,dx\r
2788 \r
2789                 in      al,dx\r
2790                 in      al,dx\r
2791                 in      al,dx\r
2792                 in      al,dx\r
2793                 in      al,dx\r
2794         }\r
2795 }\r
2796 \r