2 * $Source: /cvs/cvsroot/d2x/arch/dos/digi.c,v $
5 * $Date: 2005-02-25 10:49:48 $
7 * DOS digital audio support
9 * $Log: not supported by cvs2svn $
10 * Revision 1.3 2001/10/25 08:25:33 bradleyb
11 * Finished moving stuff to arch/blah. I know, it's ugly, but It'll be easier to sync with d1x.
13 * Revision 1.3 2001/01/31 14:04:45 bradleyb
14 * Fix compiler warnings
16 * Revision 1.2 2001/01/29 13:53:28 bradleyb
17 * Fixed build, minor fixes
34 #include "gr.h" // needed for piggy.h
42 int digi_sample_rate = SAMPLE_RATE_11K;
43 int digi_timer_rate = 9943; // rate for the timer to go off to handle the driver system (120 Hz)
45 //edited 05/17/99 Matt Mueller - added ifndef NO_ASM
46 //added on 980905 by adb to add inline fixmul for mixer on i386
49 #define do_fixmul(x,y) \
52 asm("imull %2\n\tshrdl %3,%1,%0" \
53 : "=a"(_ax), "=d"(_dx) \
54 : "rm"(y), "i"(16), "0"(x)); \
57 extern inline fix fixmul(fix x, fix y) { return do_fixmul(x,y); }
63 //changed on 980905 by adb to increase number of concurrent sounds
64 #define MAX_SOUND_SLOTS 32
66 #define SOUND_BUFFER_SIZE 512
70 /* This table is used to add two sound values together and pin
71 * the value to avoid overflow. (used with permission from ARDI)
72 * DPH: Taken from SDL/src/SDL_mixer.c.
74 static const unsigned char mix8[] =
76 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
77 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
78 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
79 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
80 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
81 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
82 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
83 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
84 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
85 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
86 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
87 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03,
88 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
89 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
90 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24,
91 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
92 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A,
93 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
94 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
95 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B,
96 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
97 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
98 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C,
99 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
100 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92,
101 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D,
102 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8,
103 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3,
104 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE,
105 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9,
106 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4,
107 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
108 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA,
109 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5,
110 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0xFF,
111 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
112 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
113 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
114 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
115 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
116 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
117 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
118 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
119 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
120 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
121 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
122 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
126 //added/changed on 980905 by adb to make sfx volume work, on 990221 by adb changed F1_0 to F1_0 / 2
127 #define SOUND_MAX_VOLUME (F1_0 / 2)
129 int digi_volume = SOUND_MAX_VOLUME;
132 static int digi_initialised = 0;
136 int playing; // Is there a sample playing on this channel?
137 int looped; // Play this sample looped?
138 fix pan; // 0 = far left, 1 = far right
139 fix volume; // 0 = nothing, 1 = fully on
140 //changed on 980905 by adb from char * to unsigned char *
141 unsigned char *samples;
143 unsigned int length; // Length of the sample
144 unsigned int position; // Position we are at at the moment.
145 int soundobj; // Which soundobject is on this channel
146 int persistent; // This can't be pre-empted
147 } SoundSlots[MAX_SOUND_SLOTS];
149 static int digi_max_channels = 16;
151 static int next_channel = 0;
153 /* Audio mixing callback */
154 //changed on 980905 by adb to cleanup, add pan support and optimize mixer
155 static void audio_mixcallback(void *userdata, unsigned char *stream, int len)
157 unsigned char *streamend = stream + len;
158 struct sound_slot *sl;
160 for (sl = SoundSlots; sl < SoundSlots + MAX_SOUND_SLOTS; sl++)
164 unsigned char *sldata = sl->samples + sl->position, *slend = sl->samples + sl->length;
165 unsigned char *sp = stream;
170 if ((x = sl->pan) & 0x8000)
172 vl = 0x20000 - x * 2;
180 vl = fixmul(vl, (x = sl->volume));
182 while (sp < streamend)
191 sldata = sl->samples;
193 v = *(sldata++) - 0x80;
194 *(sp++) = mix8[ *sp + fixmul(v, vl) + 0x80 ];
195 *(sp++) = mix8[ *sp + fixmul(v, vr) + 0x80 ];
197 sl->position = sldata - sl->samples;
203 /* Initialise audio devices. */
206 /* this is just here now to stop gcc from complaining about
207 * audio_mixcallback being declared static and not used...
209 if (0) audio_mixcallback(NULL,NULL,0);
215 void digi_reset() { }
217 /* Shut down audio */
220 if (!digi_initialised) return;
221 digi_initialised = 0;
224 void digi_stop_all_channels()
228 for (i = 0; i < MAX_SOUND_SLOTS; i++)
233 extern void digi_end_soundobj(int channel);
234 extern int SoundQ_channel;
235 extern void SoundQ_end();
236 int verify_sound_channel_free(int channel);
239 int digi_start_sound(short soundnum, fix volume, int pan, int looping, int loop_start, int loop_end, int soundobj)
241 int i, starting_channel;
243 if (!digi_initialised) return -1;
245 if (soundnum < 0) return -1;
247 Assert(GameSounds[soundnum].data != (void *)-1);
249 starting_channel = next_channel;
253 if (!SoundSlots[next_channel].playing)
256 if (!SoundSlots[next_channel].persistent)
257 break; // use this channel!
260 if (next_channel >= digi_max_channels)
262 if (next_channel == starting_channel)
264 mprintf((1, "OUT OF SOUND CHANNELS!!!\n"));
268 if (SoundSlots[next_channel].playing)
270 SoundSlots[next_channel].playing = 0;
271 if (SoundSlots[next_channel].soundobj > -1)
273 digi_end_soundobj(SoundSlots[next_channel].soundobj);
275 if (SoundQ_channel == next_channel)
280 verify_sound_channel_free(next_channel);
283 SoundSlots[next_channel].soundno = soundnum;
284 SoundSlots[next_channel].samples = GameSounds[soundnum].data;
285 SoundSlots[next_channel].length = GameSounds[soundnum].length;
286 SoundSlots[next_channel].volume = fixmul(digi_volume, volume);
287 SoundSlots[next_channel].pan = pan;
288 SoundSlots[next_channel].position = 0;
289 SoundSlots[next_channel].looped = looping;
290 SoundSlots[next_channel].playing = 1;
291 SoundSlots[next_channel].soundobj = soundobj;
292 SoundSlots[next_channel].persistent = 0;
293 if ((soundobj > -1) || (looping) || (volume > F1_0))
294 SoundSlots[next_channel].persistent = 1;
298 if (next_channel >= digi_max_channels)
305 // Returns the channel a sound number is playing on, or
307 int digi_find_channel(int soundno)
309 if (!digi_initialised)
315 if (GameSounds[soundno].data == NULL)
321 //FIXME: not implemented
326 //added on 980905 by adb from original source to make sfx volume work
327 void digi_set_digi_volume( int dvolume )
329 dvolume = fixmuldiv( dvolume, SOUND_MAX_VOLUME, 0x7fff);
330 if ( dvolume > SOUND_MAX_VOLUME )
331 digi_volume = SOUND_MAX_VOLUME;
332 else if ( dvolume < 0 )
335 digi_volume = dvolume;
337 if ( !digi_initialised ) return;
343 void digi_set_volume( int dvolume, int mvolume ) { }
345 int digi_is_sound_playing(int soundno)
349 soundno = digi_xlat_sound(soundno);
351 for (i = 0; i < MAX_SOUND_SLOTS; i++)
352 //changed on 980905 by adb: added SoundSlots[i].playing &&
353 if (SoundSlots[i].playing && SoundSlots[i].soundno == soundno)
360 //added on 980905 by adb to make sound channel setting work
361 void digi_set_max_channels(int n) {
362 digi_max_channels = n;
364 if ( digi_max_channels < 1 )
365 digi_max_channels = 1;
366 if (digi_max_channels > MAX_SOUND_SLOTS)
367 digi_max_channels = MAX_SOUND_SLOTS;
369 if ( !digi_initialised ) return;
371 digi_stop_all_channels();
374 int digi_get_max_channels() {
375 return digi_max_channels;
379 int digi_is_channel_playing(int channel)
381 if (!digi_initialised)
384 return SoundSlots[channel].playing;
387 void digi_set_channel_volume(int channel, int volume)
389 if (!digi_initialised)
392 if (!SoundSlots[channel].playing)
395 SoundSlots[channel].volume = fixmuldiv(volume, digi_volume, F1_0);
398 void digi_set_channel_pan(int channel, int pan)
400 if (!digi_initialised)
403 if (!SoundSlots[channel].playing)
406 SoundSlots[channel].pan = pan;
409 void digi_stop_sound(int channel)
411 SoundSlots[channel].playing = 0;
412 SoundSlots[channel].soundobj = -1;
413 SoundSlots[channel].persistent = 0;
416 void digi_end_sound(int channel)
418 if (!digi_initialised)
421 if (!SoundSlots[channel].playing)
424 SoundSlots[channel].soundobj = -1;
425 SoundSlots[channel].persistent = 0;
428 void digi_reset_digi_sounds() {
431 for (i=0; i< MAX_SOUND_SLOTS; i++)
432 SoundSlots[i].playing=0;
434 //added on 980905 by adb to reset sound kill system
435 memset(SampleHandles, 255, sizeof(SampleHandles));
441 // MIDI stuff follows.
442 //added/killed on 11/25/98 by Matthew Mueller
443 //void digi_set_midi_volume( int mvolume ) { }
444 //void digi_play_midi_song( char * filename, char * melodic_bank, char * drum_bank, int loop ) {}
445 //void digi_stop_current_song()
454 //void digi_pause_midi() {}
455 //void digi_resume_midi() {}
456 //end this section kill - MM
464 if (!digi_initialised)
467 for (i = 0; i < digi_max_channels; i++)
469 if (digi_is_channel_playing(i))
473 mprintf_at((0, 2, 0, "DIGI: Active Sound Channels: %d/%d (HMI says %d/32) ", n_voices, digi_max_channels, -1));
474 //mprintf_at((0, 3, 0, "DIGI: Number locked sounds: %d ", digi_total_locks ));