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