Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
8526 maxcodehac 1
/*
2
 * sound.c
3
 * Copyright (C) 1998 Brainchild Design - http://brainchilddesign.com/
4
 *
5
 * Copyright (C) 2001 Chuck Mason 
6
 *
7
 * Copyright (C) 2002 Florian Schulze 
8
 *
9
 * This file is part of Jump'n'Bump.
10
 *
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.
15
 *
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.
20
 *
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
24
 */
25
 
26
#include "globals.h"
27
#include 
28
#ifndef _MSC_VER
29
#include 
30
#endif
31
#include "SDL.h"
32
 
33
#ifndef NO_SDL_MIXER
34
#include "SDL_mixer.h"
35
 
36
static Mix_Music *current_music = (Mix_Music *) NULL;
37
#endif
38
 
39
sfx_data sounds[NUM_SFX];
40
 
41
static int SAMPLECOUNT = 512;
42
 
43
#define MAX_CHANNELS	32
44
 
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;
61
 
62
channel_info_t channelinfo[MAX_CHANNELS];
63
 
64
/* Sample rate in samples/second */
65
int audio_rate = 44100;
66
int global_sfx_volume = 0;
67
/*
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.
75
//
76
// This function currently supports only 16bit.
77
*/
78
 
79
static void stopchan(int i)
80
{
81
	if (channelinfo[i].data) {
82
		memset(&channelinfo[i], 0, sizeof(channel_info_t));
83
	}
84
}
85
 
86
 
87
/*
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.
93
*/
94
int addsfx(signed short *data, int len, int loop, int samplerate, int channel)
95
{
96
	stopchan(channel);
97
 
98
	/* We will handle the new SFX. */
99
	/* Set pointer to raw data. */
100
	channelinfo[channel].data = data;
101
	channelinfo[channel].startdata = data;
102
 
103
	/* Set pointer to end of raw data. */
104
	channelinfo[channel].enddata = channelinfo[channel].data + len - 1;
105
	channelinfo[channel].samplerate = samplerate;
106
 
107
	channelinfo[channel].loop = loop;
108
	channelinfo[channel].stepremainder = 0;
109
 
110
	return channel;
111
}
112
 
113
 
114
static void updateSoundParams(int slot, int volume)
115
{
116
	int rightvol;
117
	int leftvol;
118
 
119
	/*
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
125
	*/
126
	channelinfo[slot].step = ((channelinfo[slot].samplerate<<16)/audio_rate);
127
 
128
	leftvol = volume;
129
	rightvol= volume;
130
 
131
	/* Sanity check, clamp volume. */
132
	if (rightvol < 0)
133
		rightvol = 0;
134
	if (rightvol > 127)
135
		rightvol = 127;
136
 
137
	if (leftvol < 0)
138
		leftvol = 0;
139
	if (leftvol > 127)
140
		leftvol = 127;
141
 
142
	channelinfo[slot].leftvol = leftvol;
143
	channelinfo[slot].rightvol = rightvol;
144
}
145
 
146
 
147
void mix_sound(void *unused, Uint8 *stream, int len)
148
{
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;
154
 
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;
161
 
162
	/* Mixing channel index. */
163
	int       chan;
164
 
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;
170
 
171
	/* Determine end, for left channel only */
172
	/*  (right channel is implicit). */
173
	leftend = leftout + (len/4)*step;
174
 
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;
182
 
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;
195
 
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;
208
 
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);
215
					}
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 = MIX_DEFAULT_FORMAT;
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
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
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
	unsigned 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");
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;
495
	}
496
 
497
	if (Mix_PlayingMusic())
498
		Mix_FadeOutMusic(1500);
499
 
500
	if (current_music) {
501
		Mix_FreeMusic(current_music);
502
		current_music = NULL;
503
	}
504
 
505
	if (fp == NULL) {
506
		return 0;
507
	}
508
 
509
	tmp = fopen(filename, "wb");
510
	if (tmp) {
511
        fwrite(fp, len, 1, tmp);
512
		fflush(tmp);
513
		fclose(tmp);
514
	}
515
 
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;
521
	}
522
 
523
#endif
524
 
525
	return 0;
526
}
527
 
528
char dj_start_mod(void)
529
{
530
#ifndef NO_SDL_MIXER
531
	if (main_info.no_sound)
532
		return 0;
533
 
534
	Mix_VolumeMusic(0);
535
	Mix_PlayMusic(current_music, -1);
536
#endif
537
 
538
	return 0;
539
}
540
 
541
void dj_stop_mod(void)
542
{
543
#ifndef NO_SDL_MIXER
544
	if (main_info.no_sound)
545
		return;
546
 
547
	Mix_HaltMusic();
548
#endif
549
}
550
 
551
void dj_set_mod_volume(char volume)
552
{
553
#ifndef NO_SDL_MIXER
554
	if (main_info.no_sound)
555
		return;
556
 
557
	Mix_VolumeMusic(volume);
558
#endif
559
}
560
 
561
char dj_load_mod(unsigned char * file_handle, char *filename, char mod_num)
562
{
563
	return 0;
564
}
565
 
566
void dj_free_mod(char mod_num)
567
{
568
}