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