Skip to content

Latest commit

 

History

History
867 lines (779 loc) · 20.9 KB

mixer.c

File metadata and controls

867 lines (779 loc) · 20.9 KB
 
Oct 21, 1999
Oct 21, 1999
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*
MIXERLIB: An audio mixer library based on the SDL library
Copyright (C) 1997-1999 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
5635-34 Springhouse Dr.
Pleasanton, CA 94588 (USA)
slouken@devolution.com
*/
Oct 26, 1999
Oct 26, 1999
25
26
/* $Id$ */
Oct 21, 1999
Oct 21, 1999
27
28
29
30
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Dec 21, 1999
Dec 21, 1999
31
32
#include "SDL_mutex.h"
#include "SDL_endian.h"
Dec 27, 1999
Dec 27, 1999
33
#include "SDL_timer.h"
Oct 21, 1999
Oct 21, 1999
34
Jan 14, 2000
Jan 14, 2000
35
#include "SDL_mixer.h"
Oct 21, 1999
Oct 21, 1999
36
37
38
39
40
41
42
43
44
45
46
47
static int audio_opened = 0;
static SDL_AudioSpec mixer;
static SDL_mutex *mixer_lock;
static struct _Mix_Channel {
Mix_Chunk *chunk;
int playing;
int paused;
Uint8 *samples;
int volume;
int looping;
Oct 26, 1999
Oct 26, 1999
48
int tag;
Feb 1, 2000
Feb 1, 2000
49
Uint32 expire;
Oct 27, 1999
Oct 27, 1999
50
Uint32 start_time;
Oct 23, 1999
Oct 23, 1999
51
52
Mix_Fading fading;
int fade_volume;
Feb 1, 2000
Feb 1, 2000
53
Uint32 fade_length;
Oct 23, 1999
Oct 23, 1999
54
Uint32 ticks_fade;
Jun 26, 2000
Jun 26, 2000
55
} *mix_channel = NULL;
Oct 26, 1999
Oct 26, 1999
56
static int num_channels;
Nov 11, 1999
Nov 11, 1999
57
static int reserved_channels = 0;
Oct 21, 1999
Oct 21, 1999
58
59
Dec 26, 1999
Dec 26, 1999
60
61
/* Support for hooking into the mixer callback system */
static void (*mix_postmix)(void *udata, Uint8 *stream, int len) = NULL;
Dec 27, 1999
Dec 27, 1999
62
static void *mix_postmix_data = NULL;
Dec 26, 1999
Dec 26, 1999
63
Feb 1, 2000
Feb 1, 2000
64
65
66
67
/* Music function declarations */
extern int open_music(SDL_AudioSpec *mixer);
extern void close_music(void);
Oct 21, 1999
Oct 21, 1999
68
/* Support for user defined music functions, plus the default one */
Feb 1, 2000
Feb 1, 2000
69
extern int volatile music_active;
Oct 21, 1999
Oct 21, 1999
70
71
extern void music_mixer(void *udata, Uint8 *stream, int len);
static void (*mix_music)(void *udata, Uint8 *stream, int len) = music_mixer;
Feb 1, 2000
Feb 1, 2000
72
static void *music_data = NULL;
Oct 21, 1999
Oct 21, 1999
73
74
75
76
77
/* Mixing function */
static void mix_channels(void *udata, Uint8 *stream, int len)
{
int i, mixable, volume;
Oct 26, 1999
Oct 26, 1999
78
Uint32 sdl_ticks;
Oct 21, 1999
Oct 21, 1999
79
Nov 8, 1999
Nov 8, 1999
80
/* Mix the music (must be done before the channels are added) */
Nov 11, 1999
Nov 11, 1999
81
if ( music_active || (mix_music != music_mixer) ) {
Nov 8, 1999
Nov 8, 1999
82
83
84
mix_music(music_data, stream, len);
}
Oct 21, 1999
Oct 21, 1999
85
86
/* Grab the channels we need to mix */
SDL_mutexP(mixer_lock);
Oct 26, 1999
Oct 26, 1999
87
88
sdl_ticks = SDL_GetTicks();
for ( i=0; i<num_channels; ++i ) {
Jun 26, 2000
Jun 26, 2000
89
90
if( ! mix_channel[i].paused ) {
if ( mix_channel[i].expire > 0 && mix_channel[i].expire < sdl_ticks ) {
Oct 27, 1999
Oct 27, 1999
91
/* Expiration delay for that channel is reached */
Jun 26, 2000
Jun 26, 2000
92
93
94
95
96
97
98
99
100
101
mix_channel[i].playing = 0;
mix_channel[i].fading = MIX_NO_FADING;
mix_channel[i].expire = 0;
} else if ( mix_channel[i].fading != MIX_NO_FADING ) {
Uint32 ticks = sdl_ticks - mix_channel[i].ticks_fade;
if( ticks > mix_channel[i].fade_length ) {
if( mix_channel[i].fading == MIX_FADING_OUT ) {
mix_channel[i].playing = 0;
mix_channel[i].expire = 0;
Mix_Volume(i, mix_channel[i].fading); /* Restore the volume */
Oct 27, 1999
Oct 27, 1999
102
}
Jun 26, 2000
Jun 26, 2000
103
mix_channel[i].fading = MIX_NO_FADING;
Oct 23, 1999
Oct 23, 1999
104
} else {
Jun 26, 2000
Jun 26, 2000
105
106
107
if( mix_channel[i].fading == MIX_FADING_OUT ) {
Mix_Volume(i, (mix_channel[i].fade_volume * (mix_channel[i].fade_length-ticks))
/ mix_channel[i].fade_length );
Oct 27, 1999
Oct 27, 1999
108
} else {
Jun 26, 2000
Jun 26, 2000
109
Mix_Volume(i, (mix_channel[i].fade_volume * ticks) / mix_channel[i].fade_length );
Oct 27, 1999
Oct 27, 1999
110
}
Oct 23, 1999
Oct 23, 1999
111
112
}
}
Jun 26, 2000
Jun 26, 2000
113
114
115
if ( mix_channel[i].playing > 0 ) {
volume = (mix_channel[i].volume*mix_channel[i].chunk->volume) / MIX_MAX_VOLUME;
mixable = mix_channel[i].playing;
Feb 2, 2000
Feb 2, 2000
116
117
118
if ( mixable > len ) {
mixable = len;
}
Jun 26, 2000
Jun 26, 2000
119
120
121
SDL_MixAudio(stream,mix_channel[i].samples,mixable,volume);
mix_channel[i].samples += mixable;
mix_channel[i].playing -= mixable;
Nov 30, 1999
Nov 30, 1999
122
123
/* If looping the sample and we are at its end, make sure
we will still return a full buffer */
Jun 26, 2000
Jun 26, 2000
124
while ( mix_channel[i].looping && mixable < len ) {
Feb 2, 2000
Feb 2, 2000
125
int remaining = len - mixable;
Jun 26, 2000
Jun 26, 2000
126
int alen = mix_channel[i].chunk->alen;
Feb 2, 2000
Feb 2, 2000
127
128
129
if (remaining > alen) {
remaining = alen;
}
Jun 26, 2000
Jun 26, 2000
130
131
132
133
SDL_MixAudio(stream+mixable, mix_channel[i].chunk->abuf, remaining, volume);
--mix_channel[i].looping;
mix_channel[i].samples = mix_channel[i].chunk->abuf + remaining;
mix_channel[i].playing = mix_channel[i].chunk->alen - remaining;
Feb 2, 2000
Feb 2, 2000
134
135
mixable += remaining;
}
Jun 26, 2000
Jun 26, 2000
136
137
138
139
if ( ! mix_channel[i].playing && mix_channel[i].looping ) {
if ( --mix_channel[i].looping ) {
mix_channel[i].samples = mix_channel[i].chunk->abuf;
mix_channel[i].playing = mix_channel[i].chunk->alen;
Oct 27, 1999
Oct 27, 1999
140
}
Oct 21, 1999
Oct 21, 1999
141
142
143
144
}
}
}
}
Dec 26, 1999
Dec 26, 1999
145
146
147
if ( mix_postmix ) {
mix_postmix(mix_postmix_data, stream, len);
}
Oct 21, 1999
Oct 21, 1999
148
149
150
151
152
153
154
155
156
157
158
SDL_mutexV(mixer_lock);
}
static void PrintFormat(char *title, SDL_AudioSpec *fmt)
{
printf("%s: %d bit %s audio (%s) at %u Hz\n", title, (fmt->format&0xFF),
(fmt->format&0x8000) ? "signed" : "unsigned",
(fmt->channels > 1) ? "stereo" : "mono", fmt->freq);
}
/* Open the mixer with a certain desired audio format */
Jun 26, 2000
Jun 26, 2000
159
int Mix_OpenAudio(int frequency, Uint16 format, int nchannels, int chunksize)
Oct 21, 1999
Oct 21, 1999
160
161
162
163
164
165
166
167
168
169
170
171
172
{
int i;
SDL_AudioSpec desired;
/* If the mixer is already opened, increment open count */
if ( audio_opened ) {
++audio_opened;
return(0);
}
/* Set the desired format and frequency */
desired.freq = frequency;
desired.format = format;
Jun 26, 2000
Jun 26, 2000
173
desired.channels = nchannels;
Oct 21, 1999
Oct 21, 1999
174
175
176
177
178
179
180
181
182
183
184
185
186
187
desired.samples = chunksize;
desired.callback = mix_channels;
desired.userdata = NULL;
/* Accept nearly any audio format */
if ( SDL_OpenAudio(&desired, &mixer) < 0 ) {
return(-1);
}
#if 0
PrintFormat("Audio device", &mixer);
#endif
/* Create the channel lock mutex */
mixer_lock = SDL_CreateMutex();
Feb 11, 2000
Feb 11, 2000
188
#ifndef macintosh /* Hmm.. what implications does this have? */
Oct 21, 1999
Oct 21, 1999
189
190
191
192
193
if ( mixer_lock == NULL ) {
SDL_CloseAudio();
SDL_SetError("Unable to create mixer lock");
return(-1);
}
Feb 11, 2000
Feb 11, 2000
194
#endif
Oct 21, 1999
Oct 21, 1999
195
196
197
198
199
200
201
/* Initialize the music players */
if ( open_music(&mixer) < 0 ) {
SDL_CloseAudio();
SDL_DestroyMutex(mixer_lock);
return(-1);
}
Oct 26, 1999
Oct 26, 1999
202
203
num_channels = MIX_CHANNELS;
Jun 26, 2000
Jun 26, 2000
204
mix_channel = (struct _Mix_Channel *) malloc(num_channels * sizeof(struct _Mix_Channel));
Oct 26, 1999
Oct 26, 1999
205
Oct 21, 1999
Oct 21, 1999
206
/* Clear out the audio channels */
Oct 26, 1999
Oct 26, 1999
207
for ( i=0; i<num_channels; ++i ) {
Jun 26, 2000
Jun 26, 2000
208
209
210
211
212
213
mix_channel[i].chunk = NULL;
mix_channel[i].playing = 0;
mix_channel[i].looping = 0;
mix_channel[i].volume = SDL_MIX_MAXVOLUME;
mix_channel[i].tag = -1;
mix_channel[i].expire = 0;
Oct 21, 1999
Oct 21, 1999
214
215
216
217
218
219
220
}
Mix_VolumeMusic(SDL_MIX_MAXVOLUME);
audio_opened = 1;
SDL_PauseAudio(0);
return(0);
}
Oct 26, 1999
Oct 26, 1999
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
/* Dynamically change the number of channels managed by the mixer.
If decreasing the number of channels, the upper channels are
stopped.
*/
int Mix_AllocateChannels(int numchans)
{
if ( numchans<0 || numchans==num_channels )
return(num_channels);
if ( numchans < num_channels ) {
/* Stop the affected channels */
int i;
for(i=numchans; i < num_channels; i++) {
Mix_HaltChannel(i);
}
}
SDL_mutexP(mixer_lock);
Jun 26, 2000
Jun 26, 2000
238
mix_channel = (struct _Mix_Channel *) realloc(mix_channel, numchans * sizeof(struct _Mix_Channel));
Oct 26, 1999
Oct 26, 1999
239
240
241
242
if ( numchans > num_channels ) {
/* Initialize the new channels */
int i;
for(i=num_channels; i < numchans; i++) {
Jun 26, 2000
Jun 26, 2000
243
244
245
246
247
248
mix_channel[i].chunk = NULL;
mix_channel[i].playing = 0;
mix_channel[i].looping = 0;
mix_channel[i].volume = SDL_MIX_MAXVOLUME;
mix_channel[i].tag = -1;
mix_channel[i].expire = 0;
Oct 26, 1999
Oct 26, 1999
249
250
251
252
253
254
255
}
}
num_channels = numchans;
SDL_mutexV(mixer_lock);
return(num_channels);
}
Oct 21, 1999
Oct 21, 1999
256
257
258
259
260
261
262
263
264
265
/* Return the actual mixer parameters */
int Mix_QuerySpec(int *frequency, Uint16 *format, int *channels)
{
if ( audio_opened ) {
if ( frequency ) {
*frequency = mixer.freq;
}
if ( format ) {
*format = mixer.format;
}
Jun 26, 2000
Jun 26, 2000
266
if ( mix_channels ) {
Oct 21, 1999
Oct 21, 1999
267
268
269
270
271
272
273
274
275
276
277
278
*channels = mixer.channels;
}
}
return(audio_opened);
}
/* Load a wave file */
Mix_Chunk *Mix_LoadWAV_RW(SDL_RWops *src, int freesrc)
{
Mix_Chunk *chunk;
SDL_AudioSpec wavespec;
SDL_AudioCVT wavecvt;
Jan 28, 2000
Jan 28, 2000
279
int samplesize;
Oct 21, 1999
Oct 21, 1999
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
/* Make sure audio has been opened */
if ( ! audio_opened ) {
SDL_SetError("Audio device hasn't been opened");
if ( freesrc ) {
SDL_RWclose(src);
}
return(NULL);
}
/* Allocate the chunk memory */
chunk = (Mix_Chunk *)malloc(sizeof(Mix_Chunk));
if ( chunk == NULL ) {
SDL_SetError("Out of memory");
if ( freesrc ) {
SDL_RWclose(src);
}
return(NULL);
}
/* Load the WAV file into the chunk */
if ( SDL_LoadWAV_RW(src, freesrc,
&wavespec, (Uint8 **)&chunk->abuf, &chunk->alen) == NULL ) {
free(chunk);
return(NULL);
}
#if 0
PrintFormat("Audio device", &mixer);
PrintFormat("-- Wave file", &wavespec);
#endif
/* Build the audio converter and create conversion buffers */
if ( SDL_BuildAudioCVT(&wavecvt,
wavespec.format, wavespec.channels, wavespec.freq,
mixer.format, mixer.channels, mixer.freq) < 0 ) {
SDL_FreeWAV(chunk->abuf);
free(chunk);
return(NULL);
}
Jan 28, 2000
Jan 28, 2000
319
320
samplesize = ((wavespec.format & 0xFF)/8)*wavespec.channels;
wavecvt.len = chunk->alen & ~(samplesize-1);
Oct 21, 1999
Oct 21, 1999
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
wavecvt.buf = (Uint8 *)malloc(wavecvt.len*wavecvt.len_mult);
if ( wavecvt.buf == NULL ) {
SDL_SetError("Out of memory");
SDL_FreeWAV(chunk->abuf);
free(chunk);
return(NULL);
}
memcpy(wavecvt.buf, chunk->abuf, chunk->alen);
SDL_FreeWAV(chunk->abuf);
/* Run the audio converter */
if ( SDL_ConvertAudio(&wavecvt) < 0 ) {
free(wavecvt.buf);
free(chunk);
return(NULL);
}
Oct 21, 1999
Oct 21, 1999
337
chunk->allocated = 1;
Oct 21, 1999
Oct 21, 1999
338
339
340
341
342
343
chunk->abuf = wavecvt.buf;
chunk->alen = wavecvt.len_cvt;
chunk->volume = MIX_MAX_VOLUME;
return(chunk);
}
Oct 21, 1999
Oct 21, 1999
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
/* Load a wave file of the mixer format from a memory buffer */
Mix_Chunk *Mix_QuickLoad_WAV(Uint8 *mem)
{
Mix_Chunk *chunk;
Uint8 magic[4];
/* Make sure audio has been opened */
if ( ! audio_opened ) {
SDL_SetError("Audio device hasn't been opened");
return(NULL);
}
/* Allocate the chunk memory */
chunk = (Mix_Chunk *)malloc(sizeof(Mix_Chunk));
if ( chunk == NULL ) {
SDL_SetError("Out of memory");
return(NULL);
}
/* Essentially just skip to the audio data (no error checking - fast) */
chunk->allocated = 0;
mem += 12; /* WAV header */
do {
memcpy(magic, mem, 4);
mem += 4;
chunk->alen = ((mem[3]<<24)|(mem[2]<<16)|(mem[1]<<8)|(mem[0]));
mem += 4;
chunk->abuf = mem;
mem += chunk->alen;
} while ( memcmp(magic, "data", 4) != 0 );
chunk->volume = MIX_MAX_VOLUME;
return(chunk);
}
Oct 21, 1999
Oct 21, 1999
379
380
381
382
383
384
385
386
/* Free an audio chunk previously loaded */
void Mix_FreeChunk(Mix_Chunk *chunk)
{
int i;
/* Caution -- if the chunk is playing, the mixer will crash */
if ( chunk ) {
/* Guarantee that this chunk isn't playing */
Jun 26, 2000
Jun 26, 2000
387
388
389
390
391
392
if ( mix_channel ) {
SDL_mutexP(mixer_lock);
for ( i=0; i<num_channels; ++i ) {
if ( chunk == mix_channel[i].chunk ) {
mix_channel[i].playing = 0;
}
Oct 21, 1999
Oct 21, 1999
393
}
Jun 26, 2000
Jun 26, 2000
394
SDL_mutexV(mixer_lock);
Oct 21, 1999
Oct 21, 1999
395
396
397
}
/* Actually free the chunk */
Oct 21, 1999
Oct 21, 1999
398
399
400
if ( chunk->allocated ) {
free(chunk->abuf);
}
Oct 21, 1999
Oct 21, 1999
401
402
403
404
free(chunk);
}
}
Dec 26, 1999
Dec 26, 1999
405
406
407
408
409
410
411
412
413
414
415
416
417
/* Set a function that is called after all mixing is performed.
This can be used to provide real-time visual display of the audio stream
or add a custom mixer filter for the stream data.
*/
void Mix_SetPostMix(void (*mix_func)
(void *udata, Uint8 *stream, int len), void *arg)
{
SDL_LockAudio();
mix_postmix_data = arg;
mix_postmix = mix_func;
SDL_UnlockAudio();
}
Oct 21, 1999
Oct 21, 1999
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
/* Add your own music player or mixer function.
If 'mix_func' is NULL, the default music player is re-enabled.
*/
void Mix_HookMusic(void (*mix_func)(void *udata, Uint8 *stream, int len),
void *arg)
{
SDL_LockAudio();
if ( mix_func != NULL ) {
music_data = arg;
mix_music = mix_func;
} else {
music_data = NULL;
mix_music = music_mixer;
}
SDL_UnlockAudio();
}
void *Mix_GetMusicHookData(void)
{
return(music_data);
}
/* Reserve the first channels (0 -> n-1) for the application, i.e. don't allocate
them dynamically to the next sample if requested with a -1 value below.
Returns the number of reserved channels.
*/
int Mix_ReserveChannels(int num)
{
Oct 26, 1999
Oct 26, 1999
446
447
if (num > num_channels)
num = num_channels;
Oct 21, 1999
Oct 21, 1999
448
449
450
451
452
453
reserved_channels = num;
return num;
}
/* Play an audio chunk on a specific channel.
If the specified channel is -1, play on the first free channel.
Oct 26, 1999
Oct 26, 1999
454
455
'ticks' is the number of milliseconds at most to play the sample, or -1
if there is no limit.
Oct 21, 1999
Oct 21, 1999
456
457
Returns which channel was used to play the sound.
*/
Oct 26, 1999
Oct 26, 1999
458
int Mix_PlayChannelTimed(int which, Mix_Chunk *chunk, int loops, int ticks)
Oct 21, 1999
Oct 21, 1999
459
460
461
462
463
464
465
466
467
468
469
470
471
{
int i;
/* Don't play null pointers :-) */
if ( chunk == NULL ) {
return(-1);
}
/* Lock the mixer while modifying the playing channels */
SDL_mutexP(mixer_lock);
{
/* If which is -1, play on the first free channel */
if ( which == -1 ) {
Oct 26, 1999
Oct 26, 1999
472
for ( i=reserved_channels; i<num_channels; ++i ) {
Jun 26, 2000
Jun 26, 2000
473
if ( mix_channel[i].playing <= 0 )
Oct 21, 1999
Oct 21, 1999
474
475
break;
}
Oct 26, 1999
Oct 26, 1999
476
if ( i == num_channels ) {
Oct 21, 1999
Oct 21, 1999
477
478
479
480
481
482
483
484
which = -1;
} else {
which = i;
}
}
/* Queue up the audio data for this channel */
if ( which >= 0 ) {
Oct 27, 1999
Oct 27, 1999
485
Uint32 sdl_ticks = SDL_GetTicks();
Jun 26, 2000
Jun 26, 2000
486
487
488
489
490
491
492
493
mix_channel[which].samples = chunk->abuf;
mix_channel[which].playing = chunk->alen;
mix_channel[which].looping = loops;
mix_channel[which].chunk = chunk;
mix_channel[which].paused = 0;
mix_channel[which].fading = MIX_NO_FADING;
mix_channel[which].start_time = sdl_ticks;
mix_channel[which].expire = (ticks>0) ? (sdl_ticks + ticks) : 0;
Oct 23, 1999
Oct 23, 1999
494
495
496
497
498
499
500
501
}
}
SDL_mutexV(mixer_lock);
/* Return the channel on which the sound is being played */
return(which);
}
Oct 26, 1999
Oct 26, 1999
502
503
504
505
506
507
508
509
510
511
512
513
/* Change the expiration delay for a channel */
int Mix_ExpireChannel(int which, int ticks)
{
int status = 0;
if ( which == -1 ) {
int i;
for ( i=0; i < num_channels; ++ i ) {
status += Mix_ExpireChannel(i, ticks);
}
} else if ( which < num_channels ) {
SDL_mutexP(mixer_lock);
Jun 26, 2000
Jun 26, 2000
514
mix_channel[which].expire = (ticks>0) ? (SDL_GetTicks() + ticks) : 0;
Oct 26, 1999
Oct 26, 1999
515
516
517
518
519
520
SDL_mutexV(mixer_lock);
++ status;
}
return(status);
}
Oct 23, 1999
Oct 23, 1999
521
/* Fade in a sound on a channel, over ms milliseconds */
Oct 26, 1999
Oct 26, 1999
522
int Mix_FadeInChannelTimed(int which, Mix_Chunk *chunk, int loops, int ms, int ticks)
Oct 23, 1999
Oct 23, 1999
523
524
525
526
527
528
529
530
531
532
533
534
535
{
int i;
/* Don't play null pointers :-) */
if ( chunk == NULL ) {
return(-1);
}
/* Lock the mixer while modifying the playing channels */
SDL_mutexP(mixer_lock);
{
/* If which is -1, play on the first free channel */
if ( which == -1 ) {
Oct 26, 1999
Oct 26, 1999
536
for ( i=reserved_channels; i<num_channels; ++i ) {
Jun 26, 2000
Jun 26, 2000
537
if ( mix_channel[i].playing <= 0 )
Oct 23, 1999
Oct 23, 1999
538
539
break;
}
Oct 26, 1999
Oct 26, 1999
540
if ( i == num_channels ) {
Oct 23, 1999
Oct 23, 1999
541
542
543
544
545
546
547
548
which = -1;
} else {
which = i;
}
}
/* Queue up the audio data for this channel */
if ( which >= 0 ) {
Oct 27, 1999
Oct 27, 1999
549
Uint32 sdl_ticks = SDL_GetTicks();
Jun 26, 2000
Jun 26, 2000
550
551
552
553
554
555
556
557
558
559
560
mix_channel[which].samples = chunk->abuf;
mix_channel[which].playing = chunk->alen;
mix_channel[which].looping = loops;
mix_channel[which].chunk = chunk;
mix_channel[which].paused = 0;
mix_channel[which].fading = MIX_FADING_IN;
mix_channel[which].fade_volume = mix_channel[which].volume;
mix_channel[which].volume = 0;
mix_channel[which].fade_length = (Uint32)ms;
mix_channel[which].start_time = mix_channel[which].ticks_fade = sdl_ticks;
mix_channel[which].expire = (ticks > 0) ? (sdl_ticks+ticks) : 0;
Oct 21, 1999
Oct 21, 1999
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
}
}
SDL_mutexV(mixer_lock);
/* Return the channel on which the sound is being played */
return(which);
}
/* Set volume of a particular channel */
int Mix_Volume(int which, int volume)
{
int i;
int prev_volume;
if ( which == -1 ) {
prev_volume = 0;
Oct 26, 1999
Oct 26, 1999
577
for ( i=0; i<num_channels; ++i ) {
Oct 21, 1999
Oct 21, 1999
578
579
prev_volume += Mix_Volume(i, volume);
}
Oct 26, 1999
Oct 26, 1999
580
prev_volume /= num_channels;
Oct 21, 1999
Oct 21, 1999
581
} else {
Jun 26, 2000
Jun 26, 2000
582
prev_volume = mix_channel[which].volume;
Oct 23, 1999
Oct 23, 1999
583
584
if ( volume < 0 ) {
volume = 0;
Oct 21, 1999
Oct 21, 1999
585
}
Oct 23, 1999
Oct 23, 1999
586
587
588
if ( volume > SDL_MIX_MAXVOLUME ) {
volume = SDL_MIX_MAXVOLUME;
}
Jun 26, 2000
Jun 26, 2000
589
mix_channel[which].volume = volume;
Oct 21, 1999
Oct 21, 1999
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
}
return(prev_volume);
}
/* Set volume of a particular chunk */
int Mix_VolumeChunk(Mix_Chunk *chunk, int volume)
{
int prev_volume;
prev_volume = chunk->volume;
if ( volume >= 0 ) {
if ( volume > MIX_MAX_VOLUME ) {
volume = MIX_MAX_VOLUME;
}
chunk->volume = volume;
}
return(prev_volume);
}
/* Halt playing of a particular channel */
int Mix_HaltChannel(int which)
{
int i;
if ( which == -1 ) {
Oct 26, 1999
Oct 26, 1999
614
for ( i=0; i<num_channels; ++i ) {
Oct 21, 1999
Oct 21, 1999
615
616
617
618
Mix_HaltChannel(i);
}
} else {
SDL_mutexP(mixer_lock);
Jun 26, 2000
Jun 26, 2000
619
620
621
622
623
mix_channel[which].playing = 0;
mix_channel[which].expire = 0;
if(mix_channel[which].fading != MIX_NO_FADING) /* Restore volume */
mix_channel[which].volume = mix_channel[which].fade_volume;
mix_channel[which].fading = MIX_NO_FADING;
Oct 21, 1999
Oct 21, 1999
624
625
626
627
628
SDL_mutexV(mixer_lock);
}
return(0);
}
Oct 26, 1999
Oct 26, 1999
629
630
631
632
633
634
/* Halt playing of a particular group of channels */
int Mix_HaltGroup(int tag)
{
int i;
for ( i=0; i<num_channels; ++i ) {
Jun 26, 2000
Jun 26, 2000
635
if( mix_channel[i].tag == tag ) {
Oct 26, 1999
Oct 26, 1999
636
637
638
639
640
641
Mix_HaltChannel(i);
}
}
return(0);
}
Oct 23, 1999
Oct 23, 1999
642
643
644
645
646
647
648
649
650
/* Fade out a channel and then stop it automatically */
int Mix_FadeOutChannel(int which, int ms)
{
int status;
status = 0;
if ( which == -1 ) {
int i;
Oct 26, 1999
Oct 26, 1999
651
for ( i=0; i<num_channels; ++i ) {
Oct 23, 1999
Oct 23, 1999
652
653
654
655
status += Mix_FadeOutChannel(i,ms);
}
} else {
SDL_mutexP(mixer_lock);
Jun 26, 2000
Jun 26, 2000
656
if ( mix_channel[which].playing && mix_channel[which].volume>0 &&
Nov 17, 2000
Nov 17, 2000
657
mix_channel[which].fading!=MIX_FADING_OUT ) {
Oct 23, 1999
Oct 23, 1999
658
Jun 26, 2000
Jun 26, 2000
659
660
661
662
mix_channel[which].fading = MIX_FADING_OUT;
mix_channel[which].fade_volume = mix_channel[which].volume;
mix_channel[which].fade_length = ms;
mix_channel[which].ticks_fade = SDL_GetTicks();
Oct 23, 1999
Oct 23, 1999
663
664
665
666
667
668
669
++ status;
}
SDL_mutexV(mixer_lock);
}
return(status);
}
Oct 26, 1999
Oct 26, 1999
670
671
672
673
674
675
/* Halt playing of a particular group of channels */
int Mix_FadeOutGroup(int tag, int ms)
{
int i;
int status = 0;
for ( i=0; i<num_channels; ++i ) {
Jun 26, 2000
Jun 26, 2000
676
if( mix_channel[i].tag == tag ) {
Oct 26, 1999
Oct 26, 1999
677
678
679
680
681
682
status += Mix_FadeOutChannel(i,ms);
}
}
return(status);
}
Oct 23, 1999
Oct 23, 1999
683
684
Mix_Fading Mix_FadingChannel(int which)
{
Jun 26, 2000
Jun 26, 2000
685
return mix_channel[which].fading;
Oct 23, 1999
Oct 23, 1999
686
687
}
Oct 21, 1999
Oct 21, 1999
688
/* Check the status of a specific channel.
Jun 26, 2000
Jun 26, 2000
689
If the specified mix_channel is -1, check all mix_channels.
Oct 21, 1999
Oct 21, 1999
690
691
692
693
694
695
696
697
698
*/
int Mix_Playing(int which)
{
int status;
status = 0;
if ( which == -1 ) {
int i;
Oct 26, 1999
Oct 26, 1999
699
for ( i=0; i<num_channels; ++i ) {
Jun 26, 2000
Jun 26, 2000
700
if ( mix_channel[i].playing > 0 ) {
Oct 21, 1999
Oct 21, 1999
701
702
703
704
++status;
}
}
} else {
Jun 26, 2000
Jun 26, 2000
705
if ( mix_channel[which].playing > 0 ) {
Oct 21, 1999
Oct 21, 1999
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
++status;
}
}
return(status);
}
/* Close the mixer, halting all playing audio */
void Mix_CloseAudio(void)
{
if ( audio_opened ) {
if ( audio_opened == 1 ) {
close_music();
Mix_HaltChannel(-1);
SDL_CloseAudio();
SDL_DestroyMutex(mixer_lock);
Jun 26, 2000
Jun 26, 2000
721
722
free(mix_channel);
mix_channel = NULL;
Oct 21, 1999
Oct 21, 1999
723
724
725
726
727
728
729
730
}
--audio_opened;
}
}
/* Pause a particular channel (or all) */
void Mix_Pause(int which)
{
Oct 27, 1999
Oct 27, 1999
731
Uint32 sdl_ticks = SDL_GetTicks();
Oct 21, 1999
Oct 21, 1999
732
733
734
if ( which == -1 ) {
int i;
Oct 26, 1999
Oct 26, 1999
735
for ( i=0; i<num_channels; ++i ) {
Jun 26, 2000
Jun 26, 2000
736
737
if ( mix_channel[i].playing > 0 ) {
mix_channel[i].paused = sdl_ticks;
Oct 21, 1999
Oct 21, 1999
738
739
740
}
}
} else {
Jun 26, 2000
Jun 26, 2000
741
742
if ( mix_channel[which].playing > 0 ) {
mix_channel[which].paused = sdl_ticks;
Oct 21, 1999
Oct 21, 1999
743
744
745
746
747
748
749
}
}
}
/* Resume a paused channel */
void Mix_Resume(int which)
{
Oct 27, 1999
Oct 27, 1999
750
Uint32 sdl_ticks = SDL_GetTicks();
Oct 21, 1999
Oct 21, 1999
751
752
753
if ( which == -1 ) {
int i;
Oct 27, 1999
Oct 27, 1999
754
SDL_mutexP(mixer_lock);
Oct 26, 1999
Oct 26, 1999
755
for ( i=0; i<num_channels; ++i ) {
Jun 26, 2000
Jun 26, 2000
756
757
758
759
if ( mix_channel[i].playing > 0 ) {
if(mix_channel[i].expire > 0)
mix_channel[i].expire += sdl_ticks - mix_channel[i].paused;
mix_channel[i].paused = 0;
Oct 21, 1999
Oct 21, 1999
760
761
}
}
Oct 27, 1999
Oct 27, 1999
762
SDL_mutexV(mixer_lock);
Oct 21, 1999
Oct 21, 1999
763
} else {
Oct 27, 1999
Oct 27, 1999
764
SDL_mutexP(mixer_lock);
Jun 26, 2000
Jun 26, 2000
765
766
767
768
if ( mix_channel[which].playing > 0 ) {
if(mix_channel[which].expire > 0)
mix_channel[which].expire += sdl_ticks - mix_channel[which].paused;
mix_channel[which].paused = 0;
Oct 21, 1999
Oct 21, 1999
769
}
Oct 27, 1999
Oct 27, 1999
770
SDL_mutexV(mixer_lock);
Oct 21, 1999
Oct 21, 1999
771
772
}
}
Oct 26, 1999
Oct 26, 1999
773
Nov 1, 1999
Nov 1, 1999
774
775
int Mix_Paused(int which)
{
Nov 1, 1999
Nov 1, 1999
776
if ( which > num_channels )
Nov 1, 1999
Nov 1, 1999
777
return(0);
Nov 1, 1999
Nov 1, 1999
778
779
780
781
if ( which < 0 ) {
int status = 0;
int i;
for( i=0; i < num_channels; ++i ) {
Jun 26, 2000
Jun 26, 2000
782
if ( mix_channel[i].paused ) {
Nov 1, 1999
Nov 1, 1999
783
784
785
786
787
++ status;
}
}
return(status);
} else {
Jun 26, 2000
Jun 26, 2000
788
return(mix_channel[which].paused != 0);
Nov 1, 1999
Nov 1, 1999
789
}
Nov 1, 1999
Nov 1, 1999
790
791
}
Oct 26, 1999
Oct 26, 1999
792
793
794
795
796
797
798
/* Change the group of a channel */
int Mix_GroupChannel(int which, int tag)
{
if ( which < 0 || which > num_channels )
return(0);
SDL_mutexP(mixer_lock);
Jun 26, 2000
Jun 26, 2000
799
mix_channel[which].tag = tag;
Oct 26, 1999
Oct 26, 1999
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
SDL_mutexV(mixer_lock);
return(1);
}
/* Assign several consecutive channels to a group */
int Mix_GroupChannels(int from, int to, int tag)
{
int status = 0;
for( ; from <= to; ++ from ) {
status += Mix_GroupChannel(from, tag);
}
return(status);
}
/* Finds the first available channel in a group of channels */
int Mix_GroupAvailable(int tag)
{
int i;
for( i=0; i < num_channels; i ++ ) {
Jun 26, 2000
Jun 26, 2000
819
820
if ( ((tag == -1) || (tag == mix_channel[i].tag)) &&
(mix_channel[i].playing <= 0) )
Oct 26, 1999
Oct 26, 1999
821
822
823
824
825
826
827
828
829
830
return i;
}
return(-1);
}
int Mix_GroupCount(int tag)
{
int count = 0;
int i;
for( i=0; i < num_channels; i ++ ) {
Jun 26, 2000
Jun 26, 2000
831
if ( mix_channel[i].tag==tag || tag==-1 )
Oct 26, 1999
Oct 26, 1999
832
833
834
835
++ count;
}
return(count);
}
Oct 27, 1999
Oct 27, 1999
836
837
838
839
840
841
842
843
/* Finds the "oldest" sample playing in a group of channels */
int Mix_GroupOldest(int tag)
{
int chan = -1;
Uint32 mintime = SDL_GetTicks();
int i;
for( i=0; i < num_channels; i ++ ) {
Jun 26, 2000
Jun 26, 2000
844
845
846
if ( (mix_channel[i].tag==tag || tag==-1) && mix_channel[i].playing > 0
&& mix_channel[i].start_time <= mintime ) {
mintime = mix_channel[i].start_time;
Oct 27, 1999
Oct 27, 1999
847
848
849
850
851
852
853
854
855
856
857
858
859
chan = i;
}
}
return(chan);
}
/* Finds the "most recent" (i.e. last) sample playing in a group of channels */
int Mix_GroupNewer(int tag)
{
int chan = -1;
Uint32 maxtime = 0;
int i;
for( i=0; i < num_channels; i ++ ) {
Jun 26, 2000
Jun 26, 2000
860
861
862
if ( (mix_channel[i].tag==tag || tag==-1) && mix_channel[i].playing > 0
&& mix_channel[i].start_time >= maxtime ) {
maxtime = mix_channel[i].start_time;
Oct 27, 1999
Oct 27, 1999
863
864
865
866
867
chan = i;
}
}
return(chan);
}