source: sdl_mixer/trunk/mixer.c@ 1452

Last change on this file since 1452 was 1452, checked in by valerius, 9 years ago

sdl_mixer: Apply OS/2-specific patches.

File size: 35.0 KB
Line 
1/*
2 SDL_mixer: An audio mixer library based on the SDL library
3 Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21
22/* $Id$ */
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27
28#include "SDL_mutex.h"
29#include "SDL_endian.h"
30#include "SDL_timer.h"
31
32#include "SDL_mixer.h"
33#include "load_aiff.h"
34#include "load_voc.h"
35#include "load_ogg.h"
36#include "load_flac.h"
37#include "dynamic_flac.h"
38#include "dynamic_mod.h"
39#include "dynamic_mp3.h"
40#include "dynamic_ogg.h"
41
42#define __MIX_INTERNAL_EFFECT__
43#include "effects_internal.h"
44
45/* Magic numbers for various audio file formats */
46#define RIFF 0x46464952 /* "RIFF" */
47#define WAVE 0x45564157 /* "WAVE" */
48#define FORM 0x4d524f46 /* "FORM" */
49#define OGGS 0x5367674f /* "OggS" */
50#define CREA 0x61657243 /* "Crea" */
51#define FLAC 0x43614C66 /* "fLaC" */
52
53static int audio_opened = 0;
54static SDL_AudioSpec mixer;
55
56typedef struct _Mix_effectinfo
57{
58 Mix_EffectFunc_t callback;
59 Mix_EffectDone_t done_callback;
60 void *udata;
61 struct _Mix_effectinfo *next;
62} effect_info;
63
64static struct _Mix_Channel {
65 Mix_Chunk *chunk;
66 int playing;
67 int paused;
68 Uint8 *samples;
69 int volume;
70 int looping;
71 int tag;
72 Uint32 expire;
73 Uint32 start_time;
74 Mix_Fading fading;
75 int fade_volume;
76 int fade_volume_reset;
77 Uint32 fade_length;
78 Uint32 ticks_fade;
79 effect_info *effects;
80} *mix_channel = NULL;
81
82static effect_info *posteffects = NULL;
83
84static int num_channels;
85static int reserved_channels = 0;
86
87
88/* Support for hooking into the mixer callback system */
89static void (*mix_postmix)(void *udata, Uint8 *stream, int len) = NULL;
90static void *mix_postmix_data = NULL;
91
92/* rcg07062001 callback to alert when channels are done playing. */
93static void (*channel_done_callback)(int channel) = NULL;
94
95/* Music function declarations */
96extern int open_music(SDL_AudioSpec *mixer);
97extern void close_music(void);
98
99/* Support for user defined music functions, plus the default one */
100extern int volatile music_active;
101extern void music_mixer(void *udata, Uint8 *stream, int len);
102static void (*mix_music)(void *udata, Uint8 *stream, int len) = music_mixer;
103static void *music_data = NULL;
104
105/* rcg06042009 report available decoders at runtime. */
106static const char **chunk_decoders = NULL;
107static int num_decoders = 0;
108
109/* Semicolon-separated SoundFont paths */
110#ifdef MID_MUSIC
111extern char* soundfont_paths;
112#endif
113
114int Mix_GetNumChunkDecoders(void)
115{
116 return(num_decoders);
117}
118
119const char *Mix_GetChunkDecoder(int index)
120{
121 if ((index < 0) || (index >= num_decoders)) {
122 return NULL;
123 }
124 return(chunk_decoders[index]);
125}
126
127static void add_chunk_decoder(const char *decoder)
128{
129 void *ptr = SDL_realloc(chunk_decoders, (num_decoders + 1) * sizeof (const char **));
130 if (ptr == NULL) {
131 return; /* oh well, go on without it. */
132 }
133 chunk_decoders = (const char **) ptr;
134 chunk_decoders[num_decoders++] = decoder;
135}
136
137/* rcg06192001 get linked library's version. */
138const SDL_version *Mix_Linked_Version(void)
139{
140 static SDL_version linked_version;
141 SDL_MIXER_VERSION(&linked_version);
142 return(&linked_version);
143}
144
145static int initialized = 0;
146
147int Mix_Init(int flags)
148{
149 int result = 0;
150
151 if (flags & MIX_INIT_FLUIDSYNTH) {
152#ifdef USE_FLUIDSYNTH_MIDI
153 if ((initialized & MIX_INIT_FLUIDSYNTH) || Mix_InitFluidSynth() == 0) {
154 result |= MIX_INIT_FLUIDSYNTH;
155 }
156#else
157 Mix_SetError("Mixer not built with FluidSynth support");
158#endif
159 }
160 if (flags & MIX_INIT_FLAC) {
161#ifdef FLAC_MUSIC
162 if ((initialized & MIX_INIT_FLAC) || Mix_InitFLAC() == 0) {
163 result |= MIX_INIT_FLAC;
164 }
165#else
166 Mix_SetError("Mixer not built with FLAC support");
167#endif
168 }
169 if (flags & MIX_INIT_MOD) {
170#ifdef MOD_MUSIC
171 if ((initialized & MIX_INIT_MOD) || Mix_InitMOD() == 0) {
172 result |= MIX_INIT_MOD;
173 }
174#else
175 Mix_SetError("Mixer not built with MOD support");
176#endif
177 }
178 if (flags & MIX_INIT_MP3) {
179#ifdef MP3_MUSIC
180 if ((initialized & MIX_INIT_MP3) || Mix_InitMP3() == 0) {
181 result |= MIX_INIT_MP3;
182 }
183#else
184 Mix_SetError("Mixer not built with MP3 support");
185#endif
186 }
187 if (flags & MIX_INIT_OGG) {
188#ifdef OGG_MUSIC
189 if ((initialized & MIX_INIT_OGG) || Mix_InitOgg() == 0) {
190 result |= MIX_INIT_OGG;
191 }
192#else
193 Mix_SetError("Mixer not built with Ogg Vorbis support");
194#endif
195 }
196 initialized |= result;
197
198 return (result);
199}
200
201void Mix_Quit()
202{
203#ifdef USE_FLUIDSYNTH_MIDI
204 if (initialized & MIX_INIT_FLUIDSYNTH) {
205 Mix_QuitFluidSynth();
206 }
207#endif
208#ifdef FLAC_MUSIC
209 if (initialized & MIX_INIT_FLAC) {
210 Mix_QuitFLAC();
211 }
212#endif
213#ifdef MOD_MUSIC
214 if (initialized & MIX_INIT_MOD) {
215 Mix_QuitMOD();
216 }
217#endif
218#ifdef MP3_MUSIC
219 if (initialized & MIX_INIT_MP3) {
220 Mix_QuitMP3();
221 }
222#endif
223#ifdef OGG_MUSIC
224 if (initialized & MIX_INIT_OGG) {
225 Mix_QuitOgg();
226 }
227#endif
228#ifdef MID_MUSIC
229 if (soundfont_paths) {
230 SDL_free(soundfont_paths);
231 }
232#endif
233 initialized = 0;
234}
235
236static int _Mix_remove_all_effects(int channel, effect_info **e);
237
238/*
239 * rcg06122001 Cleanup effect callbacks.
240 * MAKE SURE SDL_LockAudio() is called before this (or you're in the
241 * audio callback).
242 */
243static void _Mix_channel_done_playing(int channel)
244{
245 if (channel_done_callback) {
246 channel_done_callback(channel);
247 }
248
249 /*
250 * Call internal function directly, to avoid locking audio from
251 * inside audio callback.
252 */
253 _Mix_remove_all_effects(channel, &mix_channel[channel].effects);
254}
255
256
257static void *Mix_DoEffects(int chan, void *snd, int len)
258{
259 int posteffect = (chan == MIX_CHANNEL_POST);
260 effect_info *e = ((posteffect) ? posteffects : mix_channel[chan].effects);
261 void *buf = snd;
262
263 if (e != NULL) { /* are there any registered effects? */
264 /* if this is the postmix, we can just overwrite the original. */
265 if (!posteffect) {
266 buf = SDL_malloc(len);
267 if (buf == NULL) {
268 return(snd);
269 }
270 memcpy(buf, snd, len);
271 }
272
273 for (; e != NULL; e = e->next) {
274 if (e->callback != NULL) {
275 e->callback(chan, buf, len, e->udata);
276 }
277 }
278 }
279
280 /* be sure to SDL_free() the return value if != snd ... */
281 return(buf);
282}
283
284
285/* Mixing function */
286#ifdef __WATCOMC__
287static void SDLCALL mix_channels(void *udata, Uint8 *stream, int len)
288#else
289static void mix_channels(void *udata, Uint8 *stream, int len)
290#endif
291{
292 Uint8 *mix_input;
293 int i, mixable, volume = SDL_MIX_MAXVOLUME;
294 Uint32 sdl_ticks;
295
296#if SDL_VERSION_ATLEAST(1, 3, 0)
297 /* Need to initialize the stream in SDL 1.3+ */
298 memset(stream, mixer.silence, len);
299#endif
300
301 /* Mix the music (must be done before the channels are added) */
302 if ( music_active || (mix_music != music_mixer) ) {
303 mix_music(music_data, stream, len);
304 }
305
306 /* Mix any playing channels... */
307 sdl_ticks = SDL_GetTicks();
308 for ( i=0; i<num_channels; ++i ) {
309 if( ! mix_channel[i].paused ) {
310 if ( mix_channel[i].expire > 0 && mix_channel[i].expire < sdl_ticks ) {
311 /* Expiration delay for that channel is reached */
312 mix_channel[i].playing = 0;
313 mix_channel[i].looping = 0;
314 mix_channel[i].fading = MIX_NO_FADING;
315 mix_channel[i].expire = 0;
316 _Mix_channel_done_playing(i);
317 } else if ( mix_channel[i].fading != MIX_NO_FADING ) {
318 Uint32 ticks = sdl_ticks - mix_channel[i].ticks_fade;
319 if( ticks > mix_channel[i].fade_length ) {
320 Mix_Volume(i, mix_channel[i].fade_volume_reset); /* Restore the volume */
321 if( mix_channel[i].fading == MIX_FADING_OUT ) {
322 mix_channel[i].playing = 0;
323 mix_channel[i].looping = 0;
324 mix_channel[i].expire = 0;
325 _Mix_channel_done_playing(i);
326 }
327 mix_channel[i].fading = MIX_NO_FADING;
328 } else {
329 if( mix_channel[i].fading == MIX_FADING_OUT ) {
330 Mix_Volume(i, (mix_channel[i].fade_volume * (mix_channel[i].fade_length-ticks))
331 / mix_channel[i].fade_length );
332 } else {
333 Mix_Volume(i, (mix_channel[i].fade_volume * ticks) / mix_channel[i].fade_length );
334 }
335 }
336 }
337 if ( mix_channel[i].playing > 0 ) {
338 int index = 0;
339 int remaining = len;
340 while (mix_channel[i].playing > 0 && index < len) {
341 remaining = len - index;
342 volume = (mix_channel[i].volume*mix_channel[i].chunk->volume) / MIX_MAX_VOLUME;
343 mixable = mix_channel[i].playing;
344 if ( mixable > remaining ) {
345 mixable = remaining;
346 }
347
348 mix_input = Mix_DoEffects(i, mix_channel[i].samples, mixable);
349 SDL_MixAudio(stream+index,mix_input,mixable,volume);
350 if (mix_input != mix_channel[i].samples)
351 SDL_free(mix_input);
352
353 mix_channel[i].samples += mixable;
354 mix_channel[i].playing -= mixable;
355 index += mixable;
356
357 /* rcg06072001 Alert app if channel is done playing. */
358 if (!mix_channel[i].playing && !mix_channel[i].looping) {
359 _Mix_channel_done_playing(i);
360 }
361 }
362
363 /* If looping the sample and we are at its end, make sure
364 we will still return a full buffer */
365 while ( mix_channel[i].looping && index < len ) {
366 int alen = mix_channel[i].chunk->alen;
367 remaining = len - index;
368 if (remaining > alen) {
369 remaining = alen;
370 }
371
372 mix_input = Mix_DoEffects(i, mix_channel[i].chunk->abuf, remaining);
373 SDL_MixAudio(stream+index, mix_input, remaining, volume);
374 if (mix_input != mix_channel[i].chunk->abuf)
375 SDL_free(mix_input);
376
377 --mix_channel[i].looping;
378 mix_channel[i].samples = mix_channel[i].chunk->abuf + remaining;
379 mix_channel[i].playing = mix_channel[i].chunk->alen - remaining;
380 index += remaining;
381 }
382 if ( ! mix_channel[i].playing && mix_channel[i].looping ) {
383 --mix_channel[i].looping;
384 mix_channel[i].samples = mix_channel[i].chunk->abuf;
385 mix_channel[i].playing = mix_channel[i].chunk->alen;
386 }
387 }
388 }
389 }
390
391 /* rcg06122001 run posteffects... */
392 Mix_DoEffects(MIX_CHANNEL_POST, stream, len);
393
394 if ( mix_postmix ) {
395 mix_postmix(mix_postmix_data, stream, len);
396 }
397}
398
399#if 0
400static void PrintFormat(char *title, SDL_AudioSpec *fmt)
401{
402 printf("%s: %d bit %s audio (%s) at %u Hz\n", title, (fmt->format&0xFF),
403 (fmt->format&0x8000) ? "signed" : "unsigned",
404 (fmt->channels > 2) ? "surround" :
405 (fmt->channels > 1) ? "stereo" : "mono", fmt->freq);
406}
407#endif
408
409
410/* Open the mixer with a certain desired audio format */
411int Mix_OpenAudio(int frequency, Uint16 format, int nchannels, int chunksize)
412{
413 int i;
414 SDL_AudioSpec desired;
415
416 /* If the mixer is already opened, increment open count */
417 if ( audio_opened ) {
418 if ( format == mixer.format && nchannels == mixer.channels ) {
419 ++audio_opened;
420 return(0);
421 }
422 while ( audio_opened ) {
423 Mix_CloseAudio();
424 }
425 }
426
427 /* Set the desired format and frequency */
428 desired.freq = frequency;
429 desired.format = format;
430 desired.channels = nchannels;
431 desired.samples = chunksize;
432 desired.callback = mix_channels;
433 desired.userdata = NULL;
434
435 /* Accept nearly any audio format */
436 if ( SDL_OpenAudio(&desired, &mixer) < 0 ) {
437 return(-1);
438 }
439#if 0
440 PrintFormat("Audio device", &mixer);
441#endif
442
443 /* Initialize the music players */
444 if ( open_music(&mixer) < 0 ) {
445 SDL_CloseAudio();
446 return(-1);
447 }
448
449 num_channels = MIX_CHANNELS;
450 mix_channel = (struct _Mix_Channel *) SDL_malloc(num_channels * sizeof(struct _Mix_Channel));
451
452 /* Clear out the audio channels */
453 for ( i=0; i<num_channels; ++i ) {
454 mix_channel[i].chunk = NULL;
455 mix_channel[i].playing = 0;
456 mix_channel[i].looping = 0;
457 mix_channel[i].volume = SDL_MIX_MAXVOLUME;
458 mix_channel[i].fade_volume = SDL_MIX_MAXVOLUME;
459 mix_channel[i].fade_volume_reset = SDL_MIX_MAXVOLUME;
460 mix_channel[i].fading = MIX_NO_FADING;
461 mix_channel[i].tag = -1;
462 mix_channel[i].expire = 0;
463 mix_channel[i].effects = NULL;
464 mix_channel[i].paused = 0;
465 }
466 Mix_VolumeMusic(SDL_MIX_MAXVOLUME);
467
468 _Mix_InitEffects();
469
470 /* This list is (currently) decided at build time. */
471 add_chunk_decoder("WAVE");
472 add_chunk_decoder("AIFF");
473 add_chunk_decoder("VOC");
474#ifdef OGG_MUSIC
475 add_chunk_decoder("OGG");
476#endif
477#ifdef FLAC_MUSIC
478 add_chunk_decoder("FLAC");
479#endif
480
481 audio_opened = 1;
482 SDL_PauseAudio(0);
483 return(0);
484}
485
486/* Dynamically change the number of channels managed by the mixer.
487 If decreasing the number of channels, the upper channels are
488 stopped.
489 */
490int Mix_AllocateChannels(int numchans)
491{
492 if ( numchans<0 || numchans==num_channels )
493 return(num_channels);
494
495 if ( numchans < num_channels ) {
496 /* Stop the affected channels */
497 int i;
498 for(i=numchans; i < num_channels; i++) {
499 Mix_UnregisterAllEffects(i);
500 Mix_HaltChannel(i);
501 }
502 }
503 SDL_LockAudio();
504 mix_channel = (struct _Mix_Channel *) SDL_realloc(mix_channel, numchans * sizeof(struct _Mix_Channel));
505 if ( numchans > num_channels ) {
506 /* Initialize the new channels */
507 int i;
508 for(i=num_channels; i < numchans; i++) {
509 mix_channel[i].chunk = NULL;
510 mix_channel[i].playing = 0;
511 mix_channel[i].looping = 0;
512 mix_channel[i].volume = SDL_MIX_MAXVOLUME;
513 mix_channel[i].fade_volume = SDL_MIX_MAXVOLUME;
514 mix_channel[i].fade_volume_reset = SDL_MIX_MAXVOLUME;
515 mix_channel[i].fading = MIX_NO_FADING;
516 mix_channel[i].tag = -1;
517 mix_channel[i].expire = 0;
518 mix_channel[i].effects = NULL;
519 mix_channel[i].paused = 0;
520 }
521 }
522 num_channels = numchans;
523 SDL_UnlockAudio();
524 return(num_channels);
525}
526
527/* Return the actual mixer parameters */
528int Mix_QuerySpec(int *frequency, Uint16 *format, int *channels)
529{
530 if ( audio_opened ) {
531 if ( frequency ) {
532 *frequency = mixer.freq;
533 }
534 if ( format ) {
535 *format = mixer.format;
536 }
537 if ( channels ) {
538 *channels = mixer.channels;
539 }
540 }
541 return(audio_opened);
542}
543
544
545/*
546 * !!! FIXME: Ideally, we want a Mix_LoadSample_RW(), which will handle the
547 * generic setup, then call the correct file format loader.
548 */
549
550/* Load a wave file */
551Mix_Chunk *Mix_LoadWAV_RW(SDL_RWops *src, int freesrc)
552{
553 Uint32 magic;
554 Mix_Chunk *chunk;
555 SDL_AudioSpec wavespec, *loaded;
556 SDL_AudioCVT wavecvt;
557 int samplesize;
558
559 /* rcg06012001 Make sure src is valid */
560 if ( ! src ) {
561 SDL_SetError("Mix_LoadWAV_RW with NULL src");
562 return(NULL);
563 }
564
565 /* Make sure audio has been opened */
566 if ( ! audio_opened ) {
567 SDL_SetError("Audio device hasn't been opened");
568 if ( freesrc && src ) {
569 SDL_RWclose(src);
570 }
571 return(NULL);
572 }
573
574 /* Allocate the chunk memory */
575 chunk = (Mix_Chunk *)SDL_malloc(sizeof(Mix_Chunk));
576 if ( chunk == NULL ) {
577 SDL_SetError("Out of memory");
578 if ( freesrc ) {
579 SDL_RWclose(src);
580 }
581 return(NULL);
582 }
583
584 /* Find out what kind of audio file this is */
585 magic = SDL_ReadLE32(src);
586 /* Seek backwards for compatibility with older loaders */
587 SDL_RWseek(src, -(int)sizeof(Uint32), RW_SEEK_CUR);
588
589 switch (magic) {
590 case WAVE:
591 case RIFF:
592 loaded = SDL_LoadWAV_RW(src, freesrc, &wavespec,
593 (Uint8 **)&chunk->abuf, &chunk->alen);
594 break;
595 case FORM:
596 loaded = Mix_LoadAIFF_RW(src, freesrc, &wavespec,
597 (Uint8 **)&chunk->abuf, &chunk->alen);
598 break;
599#ifdef OGG_MUSIC
600 case OGGS:
601 loaded = Mix_LoadOGG_RW(src, freesrc, &wavespec,
602 (Uint8 **)&chunk->abuf, &chunk->alen);
603 break;
604#endif
605#ifdef FLAC_MUSIC
606 case FLAC:
607 loaded = Mix_LoadFLAC_RW(src, freesrc, &wavespec,
608 (Uint8 **)&chunk->abuf, &chunk->alen);
609 break;
610#endif
611 case CREA:
612 loaded = Mix_LoadVOC_RW(src, freesrc, &wavespec,
613 (Uint8 **)&chunk->abuf, &chunk->alen);
614 break;
615 default:
616 SDL_SetError("Unrecognized sound file type");
617 return(0);
618 }
619 if ( !loaded ) {
620 SDL_free(chunk);
621 if ( freesrc ) {
622 SDL_RWclose(src);
623 }
624 return(NULL);
625 }
626
627#if 0
628 PrintFormat("Audio device", &mixer);
629 PrintFormat("-- Wave file", &wavespec);
630#endif
631
632 /* Build the audio converter and create conversion buffers */
633 if ( wavespec.format != mixer.format ||
634 wavespec.channels != mixer.channels ||
635 wavespec.freq != mixer.freq ) {
636 if ( SDL_BuildAudioCVT(&wavecvt,
637 wavespec.format, wavespec.channels, wavespec.freq,
638 mixer.format, mixer.channels, mixer.freq) < 0 ) {
639 SDL_free(chunk->abuf);
640 SDL_free(chunk);
641 return(NULL);
642 }
643 samplesize = ((wavespec.format & 0xFF)/8)*wavespec.channels;
644 wavecvt.len = chunk->alen & ~(samplesize-1);
645 wavecvt.buf = (Uint8 *)SDL_calloc(1, wavecvt.len*wavecvt.len_mult);
646 if ( wavecvt.buf == NULL ) {
647 SDL_SetError("Out of memory");
648 SDL_free(chunk->abuf);
649 SDL_free(chunk);
650 return(NULL);
651 }
652 memcpy(wavecvt.buf, chunk->abuf, chunk->alen);
653 SDL_free(chunk->abuf);
654
655 /* Run the audio converter */
656 if ( SDL_ConvertAudio(&wavecvt) < 0 ) {
657 SDL_free(wavecvt.buf);
658 SDL_free(chunk);
659 return(NULL);
660 }
661
662 chunk->abuf = wavecvt.buf;
663 chunk->alen = wavecvt.len_cvt;
664 }
665
666 chunk->allocated = 1;
667 chunk->volume = MIX_MAX_VOLUME;
668
669 return(chunk);
670}
671
672/* Load a wave file of the mixer format from a memory buffer */
673Mix_Chunk *Mix_QuickLoad_WAV(Uint8 *mem)
674{
675 Mix_Chunk *chunk;
676 Uint8 magic[4];
677
678 /* Make sure audio has been opened */
679 if ( ! audio_opened ) {
680 SDL_SetError("Audio device hasn't been opened");
681 return(NULL);
682 }
683
684 /* Allocate the chunk memory */
685 chunk = (Mix_Chunk *)SDL_calloc(1,sizeof(Mix_Chunk));
686 if ( chunk == NULL ) {
687 SDL_SetError("Out of memory");
688 return(NULL);
689 }
690
691 /* Essentially just skip to the audio data (no error checking - fast) */
692 chunk->allocated = 0;
693 mem += 12; /* WAV header */
694 do {
695 memcpy(magic, mem, 4);
696 mem += 4;
697 chunk->alen = ((mem[3]<<24)|(mem[2]<<16)|(mem[1]<<8)|(mem[0]));
698 mem += 4;
699 chunk->abuf = mem;
700 mem += chunk->alen;
701 } while ( memcmp(magic, "data", 4) != 0 );
702 chunk->volume = MIX_MAX_VOLUME;
703
704 return(chunk);
705}
706
707/* Load raw audio data of the mixer format from a memory buffer */
708Mix_Chunk *Mix_QuickLoad_RAW(Uint8 *mem, Uint32 len)
709{
710 Mix_Chunk *chunk;
711
712 /* Make sure audio has been opened */
713 if ( ! audio_opened ) {
714 SDL_SetError("Audio device hasn't been opened");
715 return(NULL);
716 }
717
718 /* Allocate the chunk memory */
719 chunk = (Mix_Chunk *)SDL_malloc(sizeof(Mix_Chunk));
720 if ( chunk == NULL ) {
721 SDL_SetError("Out of memory");
722 return(NULL);
723 }
724
725 /* Essentially just point at the audio data (no error checking - fast) */
726 chunk->allocated = 0;
727 chunk->alen = len;
728 chunk->abuf = mem;
729 chunk->volume = MIX_MAX_VOLUME;
730
731 return(chunk);
732}
733
734/* Free an audio chunk previously loaded */
735void Mix_FreeChunk(Mix_Chunk *chunk)
736{
737 int i;
738
739 /* Caution -- if the chunk is playing, the mixer will crash */
740 if ( chunk ) {
741 /* Guarantee that this chunk isn't playing */
742 SDL_LockAudio();
743 if ( mix_channel ) {
744 for ( i=0; i<num_channels; ++i ) {
745 if ( chunk == mix_channel[i].chunk ) {
746 mix_channel[i].playing = 0;
747 mix_channel[i].looping = 0;
748 }
749 }
750 }
751 SDL_UnlockAudio();
752 /* Actually free the chunk */
753 if ( chunk->allocated ) {
754 SDL_free(chunk->abuf);
755 }
756 SDL_free(chunk);
757 }
758}
759
760/* Set a function that is called after all mixing is performed.
761 This can be used to provide real-time visual display of the audio stream
762 or add a custom mixer filter for the stream data.
763*/
764void Mix_SetPostMix(void (*mix_func)
765 (void *udata, Uint8 *stream, int len), void *arg)
766{
767 SDL_LockAudio();
768 mix_postmix_data = arg;
769 mix_postmix = mix_func;
770 SDL_UnlockAudio();
771}
772
773/* Add your own music player or mixer function.
774 If 'mix_func' is NULL, the default music player is re-enabled.
775 */
776void Mix_HookMusic(void (*mix_func)(void *udata, Uint8 *stream, int len),
777 void *arg)
778{
779 SDL_LockAudio();
780 if ( mix_func != NULL ) {
781 music_data = arg;
782 mix_music = mix_func;
783 } else {
784 music_data = NULL;
785 mix_music = music_mixer;
786 }
787 SDL_UnlockAudio();
788}
789
790void *Mix_GetMusicHookData(void)
791{
792 return(music_data);
793}
794
795void Mix_ChannelFinished(void (*channel_finished)(int channel))
796{
797 SDL_LockAudio();
798 channel_done_callback = channel_finished;
799 SDL_UnlockAudio();
800}
801
802
803/* Reserve the first channels (0 -> n-1) for the application, i.e. don't allocate
804 them dynamically to the next sample if requested with a -1 value below.
805 Returns the number of reserved channels.
806 */
807int Mix_ReserveChannels(int num)
808{
809 if (num > num_channels)
810 num = num_channels;
811 reserved_channels = num;
812 return num;
813}
814
815static int checkchunkintegral(Mix_Chunk *chunk)
816{
817 int frame_width = 1;
818
819 if ((mixer.format & 0xFF) == 16) frame_width = 2;
820 frame_width *= mixer.channels;
821 while (chunk->alen % frame_width) chunk->alen--;
822 return chunk->alen;
823}
824
825/* Play an audio chunk on a specific channel.
826 If the specified channel is -1, play on the first free channel.
827 'ticks' is the number of milliseconds at most to play the sample, or -1
828 if there is no limit.
829 Returns which channel was used to play the sound.
830*/
831int Mix_PlayChannelTimed(int which, Mix_Chunk *chunk, int loops, int ticks)
832{
833 int i;
834
835 /* Don't play null pointers :-) */
836 if ( chunk == NULL ) {
837 Mix_SetError("Tried to play a NULL chunk");
838 return(-1);
839 }
840 if ( !checkchunkintegral(chunk)) {
841 Mix_SetError("Tried to play a chunk with a bad frame");
842 return(-1);
843 }
844
845 /* Lock the mixer while modifying the playing channels */
846 SDL_LockAudio();
847 {
848 /* If which is -1, play on the first free channel */
849 if ( which == -1 ) {
850 for ( i=reserved_channels; i<num_channels; ++i ) {
851 if ( mix_channel[i].playing <= 0 )
852 break;
853 }
854 if ( i == num_channels ) {
855 Mix_SetError("No free channels available");
856 which = -1;
857 } else {
858 which = i;
859 }
860 }
861
862 /* Queue up the audio data for this channel */
863 if ( which >= 0 && which < num_channels ) {
864 Uint32 sdl_ticks = SDL_GetTicks();
865 if (Mix_Playing(which))
866 _Mix_channel_done_playing(which);
867 mix_channel[which].samples = chunk->abuf;
868 mix_channel[which].playing = chunk->alen;
869 mix_channel[which].looping = loops;
870 mix_channel[which].chunk = chunk;
871 mix_channel[which].paused = 0;
872 mix_channel[which].fading = MIX_NO_FADING;
873 mix_channel[which].start_time = sdl_ticks;
874 mix_channel[which].expire = (ticks>0) ? (sdl_ticks + ticks) : 0;
875 }
876 }
877 SDL_UnlockAudio();
878
879 /* Return the channel on which the sound is being played */
880 return(which);
881}
882
883/* Change the expiration delay for a channel */
884int Mix_ExpireChannel(int which, int ticks)
885{
886 int status = 0;
887
888 if ( which == -1 ) {
889 int i;
890 for ( i=0; i < num_channels; ++ i ) {
891 status += Mix_ExpireChannel(i, ticks);
892 }
893 } else if ( which < num_channels ) {
894 SDL_LockAudio();
895 mix_channel[which].expire = (ticks>0) ? (SDL_GetTicks() + ticks) : 0;
896 SDL_UnlockAudio();
897 ++ status;
898 }
899 return(status);
900}
901
902/* Fade in a sound on a channel, over ms milliseconds */
903int Mix_FadeInChannelTimed(int which, Mix_Chunk *chunk, int loops, int ms, int ticks)
904{
905 int i;
906
907 /* Don't play null pointers :-) */
908 if ( chunk == NULL ) {
909 return(-1);
910 }
911 if ( !checkchunkintegral(chunk)) {
912 Mix_SetError("Tried to play a chunk with a bad frame");
913 return(-1);
914 }
915
916 /* Lock the mixer while modifying the playing channels */
917 SDL_LockAudio();
918 {
919 /* If which is -1, play on the first free channel */
920 if ( which == -1 ) {
921 for ( i=reserved_channels; i<num_channels; ++i ) {
922 if ( mix_channel[i].playing <= 0 )
923 break;
924 }
925 if ( i == num_channels ) {
926 which = -1;
927 } else {
928 which = i;
929 }
930 }
931
932 /* Queue up the audio data for this channel */
933 if ( which >= 0 && which < num_channels ) {
934 Uint32 sdl_ticks = SDL_GetTicks();
935 if (Mix_Playing(which))
936 _Mix_channel_done_playing(which);
937 mix_channel[which].samples = chunk->abuf;
938 mix_channel[which].playing = chunk->alen;
939 mix_channel[which].looping = loops;
940 mix_channel[which].chunk = chunk;
941 mix_channel[which].paused = 0;
942 mix_channel[which].fading = MIX_FADING_IN;
943 mix_channel[which].fade_volume = mix_channel[which].volume;
944 mix_channel[which].fade_volume_reset = mix_channel[which].volume;
945 mix_channel[which].volume = 0;
946 mix_channel[which].fade_length = (Uint32)ms;
947 mix_channel[which].start_time = mix_channel[which].ticks_fade = sdl_ticks;
948 mix_channel[which].expire = (ticks > 0) ? (sdl_ticks+ticks) : 0;
949 }
950 }
951 SDL_UnlockAudio();
952
953 /* Return the channel on which the sound is being played */
954 return(which);
955}
956
957/* Set volume of a particular channel */
958int Mix_Volume(int which, int volume)
959{
960 int i;
961 int prev_volume = 0;
962
963 if ( which == -1 ) {
964 for ( i=0; i<num_channels; ++i ) {
965 prev_volume += Mix_Volume(i, volume);
966 }
967 prev_volume /= num_channels;
968 } else if ( which < num_channels ) {
969 prev_volume = mix_channel[which].volume;
970 if ( volume >= 0 ) {
971 if ( volume > SDL_MIX_MAXVOLUME ) {
972 volume = SDL_MIX_MAXVOLUME;
973 }
974 mix_channel[which].volume = volume;
975 }
976 }
977 return(prev_volume);
978}
979/* Set volume of a particular chunk */
980int Mix_VolumeChunk(Mix_Chunk *chunk, int volume)
981{
982 int prev_volume;
983
984 prev_volume = chunk->volume;
985 if ( volume >= 0 ) {
986 if ( volume > MIX_MAX_VOLUME ) {
987 volume = MIX_MAX_VOLUME;
988 }
989 chunk->volume = volume;
990 }
991 return(prev_volume);
992}
993
994/* Halt playing of a particular channel */
995int Mix_HaltChannel(int which)
996{
997 int i;
998
999 if ( which == -1 ) {
1000 for ( i=0; i<num_channels; ++i ) {
1001 Mix_HaltChannel(i);
1002 }
1003 } else if ( which < num_channels ) {
1004 SDL_LockAudio();
1005 if (mix_channel[which].playing) {
1006 _Mix_channel_done_playing(which);
1007 mix_channel[which].playing = 0;
1008 mix_channel[which].looping = 0;
1009 }
1010 mix_channel[which].expire = 0;
1011 if(mix_channel[which].fading != MIX_NO_FADING) /* Restore volume */
1012 mix_channel[which].volume = mix_channel[which].fade_volume_reset;
1013 mix_channel[which].fading = MIX_NO_FADING;
1014 SDL_UnlockAudio();
1015 }
1016 return(0);
1017}
1018
1019/* Halt playing of a particular group of channels */
1020int Mix_HaltGroup(int tag)
1021{
1022 int i;
1023
1024 for ( i=0; i<num_channels; ++i ) {
1025 if( mix_channel[i].tag == tag ) {
1026 Mix_HaltChannel(i);
1027 }
1028 }
1029 return(0);
1030}
1031
1032/* Fade out a channel and then stop it automatically */
1033int Mix_FadeOutChannel(int which, int ms)
1034{
1035 int status;
1036
1037 status = 0;
1038 if ( audio_opened ) {
1039 if ( which == -1 ) {
1040 int i;
1041
1042 for ( i=0; i<num_channels; ++i ) {
1043 status += Mix_FadeOutChannel(i, ms);
1044 }
1045 } else if ( which < num_channels ) {
1046 SDL_LockAudio();
1047 if ( mix_channel[which].playing &&
1048 (mix_channel[which].volume > 0) &&
1049 (mix_channel[which].fading != MIX_FADING_OUT) ) {
1050 mix_channel[which].fade_volume = mix_channel[which].volume;
1051 mix_channel[which].fading = MIX_FADING_OUT;
1052 mix_channel[which].fade_length = ms;
1053 mix_channel[which].ticks_fade = SDL_GetTicks();
1054
1055 /* only change fade_volume_reset if we're not fading. */
1056 if (mix_channel[which].fading == MIX_NO_FADING) {
1057 mix_channel[which].fade_volume_reset = mix_channel[which].volume;
1058 }
1059 ++status;
1060 }
1061 SDL_UnlockAudio();
1062 }
1063 }
1064 return(status);
1065}
1066
1067/* Halt playing of a particular group of channels */
1068int Mix_FadeOutGroup(int tag, int ms)
1069{
1070 int i;
1071 int status = 0;
1072 for ( i=0; i<num_channels; ++i ) {
1073 if( mix_channel[i].tag == tag ) {
1074 status += Mix_FadeOutChannel(i,ms);
1075 }
1076 }
1077 return(status);
1078}
1079
1080Mix_Fading Mix_FadingChannel(int which)
1081{
1082 if ( which < 0 || which >= num_channels ) {
1083 return MIX_NO_FADING;
1084 }
1085 return mix_channel[which].fading;
1086}
1087
1088/* Check the status of a specific channel.
1089 If the specified mix_channel is -1, check all mix channels.
1090*/
1091int Mix_Playing(int which)
1092{
1093 int status;
1094
1095 status = 0;
1096 if ( which == -1 ) {
1097 int i;
1098
1099 for ( i=0; i<num_channels; ++i ) {
1100 if ((mix_channel[i].playing > 0) ||
1101 (mix_channel[i].looping > 0))
1102 {
1103 ++status;
1104 }
1105 }
1106 } else if ( which < num_channels ) {
1107 if ( (mix_channel[which].playing > 0) ||
1108 (mix_channel[which].looping > 0) )
1109 {
1110 ++status;
1111 }
1112 }
1113 return(status);
1114}
1115
1116/* rcg06072001 Get the chunk associated with a channel. */
1117Mix_Chunk *Mix_GetChunk(int channel)
1118{
1119 Mix_Chunk *retval = NULL;
1120
1121 if ((channel >= 0) && (channel < num_channels)) {
1122 retval = mix_channel[channel].chunk;
1123 }
1124
1125 return(retval);
1126}
1127
1128/* Close the mixer, halting all playing audio */
1129void Mix_CloseAudio(void)
1130{
1131 int i;
1132
1133 if ( audio_opened ) {
1134 if ( audio_opened == 1 ) {
1135 for (i = 0; i < num_channels; i++) {
1136 Mix_UnregisterAllEffects(i);
1137 }
1138 Mix_UnregisterAllEffects(MIX_CHANNEL_POST);
1139 close_music();
1140 Mix_HaltChannel(-1);
1141 _Mix_DeinitEffects();
1142 SDL_CloseAudio();
1143 SDL_free(mix_channel);
1144 mix_channel = NULL;
1145
1146 /* rcg06042009 report available decoders at runtime. */
1147 SDL_free(chunk_decoders);
1148 chunk_decoders = NULL;
1149 num_decoders = 0;
1150 }
1151 --audio_opened;
1152 }
1153}
1154
1155/* Pause a particular channel (or all) */
1156void Mix_Pause(int which)
1157{
1158 Uint32 sdl_ticks = SDL_GetTicks();
1159 if ( which == -1 ) {
1160 int i;
1161
1162 for ( i=0; i<num_channels; ++i ) {
1163 if ( mix_channel[i].playing > 0 ) {
1164 mix_channel[i].paused = sdl_ticks;
1165 }
1166 }
1167 } else if ( which < num_channels ) {
1168 if ( mix_channel[which].playing > 0 ) {
1169 mix_channel[which].paused = sdl_ticks;
1170 }
1171 }
1172}
1173
1174/* Resume a paused channel */
1175void Mix_Resume(int which)
1176{
1177 Uint32 sdl_ticks = SDL_GetTicks();
1178
1179 SDL_LockAudio();
1180 if ( which == -1 ) {
1181 int i;
1182
1183 for ( i=0; i<num_channels; ++i ) {
1184 if ( mix_channel[i].playing > 0 ) {
1185 if(mix_channel[i].expire > 0)
1186 mix_channel[i].expire += sdl_ticks - mix_channel[i].paused;
1187 mix_channel[i].paused = 0;
1188 }
1189 }
1190 } else if ( which < num_channels ) {
1191 if ( mix_channel[which].playing > 0 ) {
1192 if(mix_channel[which].expire > 0)
1193 mix_channel[which].expire += sdl_ticks - mix_channel[which].paused;
1194 mix_channel[which].paused = 0;
1195 }
1196 }
1197 SDL_UnlockAudio();
1198}
1199
1200int Mix_Paused(int which)
1201{
1202 if ( which < 0 ) {
1203 int status = 0;
1204 int i;
1205 for( i=0; i < num_channels; ++i ) {
1206 if ( mix_channel[i].paused ) {
1207 ++ status;
1208 }
1209 }
1210 return(status);
1211 } else if ( which < num_channels ) {
1212 return(mix_channel[which].paused != 0);
1213 } else {
1214 return(0);
1215 }
1216}
1217
1218/* Change the group of a channel */
1219int Mix_GroupChannel(int which, int tag)
1220{
1221 if ( which < 0 || which > num_channels )
1222 return(0);
1223
1224 SDL_LockAudio();
1225 mix_channel[which].tag = tag;
1226 SDL_UnlockAudio();
1227 return(1);
1228}
1229
1230/* Assign several consecutive channels to a group */
1231int Mix_GroupChannels(int from, int to, int tag)
1232{
1233 int status = 0;
1234 for( ; from <= to; ++ from ) {
1235 status += Mix_GroupChannel(from, tag);
1236 }
1237 return(status);
1238}
1239
1240/* Finds the first available channel in a group of channels */
1241int Mix_GroupAvailable(int tag)
1242{
1243 int i;
1244 for( i=0; i < num_channels; i ++ ) {
1245 if ( ((tag == -1) || (tag == mix_channel[i].tag)) &&
1246 (mix_channel[i].playing <= 0) )
1247 return i;
1248 }
1249 return(-1);
1250}
1251
1252int Mix_GroupCount(int tag)
1253{
1254 int count = 0;
1255 int i;
1256 for( i=0; i < num_channels; i ++ ) {
1257 if ( mix_channel[i].tag==tag || tag==-1 )
1258 ++ count;
1259 }
1260 return(count);
1261}
1262
1263/* Finds the "oldest" sample playing in a group of channels */
1264int Mix_GroupOldest(int tag)
1265{
1266 int chan = -1;
1267 Uint32 mintime = SDL_GetTicks();
1268 int i;
1269 for( i=0; i < num_channels; i ++ ) {
1270 if ( (mix_channel[i].tag==tag || tag==-1) && mix_channel[i].playing > 0
1271 && mix_channel[i].start_time <= mintime ) {
1272 mintime = mix_channel[i].start_time;
1273 chan = i;
1274 }
1275 }
1276 return(chan);
1277}
1278
1279/* Finds the "most recent" (i.e. last) sample playing in a group of channels */
1280int Mix_GroupNewer(int tag)
1281{
1282 int chan = -1;
1283 Uint32 maxtime = 0;
1284 int i;
1285 for( i=0; i < num_channels; i ++ ) {
1286 if ( (mix_channel[i].tag==tag || tag==-1) && mix_channel[i].playing > 0
1287 && mix_channel[i].start_time >= maxtime ) {
1288 maxtime = mix_channel[i].start_time;
1289 chan = i;
1290 }
1291 }
1292 return(chan);
1293}
1294
1295
1296
1297/*
1298 * rcg06122001 The special effects exportable API.
1299 * Please see effect_*.c for internally-implemented effects, such
1300 * as Mix_SetPanning().
1301 */
1302
1303/* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
1304static int _Mix_register_effect(effect_info **e, Mix_EffectFunc_t f,
1305 Mix_EffectDone_t d, void *arg)
1306{
1307 effect_info *new_e;
1308
1309 if (!e) {
1310 Mix_SetError("Internal error");
1311 return(0);
1312 }
1313
1314 if (f == NULL) {
1315 Mix_SetError("NULL effect callback");
1316 return(0);
1317 }
1318
1319 new_e = SDL_malloc(sizeof (effect_info));
1320 if (new_e == NULL) {
1321 Mix_SetError("Out of memory");
1322 return(0);
1323 }
1324
1325 new_e->callback = f;
1326 new_e->done_callback = d;
1327 new_e->udata = arg;
1328 new_e->next = NULL;
1329
1330 /* add new effect to end of linked list... */
1331 if (*e == NULL) {
1332 *e = new_e;
1333 } else {
1334 effect_info *cur = *e;
1335 while (1) {
1336 if (cur->next == NULL) {
1337 cur->next = new_e;
1338 break;
1339 }
1340 cur = cur->next;
1341 }
1342 }
1343
1344 return(1);
1345}
1346
1347
1348/* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
1349static int _Mix_remove_effect(int channel, effect_info **e, Mix_EffectFunc_t f)
1350{
1351 effect_info *cur;
1352 effect_info *prev = NULL;
1353 effect_info *next = NULL;
1354
1355 if (!e) {
1356 Mix_SetError("Internal error");
1357 return(0);
1358 }
1359
1360 for (cur = *e; cur != NULL; cur = cur->next) {
1361 if (cur->callback == f) {
1362 next = cur->next;
1363 if (cur->done_callback != NULL) {
1364 cur->done_callback(channel, cur->udata);
1365 }
1366 SDL_free(cur);
1367
1368 if (prev == NULL) { /* removing first item of list? */
1369 *e = next;
1370 } else {
1371 prev->next = next;
1372 }
1373 return(1);
1374 }
1375 prev = cur;
1376 }
1377
1378 Mix_SetError("No such effect registered");
1379 return(0);
1380}
1381
1382
1383/* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
1384static int _Mix_remove_all_effects(int channel, effect_info **e)
1385{
1386 effect_info *cur;
1387 effect_info *next;
1388
1389 if (!e) {
1390 Mix_SetError("Internal error");
1391 return(0);
1392 }
1393
1394 for (cur = *e; cur != NULL; cur = next) {
1395 next = cur->next;
1396 if (cur->done_callback != NULL) {
1397 cur->done_callback(channel, cur->udata);
1398 }
1399 SDL_free(cur);
1400 }
1401 *e = NULL;
1402
1403 return(1);
1404}
1405
1406
1407/* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
1408int _Mix_RegisterEffect_locked(int channel, Mix_EffectFunc_t f,
1409 Mix_EffectDone_t d, void *arg)
1410{
1411 effect_info **e = NULL;
1412
1413 if (channel == MIX_CHANNEL_POST) {
1414 e = &posteffects;
1415 } else {
1416 if ((channel < 0) || (channel >= num_channels)) {
1417 Mix_SetError("Invalid channel number");
1418 return(0);
1419 }
1420 e = &mix_channel[channel].effects;
1421 }
1422
1423 return _Mix_register_effect(e, f, d, arg);
1424}
1425
1426int Mix_RegisterEffect(int channel, Mix_EffectFunc_t f,
1427 Mix_EffectDone_t d, void *arg)
1428{
1429 int retval;
1430 SDL_LockAudio();
1431 retval = _Mix_RegisterEffect_locked(channel, f, d, arg);
1432 SDL_UnlockAudio();
1433 return retval;
1434}
1435
1436
1437/* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
1438int _Mix_UnregisterEffect_locked(int channel, Mix_EffectFunc_t f)
1439{
1440 effect_info **e = NULL;
1441
1442 if (channel == MIX_CHANNEL_POST) {
1443 e = &posteffects;
1444 } else {
1445 if ((channel < 0) || (channel >= num_channels)) {
1446 Mix_SetError("Invalid channel number");
1447 return(0);
1448 }
1449 e = &mix_channel[channel].effects;
1450 }
1451
1452 return _Mix_remove_effect(channel, e, f);
1453}
1454
1455int Mix_UnregisterEffect(int channel, Mix_EffectFunc_t f)
1456{
1457 int retval;
1458 SDL_LockAudio();
1459 retval = _Mix_UnregisterEffect_locked(channel, f);
1460 SDL_UnlockAudio();
1461 return(retval);
1462}
1463
1464/* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
1465int _Mix_UnregisterAllEffects_locked(int channel)
1466{
1467 effect_info **e = NULL;
1468
1469 if (channel == MIX_CHANNEL_POST) {
1470 e = &posteffects;
1471 } else {
1472 if ((channel < 0) || (channel >= num_channels)) {
1473 Mix_SetError("Invalid channel number");
1474 return(0);
1475 }
1476 e = &mix_channel[channel].effects;
1477 }
1478
1479 return _Mix_remove_all_effects(channel, e);
1480}
1481
1482int Mix_UnregisterAllEffects(int channel)
1483{
1484 int retval;
1485 SDL_LockAudio();
1486 retval = _Mix_UnregisterAllEffects_locked(channel);
1487 SDL_UnlockAudio();
1488 return(retval);
1489}
1490
1491/* end of mixer.c ... */
1492
Note: See TracBrowser for help on using the repository browser.