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