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> */
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
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
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
)
179 unsigned char *cnvsfx
;
185 // Get the sound data from the WAD, allocate lump
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
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");
202 sfxlump
= W_GetNumForName (name
);
204 size
= W_LumpLength (sfxlump
);
207 // fprintf( stderr, "." );
208 // fprintf( stderr, " -loading %s (lump %d, %d bytes)\n",
209 // sfxname, sfxlump, size );
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.
227 // Return allocated converted data.
228 return (void *)cnvsfx
;
231 /**********************************************************************/
232 // Init at program start...
233 void I_InitSound (void)
237 if (M_CheckParm("-nosfx"))
240 if (M_CheckParm("-music")) {
241 if (M_CheckParm("-70Hz")) {
243 BUFFER_SIZE
= NUM_SAMPLES
* 2 * 2;
245 fprintf (stderr
, "I_InitSound: Playing music at 70Hz.\n");
247 } else if (M_CheckParm("-140Hz")) {
249 BUFFER_SIZE
= NUM_SAMPLES
* 2 * 2;
251 fprintf (stderr
, "I_InitSound: Playing music at 140Hz.\n");
258 // create sound handling task
259 sound_task
= (struct Task
*)CreateNewProcTags( NP_Output
, Output(),
261 NP_Name
, (IPTR
)"doom_sound_daemon",
262 NP_CloseOutput
, FALSE
,
263 NP_CloseInput
, FALSE
,
265 NP_Entry
, (IPTR
)sound_handler
,
269 fprintf (stderr
, "I_InitSound: Cannot create sound daemon, no sfx or music.\n");
273 while (!sound_status
)
276 switch (sound_status
) {
278 fprintf (stderr
, "I_InitSound: Sound daemon running.\n");
282 fprintf (stderr
, "I_InitSound: Cannot create audio msgport, no sfx or music.\n");
286 fprintf (stderr
, "I_InitSound: Cannot create audio request, no sfx or music.\n");
290 fprintf (stderr
, "I_InitSound: Cannot open AHI device, no sfx or music.\n");
294 fprintf (stderr
, "I_InitSound: Cannot create double-buffer request, no sfx or music.\n");
298 fprintf (stderr
, "I_InitSound: Cannot allocate mixing buffers, no sfx or music.\n");
302 fprintf (stderr
, "I_InitSound: Cannot open MIDI instruments file, no music.\n");
304 break; // non-fatal error
306 fprintf (stderr
, "I_InitSound: Cannot alloc memory for MIDI instruments, no music.\n");
308 break; // non-fatal error
310 fprintf (stderr
, "I_InitSound: Error while initializing sound daemon, no sfx or music.\n");
315 fprintf (stderr
, "I_InitSound: AHI audio initialized.\n" );
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
]);
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");
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");
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:");
365 if (sound_status
> 0) {
366 sound_status
= 0xDEADBEEF; // DIE, DAEMON! DIE!!
371 // fprintf (stderr, " Sound module closed.\n");
375 /**********************************************************************/
376 /**********************************************************************/
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
)
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.
409 // fprintf (stderr, "I_StartSound(%d,%d,%d,%d,%d,%d)\n", id, cnum, vol, sep, pitch, priority);
413 Sfx_Start (S_sfx
[id
].data
, cnum
, changepitch
? freqs
[pitch
] : 11025,
414 vol
, sep
, lengths
[id
]);
419 /**********************************************************************/
420 // Stops a sound channel.
421 void I_StopSound(int handle
)
423 // fprintf (stderr, "I_StopSound(%d)\n", 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);
438 return Sfx_Done(handle
) ? 1 : 0;
443 /**********************************************************************/
444 // Updates the volume, separation,
445 // and pitch of a sound channel.
453 // fprintf (stderr, "I_UpdateSoundParams(%d,%d,%d,%d)\n", handle, vol, sep, pitch);
456 Sfx_Update(handle
, changepitch
? freqs
[pitch
] : 11025, vol
, sep
);
459 /**********************************************************************/
460 /**********************************************************************/
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 /**********************************************************************/
483 void I_InitMusic(void)
485 fprintf (stderr
, "I_InitMusic:");
488 if (M_CheckParm("-music") && (music_okay
== 1)) {
489 fprintf (stderr
, " Music okay.\n");
492 if (M_CheckParm("-70Hz")) {
494 BUFFER_SIZE
= NUM_SAMPLES
* 2 * 2;
496 } else if (M_CheckParm("-140Hz")) {
498 BUFFER_SIZE
= NUM_SAMPLES
* 2 * 2;
506 fprintf (stderr
, " No music.\n");
510 /**********************************************************************/
511 void I_ShutdownMusic(void)
513 // fprintf (stderr, "I_ShutdownMusic()\n");
516 /**********************************************************************/
518 void I_SetMusicVolume(int volume
)
520 // fprintf (stderr, "I_SetMusicVolume(%d)\n", volume);
522 snd_MusicVolume
= volume
;
528 /**********************************************************************/
529 // PAUSE game handling.
530 void I_PauseSong(int handle
)
532 // fprintf (stderr, "I_PauseSong(%d)\n", handle);
538 /**********************************************************************/
539 void I_ResumeSong(int handle
)
541 // fprintf (stderr, "I_ResumeSong(%d)\n", handle);
547 /**********************************************************************/
548 // Registers a song handle to song data.
549 int I_RegisterSong(void *data
)
551 // fprintf (stderr, "I_RegisterSong(%08x)\n", data);
554 return Mus_Register(data
);
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.
569 // fprintf (stderr, "I_PlaySong(%d,%d)\n", handle, looping);
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);
589 /**********************************************************************/
590 // See above (register), then think backwards
591 void I_UnRegisterSong(int handle
)
593 // fprintf (stderr, "I_UnRegisterSong(%d)\n", handle);
596 Mus_Unregister(handle
);
599 /**********************************************************************/
601 void _STDaudio_cleanup (void)
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
;
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
;
624 audVoice
[cnum
].rtvol
= (vol
- (vol
* sep
* sep
) / 65536.0f
) / 127.0f
;
625 audVoice
[cnum
].flags
= 0x81;
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
;
637 audVoice
[cnum
].step
= (float)step
/ 44100.0f
;
638 audVoice
[cnum
].ltvol
= (vol
- (vol
* sep
* sep
) / 65536.0f
) / 127.0f
;
640 audVoice
[cnum
].rtvol
= (vol
- (vol
* sep
* sep
) / 65536.0f
) / 127.0f
;
644 void Sfx_Stop(int cnum
)
647 audVoice
[cnum
].flags
&= 0xFE;
651 int Sfx_Done(int cnum
)
656 done
= (audVoice
[cnum
].flags
& 0x01) ? (int)audVoice
[cnum
].index
+ 1 : 0;
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;
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
682 return 0; // illegal score length
683 score_start
= SWAPSHORT(wptr
[3]); // score start
685 return 0; // illegal score start offset
687 inst_cnt
= SWAPSHORT(wptr
[6]); // instrument count
689 return 0; // illegal instrument count
691 // okay, MUS data seems to check out
693 score_data
= musdata
;
697 void Mus_Unregister(int handle
)
700 // music won't start playing until mus_playing set at this point
708 void Mus_Play(int handle
, int looping
)
713 mus_looping
= looping
;
714 mus_playing
= 2; // 2 = play from start
717 void Mus_Stop(int handle
)
722 mus_playing
= -1; // stop playing
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
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
)
756 WORD
*smpbuff
= buffer
;
761 // process music if playing
764 mus_playing
= 0; // music now off
766 if (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) {
785 nextEvent
: // next event
787 event
= *score_ptr
++;
788 switch((event
>> 4) & 7) {
790 channel
= (int)(event
& 15);
793 voice
= mus_channel
[channel
].map
[(ULONG
)note
] - 1;
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
801 channel
= (int)(event
& 15);
804 if (note
& 0x80) { // set volume as well
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
;
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
;
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
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
847 channel
= (int)(event
& 15);
848 mus_channel
[channel
].pitch
= pitch_table
[(ULONG
)*score_ptr
++ & 0xff];
851 score_ptr
++; // skip value - not supported
853 case 4: // Change control
854 channel
= (int)(event
& 15);
856 value
= *score_ptr
++;
859 // set channel instrument
860 mus_channel
[channel
].instrument
= (ULONG
)value
;
861 mus_channel
[channel
].pitch
= 1.0f
;
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
;
869 mus_channel
[channel
].rtvol
= (volume
- (volume
* pan
* pan
) / 65536.0f
) / 127.0f
;
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
;
877 mus_channel
[channel
].rtvol
= (volume
- (volume
* pan
* pan
) / 65536.0f
) / 127.0f
;
883 score_ptr
= (UBYTE
*)((ULONG
)score_data
+ (ULONG
)score_start
);
885 for (voice
=0; voice
<MUS_VOICES
; voice
++) {
886 audVoice
[voice
+ SFX_VOICES
].flags
= 0;
887 voice_avail
[voice
] = 0;
895 } while (!(event
& 0x80)); // not last event
897 // now get the time until the next event(s)
900 while (time
& 0x80) {
901 // while msb set, accumulate 7 bits
902 next_time
|= (ULONG
)(time
& 0x7f);
906 next_time
|= (ULONG
)time
;
907 mus_delay
+= next_time
;
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) {
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
;
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
956 index
-= (float)length
;
957 index
+= (float)loop
;
959 audVoice
[ix
].flags
= 0; // disable voice
960 break; // exit sample loop
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
);
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__
990 return (UWORD
)((x
>>8) | (x
<<8));
998 | ((x
<<8) & 0xff0000)
1004 /**********************************************************************/
1006 ULONG
sound_handler(char *args
)
1012 struct midiHdr
*mhdr
;
1016 // try to initialize AHI
1017 if(!(audio_mp
= CreateMsgPort())) {
1022 if(!(audio_io1
= (struct AHIRequest
*)CreateIORequest(audio_mp
, sizeof(struct AHIRequest
)))) {
1023 DeleteMsgPort(audio_mp
);
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
);
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
);
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
);
1057 FreeVec((APTR
)buffer1
);
1061 FreeVec((APTR
)buffer2
);
1068 numChannels
= SFX_VOICES
;
1069 audio_is_open
= TRUE
;
1073 // try to set up MIDI instruments
1074 hnd
= fopen("PROGDIR:MIDI_Instruments","rb");
1076 fseek(hnd
, 0, SEEK_END
);
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
);
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;
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;
1114 sound_status
= 3; // couldn't allocate memory
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
);
1136 while (sound_status
!= 0xDEADBEEF) {
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
);
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
);
1173 // cleanup and shut down daemon
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
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
);
1193 FreeVec((APTR
)buffer1
);
1195 FreeVec((APTR
)buffer2
);
1198 if(midi_instruments
) {
1199 FreeVec(midi_instruments
);
1200 midi_instruments
= NULL
;
1203 audio_is_open
= FALSE
;
1208 /**********************************************************************/