# Correct the needed linklibs in curl-config also.
[AROS-Contrib.git] / Games / Doom / aros_sound.c
blob65c8c418ee0fca876e3c303c3c366a735392afa5
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdarg.h>
4 #include <string.h>
6 #include <exec/exec.h>
7 #include <dos/dos.h>
8 #include <graphics/gfxbase.h>
9 #include <devices/ahi.h>
11 #include <proto/exec.h>
12 #include <proto/dos.h>
13 #include <proto/graphics.h>
15 /* #include <math.h> */
17 #include "z_zone.h"
19 #include "i_system.h"
20 #include "i_sound.h"
21 #include "m_argv.h"
22 #include "m_misc.h"
23 #include "w_wad.h"
24 #include "m_swap.h"
26 #include "doomdef.h"
28 // Any value of numChannels set
29 // by the defaults code in M_misc is now clobbered by I_InitSound().
30 // number of channels available for sound effects
32 extern int numChannels;
34 /**********************************************************************/
36 // NUM_VOICES = SFX_VOICES + MUS_VOICES
37 #define NUM_VOICES 64
38 #define SFX_VOICES 32
39 #define MUS_VOICES 32
41 struct Channel {
42 float pitch;
43 float pan;
44 float vol;
45 float ltvol;
46 float rtvol;
47 int instrument;
48 int map[128];
51 struct midiHdr {
52 ULONG rate;
53 ULONG loop; // 16.16 fixed pt
54 ULONG length; // 16.16 fixed pt
55 UWORD base; // note base of sample
56 BYTE sample[8]; // actual length varies
59 struct Voice {
60 BYTE *wave;
61 float index;
62 float step;
63 ULONG loop;
64 ULONG length;
65 float ltvol;
66 float rtvol;
67 UWORD base;
68 UWORD flags;
69 int chan;
72 static int voice_avail[MUS_VOICES];
73 static struct Channel mus_channel[16];
74 static struct Voice audVoice[NUM_VOICES];
75 static struct Voice midiVoice[256];
77 // The actual lengths of all sound effects.
78 static int lengths[NUMSFX];
80 static struct Task *sound_task = NULL;
81 static struct MsgPort *audio_mp = NULL;
82 static struct AHIRequest *audio_io1 = NULL;
83 static struct AHIRequest *audio_io2 = NULL;
85 static WORD *buffer1 = NULL;
86 static WORD *buffer2 = NULL;
88 static ULONG NUM_SAMPLES = 1260; // 1260 = 35Hz, 630 = 70Hz, 315 = 140Hz
89 static ULONG BUFFER_SIZE = (1260 * 2 * 2); // stereo 16-bit samples
90 static ULONG BEATS_PER_PASS = 4; // 4 = 35Hz, 2 = 70Hz, 1 = 140Hz
92 static int sound_status = 0;
94 static BOOL audio_is_open = FALSE;
96 static int changepitch;
98 /* sampling freq (Hz) for each pitch step when changepitch is TRUE
99 calculated from (2^((i-128)/64))*11025
100 I'm not sure if this is the right formula */
101 static UWORD freqs[256] = {
102 2756, 2786, 2817, 2847, 2878, 2910, 2941, 2973,
103 3006, 3038, 3072, 3105, 3139, 3173, 3208, 3242,
104 3278, 3313, 3350, 3386, 3423, 3460, 3498, 3536,
105 3574, 3613, 3653, 3692, 3733, 3773, 3814, 3856,
106 3898, 3940, 3983, 4027, 4071, 4115, 4160, 4205,
107 4251, 4297, 4344, 4391, 4439, 4487, 4536, 4586,
108 4635, 4686, 4737, 4789, 4841, 4893, 4947, 5001,
109 5055, 5110, 5166, 5222, 5279, 5336, 5394, 5453,
110 5513, 5573, 5633, 5695, 5757, 5819, 5883, 5947,
111 6011, 6077, 6143, 6210, 6278, 6346, 6415, 6485,
112 6556, 6627, 6699, 6772, 6846, 6920, 6996, 7072,
113 7149, 7227, 7305, 7385, 7465, 7547, 7629, 7712,
114 7796, 7881, 7967, 8053, 8141, 8230, 8319, 8410,
115 8501, 8594, 8688, 8782, 8878, 8975, 9072, 9171,
116 9271, 9372, 9474, 9577, 9681, 9787, 9893, 10001,
117 10110, 10220, 10331, 10444, 10558, 10673, 10789, 10906,
118 11025, 11145, 11266, 11389, 11513, 11638, 11765, 11893,
119 12023, 12154, 12286, 12420, 12555, 12692, 12830, 12970,
120 13111, 13254, 13398, 13544, 13691, 13841, 13991, 14144,
121 14298, 14453, 14611, 14770, 14931, 15093, 15258, 15424,
122 15592, 15761, 15933, 16107, 16282, 16459, 16639, 16820,
123 17003, 17188, 17375, 17564, 17756, 17949, 18144, 18342,
124 18542, 18744, 18948, 19154, 19363, 19574, 19787, 20002,
125 20220, 20440, 20663, 20888, 21115, 21345, 21578, 21812,
126 22050, 22290, 22533, 22778, 23026, 23277, 23530, 23787,
127 24046, 24308, 24572, 24840, 25110, 25384, 25660, 25940,
128 26222, 26508, 26796, 27088, 27383, 27681, 27983, 28287,
129 28595, 28907, 29221, 29540, 29861, 30187, 30515, 30848,
130 31183, 31523, 31866, 32213, 32564, 32919, 33277, 33639,
131 34006, 34376, 34750, 35129, 35511, 35898, 36289, 36684,
132 37084, 37487, 37896, 38308, 38725, 39147, 39573, 40004,
133 40440, 40880, 41325, 41775, 42230, 42690, 43155, 43625
136 static int note_table[128] = {
137 65536/64,69433/64,73562/64,77936/64,82570/64,87480/64,92682/64,98193/64,104032/64,110218/64,116772/64,123715/64,
138 65536/32,69433/32,73562/32,77936/32,82570/32,87480/32,92682/32,98193/32,104032/32,110218/32,116772/32,123715/32,
139 65536/16,69433/16,73562/16,77936/16,82570/16,87480/16,92682/16,98193/16,104032/16,110218/16,116772/16,123715/16,
140 65536/8,69433/8,73562/8,77936/8,82570/8,87480/8,92682/8,98193/8,104032/8,110218/8,116772/8,123715/8,
141 65536/4,69433/4,73562/4,77936/4,82570/4,87480/4,92682/4,98193/4,104032/4,110218/4,116772/4,123715/4,
142 65536/2,69433/2,73562/2,77936/2,82570/2,87480/2,92682/2,98193/2,104032/2,110218/2,116772/2,123715/2,
143 65536,69433,73562,77936,82570,87480,92682,98193,104032,110218,116772,123715,
144 65536*2,69433*2,73562*2,77936*2,82570*2,87480*2,92682*2,98193*2,104032*2,110218*2,116772*2,123715*2,
145 65536*4,69433*4,73562*4,77936*4,82570*4,87480*4,92682*4,98193*4,104032*4,110218*4,116772*4,123715*4,
146 65536*8,69433*8,73562*8,77936*8,82570*8,87480*8,92682*8,98193*8,104032*8,110218*8,116772*8,123715*8,
147 65536*16,69433*16,73562*16,77936*16,82570*16,87480*16,92682*16,98193*16
150 static float pitch_table[256];
152 static float master_vol = 64.0f;
154 /**********************************************************************/
156 ULONG sound_handler(char *args);
158 void Sfx_Start(char *wave, int cnum, int step, int vol, int sep, int length);
159 void Sfx_Update(int cnum, int step, int vol, int sep);
160 void Sfx_Stop(int cnum);
161 int Sfx_Done(int cnum);
163 void Mus_SetVol(int vol);
164 int Mus_Register(void *musdata);
165 void Mus_Unregister(int handle);
166 void Mus_Play(int handle, int looping);
167 void Mus_Stop(int handle);
168 void Mus_Pause(int handle);
169 void Mus_Resume(int handle);
171 /**********************************************************************/
173 // This function loads the sound data for sfxname from the WAD lump,
174 // and returns a ptr to the data in fastmem and its length in len.
176 static void *getsfx (char *sfxname, int *len)
178 unsigned char *sfx;
179 unsigned char *cnvsfx;
180 int i;
181 int size;
182 char name[32];
183 int sfxlump;
185 // Get the sound data from the WAD, allocate lump
186 // in zone memory.
187 sprintf(name, "ds%s", sfxname);
189 // Now, there is a severe problem with the
190 // sound handling, in it is not (yet/anymore)
191 // gamemode aware. That means, sounds from
192 // DOOM II will be requested even with DOOM
193 // shareware.
194 // The sound list is wired into sounds.c,
195 // which sets the external variable.
196 // I do not do runtime patches to that
197 // variable. Instead, we will use a
198 // default sound for replacement.
199 if (W_CheckNumForName(name) == -1)
200 sfxlump = W_GetNumForName("dspistol");
201 else
202 sfxlump = W_GetNumForName (name);
204 size = W_LumpLength (sfxlump);
206 // Debug.
207 // fprintf( stderr, "." );
208 // fprintf( stderr, " -loading %s (lump %d, %d bytes)\n",
209 // sfxname, sfxlump, size );
210 //fflush( stderr );
212 sfx = (unsigned char*)W_CacheLumpNum (sfxlump, PU_STATIC);
214 // Allocate from zone memory.
215 cnvsfx = (unsigned char*)Z_Malloc (size, PU_STATIC, 0);
217 // Now copy and convert offset to signed.
218 for (i = 0; i < size; i++)
219 cnvsfx[i] = sfx[i] ^ 0x80;
221 // Remove the cached lump.
222 Z_Free( sfx );
224 // return length.
225 *len = size;
227 // Return allocated converted data.
228 return (void *)cnvsfx;
231 /**********************************************************************/
232 // Init at program start...
233 void I_InitSound (void)
235 int i;
237 if (M_CheckParm("-nosfx"))
238 return;
240 if (M_CheckParm("-music")) {
241 if (M_CheckParm("-70Hz")) {
242 NUM_SAMPLES = 630;
243 BUFFER_SIZE = NUM_SAMPLES * 2 * 2;
244 BEATS_PER_PASS = 2;
245 fprintf (stderr, "I_InitSound: Playing music at 70Hz.\n");
246 fflush( stderr );
247 } else if (M_CheckParm("-140Hz")) {
248 NUM_SAMPLES = 315;
249 BUFFER_SIZE = NUM_SAMPLES * 2 * 2;
250 BEATS_PER_PASS = 1;
251 fprintf (stderr, "I_InitSound: Playing music at 140Hz.\n");
252 fflush( stderr );
256 sound_status = 0;
258 // create sound handling task
259 sound_task = (struct Task *)CreateNewProcTags( NP_Output, Output(),
260 NP_Input, Input(),
261 NP_Name, (IPTR)"doom_sound_daemon",
262 NP_CloseOutput, FALSE,
263 NP_CloseInput, FALSE,
264 NP_StackSize, 20000,
265 NP_Entry, (IPTR)sound_handler,
266 NP_Priority, 40,
267 TAG_DONE);
268 if (!sound_task) {
269 fprintf (stderr, "I_InitSound: Cannot create sound daemon, no sfx or music.\n");
270 fflush( stderr );
271 return;
273 while (!sound_status)
274 Delay(10);
276 switch (sound_status) {
277 case 1:
278 fprintf (stderr, "I_InitSound: Sound daemon running.\n");
279 fflush( stderr );
280 break;
281 case -1:
282 fprintf (stderr, "I_InitSound: Cannot create audio msgport, no sfx or music.\n");
283 fflush( stderr );
284 return;
285 case -2:
286 fprintf (stderr, "I_InitSound: Cannot create audio request, no sfx or music.\n");
287 fflush( stderr );
288 return;
289 case -3:
290 fprintf (stderr, "I_InitSound: Cannot open AHI device, no sfx or music.\n");
291 fflush( stderr );
292 return;
293 case -4:
294 fprintf (stderr, "I_InitSound: Cannot create double-buffer request, no sfx or music.\n");
295 fflush( stderr );
296 return;
297 case -5:
298 fprintf (stderr, "I_InitSound: Cannot allocate mixing buffers, no sfx or music.\n");
299 fflush( stderr );
300 return;
301 case 2:
302 fprintf (stderr, "I_InitSound: Cannot open MIDI instruments file, no music.\n");
303 fflush( stderr );
304 break; // non-fatal error
305 case 3:
306 fprintf (stderr, "I_InitSound: Cannot alloc memory for MIDI instruments, no music.\n");
307 fflush( stderr );
308 break; // non-fatal error
309 default:
310 fprintf (stderr, "I_InitSound: Error while initializing sound daemon, no sfx or music.\n");
311 fflush( stderr );
312 return;
315 fprintf (stderr, "I_InitSound: AHI audio initialized.\n" );
316 fflush( stderr );
318 changepitch = M_CheckParm ("-changepitch");
320 // Initialize external data (all sounds) at start, keep static.
321 for (i = 1; i < NUMSFX; i++) {
322 // Alias? Example is the chaingun sound linked to pistol.
323 if (!S_sfx[i].link) {
324 // Load data from WAD file.
325 S_sfx[i].data = getsfx(S_sfx[i].name, &lengths[i]);
326 } else {
327 // Previously loaded already?
328 S_sfx[i].data = S_sfx[i].link->data;
329 lengths[i] = lengths[(S_sfx[i].link - S_sfx)/sizeof(sfxinfo_t)];
332 fprintf (stderr, "I_InitSound: Pre-cached all sound data.\n");
333 fflush( stderr );
335 // fill in pitch wheel table
336 for (i=0; i<128; i++)
337 pitch_table[i] = 1.0f + (-3678.0f * (float)(128-i) / 64.0f) / 65536.0f;
338 for (i=0; i<128; i++)
339 pitch_table[i+128] = 1.0f + (3897.0f * (float)i / 64.0f) / 65536.0f;
341 // Finished initialization.
342 fprintf (stderr, "I_InitSound: Sound module ready.\n");
343 fflush( stderr );
346 /**********************************************************************/
347 // ... update sound buffer and audio device at runtime...
348 void I_UpdateSound (void)
352 /**********************************************************************/
353 // ... update sound buffer and audio device at runtime...
354 void I_SubmitSound (void)
358 /**********************************************************************/
359 // ... shut down and relase at program termination.
360 void I_ShutdownSound (void)
362 // fprintf (stderr, "I_ShutdownSound:");
363 // fflush( stderr );
365 if (sound_status > 0) {
366 sound_status = 0xDEADBEEF; // DIE, DAEMON! DIE!!
367 while (sound_status)
368 Delay(10);
371 // fprintf (stderr, " Sound module closed.\n");
372 // fflush( stderr );
375 /**********************************************************************/
376 /**********************************************************************/
378 // SFX I/O
381 /**********************************************************************/
382 // Initialize number of channels
383 void I_SetChannels (void)
387 /**********************************************************************/
388 // Get raw data lump index for sound descriptor.
389 int I_GetSfxLumpNum (sfxinfo_t *sfx)
391 char namebuf[9];
393 // fprintf (stderr, "I_GetSfxLumpNum()\n");
395 sprintf(namebuf, "ds%s", sfx->name);
396 return W_GetNumForName(namebuf);
399 /**********************************************************************/
400 // Starts a sound in a particular sound channel.
401 int I_StartSound (
402 int id,
403 int cnum,
404 int vol,
405 int sep,
406 int pitch,
407 int priority )
409 // fprintf (stderr, "I_StartSound(%d,%d,%d,%d,%d,%d)\n", id, cnum, vol, sep, pitch, priority);
411 if (audio_is_open) {
412 I_StopSound(cnum);
413 Sfx_Start (S_sfx[id].data, cnum, changepitch ? freqs[pitch] : 11025,
414 vol, sep, lengths[id]);
416 return cnum;
419 /**********************************************************************/
420 // Stops a sound channel.
421 void I_StopSound(int handle)
423 // fprintf (stderr, "I_StopSound(%d)\n", handle);
425 if (audio_is_open)
426 Sfx_Stop(handle);
429 /**********************************************************************/
430 // Called by S_*() functions
431 // to see if a channel is still playing.
432 // Returns 0 if no longer playing, 1 if playing.
433 int I_SoundIsPlaying(int handle)
435 // fprintf (stderr, "I_SoundIsPlaying(%d)\n", handle);
437 if (audio_is_open)
438 return Sfx_Done(handle) ? 1 : 0;
440 return 0;
443 /**********************************************************************/
444 // Updates the volume, separation,
445 // and pitch of a sound channel.
446 void
447 I_UpdateSoundParams
448 ( int handle,
449 int vol,
450 int sep,
451 int pitch )
453 // fprintf (stderr, "I_UpdateSoundParams(%d,%d,%d,%d)\n", handle, vol, sep, pitch);
455 if (audio_is_open)
456 Sfx_Update(handle, changepitch ? freqs[pitch] : 11025, vol, sep);
459 /**********************************************************************/
460 /**********************************************************************/
462 // MUSIC API.
465 static int musicdies=-1;
466 static int music_okay = 0;
468 static APTR midi_instruments = NULL;
470 static UWORD score_len, score_start, inst_cnt;
471 static void *score_data;
472 static UBYTE *score_ptr;
474 static int mus_delay = 0;
475 static int mus_playing = 0;
476 static int mus_looping = 0;
477 static float mus_volume = 1.0f;
479 /**********************************************************************/
481 // MUSIC I/O
483 void I_InitMusic(void)
485 fprintf (stderr, "I_InitMusic:");
486 fflush( stderr );
488 if (M_CheckParm("-music") && (music_okay == 1)) {
489 fprintf (stderr, " Music okay.\n");
490 fflush( stderr );
492 if (M_CheckParm("-70Hz")) {
493 NUM_SAMPLES = 630;
494 BUFFER_SIZE = NUM_SAMPLES * 2 * 2;
495 BEATS_PER_PASS = 2;
496 } else if (M_CheckParm("-140Hz")) {
497 NUM_SAMPLES = 315;
498 BUFFER_SIZE = NUM_SAMPLES * 2 * 2;
499 BEATS_PER_PASS = 1;
502 return;
505 music_okay = 0;
506 fprintf (stderr, " No music.\n");
507 fflush( stderr );
510 /**********************************************************************/
511 void I_ShutdownMusic(void)
513 // fprintf (stderr, "I_ShutdownMusic()\n");
516 /**********************************************************************/
517 // Volume.
518 void I_SetMusicVolume(int volume)
520 // fprintf (stderr, "I_SetMusicVolume(%d)\n", volume);
522 snd_MusicVolume = volume;
524 if (music_okay)
525 Mus_SetVol(volume);
528 /**********************************************************************/
529 // PAUSE game handling.
530 void I_PauseSong(int handle)
532 // fprintf (stderr, "I_PauseSong(%d)\n", handle);
534 if (music_okay)
535 Mus_Pause(handle);
538 /**********************************************************************/
539 void I_ResumeSong(int handle)
541 // fprintf (stderr, "I_ResumeSong(%d)\n", handle);
543 if (music_okay)
544 Mus_Resume(handle);
547 /**********************************************************************/
548 // Registers a song handle to song data.
549 int I_RegisterSong(void *data)
551 // fprintf (stderr, "I_RegisterSong(%08x)\n", data);
553 if (music_okay)
554 return Mus_Register(data);
556 return 0;
559 /**********************************************************************/
560 // Called by anything that wishes to start music.
561 // plays a song, and when the song is done,
562 // starts playing it again in an endless loop.
563 // Horrible thing to do, considering.
564 void
565 I_PlaySong
566 ( int handle,
567 int looping )
569 // fprintf (stderr, "I_PlaySong(%d,%d)\n", handle, looping);
571 if (music_okay)
572 Mus_Play(handle, looping);
574 musicdies = gametic + TICRATE*30;
577 /**********************************************************************/
578 // Stops a song over 3 seconds.
579 void I_StopSong(int handle)
581 // fprintf (stderr, "I_StopSong(%d)\n", handle);
583 if (music_okay)
584 Mus_Stop(handle);
586 musicdies = 0;
589 /**********************************************************************/
590 // See above (register), then think backwards
591 void I_UnRegisterSong(int handle)
593 // fprintf (stderr, "I_UnRegisterSong(%d)\n", handle);
595 if (music_okay)
596 Mus_Unregister(handle);
599 /**********************************************************************/
601 void _STDaudio_cleanup (void)
603 I_ShutdownSound ();
604 I_ShutdownMusic ();
607 /**********************************************************************/
609 void Sfx_Start(char *wave, int cnum, int step, int volume, int seperation, int length)
611 float vol = (float)volume;
612 float sep = (float)seperation;
614 vol = (volume > 15) ? 127.0f : vol * 8.0f + 7.0f;
616 Forbid();
617 audVoice[cnum].wave = wave + 8;
618 audVoice[cnum].index = 0.0f;
619 audVoice[cnum].step = (float)step / 44100.0f;
620 audVoice[cnum].loop = 0;
621 audVoice[cnum].length = length - 8;
622 audVoice[cnum].ltvol = (vol - (vol * sep * sep) / 65536.0f) / 127.0f;
623 sep -= 256.0f;
624 audVoice[cnum].rtvol = (vol - (vol * sep * sep) / 65536.0f) / 127.0f;
625 audVoice[cnum].flags = 0x81;
626 Permit();
629 void Sfx_Update(int cnum, int step, int volume, int seperation)
631 float vol = (float)volume;
632 float sep = (float)seperation;
634 vol = (volume > 15) ? 127.0f : vol * 8.0f + 7.0f;
636 Forbid();
637 audVoice[cnum].step = (float)step / 44100.0f;
638 audVoice[cnum].ltvol = (vol - (vol * sep * sep) / 65536.0f) / 127.0f;
639 sep -= 256.0f;
640 audVoice[cnum].rtvol = (vol - (vol * sep * sep) / 65536.0f) / 127.0f;
641 Permit();
644 void Sfx_Stop(int cnum)
646 Forbid();
647 audVoice[cnum].flags &= 0xFE;
648 Permit();
651 int Sfx_Done(int cnum)
653 int done;
655 Forbid();
656 done = (audVoice[cnum].flags & 0x01) ? (int)audVoice[cnum].index + 1 : 0;
657 Permit();
658 return done;
661 /**********************************************************************/
663 void Mus_SetVol(int vol)
665 mus_volume = (vol > 15) ? 1.0f : ((float)vol * 8.0f + 7.0f) / 127.0f;
668 int Mus_Register(void *musdata)
670 ULONG *lptr = (ULONG *)musdata;
671 UWORD *wptr = (UWORD *)musdata;
672 //UBYTE *bptr = (UBYTE *)musdata;
673 //UWORD ix, iy;
675 Mus_Unregister(1);
676 // music won't start playing until mus_playing set at this point
678 if(lptr[0] != SWAPLONG(0x1a53554d)) // 0x4d55531a
679 return 0; // "MUS",26 always starts a vaild MUS file
680 score_len = SWAPSHORT(wptr[2]); // score length
681 if(!score_len)
682 return 0; // illegal score length
683 score_start = SWAPSHORT(wptr[3]); // score start
684 if(score_start < 18)
685 return 0; // illegal score start offset
687 inst_cnt = SWAPSHORT(wptr[6]); // instrument count
688 if(!inst_cnt)
689 return 0; // illegal instrument count
691 // okay, MUS data seems to check out
693 score_data = musdata;
694 return 1;
697 void Mus_Unregister(int handle)
699 Mus_Stop(handle);
700 // music won't start playing until mus_playing set at this point
702 score_data = 0;
703 score_len = 0;
704 score_start = 0;
705 inst_cnt = 0;
708 void Mus_Play(int handle, int looping)
710 if (!handle)
711 return;
713 mus_looping = looping;
714 mus_playing = 2; // 2 = play from start
717 void Mus_Stop(int handle)
719 int ix;
721 if(mus_playing) {
722 mus_playing = -1; // stop playing
723 while (mus_playing)
724 Delay(10);
727 // disable instruments in score (just disable them all)
728 for (ix=SFX_VOICES; ix<NUM_VOICES; ix++)
729 audVoice[ix].flags = 0x00; // disable voice
731 mus_looping = 0;
732 mus_delay = 0;
735 void Mus_Pause(int handle)
737 mus_playing = 0; // 0 = not playing
740 void Mus_Resume(int handle)
742 mus_playing = 1; // 1 = play from current position
745 /**********************************************************************/
747 void fill_buffer(WORD *buffer)
749 float index;
750 float step;
751 ULONG loop;
752 ULONG length;
753 float ltvol;
754 float rtvol;
755 BYTE *wvbuff;
756 WORD *smpbuff = buffer;
757 float sample;
758 int ix;
759 int iy;
761 // process music if playing
762 if (mus_playing) {
763 if (mus_playing < 0)
764 mus_playing = 0; // music now off
765 else {
766 if (mus_playing > 1) {
767 mus_playing = 1;
768 // start music from beginning
769 score_ptr = (UBYTE *)((ULONG)score_data + (ULONG)score_start);
771 mus_delay -= BEATS_PER_PASS; // 1=140Hz, 2=70Hz, 4=35Hz
772 if (mus_delay <= 0) {
773 UBYTE event;
774 UBYTE note;
775 UBYTE time;
776 UBYTE ctrl;
777 UBYTE value;
778 int next_time;
779 int channel;
780 int voice;
781 int inst;
782 float volume;
783 float pan;
785 nextEvent: // next event
786 do {
787 event = *score_ptr++;
788 switch((event >> 4) & 7) {
789 case 0: // Release
790 channel = (int)(event & 15);
791 note = *score_ptr++;
792 note &= 0x7f;
793 voice = mus_channel[channel].map[(ULONG)note] - 1;
794 if (voice >= 0) {
795 mus_channel[channel].map[(ULONG)note] = 0; // clear mapping
796 voice_avail[voice] = 0; // voice available
797 audVoice[voice + SFX_VOICES].flags |= 0x02; // voice releasing
799 break;
800 case 1: // Play note
801 channel = (int)(event & 15);
802 note = *score_ptr++;
803 volume = -1.0f;
804 if (note & 0x80) { // set volume as well
805 note &= 0x7f;
806 volume = (float)*score_ptr++;
808 for (voice=0; voice<MUS_VOICES; voice++) {
809 if (!voice_avail[voice])
810 break; // found free voice
812 if (voice < MUS_VOICES) {
813 voice_avail[voice] = 1; // in use
814 mus_channel[channel].map[(ULONG)note] = voice + 1;
815 if (volume >= 0.0f) {
816 mus_channel[channel].vol = volume;
817 pan = mus_channel[channel].pan;
818 mus_channel[channel].ltvol = (volume - (volume * pan * pan) / 65536.0f) / 127.0f;
819 pan -= 256.0f;
820 mus_channel[channel].rtvol = (volume - (volume * pan * pan) / 65536.0f) / 127.0f;
822 audVoice[voice + SFX_VOICES].ltvol = mus_channel[channel].ltvol;
823 audVoice[voice + SFX_VOICES].rtvol = mus_channel[channel].rtvol;
824 if (channel != 15) {
825 inst = mus_channel[channel].instrument;
826 audVoice[voice + SFX_VOICES].chan = channel; // back link for pitch wheel
827 audVoice[voice + SFX_VOICES].wave = midiVoice[inst].wave;
828 audVoice[voice + SFX_VOICES].index = 0.0f;
829 audVoice[voice + SFX_VOICES].step = (float)note_table[(72 - midiVoice[inst].base + (ULONG)note) & 0x7f] / 262144.0f;
830 audVoice[voice + SFX_VOICES].loop = midiVoice[inst].loop >> 16;
831 audVoice[voice + SFX_VOICES].length = midiVoice[inst].length >> 16;
832 audVoice[voice + SFX_VOICES].flags = 0x01; // enable voice
833 } else {
834 // percussion channel - note is percussion instrument
835 inst = (ULONG)note + 100;
836 audVoice[voice + SFX_VOICES].chan = channel; // back link for pitch wheel
837 audVoice[voice + SFX_VOICES].wave = midiVoice[inst].wave;
838 audVoice[voice + SFX_VOICES].index = 0.0f;
839 audVoice[voice + SFX_VOICES].step = 11025.0f / 44100.0f;
840 audVoice[voice + SFX_VOICES].loop = midiVoice[inst].loop >> 16;
841 audVoice[voice + SFX_VOICES].length = midiVoice[inst].length >> 16;
842 audVoice[voice + SFX_VOICES].flags = 0x01; // enable voice
845 break;
846 case 2: // Pitch
847 channel = (int)(event & 15);
848 mus_channel[channel].pitch = pitch_table[(ULONG)*score_ptr++ & 0xff];
849 break;
850 case 3: // Tempo
851 score_ptr++; // skip value - not supported
852 break;
853 case 4: // Change control
854 channel = (int)(event & 15);
855 ctrl = *score_ptr++;
856 value = *score_ptr++;
857 switch(ctrl) {
858 case 0:
859 // set channel instrument
860 mus_channel[channel].instrument = (ULONG)value;
861 mus_channel[channel].pitch = 1.0f;
862 break;
863 case 3:
864 // set channel volume
865 mus_channel[channel].vol = volume = (float)value;
866 pan = mus_channel[channel].pan;
867 mus_channel[channel].ltvol = (volume - (volume * pan * pan) / 65536.0f) / 127.0f;
868 pan -= 256.0f;
869 mus_channel[channel].rtvol = (volume - (volume * pan * pan) / 65536.0f) / 127.0f;
870 break;
871 case 4:
872 // set channel pan
873 mus_channel[channel].pan = pan = (float)value;
874 volume = mus_channel[channel].vol;
875 mus_channel[channel].ltvol = (volume - (volume * pan * pan) / 65536.0f) / 127.0f;
876 pan -= 256.0f;
877 mus_channel[channel].rtvol = (volume - (volume * pan * pan) / 65536.0f) / 127.0f;
878 break;
880 break;
881 case 6: // End score
882 if (mus_looping)
883 score_ptr = (UBYTE *)((ULONG)score_data + (ULONG)score_start);
884 else {
885 for (voice=0; voice<MUS_VOICES; voice++) {
886 audVoice[voice + SFX_VOICES].flags = 0;
887 voice_avail[voice] = 0;
889 mus_delay = 0;
890 mus_playing = 0;
891 goto mix;
893 break;
895 } while (!(event & 0x80)); // not last event
897 // now get the time until the next event(s)
898 next_time = 0;
899 time = *score_ptr++;
900 while (time & 0x80) {
901 // while msb set, accumulate 7 bits
902 next_time |= (ULONG)(time & 0x7f);
903 next_time <<= 7;
904 time = *score_ptr++;
906 next_time |= (ULONG)time;
907 mus_delay += next_time;
908 if (mus_delay <= 0)
909 goto nextEvent;
914 mix:
915 // clear buffer
916 memset((void *)buffer, 0, BUFFER_SIZE);
918 // mix enabled voices
919 for (ix=0; ix<NUM_VOICES; ix++) {
920 if (audVoice[ix].flags & 0x01) {
921 // process enabled voice
922 if (!(audVoice[ix].flags & 0x80) && !(mus_playing))
923 continue; // skip instrument if music not playing
925 index = audVoice[ix].index;
926 step = audVoice[ix].step;
927 loop = audVoice[ix].loop;
928 length = audVoice[ix].length;
929 ltvol = audVoice[ix].ltvol;
930 rtvol = audVoice[ix].rtvol;
931 wvbuff = audVoice[ix].wave;
933 if (!(audVoice[ix].flags & 0x80)) {
934 // special handling for instrument
935 if (audVoice[ix].flags & 0x02) {
936 // releasing
937 ltvol *= 0.90f;
938 rtvol *= 0.90f;
939 audVoice[ix].ltvol = ltvol;
940 audVoice[ix].rtvol = rtvol;
941 if (ltvol <= 0.02f && rtvol <= 0.02f) {
942 audVoice[ix].flags = 0; // disable voice
943 continue; // next voice
946 step *= mus_channel[audVoice[ix].chan & 15].pitch;
947 ltvol *= mus_volume;
948 rtvol *= mus_volume;
951 for (iy=0; iy<(NUM_SAMPLES<<1); iy+=2) {
952 if ((ULONG)index >= length) {
953 if (!(audVoice[ix].flags & 0x80)) {
954 // check if instrument has loop
955 if (loop) {
956 index -= (float)length;
957 index += (float)loop;
958 } else {
959 audVoice[ix].flags = 0; // disable voice
960 break; // exit sample loop
962 } else {
963 audVoice[ix].flags = 0; // disable voice
964 break; // exit sample loop
967 sample = (wvbuff) ? (float)wvbuff[(int)index] : 0.0f; // for safety
968 smpbuff[iy] += (WORD)(sample * ltvol * master_vol);
969 smpbuff[iy + 1] += (WORD)(sample * rtvol * master_vol);
970 index += step;
972 audVoice[ix].index = index;
977 /**********************************************************************/
978 // Need swap routines because the MIDI file was made on the Amiga and
979 // is in big endian format. :)
981 #ifdef __BIG_ENDIAN__
983 #define WSWAP(x) x
984 #define LSWAP(x) x
986 #else
988 UWORD WSWAP(UWORD x)
990 return (UWORD)((x>>8) | (x<<8));
993 ULONG LSWAP(ULONG x)
995 return
996 (x>>24)
997 | ((x>>8) & 0xff00)
998 | ((x<<8) & 0xff0000)
999 | (x<<24);
1002 #endif
1004 /**********************************************************************/
1006 ULONG sound_handler(char *args)
1008 FILE *hnd;
1009 int size;
1010 int i;
1011 ULONG *miptr;
1012 struct midiHdr *mhdr;
1013 int current = 0;
1014 ULONG playing = 0;
1016 // try to initialize AHI
1017 if(!(audio_mp = CreateMsgPort())) {
1018 sound_status = -1;
1019 return 0;
1022 if(!(audio_io1 = (struct AHIRequest *)CreateIORequest(audio_mp, sizeof(struct AHIRequest)))) {
1023 DeleteMsgPort(audio_mp);
1024 sound_status = -2;
1025 return 0;
1027 audio_io1->ahir_Version = 4;
1029 if(OpenDevice(AHINAME, 0, (struct IORequest *)audio_io1, 0)) {
1030 DeleteIORequest((struct IORequest *)audio_io1);
1031 DeleteMsgPort(audio_mp);
1032 sound_status = -3;
1033 return 0;
1036 // init double-buffer iorequest
1037 if(!(audio_io2 = AllocVec(sizeof(struct AHIRequest), MEMF_PUBLIC))) {
1038 CloseDevice((struct IORequest *)audio_io1);
1039 DeleteIORequest((struct IORequest *)audio_io1);
1040 DeleteMsgPort(audio_mp);
1041 sound_status = -4;
1042 return 0;
1044 memcpy(audio_io2, audio_io1, sizeof(struct AHIRequest));
1046 // Allocate mixing buffers
1047 buffer1 = (WORD *)AllocVec(BUFFER_SIZE, MEMF_PUBLIC+MEMF_CLEAR);
1048 buffer2 = (WORD *)AllocVec(BUFFER_SIZE, MEMF_PUBLIC+MEMF_CLEAR);
1050 if(buffer1 == NULL || buffer2 == NULL) {
1051 CloseDevice((struct IORequest *)audio_io1);
1052 DeleteIORequest((struct IORequest *)audio_io1);
1053 DeleteMsgPort(audio_mp);
1054 FreeVec((APTR)audio_io2);
1055 audio_io2 = NULL;
1056 if(buffer1) {
1057 FreeVec((APTR)buffer1);
1058 buffer1 = NULL;
1060 if(buffer2) {
1061 FreeVec((APTR)buffer2);
1062 buffer2 = NULL;
1064 sound_status = -5;
1065 return 0;
1068 numChannels = SFX_VOICES;
1069 audio_is_open = TRUE;
1071 music_okay = 0;
1073 // try to set up MIDI instruments
1074 hnd = fopen("PROGDIR:MIDI_Instruments","rb");
1075 if (hnd) {
1076 fseek(hnd, 0, SEEK_END);
1077 size = ftell(hnd);
1078 fseek(hnd, 0, SEEK_SET);
1080 midi_instruments = AllocVec(size, MEMF_PUBLIC+MEMF_CLEAR);
1081 if (midi_instruments) {
1082 fread((void *)midi_instruments, 1, size, hnd);
1083 fclose(hnd);
1084 // set midiVoice[] from file
1085 miptr = (ULONG *)midi_instruments;
1086 for(i=0; i<256; i++) {
1087 if(i>181 || miptr[i]==0 || LSWAP(miptr[i]) >= size) {
1088 midiVoice[i].wave = 0;
1089 midiVoice[i].index = 0.0f;
1090 midiVoice[i].step = 11025.0f / 44100.0f;
1091 midiVoice[i].loop = 0;
1092 midiVoice[i].length = 2000 << 16;
1093 midiVoice[i].ltvol = 0.0f;
1094 midiVoice[i].rtvol = 0.0f;
1095 midiVoice[i].base = 60;
1096 midiVoice[i].flags = 0x00;
1097 } else {
1098 mhdr = (struct midiHdr *)(midi_instruments + LSWAP(miptr[i]));
1099 midiVoice[i].wave = &mhdr->sample[0];
1100 midiVoice[i].index = 0.0f;
1101 midiVoice[i].step = 11025.0f / 44100.0f;
1102 midiVoice[i].loop = LSWAP(mhdr->loop);
1103 midiVoice[i].length = LSWAP(mhdr->length);
1104 midiVoice[i].ltvol = 0.0f;
1105 midiVoice[i].rtvol = 0.0f;
1106 midiVoice[i].base = WSWAP(mhdr->base);
1107 midiVoice[i].flags = 0x00;
1110 music_okay = 1;
1111 sound_status = 1;
1112 } else {
1113 fclose(hnd);
1114 sound_status = 3; // couldn't allocate memory
1116 } else {
1117 sound_status = 2; // couldn't open MIDI file
1120 // send first (empty) buffer, then enter main loop
1121 audio_io1->ahir_Std.io_Message.mn_Node.ln_Pri = 60;
1122 audio_io1->ahir_Std.io_Data = buffer1;
1123 audio_io1->ahir_Std.io_Length = BUFFER_SIZE;
1124 audio_io1->ahir_Std.io_Offset = 0;
1125 audio_io1->ahir_Std.io_Command = CMD_WRITE;
1126 audio_io1->ahir_Frequency = 44100;
1127 audio_io1->ahir_Volume = 0x10000;
1128 audio_io1->ahir_Type = AHIST_S16S;
1129 audio_io1->ahir_Position = 0x8000;
1130 audio_io1->ahir_Link = NULL;
1131 SendIO((struct IORequest *)audio_io1);
1132 playing++;
1133 current = 1;
1135 // main loop
1136 while (sound_status != 0xDEADBEEF) {
1137 if (current) {
1138 if(playing>1)
1139 WaitIO((struct IORequest *)audio_io2);
1140 fill_buffer(buffer2);
1141 audio_io2->ahir_Std.io_Message.mn_Node.ln_Pri = 60;
1142 audio_io2->ahir_Std.io_Data = buffer2;
1143 audio_io2->ahir_Std.io_Length = BUFFER_SIZE;
1144 audio_io2->ahir_Std.io_Offset = 0;
1145 audio_io2->ahir_Std.io_Command = CMD_WRITE;
1146 audio_io2->ahir_Frequency = 44100;
1147 audio_io2->ahir_Volume = 0x10000;
1148 audio_io2->ahir_Type = AHIST_S16S;
1149 audio_io2->ahir_Position = 0x8000;
1150 audio_io2->ahir_Link = audio_io1;
1151 SendIO((struct IORequest *)audio_io2);
1152 playing++;
1153 current = 0;
1154 } else {
1155 WaitIO((struct IORequest *)audio_io1);
1156 fill_buffer(buffer1);
1157 audio_io1->ahir_Std.io_Message.mn_Node.ln_Pri = 60;
1158 audio_io1->ahir_Std.io_Data = buffer1;
1159 audio_io1->ahir_Std.io_Length = BUFFER_SIZE;
1160 audio_io1->ahir_Std.io_Offset = 0;
1161 audio_io1->ahir_Std.io_Command = CMD_WRITE;
1162 audio_io1->ahir_Frequency = 44100;
1163 audio_io1->ahir_Volume = 0x10000;
1164 audio_io1->ahir_Type = AHIST_S16S;
1165 audio_io1->ahir_Position = 0x8000;
1166 audio_io1->ahir_Link = audio_io2;
1167 SendIO((struct IORequest *)audio_io1);
1168 playing++;
1169 current = 1;
1173 // cleanup and shut down daemon
1174 if(playing>1) {
1175 AbortIO((struct IORequest *)audio_io2);
1176 WaitIO((struct IORequest *)audio_io2);
1179 AbortIO((struct IORequest *)audio_io1);
1180 WaitIO((struct IORequest *)audio_io1);
1182 // double abort to be sure to break double-buffering
1183 if(playing>1) {
1184 AbortIO((struct IORequest *)audio_io2);
1185 WaitIO((struct IORequest *)audio_io2);
1188 CloseDevice((struct IORequest *)audio_io1);
1189 DeleteIORequest((struct IORequest *)audio_io1);
1190 DeleteMsgPort(audio_mp);
1191 FreeVec((APTR)audio_io2);
1192 audio_io2 = NULL;
1193 FreeVec((APTR)buffer1);
1194 buffer1 = NULL;
1195 FreeVec((APTR)buffer2);
1196 buffer2 = NULL;
1198 if(midi_instruments) {
1199 FreeVec(midi_instruments);
1200 midi_instruments = NULL;
1203 audio_is_open = FALSE;
1204 sound_status = 0;
1205 return 0;
1208 /**********************************************************************/