Import jumpnbump/1.50
[jumpnbump.git] / sdl / sound.c
blob886d4b0f1426b5794f3e889faa63c56d0b1f4ffc
1 /*
2 * sound.c
3 * Copyright (C) 1998 Brainchild Design - http://brainchilddesign.com/
4 *
5 * Copyright (C) 2001 Chuck Mason <cemason@users.sourceforge.net>
7 * Copyright (C) 2002 Florian Schulze <crow@icculus.org>
9 * This file is part of Jump'n'Bump.
11 * Jump'n'Bump is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * Jump'n'Bump is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include "globals.h"
27 #include <limits.h>
28 #ifndef _MSC_VER
29 #include <unistd.h>
30 #endif
31 #include "SDL.h"
33 #ifndef NO_SDL_MIXER
34 #include "SDL_mixer.h"
36 static Mix_Music *current_music = (Mix_Music *) NULL;
37 #endif
39 sfx_data sounds[NUM_SFX];
41 static int SAMPLECOUNT = 512;
43 #define MAX_CHANNELS 32
45 typedef struct {
46 /* loop flag */
47 int loop;
48 /* The channel step amount... */
49 unsigned int step;
50 /* ... and a 0.16 bit remainder of last step. */
51 unsigned int stepremainder;
52 unsigned int samplerate;
53 /* The channel data pointers, start and end. */
54 signed short* data;
55 signed short* startdata;
56 signed short* enddata;
57 /* Hardware left and right channel volume lookup. */
58 int leftvol;
59 int rightvol;
60 } channel_info_t;
62 channel_info_t channelinfo[MAX_CHANNELS];
64 /* Sample rate in samples/second */
65 int audio_rate = 44100;
66 int global_sfx_volume = 0;
68 // This function loops all active (internal) sound
69 // channels, retrieves a given number of samples
70 // from the raw sound data, modifies it according
71 // to the current (internal) channel parameters,
72 // mixes the per channel samples into the given
73 // mixing buffer, and clamping it to the allowed
74 // range.
76 // This function currently supports only 16bit.
79 static void stopchan(int i)
81 if (channelinfo[i].data) {
82 memset(&channelinfo[i], 0, sizeof(channel_info_t));
88 // This function adds a sound to the
89 // list of currently active sounds,
90 // which is maintained as a given number
91 // (eight, usually) of internal channels.
92 // Returns a handle.
94 int addsfx(signed short *data, int len, int loop, int samplerate, int channel)
96 stopchan(channel);
98 /* We will handle the new SFX. */
99 /* Set pointer to raw data. */
100 channelinfo[channel].data = data;
101 channelinfo[channel].startdata = data;
103 /* Set pointer to end of raw data. */
104 channelinfo[channel].enddata = channelinfo[channel].data + len - 1;
105 channelinfo[channel].samplerate = samplerate;
107 channelinfo[channel].loop = loop;
108 channelinfo[channel].stepremainder = 0;
110 return channel;
114 static void updateSoundParams(int slot, int volume)
116 int rightvol;
117 int leftvol;
120 // Set stepping
121 // MWM 2000-12-24: Calculates proportion of channel samplerate
122 // to global samplerate for mixing purposes.
123 // Patched to shift left *then* divide, to minimize roundoff errors
124 // as well as to use SAMPLERATE as defined above, not to assume 11025 Hz
126 channelinfo[slot].step = ((channelinfo[slot].samplerate<<16)/audio_rate);
128 leftvol = volume;
129 rightvol= volume;
131 /* Sanity check, clamp volume. */
132 if (rightvol < 0)
133 rightvol = 0;
134 if (rightvol > 127)
135 rightvol = 127;
137 if (leftvol < 0)
138 leftvol = 0;
139 if (leftvol > 127)
140 leftvol = 127;
142 channelinfo[slot].leftvol = leftvol;
143 channelinfo[slot].rightvol = rightvol;
147 void mix_sound(void *unused, Uint8 *stream, int len)
149 /* Mix current sound data. */
150 /* Data, from raw sound, for right and left. */
151 register int sample;
152 register int dl;
153 register int dr;
155 /* Pointers in audio stream, left, right, end. */
156 signed short* leftout;
157 signed short* rightout;
158 signed short* leftend;
159 /* Step in stream, left and right, thus two. */
160 int step;
162 /* Mixing channel index. */
163 int chan;
165 /* Left and right channel */
166 /* are in audio stream, alternating. */
167 leftout = (signed short *)stream;
168 rightout = ((signed short *)stream)+1;
169 step = 2;
171 /* Determine end, for left channel only */
172 /* (right channel is implicit). */
173 leftend = leftout + (len/4)*step;
175 /* Mix sounds into the mixing buffer. */
176 /* Loop over step*SAMPLECOUNT, */
177 /* that is 512 values for two channels. */
178 while (leftout != leftend) {
179 /* Reset left/right value. */
180 dl = *leftout * 256;
181 dr = *rightout * 256;
183 /* Love thy L2 chache - made this a loop. */
184 /* Now more channels could be set at compile time */
185 /* as well. Thus loop those channels. */
186 for ( chan = 0; chan < MAX_CHANNELS; chan++ ) {
187 /* Check channel, if active. */
188 if (channelinfo[chan].data) {
189 /* Get the raw data from the channel. */
190 /* no filtering */
191 /* sample = *channelinfo[chan].data; */
192 /* linear filtering */
193 sample = (int)(((int)channelinfo[chan].data[0] * (int)(0x10000 - channelinfo[chan].stepremainder))
194 + ((int)channelinfo[chan].data[1] * (int)(channelinfo[chan].stepremainder))) >> 16;
196 /* Add left and right part */
197 /* for this channel (sound) */
198 /* to the current data. */
199 /* Adjust volume accordingly. */
200 dl += sample * (channelinfo[chan].leftvol * global_sfx_volume) / 128;
201 dr += sample * (channelinfo[chan].rightvol * global_sfx_volume) / 128;
202 /* Increment index ??? */
203 channelinfo[chan].stepremainder += channelinfo[chan].step;
204 /* MSB is next sample??? */
205 channelinfo[chan].data += channelinfo[chan].stepremainder >> 16;
206 /* Limit to LSB??? */
207 channelinfo[chan].stepremainder &= 0xffff;
209 /* Check whether we are done. */
210 if (channelinfo[chan].data >= channelinfo[chan].enddata) {
211 if (channelinfo[chan].loop) {
212 channelinfo[chan].data = channelinfo[chan].startdata;
213 } else {
214 stopchan(chan);
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; */
226 dl = dl / 256;
227 dr = dr / 256;
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;
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;
244 /* Increment current pointers in stream */
245 leftout += step;
246 rightout += step;
250 /* misc handling */
252 char dj_init(void)
254 Uint16 audio_format = MIX_DEFAULT_FORMAT;
255 int audio_channels = 2;
256 int audio_buffers = 4096;
258 open_screen();
260 if (main_info.no_sound)
261 return 0;
263 audio_buffers = SAMPLECOUNT*audio_rate/11025;
265 memset(channelinfo, 0, sizeof(channelinfo));
266 memset(sounds, 0, sizeof(sounds));
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;
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);
278 Mix_SetMusicCMD(getenv("MUSIC_CMD"));
280 Mix_SetPostMix(mix_sound, NULL);
281 #else
282 main_info.no_sound = 1;
283 return 1;
284 #endif
286 return 0;
289 void dj_deinit(void)
291 if (main_info.no_sound)
292 return;
294 #ifndef NO_SDL_MIXER
295 Mix_HaltMusic();
296 if (current_music)
297 Mix_FreeMusic(current_music);
298 current_music = NULL;
300 Mix_CloseAudio();
301 #endif
303 SDL_Quit();
306 void dj_start(void)
310 void dj_stop(void)
314 char dj_autodetect_sd(void)
316 return 0;
319 char dj_set_stereo(char flag)
321 return 0;
324 void dj_set_auto_mix(char flag)
328 unsigned short dj_set_mixing_freq(unsigned short freq)
330 return freq;
333 void dj_set_dma_time(unsigned short time)
337 void dj_set_nosound(char flag)
341 /* mix handling */
343 void dj_mix(void)
347 /* sfx handling */
349 char dj_set_num_sfx_channels(char num_channels)
351 return num_channels;
354 void dj_set_sfx_volume(char volume)
356 if (main_info.no_sound)
357 return;
359 SDL_LockAudio();
360 global_sfx_volume = volume*2;
361 SDL_UnlockAudio();
364 void dj_play_sfx(unsigned char sfx_num, unsigned short freq, char volume, char panning, unsigned short delay, char channel)
366 int slot;
368 if (main_info.music_no_sound || main_info.no_sound)
369 return;
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;
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();
386 char dj_get_sfx_settings(unsigned char sfx_num, sfx_data *data)
388 if (main_info.no_sound)
389 return 0;
391 memcpy(data, &sounds[sfx_num], sizeof(sfx_data));
392 return 0;
395 char dj_set_sfx_settings(unsigned char sfx_num, sfx_data *data)
397 if (main_info.no_sound)
398 return 0;
400 memcpy(&sounds[sfx_num], data, sizeof(sfx_data));
401 return 0;
404 void dj_set_sfx_channel_volume(char channel_num, char volume)
406 if (main_info.no_sound)
407 return;
409 SDL_LockAudio();
410 updateSoundParams(channel_num, volume*2);
411 SDL_UnlockAudio();
414 void dj_stop_sfx_channel(char channel_num)
416 if (main_info.no_sound)
417 return;
419 SDL_LockAudio();
420 stopchan(channel_num);
421 SDL_UnlockAudio();
424 char dj_load_sfx(unsigned char * file_handle, char *filename, int file_length, char sfx_type, unsigned char sfx_num)
426 unsigned int i;
427 unsigned char *src;
428 unsigned short *dest;
430 if (main_info.no_sound)
431 return 0;
433 sounds[sfx_num].buf = malloc(file_length);
435 memcpy(sounds[sfx_num].buf, file_handle, file_length);
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++)
442 unsigned short temp;
443 temp = src[0] + (src[1] << 8);
444 *dest = temp;
445 src += 2;
446 dest++;
448 return 0;
451 void dj_free_sfx(unsigned char sfx_num)
453 if (main_info.no_sound)
454 return;
456 free(sounds[sfx_num].buf);
457 memset(&sounds[sfx_num], 0, sizeof(sfx_data));
460 /* mod handling */
462 char dj_ready_mod(char mod_num)
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 unsigned char *fp;
472 int len;
474 if (main_info.no_sound)
475 return 0;
477 switch (mod_num) {
478 case MOD_MENU:
479 fp = dat_open("jump.mod");
480 len = dat_filelen("jump.mod");
481 break;
482 case MOD_GAME:
483 fp = dat_open("bump.mod");
484 len = dat_filelen("bump.mod");
485 break;
486 case MOD_SCORES:
487 fp = dat_open("scores.mod");
488 len = dat_filelen("scores.mod");
489 break;
490 default:
491 fprintf(stderr, "bogus parameter to dj_ready_mod()\n");
492 fp = NULL;
493 len = 0;
494 break;
497 if (Mix_PlayingMusic())
498 Mix_FadeOutMusic(1500);
500 if (current_music) {
501 Mix_FreeMusic(current_music);
502 current_music = NULL;
505 if (fp == NULL) {
506 return 0;
509 tmp = fopen(filename, "wb");
510 if (tmp) {
511 fwrite(fp, len, 1, tmp);
512 fflush(tmp);
513 fclose(tmp);
516 current_music = Mix_LoadMUS(filename);
517 unlink(filename);
518 if (current_music == NULL) {
519 fprintf(stderr, "Couldn't load music: %s\n", SDL_GetError());
520 return 0;
523 #endif
525 return 0;
528 char dj_start_mod(void)
530 #ifndef NO_SDL_MIXER
531 if (main_info.no_sound)
532 return 0;
534 Mix_VolumeMusic(0);
535 Mix_PlayMusic(current_music, -1);
536 #endif
538 return 0;
541 void dj_stop_mod(void)
543 #ifndef NO_SDL_MIXER
544 if (main_info.no_sound)
545 return;
547 Mix_HaltMusic();
548 #endif
551 void dj_set_mod_volume(char volume)
553 #ifndef NO_SDL_MIXER
554 if (main_info.no_sound)
555 return;
557 Mix_VolumeMusic(volume);
558 #endif
561 char dj_load_mod(unsigned char * file_handle, char *filename, char mod_num)
563 return 0;
566 void dj_free_mod(char mod_num)