3 * Copyright (C) 1998 Brainchild Design - http://brainchilddesign.com/
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
36 #include "SDL_mixer.h"
38 static Mix_Music
*current_music
= (Mix_Music
*) NULL
;
41 sfx_data sounds
[NUM_SFX
];
43 static int SAMPLECOUNT
= 512;
45 #define MAX_CHANNELS 32
50 /* The channel step amount... */
52 /* ... and a 0.16 bit remainder of last step. */
53 unsigned int stepremainder
;
54 unsigned int samplerate
;
55 /* The channel data pointers, start and end. */
57 signed short* startdata
;
58 signed short* enddata
;
59 /* Hardware left and right channel volume lookup. */
64 channel_info_t channelinfo
[MAX_CHANNELS
];
66 /* Sample rate in samples/second */
67 int audio_rate
= 44100;
68 int global_sfx_volume
= 0;
70 // This function loops all active (internal) sound
71 // channels, retrieves a given number of samples
72 // from the raw sound data, modifies it according
73 // to the current (internal) channel parameters,
74 // mixes the per channel samples into the given
75 // mixing buffer, and clamping it to the allowed
78 // This function currently supports only 16bit.
81 static void stopchan(int i
)
83 if (channelinfo
[i
].data
) {
84 memset(&channelinfo
[i
], 0, sizeof(channel_info_t
));
90 // This function adds a sound to the
91 // list of currently active sounds,
92 // which is maintained as a given number
93 // (eight, usually) of internal channels.
96 int addsfx(signed short *data
, int len
, int loop
, int samplerate
, int channel
)
100 /* We will handle the new SFX. */
101 /* Set pointer to raw data. */
102 channelinfo
[channel
].data
= data
;
103 channelinfo
[channel
].startdata
= data
;
105 /* Set pointer to end of raw data. */
106 channelinfo
[channel
].enddata
= channelinfo
[channel
].data
+ len
- 1;
107 channelinfo
[channel
].samplerate
= samplerate
;
109 channelinfo
[channel
].loop
= loop
;
110 channelinfo
[channel
].stepremainder
= 0;
116 static void updateSoundParams(int slot
, int volume
)
123 // MWM 2000-12-24: Calculates proportion of channel samplerate
124 // to global samplerate for mixing purposes.
125 // Patched to shift left *then* divide, to minimize roundoff errors
126 // as well as to use SAMPLERATE as defined above, not to assume 11025 Hz
128 channelinfo
[slot
].step
= ((channelinfo
[slot
].samplerate
<<16)/audio_rate
);
133 /* Sanity check, clamp volume. */
144 channelinfo
[slot
].leftvol
= leftvol
;
145 channelinfo
[slot
].rightvol
= rightvol
;
149 void mix_sound(void *unused
, Uint8
*stream
, int len
)
151 /* Mix current sound data. */
152 /* Data, from raw sound, for right and left. */
157 /* Pointers in audio stream, left, right, end. */
158 signed short* leftout
;
159 signed short* rightout
;
160 signed short* leftend
;
161 /* Step in stream, left and right, thus two. */
164 /* Mixing channel index. */
167 /* Left and right channel */
168 /* are in audio stream, alternating. */
169 leftout
= (signed short *)stream
;
170 rightout
= ((signed short *)stream
)+1;
173 /* Determine end, for left channel only */
174 /* (right channel is implicit). */
175 leftend
= leftout
+ (len
/4)*step
;
177 /* Mix sounds into the mixing buffer. */
178 /* Loop over step*SAMPLECOUNT, */
179 /* that is 512 values for two channels. */
180 while (leftout
!= leftend
) {
181 /* Reset left/right value. */
183 dr
= *rightout
* 256;
185 /* Love thy L2 chache - made this a loop. */
186 /* Now more channels could be set at compile time */
187 /* as well. Thus loop those channels. */
188 for ( chan
= 0; chan
< MAX_CHANNELS
; chan
++ ) {
189 /* Check channel, if active. */
190 if (channelinfo
[chan
].data
) {
191 /* Get the raw data from the channel. */
193 /* sample = *channelinfo[chan].data; */
194 /* linear filtering */
195 sample
= (int)(((int)channelinfo
[chan
].data
[0] * (int)(0x10000 - channelinfo
[chan
].stepremainder
))
196 + ((int)channelinfo
[chan
].data
[1] * (int)(channelinfo
[chan
].stepremainder
))) >> 16;
198 /* Add left and right part */
199 /* for this channel (sound) */
200 /* to the current data. */
201 /* Adjust volume accordingly. */
202 dl
+= sample
* (channelinfo
[chan
].leftvol
* global_sfx_volume
) / 128;
203 dr
+= sample
* (channelinfo
[chan
].rightvol
* global_sfx_volume
) / 128;
204 /* Increment index ??? */
205 channelinfo
[chan
].stepremainder
+= channelinfo
[chan
].step
;
206 /* MSB is next sample??? */
207 channelinfo
[chan
].data
+= channelinfo
[chan
].stepremainder
>> 16;
208 /* Limit to LSB??? */
209 channelinfo
[chan
].stepremainder
&= 0xffff;
211 /* Check whether we are done. */
212 if (channelinfo
[chan
].data
>= channelinfo
[chan
].enddata
) {
213 if (channelinfo
[chan
].loop
) {
214 channelinfo
[chan
].data
= channelinfo
[chan
].startdata
;
222 /* Clamp to range. Left hardware channel. */
223 /* Has been char instead of short. */
224 /* if (dl > 127) *leftout = 127; */
225 /* else if (dl < -128) *leftout = -128; */
226 /* else *leftout = dl; */
233 else if (dl
< SHRT_MIN
)
236 *leftout
= (signed short)dl
;
238 /* Same for right hardware channel. */
240 *rightout
= SHRT_MAX
;
241 else if (dr
< SHRT_MIN
)
242 *rightout
= SHRT_MIN
;
244 *rightout
= (signed short)dr
;
246 /* Increment current pointers in stream */
256 Uint16 audio_format
= MIX_DEFAULT_FORMAT
;
257 int audio_channels
= 2;
258 int audio_buffers
= 4096;
262 if (main_info
.no_sound
)
265 audio_buffers
= SAMPLECOUNT
*audio_rate
/11025;
267 memset(channelinfo
, 0, sizeof(channelinfo
));
268 memset(sounds
, 0, sizeof(sounds
));
271 if (Mix_OpenAudio(audio_rate
, audio_format
, audio_channels
, audio_buffers
) < 0) {
272 fprintf(stderr
, "Couldn't open audio: %s\n", SDL_GetError());
273 main_info
.no_sound
= 1;
277 Mix_QuerySpec(&audio_rate
, &audio_format
, &audio_channels
);
278 printf("Opened audio at %dHz %dbit %s, %d bytes audio buffer\n", audio_rate
, (audio_format
& 0xFF), (audio_channels
> 1) ? "stereo" : "mono", audio_buffers
);
280 Mix_SetMusicCMD(getenv("MUSIC_CMD"));
282 Mix_SetPostMix(mix_sound
, NULL
);
284 main_info
.no_sound
= 1;
293 if (main_info
.no_sound
)
299 Mix_FreeMusic(current_music
);
300 current_music
= NULL
;
316 char dj_autodetect_sd(void)
321 char dj_set_stereo(char flag
)
326 void dj_set_auto_mix(char flag
)
330 unsigned short dj_set_mixing_freq(unsigned short freq
)
335 void dj_set_dma_time(unsigned short time
)
339 void dj_set_nosound(char flag
)
351 char dj_set_num_sfx_channels(char num_channels
)
356 void dj_set_sfx_volume(char volume
)
358 if (main_info
.no_sound
)
362 global_sfx_volume
= volume
*2;
366 void dj_play_sfx(unsigned char sfx_num
, unsigned short freq
, char volume
, char panning
, unsigned short delay
, char channel
)
370 if (main_info
.music_no_sound
|| main_info
.no_sound
)
374 for (slot
=0; slot
<MAX_CHANNELS
; slot
++)
375 if (channelinfo
[slot
].data
==NULL
)
377 if (slot
>=MAX_CHANNELS
)
383 addsfx((short *)sounds
[sfx_num
].buf
, sounds
[sfx_num
].length
, sounds
[sfx_num
].loop
, freq
, slot
);
384 updateSoundParams(slot
, volume
*2);
388 char dj_get_sfx_settings(unsigned char sfx_num
, sfx_data
*data
)
390 if (main_info
.no_sound
)
393 memcpy(data
, &sounds
[sfx_num
], sizeof(sfx_data
));
397 char dj_set_sfx_settings(unsigned char sfx_num
, sfx_data
*data
)
399 if (main_info
.no_sound
)
402 memcpy(&sounds
[sfx_num
], data
, sizeof(sfx_data
));
406 void dj_set_sfx_channel_volume(char channel_num
, char volume
)
408 if (main_info
.no_sound
)
412 updateSoundParams(channel_num
, volume
*2);
416 void dj_stop_sfx_channel(char channel_num
)
418 if (main_info
.no_sound
)
422 stopchan(channel_num
);
426 char dj_load_sfx(unsigned char * file_handle
, char *filename
, int file_length
, char sfx_type
, unsigned char sfx_num
)
430 unsigned short *dest
;
432 if (main_info
.no_sound
)
435 sounds
[sfx_num
].buf
= malloc(file_length
);
437 memcpy(sounds
[sfx_num
].buf
, file_handle
, file_length
);
439 sounds
[sfx_num
].length
= file_length
/ 2;
440 src
= sounds
[sfx_num
].buf
;
441 dest
= (unsigned short *)sounds
[sfx_num
].buf
;
442 for (i
=0; i
<sounds
[sfx_num
].length
; i
++)
445 temp
= src
[0] + (src
[1] << 8);
453 void dj_free_sfx(unsigned char sfx_num
)
455 if (main_info
.no_sound
)
458 free(sounds
[sfx_num
].buf
);
459 memset(&sounds
[sfx_num
], 0, sizeof(sfx_data
));
464 char dj_ready_mod(char mod_num
)
473 if (main_info
.no_sound
)
478 fp
= dat_open("jump.mod");
479 len
= dat_filelen("jump.mod");
482 fp
= dat_open("bump.mod");
483 len
= dat_filelen("bump.mod");
486 fp
= dat_open("scores.mod");
487 len
= dat_filelen("scores.mod");
490 fprintf(stderr
, "bogus parameter to dj_ready_mod()\n");
496 if (Mix_PlayingMusic())
497 Mix_FadeOutMusic(1500);
500 Mix_FreeMusic(current_music
);
501 current_music
= NULL
;
508 filename
= strdup("/tmp/jumpnbump.mod.XXXXXX");
509 tmp_fd
= mkstemp(filename
);
514 tmp
= fdopen(tmp_fd
, "wb");
519 fwrite(fp
, len
, 1, tmp
);
523 current_music
= Mix_LoadMUS(filename
);
526 if (current_music
== NULL
) {
527 fprintf(stderr
, "Couldn't load music: %s\n", SDL_GetError());
536 char dj_start_mod(void)
539 if (main_info
.no_sound
)
543 Mix_PlayMusic(current_music
, -1);
549 void dj_stop_mod(void)
552 if (main_info
.no_sound
)
559 void dj_set_mod_volume(char volume
)
562 if (main_info
.no_sound
)
565 Mix_VolumeMusic(volume
);
569 char dj_load_mod(unsigned char * file_handle
, char *filename
, char mod_num
)
574 void dj_free_mod(char mod_num
)