]> 4ch.mooo.com Git - 16.git/blob - 16/ID_SD.C
porting and tweaking sd more i added a cuted code file and a xxdiff friendlyer versio...
[16.git] / 16 / ID_SD.C
1 /* Catacomb 3-D Source Code\r
2  * Copyright (C) 1993-2014 Flat Rock Software\r
3  *\r
4  * This program is free software; you can redistribute it and/or modify\r
5  * it under the terms of the GNU General Public License as published by\r
6  * the Free Software Foundation; either version 2 of the License, or\r
7  * (at your option) any later version.\r
8  *\r
9  * This program is distributed in the hope that it will be useful,\r
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
12  * GNU General Public License for more details.\r
13  *\r
14  * You should have received a copy of the GNU General Public License along\r
15  * with this program; if not, write to the Free Software Foundation, Inc.,\r
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
17  */\r
18 \r
19 //\r
20 //      ID Engine\r
21 //      ID_SD.c - Sound Manager\r
22 //      v1.1d1\r
23 //      By Jason Blochowiak\r
24 //\r
25 \r
26 //\r
27 //      This module handles dealing with generating sound on the appropriate\r
28 //              hardware\r
29 //\r
30 //      Depends on: User Mgr (for parm checking)\r
31 //\r
32 //      Globals:\r
33 //              For User Mgr:\r
34 //                      SoundSourcePresent - Sound Source thingie present?\r
35 //                      SoundBlasterPresent - SoundBlaster card present?\r
36 //                      AdLibPresent - AdLib card present?\r
37 //                      SoundMode - What device is used for sound effects\r
38 //                              (Use SM_SetSoundMode() to set)\r
39 //                      MusicMode - What device is used for music\r
40 //                              (Use SM_SetMusicMode() to set)\r
41 //              For Cache Mgr:\r
42 //                      NeedsDigitized - load digitized sounds?\r
43 //                      NeedsMusic - load music?\r
44 //\r
45 \r
46 #pragma hdrstop         // Wierdo thing with MUSE\r
47 \r
48 #include <dos.h>\r
49 \r
50 #ifdef  _MUSE_      // Will be defined in ID_Types.h\r
51 #include "ID_SD.h"\r
52 #else\r
53 #include "ID_HEADS.H"\r
54 #endif\r
55 #pragma hdrstop\r
56 #pragma warn    -pia\r
57 \r
58 #define SDL_SoundFinished()     {SoundNumber = SoundPriority = 0;}\r
59 \r
60 // Macros for AdLib stuff\r
61 #define selreg(n)       outportb(alFMAddr,n)\r
62 #define writereg(n)     outportb(alFMData,n)\r
63 #define readstat()      inportb(alFMStatus)\r
64 \r
65 //      Global variables\r
66         boolean         SoundSourcePresent,SoundBlasterPresent,AdLibPresent,\r
67                                 NeedsDigitized,NeedsMusic;\r
68         SDMode          SoundMode;\r
69         SMMode          MusicMode;\r
70         dword   TimeCount;\r
71         word            HackCount;\r
72         word            *SoundTable;    // Really * _seg *SoundTable, but that don't work\r
73         boolean         ssIsTandy;\r
74         word            ssPort = 2;\r
75 \r
76 //      Internal variables\r
77 static  boolean                 SD_Started;\r
78                 boolean                 TimerDone;\r
79                 word                    TimerVal,TimerDelay10,TimerDelay25,TimerDelay100;\r
80                 dword           TimerDivisor,TimerCount;\r
81 static  char                    *ParmStrings[] =\r
82                                                 {\r
83                                                         "noal",\r
84                                                         nil\r
85                                                 };\r
86 static  void                    (*SoundUserHook)(void);\r
87                 word                    SoundNumber,SoundPriority;\r
88                 void interrupt  (*t0OldService)(void);\r
89 //              word                    t0CountTable[] = {8,8,8,8,40,40};\r
90                 long                    LocalTime;\r
91 \r
92 //      PC Sound variables\r
93                 volatile byte                   pcLastSample,far *pcSound;\r
94                 dword           pcLengthLeft;\r
95                 word                    pcSoundLookup[255];\r
96 \r
97 //      AdLib variables\r
98                 boolean                 alNoCheck;\r
99                 byte                    far *alSound;\r
100                 word                    alBlock;\r
101                 dword           alLengthLeft;\r
102                 dword           alTimeCount;\r
103                 Instrument              alZeroInst;\r
104 \r
105 // This table maps channel numbers to carrier and modulator op cells\r
106 static  byte                    carriers[9] =  { 3, 4, 5,11,12,13,19,20,21},\r
107                                                 modifiers[9] = { 0, 1, 2, 8, 9,10,16,17,18},\r
108 // This table maps percussive voice numbers to op cells\r
109                                                 pcarriers[5] = {19,0xff,0xff,0xff,0xff},\r
110                                                 pmodifiers[5] = {16,17,18,20,21};\r
111 \r
112 //      Sequencer variables\r
113                 boolean                 sqActive;\r
114 static  word                    alFXReg;\r
115 static  ActiveTrack             *tracks[sqMaxTracks],\r
116                                                 mytracks[sqMaxTracks];\r
117 static  word                    sqMode,sqFadeStep;\r
118                 word                    far *sqHack,far *sqHackPtr,sqHackLen,sqHackSeqLen;\r
119                 long                    sqHackTime;\r
120 \r
121 //      Internal routines\r
122 \r
123 ///////////////////////////////////////////////////////////////////////////\r
124 //\r
125 //      SDL_SetTimer0() - Sets system timer 0 to the specified speed\r
126 //\r
127 ///////////////////////////////////////////////////////////////////////////\r
128 #pragma argsused\r
129 static void\r
130 SDL_SetTimer0(word speed)\r
131 {\r
132 #ifndef TPROF   // If using Borland's profiling, don't screw with the timer\r
133         outportb(0x43,0x36);                            // Change timer 0\r
134         outportb(0x40,speed);\r
135         outportb(0x40,speed >> 8);\r
136         TimerDivisor = speed;\r
137 #else\r
138         TimerDivisor = 0x10000;\r
139 #endif\r
140 }\r
141 \r
142 ///////////////////////////////////////////////////////////////////////////\r
143 //\r
144 //      SDL_SetIntsPerSec() - Uses SDL_SetTimer0() to set the number of\r
145 //              interrupts generated by system timer 0 per second\r
146 //\r
147 ///////////////////////////////////////////////////////////////////////////\r
148 static void\r
149 SDL_SetIntsPerSec(word ints)\r
150 {\r
151         SDL_SetTimer0(1192030 / ints);\r
152 }\r
153 \r
154 ///////////////////////////////////////////////////////////////////////////\r
155 //\r
156 //      SDL_TimingService() - Used by SDL_InitDelay() to determine a timing\r
157 //              value for the current system that we're running on\r
158 //\r
159 ///////////////////////////////////////////////////////////////////////////\r
160 static void interrupt\r
161 SDL_TimingService(void)\r
162 {\r
163         TimerVal = _CX;\r
164         TimerDone++;\r
165 \r
166         outportb(0x20,0x20);                            // Ack interrupt\r
167 }\r
168 \r
169 ///////////////////////////////////////////////////////////////////////////\r
170 //\r
171 //      SDL_InitDelay() - Sets up TimerDelay's for SDL_Delay()\r
172 //\r
173 ///////////////////////////////////////////////////////////////////////////\r
174 static void\r
175 SDL_InitDelay(void)\r
176 {\r
177         int             i;\r
178         word    timer;\r
179 \r
180         setvect(8,SDL_TimingService);           // Set to my timer 0 ISR\r
181 \r
182         SDL_SetIntsPerSec(1000);                        // Time 1ms\r
183 \r
184         for (i = 0,timer = 0;i < 10;i++)        // Do timing test 10 times\r
185         {\r
186         asm     xor             dx,dx                                   // Zero DX\r
187         asm     mov             cx,0xffff                               // Put starting value in CX\r
188         asm     mov             [TimerDone],cx                  // TimerDone = false - 1\r
189 startloop:\r
190         asm     or              [TimerDone],0\r
191         asm     jnz             startloop                               // Make sure we're at the start\r
192 loop:\r
193         asm     test    [TimerDone],1                   // See if TimerDone flag got hit\r
194         asm     jnz             done                                    // Yep - drop out of the loop\r
195         asm     loop    loop\r
196 done:\r
197 \r
198                 if (0xffff - TimerVal > timer)\r
199                         timer = 0xffff - TimerVal;\r
200         }\r
201         timer += timer / 2;                                     // Use some slop\r
202         TimerDelay10 =  timer / (1000 / 10);\r
203         TimerDelay25 =  timer / (1000 / 25);\r
204         TimerDelay100 = timer / (1000 / 100);\r
205 \r
206         SDL_SetTimer0(0);                                       // Reset timer 0\r
207 \r
208         setvect(8,t0OldService);                        // Set back to old ISR\r
209 }\r
210 \r
211 ///////////////////////////////////////////////////////////////////////////\r
212 //\r
213 //      SDL_Delay() - Delays the specified amount of time\r
214 //\r
215 ///////////////////////////////////////////////////////////////////////////\r
216 static void\r
217 SDL_Delay(word delay)\r
218 {\r
219         if (!delay)\r
220                 return;\r
221 \r
222 asm     mov             cx,[delay]\r
223 loop:\r
224 asm     test    [TimerDone],0   // Useless code - just for timing equivilency\r
225 asm     jnz             done\r
226 asm     loop    loop\r
227 done:;\r
228 }\r
229 \r
230 //\r
231 //      PC Sound code\r
232 //\r
233 \r
234 ///////////////////////////////////////////////////////////////////////////\r
235 //\r
236 //      SDL_PCPlaySound() - Plays the specified sound on the PC speaker\r
237 //\r
238 ///////////////////////////////////////////////////////////////////////////\r
239 #ifdef  _MUSE_\r
240 void\r
241 #else\r
242 static void\r
243 #endif\r
244 SDL_PCPlaySound(PCSound far *sound)\r
245 {\r
246 asm     pushf\r
247 asm     cli\r
248 \r
249         pcLastSample = -1;\r
250         pcLengthLeft = sound->common.length;\r
251         pcSound = sound->data;\r
252 \r
253 asm     popf\r
254 }\r
255 \r
256 ///////////////////////////////////////////////////////////////////////////\r
257 //\r
258 //      SDL_PCStopSound() - Stops the current sound playing on the PC Speaker\r
259 //\r
260 ///////////////////////////////////////////////////////////////////////////\r
261 #ifdef  _MUSE_\r
262 void\r
263 #else\r
264 static void\r
265 #endif\r
266 SDL_PCStopSound(void)\r
267 {\r
268 asm     pushf\r
269 asm     cli\r
270 \r
271         (long)pcSound = 0;\r
272 \r
273 asm     in      al,0x61                 // Turn the speaker off\r
274 asm     and     al,0xfd                 // ~2\r
275 asm     out     0x61,al\r
276 \r
277 asm     popf\r
278 }\r
279 \r
280 ///////////////////////////////////////////////////////////////////////////\r
281 //\r
282 //      SDL_PCService() - Handles playing the next sample in a PC sound\r
283 //\r
284 ///////////////////////////////////////////////////////////////////////////\r
285 static void\r
286 SDL_PCService(void)\r
287 {\r
288         byte    s;\r
289         word    t;\r
290 \r
291         if (pcSound)\r
292         {\r
293                 s = *pcSound++;\r
294                 if (s != pcLastSample)\r
295                 {\r
296                 asm     pushf\r
297                 asm     cli\r
298 \r
299                         pcLastSample = s;\r
300                         if (s)                                  // We have a frequency!\r
301                         {\r
302                                 t = pcSoundLookup[s];\r
303                         asm     mov     bx,[t]\r
304 \r
305                         asm     mov     al,0xb6                 // Write to channel 2 (speaker) timer\r
306                         asm     out     43h,al\r
307                         asm     mov     al,bl\r
308                         asm     out     42h,al                  // Low byte\r
309                         asm     mov     al,bh\r
310                         asm     out     42h,al                  // High byte\r
311 \r
312                         asm     in      al,0x61                 // Turn the speaker & gate on\r
313                         asm     or      al,3\r
314                         asm     out     0x61,al\r
315                         }\r
316                         else                                    // Time for some silence\r
317                         {\r
318                         asm     in      al,0x61                 // Turn the speaker & gate off\r
319                         asm     and     al,0xfc                 // ~3\r
320                         asm     out     0x61,al\r
321                         }\r
322 \r
323                 asm     popf\r
324                 }\r
325 \r
326                 if (!(--pcLengthLeft))\r
327                 {\r
328                         SDL_PCStopSound();\r
329                         SDL_SoundFinished();\r
330                 }\r
331         }\r
332 }\r
333 \r
334 ///////////////////////////////////////////////////////////////////////////\r
335 //\r
336 //      SDL_ShutPC() - Turns off the pc speaker\r
337 //\r
338 ///////////////////////////////////////////////////////////////////////////\r
339 static void\r
340 SDL_ShutPC(void)\r
341 {\r
342 asm     pushf\r
343 asm     cli\r
344 \r
345         pcSound = 0;\r
346 \r
347 asm     in      al,0x61                 // Turn the speaker & gate off\r
348 asm     and     al,0xfc                 // ~3\r
349 asm     out     0x61,al\r
350 \r
351 asm     popf\r
352 }\r
353 \r
354 //      AdLib Code\r
355 \r
356 ///////////////////////////////////////////////////////////////////////////\r
357 //\r
358 //      alOut(n,b) - Puts b in AdLib card register n\r
359 //\r
360 ///////////////////////////////////////////////////////////////////////////\r
361 void\r
362 alOut(byte n,byte b)\r
363 {\r
364 asm     pushf\r
365 asm     cli\r
366 \r
367 asm     mov             dx,0x388\r
368 asm     mov             al,[n]\r
369 asm     out             dx,al\r
370 #if 0\r
371         SDL_Delay(TimerDelay10);\r
372 #else\r
373 asm     in      al, dx\r
374 asm     in      al, dx\r
375 asm     in      al, dx\r
376 asm     in      al, dx\r
377 asm     in      al, dx\r
378 asm     in      al, dx\r
379 #endif\r
380 \r
381 asm     mov             dx,0x389\r
382 asm     mov             al,[b]\r
383 asm     out             dx,al\r
384 \r
385 asm     popf\r
386 \r
387 #if 0\r
388         SDL_Delay(TimerDelay25);\r
389 #else\r
390 asm     mov     dx,0x388\r
391 asm     in      al, dx\r
392 asm     in      al, dx\r
393 asm     in      al, dx\r
394 asm     in      al, dx\r
395 asm     in      al, dx\r
396 asm     in      al, dx\r
397 asm     in      al, dx\r
398 asm     in      al, dx\r
399 asm     in      al, dx\r
400 asm     in      al, dx\r
401 \r
402 asm     in      al, dx\r
403 asm     in      al, dx\r
404 asm     in      al, dx\r
405 asm     in      al, dx\r
406 asm     in      al, dx\r
407 asm     in      al, dx\r
408 asm     in      al, dx\r
409 asm     in      al, dx\r
410 asm     in      al, dx\r
411 asm     in      al, dx\r
412 \r
413 asm     in      al, dx\r
414 asm     in      al, dx\r
415 asm     in      al, dx\r
416 asm     in      al, dx\r
417 asm     in      al, dx\r
418 asm     in      al, dx\r
419 asm     in      al, dx\r
420 asm     in      al, dx\r
421 asm     in      al, dx\r
422 asm     in      al, dx\r
423 \r
424 asm     in      al, dx\r
425 asm     in      al, dx\r
426 asm     in      al, dx\r
427 asm     in      al, dx\r
428 asm     in      al, dx\r
429 #endif\r
430 }\r
431 \r
432 #if 0\r
433 ///////////////////////////////////////////////////////////////////////////\r
434 //\r
435 //      SDL_SetInstrument() - Puts an instrument into a generator\r
436 //\r
437 ///////////////////////////////////////////////////////////////////////////\r
438 static void\r
439 SDL_SetInstrument(int track,int which,Instrument far *inst,boolean percussive)\r
440 {\r
441         byte            c,m;\r
442 \r
443         if (percussive)\r
444         {\r
445                 c = pcarriers[which];\r
446                 m = pmodifiers[which];\r
447         }\r
448         else\r
449         {\r
450                 c = carriers[which];\r
451                 m = modifiers[which];\r
452         }\r
453 \r
454         tracks[track - 1]->inst = *inst;\r
455         tracks[track - 1]->percussive = percussive;\r
456 \r
457         alOut(m + alChar,inst->mChar);\r
458         alOut(m + alScale,inst->mScale);\r
459         alOut(m + alAttack,inst->mAttack);\r
460         alOut(m + alSus,inst->mSus);\r
461         alOut(m + alWave,inst->mWave);\r
462 \r
463         // Most percussive instruments only use one cell\r
464         if (c != 0xff)\r
465         {\r
466                 alOut(c + alChar,inst->cChar);\r
467                 alOut(c + alScale,inst->cScale);\r
468                 alOut(c + alAttack,inst->cAttack);\r
469                 alOut(c + alSus,inst->cSus);\r
470                 alOut(c + alWave,inst->cWave);\r
471         }\r
472 \r
473         alOut(which + alFeedCon,inst->nConn);   // DEBUG - I think this is right\r
474 }\r
475 #endif\r
476 \r
477 ///////////////////////////////////////////////////////////////////////////\r
478 //\r
479 //      SDL_ALStopSound() - Turns off any sound effects playing through the\r
480 //              AdLib card\r
481 //\r
482 ///////////////////////////////////////////////////////////////////////////\r
483 #ifdef  _MUSE_\r
484 void\r
485 #else\r
486 static void\r
487 #endif\r
488 SDL_ALStopSound(void)\r
489 {\r
490 asm     pushf\r
491 asm     cli\r
492 \r
493         (long)alSound = 0;\r
494         alOut(alFreqH + 0,0);\r
495 \r
496 asm     popf\r
497 }\r
498 \r
499 static void\r
500 SDL_AlSetFXInst(Instrument far *inst)\r
501 {\r
502         byte            c,m;\r
503 \r
504         m = modifiers[0];\r
505         c = carriers[0];\r
506         alOut(m + alChar,inst->mChar);\r
507         alOut(m + alScale,inst->mScale);\r
508         alOut(m + alAttack,inst->mAttack);\r
509         alOut(m + alSus,inst->mSus);\r
510         alOut(m + alWave,inst->mWave);\r
511         alOut(c + alChar,inst->cChar);\r
512         alOut(c + alScale,inst->cScale);\r
513         alOut(c + alAttack,inst->cAttack);\r
514         alOut(c + alSus,inst->cSus);\r
515         alOut(c + alWave,inst->cWave);\r
516         // DEBUG!!! - I just put this in\r
517 //      alOut(alFeedCon,inst->nConn);\r
518 }\r
519 \r
520 ///////////////////////////////////////////////////////////////////////////\r
521 //\r
522 //      SDL_ALPlaySound() - Plays the specified sound on the AdLib card\r
523 //\r
524 ///////////////////////////////////////////////////////////////////////////\r
525 #ifdef  _MUSE_\r
526 void\r
527 #else\r
528 static void\r
529 #endif\r
530 SDL_ALPlaySound(AdLibSound far *sound)\r
531 {\r
532         Instrument      far *inst;\r
533 \r
534         SDL_ALStopSound();\r
535 \r
536 asm     pushf\r
537 asm     cli\r
538 \r
539         alLengthLeft = sound->common.length;\r
540         alSound = sound->data;\r
541         alBlock = ((sound->block & 7) << 2) | 0x20;\r
542         inst = &sound->inst;\r
543 \r
544         if (!(inst->mSus | inst->cSus))\r
545         {\r
546         asm     popf\r
547                 Quit("SDL_ALPlaySound() - Bad instrument");\r
548         }\r
549 \r
550         SDL_AlSetFXInst(inst);\r
551 \r
552 asm     popf\r
553 }\r
554 \r
555 ///////////////////////////////////////////////////////////////////////////\r
556 //\r
557 //      SDL_ALSoundService() - Plays the next sample out through the AdLib card\r
558 //\r
559 ///////////////////////////////////////////////////////////////////////////\r
560 static void\r
561 SDL_ALSoundService(void)\r
562 {\r
563         byte    s;\r
564 \r
565         if (alSound)\r
566         {\r
567                 s = *alSound++;\r
568                 if (!s)\r
569                         alOut(alFreqH + 0,0);\r
570                 else\r
571                 {\r
572                         alOut(alFreqL + 0,s);\r
573                         alOut(alFreqH + 0,alBlock);\r
574                 }\r
575 \r
576                 if (!(--alLengthLeft))\r
577                 {\r
578                         (long)alSound = 0;\r
579                         alOut(alFreqH + 0,0);\r
580                         SDL_SoundFinished();\r
581                 }\r
582         }\r
583 }\r
584 \r
585 #if 0\r
586 ///////////////////////////////////////////////////////////////////////////\r
587 //\r
588 //      SDL_SelectMeasure() - sets up sequencing variables for a given track\r
589 //\r
590 ///////////////////////////////////////////////////////////////////////////\r
591 static void\r
592 SDL_SelectMeasure(ActiveTrack *track)\r
593 {\r
594         track->seq = track->moods[track->mood];\r
595         track->nextevent = 0;\r
596 }\r
597 #endif\r
598 \r
599 static void\r
600 SDL_ALService(void)\r
601 {\r
602         byte    a,v;\r
603         word    w;\r
604 \r
605         if (!sqActive)\r
606                 return;\r
607 \r
608         while (sqHackLen && (sqHackTime <= alTimeCount))\r
609         {\r
610                 w = *sqHackPtr++;\r
611                 sqHackTime = alTimeCount + *sqHackPtr++;\r
612         asm     mov     dx,[w]\r
613         asm     mov     [a],dl\r
614         asm     mov     [v],dh\r
615                 alOut(a,v);\r
616                 sqHackLen -= 4;\r
617         }\r
618         alTimeCount++;\r
619         if (!sqHackLen)\r
620         {\r
621                 sqHackPtr = (word far *)sqHack;\r
622                 sqHackLen = sqHackSeqLen;\r
623                 alTimeCount = sqHackTime = 0;\r
624         }\r
625 }\r
626 \r
627 ///////////////////////////////////////////////////////////////////////////\r
628 //\r
629 //      SDL_ShutAL() - Shuts down the AdLib card for sound effects\r
630 //\r
631 ///////////////////////////////////////////////////////////////////////////\r
632 static void\r
633 SDL_ShutAL(void)\r
634 {\r
635 asm     pushf\r
636 asm     cli\r
637 \r
638         alOut(alEffects,0);\r
639         alOut(alFreqH + 0,0);\r
640         SDL_AlSetFXInst(&alZeroInst);\r
641         alSound = 0;\r
642 \r
643 asm     popf\r
644 }\r
645 \r
646 ///////////////////////////////////////////////////////////////////////////\r
647 //\r
648 //      SDL_CleanAL() - Totally shuts down the AdLib card\r
649 //\r
650 ///////////////////////////////////////////////////////////////////////////\r
651 static void\r
652 SDL_CleanAL(void)\r
653 {\r
654         int     i;\r
655 \r
656 asm     pushf\r
657 asm     cli\r
658 \r
659         alOut(alEffects,0);\r
660         for (i = 1;i < 0xf5;i++)\r
661                 alOut(i,0);\r
662 \r
663 asm     popf\r
664 }\r
665 \r
666 ///////////////////////////////////////////////////////////////////////////\r
667 //\r
668 //      SDL_StartAL() - Starts up the AdLib card for sound effects\r
669 //\r
670 ///////////////////////////////////////////////////////////////////////////\r
671 static void\r
672 SDL_StartAL(void)\r
673 {\r
674         alFXReg = 0;\r
675         alOut(alEffects,alFXReg);\r
676         SDL_AlSetFXInst(&alZeroInst);\r
677 }\r
678 \r
679 ///////////////////////////////////////////////////////////////////////////\r
680 //\r
681 //      SDL_DetectAdLib() - Determines if there's an AdLib (or SoundBlaster\r
682 //              emulating an AdLib) present\r
683 //\r
684 ///////////////////////////////////////////////////////////////////////////\r
685 static boolean\r
686 SDL_DetectAdLib(void)\r
687 {\r
688         byte    status1,status2;\r
689         int             i;\r
690 \r
691         alOut(4,0x60);  // Reset T1 & T2\r
692         alOut(4,0x80);  // Reset IRQ\r
693         status1 = readstat();\r
694         alOut(2,0xff);  // Set timer 1\r
695         alOut(4,0x21);  // Start timer 1\r
696         SDL_Delay(TimerDelay100);\r
697 \r
698         status2 = readstat();\r
699         alOut(4,0x60);\r
700         alOut(4,0x80);\r
701 \r
702         if (((status1 & 0xe0) == 0x00) && ((status2 & 0xe0) == 0xc0))\r
703         {\r
704                 for (i = 1;i <= 0xf5;i++)       // Zero all the registers\r
705                         alOut(i,0);\r
706 \r
707                 alOut(1,0x20);  // Set WSE=1\r
708                 alOut(8,0);             // Set CSM=0 & SEL=0\r
709 \r
710                 return(true);\r
711         }\r
712         else\r
713                 return(false);\r
714 }\r
715 \r
716 ///////////////////////////////////////////////////////////////////////////\r
717 //\r
718 //      SDL_t0Service() - My timer 0 ISR which handles the different timings and\r
719 //              dispatches to whatever other routines are appropriate\r
720 //\r
721 ///////////////////////////////////////////////////////////////////////////\r
722 static void interrupt\r
723 SDL_t0Service(void)\r
724 {\r
725 static  word    count = 1;\r
726 \r
727 #if 0   // for debugging\r
728 asm     mov     dx,STATUS_REGISTER_1\r
729 asm     in      al,dx\r
730 asm     mov     dx,ATR_INDEX\r
731 asm     mov     al,ATR_OVERSCAN\r
732 asm     out     dx,al\r
733 asm     mov     al,4    // red\r
734 asm     out     dx,al\r
735 #endif\r
736 \r
737         HackCount++;\r
738 \r
739         if (MusicMode == smm_AdLib)\r
740         {\r
741                 SDL_ALService();\r
742                 if (!(++count & 7))\r
743                 {\r
744                         LocalTime++;\r
745                         TimeCount++;\r
746                         if (SoundUserHook)\r
747                                 SoundUserHook();\r
748                 }\r
749                 if (!(count & 3))\r
750                 {\r
751                         switch (SoundMode)\r
752                         {\r
753                         case sdm_PC:\r
754                                 SDL_PCService();\r
755                                 break;\r
756                         case sdm_AdLib:\r
757                                 SDL_ALSoundService();\r
758                                 break;\r
759                         }\r
760                 }\r
761         }\r
762         else\r
763         {\r
764                 if (!(++count & 1))\r
765                 {\r
766                         LocalTime++;\r
767                         TimeCount++;\r
768                         if (SoundUserHook)\r
769                                 SoundUserHook();\r
770                 }\r
771                 switch (SoundMode)\r
772                 {\r
773                 case sdm_PC:\r
774                         SDL_PCService();\r
775                         break;\r
776                 case sdm_AdLib:\r
777                         SDL_ALSoundService();\r
778                         break;\r
779                 }\r
780         }\r
781 \r
782 asm     mov     ax,[WORD PTR TimerCount]\r
783 asm     add     ax,[WORD PTR TimerDivisor]\r
784 asm     mov     [WORD PTR TimerCount],ax\r
785 asm     jnc     myack\r
786         t0OldService();                 // If we overflow a word, time to call old int handler\r
787 asm     jmp     olddone\r
788 myack:;\r
789         outportb(0x20,0x20);    // Ack the interrupt\r
790 olddone:;\r
791 \r
792 #if 0   // for debugging\r
793 asm     mov     dx,STATUS_REGISTER_1\r
794 asm     in      al,dx\r
795 asm     mov     dx,ATR_INDEX\r
796 asm     mov     al,ATR_OVERSCAN\r
797 asm     out     dx,al\r
798 asm     mov     al,3    // blue\r
799 asm     out     dx,al\r
800 asm     mov     al,0x20 // normal\r
801 asm     out     dx,al\r
802 #endif\r
803 }\r
804 \r
805 ////////////////////////////////////////////////////////////////////////////\r
806 //\r
807 //      SDL_ShutDevice() - turns off whatever device was being used for sound fx\r
808 //\r
809 ////////////////////////////////////////////////////////////////////////////\r
810 static void\r
811 SDL_ShutDevice(void)\r
812 {\r
813         switch (SoundMode)\r
814         {\r
815         case sdm_PC:\r
816                 SDL_ShutPC();\r
817                 break;\r
818         case sdm_AdLib:\r
819                 SDL_ShutAL();\r
820                 break;\r
821         }\r
822         SoundMode = sdm_Off;\r
823 }\r
824 \r
825 ///////////////////////////////////////////////////////////////////////////\r
826 //\r
827 //      SDL_CleanDevice() - totally shuts down all sound devices\r
828 //\r
829 ///////////////////////////////////////////////////////////////////////////\r
830 static void\r
831 SDL_CleanDevice(void)\r
832 {\r
833         if ((SoundMode == sdm_AdLib) || (MusicMode == smm_AdLib))\r
834                 SDL_CleanAL();\r
835 }\r
836 \r
837 ///////////////////////////////////////////////////////////////////////////\r
838 //\r
839 //      SDL_StartDevice() - turns on whatever device is to be used for sound fx\r
840 //\r
841 ///////////////////////////////////////////////////////////////////////////\r
842 static void\r
843 SDL_StartDevice(void)\r
844 {\r
845         switch (SoundMode)\r
846         {\r
847         case sdm_AdLib:\r
848                 SDL_StartAL();\r
849                 break;\r
850         }\r
851         SoundNumber = SoundPriority = 0;\r
852 }\r
853 \r
854 static void\r
855 SDL_SetTimerSpeed(void)\r
856 {\r
857         word    rate;\r
858 \r
859         if (MusicMode == smm_AdLib)\r
860                 rate = TickBase * 8;\r
861         else\r
862                 rate = TickBase * 2;\r
863         SDL_SetIntsPerSec(rate);\r
864 }\r
865 \r
866 //      Public routines\r
867 \r
868 ///////////////////////////////////////////////////////////////////////////\r
869 //\r
870 //      SD_SetSoundMode() - Sets which sound hardware to use for sound effects\r
871 //\r
872 ///////////////////////////////////////////////////////////////////////////\r
873 boolean\r
874 SD_SetSoundMode(SDMode mode)\r
875 {\r
876         boolean result;\r
877         word    tableoffset;\r
878 \r
879         SD_StopSound();\r
880 \r
881 #ifndef _MUSE_\r
882         switch (mode)\r
883         {\r
884         case sdm_Off:\r
885                 NeedsDigitized = false;\r
886                 result = true;\r
887                 break;\r
888         case sdm_PC:\r
889                 tableoffset = STARTPCSOUNDS;\r
890                 NeedsDigitized = false;\r
891                 result = true;\r
892                 break;\r
893         case sdm_AdLib:\r
894                 if (AdLibPresent)\r
895                 {\r
896                         tableoffset = STARTADLIBSOUNDS;\r
897                         NeedsDigitized = false;\r
898                         result = true;\r
899                 }\r
900                 break;\r
901         default:\r
902                 result = false;\r
903                 break;\r
904         }\r
905 #endif\r
906 \r
907         if (result && (mode != SoundMode))\r
908         {\r
909                 SDL_ShutDevice();\r
910                 SoundMode = mode;\r
911 #ifndef _MUSE_\r
912                 SoundTable = (word *)(&audiosegs[tableoffset]);\r
913 #endif\r
914                 SDL_StartDevice();\r
915         }\r
916 \r
917         SDL_SetTimerSpeed();\r
918 \r
919         return(result);\r
920 }\r
921 \r
922 ///////////////////////////////////////////////////////////////////////////\r
923 //\r
924 //      SD_SetMusicMode() - sets the device to use for background music\r
925 //\r
926 ///////////////////////////////////////////////////////////////////////////\r
927 boolean\r
928 SD_SetMusicMode(SMMode mode)\r
929 {\r
930         boolean result;\r
931 \r
932         SD_FadeOutMusic();\r
933         while (SD_MusicPlaying())\r
934                 ;\r
935 \r
936         switch (mode)\r
937         {\r
938         case smm_Off:\r
939                 NeedsMusic = false;\r
940                 result = true;\r
941                 break;\r
942         case smm_AdLib:\r
943                 if (AdLibPresent)\r
944                 {\r
945                         NeedsMusic = true;\r
946                         result = true;\r
947                 }\r
948                 break;\r
949         default:\r
950                 result = false;\r
951                 break;\r
952         }\r
953 \r
954         if (result)\r
955                 MusicMode = mode;\r
956 \r
957         SDL_SetTimerSpeed();\r
958 \r
959         return(result);\r
960 }\r
961 \r
962 ///////////////////////////////////////////////////////////////////////////\r
963 //\r
964 //      SD_Startup() - starts up the Sound Mgr\r
965 //              Detects all additional sound hardware and installs my ISR\r
966 //\r
967 ///////////////////////////////////////////////////////////////////////////\r
968 void\r
969 SD_Startup(void)\r
970 {\r
971         int     i;\r
972 \r
973         if (SD_Started)\r
974                 return;\r
975 \r
976         ssIsTandy = false;\r
977         alNoCheck = false;\r
978 #ifndef _MUSE_\r
979         for (i = 1;i < _argc;i++)\r
980         {\r
981                 switch (US_CheckParm(_argv[i],ParmStrings))\r
982                 {\r
983                 case 0:                                         // No AdLib detection\r
984                         alNoCheck = true;\r
985                         break;\r
986                 }\r
987         }\r
988 #endif\r
989 \r
990         SoundUserHook = 0;\r
991 \r
992         t0OldService = getvect(8);      // Get old timer 0 ISR\r
993 \r
994         SDL_InitDelay();                        // SDL_InitDelay() uses t0OldService\r
995 \r
996         setvect(8,SDL_t0Service);       // Set to my timer 0 ISR\r
997         LocalTime = TimeCount = alTimeCount = 0;\r
998 \r
999         SD_SetSoundMode(sdm_Off);\r
1000         SD_SetMusicMode(smm_Off);\r
1001 \r
1002         if (!alNoCheck)\r
1003                 AdLibPresent = SDL_DetectAdLib();\r
1004 \r
1005         for (i = 0;i < 255;i++)\r
1006                 pcSoundLookup[i] = i * 60;\r
1007 \r
1008         SD_Started = true;\r
1009 }\r
1010 \r
1011 ///////////////////////////////////////////////////////////////////////////\r
1012 //\r
1013 //      SD_Default() - Sets up the default behaviour for the Sound Mgr whether\r
1014 //              the config file was present or not.\r
1015 //\r
1016 ///////////////////////////////////////////////////////////////////////////\r
1017 void\r
1018 SD_Default(boolean gotit,SDMode sd,SMMode sm)\r
1019 {\r
1020         boolean gotsd,gotsm;\r
1021 \r
1022         gotsd = gotsm = gotit;\r
1023 \r
1024         if (gotsd)      // Make sure requested sound hardware is available\r
1025         {\r
1026                 switch (sd)\r
1027                 {\r
1028                 case sdm_AdLib:\r
1029                         gotsd = AdLibPresent;\r
1030                         break;\r
1031                 }\r
1032         }\r
1033         if (!gotsd)\r
1034         {\r
1035                 if (AdLibPresent)\r
1036                         sd = sdm_AdLib;\r
1037                 else\r
1038                         sd = sdm_PC;\r
1039         }\r
1040         if (sd != SoundMode)\r
1041                 SD_SetSoundMode(sd);\r
1042 \r
1043 \r
1044         if (gotsm)      // Make sure requested music hardware is available\r
1045         {\r
1046                 switch (sm)\r
1047                 {\r
1048                 case sdm_AdLib:\r
1049                         gotsm = AdLibPresent;\r
1050                         break;\r
1051                 }\r
1052         }\r
1053         if (!gotsm)\r
1054         {\r
1055                 if (AdLibPresent)\r
1056                         sm = smm_AdLib;\r
1057         }\r
1058         if (sm != MusicMode)\r
1059                 SD_SetMusicMode(sm);\r
1060 }\r
1061 \r
1062 ///////////////////////////////////////////////////////////////////////////\r
1063 //\r
1064 //      SD_Shutdown() - shuts down the Sound Mgr\r
1065 //              Removes sound ISR and turns off whatever sound hardware was active\r
1066 //\r
1067 ///////////////////////////////////////////////////////////////////////////\r
1068 void\r
1069 SD_Shutdown(void)\r
1070 {\r
1071         if (!SD_Started)\r
1072                 return;\r
1073 \r
1074         SD_MusicOff();\r
1075         SDL_ShutDevice();\r
1076         SDL_CleanDevice();\r
1077 \r
1078         asm     pushf\r
1079         asm     cli\r
1080 \r
1081         SDL_SetTimer0(0);\r
1082 \r
1083         setvect(8,t0OldService);\r
1084 \r
1085         asm     popf\r
1086 \r
1087         SD_Started = false;\r
1088 }\r
1089 \r
1090 ///////////////////////////////////////////////////////////////////////////\r
1091 //\r
1092 //      SD_SetUserHook() - sets the routine that the Sound Mgr calls every 1/70th\r
1093 //              of a second from its timer 0 ISR\r
1094 //\r
1095 ///////////////////////////////////////////////////////////////////////////\r
1096 void\r
1097 SD_SetUserHook(void (* hook)(void))\r
1098 {\r
1099         SoundUserHook = hook;\r
1100 }\r
1101 \r
1102 ///////////////////////////////////////////////////////////////////////////\r
1103 //\r
1104 //      SD_PlaySound() - plays the specified sound on the appropriate hardware\r
1105 //\r
1106 ///////////////////////////////////////////////////////////////////////////\r
1107 void\r
1108 SD_PlaySound(soundnames sound)\r
1109 {\r
1110         SoundCommon     far *s;\r
1111 \r
1112         if ((SoundMode == sdm_Off) || (sound == -1))\r
1113                 return;\r
1114 \r
1115         s = MK_FP(SoundTable[sound],0);\r
1116         if (!s)\r
1117                 Quit("SD_PlaySound() - Uncached sound");\r
1118         if (!s->length)\r
1119                 Quit("SD_PlaySound() - Zero length sound");\r
1120         if (s->priority < SoundPriority)\r
1121                 return;\r
1122 \r
1123         switch (SoundMode)\r
1124         {\r
1125         case sdm_PC:\r
1126                 SDL_PCPlaySound((void far *)s);\r
1127                 break;\r
1128         case sdm_AdLib:\r
1129                 SDL_ALPlaySound((void far *)s);\r
1130                 break;\r
1131         }\r
1132 \r
1133         SoundNumber = sound;\r
1134         SoundPriority = s->priority;\r
1135 }\r
1136 \r
1137 ///////////////////////////////////////////////////////////////////////////\r
1138 //\r
1139 //      SD_SoundPlaying() - returns the sound number that's playing, or 0 if\r
1140 //              no sound is playing\r
1141 //\r
1142 ///////////////////////////////////////////////////////////////////////////\r
1143 word\r
1144 SD_SoundPlaying(void)\r
1145 {\r
1146         boolean result = false;\r
1147 \r
1148         switch (SoundMode)\r
1149         {\r
1150         case sdm_PC:\r
1151                 result = pcSound? true : false;\r
1152                 break;\r
1153         case sdm_AdLib:\r
1154                 result = alSound? true : false;\r
1155                 break;\r
1156         }\r
1157 \r
1158         if (result)\r
1159                 return(SoundNumber);\r
1160         else\r
1161                 return(false);\r
1162 }\r
1163 \r
1164 ///////////////////////////////////////////////////////////////////////////\r
1165 //\r
1166 //      SD_StopSound() - if a sound is playing, stops it\r
1167 //\r
1168 ///////////////////////////////////////////////////////////////////////////\r
1169 void\r
1170 SD_StopSound(void)\r
1171 {\r
1172         switch (SoundMode)\r
1173         {\r
1174         case sdm_PC:\r
1175                 SDL_PCStopSound();\r
1176                 break;\r
1177         case sdm_AdLib:\r
1178                 SDL_ALStopSound();\r
1179                 break;\r
1180         }\r
1181 \r
1182         SDL_SoundFinished();\r
1183 }\r
1184 \r
1185 ///////////////////////////////////////////////////////////////////////////\r
1186 //\r
1187 //      SD_WaitSoundDone() - waits until the current sound is done playing\r
1188 //\r
1189 ///////////////////////////////////////////////////////////////////////////\r
1190 void\r
1191 SD_WaitSoundDone(void)\r
1192 {\r
1193         while (SD_SoundPlaying())\r
1194                 ;\r
1195 }\r
1196 \r
1197 ///////////////////////////////////////////////////////////////////////////\r
1198 //\r
1199 //      SD_MusicOn() - turns on the sequencer\r
1200 //\r
1201 ///////////////////////////////////////////////////////////////////////////\r
1202 void\r
1203 SD_MusicOn(void)\r
1204 {\r
1205         sqActive = true;\r
1206 }\r
1207 \r
1208 ///////////////////////////////////////////////////////////////////////////\r
1209 //\r
1210 //      SD_MusicOff() - turns off the sequencer and any playing notes\r
1211 //\r
1212 ///////////////////////////////////////////////////////////////////////////\r
1213 void\r
1214 SD_MusicOff(void)\r
1215 {\r
1216         word    i;\r
1217 \r
1218 \r
1219         switch (MusicMode)\r
1220         {\r
1221         case smm_AdLib:\r
1222                 alFXReg = 0;\r
1223                 alOut(alEffects,0);\r
1224                 for (i = 0;i < sqMaxTracks;i++)\r
1225                         alOut(alFreqH + i + 1,0);\r
1226                 break;\r
1227         }\r
1228         sqActive = false;\r
1229 }\r
1230 \r
1231 ///////////////////////////////////////////////////////////////////////////\r
1232 //\r
1233 //      SD_StartMusic() - starts playing the music pointed to\r
1234 //\r
1235 ///////////////////////////////////////////////////////////////////////////\r
1236 void\r
1237 SD_StartMusic(MusicGroup far *music)\r
1238 {\r
1239         SD_MusicOff();\r
1240 asm     pushf\r
1241 asm     cli\r
1242 \r
1243         if (MusicMode == smm_AdLib)\r
1244         {\r
1245                 sqHackPtr = sqHack = music->values;\r
1246                 sqHackSeqLen = sqHackLen = music->length;\r
1247                 sqHackTime = 0;\r
1248                 alTimeCount = 0;\r
1249                 SD_MusicOn();\r
1250         }\r
1251 \r
1252 asm     popf\r
1253 }\r
1254 \r
1255 ///////////////////////////////////////////////////////////////////////////\r
1256 //\r
1257 //      SD_FadeOutMusic() - starts fading out the music. Call SD_MusicPlaying()\r
1258 //              to see if the fadeout is complete\r
1259 //\r
1260 ///////////////////////////////////////////////////////////////////////////\r
1261 void\r
1262 SD_FadeOutMusic(void)\r
1263 {\r
1264         switch (MusicMode)\r
1265         {\r
1266         case smm_AdLib:\r
1267                 // DEBUG - quick hack to turn the music off\r
1268                 SD_MusicOff();\r
1269                 break;\r
1270         }\r
1271 }\r
1272 \r
1273 ///////////////////////////////////////////////////////////////////////////\r
1274 //\r
1275 //      SD_MusicPlaying() - returns true if music is currently playing, false if\r
1276 //              not\r
1277 //\r
1278 ///////////////////////////////////////////////////////////////////////////\r
1279 boolean\r
1280 SD_MusicPlaying(void)\r
1281 {\r
1282         boolean result;\r
1283 \r
1284         switch (MusicMode)\r
1285         {\r
1286         case smm_AdLib:\r
1287                 result = false;\r
1288                 // DEBUG - not written\r
1289                 break;\r
1290         default:\r
1291                 result = false;\r
1292         }\r
1293 \r
1294         return(result);\r
1295 }\r