summaryrefslogtreecommitdiff
path: root/apps/plugins/sdl/progs/wolf3d/id_sd.c
diff options
context:
space:
mode:
authorFranklin Wei <git@fwei.tk>2019-07-07 22:00:20 -0400
committerFranklin Wei <git@fwei.tk>2019-07-09 11:20:55 -0400
commit3f59fc8b771625aca9c3aefe03cf1038d8461963 (patch)
treee0623a323613baa0b0993411b38bcaed144b27ed /apps/plugins/sdl/progs/wolf3d/id_sd.c
parent439a0d1d91fa040d261fc39b87278bc9f5391dcc (diff)
downloadrockbox-3f59fc8b771625aca9c3aefe03cf1038d8461963.tar.gz
rockbox-3f59fc8b771625aca9c3aefe03cf1038d8461963.zip
Wolfenstein 3-D!
This is a port of Wolf4SDL, which is derived from the original id software source release. The port runs on top of the SDL plugin runtime and is loaded as an overlay. Licensing of the game code is not an issue, as discussed below (essentially, the Debian project treats Wolf4SDL as GPLv2, with an email from John Carmack backing it up): http://forums.rockbox.org/index.php?topic=52872 Included is a copy of MAME's Yamaha OPL sound chip emulator (fmopl_gpl.c). This file was not part of the original Wolf4SDL source (which includes a non-GPL'd version), but was rather rebased from from a later MAME source which had been relicensed to GPLv2. Change-Id: I64c2ba035e0be7e2f49252f40640641416613439
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}