]> icculus.org git repositories - crow/jumpnbump.git/blob - sdl/sound.c
Fixed SDL_Delay.
[crow/jumpnbump.git] / sdl / sound.c
1 /*
2  * sound.c
3  * Copyright (C) 1998 Brainchild Design - http://brainchilddesign.com/
4  * 
5  * Copyright (C) 2001 Chuck Mason <cemason@users.sourceforge.net>
6  *
7  * Copyright (C) 2002 Florian Schulze <crow@icculus.org>
8  *
9  * Portions of this code are from the MPEG software simulation group
10  * idct implementation. This code will be replaced with a new
11  * implementation soon.
12  *
13  * This file is part of Jump'n'Bump.
14  *
15  * Jump'n'Bump is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 2 of the License, or
18  * (at your option) any later version.
19  *
20  * Jump'n'Bump is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28  */
29
30 #include "globals.h"
31 #include <limits.h>
32
33 static Mix_Music *current_music = (Mix_Music *) NULL;
34
35 sfx_data sounds[NUM_SFX];
36
37 static int SAMPLECOUNT = 512;
38
39 #define MAX_CHANNELS    32
40
41 typedef struct {
42         // loop flag
43         int loop;
44         // The channel step amount...
45         unsigned int step;
46         // ... and a 0.16 bit remainder of last step.
47         unsigned int stepremainder;
48         unsigned int samplerate;
49         // The channel data pointers, start and end.
50         signed short* data;
51         signed short* startdata;
52         signed short* enddata;
53         // Hardware left and right channel volume lookup.
54         int leftvol;
55         int rightvol;
56 } channel_info_t;
57
58 channel_info_t channelinfo[MAX_CHANNELS];
59
60 // Sample rate in samples/second
61 int audio_rate = 44100;
62 int global_sfx_volume = 0;
63 //
64 // This function loops all active (internal) sound
65 //  channels, retrieves a given number of samples
66 //  from the raw sound data, modifies it according
67 //  to the current (internal) channel parameters,
68 //  mixes the per channel samples into the given
69 //  mixing buffer, and clamping it to the allowed
70 //  range.
71 //
72 // This function currently supports only 16bit.
73 //
74
75 static void stopchan(int i)
76 {
77         if (channelinfo[i].data) {
78                 memset(&channelinfo[i], 0, sizeof(channel_info_t));
79         }
80 }
81
82
83 //
84 // This function adds a sound to the
85 //  list of currently active sounds,
86 //  which is maintained as a given number
87 //  (eight, usually) of internal channels.
88 // Returns a handle.
89 //
90 int addsfx(signed short *data, int len, int loop, int samplerate, int channel)
91 {
92         stopchan(channel);
93
94         // We will handle the new SFX.
95         // Set pointer to raw data.
96         channelinfo[channel].data = data;
97         channelinfo[channel].startdata = data;
98       
99         /* Set pointer to end of raw data. */
100         channelinfo[channel].enddata = channelinfo[channel].data + len - 1;
101         channelinfo[channel].samplerate = samplerate;
102
103         channelinfo[channel].loop = loop;
104         channelinfo[channel].stepremainder = 0;
105
106         return channel;
107 }
108
109
110 static void updateSoundParams(int slot, int volume)
111 {
112         int rightvol;
113         int leftvol;
114
115         // Set stepping
116         // MWM 2000-12-24: Calculates proportion of channel samplerate
117         // to global samplerate for mixing purposes.
118         // Patched to shift left *then* divide, to minimize roundoff errors
119         // as well as to use SAMPLERATE as defined above, not to assume 11025 Hz
120         channelinfo[slot].step = ((channelinfo[slot].samplerate<<16)/audio_rate);
121
122         leftvol = volume;
123         rightvol= volume;  
124
125         // Sanity check, clamp volume.
126         if (rightvol < 0)
127                 rightvol = 0;
128         if (rightvol > 127)
129                 rightvol = 127;
130     
131         if (leftvol < 0)
132                 leftvol = 0;
133         if (leftvol > 127)
134                 leftvol = 127;
135     
136         channelinfo[slot].leftvol = leftvol;
137         channelinfo[slot].rightvol = rightvol;
138 }
139
140
141 void mix_sound(void *unused, Uint8 *stream, int len)
142 {
143         // Mix current sound data.
144         // Data, from raw sound, for right and left.
145         register int sample;
146         register int    dl;
147         register int    dr;
148
149         // Pointers in audio stream, left, right, end.
150         signed short*   leftout;
151         signed short*   rightout;
152         signed short*   leftend;
153         // Step in stream, left and right, thus two.
154         int       step;
155
156         // Mixing channel index.
157         int       chan;
158
159         // Left and right channel
160         //  are in audio stream, alternating.
161         leftout = (signed short *)stream;
162         rightout = ((signed short *)stream)+1;
163         step = 2;
164
165         // Determine end, for left channel only
166         //  (right channel is implicit).
167         leftend = leftout + (len/4)*step;
168
169         // Mix sounds into the mixing buffer.
170         // Loop over step*SAMPLECOUNT,
171         //  that is 512 values for two channels.
172         while (leftout != leftend) {
173                 // Reset left/right value. 
174                 //dl = 0;
175                 //dr = 0;
176                 dl = *leftout * 256;
177                 dr = *rightout * 256;
178
179                 // Love thy L2 chache - made this a loop.
180                 // Now more channels could be set at compile time
181                 //  as well. Thus loop those  channels.
182                 for ( chan = 0; chan < MAX_CHANNELS; chan++ ) {
183                         // Check channel, if active.
184                         if (channelinfo[chan].data) {
185                                 // Get the raw data from the channel.
186                                 // no filtering
187                                 // sample = *channelinfo[chan].data;
188                                 // linear filtering
189                                 sample = (int)(((int)channelinfo[chan].data[0] * (int)(0x10000 - channelinfo[chan].stepremainder))
190                                         + ((int)channelinfo[chan].data[1] * (int)(channelinfo[chan].stepremainder))) >> 16;
191
192                                 // Add left and right part
193                                 //  for this channel (sound)
194                                 //  to the current data.
195                                 // Adjust volume accordingly.
196                                 dl += sample * (channelinfo[chan].leftvol * global_sfx_volume) / 128;
197                                 dr += sample * (channelinfo[chan].rightvol * global_sfx_volume) / 128;
198                                 // Increment index ???
199                                 channelinfo[chan].stepremainder += channelinfo[chan].step;
200                                 // MSB is next sample???
201                                 channelinfo[chan].data += channelinfo[chan].stepremainder >> 16;
202                                 // Limit to LSB???
203                                 channelinfo[chan].stepremainder &= 0xffff;
204
205                                 // Check whether we are done.
206                                 if (channelinfo[chan].data >= channelinfo[chan].enddata)
207                                         if (channelinfo[chan].loop) {
208                                                 channelinfo[chan].data = channelinfo[chan].startdata;
209                                         } else {
210                                                 stopchan(chan);
211                                         }
212                         }
213                 }
214   
215                 // Clamp to range. Left hardware channel.
216                 // Has been char instead of short.
217                 // if (dl > 127) *leftout = 127;
218                 // else if (dl < -128) *leftout = -128;
219                 // else *leftout = dl;
220
221                 dl = dl / 256;
222                 dr = dr / 256;
223
224                 if (dl > SHRT_MAX)
225                         *leftout = SHRT_MAX;
226                 else if (dl < SHRT_MIN)
227                         *leftout = SHRT_MIN;
228                 else
229                         *leftout = (signed short)dl;
230
231                 // Same for right hardware channel.
232                 if (dr > SHRT_MAX)
233                         *rightout = SHRT_MAX;
234                 else if (dr < SHRT_MIN)
235                         *rightout = SHRT_MIN;
236                 else
237                         *rightout = (signed short)dr;
238
239                 // Increment current pointers in stream
240                 leftout += step;
241                 rightout += step;
242         }
243 }
244
245 /* misc handling */
246
247 char dj_init(void)
248 {
249         Uint16 audio_format = AUDIO_U16;
250         int audio_channels = 2;
251         int audio_buffers = 4096;
252
253         open_screen();
254
255         if (main_info.no_sound)
256                 return 0;
257
258         audio_buffers = SAMPLECOUNT*audio_rate/11025;
259
260         if (Mix_OpenAudio(audio_rate, audio_format, audio_channels, audio_buffers) < 0) {
261                 fprintf(stderr, "Couldn't open audio: %s\n", SDL_GetError());
262                 main_info.no_sound = 1;
263                 return 1;
264         }
265
266         Mix_QuerySpec(&audio_rate, &audio_format, &audio_channels);
267         printf("Opened audio at %dHz %dbit %s, %d bytes audio buffer\n", audio_rate, (audio_format & 0xFF), (audio_channels > 1) ? "stereo" : "mono", audio_buffers);
268
269         Mix_SetMusicCMD(getenv("MUSIC_CMD"));
270
271         Mix_SetPostMix(mix_sound, NULL);
272
273         memset(channelinfo, 0, sizeof(channelinfo));
274         memset(sounds, 0, sizeof(sounds));
275
276         return 0;
277 }
278
279 void dj_deinit(void)
280 {
281         if (main_info.no_sound)
282                 return;
283
284         Mix_HaltMusic();
285         if (current_music)
286                 Mix_FreeMusic(current_music);
287         current_music = NULL;
288
289         Mix_CloseAudio();
290
291         SDL_Quit();
292 }
293
294 void dj_start(void)
295 {
296 }
297
298 void dj_stop(void)
299 {
300 }
301
302 char dj_autodetect_sd(void)
303 {
304         return 0;
305 }
306
307 char dj_set_stereo(char flag)
308 {
309         return 0;
310 }
311
312 void dj_set_auto_mix(char flag)
313 {
314 }
315
316 unsigned short dj_set_mixing_freq(unsigned short freq)
317 {
318         return freq;
319 }
320
321 void dj_set_dma_time(unsigned short time)
322 {
323 }
324
325 void dj_set_nosound(char flag)
326 {
327 }
328
329 /* mix handling */
330
331 void dj_mix(void)
332 {
333 }
334
335 /* sfx handling */
336
337 char dj_set_num_sfx_channels(char num_channels)
338 {
339         return num_channels;
340 }
341
342 void dj_set_sfx_volume(char volume)
343 {
344         if (main_info.no_sound)
345                 return;
346
347         SDL_LockAudio();
348         global_sfx_volume = volume*2;
349         SDL_UnlockAudio();
350 }
351
352 void dj_play_sfx(unsigned char sfx_num, unsigned short freq, char volume, char panning, unsigned short delay, char channel)
353 {
354         int slot;
355
356         if (main_info.no_sound)
357                 return;
358
359         if (channel<0) {
360                 for (slot=0; slot<MAX_CHANNELS; slot++)
361                         if (channelinfo[slot].data==NULL)
362                                 break;
363                 if (slot>=MAX_CHANNELS)
364                         return;
365         } else
366                 slot = channel;
367
368         SDL_LockAudio();
369         addsfx((short *)sounds[sfx_num].buf, sounds[sfx_num].length, sounds[sfx_num].loop, freq, slot);
370         updateSoundParams(slot, volume*2);
371         SDL_UnlockAudio();
372 }
373
374 char dj_get_sfx_settings(unsigned char sfx_num, sfx_data *data)
375 {
376         if (main_info.no_sound)
377                 return 0;
378
379         memcpy(data, &sounds[sfx_num], sizeof(sfx_data));
380         return 0;
381 }
382
383 char dj_set_sfx_settings(unsigned char sfx_num, sfx_data *data)
384 {
385         if (main_info.no_sound)
386                 return 0;
387
388         memcpy(&sounds[sfx_num], data, sizeof(sfx_data));
389         return 0;
390 }
391
392 void dj_set_sfx_channel_volume(char channel_num, char volume)
393 {
394         if (main_info.no_sound)
395                 return;
396
397         SDL_LockAudio();
398         updateSoundParams(channel_num, volume*2);
399         SDL_UnlockAudio();
400 }
401
402 void dj_stop_sfx_channel(char channel_num)
403 {
404         if (main_info.no_sound)
405                 return;
406
407         SDL_LockAudio();
408         stopchan(channel_num);
409         SDL_UnlockAudio();
410 }
411
412 char dj_load_sfx(FILE * file_handle, char *filename, int file_length, char sfx_type, unsigned char sfx_num)
413 {
414         if (main_info.no_sound)
415                 return 0;
416
417         sounds[sfx_num].buf = malloc(file_length);
418         fread(sounds[sfx_num].buf, 1, file_length, file_handle);
419         sounds[sfx_num].length = file_length / 2;
420         return 0;
421 }
422
423 void dj_free_sfx(unsigned char sfx_num)
424 {
425         if (main_info.no_sound)
426                 return;
427
428         free(sounds[sfx_num].buf);
429         memset(&sounds[sfx_num], 0, sizeof(sfx_data));
430 }
431
432 /* mod handling */
433
434 char dj_ready_mod(char mod_num)
435 {
436         FILE *tmp;
437 #if ((defined _MSC_VER) || (defined __MINGW32__))
438         char filename[] = "jnb.tmpmusic.mod";
439 #else
440         char filename[] = "/tmp/jnb.tmpmusic.mod";
441 #endif
442         FILE *fp;
443         int len;
444
445         if (main_info.no_sound)
446                 return 0;
447
448         switch (mod_num) {
449         case MOD_MENU:
450                 fp = dat_open("jump.mod", datfile_name, "rb");
451                 len = dat_filelen("jump.mod", datfile_name);
452                 break;
453         case MOD_GAME:
454                 fp = dat_open("bump.mod", datfile_name, "rb");
455                 len = dat_filelen("bump.mod", datfile_name);
456                 break;
457         case MOD_SCORES:
458                 fp = dat_open("scores.mod", datfile_name, "rb");
459                 len = dat_filelen("scores.mod", datfile_name);
460                 break;
461         default:
462                 break;
463         }
464
465         if (Mix_PlayingMusic())
466                 Mix_FadeOutMusic(1500);
467
468         if (current_music) {
469                 Mix_FreeMusic(current_music);
470                 current_music = NULL;
471         }
472         tmp = fopen(filename, "wb");
473         if (tmp) {
474                 for (; len > 0; len--)
475                         fputc(fgetc(fp), tmp);
476                 fflush(tmp);
477                 fclose(tmp);
478         }
479         fclose(fp);
480
481         current_music = Mix_LoadMUS(filename);
482         if (current_music == NULL) {
483                 fprintf(stderr, "Couldn't load music: %s\n", SDL_GetError());
484                 return 0;
485         }
486
487         return 0;
488 }
489
490 char dj_start_mod(void)
491 {
492         if (main_info.no_sound)
493                 return 0;
494
495         Mix_VolumeMusic(0);
496         Mix_PlayMusic(current_music, -1);
497
498         return 0;
499 }
500
501 void dj_stop_mod(void)
502 {
503         if (main_info.no_sound)
504                 return;
505
506         Mix_HaltMusic();
507 }
508
509 void dj_set_mod_volume(char volume)
510 {
511         if (main_info.no_sound)
512                 return;
513
514         Mix_VolumeMusic(volume);
515 }
516
517 char dj_load_mod(FILE * file_handle, char *filename, char mod_num)
518 {
519         return 0;
520 }
521
522 void dj_free_mod(char mod_num)
523 {
524 }