summaryrefslogtreecommitdiff
path: root/apps/plugins/sdl/progs/wolf3d/id_sd.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/sdl/progs/wolf3d/id_sd.c')
-rw-r--r--apps/plugins/sdl/progs/wolf3d/id_sd.c1578
1 files changed, 1578 insertions, 0 deletions
diff --git a/apps/plugins/sdl/progs/wolf3d/id_sd.c b/apps/plugins/sdl/progs/wolf3d/id_sd.c
new file mode 100644
index 0000000000..a528caa606
--- /dev/null
+++ b/apps/plugins/sdl/progs/wolf3d/id_sd.c
@@ -0,0 +1,1578 @@
1//
2// ID Engine
3// ID_SD.c - Sound Manager for Wolfenstein 3D
4// v1.2
5// By Jason Blochowiak
6//
7
8//
9// This module handles dealing with generating sound on the appropriate
10// hardware
11//
12// Depends on: User Mgr (for parm checking)
13//
14// Globals:
15// For User Mgr:
16// SoundBlasterPresent - SoundBlaster card present?
17// AdLibPresent - AdLib card present?
18// SoundMode - What device is used for sound effects
19// (Use SM_SetSoundMode() to set)
20// MusicMode - What device is used for music
21// (Use SM_SetMusicMode() to set)
22// DigiMode - What device is used for digitized sound effects
23// (Use SM_SetDigiDevice() to set)
24//
25// For Cache Mgr:
26// NeedsDigitized - load digitized sounds?
27// NeedsMusic - load music?
28//
29
30#include "wl_def.h"
31#include "fmopl.h"
32
33#include "fixedpoint.h"
34
35#pragma hdrstop
36
37#define ORIGSAMPLERATE 7042
38
39typedef struct
40{
41 char RIFF[4];
42 longword filelenminus8;
43 char WAVE[4];
44 char fmt_[4];
45 longword formatlen;
46 word val0x0001;
47 word channels;
48 longword samplerate;
49 longword bytespersec;
50 word bytespersample;
51 word bitspersample;
52} headchunk;
53
54typedef struct
55{
56 char chunkid[4];
57 longword chunklength;
58} wavechunk;
59
60typedef struct
61{
62 uint32_t startpage;
63 uint32_t length;
64} digiinfo;
65
66static Mix_Chunk *SoundChunks[ STARTMUSIC - STARTDIGISOUNDS];
67static byte *SoundBuffers[STARTMUSIC - STARTDIGISOUNDS];
68
69globalsoundpos channelSoundPos[MIX_CHANNELS];
70
71// Global variables
72 boolean AdLibPresent,
73 SoundBlasterPresent,SBProPresent,
74 SoundPositioned;
75 SDMode SoundMode;
76 SMMode MusicMode;
77 SDSMode DigiMode;
78static byte **SoundTable;
79 int DigiMap[LASTSOUND];
80 int DigiChannel[STARTMUSIC - STARTDIGISOUNDS];
81
82// Internal variables
83static boolean SD_Started;
84static boolean nextsoundpos;
85static soundnames SoundNumber;
86static soundnames DigiNumber;
87static word SoundPriority;
88static word DigiPriority;
89static int LeftPosition;
90static int RightPosition;
91
92 word NumDigi;
93static digiinfo *DigiList;
94static boolean DigiPlaying;
95
96// PC Sound variables
97static volatile byte pcLastSample;
98static byte * volatile pcSound;
99static longword pcLengthLeft;
100
101// AdLib variables
102static byte * volatile alSound;
103static byte alBlock;
104static longword alLengthLeft;
105static longword alTimeCount;
106static Instrument alZeroInst;
107
108// Sequencer variables
109static volatile boolean sqActive;
110static word *sqHack;
111static word *sqHackPtr;
112static int sqHackLen;
113static int sqHackSeqLen;
114static longword sqHackTime;
115
116
117static void SDL_SoundFinished(void)
118{
119#ifdef SOUND_ENABLE
120 SoundNumber = (soundnames)0;
121 SoundPriority = 0;
122#endif
123}
124
125
126#ifdef NOTYET
127
128void SDL_turnOnPCSpeaker(word timerval);
129#pragma aux SDL_turnOnPCSpeaker = \
130 "mov al,0b6h" \
131 "out 43h,al" \
132 "mov al,bl" \
133 "out 42h,al" \
134 "mov al,bh" \
135 "out 42h,al" \
136 "in al,61h" \
137 "or al,3" \
138 "out 61h,al" \
139 parm [bx] \
140 modify exact [al]
141
142void SDL_turnOffPCSpeaker();
143#pragma aux SDL_turnOffPCSpeaker = \
144 "in al,61h" \
145 "and al,0fch" \
146 "out 61h,al" \
147 modify exact [al]
148
149void SDL_setPCSpeaker(byte val);
150#pragma aux SDL_setPCSpeaker = \
151 "in al,61h" \
152 "and al,0fch" \
153 "or al,ah" \
154 "out 61h,al" \
155 parm [ah] \
156 modify exact [al]
157
158void SDL_DoFX()
159{
160 if(pcSound)
161 {
162 if(*pcSound!=pcLastSample)
163 {
164 pcLastSample=*pcSound;
165
166 if(pcLastSample)
167 SDL_turnOnPCSpeaker(pcLastSample*60);
168 else
169 SDL_turnOffPCSpeaker();
170 }
171 pcSound++;
172 pcLengthLeft--;
173 if(!pcLengthLeft)
174 {
175 pcSound=0;
176 SoundNumber=(soundnames)0;
177 SoundPriority=0;
178 SDL_turnOffPCSpeaker();
179 }
180 }
181
182 // [adlib sound stuff removed...]
183}
184
185static void SDL_DigitizedDoneInIRQ(void);
186
187void SDL_DoFast()
188{
189 count_fx++;
190 if(count_fx>=5)
191 {
192 count_fx=0;
193
194 SDL_DoFX();
195
196 count_time++;
197 if(count_time>=2)
198 {
199 TimeCount++;
200 count_time=0;
201 }
202 }
203
204 // [adlib music and soundsource stuff removed...]
205
206 TimerCount+=TimerDivisor;
207 if(*((word *)&TimerCount+1))
208 {
209 *((word *)&TimerCount+1)=0;
210 t0OldService();
211 }
212 else
213 {
214 outp(0x20,0x20);
215 }
216}
217
218// Timer 0 ISR for 7000Hz interrupts
219void __interrupt SDL_t0ExtremeAsmService(void)
220{
221 if(pcindicate)
222 {
223 if(pcSound)
224 {
225 SDL_setPCSpeaker(((*pcSound++)&0x80)>>6);
226 pcLengthLeft--;
227 if(!pcLengthLeft)
228 {
229 pcSound=0;
230 SDL_turnOffPCSpeaker();
231 SDL_DigitizedDoneInIRQ();
232 }
233 }
234 }
235 extreme++;
236 if(extreme>=10)
237 {
238 extreme=0;
239 SDL_DoFast();
240 }
241 else
242 outp(0x20,0x20);
243}
244
245// Timer 0 ISR for 700Hz interrupts
246void __interrupt SDL_t0FastAsmService(void)
247{
248 SDL_DoFast();
249}
250
251// Timer 0 ISR for 140Hz interrupts
252void __interrupt SDL_t0SlowAsmService(void)
253{
254 count_time++;
255 if(count_time>=2)
256 {
257 TimeCount++;
258 count_time=0;
259 }
260
261 SDL_DoFX();
262
263 TimerCount+=TimerDivisor;
264 if(*((word *)&TimerCount+1))
265 {
266 *((word *)&TimerCount+1)=0;
267 t0OldService();
268 }
269 else
270 outp(0x20,0x20);
271}
272
273void SDL_IndicatePC(boolean ind)
274{
275 pcindicate=ind;
276}
277
278///////////////////////////////////////////////////////////////////////////
279//
280// SDL_SetTimer0() - Sets system timer 0 to the specified speed
281//
282///////////////////////////////////////////////////////////////////////////
283static void
284SDL_SetTimer0(word speed)
285{
286#ifndef TPROF // If using Borland's profiling, don't screw with the timer
287// _asm pushfd
288 _asm cli
289
290 outp(0x43,0x36); // Change timer 0
291 outp(0x40,(byte)speed);
292 outp(0x40,speed >> 8);
293 // Kludge to handle special case for digitized PC sounds
294 if (TimerDivisor == (1192030 / (TickBase * 100)))
295 TimerDivisor = (1192030 / (TickBase * 10));
296 else
297 TimerDivisor = speed;
298
299// _asm popfd
300 _asm sti
301#else
302 TimerDivisor = 0x10000;
303#endif
304}
305
306///////////////////////////////////////////////////////////////////////////
307//
308// SDL_SetIntsPerSec() - Uses SDL_SetTimer0() to set the number of
309// interrupts generated by system timer 0 per second
310//
311///////////////////////////////////////////////////////////////////////////
312static void
313SDL_SetIntsPerSec(word ints)
314{
315 TimerRate = ints;
316 SDL_SetTimer0(1192030 / ints);
317}
318
319static void
320SDL_SetTimerSpeed(void)
321{
322 word rate;
323 void (_interrupt *isr)(void);
324
325 if ((DigiMode == sds_PC) && DigiPlaying)
326 {
327 rate = TickBase * 100;
328 isr = SDL_t0ExtremeAsmService;
329 }
330 else if ((MusicMode == smm_AdLib) || ((DigiMode == sds_SoundSource) && DigiPlaying) )
331 {
332 rate = TickBase * 10;
333 isr = SDL_t0FastAsmService;
334 }
335 else
336 {
337 rate = TickBase * 2;
338 isr = SDL_t0SlowAsmService;
339 }
340
341 if (rate != TimerRate)
342 {
343 _dos_setvect(8,isr);
344 SDL_SetIntsPerSec(rate);
345 TimerRate = rate;
346 }
347}
348
349//
350// PC Sound code
351//
352
353///////////////////////////////////////////////////////////////////////////
354//
355// SDL_PCPlaySample() - Plays the specified sample on the PC speaker
356//
357///////////////////////////////////////////////////////////////////////////
358#ifdef _MUSE_
359void
360#else
361static void
362#endif
363SDL_PCPlaySample(byte *data,longword len,boolean inIRQ)
364{
365 if(!inIRQ)
366 {
367// _asm pushfd
368 _asm cli
369 }
370
371 SDL_IndicatePC(true);
372
373 pcLengthLeft = len;
374 pcSound = (volatile byte *)data;
375
376 if(!inIRQ)
377 {
378// _asm popfd
379 _asm sti
380 }
381}
382
383///////////////////////////////////////////////////////////////////////////
384//
385// SDL_PCStopSample() - Stops a sample playing on the PC speaker
386//
387///////////////////////////////////////////////////////////////////////////
388#ifdef _MUSE_
389void
390#else
391static void
392#endif
393SDL_PCStopSampleInIRQ(void)
394{
395 pcSound = 0;
396
397 SDL_IndicatePC(false);
398
399 _asm in al,0x61 // Turn the speaker off
400 _asm and al,0xfd // ~2
401 _asm out 0x61,al
402}
403
404///////////////////////////////////////////////////////////////////////////
405//
406// SDL_PCPlaySound() - Plays the specified sound on the PC speaker
407//
408///////////////////////////////////////////////////////////////////////////
409#ifdef _MUSE_
410void
411#else
412static void
413#endif
414SDL_PCPlaySound(PCSound *sound)
415{
416// _asm pushfd
417 _asm cli
418
419 pcLastSample = -1;
420 pcLengthLeft = sound->common.length;
421 pcSound = sound->data;
422
423// _asm popfd
424 _asm sti
425}
426
427///////////////////////////////////////////////////////////////////////////
428//
429// SDL_PCStopSound() - Stops the current sound playing on the PC Speaker
430//
431///////////////////////////////////////////////////////////////////////////
432#ifdef _MUSE_
433void
434#else
435static void
436#endif
437SDL_PCStopSound(void)
438{
439// _asm pushfd
440 _asm cli
441
442 pcSound = 0;
443
444 _asm in al,0x61 // Turn the speaker off
445 _asm and al,0xfd // ~2
446 _asm out 0x61,al
447
448// _asm popfd
449 _asm sti
450}
451
452///////////////////////////////////////////////////////////////////////////
453//
454// SDL_ShutPC() - Turns off the pc speaker
455//
456///////////////////////////////////////////////////////////////////////////
457static void
458SDL_ShutPC(void)
459{
460// _asm pushfd
461 _asm cli
462
463 pcSound = 0;
464
465 _asm in al,0x61 // Turn the speaker & gate off
466 _asm and al,0xfc // ~3
467 _asm out 0x61,al
468
469// _asm popfd
470 _asm sti
471}
472
473#endif
474
475void
476SD_StopDigitized(void)
477{
478#ifdef SOUND_ENABLE
479 DigiPlaying = false;
480 DigiNumber = (soundnames) 0;
481 DigiPriority = 0;
482 SoundPositioned = false;
483 if ((DigiMode == sds_PC) && (SoundMode == sdm_PC))
484 SDL_SoundFinished();
485
486 switch (DigiMode)
487 {
488 case sds_PC:
489// SDL_PCStopSampleInIRQ();
490 break;
491 case sds_SoundBlaster:
492// SDL_SBStopSampleInIRQ();
493 Mix_HaltChannel(-1);
494 break;
495 }
496#endif
497}
498
499int SD_GetChannelForDigi(int which)
500{
501#ifdef SOUND_ENABLE
502 if(DigiChannel[which] != -1) return DigiChannel[which];
503
504 int channel = Mix_GroupAvailable(1);
505 if(channel == -1) channel = Mix_GroupOldest(1);
506 if(channel == -1) // All sounds stopped in the meantime?
507 return Mix_GroupAvailable(1);
508 return channel;
509#endif
510 return 0;
511}
512
513void SD_SetPosition(int channel, int leftpos, int rightpos)
514{
515#ifdef SOUND_ENABLE
516 if((leftpos < 0) || (leftpos > 15) || (rightpos < 0) || (rightpos > 15)
517 || ((leftpos == 15) && (rightpos == 15)))
518 Quit("SD_SetPosition: Illegal position");
519
520 switch (DigiMode)
521 {
522 case sds_SoundBlaster:
523// SDL_PositionSBP(leftpos,rightpos);
524 Mix_SetPanning(channel, ((15 - leftpos) << 4) + 15,
525 ((15 - rightpos) << 4) + 15);
526 break;
527 }
528#endif
529}
530
531#define FP_FLOOR(x, fracbits) (x & (~((1<<(fracbits))-1)))
532
533/* more precise than original samples */
534#define FRACBITS 10
535#define FP_MATH
536
537#ifdef FP_MATH
538/* Looks to be some sort of interpolation - FW19 */
539Sint16 GetSample(long csample_fp, byte *samples, int size)
540{
541 //float s0=0, s1=0, s2=0;
542 long s0_fp = 0, s1_fp = 0, s2_fp = 0;
543 long cursample_fp = FP_FLOOR(csample_fp, FRACBITS);
544 long sf_fp = csample_fp - cursample_fp;
545 const long one = 1 << FRACBITS;
546
547 int cursample = cursample_fp >> FRACBITS;
548
549 if(cursample-1 >= 0) s0_fp = (samples[cursample-1] - 128) << FRACBITS;
550 s1_fp = (samples[cursample] - 128) << FRACBITS;
551 if(cursample+1 < size) s2_fp = (samples[cursample+1] - 128) << FRACBITS;
552
553 //float val = s0*sf*(sf-1)/2 - s1*(sf*sf-1) + s2*(sf+1)*sf/2;
554
555 long val_fp = fp_mul(s0_fp, fp_mul(sf_fp, sf_fp - one, FRACBITS), FRACBITS) / 2 -
556 fp_mul(s1_fp, fp_mul(sf_fp, sf_fp, FRACBITS) - one, FRACBITS) +
557 fp_mul(s2_fp, fp_mul(sf_fp + one, sf_fp, FRACBITS), FRACBITS) / 2;
558
559 int32_t intval = (int32_t) (val_fp * 256) >> FRACBITS;
560 if(intval < -32768) intval = -32768;
561 else if(intval > 32767) intval = 32767;
562 return (Sint16) intval;
563}
564#else
565Sint16 GetSample(float csample, byte *samples, int size)
566{
567 float s0=0, s1=0, s2=0;
568 int cursample = (int) csample;
569 float sf = csample - (float) cursample;
570
571 if(cursample-1 >= 0) s0 = (float) (samples[cursample-1] - 128);
572 s1 = (float) (samples[cursample] - 128);
573 if(cursample+1 < size) s2 = (float) (samples[cursample+1] - 128);
574
575 float val = s0*sf*(sf-1)/2 - s1*(sf*sf-1) + s2*(sf+1)*sf/2;
576 int32_t intval = (int32_t) (val * 256);
577 if(intval < -32768) intval = -32768;
578 else if(intval > 32767) intval = 32767;
579 return (Sint16) intval;
580}
581#endif
582
583void SD_PrepareSound(int which)
584{
585#ifdef SOUND_ENABLE
586#ifdef FP_MATH
587 if(DigiList == NULL)
588 Quit("SD_PrepareSound(%i): DigiList not initialized!\n", which);
589
590 int page = DigiList[which].startpage;
591 int size = DigiList[which].length;
592
593 byte *origsamples = PM_GetSound(page);
594 if(origsamples + size >= PM_GetEnd())
595 Quit("SD_PrepareSound(%i): Sound reaches out of page file!\n", which);
596
597 /* this is fine to keep as floating-point */
598 int destsamples = (int) ((float) size * (float) param_samplerate
599 / (float) ORIGSAMPLERATE);
600
601 byte *wavebuffer = (byte *) malloc(sizeof(headchunk) + sizeof(wavechunk)
602 + destsamples * 2); // dest are 16-bit samples
603 if(wavebuffer == NULL)
604 Quit("Unable to allocate wave buffer for sound %i size %d %d %d %d!\n", which, destsamples, size, param_samplerate, ORIGSAMPLERATE);
605
606 headchunk head = {{'R','I','F','F'}, 0, {'W','A','V','E'},
607 {'f','m','t',' '}, 0x10, 0x0001, 1, param_samplerate, param_samplerate*2, 2, 16};
608 wavechunk dhead = {{'d', 'a', 't', 'a'}, destsamples*2};
609 head.filelenminus8 = sizeof(head) + destsamples*2; // (sizeof(dhead)-8 = 0)
610 memcpy(wavebuffer, &head, sizeof(head));
611 memcpy(wavebuffer+sizeof(head), &dhead, sizeof(dhead));
612
613 // alignment is correct, as wavebuffer comes from malloc
614 // and sizeof(headchunk) % 4 == 0 and sizeof(wavechunk) % 4 == 0
615 Sint16 *newsamples = (Sint16 *)(void *) (wavebuffer + sizeof(headchunk)
616 + sizeof(wavechunk));
617
618 long scale_fac_fp = fp_div(size << FRACBITS, destsamples << FRACBITS, FRACBITS);
619
620 for(int i=0; i<destsamples; i++)
621 {
622 newsamples[i] = GetSample(fp_mul(i << FRACBITS, scale_fac_fp, FRACBITS),
623 origsamples, size);
624 }
625 SoundBuffers[which] = wavebuffer;
626
627 SoundChunks[which] = Mix_LoadWAV_RW(SDL_RWFromMem(wavebuffer,
628 sizeof(headchunk) + sizeof(wavechunk) + destsamples * 2), 1);
629#else
630 if(DigiList == NULL)
631 Quit("SD_PrepareSound(%i): DigiList not initialized!\n", which);
632
633 int page = DigiList[which].startpage;
634 int size = DigiList[which].length;
635
636 byte *origsamples = PM_GetSound(page);
637 if(origsamples + size >= PM_GetEnd())
638 Quit("SD_PrepareSound(%i): Sound reaches out of page file!\n", which);
639
640 int destsamples = (int) ((float) size * (float) param_samplerate
641 / (float) ORIGSAMPLERATE);
642
643 byte *wavebuffer = (byte *) malloc(sizeof(headchunk) + sizeof(wavechunk)
644 + destsamples * 2); // dest are 16-bit samples
645 if(wavebuffer == NULL)
646 Quit("Unable to allocate wave buffer for sound %i!\n", which);
647
648 headchunk head = {{'R','I','F','F'}, 0, {'W','A','V','E'},
649 {'f','m','t',' '}, 0x10, 0x0001, 1, param_samplerate, param_samplerate*2, 2, 16};
650 wavechunk dhead = {{'d', 'a', 't', 'a'}, destsamples*2};
651 head.filelenminus8 = sizeof(head) + destsamples*2; // (sizeof(dhead)-8 = 0)
652 memcpy(wavebuffer, &head, sizeof(head));
653 memcpy(wavebuffer+sizeof(head), &dhead, sizeof(dhead));
654
655 // alignment is correct, as wavebuffer comes from malloc
656 // and sizeof(headchunk) % 4 == 0 and sizeof(wavechunk) % 4 == 0
657 Sint16 *newsamples = (Sint16 *)(void *) (wavebuffer + sizeof(headchunk)
658 + sizeof(wavechunk));
659 float cursample = 0.F;
660 float samplestep = (float) ORIGSAMPLERATE / (float) param_samplerate;
661 for(int i=0; i<destsamples; i++, cursample+=samplestep)
662 {
663 newsamples[i] = GetSample((float)size * (float)i / (float)destsamples,
664 origsamples, size);
665 }
666 SoundBuffers[which] = wavebuffer;
667
668 SoundChunks[which] = Mix_LoadWAV_RW(SDL_RWFromMem(wavebuffer,
669 sizeof(headchunk) + sizeof(wavechunk) + destsamples * 2), 1);
670#endif
671#endif
672}
673
674int SD_PlayDigitized(word which,int leftpos,int rightpos)
675{
676#ifdef SOUND_ENABLE
677 if (!DigiMode)
678 return 0;
679
680 if (which >= NumDigi)
681 Quit("SD_PlayDigitized: bad sound number %i", which);
682
683 int channel = SD_GetChannelForDigi(which);
684 SD_SetPosition(channel, leftpos,rightpos);
685
686 DigiPlaying = true;
687
688 Mix_Chunk *sample = SoundChunks[which];
689 if(sample == NULL)
690 {
691 printf("SoundChunks[%i] is NULL!\n", which);
692 return 0;
693 }
694
695 if(Mix_PlayChannel(channel, sample, 0) == -1)
696 {
697 printf("Unable to play sound: %s\n", Mix_GetError());
698 return 0;
699 }
700
701 return channel;
702#endif
703 return 0;
704}
705
706void SD_ChannelFinished(int channel)
707{
708#ifdef SOUND_ENABLE
709 channelSoundPos[channel].valid = 0;
710#endif
711}
712
713void
714SD_SetDigiDevice(SDSMode mode)
715{
716#ifdef SOUND_ENABLE
717 boolean devicenotpresent;
718
719 if (mode == DigiMode)
720 return;
721
722 SD_StopDigitized();
723
724 devicenotpresent = false;
725 switch (mode)
726 {
727 case sds_SoundBlaster:
728 if (!SoundBlasterPresent)
729 devicenotpresent = true;
730 break;
731 }
732
733 if (!devicenotpresent)
734 {
735 DigiMode = mode;
736
737#ifdef NOTYET
738 SDL_SetTimerSpeed();
739#endif
740 }
741#endif
742}
743
744void
745SDL_SetupDigi(void)
746{
747#ifdef SOUND_ENABLE
748 // Correct padding enforced by PM_Startup()
749 word *soundInfoPage = (word *) (void *) PM_GetPage(ChunksInFile-1);
750 NumDigi = (word) PM_GetPageSize(ChunksInFile - 1) / 4;
751
752 DigiList = (digiinfo *) malloc(NumDigi * sizeof(digiinfo));
753 int i;
754 for(i = 0; i < NumDigi; i++)
755 {
756 // Calculate the size of the digi from the sizes of the pages between
757 // the start page and the start page of the next sound
758
759 DigiList[i].startpage = soundInfoPage[i * 2];
760 if((int) DigiList[i].startpage >= ChunksInFile - 1)
761 {
762 NumDigi = i;
763 break;
764 }
765
766 int lastPage;
767 if(i < NumDigi - 1)
768 {
769 lastPage = soundInfoPage[i * 2 + 2];
770 if(lastPage == 0 || lastPage + PMSoundStart > ChunksInFile - 1) lastPage = ChunksInFile - 1;
771 else lastPage += PMSoundStart;
772 }
773 else lastPage = ChunksInFile - 1;
774
775 int size = 0;
776 for(int page = PMSoundStart + DigiList[i].startpage; page < lastPage; page++)
777 size += PM_GetPageSize(page);
778
779 // Don't include padding of sound info page, if padding was added
780 if(lastPage == ChunksInFile - 1 && PMSoundInfoPagePadded) size--;
781
782 // Patch lower 16-bit of size with size from sound info page.
783 // The original VSWAP contains padding which is included in the page size,
784 // but not included in the 16-bit size. So we use the more precise value.
785 if((size & 0xffff0000) != 0 && (size & 0xffff) < soundInfoPage[i * 2 + 1])
786 size -= 0x10000;
787 size = (size & 0xffff0000) | soundInfoPage[i * 2 + 1];
788
789 DigiList[i].length = size;
790 }
791
792 for(i = 0; i < LASTSOUND; i++)
793 {
794 DigiMap[i] = -1;
795 DigiChannel[i] = -1;
796 }
797#endif
798}
799
800// AdLib Code
801
802///////////////////////////////////////////////////////////////////////////
803//
804// SDL_ALStopSound() - Turns off any sound effects playing through the
805// AdLib card
806//
807///////////////////////////////////////////////////////////////////////////
808static void
809SDL_ALStopSound(void)
810{
811#ifdef SOUND_ENABLE
812 alSound = 0;
813 alOut(alFreqH + 0, 0);
814#endif
815}
816
817static void
818SDL_AlSetFXInst(Instrument *inst)
819{
820#ifdef SOUND_ENABLE
821 byte c,m;
822
823 m = 0; // modulator cell for channel 0
824 c = 3; // carrier cell for channel 0
825 alOut(m + alChar,inst->mChar);
826 alOut(m + alScale,inst->mScale);
827 alOut(m + alAttack,inst->mAttack);
828 alOut(m + alSus,inst->mSus);
829 alOut(m + alWave,inst->mWave);
830 alOut(c + alChar,inst->cChar);
831 alOut(c + alScale,inst->cScale);
832 alOut(c + alAttack,inst->cAttack);
833 alOut(c + alSus,inst->cSus);
834 alOut(c + alWave,inst->cWave);
835
836 // Note: Switch commenting on these lines for old MUSE compatibility
837// alOutInIRQ(alFeedCon,inst->nConn);
838 alOut(alFeedCon,0);
839#endif
840}
841
842///////////////////////////////////////////////////////////////////////////
843//
844// SDL_ALPlaySound() - Plays the specified sound on the AdLib card
845//
846///////////////////////////////////////////////////////////////////////////
847static void
848SDL_ALPlaySound(AdLibSound *sound)
849{
850#ifdef SOUND_ENABLE
851 Instrument *inst;
852 byte *data;
853
854 SDL_ALStopSound();
855
856 alLengthLeft = sound->common.length;
857 data = sound->data;
858 alBlock = ((sound->block & 7) << 2) | 0x20;
859 inst = &sound->inst;
860
861 if (!(inst->mSus | inst->cSus))
862 {
863 Quit("SDL_ALPlaySound() - Bad instrument");
864 }
865
866 SDL_AlSetFXInst(inst);
867 alSound = (byte *)data;
868#endif
869}
870
871///////////////////////////////////////////////////////////////////////////
872//
873// SDL_ShutAL() - Shuts down the AdLib card for sound effects
874//
875///////////////////////////////////////////////////////////////////////////
876static void
877SDL_ShutAL(void)
878{
879#ifdef SOUND_ENABLE
880 alSound = 0;
881 alOut(alEffects,0);
882 alOut(alFreqH + 0,0);
883 SDL_AlSetFXInst(&alZeroInst);
884#endif
885}
886
887///////////////////////////////////////////////////////////////////////////
888//
889// SDL_CleanAL() - Totally shuts down the AdLib card
890//
891///////////////////////////////////////////////////////////////////////////
892static void
893SDL_CleanAL(void)
894{
895#ifdef SOUND_ENABLE
896 int i;
897
898 alOut(alEffects,0);
899 for (i = 1; i < 0xf5; i++)
900 alOut(i, 0);
901#endif
902}
903
904///////////////////////////////////////////////////////////////////////////
905//
906// SDL_StartAL() - Starts up the AdLib card for sound effects
907//
908///////////////////////////////////////////////////////////////////////////
909static void
910SDL_StartAL(void)
911{
912#ifdef SOUND_ENABLE
913 alOut(alEffects, 0);
914 SDL_AlSetFXInst(&alZeroInst);
915#endif
916}
917
918///////////////////////////////////////////////////////////////////////////
919//
920// SDL_DetectAdLib() - Determines if there's an AdLib (or SoundBlaster
921// emulating an AdLib) present
922//
923///////////////////////////////////////////////////////////////////////////
924static boolean
925SDL_DetectAdLib(void)
926{
927#ifdef SOUND_ENABLE
928 for (int i = 1; i <= 0xf5; i++) // Zero all the registers
929 alOut(i, 0);
930
931 alOut(1, 0x20); // Set WSE=1
932// alOut(8, 0); // Set CSM=0 & SEL=0
933
934 return true;
935#endif
936}
937
938////////////////////////////////////////////////////////////////////////////
939//
940// SDL_ShutDevice() - turns off whatever device was being used for sound fx
941//
942////////////////////////////////////////////////////////////////////////////
943static void
944SDL_ShutDevice(void)
945{
946#ifdef SOUND_ENABLE
947 switch (SoundMode)
948 {
949 case sdm_PC:
950// SDL_ShutPC();
951 break;
952 case sdm_AdLib:
953 SDL_ShutAL();
954 break;
955 }
956 SoundMode = sdm_Off;
957#endif
958}
959
960///////////////////////////////////////////////////////////////////////////
961//
962// SDL_CleanDevice() - totally shuts down all sound devices
963//
964///////////////////////////////////////////////////////////////////////////
965static void
966SDL_CleanDevice(void)
967{
968#ifdef SOUND_ENABLE
969 if ((SoundMode == sdm_AdLib) || (MusicMode == smm_AdLib))
970 SDL_CleanAL();
971#endif
972}
973
974///////////////////////////////////////////////////////////////////////////
975//
976// SDL_StartDevice() - turns on whatever device is to be used for sound fx
977//
978///////////////////////////////////////////////////////////////////////////
979static void
980SDL_StartDevice(void)
981{
982#ifdef SOUND_ENABLE
983 switch (SoundMode)
984 {
985 case sdm_AdLib:
986 SDL_StartAL();
987 break;
988 }
989 SoundNumber = (soundnames) 0;
990 SoundPriority = 0;
991#endif
992}
993
994// Public routines
995
996///////////////////////////////////////////////////////////////////////////
997//
998// SD_SetSoundMode() - Sets which sound hardware to use for sound effects
999//
1000///////////////////////////////////////////////////////////////////////////
1001boolean
1002SD_SetSoundMode(SDMode mode)
1003{
1004#ifdef SOUND_ENABLE
1005 boolean result = false;
1006 word tableoffset;
1007
1008 SD_StopSound();
1009
1010 if ((mode == sdm_AdLib) && !AdLibPresent)
1011 mode = sdm_PC;
1012
1013 switch (mode)
1014 {
1015 case sdm_Off:
1016 tableoffset = STARTADLIBSOUNDS;
1017 result = true;
1018 break;
1019 case sdm_PC:
1020 tableoffset = STARTPCSOUNDS;
1021 result = true;
1022 break;
1023 case sdm_AdLib:
1024 tableoffset = STARTADLIBSOUNDS;
1025 if (AdLibPresent)
1026 result = true;
1027 break;
1028 default:
1029 Quit("SD_SetSoundMode: Invalid sound mode %i", mode);
1030 return false;
1031 }
1032 SoundTable = &audiosegs[tableoffset];
1033
1034 if (result && (mode != SoundMode))
1035 {
1036 SDL_ShutDevice();
1037 SoundMode = mode;
1038 SDL_StartDevice();
1039 }
1040
1041 return(result);
1042#endif
1043 return true;
1044}
1045
1046///////////////////////////////////////////////////////////////////////////
1047//
1048// SD_SetMusicMode() - sets the device to use for background music
1049//
1050///////////////////////////////////////////////////////////////////////////
1051boolean
1052SD_SetMusicMode(SMMode mode)
1053{
1054#ifdef SOUND_ENABLE
1055 boolean result = false;
1056
1057 SD_FadeOutMusic();
1058 while (SD_MusicPlaying())
1059 SDL_Delay(5);
1060
1061 switch (mode)
1062 {
1063 case smm_Off:
1064 result = true;
1065 break;
1066 case smm_AdLib:
1067 if (AdLibPresent)
1068 result = true;
1069 break;
1070 }
1071
1072 if (result)
1073 MusicMode = mode;
1074
1075// SDL_SetTimerSpeed();
1076
1077 return(result);
1078#endif
1079}
1080
1081int numreadysamples = 0;
1082byte *curAlSound = 0;
1083byte *curAlSoundPtr = 0;
1084longword curAlLengthLeft = 0;
1085int soundTimeCounter = 5;
1086int samplesPerMusicTick;
1087
1088void *OPL_ptr = NULL;
1089
1090void SDL_IMFMusicPlayer(void *udata, Uint8 *stream, int len)
1091{
1092#ifdef SOUND_ENABLE
1093 int stereolen = len>>1;
1094 int sampleslen = stereolen>>1;
1095 INT16 *stream16 = (INT16 *) (void *) stream; // expect correct alignment
1096
1097 while(1)
1098 {
1099 if(numreadysamples)
1100 {
1101 if(numreadysamples<sampleslen)
1102 {
1103 YM3812UpdateOne(OPL_ptr, stream16, numreadysamples);
1104 stream16 += numreadysamples*2;
1105 sampleslen -= numreadysamples;
1106 }
1107 else
1108 {
1109 YM3812UpdateOne(OPL_ptr, stream16, sampleslen);
1110 numreadysamples -= sampleslen;
1111 return;
1112 }
1113 }
1114 soundTimeCounter--;
1115 if(!soundTimeCounter)
1116 {
1117 soundTimeCounter = 5;
1118 if(curAlSound != alSound)
1119 {
1120 curAlSound = curAlSoundPtr = alSound;
1121 curAlLengthLeft = alLengthLeft;
1122 }
1123 if(curAlSound)
1124 {
1125 if(*curAlSoundPtr)
1126 {
1127 alOut(alFreqL, *curAlSoundPtr);
1128 alOut(alFreqH, alBlock);
1129 }
1130 else alOut(alFreqH, 0);
1131 curAlSoundPtr++;
1132 curAlLengthLeft--;
1133 if(!curAlLengthLeft)
1134 {
1135 curAlSound = alSound = 0;
1136 SoundNumber = (soundnames) 0;
1137 SoundPriority = 0;
1138 alOut(alFreqH, 0);
1139 }
1140 }
1141 }
1142 if(sqActive)
1143 {
1144 do
1145 {
1146 if(sqHackTime > alTimeCount) break;
1147 sqHackTime = alTimeCount + *(sqHackPtr+1);
1148 alOut(*(byte *) sqHackPtr, *(((byte *) sqHackPtr)+1));
1149 sqHackPtr += 2;
1150 sqHackLen -= 4;
1151 }
1152 while(sqHackLen>0);
1153 alTimeCount++;
1154 if(!sqHackLen)
1155 {
1156 sqHackPtr = sqHack;
1157 sqHackLen = sqHackSeqLen;
1158 sqHackTime = 0;
1159 alTimeCount = 0;
1160 }
1161 }
1162 numreadysamples = samplesPerMusicTick;
1163 }
1164#endif
1165}
1166
1167///////////////////////////////////////////////////////////////////////////
1168//
1169// SD_Startup() - starts up the Sound Mgr
1170// Detects all additional sound hardware and installs my ISR
1171//
1172///////////////////////////////////////////////////////////////////////////
1173void
1174SD_Startup(void)
1175{
1176#ifdef SOUND_ENABLE
1177 int i;
1178
1179 if (SD_Started)
1180 return;
1181
1182 if(Mix_OpenAudio(param_samplerate, AUDIO_S16, 2, param_audiobuffer))
1183 {
1184 printf("Unable to open audio: %s\n", Mix_GetError());
1185 return;
1186 }
1187
1188 Mix_ReserveChannels(2); // reserve player and boss weapon channels
1189 Mix_GroupChannels(2, MIX_CHANNELS-1, 1); // group remaining channels
1190
1191 // Init music
1192
1193 samplesPerMusicTick = param_samplerate / 700; // SDL_t0FastAsmService played at 700Hz
1194
1195 if(!(OPL_ptr = YM3812Init((void*)1,3579545,param_samplerate)))
1196 {
1197 //printf("Unable to create virtual OPL!!\n");
1198 }
1199
1200 for(i=1;i<0xf6;i++)
1201 YM3812Write(OPL_ptr,i,0);
1202
1203 YM3812Write(OPL_ptr,1,0x20); // Set WSE=1
1204// YM3812Write(0,8,0); // Set CSM=0 & SEL=0 // already set in for statement
1205
1206 Mix_HookMusic(SDL_IMFMusicPlayer, 0);
1207 Mix_ChannelFinished(SD_ChannelFinished);
1208 AdLibPresent = true;
1209 SoundBlasterPresent = true;
1210
1211 alTimeCount = 0;
1212
1213 SD_SetSoundMode(sdm_Off);
1214 SD_SetMusicMode(smm_Off);
1215
1216 SDL_SetupDigi();
1217
1218 SD_Started = true;
1219#endif
1220}
1221
1222///////////////////////////////////////////////////////////////////////////
1223//
1224// SD_Shutdown() - shuts down the Sound Mgr
1225// Removes sound ISR and turns off whatever sound hardware was active
1226//
1227///////////////////////////////////////////////////////////////////////////
1228void
1229SD_Shutdown(void)
1230{
1231#ifdef SOUND_ENABLE
1232 if (!SD_Started)
1233 return;
1234
1235 SD_MusicOff();
1236 SD_StopSound();
1237
1238 for(int i = 0; i < STARTMUSIC - STARTDIGISOUNDS; i++)
1239 {
1240 if(SoundChunks[i]) Mix_FreeChunk(SoundChunks[i]);
1241 if(SoundBuffers[i]) free(SoundBuffers[i]);
1242 }
1243
1244 free(DigiList);
1245
1246 SD_Started = false;
1247#endif
1248}
1249
1250///////////////////////////////////////////////////////////////////////////
1251//
1252// SD_PositionSound() - Sets up a stereo imaging location for the next
1253// sound to be played. Each channel ranges from 0 to 15.
1254//
1255///////////////////////////////////////////////////////////////////////////
1256void
1257SD_PositionSound(int leftvol,int rightvol)
1258{
1259#ifdef SOUND_ENABLE
1260 LeftPosition = leftvol;
1261 RightPosition = rightvol;
1262 nextsoundpos = true;
1263#endif
1264}
1265
1266///////////////////////////////////////////////////////////////////////////
1267//
1268// SD_PlaySound() - plays the specified sound on the appropriate hardware
1269//
1270///////////////////////////////////////////////////////////////////////////
1271boolean
1272SD_PlaySound(soundnames sound)
1273{
1274#ifdef SOUND_ENABLE
1275 boolean ispos;
1276 SoundCommon *s;
1277 int lp,rp;
1278
1279 lp = LeftPosition;
1280 rp = RightPosition;
1281 LeftPosition = 0;
1282 RightPosition = 0;
1283
1284 ispos = nextsoundpos;
1285 nextsoundpos = false;
1286
1287 if (sound == -1 || (DigiMode == sds_Off && SoundMode == sdm_Off))
1288 return 0;
1289
1290 s = (SoundCommon *) SoundTable[sound];
1291
1292 if ((SoundMode != sdm_Off) && !s)
1293 Quit("SD_PlaySound() - Uncached sound");
1294
1295 if ((DigiMode != sds_Off) && (DigiMap[sound] != -1))
1296 {
1297 if ((DigiMode == sds_PC) && (SoundMode == sdm_PC))
1298 {
1299#ifdef NOTYET
1300 if (s->priority < SoundPriority)
1301 return 0;
1302
1303 SDL_PCStopSound();
1304
1305 SD_PlayDigitized(DigiMap[sound],lp,rp);
1306 SoundPositioned = ispos;
1307 SoundNumber = sound;
1308 SoundPriority = s->priority;
1309#else
1310 return 0;
1311#endif
1312 }
1313 else
1314 {
1315#ifdef NOTYET
1316 if (s->priority < DigiPriority)
1317 return(false);
1318#endif
1319
1320 int channel = SD_PlayDigitized(DigiMap[sound], lp, rp);
1321 SoundPositioned = ispos;
1322 DigiNumber = sound;
1323 DigiPriority = s->priority;
1324 return channel + 1;
1325 }
1326
1327 return(true);
1328 }
1329
1330 if (SoundMode == sdm_Off)
1331 return 0;
1332
1333 if (!s->length)
1334 Quit("SD_PlaySound() - Zero length sound");
1335 if (s->priority < SoundPriority)
1336 return 0;
1337
1338 switch (SoundMode)
1339 {
1340 case sdm_PC:
1341// SDL_PCPlaySound((PCSound *)s);
1342 break;
1343 case sdm_AdLib:
1344 SDL_ALPlaySound((AdLibSound *)s);
1345 break;
1346 }
1347
1348 SoundNumber = sound;
1349 SoundPriority = s->priority;
1350
1351 return 0;
1352#endif
1353 return 0;
1354}
1355
1356///////////////////////////////////////////////////////////////////////////
1357//
1358// SD_SoundPlaying() - returns the sound number that's playing, or 0 if
1359// no sound is playing
1360//
1361///////////////////////////////////////////////////////////////////////////
1362word
1363SD_SoundPlaying(void)
1364{
1365#ifdef SOUND_ENABLE
1366 boolean result = false;
1367
1368 switch (SoundMode)
1369 {
1370 case sdm_PC:
1371 result = pcSound? true : false;
1372 break;
1373 case sdm_AdLib:
1374 result = alSound? true : false;
1375 break;
1376 }
1377
1378 if (result)
1379 return(SoundNumber);
1380 else
1381 return(false);
1382#endif
1383 return false;
1384}
1385
1386///////////////////////////////////////////////////////////////////////////
1387//
1388// SD_StopSound() - if a sound is playing, stops it
1389//
1390///////////////////////////////////////////////////////////////////////////
1391void
1392SD_StopSound(void)
1393{
1394#ifdef SOUND_ENABLE
1395 if (DigiPlaying)
1396 SD_StopDigitized();
1397
1398 switch (SoundMode)
1399 {
1400 case sdm_PC:
1401// SDL_PCStopSound();
1402 break;
1403 case sdm_AdLib:
1404 SDL_ALStopSound();
1405 break;
1406 }
1407
1408 SoundPositioned = false;
1409
1410 SDL_SoundFinished();
1411#endif
1412}
1413
1414///////////////////////////////////////////////////////////////////////////
1415//
1416// SD_WaitSoundDone() - waits until the current sound is done playing
1417//
1418///////////////////////////////////////////////////////////////////////////
1419void
1420SD_WaitSoundDone(void)
1421{
1422#ifdef SOUND_ENABLE
1423 while (SD_SoundPlaying())
1424 SDL_Delay(5);
1425#endif
1426}
1427
1428///////////////////////////////////////////////////////////////////////////
1429//
1430// SD_MusicOn() - turns on the sequencer
1431//
1432///////////////////////////////////////////////////////////////////////////
1433void
1434SD_MusicOn(void)
1435{
1436#ifdef SOUND_ENABLE
1437 sqActive = true;
1438#endif
1439}
1440
1441///////////////////////////////////////////////////////////////////////////
1442//
1443// SD_MusicOff() - turns off the sequencer and any playing notes
1444// returns the last music offset for music continue
1445//
1446///////////////////////////////////////////////////////////////////////////
1447int
1448SD_MusicOff(void)
1449{
1450#ifdef SOUND_ENABLE
1451 word i;
1452
1453 sqActive = false;
1454 switch (MusicMode)
1455 {
1456 case smm_AdLib:
1457 alOut(alEffects, 0);
1458 for (i = 0;i < sqMaxTracks;i++)
1459 alOut(alFreqH + i + 1, 0);
1460 break;
1461 }
1462
1463 return (int) (sqHackPtr-sqHack);
1464#endif
1465}
1466
1467///////////////////////////////////////////////////////////////////////////
1468//
1469// SD_StartMusic() - starts playing the music pointed to
1470//
1471///////////////////////////////////////////////////////////////////////////
1472void
1473SD_StartMusic(int chunk)
1474{
1475#ifdef SOUND_ENABLE
1476 SD_MusicOff();
1477
1478 if (MusicMode == smm_AdLib)
1479 {
1480 int32_t chunkLen = CA_CacheAudioChunk(chunk);
1481 sqHack = (word *)(void *) audiosegs[chunk]; // alignment is correct
1482 if(*sqHack == 0) sqHackLen = sqHackSeqLen = chunkLen;
1483 else sqHackLen = sqHackSeqLen = *sqHack++;
1484 sqHackPtr = sqHack;
1485 sqHackTime = 0;
1486 alTimeCount = 0;
1487 SD_MusicOn();
1488 }
1489#endif
1490}
1491
1492void
1493SD_ContinueMusic(int chunk, int startoffs)
1494{
1495#ifdef SOUND_ENABLE
1496 SD_MusicOff();
1497
1498 if (MusicMode == smm_AdLib)
1499 {
1500 int32_t chunkLen = CA_CacheAudioChunk(chunk);
1501 sqHack = (word *)(void *) audiosegs[chunk]; // alignment is correct
1502 if(*sqHack == 0) sqHackLen = sqHackSeqLen = chunkLen;
1503 else sqHackLen = sqHackSeqLen = *sqHack++;
1504 sqHackPtr = sqHack;
1505
1506 if(startoffs >= sqHackLen)
1507 {
1508 Quit("SD_StartMusic: Illegal startoffs provided!");
1509 }
1510
1511 // fast forward to correct position
1512 // (needed to reconstruct the instruments)
1513
1514 for(int i = 0; i < startoffs; i += 2)
1515 {
1516 byte reg = *(byte *)sqHackPtr;
1517 byte val = *(((byte *)sqHackPtr) + 1);
1518 if(reg >= 0xb1 && reg <= 0xb8) val &= 0xdf; // disable play note flag
1519 else if(reg == 0xbd) val &= 0xe0; // disable drum flags
1520
1521 alOut(reg,val);
1522 sqHackPtr += 2;
1523 sqHackLen -= 4;
1524 }
1525 sqHackTime = 0;
1526 alTimeCount = 0;
1527
1528 SD_MusicOn();
1529 }
1530#endif
1531}
1532
1533///////////////////////////////////////////////////////////////////////////
1534//
1535// SD_FadeOutMusic() - starts fading out the music. Call SD_MusicPlaying()
1536// to see if the fadeout is complete
1537//
1538///////////////////////////////////////////////////////////////////////////
1539void
1540SD_FadeOutMusic(void)
1541{
1542#ifdef SOUND_ENABLE
1543 switch (MusicMode)
1544 {
1545 case smm_AdLib:
1546 // DEBUG - quick hack to turn the music off
1547 SD_MusicOff();
1548 break;
1549 }
1550#endif
1551}
1552
1553///////////////////////////////////////////////////////////////////////////
1554//
1555// SD_MusicPlaying() - returns true if music is currently playing, false if
1556// not
1557//
1558///////////////////////////////////////////////////////////////////////////
1559boolean
1560SD_MusicPlaying(void)
1561{
1562#ifdef SOUND_ENABLE
1563 boolean result;
1564
1565 switch (MusicMode)
1566 {
1567 case smm_AdLib:
1568 result = sqActive;
1569 break;
1570 default:
1571 result = false;
1572 break;
1573 }
1574
1575 return(result);
1576#endif
1577 return false;
1578}