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