Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 9564 → Rev 9565

/contrib/sdk/sources/SDL_mixer-1.2.12/Makefile
0,0 → 1,33
CC = kos32-gcc
AR = kos32-ar
LD = kos32-ld
STRIP = kos32-strip
 
LIBNAME=libSDL_mixer
 
SDK_DIR:= $(abspath ../../../sdk)
 
OBJS = effect_stereoreverse.o \
effect_position.o \
effects_internal.o \
music.o \
mixer.o \
load_ogg.o \
music_ogg.o \
dynamic_ogg.o \
wavestream.o \
load_aiff.o \
load_voc.o
CFLAGS = -c -O2 -mpreferred-stack-boundary=2 -fno-ident -fomit-frame-pointer -fno-stack-check -fno-stack-protector -mno-stack-arg-probe -fno-exceptions -fno-asynchronous-unwind-tables -ffast-math -mno-ms-bitfields -march=pentium-mmx -UWIN32 -U_Win32 -U_WIN32 -U__MINGW32__ -I../newlib/libc/include/ -I../SDL-1.2.2_newlib/include -I../libogg-1.3.5/include -I.. -I../libvorbis-1.3.7/include -DOGG_MUSIC
 
all: $(LIBNAME).a
 
$(LIBNAME).a: $(OBJS)
$(AR) -crs $(SDK_DIR)/lib/$(LIBNAME).a $(OBJS)
 
%.o : %.c Makefile
$(CC) $(CFLAGS) -o $@ $<
 
clean:
rm -f */*.o \ rm *.o \ rm */*/*.o
/contrib/sdk/sources/SDL_mixer-1.2.12/SDL_mixer.h
0,0 → 1,635
/*
SDL_mixer: An audio mixer library based on the SDL library
Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
 
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
 
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
 
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
 
/* $Id$ */
 
#ifndef _SDL_MIXER_H
#define _SDL_MIXER_H
 
#include "SDL_types.h"
#include "SDL_rwops.h"
#include "SDL_audio.h"
#include "SDL_endian.h"
#include "SDL_version.h"
#include "SDL_stdinc.h"
#include "begin_code.h"
 
/* Set up for C function definitions, even when using C++ */
#ifdef __cplusplus
extern "C" {
#endif
 
/* Printable format: "%d.%d.%d", MAJOR, MINOR, PATCHLEVEL
*/
#define SDL_MIXER_MAJOR_VERSION 1
#define SDL_MIXER_MINOR_VERSION 2
#define SDL_MIXER_PATCHLEVEL 12
 
/* This macro can be used to fill a version structure with the compile-time
* version of the SDL_mixer library.
*/
#define SDL_MIXER_VERSION(X) \
{ \
(X)->major = SDL_MIXER_MAJOR_VERSION; \
(X)->minor = SDL_MIXER_MINOR_VERSION; \
(X)->patch = SDL_MIXER_PATCHLEVEL; \
}
 
/* Backwards compatibility */
#define MIX_MAJOR_VERSION SDL_MIXER_MAJOR_VERSION
#define MIX_MINOR_VERSION SDL_MIXER_MINOR_VERSION
#define MIX_PATCHLEVEL SDL_MIXER_PATCHLEVEL
#define MIX_VERSION(X) SDL_MIXER_VERSION(X)
 
/* This function gets the version of the dynamically linked SDL_mixer library.
it should NOT be used to fill a version structure, instead you should
use the SDL_MIXER_VERSION() macro.
*/
extern DECLSPEC const SDL_version * SDLCALL Mix_Linked_Version(void);
 
typedef enum
{
MIX_INIT_FLAC = 0x00000001,
MIX_INIT_MOD = 0x00000002,
MIX_INIT_MP3 = 0x00000004,
MIX_INIT_OGG = 0x00000008,
MIX_INIT_FLUIDSYNTH = 0x00000010
} MIX_InitFlags;
 
/* Loads dynamic libraries and prepares them for use. Flags should be
one or more flags from MIX_InitFlags OR'd together.
It returns the flags successfully initialized, or 0 on failure.
*/
extern DECLSPEC int SDLCALL Mix_Init(int flags);
 
/* Unloads libraries loaded with Mix_Init */
extern DECLSPEC void SDLCALL Mix_Quit(void);
 
 
/* The default mixer has 8 simultaneous mixing channels */
#ifndef MIX_CHANNELS
#define MIX_CHANNELS 8
#endif
 
/* Good default values for a PC soundcard */
#define MIX_DEFAULT_FREQUENCY 22050
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
#define MIX_DEFAULT_FORMAT AUDIO_S16LSB
#else
#define MIX_DEFAULT_FORMAT AUDIO_S16MSB
#endif
#define MIX_DEFAULT_CHANNELS 2
#define MIX_MAX_VOLUME 128 /* Volume of a chunk */
 
/* The internal format for an audio chunk */
typedef struct Mix_Chunk {
int allocated;
Uint8 *abuf;
Uint32 alen;
Uint8 volume; /* Per-sample volume, 0-128 */
} Mix_Chunk;
 
/* The different fading types supported */
typedef enum {
MIX_NO_FADING,
MIX_FADING_OUT,
MIX_FADING_IN
} Mix_Fading;
 
typedef enum {
MUS_NONE,
MUS_CMD,
MUS_WAV,
MUS_MOD,
MUS_MID,
MUS_OGG,
MUS_MP3,
MUS_MP3_MAD,
MUS_FLAC,
MUS_MODPLUG
} Mix_MusicType;
 
/* The internal format for a music chunk interpreted via mikmod */
typedef struct _Mix_Music Mix_Music;
 
/* Open the mixer with a certain audio format */
extern DECLSPEC int SDLCALL Mix_OpenAudio(int frequency, Uint16 format, int channels,
int chunksize);
 
/* Dynamically change the number of channels managed by the mixer.
If decreasing the number of channels, the upper channels are
stopped.
This function returns the new number of allocated channels.
*/
extern DECLSPEC int SDLCALL Mix_AllocateChannels(int numchans);
 
/* Find out what the actual audio device parameters are.
This function returns 1 if the audio has been opened, 0 otherwise.
*/
extern DECLSPEC int SDLCALL Mix_QuerySpec(int *frequency,Uint16 *format,int *channels);
 
/* Load a wave file or a music (.mod .s3m .it .xm) file */
extern DECLSPEC Mix_Chunk * SDLCALL Mix_LoadWAV_RW(SDL_RWops *src, int freesrc);
#define Mix_LoadWAV(file) Mix_LoadWAV_RW(SDL_RWFromFile(file, "rb"), 1)
extern DECLSPEC Mix_Music * SDLCALL Mix_LoadMUS(const char *file);
 
/* Load a music file from an SDL_RWop object (Ogg and MikMod specific currently)
Matt Campbell (matt@campbellhome.dhs.org) April 2000 */
extern DECLSPEC Mix_Music * SDLCALL Mix_LoadMUS_RW(SDL_RWops *rw);
 
/* Load a music file from an SDL_RWop object assuming a specific format */
extern DECLSPEC Mix_Music * SDLCALL Mix_LoadMUSType_RW(SDL_RWops *rw, Mix_MusicType type, int freesrc);
 
/* Load a wave file of the mixer format from a memory buffer */
extern DECLSPEC Mix_Chunk * SDLCALL Mix_QuickLoad_WAV(Uint8 *mem);
 
/* Load raw audio data of the mixer format from a memory buffer */
extern DECLSPEC Mix_Chunk * SDLCALL Mix_QuickLoad_RAW(Uint8 *mem, Uint32 len);
 
/* Free an audio chunk previously loaded */
extern DECLSPEC void SDLCALL Mix_FreeChunk(Mix_Chunk *chunk);
extern DECLSPEC void SDLCALL Mix_FreeMusic(Mix_Music *music);
 
/* Get a list of chunk/music decoders that this build of SDL_mixer provides.
This list can change between builds AND runs of the program, if external
libraries that add functionality become available.
You must successfully call Mix_OpenAudio() before calling these functions.
This API is only available in SDL_mixer 1.2.9 and later.
 
// usage...
int i;
const int total = Mix_GetNumChunkDecoders();
for (i = 0; i < total; i++)
printf("Supported chunk decoder: [%s]\n", Mix_GetChunkDecoder(i));
 
Appearing in this list doesn't promise your specific audio file will
decode...but it's handy to know if you have, say, a functioning Timidity
install.
 
These return values are static, read-only data; do not modify or free it.
The pointers remain valid until you call Mix_CloseAudio().
*/
extern DECLSPEC int SDLCALL Mix_GetNumChunkDecoders(void);
extern DECLSPEC const char * SDLCALL Mix_GetChunkDecoder(int index);
extern DECLSPEC int SDLCALL Mix_GetNumMusicDecoders(void);
extern DECLSPEC const char * SDLCALL Mix_GetMusicDecoder(int index);
 
/* Find out the music format of a mixer music, or the currently playing
music, if 'music' is NULL.
*/
extern DECLSPEC Mix_MusicType SDLCALL Mix_GetMusicType(const Mix_Music *music);
 
/* 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.
*/
extern DECLSPEC void SDLCALL Mix_SetPostMix(void (*mix_func)
(void *udata, Uint8 *stream, int len), void *arg);
 
/* Add your own music player or additional mixer function.
If 'mix_func' is NULL, the default music player is re-enabled.
*/
extern DECLSPEC void SDLCALL Mix_HookMusic(void (*mix_func)
(void *udata, Uint8 *stream, int len), void *arg);
 
/* Add your own callback when the music has finished playing.
This callback is only called if the music finishes naturally.
*/
extern DECLSPEC void SDLCALL Mix_HookMusicFinished(void (*music_finished)(void));
 
/* Get a pointer to the user data for the current music hook */
extern DECLSPEC void * SDLCALL Mix_GetMusicHookData(void);
 
/*
* Add your own callback when a channel has finished playing. NULL
* to disable callback. The callback may be called from the mixer's audio
* callback or it could be called as a result of Mix_HaltChannel(), etc.
* do not call SDL_LockAudio() from this callback; you will either be
* inside the audio callback, or SDL_mixer will explicitly lock the audio
* before calling your callback.
*/
extern DECLSPEC void SDLCALL Mix_ChannelFinished(void (*channel_finished)(int channel));
 
 
/* Special Effects API by ryan c. gordon. (icculus@icculus.org) */
 
#define MIX_CHANNEL_POST -2
 
/* This is the format of a special effect callback:
*
* myeffect(int chan, void *stream, int len, void *udata);
*
* (chan) is the channel number that your effect is affecting. (stream) is
* the buffer of data to work upon. (len) is the size of (stream), and
* (udata) is a user-defined bit of data, which you pass as the last arg of
* Mix_RegisterEffect(), and is passed back unmolested to your callback.
* Your effect changes the contents of (stream) based on whatever parameters
* are significant, or just leaves it be, if you prefer. You can do whatever
* you like to the buffer, though, and it will continue in its changed state
* down the mixing pipeline, through any other effect functions, then finally
* to be mixed with the rest of the channels and music for the final output
* stream.
*
* DO NOT EVER call SDL_LockAudio() from your callback function!
*/
typedef void (*Mix_EffectFunc_t)(int chan, void *stream, int len, void *udata);
 
/*
* This is a callback that signifies that a channel has finished all its
* loops and has completed playback. This gets called if the buffer
* plays out normally, or if you call Mix_HaltChannel(), implicitly stop
* a channel via Mix_AllocateChannels(), or unregister a callback while
* it's still playing.
*
* DO NOT EVER call SDL_LockAudio() from your callback function!
*/
typedef void (*Mix_EffectDone_t)(int chan, void *udata);
 
 
/* Register a special effect function. At mixing time, the channel data is
* copied into a buffer and passed through each registered effect function.
* After it passes through all the functions, it is mixed into the final
* output stream. The copy to buffer is performed once, then each effect
* function performs on the output of the previous effect. Understand that
* this extra copy to a buffer is not performed if there are no effects
* registered for a given chunk, which saves CPU cycles, and any given
* effect will be extra cycles, too, so it is crucial that your code run
* fast. Also note that the data that your function is given is in the
* format of the sound device, and not the format you gave to Mix_OpenAudio(),
* although they may in reality be the same. This is an unfortunate but
* necessary speed concern. Use Mix_QuerySpec() to determine if you can
* handle the data before you register your effect, and take appropriate
* actions.
* You may also specify a callback (Mix_EffectDone_t) that is called when
* the channel finishes playing. This gives you a more fine-grained control
* than Mix_ChannelFinished(), in case you need to free effect-specific
* resources, etc. If you don't need this, you can specify NULL.
* You may set the callbacks before or after calling Mix_PlayChannel().
* Things like Mix_SetPanning() are just internal special effect functions,
* so if you are using that, you've already incurred the overhead of a copy
* to a separate buffer, and that these effects will be in the queue with
* any functions you've registered. The list of registered effects for a
* channel is reset when a chunk finishes playing, so you need to explicitly
* set them with each call to Mix_PlayChannel*().
* You may also register a special effect function that is to be run after
* final mixing occurs. The rules for these callbacks are identical to those
* in Mix_RegisterEffect, but they are run after all the channels and the
* music have been mixed into a single stream, whereas channel-specific
* effects run on a given channel before any other mixing occurs. These
* global effect callbacks are call "posteffects". Posteffects only have
* their Mix_EffectDone_t function called when they are unregistered (since
* the main output stream is never "done" in the same sense as a channel).
* You must unregister them manually when you've had enough. Your callback
* will be told that the channel being mixed is (MIX_CHANNEL_POST) if the
* processing is considered a posteffect.
*
* After all these effects have finished processing, the callback registered
* through Mix_SetPostMix() runs, and then the stream goes to the audio
* device.
*
* DO NOT EVER call SDL_LockAudio() from your callback function!
*
* returns zero if error (no such channel), nonzero if added.
* Error messages can be retrieved from Mix_GetError().
*/
extern DECLSPEC int SDLCALL Mix_RegisterEffect(int chan, Mix_EffectFunc_t f,
Mix_EffectDone_t d, void *arg);
 
 
/* You may not need to call this explicitly, unless you need to stop an
* effect from processing in the middle of a chunk's playback.
* Posteffects are never implicitly unregistered as they are for channels,
* but they may be explicitly unregistered through this function by
* specifying MIX_CHANNEL_POST for a channel.
* returns zero if error (no such channel or effect), nonzero if removed.
* Error messages can be retrieved from Mix_GetError().
*/
extern DECLSPEC int SDLCALL Mix_UnregisterEffect(int channel, Mix_EffectFunc_t f);
 
 
/* You may not need to call this explicitly, unless you need to stop all
* effects from processing in the middle of a chunk's playback. Note that
* this will also shut off some internal effect processing, since
* Mix_SetPanning() and others may use this API under the hood. This is
* called internally when a channel completes playback.
* Posteffects are never implicitly unregistered as they are for channels,
* but they may be explicitly unregistered through this function by
* specifying MIX_CHANNEL_POST for a channel.
* returns zero if error (no such channel), nonzero if all effects removed.
* Error messages can be retrieved from Mix_GetError().
*/
extern DECLSPEC int SDLCALL Mix_UnregisterAllEffects(int channel);
 
 
#define MIX_EFFECTSMAXSPEED "MIX_EFFECTSMAXSPEED"
 
/*
* These are the internally-defined mixing effects. They use the same API that
* effects defined in the application use, but are provided here as a
* convenience. Some effects can reduce their quality or use more memory in
* the name of speed; to enable this, make sure the environment variable
* MIX_EFFECTSMAXSPEED (see above) is defined before you call
* Mix_OpenAudio().
*/
 
 
/* Set the panning of a channel. The left and right channels are specified
* as integers between 0 and 255, quietest to loudest, respectively.
*
* Technically, this is just individual volume control for a sample with
* two (stereo) channels, so it can be used for more than just panning.
* If you want real panning, call it like this:
*
* Mix_SetPanning(channel, left, 255 - left);
*
* ...which isn't so hard.
*
* Setting (channel) to MIX_CHANNEL_POST registers this as a posteffect, and
* the panning will be done to the final mixed stream before passing it on
* to the audio device.
*
* This uses the Mix_RegisterEffect() API internally, and returns without
* registering the effect function if the audio device is not configured
* for stereo output. Setting both (left) and (right) to 255 causes this
* effect to be unregistered, since that is the data's normal state.
*
* returns zero if error (no such channel or Mix_RegisterEffect() fails),
* nonzero if panning effect enabled. Note that an audio device in mono
* mode is a no-op, but this call will return successful in that case.
* Error messages can be retrieved from Mix_GetError().
*/
extern DECLSPEC int SDLCALL Mix_SetPanning(int channel, Uint8 left, Uint8 right);
 
 
/* Set the position of a channel. (angle) is an integer from 0 to 360, that
* specifies the location of the sound in relation to the listener. (angle)
* will be reduced as neccesary (540 becomes 180 degrees, -100 becomes 260).
* Angle 0 is due north, and rotates clockwise as the value increases.
* For efficiency, the precision of this effect may be limited (angles 1
* through 7 might all produce the same effect, 8 through 15 are equal, etc).
* (distance) is an integer between 0 and 255 that specifies the space
* between the sound and the listener. The larger the number, the further
* away the sound is. Using 255 does not guarantee that the channel will be
* culled from the mixing process or be completely silent. For efficiency,
* the precision of this effect may be limited (distance 0 through 5 might
* all produce the same effect, 6 through 10 are equal, etc). Setting (angle)
* and (distance) to 0 unregisters this effect, since the data would be
* unchanged.
*
* If you need more precise positional audio, consider using OpenAL for
* spatialized effects instead of SDL_mixer. This is only meant to be a
* basic effect for simple "3D" games.
*
* If the audio device is configured for mono output, then you won't get
* any effectiveness from the angle; however, distance attenuation on the
* channel will still occur. While this effect will function with stereo
* voices, it makes more sense to use voices with only one channel of sound,
* so when they are mixed through this effect, the positioning will sound
* correct. You can convert them to mono through SDL before giving them to
* the mixer in the first place if you like.
*
* Setting (channel) to MIX_CHANNEL_POST registers this as a posteffect, and
* the positioning will be done to the final mixed stream before passing it
* on to the audio device.
*
* This is a convenience wrapper over Mix_SetDistance() and Mix_SetPanning().
*
* returns zero if error (no such channel or Mix_RegisterEffect() fails),
* nonzero if position effect is enabled.
* Error messages can be retrieved from Mix_GetError().
*/
extern DECLSPEC int SDLCALL Mix_SetPosition(int channel, Sint16 angle, Uint8 distance);
 
 
/* Set the "distance" of a channel. (distance) is an integer from 0 to 255
* that specifies the location of the sound in relation to the listener.
* Distance 0 is overlapping the listener, and 255 is as far away as possible
* A distance of 255 does not guarantee silence; in such a case, you might
* want to try changing the chunk's volume, or just cull the sample from the
* mixing process with Mix_HaltChannel().
* For efficiency, the precision of this effect may be limited (distances 1
* through 7 might all produce the same effect, 8 through 15 are equal, etc).
* (distance) is an integer between 0 and 255 that specifies the space
* between the sound and the listener. The larger the number, the further
* away the sound is.
* Setting (distance) to 0 unregisters this effect, since the data would be
* unchanged.
* If you need more precise positional audio, consider using OpenAL for
* spatialized effects instead of SDL_mixer. This is only meant to be a
* basic effect for simple "3D" games.
*
* Setting (channel) to MIX_CHANNEL_POST registers this as a posteffect, and
* the distance attenuation will be done to the final mixed stream before
* passing it on to the audio device.
*
* This uses the Mix_RegisterEffect() API internally.
*
* returns zero if error (no such channel or Mix_RegisterEffect() fails),
* nonzero if position effect is enabled.
* Error messages can be retrieved from Mix_GetError().
*/
extern DECLSPEC int SDLCALL Mix_SetDistance(int channel, Uint8 distance);
 
 
/*
* !!! FIXME : Haven't implemented, since the effect goes past the
* end of the sound buffer. Will have to think about this.
* --ryan.
*/
#if 0
/* Causes an echo effect to be mixed into a sound. (echo) is the amount
* of echo to mix. 0 is no echo, 255 is infinite (and probably not
* what you want).
*
* Setting (channel) to MIX_CHANNEL_POST registers this as a posteffect, and
* the reverbing will be done to the final mixed stream before passing it on
* to the audio device.
*
* This uses the Mix_RegisterEffect() API internally. If you specify an echo
* of zero, the effect is unregistered, as the data is already in that state.
*
* returns zero if error (no such channel or Mix_RegisterEffect() fails),
* nonzero if reversing effect is enabled.
* Error messages can be retrieved from Mix_GetError().
*/
extern no_parse_DECLSPEC int SDLCALL Mix_SetReverb(int channel, Uint8 echo);
#endif
 
/* Causes a channel to reverse its stereo. This is handy if the user has his
* speakers hooked up backwards, or you would like to have a minor bit of
* psychedelia in your sound code. :) Calling this function with (flip)
* set to non-zero reverses the chunks's usual channels. If (flip) is zero,
* the effect is unregistered.
*
* This uses the Mix_RegisterEffect() API internally, and thus is probably
* more CPU intensive than having the user just plug in his speakers
* correctly. Mix_SetReverseStereo() returns without registering the effect
* function if the audio device is not configured for stereo output.
*
* If you specify MIX_CHANNEL_POST for (channel), then this the effect is used
* on the final mixed stream before sending it on to the audio device (a
* posteffect).
*
* returns zero if error (no such channel or Mix_RegisterEffect() fails),
* nonzero if reversing effect is enabled. Note that an audio device in mono
* mode is a no-op, but this call will return successful in that case.
* Error messages can be retrieved from Mix_GetError().
*/
extern DECLSPEC int SDLCALL Mix_SetReverseStereo(int channel, int flip);
 
/* end of effects API. --ryan. */
 
 
/* 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.
*/
extern DECLSPEC int SDLCALL Mix_ReserveChannels(int num);
 
/* Channel grouping functions */
 
/* Attach a tag to a channel. A tag can be assigned to several mixer
channels, to form groups of channels.
If 'tag' is -1, the tag is removed (actually -1 is the tag used to
represent the group of all the channels).
Returns true if everything was OK.
*/
extern DECLSPEC int SDLCALL Mix_GroupChannel(int which, int tag);
/* Assign several consecutive channels to a group */
extern DECLSPEC int SDLCALL Mix_GroupChannels(int from, int to, int tag);
/* Finds the first available channel in a group of channels,
returning -1 if none are available.
*/
extern DECLSPEC int SDLCALL Mix_GroupAvailable(int tag);
/* Returns the number of channels in a group. This is also a subtle
way to get the total number of channels when 'tag' is -1
*/
extern DECLSPEC int SDLCALL Mix_GroupCount(int tag);
/* Finds the "oldest" sample playing in a group of channels */
extern DECLSPEC int SDLCALL Mix_GroupOldest(int tag);
/* Finds the "most recent" (i.e. last) sample playing in a group of channels */
extern DECLSPEC int SDLCALL Mix_GroupNewer(int tag);
 
/* Play an audio chunk on a specific channel.
If the specified channel is -1, play on the first free channel.
If 'loops' is greater than zero, loop the sound that many times.
If 'loops' is -1, loop inifinitely (~65000 times).
Returns which channel was used to play the sound.
*/
#define Mix_PlayChannel(channel,chunk,loops) Mix_PlayChannelTimed(channel,chunk,loops,-1)
/* The same as above, but the sound is played at most 'ticks' milliseconds */
extern DECLSPEC int SDLCALL Mix_PlayChannelTimed(int channel, Mix_Chunk *chunk, int loops, int ticks);
extern DECLSPEC int SDLCALL Mix_PlayMusic(Mix_Music *music, int loops);
 
/* Fade in music or a channel over "ms" milliseconds, same semantics as the "Play" functions */
extern DECLSPEC int SDLCALL Mix_FadeInMusic(Mix_Music *music, int loops, int ms);
extern DECLSPEC int SDLCALL Mix_FadeInMusicPos(Mix_Music *music, int loops, int ms, double position);
#define Mix_FadeInChannel(channel,chunk,loops,ms) Mix_FadeInChannelTimed(channel,chunk,loops,ms,-1)
extern DECLSPEC int SDLCALL Mix_FadeInChannelTimed(int channel, Mix_Chunk *chunk, int loops, int ms, int ticks);
 
/* Set the volume in the range of 0-128 of a specific channel or chunk.
If the specified channel is -1, set volume for all channels.
Returns the original volume.
If the specified volume is -1, just return the current volume.
*/
extern DECLSPEC int SDLCALL Mix_Volume(int channel, int volume);
extern DECLSPEC int SDLCALL Mix_VolumeChunk(Mix_Chunk *chunk, int volume);
extern DECLSPEC int SDLCALL Mix_VolumeMusic(int volume);
 
/* Halt playing of a particular channel */
extern DECLSPEC int SDLCALL Mix_HaltChannel(int channel);
extern DECLSPEC int SDLCALL Mix_HaltGroup(int tag);
extern DECLSPEC int SDLCALL Mix_HaltMusic(void);
 
/* Change the expiration delay for a particular channel.
The sample will stop playing after the 'ticks' milliseconds have elapsed,
or remove the expiration if 'ticks' is -1
*/
extern DECLSPEC int SDLCALL Mix_ExpireChannel(int channel, int ticks);
 
/* Halt a channel, fading it out progressively till it's silent
The ms parameter indicates the number of milliseconds the fading
will take.
*/
extern DECLSPEC int SDLCALL Mix_FadeOutChannel(int which, int ms);
extern DECLSPEC int SDLCALL Mix_FadeOutGroup(int tag, int ms);
extern DECLSPEC int SDLCALL Mix_FadeOutMusic(int ms);
 
/* Query the fading status of a channel */
extern DECLSPEC Mix_Fading SDLCALL Mix_FadingMusic(void);
extern DECLSPEC Mix_Fading SDLCALL Mix_FadingChannel(int which);
 
/* Pause/Resume a particular channel */
extern DECLSPEC void SDLCALL Mix_Pause(int channel);
extern DECLSPEC void SDLCALL Mix_Resume(int channel);
extern DECLSPEC int SDLCALL Mix_Paused(int channel);
 
/* Pause/Resume the music stream */
extern DECLSPEC void SDLCALL Mix_PauseMusic(void);
extern DECLSPEC void SDLCALL Mix_ResumeMusic(void);
extern DECLSPEC void SDLCALL Mix_RewindMusic(void);
extern DECLSPEC int SDLCALL Mix_PausedMusic(void);
 
/* Set the current position in the music stream.
This returns 0 if successful, or -1 if it failed or isn't implemented.
This function is only implemented for MOD music formats (set pattern
order number) and for OGG, FLAC, MP3_MAD, and MODPLUG music (set
position in seconds), at the moment.
*/
extern DECLSPEC int SDLCALL Mix_SetMusicPosition(double position);
 
/* Check the status of a specific channel.
If the specified channel is -1, check all channels.
*/
extern DECLSPEC int SDLCALL Mix_Playing(int channel);
extern DECLSPEC int SDLCALL Mix_PlayingMusic(void);
 
/* Stop music and set external music playback command */
extern DECLSPEC int SDLCALL Mix_SetMusicCMD(const char *command);
 
/* Synchro value is set by MikMod from modules while playing */
extern DECLSPEC int SDLCALL Mix_SetSynchroValue(int value);
extern DECLSPEC int SDLCALL Mix_GetSynchroValue(void);
 
/* Set/Get/Iterate SoundFonts paths to use by supported MIDI backends */
extern DECLSPEC int SDLCALL Mix_SetSoundFonts(const char *paths);
extern DECLSPEC const char* SDLCALL Mix_GetSoundFonts(void);
extern DECLSPEC int SDLCALL Mix_EachSoundFont(int (*function)(const char*, void*), void *data);
 
/* Get the Mix_Chunk currently associated with a mixer channel
Returns NULL if it's an invalid channel, or there's no chunk associated.
*/
extern DECLSPEC Mix_Chunk * SDLCALL Mix_GetChunk(int channel);
 
/* Close the mixer, halting all playing audio */
extern DECLSPEC void SDLCALL Mix_CloseAudio(void);
 
/* We'll use SDL for reporting errors */
#define Mix_SetError SDL_SetError
#define Mix_GetError SDL_GetError
 
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}
#endif
#include "close_code.h"
 
#endif /* _SDL_MIXER_H */
/contrib/sdk/sources/SDL_mixer-1.2.12/dynamic_ogg.c
0,0 → 1,128
/*
SDL_mixer: An audio mixer library based on the SDL library
Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
 
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
 
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
 
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
 
#ifdef OGG_MUSIC
#include "dynamic_ogg.h"
 
vorbis_loader vorbis = {
0, NULL
};
 
#ifdef OGG_DYNAMIC
int Mix_InitOgg()
{
if ( vorbis.loaded == 0 ) {
vorbis.handle = SDL_LoadObject(OGG_DYNAMIC);
if ( vorbis.handle == NULL ) {
return -1;
}
vorbis.ov_clear =
(int (*)(OggVorbis_File *))
SDL_LoadFunction(vorbis.handle, "ov_clear");
if ( vorbis.ov_clear == NULL ) {
SDL_UnloadObject(vorbis.handle);
return -1;
}
vorbis.ov_info =
(vorbis_info *(*)(OggVorbis_File *,int))
SDL_LoadFunction(vorbis.handle, "ov_info");
if ( vorbis.ov_info == NULL ) {
SDL_UnloadObject(vorbis.handle);
return -1;
}
vorbis.ov_open_callbacks =
(int (*)(void *, OggVorbis_File *, char *, long, ov_callbacks))
SDL_LoadFunction(vorbis.handle, "ov_open_callbacks");
if ( vorbis.ov_open_callbacks == NULL ) {
SDL_UnloadObject(vorbis.handle);
return -1;
}
vorbis.ov_pcm_total =
(ogg_int64_t (*)(OggVorbis_File *,int))
SDL_LoadFunction(vorbis.handle, "ov_pcm_total");
if ( vorbis.ov_pcm_total == NULL ) {
SDL_UnloadObject(vorbis.handle);
return -1;
}
vorbis.ov_read =
#ifdef OGG_USE_TREMOR
(long (*)(OggVorbis_File *,char *,int,int *))
#else
(long (*)(OggVorbis_File *,char *,int,int,int,int,int *))
#endif
SDL_LoadFunction(vorbis.handle, "ov_read");
if ( vorbis.ov_read == NULL ) {
SDL_UnloadObject(vorbis.handle);
return -1;
}
vorbis.ov_time_seek =
#ifdef OGG_USE_TREMOR
(long (*)(OggVorbis_File *,ogg_int64_t))
#else
(int (*)(OggVorbis_File *,double))
#endif
SDL_LoadFunction(vorbis.handle, "ov_time_seek");
if ( vorbis.ov_time_seek == NULL ) {
SDL_UnloadObject(vorbis.handle);
return -1;
}
}
++vorbis.loaded;
 
return 0;
}
void Mix_QuitOgg()
{
if ( vorbis.loaded == 0 ) {
return;
}
if ( vorbis.loaded == 1 ) {
SDL_UnloadObject(vorbis.handle);
}
--vorbis.loaded;
}
#else
int Mix_InitOgg()
{
if ( vorbis.loaded == 0 ) {
vorbis.ov_clear = ov_clear;
vorbis.ov_info = ov_info;
vorbis.ov_open_callbacks = ov_open_callbacks;
vorbis.ov_pcm_total = ov_pcm_total;
vorbis.ov_read = ov_read;
vorbis.ov_time_seek = ov_time_seek;
}
++vorbis.loaded;
 
return 0;
}
void Mix_QuitOgg()
{
if ( vorbis.loaded == 0 ) {
return;
}
if ( vorbis.loaded == 1 ) {
}
--vorbis.loaded;
}
#endif /* OGG_DYNAMIC */
 
#endif /* OGG_MUSIC */
/contrib/sdk/sources/SDL_mixer-1.2.12/dynamic_ogg.h
0,0 → 1,53
/*
SDL_mixer: An audio mixer library based on the SDL library
Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
 
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
 
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
 
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
 
#ifdef OGG_MUSIC
#ifdef OGG_USE_TREMOR
#include <tremor/ivorbisfile.h>
#else
#include <vorbis/vorbisfile.h>
#endif
 
typedef struct {
int loaded;
void *handle;
int (*ov_clear)(OggVorbis_File *vf);
vorbis_info *(*ov_info)(OggVorbis_File *vf,int link);
int (*ov_open_callbacks)(void *datasource, OggVorbis_File *vf, char *initial, long ibytes, ov_callbacks callbacks);
ogg_int64_t (*ov_pcm_total)(OggVorbis_File *vf,int i);
#ifdef OGG_USE_TREMOR
long (*ov_read)(OggVorbis_File *vf,char *buffer,int length, int *bitstream);
#else
long (*ov_read)(OggVorbis_File *vf,char *buffer,int length, int bigendianp,int word,int sgned,int *bitstream);
#endif
#ifdef OGG_USE_TREMOR
int (*ov_time_seek)(OggVorbis_File *vf,ogg_int64_t pos);
#else
int (*ov_time_seek)(OggVorbis_File *vf,double pos);
#endif
} vorbis_loader;
 
extern vorbis_loader vorbis;
 
#endif /* OGG_MUSIC */
 
extern int Mix_InitOgg();
extern void Mix_QuitOgg();
/contrib/sdk/sources/SDL_mixer-1.2.12/effect_position.c
0,0 → 1,1619
/*
SDL_mixer: An audio mixer library based on the SDL library
Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
 
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
 
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
 
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
 
This file by Ryan C. Gordon (icculus@icculus.org)
 
These are some internally supported special effects that use SDL_mixer's
effect callback API. They are meant for speed over quality. :)
*/
 
/* $Id$ */
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#include "SDL.h"
#include "SDL_mixer.h"
#include "SDL_endian.h"
 
#define __MIX_INTERNAL_EFFECT__
#include "effects_internal.h"
 
/* profile code:
#include <sys/time.h>
#include <unistd.h>
struct timeval tv1;
struct timeval tv2;
gettimeofday(&tv1, NULL);
 
... do your thing here ...
 
gettimeofday(&tv2, NULL);
printf("%ld\n", tv2.tv_usec - tv1.tv_usec);
*/
 
 
/*
* Positional effects...panning, distance attenuation, etc.
*/
 
typedef struct _Eff_positionargs
{
volatile float left_f;
volatile float right_f;
volatile Uint8 left_u8;
volatile Uint8 right_u8;
volatile float left_rear_f;
volatile float right_rear_f;
volatile float center_f;
volatile float lfe_f;
volatile Uint8 left_rear_u8;
volatile Uint8 right_rear_u8;
volatile Uint8 center_u8;
volatile Uint8 lfe_u8;
volatile float distance_f;
volatile Uint8 distance_u8;
volatile Sint16 room_angle;
volatile int in_use;
volatile int channels;
} position_args;
 
static position_args **pos_args_array = NULL;
static position_args *pos_args_global = NULL;
static int position_channels = 0;
 
void _Eff_PositionDeinit(void)
{
int i;
for (i = 0; i < position_channels; i++) {
SDL_free(pos_args_array[i]);
}
 
position_channels = 0;
 
SDL_free(pos_args_global);
pos_args_global = NULL;
SDL_free(pos_args_array);
pos_args_array = NULL;
}
 
 
/* This just frees up the callback-specific data. */
static void _Eff_PositionDone(int channel, void *udata)
{
if (channel < 0) {
if (pos_args_global != NULL) {
SDL_free(pos_args_global);
pos_args_global = NULL;
}
}
 
else if (pos_args_array[channel] != NULL) {
SDL_free(pos_args_array[channel]);
pos_args_array[channel] = NULL;
}
}
 
 
static void _Eff_position_u8(int chan, void *stream, int len, void *udata)
{
volatile position_args *args = (volatile position_args *) udata;
Uint8 *ptr = (Uint8 *) stream;
int i;
 
/*
* if there's only a mono channnel (the only way we wouldn't have
* a len divisible by 2 here), then left_f and right_f are always
* 1.0, and are therefore throwaways.
*/
if (len % sizeof (Uint16) != 0) {
*ptr = (Uint8) (((float) *ptr) * args->distance_f);
ptr++;
len--;
}
 
if (args->room_angle == 180)
for (i = 0; i < len; i += sizeof (Uint8) * 2) {
/* must adjust the sample so that 0 is the center */
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->right_f) * args->distance_f) + 128);
ptr++;
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->left_f) * args->distance_f) + 128);
ptr++;
}
else for (i = 0; i < len; i += sizeof (Uint8) * 2) {
/* must adjust the sample so that 0 is the center */
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->left_f) * args->distance_f) + 128);
ptr++;
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->right_f) * args->distance_f) + 128);
ptr++;
}
}
static void _Eff_position_u8_c4(int chan, void *stream, int len, void *udata)
{
volatile position_args *args = (volatile position_args *) udata;
Uint8 *ptr = (Uint8 *) stream;
int i;
 
/*
* if there's only a mono channnel (the only way we wouldn't have
* a len divisible by 2 here), then left_f and right_f are always
* 1.0, and are therefore throwaways.
*/
if (len % sizeof (Uint16) != 0) {
*ptr = (Uint8) (((float) *ptr) * args->distance_f);
ptr++;
len--;
}
 
if (args->room_angle == 0)
for (i = 0; i < len; i += sizeof (Uint8) * 6) {
/* must adjust the sample so that 0 is the center */
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->left_f) * args->distance_f) + 128);
ptr++;
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->right_f) * args->distance_f) + 128);
ptr++;
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->left_rear_f) * args->distance_f) + 128);
ptr++;
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->right_rear_f) * args->distance_f) + 128);
ptr++;
}
else if (args->room_angle == 90)
for (i = 0; i < len; i += sizeof (Uint8) * 6) {
/* must adjust the sample so that 0 is the center */
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->right_f) * args->distance_f) + 128);
ptr++;
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->right_rear_f) * args->distance_f) + 128);
ptr++;
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->left_f) * args->distance_f) + 128);
ptr++;
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->left_rear_f) * args->distance_f) + 128);
ptr++;
}
else if (args->room_angle == 180)
for (i = 0; i < len; i += sizeof (Uint8) * 6) {
/* must adjust the sample so that 0 is the center */
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->right_rear_f) * args->distance_f) + 128);
ptr++;
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->left_rear_f) * args->distance_f) + 128);
ptr++;
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->right_f) * args->distance_f) + 128);
ptr++;
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->left_f) * args->distance_f) + 128);
ptr++;
}
else if (args->room_angle == 270)
for (i = 0; i < len; i += sizeof (Uint8) * 6) {
/* must adjust the sample so that 0 is the center */
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->left_rear_f) * args->distance_f) + 128);
ptr++;
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->left_f) * args->distance_f) + 128);
ptr++;
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->right_rear_f) * args->distance_f) + 128);
ptr++;
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->right_f) * args->distance_f) + 128);
ptr++;
}
}
 
 
static void _Eff_position_u8_c6(int chan, void *stream, int len, void *udata)
{
volatile position_args *args = (volatile position_args *) udata;
Uint8 *ptr = (Uint8 *) stream;
int i;
 
/*
* if there's only a mono channnel (the only way we wouldn't have
* a len divisible by 2 here), then left_f and right_f are always
* 1.0, and are therefore throwaways.
*/
if (len % sizeof (Uint16) != 0) {
*ptr = (Uint8) (((float) *ptr) * args->distance_f);
ptr++;
len--;
}
 
if (args->room_angle == 0)
for (i = 0; i < len; i += sizeof (Uint8) * 6) {
/* must adjust the sample so that 0 is the center */
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->left_f) * args->distance_f) + 128);
ptr++;
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->right_f) * args->distance_f) + 128);
ptr++;
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->left_rear_f) * args->distance_f) + 128);
ptr++;
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->right_rear_f) * args->distance_f) + 128);
ptr++;
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->center_f) * args->distance_f) + 128);
ptr++;
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->lfe_f) * args->distance_f) + 128);
ptr++;
}
else if (args->room_angle == 90)
for (i = 0; i < len; i += sizeof (Uint8) * 6) {
/* must adjust the sample so that 0 is the center */
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->right_f) * args->distance_f) + 128);
ptr++;
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->right_rear_f) * args->distance_f) + 128);
ptr++;
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->left_f) * args->distance_f) + 128);
ptr++;
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->left_rear_f) * args->distance_f) + 128);
ptr++;
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->right_rear_f) * args->distance_f/2) + 128)
+ (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->right_f) * args->distance_f/2) + 128);
ptr++;
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->lfe_f) * args->distance_f) + 128);
ptr++;
}
else if (args->room_angle == 180)
for (i = 0; i < len; i += sizeof (Uint8) * 6) {
/* must adjust the sample so that 0 is the center */
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->right_rear_f) * args->distance_f) + 128);
ptr++;
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->left_rear_f) * args->distance_f) + 128);
ptr++;
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->right_f) * args->distance_f) + 128);
ptr++;
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->left_f) * args->distance_f) + 128);
ptr++;
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->right_rear_f) * args->distance_f/2) + 128)
+ (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->left_rear_f) * args->distance_f/2) + 128);
ptr++;
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->lfe_f) * args->distance_f) + 128);
ptr++;
}
else if (args->room_angle == 270)
for (i = 0; i < len; i += sizeof (Uint8) * 6) {
/* must adjust the sample so that 0 is the center */
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->left_rear_f) * args->distance_f) + 128);
ptr++;
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->left_f) * args->distance_f) + 128);
ptr++;
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->right_rear_f) * args->distance_f) + 128);
ptr++;
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->right_f) * args->distance_f) + 128);
ptr++;
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->left_f) * args->distance_f/2) + 128)
+ (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->left_rear_f) * args->distance_f/2) + 128);
ptr++;
*ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
* args->lfe_f) * args->distance_f) + 128);
ptr++;
}
}
 
 
/*
* This one runs about 10.1 times faster than the non-table version, with
* no loss in quality. It does, however, require 64k of memory for the
* lookup table. Also, this will only update position information once per
* call; the non-table version always checks the arguments for each sample,
* in case the user has called Mix_SetPanning() or whatnot again while this
* callback is running.
*/
static void _Eff_position_table_u8(int chan, void *stream, int len, void *udata)
{
volatile position_args *args = (volatile position_args *) udata;
Uint8 *ptr = (Uint8 *) stream;
Uint32 *p;
int i;
Uint8 *l = ((Uint8 *) _Eff_volume_table) + (256 * args->left_u8);
Uint8 *r = ((Uint8 *) _Eff_volume_table) + (256 * args->right_u8);
Uint8 *d = ((Uint8 *) _Eff_volume_table) + (256 * args->distance_u8);
 
if (args->room_angle == 180) {
Uint8 *temp = l;
l = r;
r = temp;
}
/*
* if there's only a mono channnel, then l[] and r[] are always
* volume 255, and are therefore throwaways. Still, we have to
* be sure not to overrun the audio buffer...
*/
while (len % sizeof (Uint32) != 0) {
*ptr = d[l[*ptr]];
ptr++;
if (args->channels > 1) {
*ptr = d[r[*ptr]];
ptr++;
}
len -= args->channels;
}
 
p = (Uint32 *) ptr;
 
for (i = 0; i < len; i += sizeof (Uint32)) {
#if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
*p = (d[l[(*p & 0xFF000000) >> 24]] << 24) |
(d[r[(*p & 0x00FF0000) >> 16]] << 16) |
(d[l[(*p & 0x0000FF00) >> 8]] << 8) |
(d[r[(*p & 0x000000FF) ]] ) ;
#else
*p = (d[r[(*p & 0xFF000000) >> 24]] << 24) |
(d[l[(*p & 0x00FF0000) >> 16]] << 16) |
(d[r[(*p & 0x0000FF00) >> 8]] << 8) |
(d[l[(*p & 0x000000FF) ]] ) ;
#endif
++p;
}
}
 
 
static void _Eff_position_s8(int chan, void *stream, int len, void *udata)
{
volatile position_args *args = (volatile position_args *) udata;
Sint8 *ptr = (Sint8 *) stream;
int i;
 
/*
* if there's only a mono channnel (the only way we wouldn't have
* a len divisible by 2 here), then left_f and right_f are always
* 1.0, and are therefore throwaways.
*/
if (len % sizeof (Sint16) != 0) {
*ptr = (Sint8) (((float) *ptr) * args->distance_f);
ptr++;
len--;
}
 
if (args->room_angle == 180)
for (i = 0; i < len; i += sizeof (Sint8) * 2) {
*ptr = (Sint8)((((float) *ptr) * args->right_f) * args->distance_f);
ptr++;
*ptr = (Sint8)((((float) *ptr) * args->left_f) * args->distance_f);
ptr++;
}
else
for (i = 0; i < len; i += sizeof (Sint8) * 2) {
*ptr = (Sint8)((((float) *ptr) * args->left_f) * args->distance_f);
ptr++;
*ptr = (Sint8)((((float) *ptr) * args->right_f) * args->distance_f);
ptr++;
}
}
static void _Eff_position_s8_c4(int chan, void *stream, int len, void *udata)
{
volatile position_args *args = (volatile position_args *) udata;
Sint8 *ptr = (Sint8 *) stream;
int i;
 
/*
* if there's only a mono channnel (the only way we wouldn't have
* a len divisible by 2 here), then left_f and right_f are always
* 1.0, and are therefore throwaways.
*/
if (len % sizeof (Sint16) != 0) {
*ptr = (Sint8) (((float) *ptr) * args->distance_f);
ptr++;
len--;
}
 
for (i = 0; i < len; i += sizeof (Sint8) * 4) {
switch (args->room_angle) {
case 0:
*ptr = (Sint8)((((float) *ptr) * args->left_f) * args->distance_f); ptr++;
*ptr = (Sint8)((((float) *ptr) * args->right_f) * args->distance_f); ptr++;
*ptr = (Sint8)((((float) *ptr) * args->left_rear_f) * args->distance_f); ptr++;
*ptr = (Sint8)((((float) *ptr) * args->right_rear_f) * args->distance_f); ptr++;
break;
case 90:
*ptr = (Sint8)((((float) *ptr) * args->right_f) * args->distance_f); ptr++;
*ptr = (Sint8)((((float) *ptr) * args->right_rear_f) * args->distance_f); ptr++;
*ptr = (Sint8)((((float) *ptr) * args->left_f) * args->distance_f); ptr++;
*ptr = (Sint8)((((float) *ptr) * args->left_rear_f) * args->distance_f); ptr++;
break;
case 180:
*ptr = (Sint8)((((float) *ptr) * args->right_rear_f) * args->distance_f); ptr++;
*ptr = (Sint8)((((float) *ptr) * args->left_rear_f) * args->distance_f); ptr++;
*ptr = (Sint8)((((float) *ptr) * args->right_f) * args->distance_f); ptr++;
*ptr = (Sint8)((((float) *ptr) * args->left_f) * args->distance_f); ptr++;
break;
case 270:
*ptr = (Sint8)((((float) *ptr) * args->left_rear_f) * args->distance_f); ptr++;
*ptr = (Sint8)((((float) *ptr) * args->left_f) * args->distance_f); ptr++;
*ptr = (Sint8)((((float) *ptr) * args->right_rear_f) * args->distance_f); ptr++;
*ptr = (Sint8)((((float) *ptr) * args->right_f) * args->distance_f); ptr++;
break;
}
}
}
static void _Eff_position_s8_c6(int chan, void *stream, int len, void *udata)
{
volatile position_args *args = (volatile position_args *) udata;
Sint8 *ptr = (Sint8 *) stream;
int i;
 
/*
* if there's only a mono channnel (the only way we wouldn't have
* a len divisible by 2 here), then left_f and right_f are always
* 1.0, and are therefore throwaways.
*/
if (len % sizeof (Sint16) != 0) {
*ptr = (Sint8) (((float) *ptr) * args->distance_f);
ptr++;
len--;
}
 
for (i = 0; i < len; i += sizeof (Sint8) * 6) {
switch (args->room_angle) {
case 0:
*ptr = (Sint8)((((float) *ptr) * args->left_f) * args->distance_f); ptr++;
*ptr = (Sint8)((((float) *ptr) * args->right_f) * args->distance_f); ptr++;
*ptr = (Sint8)((((float) *ptr) * args->left_rear_f) * args->distance_f); ptr++;
*ptr = (Sint8)((((float) *ptr) * args->right_rear_f) * args->distance_f); ptr++;
*ptr = (Sint8)((((float) *ptr) * args->center_f) * args->distance_f); ptr++;
*ptr = (Sint8)((((float) *ptr) * args->lfe_f) * args->distance_f); ptr++;
break;
case 90:
*ptr = (Sint8)((((float) *ptr) * args->right_f) * args->distance_f); ptr++;
*ptr = (Sint8)((((float) *ptr) * args->right_rear_f) * args->distance_f); ptr++;
*ptr = (Sint8)((((float) *ptr) * args->left_f) * args->distance_f); ptr++;
*ptr = (Sint8)((((float) *ptr) * args->left_rear_f) * args->distance_f); ptr++;
*ptr = (Sint8)((((float) *ptr) * args->right_rear_f) * args->distance_f / 2)
+ (Sint8)((((float) *ptr) * args->right_f) * args->distance_f / 2); ptr++;
*ptr = (Sint8)((((float) *ptr) * args->lfe_f) * args->distance_f); ptr++;
break;
case 180:
*ptr = (Sint8)((((float) *ptr) * args->right_rear_f) * args->distance_f); ptr++;
*ptr = (Sint8)((((float) *ptr) * args->left_rear_f) * args->distance_f); ptr++;
*ptr = (Sint8)((((float) *ptr) * args->right_f) * args->distance_f); ptr++;
*ptr = (Sint8)((((float) *ptr) * args->left_f) * args->distance_f); ptr++;
*ptr = (Sint8)((((float) *ptr) * args->right_rear_f) * args->distance_f / 2)
+ (Sint8)((((float) *ptr) * args->left_rear_f) * args->distance_f / 2); ptr++;
*ptr = (Sint8)((((float) *ptr) * args->lfe_f) * args->distance_f); ptr++;
break;
case 270:
*ptr = (Sint8)((((float) *ptr) * args->left_rear_f) * args->distance_f); ptr++;
*ptr = (Sint8)((((float) *ptr) * args->left_f) * args->distance_f); ptr++;
*ptr = (Sint8)((((float) *ptr) * args->right_rear_f) * args->distance_f); ptr++;
*ptr = (Sint8)((((float) *ptr) * args->right_f) * args->distance_f); ptr++;
*ptr = (Sint8)((((float) *ptr) * args->left_f) * args->distance_f / 2)
+ (Sint8)((((float) *ptr) * args->left_rear_f) * args->distance_f / 2); ptr++;
*ptr = (Sint8)((((float) *ptr) * args->lfe_f) * args->distance_f); ptr++;
break;
}
}
}
 
 
/*
* This one runs about 10.1 times faster than the non-table version, with
* no loss in quality. It does, however, require 64k of memory for the
* lookup table. Also, this will only update position information once per
* call; the non-table version always checks the arguments for each sample,
* in case the user has called Mix_SetPanning() or whatnot again while this
* callback is running.
*/
static void _Eff_position_table_s8(int chan, void *stream, int len, void *udata)
{
volatile position_args *args = (volatile position_args *) udata;
Sint8 *ptr = (Sint8 *) stream;
Uint32 *p;
int i;
Sint8 *l = ((Sint8 *) _Eff_volume_table) + (256 * args->left_u8);
Sint8 *r = ((Sint8 *) _Eff_volume_table) + (256 * args->right_u8);
Sint8 *d = ((Sint8 *) _Eff_volume_table) + (256 * args->distance_u8);
 
if (args->room_angle == 180) {
Sint8 *temp = l;
l = r;
r = temp;
}
 
 
while (len % sizeof (Uint32) != 0) {
*ptr = d[l[*ptr]];
ptr++;
if (args->channels > 1) {
*ptr = d[r[*ptr]];
ptr++;
}
len -= args->channels;
}
 
p = (Uint32 *) ptr;
 
for (i = 0; i < len; i += sizeof (Uint32)) {
#if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
*p = (d[l[((Sint16)(Sint8)((*p & 0xFF000000) >> 24))+128]] << 24) |
(d[r[((Sint16)(Sint8)((*p & 0x00FF0000) >> 16))+128]] << 16) |
(d[l[((Sint16)(Sint8)((*p & 0x0000FF00) >> 8))+128]] << 8) |
(d[r[((Sint16)(Sint8)((*p & 0x000000FF) ))+128]] ) ;
#else
*p = (d[r[((Sint16)(Sint8)((*p & 0xFF000000) >> 24))+128]] << 24) |
(d[l[((Sint16)(Sint8)((*p & 0x00FF0000) >> 16))+128]] << 16) |
(d[r[((Sint16)(Sint8)((*p & 0x0000FF00) >> 8))+128]] << 8) |
(d[l[((Sint16)(Sint8)((*p & 0x000000FF) ))+128]] ) ;
#endif
++p;
}
 
 
}
 
 
/* !!! FIXME : Optimize the code for 16-bit samples? */
 
static void _Eff_position_u16lsb(int chan, void *stream, int len, void *udata)
{
volatile position_args *args = (volatile position_args *) udata;
Uint16 *ptr = (Uint16 *) stream;
int i;
 
for (i = 0; i < len; i += sizeof (Uint16) * 2) {
Sint16 sampl = (Sint16) (SDL_SwapLE16(*(ptr+0)) - 32768);
Sint16 sampr = (Sint16) (SDL_SwapLE16(*(ptr+1)) - 32768);
Uint16 swapl = (Uint16) ((Sint16) (((float) sampl * args->left_f)
* args->distance_f) + 32768);
Uint16 swapr = (Uint16) ((Sint16) (((float) sampr * args->right_f)
* args->distance_f) + 32768);
 
if (args->room_angle == 180) {
*(ptr++) = (Uint16) SDL_SwapLE16(swapr);
*(ptr++) = (Uint16) SDL_SwapLE16(swapl);
}
else {
*(ptr++) = (Uint16) SDL_SwapLE16(swapl);
*(ptr++) = (Uint16) SDL_SwapLE16(swapr);
}
}
}
static void _Eff_position_u16lsb_c4(int chan, void *stream, int len, void *udata)
{
volatile position_args *args = (volatile position_args *) udata;
Uint16 *ptr = (Uint16 *) stream;
int i;
 
for (i = 0; i < len; i += sizeof (Uint16) * 4) {
Sint16 sampl = (Sint16) (SDL_SwapLE16(*(ptr+0)) - 32768);
Sint16 sampr = (Sint16) (SDL_SwapLE16(*(ptr+1)) - 32768);
Sint16 samplr = (Sint16) (SDL_SwapLE16(*(ptr+2)) - 32768);
Sint16 samprr = (Sint16) (SDL_SwapLE16(*(ptr+3)) - 32768);
Uint16 swapl = (Uint16) ((Sint16) (((float) sampl * args->left_f)
* args->distance_f) + 32768);
Uint16 swapr = (Uint16) ((Sint16) (((float) sampr * args->right_f)
* args->distance_f) + 32768);
Uint16 swaplr = (Uint16) ((Sint16) (((float) samplr * args->left_rear_f)
* args->distance_f) + 32768);
Uint16 swaprr = (Uint16) ((Sint16) (((float) samprr * args->right_rear_f)
* args->distance_f) + 32768);
 
switch (args->room_angle) {
case 0:
*(ptr++) = (Uint16) SDL_SwapLE16(swapl);
*(ptr++) = (Uint16) SDL_SwapLE16(swapr);
*(ptr++) = (Uint16) SDL_SwapLE16(swaplr);
*(ptr++) = (Uint16) SDL_SwapLE16(swaprr);
break;
case 90:
*(ptr++) = (Uint16) SDL_SwapLE16(swapr);
*(ptr++) = (Uint16) SDL_SwapLE16(swaprr);
*(ptr++) = (Uint16) SDL_SwapLE16(swapl);
*(ptr++) = (Uint16) SDL_SwapLE16(swaplr);
break;
case 180:
*(ptr++) = (Uint16) SDL_SwapLE16(swaprr);
*(ptr++) = (Uint16) SDL_SwapLE16(swaplr);
*(ptr++) = (Uint16) SDL_SwapLE16(swapr);
*(ptr++) = (Uint16) SDL_SwapLE16(swapl);
break;
case 270:
*(ptr++) = (Uint16) SDL_SwapLE16(swaplr);
*(ptr++) = (Uint16) SDL_SwapLE16(swapl);
*(ptr++) = (Uint16) SDL_SwapLE16(swaprr);
*(ptr++) = (Uint16) SDL_SwapLE16(swapr);
break;
}
}
}
static void _Eff_position_u16lsb_c6(int chan, void *stream, int len, void *udata)
{
volatile position_args *args = (volatile position_args *) udata;
Uint16 *ptr = (Uint16 *) stream;
int i;
 
for (i = 0; i < len; i += sizeof (Uint16) * 6) {
Sint16 sampl = (Sint16) (SDL_SwapLE16(*(ptr+0)) - 32768);
Sint16 sampr = (Sint16) (SDL_SwapLE16(*(ptr+1)) - 32768);
Sint16 samplr = (Sint16) (SDL_SwapLE16(*(ptr+2)) - 32768);
Sint16 samprr = (Sint16) (SDL_SwapLE16(*(ptr+3)) - 32768);
Sint16 sampce = (Sint16) (SDL_SwapLE16(*(ptr+4)) - 32768);
Sint16 sampwf = (Sint16) (SDL_SwapLE16(*(ptr+5)) - 32768);
 
Uint16 swapl = (Uint16) ((Sint16) (((float) sampl * args->left_f)
* args->distance_f) + 32768);
Uint16 swapr = (Uint16) ((Sint16) (((float) sampr * args->right_f)
* args->distance_f) + 32768);
Uint16 swaplr = (Uint16) ((Sint16) (((float) samplr * args->left_rear_f)
* args->distance_f) + 32768);
Uint16 swaprr = (Uint16) ((Sint16) (((float) samprr * args->right_rear_f)
* args->distance_f) + 32768);
Uint16 swapce = (Uint16) ((Sint16) (((float) sampce * args->center_f)
* args->distance_f) + 32768);
Uint16 swapwf = (Uint16) ((Sint16) (((float) sampwf * args->lfe_f)
* args->distance_f) + 32768);
 
switch (args->room_angle) {
case 0:
*(ptr++) = (Uint16) SDL_SwapLE16(swapl);
*(ptr++) = (Uint16) SDL_SwapLE16(swapr);
*(ptr++) = (Uint16) SDL_SwapLE16(swaplr);
*(ptr++) = (Uint16) SDL_SwapLE16(swaprr);
*(ptr++) = (Uint16) SDL_SwapLE16(swapce);
*(ptr++) = (Uint16) SDL_SwapLE16(swapwf);
break;
case 90:
*(ptr++) = (Uint16) SDL_SwapLE16(swapr);
*(ptr++) = (Uint16) SDL_SwapLE16(swaprr);
*(ptr++) = (Uint16) SDL_SwapLE16(swapl);
*(ptr++) = (Uint16) SDL_SwapLE16(swaplr);
*(ptr++) = (Uint16) SDL_SwapLE16(swapr)/2 + (Uint16) SDL_SwapLE16(swaprr)/2;
*(ptr++) = (Uint16) SDL_SwapLE16(swapwf);
break;
case 180:
*(ptr++) = (Uint16) SDL_SwapLE16(swaprr);
*(ptr++) = (Uint16) SDL_SwapLE16(swaplr);
*(ptr++) = (Uint16) SDL_SwapLE16(swapr);
*(ptr++) = (Uint16) SDL_SwapLE16(swapl);
*(ptr++) = (Uint16) SDL_SwapLE16(swaprr)/2 + (Uint16) SDL_SwapLE16(swaplr)/2;
*(ptr++) = (Uint16) SDL_SwapLE16(swapwf);
break;
case 270:
*(ptr++) = (Uint16) SDL_SwapLE16(swaplr);
*(ptr++) = (Uint16) SDL_SwapLE16(swapl);
*(ptr++) = (Uint16) SDL_SwapLE16(swaprr);
*(ptr++) = (Uint16) SDL_SwapLE16(swapr);
*(ptr++) = (Uint16) SDL_SwapLE16(swapl)/2 + (Uint16) SDL_SwapLE16(swaplr)/2;
*(ptr++) = (Uint16) SDL_SwapLE16(swapwf);
break;
}
}
}
 
static void _Eff_position_s16lsb(int chan, void *stream, int len, void *udata)
{
/* 16 signed bits (lsb) * 2 channels. */
volatile position_args *args = (volatile position_args *) udata;
Sint16 *ptr = (Sint16 *) stream;
int i;
 
#if 0
if (len % (sizeof(Sint16) * 2)) {
fprintf(stderr,"Not an even number of frames! len=%d\n", len);
return;
}
#endif
 
for (i = 0; i < len; i += sizeof (Sint16) * 2) {
Sint16 swapl = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+0))) *
args->left_f) * args->distance_f);
Sint16 swapr = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+1))) *
args->right_f) * args->distance_f);
if (args->room_angle == 180) {
*(ptr++) = (Sint16) SDL_SwapLE16(swapr);
*(ptr++) = (Sint16) SDL_SwapLE16(swapl);
}
else {
*(ptr++) = (Sint16) SDL_SwapLE16(swapl);
*(ptr++) = (Sint16) SDL_SwapLE16(swapr);
}
}
}
static void _Eff_position_s16lsb_c4(int chan, void *stream, int len, void *udata)
{
/* 16 signed bits (lsb) * 4 channels. */
volatile position_args *args = (volatile position_args *) udata;
Sint16 *ptr = (Sint16 *) stream;
int i;
 
for (i = 0; i < len; i += sizeof (Sint16) * 4) {
Sint16 swapl = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+0))) *
args->left_f) * args->distance_f);
Sint16 swapr = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+1))) *
args->right_f) * args->distance_f);
Sint16 swaplr = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+1))) *
args->left_rear_f) * args->distance_f);
Sint16 swaprr = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+2))) *
args->right_rear_f) * args->distance_f);
switch (args->room_angle) {
case 0:
*(ptr++) = (Sint16) SDL_SwapLE16(swapl);
*(ptr++) = (Sint16) SDL_SwapLE16(swapr);
*(ptr++) = (Sint16) SDL_SwapLE16(swaplr);
*(ptr++) = (Sint16) SDL_SwapLE16(swaprr);
break;
case 90:
*(ptr++) = (Sint16) SDL_SwapLE16(swapr);
*(ptr++) = (Sint16) SDL_SwapLE16(swaprr);
*(ptr++) = (Sint16) SDL_SwapLE16(swapl);
*(ptr++) = (Sint16) SDL_SwapLE16(swaplr);
break;
case 180:
*(ptr++) = (Sint16) SDL_SwapLE16(swaprr);
*(ptr++) = (Sint16) SDL_SwapLE16(swaplr);
*(ptr++) = (Sint16) SDL_SwapLE16(swapr);
*(ptr++) = (Sint16) SDL_SwapLE16(swapl);
break;
case 270:
*(ptr++) = (Sint16) SDL_SwapLE16(swaplr);
*(ptr++) = (Sint16) SDL_SwapLE16(swapl);
*(ptr++) = (Sint16) SDL_SwapLE16(swaprr);
*(ptr++) = (Sint16) SDL_SwapLE16(swapr);
break;
}
}
}
 
static void _Eff_position_s16lsb_c6(int chan, void *stream, int len, void *udata)
{
/* 16 signed bits (lsb) * 6 channels. */
volatile position_args *args = (volatile position_args *) udata;
Sint16 *ptr = (Sint16 *) stream;
int i;
 
for (i = 0; i < len; i += sizeof (Sint16) * 6) {
Sint16 swapl = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+0))) *
args->left_f) * args->distance_f);
Sint16 swapr = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+1))) *
args->right_f) * args->distance_f);
Sint16 swaplr = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+2))) *
args->left_rear_f) * args->distance_f);
Sint16 swaprr = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+3))) *
args->right_rear_f) * args->distance_f);
Sint16 swapce = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+4))) *
args->center_f) * args->distance_f);
Sint16 swapwf = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+5))) *
args->lfe_f) * args->distance_f);
switch (args->room_angle) {
case 0:
*(ptr++) = (Sint16) SDL_SwapLE16(swapl);
*(ptr++) = (Sint16) SDL_SwapLE16(swapr);
*(ptr++) = (Sint16) SDL_SwapLE16(swaplr);
*(ptr++) = (Sint16) SDL_SwapLE16(swaprr);
*(ptr++) = (Sint16) SDL_SwapLE16(swapce);
*(ptr++) = (Sint16) SDL_SwapLE16(swapwf);
break;
case 90:
*(ptr++) = (Sint16) SDL_SwapLE16(swapr);
*(ptr++) = (Sint16) SDL_SwapLE16(swaprr);
*(ptr++) = (Sint16) SDL_SwapLE16(swapl);
*(ptr++) = (Sint16) SDL_SwapLE16(swaplr);
*(ptr++) = (Sint16) SDL_SwapLE16(swapr)/2 + (Sint16) SDL_SwapLE16(swaprr)/2;
*(ptr++) = (Sint16) SDL_SwapLE16(swapwf);
break;
case 180:
*(ptr++) = (Sint16) SDL_SwapLE16(swaprr);
*(ptr++) = (Sint16) SDL_SwapLE16(swaplr);
*(ptr++) = (Sint16) SDL_SwapLE16(swapr);
*(ptr++) = (Sint16) SDL_SwapLE16(swapl);
*(ptr++) = (Sint16) SDL_SwapLE16(swaprr)/2 + (Sint16) SDL_SwapLE16(swaplr)/2;
*(ptr++) = (Sint16) SDL_SwapLE16(swapwf);
break;
case 270:
*(ptr++) = (Sint16) SDL_SwapLE16(swaplr);
*(ptr++) = (Sint16) SDL_SwapLE16(swapl);
*(ptr++) = (Sint16) SDL_SwapLE16(swaprr);
*(ptr++) = (Sint16) SDL_SwapLE16(swapr);
*(ptr++) = (Sint16) SDL_SwapLE16(swapl)/2 + (Sint16) SDL_SwapLE16(swaplr)/2;
*(ptr++) = (Sint16) SDL_SwapLE16(swapwf);
break;
}
}
}
 
static void _Eff_position_u16msb(int chan, void *stream, int len, void *udata)
{
/* 16 signed bits (lsb) * 2 channels. */
volatile position_args *args = (volatile position_args *) udata;
Uint16 *ptr = (Uint16 *) stream;
int i;
 
for (i = 0; i < len; i += sizeof (Sint16) * 2) {
Sint16 sampl = (Sint16) (SDL_SwapBE16(*(ptr+0)) - 32768);
Sint16 sampr = (Sint16) (SDL_SwapBE16(*(ptr+1)) - 32768);
Uint16 swapl = (Uint16) ((Sint16) (((float) sampl * args->left_f)
* args->distance_f) + 32768);
Uint16 swapr = (Uint16) ((Sint16) (((float) sampr * args->right_f)
* args->distance_f) + 32768);
 
if (args->room_angle == 180) {
*(ptr++) = (Uint16) SDL_SwapBE16(swapr);
*(ptr++) = (Uint16) SDL_SwapBE16(swapl);
}
else {
*(ptr++) = (Uint16) SDL_SwapBE16(swapl);
*(ptr++) = (Uint16) SDL_SwapBE16(swapr);
}
}
}
static void _Eff_position_u16msb_c4(int chan, void *stream, int len, void *udata)
{
/* 16 signed bits (lsb) * 4 channels. */
volatile position_args *args = (volatile position_args *) udata;
Uint16 *ptr = (Uint16 *) stream;
int i;
 
for (i = 0; i < len; i += sizeof (Sint16) * 4) {
Sint16 sampl = (Sint16) (SDL_SwapBE16(*(ptr+0)) - 32768);
Sint16 sampr = (Sint16) (SDL_SwapBE16(*(ptr+1)) - 32768);
Sint16 samplr = (Sint16) (SDL_SwapBE16(*(ptr+2)) - 32768);
Sint16 samprr = (Sint16) (SDL_SwapBE16(*(ptr+3)) - 32768);
Uint16 swapl = (Uint16) ((Sint16) (((float) sampl * args->left_f)
* args->distance_f) + 32768);
Uint16 swapr = (Uint16) ((Sint16) (((float) sampr * args->right_f)
* args->distance_f) + 32768);
Uint16 swaplr = (Uint16) ((Sint16) (((float) samplr * args->left_rear_f)
* args->distance_f) + 32768);
Uint16 swaprr = (Uint16) ((Sint16) (((float) samprr * args->right_rear_f)
* args->distance_f) + 32768);
 
switch (args->room_angle) {
case 0:
*(ptr++) = (Uint16) SDL_SwapBE16(swapl);
*(ptr++) = (Uint16) SDL_SwapBE16(swapr);
*(ptr++) = (Uint16) SDL_SwapBE16(swaplr);
*(ptr++) = (Uint16) SDL_SwapBE16(swaprr);
break;
case 90:
*(ptr++) = (Uint16) SDL_SwapBE16(swapr);
*(ptr++) = (Uint16) SDL_SwapBE16(swaprr);
*(ptr++) = (Uint16) SDL_SwapBE16(swapl);
*(ptr++) = (Uint16) SDL_SwapBE16(swaplr);
break;
case 180:
*(ptr++) = (Uint16) SDL_SwapBE16(swaprr);
*(ptr++) = (Uint16) SDL_SwapBE16(swaplr);
*(ptr++) = (Uint16) SDL_SwapBE16(swapr);
*(ptr++) = (Uint16) SDL_SwapBE16(swapl);
break;
case 270:
*(ptr++) = (Uint16) SDL_SwapBE16(swaplr);
*(ptr++) = (Uint16) SDL_SwapBE16(swapl);
*(ptr++) = (Uint16) SDL_SwapBE16(swaprr);
*(ptr++) = (Uint16) SDL_SwapBE16(swapr);
break;
}
}
}
static void _Eff_position_u16msb_c6(int chan, void *stream, int len, void *udata)
{
/* 16 signed bits (lsb) * 6 channels. */
volatile position_args *args = (volatile position_args *) udata;
Uint16 *ptr = (Uint16 *) stream;
int i;
 
for (i = 0; i < len; i += sizeof (Sint16) * 6) {
Sint16 sampl = (Sint16) (SDL_SwapBE16(*(ptr+0)) - 32768);
Sint16 sampr = (Sint16) (SDL_SwapBE16(*(ptr+1)) - 32768);
Sint16 samplr = (Sint16) (SDL_SwapBE16(*(ptr+2)) - 32768);
Sint16 samprr = (Sint16) (SDL_SwapBE16(*(ptr+3)) - 32768);
Sint16 sampce = (Sint16) (SDL_SwapBE16(*(ptr+4)) - 32768);
Sint16 sampwf = (Sint16) (SDL_SwapBE16(*(ptr+5)) - 32768);
Uint16 swapl = (Uint16) ((Sint16) (((float) sampl * args->left_f)
* args->distance_f) + 32768);
Uint16 swapr = (Uint16) ((Sint16) (((float) sampr * args->right_f)
* args->distance_f) + 32768);
Uint16 swaplr = (Uint16) ((Sint16) (((float) samplr * args->left_rear_f)
* args->distance_f) + 32768);
Uint16 swaprr = (Uint16) ((Sint16) (((float) samprr * args->right_rear_f)
* args->distance_f) + 32768);
Uint16 swapce = (Uint16) ((Sint16) (((float) sampce * args->center_f)
* args->distance_f) + 32768);
Uint16 swapwf = (Uint16) ((Sint16) (((float) sampwf * args->lfe_f)
* args->distance_f) + 32768);
 
switch (args->room_angle) {
case 0:
*(ptr++) = (Uint16) SDL_SwapBE16(swapl);
*(ptr++) = (Uint16) SDL_SwapBE16(swapr);
*(ptr++) = (Uint16) SDL_SwapBE16(swaplr);
*(ptr++) = (Uint16) SDL_SwapBE16(swaprr);
*(ptr++) = (Uint16) SDL_SwapBE16(swapce);
*(ptr++) = (Uint16) SDL_SwapBE16(swapwf);
break;
case 90:
*(ptr++) = (Uint16) SDL_SwapBE16(swapr);
*(ptr++) = (Uint16) SDL_SwapBE16(swaprr);
*(ptr++) = (Uint16) SDL_SwapBE16(swapl);
*(ptr++) = (Uint16) SDL_SwapBE16(swaplr);
*(ptr++) = (Uint16) SDL_SwapBE16(swapr)/2 + (Uint16) SDL_SwapBE16(swaprr)/2;
*(ptr++) = (Uint16) SDL_SwapBE16(swapwf);
break;
case 180:
*(ptr++) = (Uint16) SDL_SwapBE16(swaprr);
*(ptr++) = (Uint16) SDL_SwapBE16(swaplr);
*(ptr++) = (Uint16) SDL_SwapBE16(swapr);
*(ptr++) = (Uint16) SDL_SwapBE16(swapl);
*(ptr++) = (Uint16) SDL_SwapBE16(swaprr)/2 + (Uint16) SDL_SwapBE16(swaplr)/2;
*(ptr++) = (Uint16) SDL_SwapBE16(swapwf);
break;
case 270:
*(ptr++) = (Uint16) SDL_SwapBE16(swaplr);
*(ptr++) = (Uint16) SDL_SwapBE16(swapl);
*(ptr++) = (Uint16) SDL_SwapBE16(swaprr);
*(ptr++) = (Uint16) SDL_SwapBE16(swapr);
*(ptr++) = (Uint16) SDL_SwapBE16(swapl)/2 + (Uint16) SDL_SwapBE16(swaplr)/2;
*(ptr++) = (Uint16) SDL_SwapBE16(swapwf);
break;
}
}
}
 
static void _Eff_position_s16msb(int chan, void *stream, int len, void *udata)
{
/* 16 signed bits (lsb) * 2 channels. */
volatile position_args *args = (volatile position_args *) udata;
Sint16 *ptr = (Sint16 *) stream;
int i;
 
for (i = 0; i < len; i += sizeof (Sint16) * 2) {
Sint16 swapl = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+0))) *
args->left_f) * args->distance_f);
Sint16 swapr = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+1))) *
args->right_f) * args->distance_f);
*(ptr++) = (Sint16) SDL_SwapBE16(swapl);
*(ptr++) = (Sint16) SDL_SwapBE16(swapr);
}
}
static void _Eff_position_s16msb_c4(int chan, void *stream, int len, void *udata)
{
/* 16 signed bits (lsb) * 4 channels. */
volatile position_args *args = (volatile position_args *) udata;
Sint16 *ptr = (Sint16 *) stream;
int i;
 
for (i = 0; i < len; i += sizeof (Sint16) * 4) {
Sint16 swapl = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+0))) *
args->left_f) * args->distance_f);
Sint16 swapr = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+1))) *
args->right_f) * args->distance_f);
Sint16 swaplr = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+2))) *
args->left_rear_f) * args->distance_f);
Sint16 swaprr = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+3))) *
args->right_rear_f) * args->distance_f);
switch (args->room_angle) {
case 0:
*(ptr++) = (Sint16) SDL_SwapBE16(swapl);
*(ptr++) = (Sint16) SDL_SwapBE16(swapr);
*(ptr++) = (Sint16) SDL_SwapBE16(swaplr);
*(ptr++) = (Sint16) SDL_SwapBE16(swaprr);
break;
case 90:
*(ptr++) = (Sint16) SDL_SwapBE16(swapr);
*(ptr++) = (Sint16) SDL_SwapBE16(swaprr);
*(ptr++) = (Sint16) SDL_SwapBE16(swapl);
*(ptr++) = (Sint16) SDL_SwapBE16(swaplr);
break;
case 180:
*(ptr++) = (Sint16) SDL_SwapBE16(swaprr);
*(ptr++) = (Sint16) SDL_SwapBE16(swaplr);
*(ptr++) = (Sint16) SDL_SwapBE16(swapr);
*(ptr++) = (Sint16) SDL_SwapBE16(swapl);
break;
case 270:
*(ptr++) = (Sint16) SDL_SwapBE16(swaplr);
*(ptr++) = (Sint16) SDL_SwapBE16(swapl);
*(ptr++) = (Sint16) SDL_SwapBE16(swaprr);
*(ptr++) = (Sint16) SDL_SwapBE16(swapr);
break;
}
}
}
static void _Eff_position_s16msb_c6(int chan, void *stream, int len, void *udata)
{
/* 16 signed bits (lsb) * 6 channels. */
volatile position_args *args = (volatile position_args *) udata;
Sint16 *ptr = (Sint16 *) stream;
int i;
 
for (i = 0; i < len; i += sizeof (Sint16) * 6) {
Sint16 swapl = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+0))) *
args->left_f) * args->distance_f);
Sint16 swapr = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+1))) *
args->right_f) * args->distance_f);
Sint16 swaplr = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+2))) *
args->left_rear_f) * args->distance_f);
Sint16 swaprr = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+3))) *
args->right_rear_f) * args->distance_f);
Sint16 swapce = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+4))) *
args->center_f) * args->distance_f);
Sint16 swapwf = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+5))) *
args->lfe_f) * args->distance_f);
 
switch (args->room_angle) {
case 0:
*(ptr++) = (Sint16) SDL_SwapBE16(swapl);
*(ptr++) = (Sint16) SDL_SwapBE16(swapr);
*(ptr++) = (Sint16) SDL_SwapBE16(swaplr);
*(ptr++) = (Sint16) SDL_SwapBE16(swaprr);
*(ptr++) = (Sint16) SDL_SwapBE16(swapce);
*(ptr++) = (Sint16) SDL_SwapBE16(swapwf);
break;
case 90:
*(ptr++) = (Sint16) SDL_SwapBE16(swapr);
*(ptr++) = (Sint16) SDL_SwapBE16(swaprr);
*(ptr++) = (Sint16) SDL_SwapBE16(swapl);
*(ptr++) = (Sint16) SDL_SwapBE16(swaplr);
*(ptr++) = (Sint16) SDL_SwapBE16(swapr)/2 + (Sint16) SDL_SwapBE16(swaprr)/2;
*(ptr++) = (Sint16) SDL_SwapBE16(swapwf);
break;
case 180:
*(ptr++) = (Sint16) SDL_SwapBE16(swaprr);
*(ptr++) = (Sint16) SDL_SwapBE16(swaplr);
*(ptr++) = (Sint16) SDL_SwapBE16(swapr);
*(ptr++) = (Sint16) SDL_SwapBE16(swapl);
*(ptr++) = (Sint16) SDL_SwapBE16(swaprr)/2 + (Sint16) SDL_SwapBE16(swaplr)/2;
*(ptr++) = (Sint16) SDL_SwapBE16(swapwf);
break;
case 270:
*(ptr++) = (Sint16) SDL_SwapBE16(swaplr);
*(ptr++) = (Sint16) SDL_SwapBE16(swapl);
*(ptr++) = (Sint16) SDL_SwapBE16(swaprr);
*(ptr++) = (Sint16) SDL_SwapBE16(swapr);
*(ptr++) = (Sint16) SDL_SwapBE16(swapl)/2 + (Sint16) SDL_SwapBE16(swaplr)/2;
*(ptr++) = (Sint16) SDL_SwapBE16(swapwf);
break;
}
}
}
 
static void init_position_args(position_args *args)
{
memset(args, '\0', sizeof (position_args));
args->in_use = 0;
args->room_angle = 0;
args->left_u8 = args->right_u8 = args->distance_u8 = 255;
args->left_f = args->right_f = args->distance_f = 1.0f;
args->left_rear_u8 = args->right_rear_u8 = args->center_u8 = args->lfe_u8 = 255;
args->left_rear_f = args->right_rear_f = args->center_f = args->lfe_f = 1.0f;
Mix_QuerySpec(NULL, NULL, (int *) &args->channels);
}
 
 
static position_args *get_position_arg(int channel)
{
void *rc;
int i;
 
if (channel < 0) {
if (pos_args_global == NULL) {
pos_args_global = SDL_malloc(sizeof (position_args));
if (pos_args_global == NULL) {
Mix_SetError("Out of memory");
return(NULL);
}
init_position_args(pos_args_global);
}
 
return(pos_args_global);
}
 
if (channel >= position_channels) {
rc = SDL_realloc(pos_args_array, (channel + 1) * sizeof (position_args *));
if (rc == NULL) {
Mix_SetError("Out of memory");
return(NULL);
}
pos_args_array = (position_args **) rc;
for (i = position_channels; i <= channel; i++) {
pos_args_array[i] = NULL;
}
position_channels = channel + 1;
}
 
if (pos_args_array[channel] == NULL) {
pos_args_array[channel] = (position_args *)SDL_malloc(sizeof(position_args));
if (pos_args_array[channel] == NULL) {
Mix_SetError("Out of memory");
return(NULL);
}
init_position_args(pos_args_array[channel]);
}
 
return(pos_args_array[channel]);
}
 
 
static Mix_EffectFunc_t get_position_effect_func(Uint16 format, int channels)
{
Mix_EffectFunc_t f = NULL;
 
switch (format) {
case AUDIO_U8:
switch (channels) {
case 1:
case 2:
f = (_Eff_build_volume_table_u8()) ? _Eff_position_table_u8 :
_Eff_position_u8;
break;
case 4:
f = _Eff_position_u8_c4;
break;
case 6:
f = _Eff_position_u8_c6;
break;
}
break;
 
case AUDIO_S8:
switch (channels) {
case 1:
case 2:
f = (_Eff_build_volume_table_s8()) ? _Eff_position_table_s8 :
_Eff_position_s8;
break;
case 4:
f = _Eff_position_s8_c4;
break;
case 6:
f = _Eff_position_s8_c6;
break;
}
break;
 
case AUDIO_U16LSB:
switch (channels) {
case 1:
case 2:
f = _Eff_position_u16lsb;
break;
case 4:
f = _Eff_position_u16lsb_c4;
break;
case 6:
f = _Eff_position_u16lsb_c6;
break;
}
break;
 
case AUDIO_S16LSB:
switch (channels) {
case 1:
case 2:
f = _Eff_position_s16lsb;
break;
case 4:
f = _Eff_position_s16lsb_c4;
break;
case 6:
f = _Eff_position_s16lsb_c6;
break;
}
break;
 
case AUDIO_U16MSB:
switch (channels) {
case 1:
case 2:
f = _Eff_position_u16msb;
break;
case 4:
f = _Eff_position_u16msb_c4;
break;
case 6:
f = _Eff_position_u16msb_c6;
break;
}
break;
 
case AUDIO_S16MSB:
switch (channels) {
case 1:
case 2:
f = _Eff_position_s16msb;
break;
case 4:
f = _Eff_position_s16msb_c4;
break;
case 6:
f = _Eff_position_s16msb_c6;
break;
}
break;
 
default:
Mix_SetError("Unsupported audio format");
}
 
return(f);
}
 
static Uint8 speaker_amplitude[6];
 
static void set_amplitudes(int channels, int angle, int room_angle)
{
int left = 255, right = 255;
int left_rear = 255, right_rear = 255, center = 255;
 
angle = SDL_abs(angle) % 360; /* make angle between 0 and 359. */
 
if (channels == 2)
{
/*
* We only attenuate by position if the angle falls on the far side
* of center; That is, an angle that's due north would not attenuate
* either channel. Due west attenuates the right channel to 0.0, and
* due east attenuates the left channel to 0.0. Slightly east of
* center attenuates the left channel a little, and the right channel
* not at all. I think of this as occlusion by one's own head. :)
*
* ...so, we split our angle circle into four quadrants...
*/
if (angle < 90) {
left = 255 - ((int) (255.0f * (((float) angle) / 89.0f)));
} else if (angle < 180) {
left = (int) (255.0f * (((float) (angle - 90)) / 89.0f));
} else if (angle < 270) {
right = 255 - ((int) (255.0f * (((float) (angle - 180)) / 89.0f)));
} else {
right = (int) (255.0f * (((float) (angle - 270)) / 89.0f));
}
}
 
if (channels == 4 || channels == 6)
{
/*
* An angle that's due north does not attenuate the center channel.
* An angle in the first quadrant, 0-90, does not attenuate the RF.
*
* ...so, we split our angle circle into 8 ...
*
* CE
* 0
* LF | RF
* |
* 270<-------|----------->90
* |
* LR | RR
* 180
*
*/
if (angle < 45) {
left = ((int) (255.0f * (((float) (180 - angle)) / 179.0f)));
left_rear = 255 - ((int) (255.0f * (((float) (angle + 45)) / 89.0f)));
right_rear = 255 - ((int) (255.0f * (((float) (90 - angle)) / 179.0f)));
} else if (angle < 90) {
center = ((int) (255.0f * (((float) (225 - angle)) / 179.0f)));
left = ((int) (255.0f * (((float) (180 - angle)) / 179.0f)));
left_rear = 255 - ((int) (255.0f * (((float) (135 - angle)) / 89.0f)));
right_rear = ((int) (255.0f * (((float) (90 + angle)) / 179.0f)));
} else if (angle < 135) {
center = ((int) (255.0f * (((float) (225 - angle)) / 179.0f)));
left = 255 - ((int) (255.0f * (((float) (angle - 45)) / 89.0f)));
right = ((int) (255.0f * (((float) (270 - angle)) / 179.0f)));
left_rear = ((int) (255.0f * (((float) (angle)) / 179.0f)));
} else if (angle < 180) {
center = 255 - ((int) (255.0f * (((float) (angle - 90)) / 89.0f)));
left = 255 - ((int) (255.0f * (((float) (225 - angle)) / 89.0f)));
right = ((int) (255.0f * (((float) (270 - angle)) / 179.0f)));
left_rear = ((int) (255.0f * (((float) (angle)) / 179.0f)));
} else if (angle < 225) {
center = 255 - ((int) (255.0f * (((float) (270 - angle)) / 89.0f)));
left = ((int) (255.0f * (((float) (angle - 90)) / 179.0f)));
right = 255 - ((int) (255.0f * (((float) (angle - 135)) / 89.0f)));
right_rear = ((int) (255.0f * (((float) (360 - angle)) / 179.0f)));
} else if (angle < 270) {
center = ((int) (255.0f * (((float) (angle - 135)) / 179.0f)));
left = ((int) (255.0f * (((float) (angle - 90)) / 179.0f)));
right = 255 - ((int) (255.0f * (((float) (315 - angle)) / 89.0f)));
right_rear = ((int) (255.0f * (((float) (360 - angle)) / 179.0f)));
} else if (angle < 315) {
center = ((int) (255.0f * (((float) (angle - 135)) / 179.0f)));
right = ((int) (255.0f * (((float) (angle - 180)) / 179.0f)));
left_rear = ((int) (255.0f * (((float) (450 - angle)) / 179.0f)));
right_rear = 255 - ((int) (255.0f * (((float) (angle - 225)) / 89.0f)));
} else {
right = ((int) (255.0f * (((float) (angle - 180)) / 179.0f)));
left_rear = ((int) (255.0f * (((float) (450 - angle)) / 179.0f)));
right_rear = 255 - ((int) (255.0f * (((float) (405 - angle)) / 89.0f)));
}
}
 
if (left < 0) left = 0; if (left > 255) left = 255;
if (right < 0) right = 0; if (right > 255) right = 255;
if (left_rear < 0) left_rear = 0; if (left_rear > 255) left_rear = 255;
if (right_rear < 0) right_rear = 0; if (right_rear > 255) right_rear = 255;
if (center < 0) center = 0; if (center > 255) center = 255;
 
if (room_angle == 90) {
speaker_amplitude[0] = (Uint8)left_rear;
speaker_amplitude[1] = (Uint8)left;
speaker_amplitude[2] = (Uint8)right_rear;
speaker_amplitude[3] = (Uint8)right;
}
else if (room_angle == 180) {
if (channels == 2) {
speaker_amplitude[0] = (Uint8)right;
speaker_amplitude[1] = (Uint8)left;
}
else {
speaker_amplitude[0] = (Uint8)right_rear;
speaker_amplitude[1] = (Uint8)left_rear;
speaker_amplitude[2] = (Uint8)right;
speaker_amplitude[3] = (Uint8)left;
}
}
else if (room_angle == 270) {
speaker_amplitude[0] = (Uint8)right;
speaker_amplitude[1] = (Uint8)right_rear;
speaker_amplitude[2] = (Uint8)left;
speaker_amplitude[3] = (Uint8)left_rear;
}
else {
speaker_amplitude[0] = (Uint8)left;
speaker_amplitude[1] = (Uint8)right;
speaker_amplitude[2] = (Uint8)left_rear;
speaker_amplitude[3] = (Uint8)right_rear;
}
speaker_amplitude[4] = (Uint8)center;
speaker_amplitude[5] = 255;
}
 
int Mix_SetPosition(int channel, Sint16 angle, Uint8 distance);
 
int Mix_SetPanning(int channel, Uint8 left, Uint8 right)
{
Mix_EffectFunc_t f = NULL;
int channels;
Uint16 format;
position_args *args = NULL;
int retval = 1;
 
Mix_QuerySpec(NULL, &format, &channels);
 
if (channels != 2 && channels != 4 && channels != 6) /* it's a no-op; we call that successful. */
return(1);
 
if (channels > 2) {
/* left = right = 255 => angle = 0, to unregister effect as when channels = 2 */
/* left = 255 => angle = -90; left = 0 => angle = +89 */
int angle = 0;
if ((left != 255) || (right != 255)) {
angle = (int)left;
angle = 127 - angle;
angle = -angle;
angle = angle * 90 / 128; /* Make it larger for more effect? */
}
return( Mix_SetPosition(channel, angle, 0) );
}
 
f = get_position_effect_func(format, channels);
if (f == NULL)
return(0);
 
SDL_LockAudio();
args = get_position_arg(channel);
if (!args) {
SDL_UnlockAudio();
return(0);
}
 
/* it's a no-op; unregister the effect, if it's registered. */
if ((args->distance_u8 == 255) && (left == 255) && (right == 255)) {
if (args->in_use) {
retval = _Mix_UnregisterEffect_locked(channel, f);
SDL_UnlockAudio();
return(retval);
} else {
SDL_UnlockAudio();
return(1);
}
}
 
args->left_u8 = left;
args->left_f = ((float) left) / 255.0f;
args->right_u8 = right;
args->right_f = ((float) right) / 255.0f;
args->room_angle = 0;
 
if (!args->in_use) {
args->in_use = 1;
retval=_Mix_RegisterEffect_locked(channel, f, _Eff_PositionDone, (void*)args);
}
 
SDL_UnlockAudio();
return(retval);
}
 
 
int Mix_SetDistance(int channel, Uint8 distance)
{
Mix_EffectFunc_t f = NULL;
Uint16 format;
position_args *args = NULL;
int channels;
int retval = 1;
 
Mix_QuerySpec(NULL, &format, &channels);
f = get_position_effect_func(format, channels);
if (f == NULL)
return(0);
 
SDL_LockAudio();
args = get_position_arg(channel);
if (!args) {
SDL_UnlockAudio();
return(0);
}
 
distance = 255 - distance; /* flip it to our scale. */
 
/* it's a no-op; unregister the effect, if it's registered. */
if ((distance == 255) && (args->left_u8 == 255) && (args->right_u8 == 255)) {
if (args->in_use) {
retval = _Mix_UnregisterEffect_locked(channel, f);
SDL_UnlockAudio();
return(retval);
} else {
SDL_UnlockAudio();
return(1);
}
}
 
args->distance_u8 = distance;
args->distance_f = ((float) distance) / 255.0f;
if (!args->in_use) {
args->in_use = 1;
retval = _Mix_RegisterEffect_locked(channel, f, _Eff_PositionDone, (void *) args);
}
 
SDL_UnlockAudio();
return(retval);
}
 
 
int Mix_SetPosition(int channel, Sint16 angle, Uint8 distance)
{
Mix_EffectFunc_t f = NULL;
Uint16 format;
int channels;
position_args *args = NULL;
Sint16 room_angle = 0;
int retval = 1;
 
Mix_QuerySpec(NULL, &format, &channels);
f = get_position_effect_func(format, channels);
if (f == NULL)
return(0);
 
angle = SDL_abs(angle) % 360; /* make angle between 0 and 359. */
 
SDL_LockAudio();
args = get_position_arg(channel);
if (!args) {
SDL_UnlockAudio();
return(0);
}
 
/* it's a no-op; unregister the effect, if it's registered. */
if ((!distance) && (!angle)) {
if (args->in_use) {
retval = _Mix_UnregisterEffect_locked(channel, f);
SDL_UnlockAudio();
return(retval);
} else {
SDL_UnlockAudio();
return(1);
}
}
 
if (channels == 2)
{
if (angle > 180)
room_angle = 180; /* exchange left and right channels */
else room_angle = 0;
}
 
if (channels == 4 || channels == 6)
{
if (angle > 315) room_angle = 0;
else if (angle > 225) room_angle = 270;
else if (angle > 135) room_angle = 180;
else if (angle > 45) room_angle = 90;
else room_angle = 0;
}
 
 
distance = 255 - distance; /* flip it to scale Mix_SetDistance() uses. */
 
set_amplitudes(channels, angle, room_angle);
 
args->left_u8 = speaker_amplitude[0];
args->left_f = ((float) speaker_amplitude[0]) / 255.0f;
args->right_u8 = speaker_amplitude[1];
args->right_f = ((float) speaker_amplitude[1]) / 255.0f;
args->left_rear_u8 = speaker_amplitude[2];
args->left_rear_f = ((float) speaker_amplitude[2]) / 255.0f;
args->right_rear_u8 = speaker_amplitude[3];
args->right_rear_f = ((float) speaker_amplitude[3]) / 255.0f;
args->center_u8 = speaker_amplitude[4];
args->center_f = ((float) speaker_amplitude[4]) / 255.0f;
args->lfe_u8 = speaker_amplitude[5];
args->lfe_f = ((float) speaker_amplitude[5]) / 255.0f;
args->distance_u8 = distance;
args->distance_f = ((float) distance) / 255.0f;
args->room_angle = room_angle;
if (!args->in_use) {
args->in_use = 1;
retval = _Mix_RegisterEffect_locked(channel, f, _Eff_PositionDone, (void *) args);
}
 
SDL_UnlockAudio();
return(retval);
}
 
 
/* end of effects_position.c ... */
 
/contrib/sdk/sources/SDL_mixer-1.2.12/effect_stereoreverse.c
0,0 → 1,120
/*
SDL_mixer: An audio mixer library based on the SDL library
Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
 
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
 
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
 
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
 
This file by Ryan C. Gordon (icculus@icculus.org)
 
These are some internally supported special effects that use SDL_mixer's
effect callback API. They are meant for speed over quality. :)
*/
 
/* $Id$ */
 
#include <stdio.h>
#include <stdlib.h>
 
#include "SDL.h"
#include "SDL_mixer.h"
 
#define __MIX_INTERNAL_EFFECT__
#include "effects_internal.h"
 
/* profile code:
#include <sys/time.h>
#include <unistd.h>
struct timeval tv1;
struct timeval tv2;
gettimeofday(&tv1, NULL);
 
... do your thing here ...
 
gettimeofday(&tv2, NULL);
printf("%ld\n", tv2.tv_usec - tv1.tv_usec);
*/
 
 
 
/*
* Stereo reversal effect...this one's pretty straightforward...
*/
 
static void _Eff_reversestereo16(int chan, void *stream, int len, void *udata)
{
/* 16 bits * 2 channels. */
Uint32 *ptr = (Uint32 *) stream;
int i;
 
for (i = 0; i < len; i += sizeof (Uint32), ptr++) {
*ptr = (((*ptr) & 0xFFFF0000) >> 16) | (((*ptr) & 0x0000FFFF) << 16);
}
}
 
 
static void _Eff_reversestereo8(int chan, void *stream, int len, void *udata)
{
/* 8 bits * 2 channels. */
Uint32 *ptr = (Uint32 *) stream;
int i;
 
/* get the last two bytes if len is not divisible by four... */
if (len % sizeof (Uint32) != 0) {
Uint16 *p = (Uint16 *) (((Uint8 *) stream) + (len - 2));
*p = (Uint16)((((*p) & 0xFF00) >> 8) | (((*ptr) & 0x00FF) << 8));
len -= 2;
}
 
for (i = 0; i < len; i += sizeof (Uint32), ptr++) {
*ptr = (((*ptr) & 0x0000FF00) >> 8) | (((*ptr) & 0x000000FF) << 8) |
(((*ptr) & 0xFF000000) >> 8) | (((*ptr) & 0x00FF0000) << 8);
}
}
 
 
int Mix_SetReverseStereo(int channel, int flip)
{
Mix_EffectFunc_t f = NULL;
int channels;
Uint16 format;
 
Mix_QuerySpec(NULL, &format, &channels);
 
if (channels == 2) {
if ((format & 0xFF) == 16)
f = _Eff_reversestereo16;
else if ((format & 0xFF) == 8)
f = _Eff_reversestereo8;
else {
Mix_SetError("Unsupported audio format");
return(0);
}
 
if (!flip) {
return(Mix_UnregisterEffect(channel, f));
} else {
return(Mix_RegisterEffect(channel, f, NULL, NULL));
}
}
 
return(1);
}
 
 
/* end of effect_stereoreverse.c ... */
 
/contrib/sdk/sources/SDL_mixer-1.2.12/effects_internal.c
0,0 → 1,124
/*
SDL_mixer: An audio mixer library based on the SDL library
Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
 
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
 
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
 
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
 
This file by Ryan C. Gordon (icculus@icculus.org)
 
These are some helper functions for the internal mixer special effects.
*/
 
/* $Id$ */
 
 
/* ------ These are used internally only. Don't touch. ------ */
 
 
 
#include <stdio.h>
#include <stdlib.h>
#include "SDL_mixer.h"
 
#define __MIX_INTERNAL_EFFECT__
#include "effects_internal.h"
 
/* Should we favor speed over memory usage and/or quality of output? */
int _Mix_effects_max_speed = 0;
 
 
void _Mix_InitEffects(void)
{
_Mix_effects_max_speed = (SDL_getenv(MIX_EFFECTSMAXSPEED) != NULL);
}
 
void _Mix_DeinitEffects(void)
{
_Eff_PositionDeinit();
}
 
 
void *_Eff_volume_table = NULL;
 
 
/* Build the volume table for Uint8-format samples.
*
* Each column of the table is a possible sample, while each row of the
* table is a volume. Volume is a Uint8, where 0 is silence and 255 is full
* volume. So _Eff_volume_table[128][mysample] would be the value of
* mysample, at half volume.
*/
void *_Eff_build_volume_table_u8(void)
{
int volume;
int sample;
Uint8 *rc;
 
if (!_Mix_effects_max_speed) {
return(NULL);
}
 
if (!_Eff_volume_table) {
rc = SDL_malloc(256 * 256);
if (rc) {
_Eff_volume_table = (void *) rc;
for (volume = 0; volume < 256; volume++) {
for (sample = -128; sample < 128; sample ++) {
*rc = (Uint8)(((float) sample) * ((float) volume / 255.0))
+ 128;
rc++;
}
}
}
}
 
return(_Eff_volume_table);
}
 
 
/* Build the volume table for Sint8-format samples.
*
* Each column of the table is a possible sample, while each row of the
* table is a volume. Volume is a Uint8, where 0 is silence and 255 is full
* volume. So _Eff_volume_table[128][mysample+128] would be the value of
* mysample, at half volume.
*/
void *_Eff_build_volume_table_s8(void)
{
int volume;
int sample;
Sint8 *rc;
 
if (!_Eff_volume_table) {
rc = SDL_malloc(256 * 256);
if (rc) {
_Eff_volume_table = (void *) rc;
for (volume = 0; volume < 256; volume++) {
for (sample = -128; sample < 128; sample ++) {
*rc = (Sint8)(((float) sample) * ((float) volume / 255.0));
rc++;
}
}
}
}
 
return(_Eff_volume_table);
}
 
 
/* end of effects.c ... */
 
/contrib/sdk/sources/SDL_mixer-1.2.12/effects_internal.h
0,0 → 1,60
/*
SDL_mixer: An audio mixer library based on the SDL library
Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
 
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
 
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
 
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
 
/* $Id$ */
 
#ifndef _INCLUDE_EFFECTS_INTERNAL_H_
#define _INCLUDE_EFFECTS_INTERNAL_H_
 
#ifndef __MIX_INTERNAL_EFFECT__
#error You should not include this file or use these functions.
#endif
 
#include "SDL_mixer.h"
 
/* Set up for C function definitions, even when using C++ */
#ifdef __cplusplus
extern "C" {
#endif
 
extern int _Mix_effects_max_speed;
extern void *_Eff_volume_table;
void *_Eff_build_volume_table_u8(void);
void *_Eff_build_volume_table_s8(void);
 
void _Mix_InitEffects(void);
void _Mix_DeinitEffects(void);
void _Eff_PositionDeinit(void);
 
int _Mix_RegisterEffect_locked(int channel, Mix_EffectFunc_t f,
Mix_EffectDone_t d, void *arg);
int _Mix_UnregisterEffect_locked(int channel, Mix_EffectFunc_t f);
int _Mix_UnregisterAllEffects_locked(int channel);
 
 
/* Set up for C function definitions, even when using C++ */
#ifdef __cplusplus
}
#endif
 
 
#endif
 
/contrib/sdk/sources/SDL_mixer-1.2.12/load_aiff.c
0,0 → 1,250
/*
SDL_mixer: An audio mixer library based on the SDL library
Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
 
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
 
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
 
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
 
This is the source needed to decode an AIFF file into a waveform.
It's pretty straightforward once you get going. The only
externally-callable function is Mix_LoadAIFF_RW(), which is meant to
act as identically to SDL_LoadWAV_RW() as possible.
 
This file by Torbjörn Andersson (torbjorn.andersson@eurotime.se)
8SVX file support added by Marc Le Douarain (mavati@club-internet.fr)
in december 2002.
*/
 
/* $Id$ */
 
#include <stdlib.h>
#include <string.h>
 
#include "SDL_endian.h"
#include "SDL_mixer.h"
#include "load_aiff.h"
 
/*********************************************/
/* Define values for AIFF (IFF audio) format */
/*********************************************/
#define FORM 0x4d524f46 /* "FORM" */
 
#define AIFF 0x46464941 /* "AIFF" */
#define SSND 0x444e5353 /* "SSND" */
#define COMM 0x4d4d4f43 /* "COMM" */
 
#define _8SVX 0x58565338 /* "8SVX" */
#define VHDR 0x52444856 /* "VHDR" */
#define BODY 0x59444F42 /* "BODY" */
 
/* This function was taken from libsndfile. I don't pretend to fully
* understand it.
*/
 
static Uint32 SANE_to_Uint32 (Uint8 *sanebuf)
{
/* Is the frequency outside of what we can represent with Uint32? */
if ( (sanebuf[0] & 0x80) || (sanebuf[0] <= 0x3F) || (sanebuf[0] > 0x40)
|| (sanebuf[0] == 0x40 && sanebuf[1] > 0x1C) )
return 0;
 
return ((sanebuf[2] << 23) | (sanebuf[3] << 15) | (sanebuf[4] << 7)
| (sanebuf[5] >> 1)) >> (29 - sanebuf[1]);
}
 
/* This function is based on SDL_LoadWAV_RW(). */
 
SDL_AudioSpec *Mix_LoadAIFF_RW (SDL_RWops *src, int freesrc,
SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len)
{
int was_error;
int found_SSND;
int found_COMM;
int found_VHDR;
int found_BODY;
long start = 0;
 
Uint32 chunk_type;
Uint32 chunk_length;
long next_chunk;
 
/* AIFF magic header */
Uint32 FORMchunk;
Uint32 AIFFmagic;
 
/* SSND chunk */
Uint32 offset;
Uint32 blocksize;
 
/* COMM format chunk */
Uint16 channels = 0;
Uint32 numsamples = 0;
Uint16 samplesize = 0;
Uint8 sane_freq[10];
Uint32 frequency = 0;
 
/* Make sure we are passed a valid data source */
was_error = 0;
if ( src == NULL ) {
was_error = 1;
goto done;
}
 
FORMchunk = SDL_ReadLE32(src);
chunk_length = SDL_ReadBE32(src);
if ( chunk_length == AIFF ) { /* The FORMchunk has already been read */
AIFFmagic = chunk_length;
chunk_length = FORMchunk;
FORMchunk = FORM;
} else {
AIFFmagic = SDL_ReadLE32(src);
}
if ( (FORMchunk != FORM) || ( (AIFFmagic != AIFF) && (AIFFmagic != _8SVX) ) ) {
SDL_SetError("Unrecognized file type (not AIFF nor 8SVX)");
was_error = 1;
goto done;
}
 
/* TODO: Better santity-checking. */
 
found_SSND = 0;
found_COMM = 0;
found_VHDR = 0;
found_BODY = 0;
 
do {
chunk_type = SDL_ReadLE32(src);
chunk_length = SDL_ReadBE32(src);
next_chunk = SDL_RWtell(src) + chunk_length;
/* Paranoia to avoid infinite loops */
if (chunk_length == 0)
break;
 
switch (chunk_type) {
case SSND:
found_SSND = 1;
offset = SDL_ReadBE32(src);
blocksize = SDL_ReadBE32(src);
start = SDL_RWtell(src) + offset;
break;
 
case COMM:
found_COMM = 1;
channels = SDL_ReadBE16(src);
numsamples = SDL_ReadBE32(src);
samplesize = SDL_ReadBE16(src);
SDL_RWread(src, sane_freq, sizeof(sane_freq), 1);
frequency = SANE_to_Uint32(sane_freq);
if (frequency == 0) {
SDL_SetError("Bad AIFF sample frequency");
was_error = 1;
goto done;
}
break;
 
case VHDR:
found_VHDR = 1;
SDL_ReadBE32(src);
SDL_ReadBE32(src);
SDL_ReadBE32(src);
frequency = SDL_ReadBE16(src);
channels = 1;
samplesize = 8;
break;
 
case BODY:
found_BODY = 1;
numsamples = chunk_length;
start = SDL_RWtell(src);
break;
 
default:
break;
}
/* a 0 pad byte can be stored for any odd-length chunk */
if (chunk_length&1)
next_chunk++;
} while ( ( ( (AIFFmagic == AIFF) && ( !found_SSND || !found_COMM ) )
|| ( (AIFFmagic == _8SVX ) && ( !found_VHDR || !found_BODY ) ) )
&& SDL_RWseek(src, next_chunk, RW_SEEK_SET) != 1 );
 
if ( (AIFFmagic == AIFF) && !found_SSND ) {
SDL_SetError("Bad AIFF (no SSND chunk)");
was_error = 1;
goto done;
}
 
if ( (AIFFmagic == AIFF) && !found_COMM ) {
SDL_SetError("Bad AIFF (no COMM chunk)");
was_error = 1;
goto done;
}
 
if ( (AIFFmagic == _8SVX) && !found_VHDR ) {
SDL_SetError("Bad 8SVX (no VHDR chunk)");
was_error = 1;
goto done;
}
 
if ( (AIFFmagic == _8SVX) && !found_BODY ) {
SDL_SetError("Bad 8SVX (no BODY chunk)");
was_error = 1;
goto done;
}
 
/* Decode the audio data format */
memset(spec, 0, sizeof(*spec));
spec->freq = frequency;
switch (samplesize) {
case 8:
spec->format = AUDIO_S8;
break;
case 16:
spec->format = AUDIO_S16MSB;
break;
default:
SDL_SetError("Unsupported AIFF samplesize");
was_error = 1;
goto done;
}
spec->channels = (Uint8) channels;
spec->samples = 4096; /* Good default buffer size */
 
*audio_len = channels * numsamples * (samplesize / 8);
*audio_buf = (Uint8 *)SDL_malloc(*audio_len);
if ( *audio_buf == NULL ) {
SDL_SetError("Out of memory");
return(NULL);
}
SDL_RWseek(src, start, RW_SEEK_SET);
if ( SDL_RWread(src, *audio_buf, *audio_len, 1) != 1 ) {
SDL_SetError("Unable to read audio data");
return(NULL);
}
 
/* Don't return a buffer that isn't a multiple of samplesize */
*audio_len &= ~((samplesize / 8) - 1);
 
done:
if ( freesrc && src ) {
SDL_RWclose(src);
}
if ( was_error ) {
spec = NULL;
}
return(spec);
}
 
/contrib/sdk/sources/SDL_mixer-1.2.12/load_aiff.h
0,0 → 1,31
/*
SDL_mixer: An audio mixer library based on the SDL library
Copyright (C) 1997-2009 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
 
This is the source needed to decode an AIFF file into a waveform.
It's pretty straightforward once you get going. The only
externally-callable function is Mix_LoadAIFF_RW(), which is meant to
act as identically to SDL_LoadWAV_RW() as possible.
 
This file by Torbjörn Andersson (torbjorn.andersson@eurotime.se)
*/
 
/* $Id$ */
 
/* Don't call this directly; use Mix_LoadWAV_RW() for now. */
SDL_AudioSpec *Mix_LoadAIFF_RW (SDL_RWops *src, int freesrc,
SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len);
/contrib/sdk/sources/SDL_mixer-1.2.12/load_ogg.c
0,0 → 1,163
/*
SDL_mixer: An audio mixer library based on the SDL library
Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
 
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
 
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
 
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
 
This is the source needed to decode an Ogg Vorbis into a waveform.
This file by Vaclav Slavik (vaclav.slavik@matfyz.cz).
*/
 
/* $Id$ */
 
#ifdef OGG_MUSIC
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#include "SDL_mutex.h"
#include "SDL_endian.h"
#include "SDL_timer.h"
 
#include "SDL_mixer.h"
#include "dynamic_ogg.h"
#include "load_ogg.h"
 
static size_t sdl_read_func(void *ptr, size_t size, size_t nmemb, void *datasource)
{
return SDL_RWread((SDL_RWops*)datasource, ptr, size, nmemb);
}
 
static int sdl_seek_func(void *datasource, ogg_int64_t offset, int whence)
{
return SDL_RWseek((SDL_RWops*)datasource, (int)offset, whence);
}
 
static int sdl_close_func_freesrc(void *datasource)
{
return SDL_RWclose((SDL_RWops*)datasource);
}
 
static int sdl_close_func_nofreesrc(void *datasource)
{
return SDL_RWseek((SDL_RWops*)datasource, 0, RW_SEEK_SET);
}
 
static long sdl_tell_func(void *datasource)
{
return SDL_RWtell((SDL_RWops*)datasource);
}
 
 
/* don't call this directly; use Mix_LoadWAV_RW() for now. */
SDL_AudioSpec *Mix_LoadOGG_RW (SDL_RWops *src, int freesrc,
SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len)
{
OggVorbis_File vf;
ov_callbacks callbacks;
vorbis_info *info;
Uint8 *buf;
int bitstream = -1;
long samplesize;
long samples;
int read, to_read;
int must_close = 1;
int was_error = 1;
if ( (!src) || (!audio_buf) || (!audio_len) ) /* sanity checks. */
goto done;
 
if ( !Mix_Init(MIX_INIT_OGG) )
goto done;
 
callbacks.read_func = sdl_read_func;
callbacks.seek_func = sdl_seek_func;
callbacks.tell_func = sdl_tell_func;
callbacks.close_func = freesrc ?
sdl_close_func_freesrc : sdl_close_func_nofreesrc;
 
if (vorbis.ov_open_callbacks(src, &vf, NULL, 0, callbacks) != 0)
{
SDL_SetError("OGG bitstream is not valid Vorbis stream!");
goto done;
}
 
must_close = 0;
info = vorbis.ov_info(&vf, -1);
*audio_buf = NULL;
*audio_len = 0;
memset(spec, '\0', sizeof (SDL_AudioSpec));
 
spec->format = AUDIO_S16;
spec->channels = info->channels;
spec->freq = info->rate;
spec->samples = 4096; /* buffer size */
samples = (long)vorbis.ov_pcm_total(&vf, -1);
 
*audio_len = spec->size = samples * spec->channels * 2;
*audio_buf = SDL_malloc(*audio_len);
if (*audio_buf == NULL)
goto done;
 
buf = *audio_buf;
to_read = *audio_len;
#ifdef OGG_USE_TREMOR
for (read = vorbis.ov_read(&vf, (char *)buf, to_read, &bitstream);
read > 0;
read = vorbis.ov_read(&vf, (char *)buf, to_read, &bitstream))
#else
for (read = vorbis.ov_read(&vf, (char *)buf, to_read, 0/*LE*/, 2/*16bit*/, 1/*signed*/, &bitstream);
read > 0;
read = vorbis.ov_read(&vf, (char *)buf, to_read, 0, 2, 1, &bitstream))
#endif
{
if (read == OV_HOLE || read == OV_EBADLINK)
break; /* error */
to_read -= read;
buf += read;
}
 
vorbis.ov_clear(&vf);
was_error = 0;
 
/* Don't return a buffer that isn't a multiple of samplesize */
samplesize = ((spec->format & 0xFF)/8)*spec->channels;
*audio_len &= ~(samplesize-1);
 
done:
if (src && must_close)
{
if (freesrc)
SDL_RWclose(src);
else
SDL_RWseek(src, 0, RW_SEEK_SET);
}
 
if ( was_error )
spec = NULL;
 
return(spec);
} /* Mix_LoadOGG_RW */
 
/* end of load_ogg.c ... */
 
#endif
/contrib/sdk/sources/SDL_mixer-1.2.12/load_ogg.h
0,0 → 1,31
/*
SDL_mixer: An audio mixer library based on the SDL library
Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
 
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
 
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
 
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
 
This is the source needed to decode an Ogg Vorbis into a waveform.
This file by Vaclav Slavik (vaclav.slavik@matfyz.cz).
*/
 
/* $Id$ */
 
#ifdef OGG_MUSIC
/* Don't call this directly; use Mix_LoadWAV_RW() for now. */
SDL_AudioSpec *Mix_LoadOGG_RW (SDL_RWops *src, int freesrc,
SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len);
#endif
/contrib/sdk/sources/SDL_mixer-1.2.12/load_voc.c
0,0 → 1,462
/*
SDL_mixer: An audio mixer library based on the SDL library
Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
 
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
 
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
 
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
 
This is the source needed to decode a Creative Labs VOC file into a
waveform. It's pretty straightforward once you get going. The only
externally-callable function is Mix_LoadVOC_RW(), which is meant to
act as identically to SDL_LoadWAV_RW() as possible.
 
This file by Ryan C. Gordon (icculus@icculus.org).
 
Heavily borrowed from sox v12.17.1's voc.c.
(http://www.freshmeat.net/projects/sox/)
*/
 
/* $Id$ */
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#include "SDL_mutex.h"
#include "SDL_endian.h"
#include "SDL_timer.h"
 
#include "SDL_mixer.h"
#include "load_voc.h"
 
/* Private data for VOC file */
typedef struct vocstuff {
Uint32 rest; /* bytes remaining in current block */
Uint32 rate; /* rate code (byte) of this chunk */
int silent; /* sound or silence? */
Uint32 srate; /* rate code (byte) of silence */
Uint32 blockseek; /* start of current output block */
Uint32 samples; /* number of samples output */
Uint32 size; /* word length of data */
Uint8 channels; /* number of sound channels */
int has_extended; /* Has an extended block been read? */
} vs_t;
 
/* Size field */
/* SJB: note that the 1st 3 are sometimes used as sizeof(type) */
#define ST_SIZE_BYTE 1
#define ST_SIZE_8BIT 1
#define ST_SIZE_WORD 2
#define ST_SIZE_16BIT 2
#define ST_SIZE_DWORD 4
#define ST_SIZE_32BIT 4
#define ST_SIZE_FLOAT 5
#define ST_SIZE_DOUBLE 6
#define ST_SIZE_IEEE 7 /* IEEE 80-bit floats. */
 
/* Style field */
#define ST_ENCODING_UNSIGNED 1 /* unsigned linear: Sound Blaster */
#define ST_ENCODING_SIGN2 2 /* signed linear 2's comp: Mac */
#define ST_ENCODING_ULAW 3 /* U-law signed logs: US telephony, SPARC */
#define ST_ENCODING_ALAW 4 /* A-law signed logs: non-US telephony */
#define ST_ENCODING_ADPCM 5 /* Compressed PCM */
#define ST_ENCODING_IMA_ADPCM 6 /* Compressed PCM */
#define ST_ENCODING_GSM 7 /* GSM 6.10 33-byte frame lossy compression */
 
#define VOC_TERM 0
#define VOC_DATA 1
#define VOC_CONT 2
#define VOC_SILENCE 3
#define VOC_MARKER 4
#define VOC_TEXT 5
#define VOC_LOOP 6
#define VOC_LOOPEND 7
#define VOC_EXTENDED 8
#define VOC_DATA_16 9
 
 
static int voc_check_header(SDL_RWops *src)
{
/* VOC magic header */
Uint8 signature[20]; /* "Creative Voice File\032" */
Uint16 datablockofs;
 
SDL_RWseek(src, 0, RW_SEEK_SET);
 
if (SDL_RWread(src, signature, sizeof (signature), 1) != 1)
return(0);
 
if (memcmp(signature, "Creative Voice File\032", sizeof (signature)) != 0) {
SDL_SetError("Unrecognized file type (not VOC)");
return(0);
}
 
/* get the offset where the first datablock is located */
if (SDL_RWread(src, &datablockofs, sizeof (Uint16), 1) != 1)
return(0);
 
datablockofs = SDL_SwapLE16(datablockofs);
 
if (SDL_RWseek(src, datablockofs, RW_SEEK_SET) != datablockofs)
return(0);
 
return(1); /* success! */
} /* voc_check_header */
 
 
/* Read next block header, save info, leave position at start of data */
static int voc_get_block(SDL_RWops *src, vs_t *v, SDL_AudioSpec *spec)
{
Uint8 bits24[3];
Uint8 uc, block;
Uint32 sblen;
Uint16 new_rate_short;
Uint32 new_rate_long;
Uint8 trash[6];
Uint16 period;
unsigned int i;
 
v->silent = 0;
while (v->rest == 0)
{
if (SDL_RWread(src, &block, sizeof (block), 1) != 1)
return 1; /* assume that's the end of the file. */
 
if (block == VOC_TERM)
return 1;
 
if (SDL_RWread(src, bits24, sizeof (bits24), 1) != 1)
return 1; /* assume that's the end of the file. */
/* Size is an 24-bit value. Ugh. */
sblen = ( (bits24[0]) | (bits24[1] << 8) | (bits24[2] << 16) );
 
switch(block)
{
case VOC_DATA:
if (SDL_RWread(src, &uc, sizeof (uc), 1) != 1)
return 0;
 
/* When DATA block preceeded by an EXTENDED */
/* block, the DATA blocks rate value is invalid */
if (!v->has_extended)
{
if (uc == 0)
{
SDL_SetError("VOC Sample rate is zero?");
return 0;
}
 
if ((v->rate != -1) && (uc != v->rate))
{
SDL_SetError("VOC sample rate codes differ");
return 0;
}
 
v->rate = uc;
spec->freq = (Uint16)(1000000.0/(256 - v->rate));
v->channels = 1;
}
 
if (SDL_RWread(src, &uc, sizeof (uc), 1) != 1)
return 0;
 
if (uc != 0)
{
SDL_SetError("VOC decoder only interprets 8-bit data");
return 0;
}
 
v->has_extended = 0;
v->rest = sblen - 2;
v->size = ST_SIZE_BYTE;
return 1;
 
case VOC_DATA_16:
if (SDL_RWread(src, &new_rate_long, sizeof (new_rate_long), 1) != 1)
return 0;
new_rate_long = SDL_SwapLE32(new_rate_long);
if (new_rate_long == 0)
{
SDL_SetError("VOC Sample rate is zero?");
return 0;
}
if ((v->rate != -1) && (new_rate_long != v->rate))
{
SDL_SetError("VOC sample rate codes differ");
return 0;
}
v->rate = new_rate_long;
spec->freq = new_rate_long;
 
if (SDL_RWread(src, &uc, sizeof (uc), 1) != 1)
return 0;
 
switch (uc)
{
case 8: v->size = ST_SIZE_BYTE; break;
case 16: v->size = ST_SIZE_WORD; break;
default:
SDL_SetError("VOC with unknown data size");
return 0;
}
 
if (SDL_RWread(src, &v->channels, sizeof (Uint8), 1) != 1)
return 0;
 
if (SDL_RWread(src, trash, sizeof (Uint8), 6) != 6)
return 0;
 
v->rest = sblen - 12;
return 1;
 
case VOC_CONT:
v->rest = sblen;
return 1;
 
case VOC_SILENCE:
if (SDL_RWread(src, &period, sizeof (period), 1) != 1)
return 0;
period = SDL_SwapLE16(period);
 
if (SDL_RWread(src, &uc, sizeof (uc), 1) != 1)
return 0;
if (uc == 0)
{
SDL_SetError("VOC silence sample rate is zero");
return 0;
}
 
/*
* Some silence-packed files have gratuitously
* different sample rate codes in silence.
* Adjust period.
*/
if ((v->rate != -1) && (uc != v->rate))
period = (Uint16)((period * (256 - uc))/(256 - v->rate));
else
v->rate = uc;
v->rest = period;
v->silent = 1;
return 1;
 
case VOC_LOOP:
case VOC_LOOPEND:
for(i = 0; i < sblen; i++) /* skip repeat loops. */
{
if (SDL_RWread(src, trash, sizeof (Uint8), 1) != 1)
return 0;
}
break;
 
case VOC_EXTENDED:
/* An Extended block is followed by a data block */
/* Set this byte so we know to use the rate */
/* value from the extended block and not the */
/* data block. */
v->has_extended = 1;
if (SDL_RWread(src, &new_rate_short, sizeof (new_rate_short), 1) != 1)
return 0;
new_rate_short = SDL_SwapLE16(new_rate_short);
if (new_rate_short == 0)
{
SDL_SetError("VOC sample rate is zero");
return 0;
}
if ((v->rate != -1) && (new_rate_short != v->rate))
{
SDL_SetError("VOC sample rate codes differ");
return 0;
}
v->rate = new_rate_short;
 
if (SDL_RWread(src, &uc, sizeof (uc), 1) != 1)
return 0;
 
if (uc != 0)
{
SDL_SetError("VOC decoder only interprets 8-bit data");
return 0;
}
 
if (SDL_RWread(src, &uc, sizeof (uc), 1) != 1)
return 0;
 
if (uc)
spec->channels = 2; /* Stereo */
/* Needed number of channels before finishing
compute for rate */
spec->freq = (256000000L/(65536L - v->rate))/spec->channels;
/* An extended block must be followed by a data */
/* block to be valid so loop back to top so it */
/* can be grabed. */
continue;
 
case VOC_MARKER:
if (SDL_RWread(src, trash, sizeof (Uint8), 2) != 2)
return 0;
 
/* Falling! Falling! */
 
default: /* text block or other krapola. */
for(i = 0; i < sblen; i++)
{
if (SDL_RWread(src, &trash, sizeof (Uint8), 1) != 1)
return 0;
}
 
if (block == VOC_TEXT)
continue; /* get next block */
}
}
 
return 1;
}
 
 
static int voc_read(SDL_RWops *src, vs_t *v, Uint8 *buf, SDL_AudioSpec *spec)
{
int done = 0;
Uint8 silence = 0x80;
 
if (v->rest == 0)
{
if (!voc_get_block(src, v, spec))
return 0;
}
 
if (v->rest == 0)
return 0;
 
if (v->silent)
{
if (v->size == ST_SIZE_WORD)
silence = 0x00;
 
/* Fill in silence */
memset(buf, silence, v->rest);
done = v->rest;
v->rest = 0;
}
 
else
{
done = SDL_RWread(src, buf, 1, v->rest);
v->rest -= done;
if (v->size == ST_SIZE_WORD)
{
#if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
Uint16 *samples = (Uint16 *)buf;
for (; v->rest > 0; v->rest -= 2)
{
*samples = SDL_SwapLE16(*samples);
samples++;
}
#endif
done >>= 1;
}
}
 
return done;
} /* voc_read */
 
 
/* don't call this directly; use Mix_LoadWAV_RW() for now. */
SDL_AudioSpec *Mix_LoadVOC_RW (SDL_RWops *src, int freesrc,
SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len)
{
vs_t v;
int was_error = 1;
int samplesize;
Uint8 *fillptr;
void *ptr;
 
if ( (!src) || (!audio_buf) || (!audio_len) ) /* sanity checks. */
goto done;
 
if ( !voc_check_header(src) )
goto done;
 
v.rate = -1;
v.rest = 0;
v.has_extended = 0;
*audio_buf = NULL;
*audio_len = 0;
memset(spec, '\0', sizeof (SDL_AudioSpec));
 
if (!voc_get_block(src, &v, spec))
goto done;
 
if (v.rate == -1)
{
SDL_SetError("VOC data had no sound!");
goto done;
}
 
spec->format = ((v.size == ST_SIZE_WORD) ? AUDIO_S16 : AUDIO_U8);
if (spec->channels == 0)
spec->channels = v.channels;
 
*audio_len = v.rest;
*audio_buf = SDL_malloc(v.rest);
if (*audio_buf == NULL)
goto done;
 
fillptr = *audio_buf;
 
while (voc_read(src, &v, fillptr, spec) > 0)
{
if (!voc_get_block(src, &v, spec))
goto done;
 
*audio_len += v.rest;
ptr = SDL_realloc(*audio_buf, *audio_len);
if (ptr == NULL)
{
SDL_free(*audio_buf);
*audio_buf = NULL;
*audio_len = 0;
goto done;
}
 
*audio_buf = ptr;
fillptr = ((Uint8 *) ptr) + (*audio_len - v.rest);
}
 
spec->samples = (Uint16)(*audio_len / v.size);
 
was_error = 0; /* success, baby! */
 
/* Don't return a buffer that isn't a multiple of samplesize */
samplesize = ((spec->format & 0xFF)/8)*spec->channels;
*audio_len &= ~(samplesize-1);
 
done:
if (src)
{
if (freesrc)
SDL_RWclose(src);
else
SDL_RWseek(src, 0, RW_SEEK_SET);
}
 
if ( was_error )
spec = NULL;
 
return(spec);
} /* Mix_LoadVOC_RW */
 
/* end of load_voc.c ... */
/contrib/sdk/sources/SDL_mixer-1.2.12/load_voc.h
0,0 → 1,36
/*
SDL_mixer: An audio mixer library based on the SDL library
Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
 
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
 
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
 
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
 
This is the source needed to decode a Creative Labs VOC file into a
waveform. It's pretty straightforward once you get going. The only
externally-callable function is Mix_LoadVOC_RW(), which is meant to
act as identically to SDL_LoadWAV_RW() as possible.
 
This file by Ryan C. Gordon (icculus@icculus.org).
 
Heavily borrowed from sox v12.17.1's voc.c.
(http://www.freshmeat.net/projects/sox/)
*/
 
/* $Id$ */
 
/* Don't call this directly; use Mix_LoadWAV_RW() for now. */
SDL_AudioSpec *Mix_LoadVOC_RW (SDL_RWops *src, int freesrc,
SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len);
/contrib/sdk/sources/SDL_mixer-1.2.12/mixer.c
0,0 → 1,1488
/*
SDL_mixer: An audio mixer library based on the SDL library
Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
 
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
 
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
 
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
 
/* $Id$ */
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#include "SDL_mutex.h"
#include "SDL_endian.h"
#include "SDL_timer.h"
 
#include "SDL_mixer.h"
//#include "load_aiff.h"
//#include "load_voc.h"
#include "load_ogg.h"
//#include "load_flac.h"
//#include "dynamic_flac.h"
//#include "dynamic_mod.h"
//#include "dynamic_mp3.h"
//#include "dynamic_ogg.h"
 
#define __MIX_INTERNAL_EFFECT__
#include "effects_internal.h"
 
/* Magic numbers for various audio file formats */
#define RIFF 0x46464952 /* "RIFF" */
#define WAVE 0x45564157 /* "WAVE" */
#define FORM 0x4d524f46 /* "FORM" */
#define OGGS 0x5367674f /* "OggS" */
#define CREA 0x61657243 /* "Crea" */
#define FLAC 0x43614C66 /* "fLaC" */
 
static int audio_opened = 0;
static SDL_AudioSpec mixer;
 
typedef struct _Mix_effectinfo
{
Mix_EffectFunc_t callback;
Mix_EffectDone_t done_callback;
void *udata;
struct _Mix_effectinfo *next;
} effect_info;
 
static struct _Mix_Channel {
Mix_Chunk *chunk;
int playing;
int paused;
Uint8 *samples;
int volume;
int looping;
int tag;
Uint32 expire;
Uint32 start_time;
Mix_Fading fading;
int fade_volume;
int fade_volume_reset;
Uint32 fade_length;
Uint32 ticks_fade;
effect_info *effects;
} *mix_channel = NULL;
 
static effect_info *posteffects = NULL;
 
static int num_channels;
static int reserved_channels = 0;
 
 
/* Support for hooking into the mixer callback system */
static void (*mix_postmix)(void *udata, Uint8 *stream, int len) = NULL;
static void *mix_postmix_data = NULL;
 
/* rcg07062001 callback to alert when channels are done playing. */
static void (*channel_done_callback)(int channel) = NULL;
 
/* Music function declarations */
extern int open_music(SDL_AudioSpec *mixer);
extern void close_music(void);
 
/* Support for user defined music functions, plus the default one */
extern int volatile music_active;
extern void music_mixer(void *udata, Uint8 *stream, int len);
static void (*mix_music)(void *udata, Uint8 *stream, int len) = music_mixer;
static void *music_data = NULL;
 
/* rcg06042009 report available decoders at runtime. */
static const char **chunk_decoders = NULL;
static int num_decoders = 0;
 
/* Semicolon-separated SoundFont paths */
#ifdef MID_MUSIC
extern char* soundfont_paths;
#endif
 
int Mix_GetNumChunkDecoders(void)
{
return(num_decoders);
}
 
const char *Mix_GetChunkDecoder(int index)
{
if ((index < 0) || (index >= num_decoders)) {
return NULL;
}
return(chunk_decoders[index]);
}
 
static void add_chunk_decoder(const char *decoder)
{
void *ptr = SDL_realloc(chunk_decoders, (num_decoders + 1) * sizeof (const char **));
if (ptr == NULL) {
return; /* oh well, go on without it. */
}
chunk_decoders = (const char **) ptr;
chunk_decoders[num_decoders++] = decoder;
}
 
/* rcg06192001 get linked library's version. */
const SDL_version *Mix_Linked_Version(void)
{
static SDL_version linked_version;
SDL_MIXER_VERSION(&linked_version);
return(&linked_version);
}
 
static int initialized = 0;
 
int Mix_Init(int flags)
{
int result = 0;
 
if (flags & MIX_INIT_FLUIDSYNTH) {
#ifdef USE_FLUIDSYNTH_MIDI
if ((initialized & MIX_INIT_FLUIDSYNTH) || Mix_InitFluidSynth() == 0) {
result |= MIX_INIT_FLUIDSYNTH;
}
#else
Mix_SetError("Mixer not built with FluidSynth support");
#endif
}
if (flags & MIX_INIT_FLAC) {
#ifdef FLAC_MUSIC
if ((initialized & MIX_INIT_FLAC) || Mix_InitFLAC() == 0) {
result |= MIX_INIT_FLAC;
}
#else
Mix_SetError("Mixer not built with FLAC support");
#endif
}
if (flags & MIX_INIT_MOD) {
#ifdef MOD_MUSIC
if ((initialized & MIX_INIT_MOD) || Mix_InitMOD() == 0) {
result |= MIX_INIT_MOD;
}
#else
Mix_SetError("Mixer not built with MOD support");
#endif
}
if (flags & MIX_INIT_MP3) {
#ifdef MP3_MUSIC
if ((initialized & MIX_INIT_MP3) || Mix_InitMP3() == 0) {
result |= MIX_INIT_MP3;
}
#else
Mix_SetError("Mixer not built with MP3 support");
#endif
}
if (flags & MIX_INIT_OGG) {
#ifdef OGG_MUSIC
if ((initialized & MIX_INIT_OGG) || Mix_InitOgg() == 0) {
result |= MIX_INIT_OGG;
}
#else
Mix_SetError("Mixer not built with Ogg Vorbis support");
#endif
}
initialized |= result;
 
return (result);
}
 
void Mix_Quit()
{
#ifdef USE_FLUIDSYNTH_MIDI
if (initialized & MIX_INIT_FLUIDSYNTH) {
Mix_QuitFluidSynth();
}
#endif
#ifdef FLAC_MUSIC
if (initialized & MIX_INIT_FLAC) {
Mix_QuitFLAC();
}
#endif
#ifdef MOD_MUSIC
if (initialized & MIX_INIT_MOD) {
Mix_QuitMOD();
}
#endif
#ifdef MP3_MUSIC
if (initialized & MIX_INIT_MP3) {
Mix_QuitMP3();
}
#endif
#ifdef OGG_MUSIC
if (initialized & MIX_INIT_OGG) {
Mix_QuitOgg();
}
#endif
#ifdef MID_MUSIC
if (soundfont_paths) {
SDL_free(soundfont_paths);
}
#endif
initialized = 0;
}
 
static int _Mix_remove_all_effects(int channel, effect_info **e);
 
/*
* rcg06122001 Cleanup effect callbacks.
* MAKE SURE SDL_LockAudio() is called before this (or you're in the
* audio callback).
*/
static void _Mix_channel_done_playing(int channel)
{
if (channel_done_callback) {
channel_done_callback(channel);
}
 
/*
* Call internal function directly, to avoid locking audio from
* inside audio callback.
*/
_Mix_remove_all_effects(channel, &mix_channel[channel].effects);
}
 
 
static void *Mix_DoEffects(int chan, void *snd, int len)
{
int posteffect = (chan == MIX_CHANNEL_POST);
effect_info *e = ((posteffect) ? posteffects : mix_channel[chan].effects);
void *buf = snd;
 
if (e != NULL) { /* are there any registered effects? */
/* if this is the postmix, we can just overwrite the original. */
if (!posteffect) {
buf = SDL_malloc(len);
if (buf == NULL) {
return(snd);
}
memcpy(buf, snd, len);
}
 
for (; e != NULL; e = e->next) {
if (e->callback != NULL) {
e->callback(chan, buf, len, e->udata);
}
}
}
 
/* be sure to SDL_free() the return value if != snd ... */
return(buf);
}
 
 
/* Mixing function */
static void mix_channels(void *udata, Uint8 *stream, int len)
{
Uint8 *mix_input;
int i, mixable, volume = SDL_MIX_MAXVOLUME;
Uint32 sdl_ticks;
 
#if SDL_VERSION_ATLEAST(1, 3, 0)
/* Need to initialize the stream in SDL 1.3+ */
memset(stream, mixer.silence, len);
#endif
 
/* Mix the music (must be done before the channels are added) */
if ( music_active || (mix_music != music_mixer) ) {
mix_music(music_data, stream, len);
}
 
/* Mix any playing channels... */
sdl_ticks = SDL_GetTicks();
for ( i=0; i<num_channels; ++i ) {
if( ! mix_channel[i].paused ) {
if ( mix_channel[i].expire > 0 && mix_channel[i].expire < sdl_ticks ) {
/* Expiration delay for that channel is reached */
mix_channel[i].playing = 0;
mix_channel[i].looping = 0;
mix_channel[i].fading = MIX_NO_FADING;
mix_channel[i].expire = 0;
_Mix_channel_done_playing(i);
} 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 ) {
Mix_Volume(i, mix_channel[i].fade_volume_reset); /* Restore the volume */
if( mix_channel[i].fading == MIX_FADING_OUT ) {
mix_channel[i].playing = 0;
mix_channel[i].looping = 0;
mix_channel[i].expire = 0;
_Mix_channel_done_playing(i);
}
mix_channel[i].fading = MIX_NO_FADING;
} else {
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 );
} else {
Mix_Volume(i, (mix_channel[i].fade_volume * ticks) / mix_channel[i].fade_length );
}
}
}
if ( mix_channel[i].playing > 0 ) {
int index = 0;
int remaining = len;
while (mix_channel[i].playing > 0 && index < len) {
remaining = len - index;
volume = (mix_channel[i].volume*mix_channel[i].chunk->volume) / MIX_MAX_VOLUME;
mixable = mix_channel[i].playing;
if ( mixable > remaining ) {
mixable = remaining;
}
 
mix_input = Mix_DoEffects(i, mix_channel[i].samples, mixable);
SDL_MixAudio(stream+index,mix_input,mixable,volume);
if (mix_input != mix_channel[i].samples)
SDL_free(mix_input);
 
mix_channel[i].samples += mixable;
mix_channel[i].playing -= mixable;
index += mixable;
 
/* rcg06072001 Alert app if channel is done playing. */
if (!mix_channel[i].playing && !mix_channel[i].looping) {
_Mix_channel_done_playing(i);
}
}
 
/* If looping the sample and we are at its end, make sure
we will still return a full buffer */
while ( mix_channel[i].looping && index < len ) {
int alen = mix_channel[i].chunk->alen;
remaining = len - index;
if (remaining > alen) {
remaining = alen;
}
 
mix_input = Mix_DoEffects(i, mix_channel[i].chunk->abuf, remaining);
SDL_MixAudio(stream+index, mix_input, remaining, volume);
if (mix_input != mix_channel[i].chunk->abuf)
SDL_free(mix_input);
 
--mix_channel[i].looping;
mix_channel[i].samples = mix_channel[i].chunk->abuf + remaining;
mix_channel[i].playing = mix_channel[i].chunk->alen - remaining;
index += remaining;
}
if ( ! mix_channel[i].playing && mix_channel[i].looping ) {
--mix_channel[i].looping;
mix_channel[i].samples = mix_channel[i].chunk->abuf;
mix_channel[i].playing = mix_channel[i].chunk->alen;
}
}
}
}
 
/* rcg06122001 run posteffects... */
Mix_DoEffects(MIX_CHANNEL_POST, stream, len);
 
if ( mix_postmix ) {
mix_postmix(mix_postmix_data, stream, len);
}
}
 
#if 0
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 > 2) ? "surround" :
(fmt->channels > 1) ? "stereo" : "mono", fmt->freq);
}
#endif
 
 
/* Open the mixer with a certain desired audio format */
int Mix_OpenAudio(int frequency, Uint16 format, int nchannels, int chunksize)
{
int i;
SDL_AudioSpec desired;
 
/* If the mixer is already opened, increment open count */
if ( audio_opened ) {
if ( format == mixer.format && nchannels == mixer.channels ) {
++audio_opened;
return(0);
}
while ( audio_opened ) {
Mix_CloseAudio();
}
}
 
/* Set the desired format and frequency */
desired.freq = frequency;
desired.format = format;
desired.channels = nchannels;
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
 
/* Initialize the music players */
if ( open_music(&mixer) < 0 ) {
SDL_CloseAudio();
return(-1);
}
 
num_channels = MIX_CHANNELS;
mix_channel = (struct _Mix_Channel *) SDL_malloc(num_channels * sizeof(struct _Mix_Channel));
 
/* Clear out the audio channels */
for ( i=0; i<num_channels; ++i ) {
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].fade_volume = SDL_MIX_MAXVOLUME;
mix_channel[i].fade_volume_reset = SDL_MIX_MAXVOLUME;
mix_channel[i].fading = MIX_NO_FADING;
mix_channel[i].tag = -1;
mix_channel[i].expire = 0;
mix_channel[i].effects = NULL;
mix_channel[i].paused = 0;
}
Mix_VolumeMusic(SDL_MIX_MAXVOLUME);
 
_Mix_InitEffects();
 
/* This list is (currently) decided at build time. */
add_chunk_decoder("WAVE");
add_chunk_decoder("AIFF");
add_chunk_decoder("VOC");
#ifdef OGG_MUSIC
add_chunk_decoder("OGG");
#endif
#ifdef FLAC_MUSIC
add_chunk_decoder("FLAC");
#endif
 
audio_opened = 1;
SDL_PauseAudio(0);
return(0);
}
 
/* 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_UnregisterAllEffects(i);
Mix_HaltChannel(i);
}
}
SDL_LockAudio();
mix_channel = (struct _Mix_Channel *) SDL_realloc(mix_channel, numchans * sizeof(struct _Mix_Channel));
if ( numchans > num_channels ) {
/* Initialize the new channels */
int i;
for(i=num_channels; i < numchans; i++) {
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].fade_volume = SDL_MIX_MAXVOLUME;
mix_channel[i].fade_volume_reset = SDL_MIX_MAXVOLUME;
mix_channel[i].fading = MIX_NO_FADING;
mix_channel[i].tag = -1;
mix_channel[i].expire = 0;
mix_channel[i].effects = NULL;
mix_channel[i].paused = 0;
}
}
num_channels = numchans;
SDL_UnlockAudio();
return(num_channels);
}
 
/* 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;
}
if ( channels ) {
*channels = mixer.channels;
}
}
return(audio_opened);
}
 
 
/*
* !!! FIXME: Ideally, we want a Mix_LoadSample_RW(), which will handle the
* generic setup, then call the correct file format loader.
*/
 
/* Load a wave file */
Mix_Chunk *Mix_LoadWAV_RW(SDL_RWops *src, int freesrc)
{
Uint32 magic;
Mix_Chunk *chunk;
SDL_AudioSpec wavespec, *loaded;
SDL_AudioCVT wavecvt;
int samplesize;
 
/* rcg06012001 Make sure src is valid */
if ( ! src ) {
SDL_SetError("Mix_LoadWAV_RW with NULL src");
return(NULL);
}
 
/* Make sure audio has been opened */
if ( ! audio_opened ) {
SDL_SetError("Audio device hasn't been opened");
if ( freesrc && src ) {
SDL_RWclose(src);
}
return(NULL);
}
 
/* Allocate the chunk memory */
chunk = (Mix_Chunk *)SDL_malloc(sizeof(Mix_Chunk));
if ( chunk == NULL ) {
SDL_SetError("Out of memory");
if ( freesrc ) {
SDL_RWclose(src);
}
return(NULL);
}
 
/* Find out what kind of audio file this is */
magic = SDL_ReadLE32(src);
/* Seek backwards for compatibility with older loaders */
SDL_RWseek(src, -(int)sizeof(Uint32), RW_SEEK_CUR);
 
switch (magic) {
case WAVE:
case RIFF:
loaded = SDL_LoadWAV_RW(src, freesrc, &wavespec,
(Uint8 **)&chunk->abuf, &chunk->alen);
break;
case FORM:
loaded = Mix_LoadAIFF_RW(src, freesrc, &wavespec,
(Uint8 **)&chunk->abuf, &chunk->alen);
break;
#ifdef OGG_MUSIC
case OGGS:
loaded = Mix_LoadOGG_RW(src, freesrc, &wavespec,
(Uint8 **)&chunk->abuf, &chunk->alen);
break;
#endif
#ifdef FLAC_MUSIC
case FLAC:
loaded = Mix_LoadFLAC_RW(src, freesrc, &wavespec,
(Uint8 **)&chunk->abuf, &chunk->alen);
break;
#endif
case CREA:
loaded = Mix_LoadVOC_RW(src, freesrc, &wavespec,
(Uint8 **)&chunk->abuf, &chunk->alen);
break;
default:
SDL_SetError("Unrecognized sound file type");
return(0);
}
if ( !loaded ) {
SDL_free(chunk);
if ( freesrc ) {
SDL_RWclose(src);
}
return(NULL);
}
 
#if 0
PrintFormat("Audio device", &mixer);
PrintFormat("-- Wave file", &wavespec);
#endif
 
/* Build the audio converter and create conversion buffers */
if ( wavespec.format != mixer.format ||
wavespec.channels != mixer.channels ||
wavespec.freq != mixer.freq ) {
if ( SDL_BuildAudioCVT(&wavecvt,
wavespec.format, wavespec.channels, wavespec.freq,
mixer.format, mixer.channels, mixer.freq) < 0 ) {
SDL_free(chunk->abuf);
SDL_free(chunk);
return(NULL);
}
samplesize = ((wavespec.format & 0xFF)/8)*wavespec.channels;
wavecvt.len = chunk->alen & ~(samplesize-1);
wavecvt.buf = (Uint8 *)SDL_calloc(1, wavecvt.len*wavecvt.len_mult);
if ( wavecvt.buf == NULL ) {
SDL_SetError("Out of memory");
SDL_free(chunk->abuf);
SDL_free(chunk);
return(NULL);
}
memcpy(wavecvt.buf, chunk->abuf, chunk->alen);
SDL_free(chunk->abuf);
 
/* Run the audio converter */
if ( SDL_ConvertAudio(&wavecvt) < 0 ) {
SDL_free(wavecvt.buf);
SDL_free(chunk);
return(NULL);
}
 
chunk->abuf = wavecvt.buf;
chunk->alen = wavecvt.len_cvt;
}
 
chunk->allocated = 1;
chunk->volume = MIX_MAX_VOLUME;
 
return(chunk);
}
 
/* 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 *)SDL_calloc(1,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);
}
 
/* Load raw audio data of the mixer format from a memory buffer */
Mix_Chunk *Mix_QuickLoad_RAW(Uint8 *mem, Uint32 len)
{
Mix_Chunk *chunk;
 
/* 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 *)SDL_malloc(sizeof(Mix_Chunk));
if ( chunk == NULL ) {
SDL_SetError("Out of memory");
return(NULL);
}
 
/* Essentially just point at the audio data (no error checking - fast) */
chunk->allocated = 0;
chunk->alen = len;
chunk->abuf = mem;
chunk->volume = MIX_MAX_VOLUME;
 
return(chunk);
}
 
/* 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 */
SDL_LockAudio();
if ( mix_channel ) {
for ( i=0; i<num_channels; ++i ) {
if ( chunk == mix_channel[i].chunk ) {
mix_channel[i].playing = 0;
mix_channel[i].looping = 0;
}
}
}
SDL_UnlockAudio();
/* Actually free the chunk */
if ( chunk->allocated ) {
SDL_free(chunk->abuf);
}
SDL_free(chunk);
}
}
 
/* 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();
}
 
/* 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);
}
 
void Mix_ChannelFinished(void (*channel_finished)(int channel))
{
SDL_LockAudio();
channel_done_callback = channel_finished;
SDL_UnlockAudio();
}
 
 
/* 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)
{
if (num > num_channels)
num = num_channels;
reserved_channels = num;
return num;
}
 
static int checkchunkintegral(Mix_Chunk *chunk)
{
int frame_width = 1;
 
if ((mixer.format & 0xFF) == 16) frame_width = 2;
frame_width *= mixer.channels;
while (chunk->alen % frame_width) chunk->alen--;
return chunk->alen;
}
 
/* Play an audio chunk on a specific channel.
If the specified channel is -1, play on the first free channel.
'ticks' is the number of milliseconds at most to play the sample, or -1
if there is no limit.
Returns which channel was used to play the sound.
*/
int Mix_PlayChannelTimed(int which, Mix_Chunk *chunk, int loops, int ticks)
{
int i;
 
/* Don't play null pointers :-) */
if ( chunk == NULL ) {
Mix_SetError("Tried to play a NULL chunk");
return(-1);
}
if ( !checkchunkintegral(chunk)) {
Mix_SetError("Tried to play a chunk with a bad frame");
return(-1);
}
 
/* Lock the mixer while modifying the playing channels */
SDL_LockAudio();
{
/* If which is -1, play on the first free channel */
if ( which == -1 ) {
for ( i=reserved_channels; i<num_channels; ++i ) {
if ( mix_channel[i].playing <= 0 )
break;
}
if ( i == num_channels ) {
Mix_SetError("No free channels available");
which = -1;
} else {
which = i;
}
}
 
/* Queue up the audio data for this channel */
if ( which >= 0 && which < num_channels ) {
Uint32 sdl_ticks = SDL_GetTicks();
if (Mix_Playing(which))
_Mix_channel_done_playing(which);
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;
}
}
SDL_UnlockAudio();
 
/* Return the channel on which the sound is being played */
return(which);
}
 
/* 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_LockAudio();
mix_channel[which].expire = (ticks>0) ? (SDL_GetTicks() + ticks) : 0;
SDL_UnlockAudio();
++ status;
}
return(status);
}
 
/* Fade in a sound on a channel, over ms milliseconds */
int Mix_FadeInChannelTimed(int which, Mix_Chunk *chunk, int loops, int ms, int ticks)
{
int i;
 
/* Don't play null pointers :-) */
if ( chunk == NULL ) {
return(-1);
}
if ( !checkchunkintegral(chunk)) {
Mix_SetError("Tried to play a chunk with a bad frame");
return(-1);
}
 
/* Lock the mixer while modifying the playing channels */
SDL_LockAudio();
{
/* If which is -1, play on the first free channel */
if ( which == -1 ) {
for ( i=reserved_channels; i<num_channels; ++i ) {
if ( mix_channel[i].playing <= 0 )
break;
}
if ( i == num_channels ) {
which = -1;
} else {
which = i;
}
}
 
/* Queue up the audio data for this channel */
if ( which >= 0 && which < num_channels ) {
Uint32 sdl_ticks = SDL_GetTicks();
if (Mix_Playing(which))
_Mix_channel_done_playing(which);
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].fade_volume_reset = 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;
}
}
SDL_UnlockAudio();
 
/* 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 = 0;
 
if ( which == -1 ) {
for ( i=0; i<num_channels; ++i ) {
prev_volume += Mix_Volume(i, volume);
}
prev_volume /= num_channels;
} else if ( which < num_channels ) {
prev_volume = mix_channel[which].volume;
if ( volume >= 0 ) {
if ( volume > SDL_MIX_MAXVOLUME ) {
volume = SDL_MIX_MAXVOLUME;
}
mix_channel[which].volume = volume;
}
}
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 ) {
for ( i=0; i<num_channels; ++i ) {
Mix_HaltChannel(i);
}
} else if ( which < num_channels ) {
SDL_LockAudio();
if (mix_channel[which].playing) {
_Mix_channel_done_playing(which);
mix_channel[which].playing = 0;
mix_channel[which].looping = 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_reset;
mix_channel[which].fading = MIX_NO_FADING;
SDL_UnlockAudio();
}
return(0);
}
 
/* Halt playing of a particular group of channels */
int Mix_HaltGroup(int tag)
{
int i;
 
for ( i=0; i<num_channels; ++i ) {
if( mix_channel[i].tag == tag ) {
Mix_HaltChannel(i);
}
}
return(0);
}
 
/* Fade out a channel and then stop it automatically */
int Mix_FadeOutChannel(int which, int ms)
{
int status;
 
status = 0;
if ( audio_opened ) {
if ( which == -1 ) {
int i;
 
for ( i=0; i<num_channels; ++i ) {
status += Mix_FadeOutChannel(i, ms);
}
} else if ( which < num_channels ) {
SDL_LockAudio();
if ( mix_channel[which].playing &&
(mix_channel[which].volume > 0) &&
(mix_channel[which].fading != MIX_FADING_OUT) ) {
mix_channel[which].fade_volume = mix_channel[which].volume;
mix_channel[which].fading = MIX_FADING_OUT;
mix_channel[which].fade_length = ms;
mix_channel[which].ticks_fade = SDL_GetTicks();
 
/* only change fade_volume_reset if we're not fading. */
if (mix_channel[which].fading == MIX_NO_FADING) {
mix_channel[which].fade_volume_reset = mix_channel[which].volume;
}
++status;
}
SDL_UnlockAudio();
}
}
return(status);
}
 
/* 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 ) {
if( mix_channel[i].tag == tag ) {
status += Mix_FadeOutChannel(i,ms);
}
}
return(status);
}
 
Mix_Fading Mix_FadingChannel(int which)
{
if ( which < 0 || which >= num_channels ) {
return MIX_NO_FADING;
}
return mix_channel[which].fading;
}
 
/* Check the status of a specific channel.
If the specified mix_channel is -1, check all mix channels.
*/
int Mix_Playing(int which)
{
int status;
 
status = 0;
if ( which == -1 ) {
int i;
 
for ( i=0; i<num_channels; ++i ) {
if ((mix_channel[i].playing > 0) ||
(mix_channel[i].looping > 0))
{
++status;
}
}
} else if ( which < num_channels ) {
if ( (mix_channel[which].playing > 0) ||
(mix_channel[which].looping > 0) )
{
++status;
}
}
return(status);
}
 
/* rcg06072001 Get the chunk associated with a channel. */
Mix_Chunk *Mix_GetChunk(int channel)
{
Mix_Chunk *retval = NULL;
 
if ((channel >= 0) && (channel < num_channels)) {
retval = mix_channel[channel].chunk;
}
 
return(retval);
}
 
/* Close the mixer, halting all playing audio */
void Mix_CloseAudio(void)
{
int i;
 
if ( audio_opened ) {
if ( audio_opened == 1 ) {
for (i = 0; i < num_channels; i++) {
Mix_UnregisterAllEffects(i);
}
Mix_UnregisterAllEffects(MIX_CHANNEL_POST);
close_music();
Mix_HaltChannel(-1);
_Mix_DeinitEffects();
SDL_CloseAudio();
SDL_free(mix_channel);
mix_channel = NULL;
 
/* rcg06042009 report available decoders at runtime. */
SDL_free(chunk_decoders);
chunk_decoders = NULL;
num_decoders = 0;
}
--audio_opened;
}
}
 
/* Pause a particular channel (or all) */
void Mix_Pause(int which)
{
Uint32 sdl_ticks = SDL_GetTicks();
if ( which == -1 ) {
int i;
 
for ( i=0; i<num_channels; ++i ) {
if ( mix_channel[i].playing > 0 ) {
mix_channel[i].paused = sdl_ticks;
}
}
} else if ( which < num_channels ) {
if ( mix_channel[which].playing > 0 ) {
mix_channel[which].paused = sdl_ticks;
}
}
}
 
/* Resume a paused channel */
void Mix_Resume(int which)
{
Uint32 sdl_ticks = SDL_GetTicks();
 
SDL_LockAudio();
if ( which == -1 ) {
int i;
 
for ( i=0; i<num_channels; ++i ) {
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;
}
}
} else if ( which < num_channels ) {
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;
}
}
SDL_UnlockAudio();
}
 
int Mix_Paused(int which)
{
if ( which < 0 ) {
int status = 0;
int i;
for( i=0; i < num_channels; ++i ) {
if ( mix_channel[i].paused ) {
++ status;
}
}
return(status);
} else if ( which < num_channels ) {
return(mix_channel[which].paused != 0);
} else {
return(0);
}
}
 
/* Change the group of a channel */
int Mix_GroupChannel(int which, int tag)
{
if ( which < 0 || which > num_channels )
return(0);
 
SDL_LockAudio();
mix_channel[which].tag = tag;
SDL_UnlockAudio();
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 ++ ) {
if ( ((tag == -1) || (tag == mix_channel[i].tag)) &&
(mix_channel[i].playing <= 0) )
return i;
}
return(-1);
}
 
int Mix_GroupCount(int tag)
{
int count = 0;
int i;
for( i=0; i < num_channels; i ++ ) {
if ( mix_channel[i].tag==tag || tag==-1 )
++ count;
}
return(count);
}
 
/* 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 ++ ) {
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;
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 ++ ) {
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;
chan = i;
}
}
return(chan);
}
 
 
 
/*
* rcg06122001 The special effects exportable API.
* Please see effect_*.c for internally-implemented effects, such
* as Mix_SetPanning().
*/
 
/* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
static int _Mix_register_effect(effect_info **e, Mix_EffectFunc_t f,
Mix_EffectDone_t d, void *arg)
{
effect_info *new_e;
 
if (!e) {
Mix_SetError("Internal error");
return(0);
}
 
if (f == NULL) {
Mix_SetError("NULL effect callback");
return(0);
}
 
new_e = SDL_malloc(sizeof (effect_info));
if (new_e == NULL) {
Mix_SetError("Out of memory");
return(0);
}
 
new_e->callback = f;
new_e->done_callback = d;
new_e->udata = arg;
new_e->next = NULL;
 
/* add new effect to end of linked list... */
if (*e == NULL) {
*e = new_e;
} else {
effect_info *cur = *e;
while (1) {
if (cur->next == NULL) {
cur->next = new_e;
break;
}
cur = cur->next;
}
}
 
return(1);
}
 
 
/* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
static int _Mix_remove_effect(int channel, effect_info **e, Mix_EffectFunc_t f)
{
effect_info *cur;
effect_info *prev = NULL;
effect_info *next = NULL;
 
if (!e) {
Mix_SetError("Internal error");
return(0);
}
 
for (cur = *e; cur != NULL; cur = cur->next) {
if (cur->callback == f) {
next = cur->next;
if (cur->done_callback != NULL) {
cur->done_callback(channel, cur->udata);
}
SDL_free(cur);
 
if (prev == NULL) { /* removing first item of list? */
*e = next;
} else {
prev->next = next;
}
return(1);
}
prev = cur;
}
 
Mix_SetError("No such effect registered");
return(0);
}
 
 
/* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
static int _Mix_remove_all_effects(int channel, effect_info **e)
{
effect_info *cur;
effect_info *next;
 
if (!e) {
Mix_SetError("Internal error");
return(0);
}
 
for (cur = *e; cur != NULL; cur = next) {
next = cur->next;
if (cur->done_callback != NULL) {
cur->done_callback(channel, cur->udata);
}
SDL_free(cur);
}
*e = NULL;
 
return(1);
}
 
 
/* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
int _Mix_RegisterEffect_locked(int channel, Mix_EffectFunc_t f,
Mix_EffectDone_t d, void *arg)
{
effect_info **e = NULL;
 
if (channel == MIX_CHANNEL_POST) {
e = &posteffects;
} else {
if ((channel < 0) || (channel >= num_channels)) {
Mix_SetError("Invalid channel number");
return(0);
}
e = &mix_channel[channel].effects;
}
 
return _Mix_register_effect(e, f, d, arg);
}
 
int Mix_RegisterEffect(int channel, Mix_EffectFunc_t f,
Mix_EffectDone_t d, void *arg)
{
int retval;
SDL_LockAudio();
retval = _Mix_RegisterEffect_locked(channel, f, d, arg);
SDL_UnlockAudio();
return retval;
}
 
 
/* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
int _Mix_UnregisterEffect_locked(int channel, Mix_EffectFunc_t f)
{
effect_info **e = NULL;
 
if (channel == MIX_CHANNEL_POST) {
e = &posteffects;
} else {
if ((channel < 0) || (channel >= num_channels)) {
Mix_SetError("Invalid channel number");
return(0);
}
e = &mix_channel[channel].effects;
}
 
return _Mix_remove_effect(channel, e, f);
}
 
int Mix_UnregisterEffect(int channel, Mix_EffectFunc_t f)
{
int retval;
SDL_LockAudio();
retval = _Mix_UnregisterEffect_locked(channel, f);
SDL_UnlockAudio();
return(retval);
}
 
/* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
int _Mix_UnregisterAllEffects_locked(int channel)
{
effect_info **e = NULL;
 
if (channel == MIX_CHANNEL_POST) {
e = &posteffects;
} else {
if ((channel < 0) || (channel >= num_channels)) {
Mix_SetError("Invalid channel number");
return(0);
}
e = &mix_channel[channel].effects;
}
 
return _Mix_remove_all_effects(channel, e);
}
 
int Mix_UnregisterAllEffects(int channel)
{
int retval;
SDL_LockAudio();
retval = _Mix_UnregisterAllEffects_locked(channel);
SDL_UnlockAudio();
return(retval);
}
 
/* end of mixer.c ... */
 
/contrib/sdk/sources/SDL_mixer-1.2.12/music.c
0,0 → 1,1597
/*
SDL_mixer: An audio mixer library based on the SDL library
Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
 
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
 
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
 
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
 
/* $Id$ */
 
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include "SDL_endian.h"
#include "SDL_audio.h"
#include "SDL_timer.h"
 
#include "SDL_mixer.h"
 
#ifdef CMD_MUSIC
#include "music_cmd.h"
#endif
#ifdef WAV_MUSIC
#include "wavestream.h"
#endif
#ifdef MODPLUG_MUSIC
#include "music_modplug.h"
#endif
#ifdef MOD_MUSIC
#include "music_mod.h"
#endif
#ifdef MID_MUSIC
# ifdef USE_TIMIDITY_MIDI
# include "timidity.h"
# endif
# ifdef USE_FLUIDSYNTH_MIDI
# include "fluidsynth.h"
# endif
# ifdef USE_NATIVE_MIDI
# include "native_midi.h"
# endif
#endif
#ifdef OGG_MUSIC
#include "music_ogg.h"
#endif
#ifdef MP3_MUSIC
#include "dynamic_mp3.h"
#endif
#ifdef MP3_MAD_MUSIC
#include "music_mad.h"
#endif
#ifdef FLAC_MUSIC
#include "music_flac.h"
#endif
 
#if defined(MP3_MUSIC) || defined(MP3_MAD_MUSIC)
static SDL_AudioSpec used_mixer;
#endif
 
 
int volatile music_active = 1;
static int volatile music_stopped = 0;
static int music_loops = 0;
static char *music_cmd = NULL;
static Mix_Music * volatile music_playing = NULL;
static int music_volume = MIX_MAX_VOLUME;
 
struct _Mix_Music {
Mix_MusicType type;
union {
#ifdef CMD_MUSIC
MusicCMD *cmd;
#endif
#ifdef WAV_MUSIC
WAVStream *wave;
#endif
#ifdef MODPLUG_MUSIC
modplug_data *modplug;
#endif
#ifdef MOD_MUSIC
struct MODULE *module;
#endif
#ifdef MID_MUSIC
#ifdef USE_TIMIDITY_MIDI
MidiSong *midi;
#endif
#ifdef USE_FLUIDSYNTH_MIDI
FluidSynthMidiSong *fluidsynthmidi;
#endif
#ifdef USE_NATIVE_MIDI
NativeMidiSong *nativemidi;
#endif
#endif
#ifdef OGG_MUSIC
OGG_music *ogg;
#endif
#ifdef MP3_MUSIC
SMPEG *mp3;
#endif
#ifdef MP3_MAD_MUSIC
mad_data *mp3_mad;
#endif
#ifdef FLAC_MUSIC
FLAC_music *flac;
#endif
} data;
Mix_Fading fading;
int fade_step;
int fade_steps;
int error;
};
#ifdef MID_MUSIC
#ifdef USE_TIMIDITY_MIDI
static int timidity_ok;
static int samplesize;
#endif
#ifdef USE_FLUIDSYNTH_MIDI
static int fluidsynth_ok;
#endif
#ifdef USE_NATIVE_MIDI
static int native_midi_ok;
#endif
#endif
 
/* Used to calculate fading steps */
static int ms_per_step;
 
/* rcg06042009 report available decoders at runtime. */
static const char **music_decoders = NULL;
static int num_decoders = 0;
 
/* Semicolon-separated SoundFont paths */
#ifdef MID_MUSIC
char* soundfont_paths = NULL;
#endif
 
int Mix_GetNumMusicDecoders(void)
{
return(num_decoders);
}
 
const char *Mix_GetMusicDecoder(int index)
{
if ((index < 0) || (index >= num_decoders)) {
return NULL;
}
return(music_decoders[index]);
}
 
static void add_music_decoder(const char *decoder)
{
void *ptr = SDL_realloc(music_decoders, (num_decoders + 1) * sizeof (const char **));
if (ptr == NULL) {
return; /* oh well, go on without it. */
}
music_decoders = (const char **) ptr;
music_decoders[num_decoders++] = decoder;
}
 
/* Local low-level functions prototypes */
static void music_internal_initialize_volume(void);
static void music_internal_volume(int volume);
static int music_internal_play(Mix_Music *music, double position);
static int music_internal_position(double position);
static int music_internal_playing();
static void music_internal_halt(void);
 
 
/* Support for hooking when the music has finished */
static void (*music_finished_hook)(void) = NULL;
 
void Mix_HookMusicFinished(void (*music_finished)(void))
{
SDL_LockAudio();
music_finished_hook = music_finished;
SDL_UnlockAudio();
}
 
 
/* If music isn't playing, halt it if no looping is required, restart it */
/* otherwhise. NOP if the music is playing */
static int music_halt_or_loop (void)
{
/* Restart music if it has to loop */
if (!music_internal_playing())
{
#ifdef USE_NATIVE_MIDI
/* Native MIDI handles looping internally */
if (music_playing->type == MUS_MID && native_midi_ok) {
music_loops = 0;
}
#endif
 
/* Restart music if it has to loop at a high level */
if (music_loops)
{
Mix_Fading current_fade;
--music_loops;
current_fade = music_playing->fading;
music_internal_play(music_playing, 0.0);
music_playing->fading = current_fade;
}
else
{
music_internal_halt();
if (music_finished_hook)
music_finished_hook();
return 0;
}
}
return 1;
}
 
 
 
/* Mixing function */
void music_mixer(void *udata, Uint8 *stream, int len)
{
int left = 0;
 
if ( music_playing && music_active ) {
/* Handle fading */
if ( music_playing->fading != MIX_NO_FADING ) {
if ( music_playing->fade_step++ < music_playing->fade_steps ) {
int volume;
int fade_step = music_playing->fade_step;
int fade_steps = music_playing->fade_steps;
 
if ( music_playing->fading == MIX_FADING_OUT ) {
volume = (music_volume * (fade_steps-fade_step)) / fade_steps;
} else { /* Fading in */
volume = (music_volume * fade_step) / fade_steps;
}
music_internal_volume(volume);
} else {
if ( music_playing->fading == MIX_FADING_OUT ) {
music_internal_halt();
if ( music_finished_hook ) {
music_finished_hook();
}
return;
}
music_playing->fading = MIX_NO_FADING;
}
}
music_halt_or_loop();
if (!music_internal_playing())
return;
 
switch (music_playing->type) {
#ifdef CMD_MUSIC
case MUS_CMD:
/* The playing is done externally */
break;
#endif
#ifdef WAV_MUSIC
case MUS_WAV:
left = WAVStream_PlaySome(stream, len);
break;
#endif
#ifdef MODPLUG_MUSIC
case MUS_MODPLUG:
left = modplug_playAudio(music_playing->data.modplug, stream, len);
break;
#endif
#ifdef MOD_MUSIC
case MUS_MOD:
left = MOD_playAudio(music_playing->data.module, stream, len);
break;
#endif
#ifdef MID_MUSIC
case MUS_MID:
#ifdef USE_NATIVE_MIDI
if ( native_midi_ok ) {
/* Native midi is handled asynchronously */
goto skip;
}
#endif
#ifdef USE_FLUIDSYNTH_MIDI
if ( fluidsynth_ok ) {
fluidsynth_playsome(music_playing->data.fluidsynthmidi, stream, len);
goto skip;
}
#endif
#ifdef USE_TIMIDITY_MIDI
if ( timidity_ok ) {
int samples = len / samplesize;
Timidity_PlaySome(stream, samples);
goto skip;
}
#endif
break;
#endif
#ifdef OGG_MUSIC
case MUS_OGG:
left = OGG_playAudio(music_playing->data.ogg, stream, len);
break;
#endif
#ifdef FLAC_MUSIC
case MUS_FLAC:
left = FLAC_playAudio(music_playing->data.flac, stream, len);
break;
#endif
#ifdef MP3_MUSIC
case MUS_MP3:
left = (len - smpeg.SMPEG_playAudio(music_playing->data.mp3, stream, len));
break;
#endif
#ifdef MP3_MAD_MUSIC
case MUS_MP3_MAD:
left = mad_getSamples(music_playing->data.mp3_mad, stream, len);
break;
#endif
default:
/* Unknown music type?? */
break;
}
}
 
skip:
/* Handle seamless music looping */
if (left > 0 && left < len) {
music_halt_or_loop();
if (music_internal_playing())
music_mixer(udata, stream+(len-left), left);
}
}
 
/* Initialize the music players with a certain desired audio format */
int open_music(SDL_AudioSpec *mixer)
{
#ifdef WAV_MUSIC
if ( WAVStream_Init(mixer) == 0 ) {
add_music_decoder("WAVE");
}
#endif
#ifdef MODPLUG_MUSIC
if ( modplug_init(mixer) == 0 ) {
add_music_decoder("MODPLUG");
}
#endif
#ifdef MOD_MUSIC
if ( MOD_init(mixer) == 0 ) {
add_music_decoder("MIKMOD");
}
#endif
#ifdef MID_MUSIC
#ifdef USE_TIMIDITY_MIDI
samplesize = mixer->size / mixer->samples;
if ( Timidity_Init(mixer->freq, mixer->format,
mixer->channels, mixer->samples) == 0 ) {
timidity_ok = 1;
add_music_decoder("TIMIDITY");
} else {
timidity_ok = 0;
}
#endif
#ifdef USE_FLUIDSYNTH_MIDI
if ( fluidsynth_init(mixer) == 0 ) {
fluidsynth_ok = 1;
add_music_decoder("FLUIDSYNTH");
} else {
fluidsynth_ok = 0;
}
#endif
#ifdef USE_NATIVE_MIDI
#ifdef USE_FLUIDSYNTH_MIDI
native_midi_ok = !fluidsynth_ok;
if ( native_midi_ok )
#endif
#ifdef USE_TIMIDITY_MIDI
native_midi_ok = !timidity_ok;
if ( !native_midi_ok ) {
native_midi_ok = (getenv("SDL_NATIVE_MUSIC") != NULL);
}
if ( native_midi_ok )
#endif
native_midi_ok = native_midi_detect();
if ( native_midi_ok )
add_music_decoder("NATIVEMIDI");
#endif
#endif
#ifdef OGG_MUSIC
if ( OGG_init(mixer) == 0 ) {
add_music_decoder("OGG");
}
#endif
#ifdef FLAC_MUSIC
if ( FLAC_init(mixer) == 0 ) {
add_music_decoder("FLAC");
}
#endif
#if defined(MP3_MUSIC) || defined(MP3_MAD_MUSIC)
/* Keep a copy of the mixer */
used_mixer = *mixer;
add_music_decoder("MP3");
#endif
 
music_playing = NULL;
music_stopped = 0;
Mix_VolumeMusic(SDL_MIX_MAXVOLUME);
 
/* Calculate the number of ms for each callback */
ms_per_step = (int) (((float)mixer->samples * 1000.0) / mixer->freq);
 
return(0);
}
 
/* Portable case-insensitive string compare function */
int MIX_string_equals(const char *str1, const char *str2)
{
while ( *str1 && *str2 ) {
if ( toupper((unsigned char)*str1) !=
toupper((unsigned char)*str2) )
break;
++str1;
++str2;
}
return (!*str1 && !*str2);
}
 
static int detect_mp3(Uint8 *magic)
{
if ( strncmp((char *)magic, "ID3", 3) == 0 ) {
return 1;
}
 
/* Detection code lifted from SMPEG */
if(((magic[0] & 0xff) != 0xff) || // No sync bits
((magic[1] & 0xf0) != 0xf0) || //
((magic[2] & 0xf0) == 0x00) || // Bitrate is 0
((magic[2] & 0xf0) == 0xf0) || // Bitrate is 15
((magic[2] & 0x0c) == 0x0c) || // Frequency is 3
((magic[1] & 0x06) == 0x00)) { // Layer is 4
return(0);
}
return 1;
}
 
/* MUS_MOD can't be auto-detected. If no other format was detected, MOD is
* assumed and MUS_MOD will be returned, meaning that the format might not
* actually be MOD-based.
*
* Returns MUS_NONE in case of errors. */
static Mix_MusicType detect_music_type(SDL_RWops *rw)
{
Uint8 magic[5];
Uint8 moremagic[9];
 
int start = SDL_RWtell(rw);
if (SDL_RWread(rw, magic, 1, 4) != 4 || SDL_RWread(rw, moremagic, 1, 8) != 8 ) {
Mix_SetError("Couldn't read from RWops");
return MUS_NONE;
}
SDL_RWseek(rw, start, RW_SEEK_SET);
magic[4]='\0';
moremagic[8] = '\0';
 
/* WAVE files have the magic four bytes "RIFF"
AIFF files have the magic 12 bytes "FORM" XXXX "AIFF" */
if (((strcmp((char *)magic, "RIFF") == 0) && (strcmp((char *)(moremagic+4), "WAVE") == 0)) ||
(strcmp((char *)magic, "FORM") == 0)) {
return MUS_WAV;
}
 
/* Ogg Vorbis files have the magic four bytes "OggS" */
if (strcmp((char *)magic, "OggS") == 0) {
return MUS_OGG;
}
 
/* FLAC files have the magic four bytes "fLaC" */
if (strcmp((char *)magic, "fLaC") == 0) {
return MUS_FLAC;
}
 
/* MIDI files have the magic four bytes "MThd" */
if (strcmp((char *)magic, "MThd") == 0) {
return MUS_MID;
}
 
if (detect_mp3(magic)) {
return MUS_MP3;
}
 
/* Assume MOD format.
*
* Apparently there is no way to check if the file is really a MOD,
* or there are too many formats supported by MikMod/ModPlug, or
* MikMod/ModPlug does this check by itself. */
return MUS_MOD;
}
 
/* Load a music file */
Mix_Music *Mix_LoadMUS(const char *file)
{
SDL_RWops *rw;
Mix_Music *music;
Mix_MusicType type;
char *ext = strrchr(file, '.');
 
#ifdef CMD_MUSIC
if ( music_cmd ) {
/* Allocate memory for the music structure */
music = (Mix_Music *)SDL_malloc(sizeof(Mix_Music));
if ( music == NULL ) {
Mix_SetError("Out of memory");
return(NULL);
}
music->error = 0;
music->type = MUS_CMD;
music->data.cmd = MusicCMD_LoadSong(music_cmd, file);
if ( music->data.cmd == NULL ) {
SDL_free(music);
music == NULL;
}
return music;
}
#endif
 
rw = SDL_RWFromFile(file, "rb");
if ( rw == NULL ) {
Mix_SetError("Couldn't open '%s'", file);
return NULL;
}
 
/* Use the extension as a first guess on the file type */
type = MUS_NONE;
ext = strrchr(file, '.');
/* No need to guard these with #ifdef *_MUSIC stuff,
* since we simply call Mix_LoadMUSType_RW() later */
if ( ext ) {
++ext; /* skip the dot in the extension */
if ( MIX_string_equals(ext, "WAV") ) {
type = MUS_WAV;
} else if ( MIX_string_equals(ext, "MID") ||
MIX_string_equals(ext, "MIDI") ||
MIX_string_equals(ext, "KAR") ) {
type = MUS_MID;
} else if ( MIX_string_equals(ext, "OGG") ) {
type = MUS_OGG;
} else if ( MIX_string_equals(ext, "FLAC") ) {
type = MUS_FLAC;
} else if ( MIX_string_equals(ext, "MPG") ||
MIX_string_equals(ext, "MPEG") ||
MIX_string_equals(ext, "MP3") ||
MIX_string_equals(ext, "MAD") ) {
type = MUS_MP3;
}
}
if ( type == MUS_NONE ) {
type = detect_music_type(rw);
}
 
/* We need to know if a specific error occurs; if not, we'll set a
* generic one, so we clear the current one. */
Mix_SetError("");
music = Mix_LoadMUSType_RW(rw, type, SDL_TRUE);
if ( music == NULL && Mix_GetError()[0] == '\0' ) {
SDL_FreeRW(rw);
Mix_SetError("Couldn't open '%s'", file);
}
return music;
}
 
Mix_Music *Mix_LoadMUS_RW(SDL_RWops *rw)
{
return Mix_LoadMUSType_RW(rw, MUS_NONE, SDL_FALSE);
}
 
Mix_Music *Mix_LoadMUSType_RW(SDL_RWops *rw, Mix_MusicType type, int freesrc)
{
Mix_Music *music;
 
if (!rw) {
Mix_SetError("RWops pointer is NULL");
return NULL;
}
 
/* If the caller wants auto-detection, figure out what kind of file
* this is. */
if (type == MUS_NONE) {
if ((type = detect_music_type(rw)) == MUS_NONE) {
/* Don't call Mix_SetError() here since detect_music_type()
* does that. */
return NULL;
}
}
 
/* Allocate memory for the music structure */
music = (Mix_Music *)SDL_malloc(sizeof(Mix_Music));
if (music == NULL ) {
Mix_SetError("Out of memory");
return NULL;
}
music->error = 0;
 
switch (type) {
#ifdef WAV_MUSIC
case MUS_WAV:
/* The WAVE loader needs the first 4 bytes of the header */
{
Uint8 magic[5];
int start = SDL_RWtell(rw);
if (SDL_RWread(rw, magic, 1, 4) != 4) {
Mix_SetError("Couldn't read from RWops");
return MUS_NONE;
}
SDL_RWseek(rw, start, RW_SEEK_SET);
magic[4] = '\0';
music->type = MUS_WAV;
music->data.wave = WAVStream_LoadSong_RW(rw, (char *)magic, freesrc);
}
if (music->data.wave == NULL) {
music->error = 1;
}
break;
#endif
#ifdef OGG_MUSIC
case MUS_OGG:
music->type = MUS_OGG;
music->data.ogg = OGG_new_RW(rw, freesrc);
if ( music->data.ogg == NULL ) {
music->error = 1;
}
break;
#endif
#ifdef FLAC_MUSIC
case MUS_FLAC:
music->type = MUS_FLAC;
music->data.flac = FLAC_new_RW(rw, freesrc);
if ( music->data.flac == NULL ) {
music->error = 1;
}
break;
#endif
#ifdef MP3_MUSIC
case MUS_MP3:
if ( Mix_Init(MIX_INIT_MP3) ) {
SMPEG_Info info;
music->type = MUS_MP3;
music->data.mp3 = smpeg.SMPEG_new_rwops(rw, &info, 0);
if ( !info.has_audio ) {
Mix_SetError("MPEG file does not have any audio stream.");
music->error = 1;
} else {
smpeg.SMPEG_actualSpec(music->data.mp3, &used_mixer);
}
} else {
music->error = 1;
}
break;
#elif defined(MP3_MAD_MUSIC)
case MUS_MP3:
music->type = MUS_MP3_MAD;
music->data.mp3_mad = mad_openFileRW(rw, &used_mixer, freesrc);
if (music->data.mp3_mad == 0) {
Mix_SetError("Could not initialize MPEG stream.");
music->error = 1;
}
break;
#endif
#ifdef MID_MUSIC
case MUS_MID:
music->type = MUS_MID;
#ifdef USE_NATIVE_MIDI
if ( native_midi_ok ) {
music->data.nativemidi = native_midi_loadsong_RW(rw, freesrc);
if ( music->data.nativemidi == NULL ) {
Mix_SetError("%s", native_midi_error());
music->error = 1;
}
break;
}
#endif
#ifdef USE_FLUIDSYNTH_MIDI
if ( fluidsynth_ok ) {
music->data.fluidsynthmidi = fluidsynth_loadsong_RW(rw, freesrc);
if ( music->data.fluidsynthmidi == NULL ) {
music->error = 1;
}
break;
}
#endif
#ifdef USE_TIMIDITY_MIDI
if ( timidity_ok ) {
music->data.midi = Timidity_LoadSong_RW(rw, freesrc);
if ( music->data.midi == NULL ) {
Mix_SetError("%s", Timidity_Error());
music->error = 1;
}
} else {
Mix_SetError("%s", Timidity_Error());
music->error = 1;
}
#endif
break;
#endif
#if defined(MODPLUG_MUSIC) || defined(MOD_MUSIC)
case MUS_MOD:
music->error = 1;
#ifdef MODPLUG_MUSIC
if ( music->error ) {
music->type = MUS_MODPLUG;
music->data.modplug = modplug_new_RW(rw, freesrc);
if ( music->data.modplug ) {
music->error = 0;
}
}
#endif
#ifdef MOD_MUSIC
if ( music->error ) {
music->type = MUS_MOD;
music->data.module = MOD_new_RW(rw, freesrc);
if ( music->data.module ) {
music->error = 0;
}
}
#endif
break;
#endif
 
default:
Mix_SetError("Unrecognized music format");
music->error=1;
} /* switch (want) */
 
 
if (music->error) {
SDL_free(music);
music=NULL;
}
return(music);
}
 
/* Free a music chunk previously loaded */
void Mix_FreeMusic(Mix_Music *music)
{
if ( music ) {
/* Stop the music if it's currently playing */
SDL_LockAudio();
if ( music == music_playing ) {
/* Wait for any fade out to finish */
while ( music->fading == MIX_FADING_OUT ) {
SDL_UnlockAudio();
SDL_Delay(100);
SDL_LockAudio();
}
if ( music == music_playing ) {
music_internal_halt();
}
}
SDL_UnlockAudio();
switch (music->type) {
#ifdef CMD_MUSIC
case MUS_CMD:
MusicCMD_FreeSong(music->data.cmd);
break;
#endif
#ifdef WAV_MUSIC
case MUS_WAV:
WAVStream_FreeSong(music->data.wave);
break;
#endif
#ifdef MODPLUG_MUSIC
case MUS_MODPLUG:
modplug_delete(music->data.modplug);
break;
#endif
#ifdef MOD_MUSIC
case MUS_MOD:
MOD_delete(music->data.module);
break;
#endif
#ifdef MID_MUSIC
case MUS_MID:
#ifdef USE_NATIVE_MIDI
if ( native_midi_ok ) {
native_midi_freesong(music->data.nativemidi);
goto skip;
}
#endif
#ifdef USE_FLUIDSYNTH_MIDI
if ( fluidsynth_ok ) {
fluidsynth_freesong(music->data.fluidsynthmidi);
goto skip;
}
#endif
#ifdef USE_TIMIDITY_MIDI
if ( timidity_ok ) {
Timidity_FreeSong(music->data.midi);
goto skip;
}
#endif
break;
#endif
#ifdef OGG_MUSIC
case MUS_OGG:
OGG_delete(music->data.ogg);
break;
#endif
#ifdef FLAC_MUSIC
case MUS_FLAC:
FLAC_delete(music->data.flac);
break;
#endif
#ifdef MP3_MUSIC
case MUS_MP3:
smpeg.SMPEG_delete(music->data.mp3);
break;
#endif
#ifdef MP3_MAD_MUSIC
case MUS_MP3_MAD:
mad_closeFile(music->data.mp3_mad);
break;
#endif
default:
/* Unknown music type?? */
break;
}
 
skip:
SDL_free(music);
}
}
 
/* Find out the music format of a mixer music, or the currently playing
music, if 'music' is NULL.
*/
Mix_MusicType Mix_GetMusicType(const Mix_Music *music)
{
Mix_MusicType type = MUS_NONE;
 
if ( music ) {
type = music->type;
} else {
SDL_LockAudio();
if ( music_playing ) {
type = music_playing->type;
}
SDL_UnlockAudio();
}
return(type);
}
 
/* Play a music chunk. Returns 0, or -1 if there was an error.
*/
static int music_internal_play(Mix_Music *music, double position)
{
int retval = 0;
 
#if defined(__MACOSX__) && defined(USE_NATIVE_MIDI)
/* This fixes a bug with native MIDI on Mac OS X, where you
can't really stop and restart MIDI from the audio callback.
*/
if ( music == music_playing && music->type == MUS_MID && native_midi_ok ) {
/* Just a seek suffices to restart playing */
music_internal_position(position);
return 0;
}
#endif
 
/* Note the music we're playing */
if ( music_playing ) {
music_internal_halt();
}
music_playing = music;
 
/* Set the initial volume */
if ( music->type != MUS_MOD ) {
music_internal_initialize_volume();
}
 
/* Set up for playback */
switch (music->type) {
#ifdef CMD_MUSIC
case MUS_CMD:
MusicCMD_Start(music->data.cmd);
break;
#endif
#ifdef WAV_MUSIC
case MUS_WAV:
WAVStream_Start(music->data.wave);
break;
#endif
#ifdef MODPLUG_MUSIC
case MUS_MODPLUG:
/* can't set volume until file is loaded, so finally set it now */
music_internal_initialize_volume();
modplug_play(music->data.modplug);
break;
#endif
#ifdef MOD_MUSIC
case MUS_MOD:
MOD_play(music->data.module);
/* Player_SetVolume() does nothing before Player_Start() */
music_internal_initialize_volume();
break;
#endif
#ifdef MID_MUSIC
case MUS_MID:
#ifdef USE_NATIVE_MIDI
if ( native_midi_ok ) {
native_midi_start(music->data.nativemidi, music_loops);
goto skip;
}
#endif
#ifdef USE_FLUIDSYNTH_MIDI
if (fluidsynth_ok ) {
fluidsynth_start(music->data.fluidsynthmidi);
goto skip;
}
#endif
#ifdef USE_TIMIDITY_MIDI
if ( timidity_ok ) {
Timidity_Start(music->data.midi);
goto skip;
}
#endif
break;
#endif
#ifdef OGG_MUSIC
case MUS_OGG:
OGG_play(music->data.ogg);
break;
#endif
#ifdef FLAC_MUSIC
case MUS_FLAC:
FLAC_play(music->data.flac);
break;
#endif
#ifdef MP3_MUSIC
case MUS_MP3:
smpeg.SMPEG_enableaudio(music->data.mp3,1);
smpeg.SMPEG_enablevideo(music->data.mp3,0);
smpeg.SMPEG_play(music_playing->data.mp3);
break;
#endif
#ifdef MP3_MAD_MUSIC
case MUS_MP3_MAD:
mad_start(music->data.mp3_mad);
break;
#endif
default:
Mix_SetError("Can't play unknown music type");
retval = -1;
break;
}
 
skip:
/* Set the playback position, note any errors if an offset is used */
if ( retval == 0 ) {
if ( position > 0.0 ) {
if ( music_internal_position(position) < 0 ) {
Mix_SetError("Position not implemented for music type");
retval = -1;
}
} else {
music_internal_position(0.0);
}
}
 
/* If the setup failed, we're not playing any music anymore */
if ( retval < 0 ) {
music_playing = NULL;
}
return(retval);
}
int Mix_FadeInMusicPos(Mix_Music *music, int loops, int ms, double position)
{
int retval;
 
if ( ms_per_step == 0 ) {
SDL_SetError("Audio device hasn't been opened");
return(-1);
}
 
/* Don't play null pointers :-) */
if ( music == NULL ) {
Mix_SetError("music parameter was NULL");
return(-1);
}
 
/* Setup the data */
if ( ms ) {
music->fading = MIX_FADING_IN;
} else {
music->fading = MIX_NO_FADING;
}
music->fade_step = 0;
music->fade_steps = ms/ms_per_step;
 
/* Play the puppy */
SDL_LockAudio();
/* If the current music is fading out, wait for the fade to complete */
while ( music_playing && (music_playing->fading == MIX_FADING_OUT) ) {
SDL_UnlockAudio();
SDL_Delay(100);
SDL_LockAudio();
}
music_active = 1;
if (loops == 1) {
/* Loop is the number of times to play the audio */
loops = 0;
}
music_loops = loops;
retval = music_internal_play(music, position);
SDL_UnlockAudio();
 
return(retval);
}
int Mix_FadeInMusic(Mix_Music *music, int loops, int ms)
{
return Mix_FadeInMusicPos(music, loops, ms, 0.0);
}
int Mix_PlayMusic(Mix_Music *music, int loops)
{
return Mix_FadeInMusicPos(music, loops, 0, 0.0);
}
 
/* Set the playing music position */
int music_internal_position(double position)
{
int retval = 0;
 
switch (music_playing->type) {
#ifdef MODPLUG_MUSIC
case MUS_MODPLUG:
modplug_jump_to_time(music_playing->data.modplug, position);
break;
#endif
#ifdef MOD_MUSIC
case MUS_MOD:
MOD_jump_to_time(music_playing->data.module, position);
break;
#endif
#ifdef OGG_MUSIC
case MUS_OGG:
OGG_jump_to_time(music_playing->data.ogg, position);
break;
#endif
#ifdef FLAC_MUSIC
case MUS_FLAC:
FLAC_jump_to_time(music_playing->data.flac, position);
break;
#endif
#ifdef MP3_MUSIC
case MUS_MP3:
smpeg.SMPEG_rewind(music_playing->data.mp3);
smpeg.SMPEG_play(music_playing->data.mp3);
if ( position > 0.0 ) {
smpeg.SMPEG_skip(music_playing->data.mp3, (float)position);
}
break;
#endif
#ifdef MP3_MAD_MUSIC
case MUS_MP3_MAD:
mad_seek(music_playing->data.mp3_mad, position);
break;
#endif
default:
/* TODO: Implement this for other music backends */
retval = -1;
break;
}
return(retval);
}
int Mix_SetMusicPosition(double position)
{
int retval;
 
SDL_LockAudio();
if ( music_playing ) {
retval = music_internal_position(position);
if ( retval < 0 ) {
Mix_SetError("Position not implemented for music type");
}
} else {
Mix_SetError("Music isn't playing");
retval = -1;
}
SDL_UnlockAudio();
 
return(retval);
}
 
/* Set the music's initial volume */
static void music_internal_initialize_volume(void)
{
if ( music_playing->fading == MIX_FADING_IN ) {
music_internal_volume(0);
} else {
music_internal_volume(music_volume);
}
}
 
/* Set the music volume */
static void music_internal_volume(int volume)
{
switch (music_playing->type) {
#ifdef CMD_MUSIC
case MUS_CMD:
MusicCMD_SetVolume(volume);
break;
#endif
#ifdef WAV_MUSIC
case MUS_WAV:
WAVStream_SetVolume(volume);
break;
#endif
#ifdef MODPLUG_MUSIC
case MUS_MODPLUG:
modplug_setvolume(music_playing->data.modplug, volume);
break;
#endif
#ifdef MOD_MUSIC
case MUS_MOD:
MOD_setvolume(music_playing->data.module, volume);
break;
#endif
#ifdef MID_MUSIC
case MUS_MID:
#ifdef USE_NATIVE_MIDI
if ( native_midi_ok ) {
native_midi_setvolume(volume);
return;
}
#endif
#ifdef USE_FLUIDSYNTH_MIDI
if ( fluidsynth_ok ) {
fluidsynth_setvolume(music_playing->data.fluidsynthmidi, volume);
return;
}
#endif
#ifdef USE_TIMIDITY_MIDI
if ( timidity_ok ) {
Timidity_SetVolume(volume);
return;
}
#endif
break;
#endif
#ifdef OGG_MUSIC
case MUS_OGG:
OGG_setvolume(music_playing->data.ogg, volume);
break;
#endif
#ifdef FLAC_MUSIC
case MUS_FLAC:
FLAC_setvolume(music_playing->data.flac, volume);
break;
#endif
#ifdef MP3_MUSIC
case MUS_MP3:
smpeg.SMPEG_setvolume(music_playing->data.mp3,(int)(((float)volume/(float)MIX_MAX_VOLUME)*100.0));
break;
#endif
#ifdef MP3_MAD_MUSIC
case MUS_MP3_MAD:
mad_setVolume(music_playing->data.mp3_mad, volume);
break;
#endif
default:
/* Unknown music type?? */
break;
}
}
int Mix_VolumeMusic(int volume)
{
int prev_volume;
 
prev_volume = music_volume;
if ( volume < 0 ) {
return prev_volume;
}
if ( volume > SDL_MIX_MAXVOLUME ) {
volume = SDL_MIX_MAXVOLUME;
}
music_volume = volume;
SDL_LockAudio();
if ( music_playing ) {
music_internal_volume(music_volume);
}
SDL_UnlockAudio();
return(prev_volume);
}
 
/* Halt playing of music */
static void music_internal_halt(void)
{
switch (music_playing->type) {
#ifdef CMD_MUSIC
case MUS_CMD:
MusicCMD_Stop(music_playing->data.cmd);
break;
#endif
#ifdef WAV_MUSIC
case MUS_WAV:
WAVStream_Stop();
break;
#endif
#ifdef MODPLUG_MUSIC
case MUS_MODPLUG:
modplug_stop(music_playing->data.modplug);
break;
#endif
#ifdef MOD_MUSIC
case MUS_MOD:
MOD_stop(music_playing->data.module);
break;
#endif
#ifdef MID_MUSIC
case MUS_MID:
#ifdef USE_NATIVE_MIDI
if ( native_midi_ok ) {
native_midi_stop();
goto skip;
}
#endif
#ifdef USE_FLUIDSYNTH_MIDI
if ( fluidsynth_ok ) {
fluidsynth_stop(music_playing->data.fluidsynthmidi);
goto skip;
}
#endif
#ifdef USE_TIMIDITY_MIDI
if ( timidity_ok ) {
Timidity_Stop();
goto skip;
}
#endif
break;
#endif
#ifdef OGG_MUSIC
case MUS_OGG:
OGG_stop(music_playing->data.ogg);
break;
#endif
#ifdef FLAC_MUSIC
case MUS_FLAC:
FLAC_stop(music_playing->data.flac);
break;
#endif
#ifdef MP3_MUSIC
case MUS_MP3:
smpeg.SMPEG_stop(music_playing->data.mp3);
break;
#endif
#ifdef MP3_MAD_MUSIC
case MUS_MP3_MAD:
mad_stop(music_playing->data.mp3_mad);
break;
#endif
default:
/* Unknown music type?? */
return;
}
 
skip:
music_playing->fading = MIX_NO_FADING;
music_playing = NULL;
}
int Mix_HaltMusic(void)
{
SDL_LockAudio();
if ( music_playing ) {
music_internal_halt();
}
SDL_UnlockAudio();
 
return(0);
}
 
/* Progressively stop the music */
int Mix_FadeOutMusic(int ms)
{
int retval = 0;
 
if ( ms_per_step == 0 ) {
SDL_SetError("Audio device hasn't been opened");
return 0;
}
 
if (ms <= 0) { /* just halt immediately. */
Mix_HaltMusic();
return 1;
}
 
SDL_LockAudio();
if ( music_playing) {
int fade_steps = (ms + ms_per_step - 1)/ms_per_step;
if ( music_playing->fading == MIX_NO_FADING ) {
music_playing->fade_step = 0;
} else {
int step;
int old_fade_steps = music_playing->fade_steps;
if ( music_playing->fading == MIX_FADING_OUT ) {
step = music_playing->fade_step;
} else {
step = old_fade_steps
- music_playing->fade_step + 1;
}
music_playing->fade_step = (step * fade_steps)
/ old_fade_steps;
}
music_playing->fading = MIX_FADING_OUT;
music_playing->fade_steps = fade_steps;
retval = 1;
}
SDL_UnlockAudio();
 
return(retval);
}
 
Mix_Fading Mix_FadingMusic(void)
{
Mix_Fading fading = MIX_NO_FADING;
 
SDL_LockAudio();
if ( music_playing ) {
fading = music_playing->fading;
}
SDL_UnlockAudio();
 
return(fading);
}
 
/* Pause/Resume the music stream */
void Mix_PauseMusic(void)
{
music_active = 0;
}
 
void Mix_ResumeMusic(void)
{
music_active = 1;
}
 
void Mix_RewindMusic(void)
{
Mix_SetMusicPosition(0.0);
}
 
int Mix_PausedMusic(void)
{
return (music_active == 0);
}
 
/* Check the status of the music */
static int music_internal_playing()
{
int playing = 1;
 
if (music_playing == NULL) {
return 0;
}
 
switch (music_playing->type) {
#ifdef CMD_MUSIC
case MUS_CMD:
if (!MusicCMD_Active(music_playing->data.cmd)) {
playing = 0;
}
break;
#endif
#ifdef WAV_MUSIC
case MUS_WAV:
if ( ! WAVStream_Active() ) {
playing = 0;
}
break;
#endif
#ifdef MODPLUG_MUSIC
case MUS_MODPLUG:
if ( ! modplug_playing(music_playing->data.modplug) ) {
playing = 0;
}
break;
#endif
#ifdef MOD_MUSIC
case MUS_MOD:
if ( ! MOD_playing(music_playing->data.module) ) {
playing = 0;
}
break;
#endif
#ifdef MID_MUSIC
case MUS_MID:
#ifdef USE_NATIVE_MIDI
if ( native_midi_ok ) {
if ( ! native_midi_active() )
playing = 0;
goto skip;
}
#endif
#ifdef USE_FLUIDSYNTH_MIDI
if ( fluidsynth_ok ) {
if ( ! fluidsynth_active(music_playing->data.fluidsynthmidi) )
playing = 0;
goto skip;
}
#endif
#ifdef USE_TIMIDITY_MIDI
if ( timidity_ok ) {
if ( ! Timidity_Active() )
playing = 0;
goto skip;
}
#endif
break;
#endif
#ifdef OGG_MUSIC
case MUS_OGG:
if ( ! OGG_playing(music_playing->data.ogg) ) {
playing = 0;
}
break;
#endif
#ifdef FLAC_MUSIC
case MUS_FLAC:
if ( ! FLAC_playing(music_playing->data.flac) ) {
playing = 0;
}
break;
#endif
#ifdef MP3_MUSIC
case MUS_MP3:
if ( smpeg.SMPEG_status(music_playing->data.mp3) != SMPEG_PLAYING )
playing = 0;
break;
#endif
#ifdef MP3_MAD_MUSIC
case MUS_MP3_MAD:
if (!mad_isPlaying(music_playing->data.mp3_mad)) {
playing = 0;
}
break;
#endif
default:
playing = 0;
break;
}
 
skip:
return(playing);
}
int Mix_PlayingMusic(void)
{
int playing = 0;
 
SDL_LockAudio();
if ( music_playing ) {
playing = music_loops || music_internal_playing();
}
SDL_UnlockAudio();
 
return(playing);
}
 
/* Set the external music playback command */
int Mix_SetMusicCMD(const char *command)
{
Mix_HaltMusic();
if ( music_cmd ) {
SDL_free(music_cmd);
music_cmd = NULL;
}
if ( command ) {
music_cmd = (char *)SDL_malloc(strlen(command)+1);
if ( music_cmd == NULL ) {
return(-1);
}
strcpy(music_cmd, command);
}
return(0);
}
 
int Mix_SetSynchroValue(int i)
{
/* Not supported by any players at this time */
return(-1);
}
 
int Mix_GetSynchroValue(void)
{
/* Not supported by any players at this time */
return(-1);
}
 
 
/* Uninitialize the music players */
void close_music(void)
{
Mix_HaltMusic();
#ifdef CMD_MUSIC
Mix_SetMusicCMD(NULL);
#endif
#ifdef MODPLUG_MUSIC
modplug_exit();
#endif
#ifdef MOD_MUSIC
MOD_exit();
#endif
#ifdef MID_MUSIC
# ifdef USE_TIMIDITY_MIDI
Timidity_Close();
# endif
#endif
 
/* rcg06042009 report available decoders at runtime. */
SDL_free(music_decoders);
music_decoders = NULL;
num_decoders = 0;
 
ms_per_step = 0;
}
 
int Mix_SetSoundFonts(const char *paths)
{
#ifdef MID_MUSIC
if (soundfont_paths) {
SDL_free(soundfont_paths);
soundfont_paths = NULL;
}
 
if (paths) {
if (!(soundfont_paths = SDL_strdup(paths))) {
Mix_SetError("Insufficient memory to set SoundFonts");
return 0;
}
}
#endif
return 1;
}
 
#ifdef MID_MUSIC
const char* Mix_GetSoundFonts(void)
{
const char* force = getenv("SDL_FORCE_SOUNDFONTS");
 
if (!soundfont_paths || (force && force[0] == '1')) {
return getenv("SDL_SOUNDFONTS");
} else {
return soundfont_paths;
}
}
 
int Mix_EachSoundFont(int (*function)(const char*, void*), void *data)
{
char *context, *path, *paths;
const char* cpaths = Mix_GetSoundFonts();
 
if (!cpaths) {
Mix_SetError("No SoundFonts have been requested");
return 0;
}
 
if (!(paths = SDL_strdup(cpaths))) {
Mix_SetError("Insufficient memory to iterate over SoundFonts");
return 0;
}
 
#if defined(__MINGW32__) || defined(__MINGW64__)
for (path = strtok(paths, ";"); path; path = strtok(NULL, ";")) {
#elif defined(_WIN32)
for (path = strtok_s(paths, ";", &context); path; path = strtok_s(NULL, ";", &context)) {
#else
for (path = strtok_r(paths, ":;", &context); path; path = strtok_r(NULL, ":;", &context)) {
#endif
if (!function(path, data)) {
SDL_free(paths);
return 0;
}
}
 
SDL_free(paths);
return 1;
}
#endif
/contrib/sdk/sources/SDL_mixer-1.2.12/music_ogg.c
0,0 → 1,234
/*
SDL_mixer: An audio mixer library based on the SDL library
Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
 
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
 
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
 
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
 
/* $Id$ */
 
#ifdef OGG_MUSIC
 
/* This file supports Ogg Vorbis music streams */
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#include "SDL_mixer.h"
#include "dynamic_ogg.h"
#include "music_ogg.h"
 
/* This is the format of the audio mixer data */
static SDL_AudioSpec mixer;
 
/* Initialize the Ogg Vorbis player, with the given mixer settings
This function returns 0, or -1 if there was an error.
*/
int OGG_init(SDL_AudioSpec *mixerfmt)
{
mixer = *mixerfmt;
return(0);
}
 
/* Set the volume for an OGG stream */
void OGG_setvolume(OGG_music *music, int volume)
{
music->volume = volume;
}
 
static size_t sdl_read_func(void *ptr, size_t size, size_t nmemb, void *datasource)
{
return SDL_RWread((SDL_RWops*)datasource, ptr, size, nmemb);
}
 
static int sdl_seek_func(void *datasource, ogg_int64_t offset, int whence)
{
return SDL_RWseek((SDL_RWops*)datasource, (int)offset, whence);
}
 
static long sdl_tell_func(void *datasource)
{
return SDL_RWtell((SDL_RWops*)datasource);
}
 
/* Load an OGG stream from an SDL_RWops object */
OGG_music *OGG_new_RW(SDL_RWops *rw, int freerw)
{
OGG_music *music;
ov_callbacks callbacks;
 
if ( !Mix_Init(MIX_INIT_OGG) ) {
if ( freerw ) {
SDL_RWclose(rw);
}
return(NULL);
}
 
SDL_memset(&callbacks, 0, sizeof(callbacks));
callbacks.read_func = sdl_read_func;
callbacks.seek_func = sdl_seek_func;
callbacks.tell_func = sdl_tell_func;
 
music = (OGG_music *)SDL_malloc(sizeof *music);
if ( music ) {
/* Initialize the music structure */
memset(music, 0, (sizeof *music));
music->rw = rw;
music->freerw = freerw;
OGG_stop(music);
OGG_setvolume(music, MIX_MAX_VOLUME);
music->section = -1;
 
if ( vorbis.ov_open_callbacks(rw, &music->vf, NULL, 0, callbacks) < 0 ) {
SDL_free(music);
if ( freerw ) {
SDL_RWclose(rw);
}
SDL_SetError("Not an Ogg Vorbis audio stream");
return(NULL);
}
} else {
if ( freerw ) {
SDL_RWclose(rw);
}
SDL_OutOfMemory();
return(NULL);
}
return(music);
}
 
/* Start playback of a given OGG stream */
void OGG_play(OGG_music *music)
{
music->playing = 1;
}
 
/* Return non-zero if a stream is currently playing */
int OGG_playing(OGG_music *music)
{
return(music->playing);
}
 
/* Read some Ogg stream data and convert it for output */
static void OGG_getsome(OGG_music *music)
{
int section;
int len;
char data[4096];
SDL_AudioCVT *cvt;
 
#ifdef OGG_USE_TREMOR
len = vorbis.ov_read(&music->vf, data, sizeof(data), &section);
#else
len = vorbis.ov_read(&music->vf, data, sizeof(data), 0, 2, 1, &section);
#endif
if ( len <= 0 ) {
if ( len == 0 ) {
music->playing = 0;
}
return;
}
cvt = &music->cvt;
if ( section != music->section ) {
vorbis_info *vi;
 
vi = vorbis.ov_info(&music->vf, -1);
SDL_BuildAudioCVT(cvt, AUDIO_S16, vi->channels, vi->rate,
mixer.format,mixer.channels,mixer.freq);
if ( cvt->buf ) {
SDL_free(cvt->buf);
}
cvt->buf = (Uint8 *)SDL_malloc(sizeof(data)*cvt->len_mult);
music->section = section;
}
if ( cvt->buf ) {
memcpy(cvt->buf, data, len);
if ( cvt->needed ) {
cvt->len = len;
SDL_ConvertAudio(cvt);
} else {
cvt->len_cvt = len;
}
music->len_available = music->cvt.len_cvt;
music->snd_available = music->cvt.buf;
} else {
SDL_SetError("Out of memory");
music->playing = 0;
}
}
 
/* Play some of a stream previously started with OGG_play() */
int OGG_playAudio(OGG_music *music, Uint8 *snd, int len)
{
int mixable;
 
while ( (len > 0) && music->playing ) {
if ( ! music->len_available ) {
OGG_getsome(music);
}
mixable = len;
if ( mixable > music->len_available ) {
mixable = music->len_available;
}
if ( music->volume == MIX_MAX_VOLUME ) {
memcpy(snd, music->snd_available, mixable);
} else {
SDL_MixAudio(snd, music->snd_available, mixable,
music->volume);
}
music->len_available -= mixable;
music->snd_available += mixable;
len -= mixable;
snd += mixable;
}
return len;
}
 
/* Stop playback of a stream previously started with OGG_play() */
void OGG_stop(OGG_music *music)
{
music->playing = 0;
}
 
/* Close the given OGG stream */
void OGG_delete(OGG_music *music)
{
if ( music ) {
if ( music->cvt.buf ) {
SDL_free(music->cvt.buf);
}
if ( music->freerw ) {
SDL_RWclose(music->rw);
}
vorbis.ov_clear(&music->vf);
SDL_free(music);
}
}
 
/* Jump (seek) to a given position (time is in seconds) */
void OGG_jump_to_time(OGG_music *music, double time)
{
#ifdef OGG_USE_TREMOR
vorbis.ov_time_seek( &music->vf, (ogg_int64_t)time );
#else
vorbis.ov_time_seek( &music->vf, time );
#endif
}
 
#endif /* OGG_MUSIC */
/contrib/sdk/sources/SDL_mixer-1.2.12/music_ogg.h
0,0 → 1,75
/*
SDL_mixer: An audio mixer library based on the SDL library
Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
 
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
 
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
 
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
 
/* $Id$ */
 
#ifdef OGG_MUSIC
 
/* This file supports Ogg Vorbis music streams */
 
#ifdef OGG_USE_TREMOR
#include <tremor/ivorbisfile.h>
#else
#include <vorbis/vorbisfile.h>
#endif
 
typedef struct {
SDL_RWops *rw;
int freerw;
int playing;
int volume;
OggVorbis_File vf;
int section;
SDL_AudioCVT cvt;
int len_available;
Uint8 *snd_available;
} OGG_music;
 
/* Initialize the Ogg Vorbis player, with the given mixer settings
This function returns 0, or -1 if there was an error.
*/
extern int OGG_init(SDL_AudioSpec *mixer);
 
/* Set the volume for an OGG stream */
extern void OGG_setvolume(OGG_music *music, int volume);
 
/* Load an OGG stream from an SDL_RWops object */
extern OGG_music *OGG_new_RW(SDL_RWops *rw, int freerw);
 
/* Start playback of a given OGG stream */
extern void OGG_play(OGG_music *music);
 
/* Return non-zero if a stream is currently playing */
extern int OGG_playing(OGG_music *music);
 
/* Play some of a stream previously started with OGG_play() */
extern int OGG_playAudio(OGG_music *music, Uint8 *stream, int len);
 
/* Stop playback of a stream previously started with OGG_play() */
extern void OGG_stop(OGG_music *music);
 
/* Close the given OGG stream */
extern void OGG_delete(OGG_music *music);
 
/* Jump (seek) to a given position (time is in seconds) */
extern void OGG_jump_to_time(OGG_music *music, double time);
 
#endif /* OGG_MUSIC */
/contrib/sdk/sources/SDL_mixer-1.2.12/native_midi/native_midi.h
0,0 → 1,38
/*
native_midi: Hardware Midi support for the SDL_mixer library
Copyright (C) 2000 Florian 'Proff' Schulze <florian.proff.schulze@gmx.net>
 
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
 
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
 
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
 
#ifndef _NATIVE_MIDI_H_
#define _NATIVE_MIDI_H_
 
#include <SDL_rwops.h>
 
typedef struct _NativeMidiSong NativeMidiSong;
 
int native_midi_detect();
NativeMidiSong *native_midi_loadsong_RW(SDL_RWops *rw, int freerw);
void native_midi_freesong(NativeMidiSong *song);
void native_midi_start(NativeMidiSong *song, int loops);
void native_midi_stop();
int native_midi_active();
void native_midi_setvolume(int volume);
const char *native_midi_error(void);
 
#endif /* _NATIVE_MIDI_H_ */
/contrib/sdk/sources/SDL_mixer-1.2.12/native_midi/native_midi_common.c
0,0 → 1,409
/*
native_midi: Hardware Midi support for the SDL_mixer library
Copyright (C) 2000,2001 Florian 'Proff' Schulze <florian.proff.schulze@gmx.net>
 
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
 
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
 
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
 
 
#include "native_midi_common.h"
 
#include "../SDL_mixer.h"
 
#include <stdlib.h>
#include <string.h>
#include <limits.h>
 
 
/* The maximum number of midi tracks that we can handle
#define MIDI_TRACKS 32 */
 
 
/* A single midi track as read from the midi file */
typedef struct
{
Uint8 *data; /* MIDI message stream */
int len; /* length of the track data */
} MIDITrack;
 
/* A midi file, stripped down to the absolute minimum - divison & track data */
typedef struct
{
int division; /* number of pulses per quarter note (ppqn) */
int nTracks; /* number of tracks */
MIDITrack *track; /* tracks */
} MIDIFile;
 
 
/* Some macros that help us stay endianess-independant */
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
#define BE_SHORT(x) (x)
#define BE_LONG(x) (x)
#else
#define BE_SHORT(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF))
#define BE_LONG(x) ((((x)&0x0000FF)<<24) | \
(((x)&0x00FF00)<<8) | \
(((x)&0xFF0000)>>8) | \
(((x)>>24)&0xFF))
#endif
 
 
 
/* Get Variable Length Quantity */
static int GetVLQ(MIDITrack *track, int *currentPos)
{
int l = 0;
Uint8 c;
while(1)
{
c = track->data[*currentPos];
(*currentPos)++;
l += (c & 0x7f);
if (!(c & 0x80))
return l;
l <<= 7;
}
}
 
/* Create a single MIDIEvent */
static MIDIEvent *CreateEvent(Uint32 time, Uint8 event, Uint8 a, Uint8 b)
{
MIDIEvent *newEvent;
newEvent = calloc(1, sizeof(MIDIEvent));
 
if (newEvent)
{
newEvent->time = time;
newEvent->status = event;
newEvent->data[0] = a;
newEvent->data[1] = b;
}
else
Mix_SetError("Out of memory");
return newEvent;
}
 
/* Convert a single midi track to a list of MIDIEvents */
static MIDIEvent *MIDITracktoStream(MIDITrack *track)
{
Uint32 atime = 0;
Uint32 len = 0;
Uint8 event,type,a,b;
Uint8 laststatus = 0;
Uint8 lastchan = 0;
int currentPos = 0;
int end = 0;
MIDIEvent *head = CreateEvent(0,0,0,0); /* dummy event to make handling the list easier */
MIDIEvent *currentEvent = head;
 
while (!end)
{
if (currentPos >= track->len)
break; /* End of data stream reached */
 
atime += GetVLQ(track, &currentPos);
event = track->data[currentPos++];
/* Handle SysEx seperatly */
if (((event>>4) & 0x0F) == MIDI_STATUS_SYSEX)
{
if (event == 0xFF)
{
type = track->data[currentPos];
currentPos++;
switch(type)
{
case 0x2f: /* End of data marker */
end = 1;
case 0x51: /* Tempo change */
/*
a=track->data[currentPos];
b=track->data[currentPos+1];
c=track->data[currentPos+2];
AddEvent(song, atime, MEVT_TEMPO, c, b, a);
*/
break;
}
}
else
type = 0;
 
len = GetVLQ(track, &currentPos);
/* Create an event and attach the extra data, if any */
currentEvent->next = CreateEvent(atime, event, type, 0);
currentEvent = currentEvent->next;
if (NULL == currentEvent)
{
FreeMIDIEventList(head);
return NULL;
}
if (len)
{
currentEvent->extraLen = len;
currentEvent->extraData = malloc(len);
memcpy(currentEvent->extraData, &(track->data[currentPos]), len);
currentPos += len;
}
}
else
{
a = event;
if (a & 0x80) /* It's a status byte */
{
/* Extract channel and status information */
lastchan = a & 0x0F;
laststatus = (a>>4) & 0x0F;
/* Read the next byte which should always be a data byte */
a = track->data[currentPos++] & 0x7F;
}
switch(laststatus)
{
case MIDI_STATUS_NOTE_OFF:
case MIDI_STATUS_NOTE_ON: /* Note on */
case MIDI_STATUS_AFTERTOUCH: /* Key Pressure */
case MIDI_STATUS_CONTROLLER: /* Control change */
case MIDI_STATUS_PITCH_WHEEL: /* Pitch wheel */
b = track->data[currentPos++] & 0x7F;
currentEvent->next = CreateEvent(atime, (Uint8)((laststatus<<4)+lastchan), a, b);
currentEvent = currentEvent->next;
if (NULL == currentEvent)
{
FreeMIDIEventList(head);
return NULL;
}
break;
 
case MIDI_STATUS_PROG_CHANGE: /* Program change */
case MIDI_STATUS_PRESSURE: /* Channel pressure */
a &= 0x7f;
currentEvent->next = CreateEvent(atime, (Uint8)((laststatus<<4)+lastchan), a, 0);
currentEvent = currentEvent->next;
if (NULL == currentEvent)
{
FreeMIDIEventList(head);
return NULL;
}
break;
 
default: /* Sysex already handled above */
break;
}
}
}
currentEvent = head->next;
free(head); /* release the dummy head event */
return currentEvent;
}
 
/*
* Convert a midi song, consisting of up to 32 tracks, to a list of MIDIEvents.
* To do so, first convert the tracks seperatly, then interweave the resulting
* MIDIEvent-Lists to one big list.
*/
static MIDIEvent *MIDItoStream(MIDIFile *mididata)
{
MIDIEvent **track;
MIDIEvent *head = CreateEvent(0,0,0,0); /* dummy event to make handling the list easier */
MIDIEvent *currentEvent = head;
int trackID;
 
if (NULL == head)
return NULL;
track = (MIDIEvent**) calloc(1, sizeof(MIDIEvent*) * mididata->nTracks);
if (NULL == head)
return NULL;
/* First, convert all tracks to MIDIEvent lists */
for (trackID = 0; trackID < mididata->nTracks; trackID++)
track[trackID] = MIDITracktoStream(&mididata->track[trackID]);
 
/* Now, merge the lists. */
/* TODO */
while(1)
{
Uint32 lowestTime = INT_MAX;
int currentTrackID = -1;
/* Find the next event */
for (trackID = 0; trackID < mididata->nTracks; trackID++)
{
if (track[trackID] && (track[trackID]->time < lowestTime))
{
currentTrackID = trackID;
lowestTime = track[currentTrackID]->time;
}
}
/* Check if we processes all events */
if (currentTrackID == -1)
break;
currentEvent->next = track[currentTrackID];
track[currentTrackID] = track[currentTrackID]->next;
 
currentEvent = currentEvent->next;
lowestTime = 0;
}
 
/* Make sure the list is properly terminated */
currentEvent->next = 0;
 
currentEvent = head->next;
free(track);
free(head); /* release the dummy head event */
return currentEvent;
}
 
static int ReadMIDIFile(MIDIFile *mididata, SDL_RWops *rw)
{
int i = 0;
Uint32 ID;
Uint32 size;
Uint16 format;
Uint16 tracks;
Uint16 division;
 
if (!mididata)
return 0;
if (!rw)
return 0;
 
/* Make sure this is really a MIDI file */
SDL_RWread(rw, &ID, 1, 4);
if (BE_LONG(ID) != 'MThd')
return 0;
/* Header size must be 6 */
SDL_RWread(rw, &size, 1, 4);
size = BE_LONG(size);
if (size != 6)
return 0;
/* We only support format 0 and 1, but not 2 */
SDL_RWread(rw, &format, 1, 2);
format = BE_SHORT(format);
if (format != 0 && format != 1)
return 0;
SDL_RWread(rw, &tracks, 1, 2);
tracks = BE_SHORT(tracks);
mididata->nTracks = tracks;
/* Allocate tracks */
mididata->track = (MIDITrack*) calloc(1, sizeof(MIDITrack) * mididata->nTracks);
if (NULL == mididata->track)
{
Mix_SetError("Out of memory");
goto bail;
}
/* Retrieve the PPQN value, needed for playback */
SDL_RWread(rw, &division, 1, 2);
mididata->division = BE_SHORT(division);
for (i=0; i<tracks; i++)
{
SDL_RWread(rw, &ID, 1, 4); /* We might want to verify this is MTrk... */
SDL_RWread(rw, &size, 1, 4);
size = BE_LONG(size);
mididata->track[i].len = size;
mididata->track[i].data = malloc(size);
if (NULL == mididata->track[i].data)
{
Mix_SetError("Out of memory");
goto bail;
}
SDL_RWread(rw, mididata->track[i].data, 1, size);
}
return 1;
 
bail:
for(;i >= 0; i--)
{
if (mididata->track[i].data)
free(mididata->track[i].data);
}
 
return 0;
}
 
MIDIEvent *CreateMIDIEventList(SDL_RWops *rw, Uint16 *division)
{
MIDIFile *mididata = NULL;
MIDIEvent *eventList;
int trackID;
mididata = calloc(1, sizeof(MIDIFile));
if (!mididata)
return NULL;
 
/* Open the file */
if ( rw != NULL )
{
/* Read in the data */
if ( ! ReadMIDIFile(mididata, rw))
{
free(mididata);
return NULL;
}
}
else
{
free(mididata);
return NULL;
}
if (division)
*division = mididata->division;
eventList = MIDItoStream(mididata);
for(trackID = 0; trackID < mididata->nTracks; trackID++)
{
if (mididata->track[trackID].data)
free(mididata->track[trackID].data);
}
free(mididata->track);
free(mididata);
return eventList;
}
 
void FreeMIDIEventList(MIDIEvent *head)
{
MIDIEvent *cur, *next;
cur = head;
 
while (cur)
{
next = cur->next;
if (cur->extraData)
free (cur->extraData);
free (cur);
cur = next;
}
}
/contrib/sdk/sources/SDL_mixer-1.2.12/native_midi/native_midi_common.h
0,0 → 1,63
/*
native_midi: Hardware Midi support for the SDL_mixer library
Copyright (C) 2000,2001 Florian 'Proff' Schulze <florian.proff.schulze@gmx.net>
 
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
 
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
 
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
 
#ifndef _NATIVE_MIDI_COMMON_H_
#define _NATIVE_MIDI_COMMON_H_
 
#include "SDL.h"
 
/* Midi Status Bytes */
#define MIDI_STATUS_NOTE_OFF 0x8
#define MIDI_STATUS_NOTE_ON 0x9
#define MIDI_STATUS_AFTERTOUCH 0xA
#define MIDI_STATUS_CONTROLLER 0xB
#define MIDI_STATUS_PROG_CHANGE 0xC
#define MIDI_STATUS_PRESSURE 0xD
#define MIDI_STATUS_PITCH_WHEEL 0xE
#define MIDI_STATUS_SYSEX 0xF
 
/* We store the midi events in a linked list; this way it is
easy to shuffle the tracks together later on; and we are
flexible in the size of each elemnt.
*/
typedef struct MIDIEvent
{
Uint32 time; /* Time at which this midi events occurs */
Uint8 status; /* Status byte */
Uint8 data[2]; /* 1 or 2 bytes additional data for most events */
 
Uint32 extraLen; /* For some SysEx events, we need additional storage */
Uint8 *extraData;
struct MIDIEvent *next;
} MIDIEvent;
 
 
/* Load a midifile to memory, converting it to a list of MIDIEvents.
This function returns a linked lists of MIDIEvents, 0 if an error occured.
*/
MIDIEvent *CreateMIDIEventList(SDL_RWops *rw, Uint16 *division);
 
/* Release a MIDIEvent list after usage. */
void FreeMIDIEventList(MIDIEvent *head);
 
 
#endif /* _NATIVE_MIDI_COMMON_H_ */
/contrib/sdk/sources/SDL_mixer-1.2.12/native_midi/native_midi_haiku.cpp
0,0 → 1,281
/*
native_midi_haiku: Native Midi support on Haiku for the SDL_mixer library
Copyright (C) 2010 Egor Suvorov <egor_suvorov@mail.ru>
 
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
 
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
 
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_config.h"
 
#ifdef __HAIKU__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <MidiStore.h>
#include <MidiDefs.h>
#include <MidiSynthFile.h>
#include <algorithm>
#include <assert.h>
extern "C" {
#include "native_midi.h"
#include "native_midi_common.h"
}
 
bool compareMIDIEvent(const MIDIEvent &a, const MIDIEvent &b)
{
return a.time < b.time;
}
 
class MidiEventsStore : public BMidi
{
public:
MidiEventsStore()
{
fPlaying = false;
fLoops = 0;
}
virtual status_t Import(SDL_RWops *rw)
{
fEvs = CreateMIDIEventList(rw, &fDivision);
if (!fEvs) {
return B_BAD_MIDI_DATA;
}
fTotal = 0;
for (MIDIEvent *x = fEvs; x; x = x->next) fTotal++;
fPos = fTotal;
 
sort_events();
return B_OK;
}
virtual void Run()
{
fPlaying = true;
fPos = 0;
MIDIEvent *ev = fEvs;
 
uint32 startTime = B_NOW;
while (KeepRunning())
{
if (!ev) {
if (fLoops && fEvs) {
--fLoops;
fPos = 0;
ev = fEvs;
} else
break;
}
SprayEvent(ev, ev->time + startTime);
ev = ev->next;
fPos++;
}
fPos = fTotal;
fPlaying = false;
}
virtual ~MidiEventsStore()
{
if (!fEvs) return;
FreeMIDIEventList(fEvs);
fEvs = 0;
}
 
bool IsPlaying()
{
return fPlaying;
}
 
void SetLoops(int loops)
{
fLoops = loops;
}
 
protected:
MIDIEvent *fEvs;
Uint16 fDivision;
 
int fPos, fTotal;
int fLoops;
bool fPlaying;
 
void SprayEvent(MIDIEvent *ev, uint32 time)
{
switch (ev->status & 0xF0)
{
case B_NOTE_OFF:
SprayNoteOff((ev->status & 0x0F) + 1, ev->data[0], ev->data[1], time);
break;
case B_NOTE_ON:
SprayNoteOn((ev->status & 0x0F) + 1, ev->data[0], ev->data[1], time);
break;
case B_KEY_PRESSURE:
SprayKeyPressure((ev->status & 0x0F) + 1, ev->data[0], ev->data[1], time);
break;
case B_CONTROL_CHANGE:
SprayControlChange((ev->status & 0x0F) + 1, ev->data[0], ev->data[1], time);
break;
case B_PROGRAM_CHANGE:
SprayProgramChange((ev->status & 0x0F) + 1, ev->data[0], time);
break;
case B_CHANNEL_PRESSURE:
SprayChannelPressure((ev->status & 0x0F) + 1, ev->data[0], time);
break;
case B_PITCH_BEND:
SprayPitchBend((ev->status & 0x0F) + 1, ev->data[0], ev->data[1], time);
break;
case 0xF:
switch (ev->status)
{
case B_SYS_EX_START:
SpraySystemExclusive(ev->extraData, ev->extraLen, time);
break;
case B_MIDI_TIME_CODE:
case B_SONG_POSITION:
case B_SONG_SELECT:
case B_CABLE_MESSAGE:
case B_TUNE_REQUEST:
case B_SYS_EX_END:
SpraySystemCommon(ev->status, ev->data[0], ev->data[1], time);
break;
case B_TIMING_CLOCK:
case B_START:
case B_STOP:
case B_CONTINUE:
case B_ACTIVE_SENSING:
SpraySystemRealTime(ev->status, time);
break;
case B_SYSTEM_RESET:
if (ev->data[0] == 0x51 && ev->data[1] == 0x03)
{
assert(ev->extraLen == 3);
int val = (ev->extraData[0] << 16) | (ev->extraData[1] << 8) | ev->extraData[2];
int tempo = 60000000 / val;
SprayTempoChange(tempo, time);
}
else
{
SpraySystemRealTime(ev->status, time);
}
}
break;
}
}
 
void sort_events()
{
MIDIEvent *items = new MIDIEvent[fTotal];
MIDIEvent *x = fEvs;
for (int i = 0; i < fTotal; i++)
{
memcpy(items + i, x, sizeof(MIDIEvent));
x = x->next;
}
std::sort(items, items + fTotal, compareMIDIEvent);
 
x = fEvs;
for (int i = 0; i < fTotal; i++)
{
MIDIEvent *ne = x->next;
memcpy(x, items + i, sizeof(MIDIEvent));
x->next = ne;
x = ne;
}
 
for (x = fEvs; x && x->next; x = x->next)
assert(x->time <= x->next->time);
 
delete[] items;
}
};
 
BMidiSynth synth;
struct _NativeMidiSong {
MidiEventsStore *store;
} *currentSong = NULL;
 
char lasterr[1024];
 
int native_midi_detect()
{
status_t res = synth.EnableInput(true, false);
return res == B_OK;
}
 
void native_midi_setvolume(int volume)
{
if (volume < 0) volume = 0;
if (volume > 128) volume = 128;
synth.SetVolume(volume / 128.0);
}
 
NativeMidiSong *native_midi_loadsong_RW(SDL_RWops *rw, int freerw)
{
NativeMidiSong *song = new NativeMidiSong;
song->store = new MidiEventsStore;
status_t res = song->store->Import(rw);
 
if (freerw) {
SDL_RWclose(rw);
}
if (res != B_OK)
{
snprintf(lasterr, sizeof lasterr, "Cannot Import() midi file: status_t=%d", res);
delete song->store;
delete song;
return NULL;
}
return song;
}
 
void native_midi_freesong(NativeMidiSong *song)
{
if (song == NULL) return;
song->store->Stop();
song->store->Disconnect(&synth);
if (currentSong == song)
{
currentSong = NULL;
}
delete song->store;
delete song; song = 0;
}
void native_midi_start(NativeMidiSong *song, int loops)
{
native_midi_stop();
song->store->Connect(&synth);
song->store->SetLoops(loops);
song->store->Start();
currentSong = song;
}
void native_midi_stop()
{
if (currentSong == NULL) return;
currentSong->store->Stop();
currentSong->store->Disconnect(&synth);
while (currentSong->store->IsPlaying())
usleep(1000);
currentSong = NULL;
}
int native_midi_active()
{
if (currentSong == NULL) return 0;
return currentSong->store->IsPlaying();
}
 
const char* native_midi_error(void)
{
return lasterr;
}
 
#endif /* __HAIKU__ */
/contrib/sdk/sources/SDL_mixer-1.2.12/native_midi/native_midi_mac.c
0,0 → 1,644
/*
native_midi_mac: Native Midi support on MacOS for the SDL_mixer library
Copyright (C) 2001 Max Horn <max@quendi.de>
 
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
 
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
 
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_config.h"
#include "SDL_endian.h"
 
#if __MACOS__ /*|| __MACOSX__ */
 
#include "native_midi.h"
#include "native_midi_common.h"
 
#if __MACOSX__
#include <QuickTime/QuickTimeMusic.h>
#else
#include <QuickTimeMusic.h>
#endif
 
#include <assert.h>
#include <stdlib.h>
#include <string.h>
 
 
/* Native Midi song */
struct _NativeMidiSong
{
Uint32 *tuneSequence;
Uint32 *tuneHeader;
};
 
enum
{
/* number of (32-bit) long words in a note request event */
kNoteRequestEventLength = ((sizeof(NoteRequest)/sizeof(long)) + 2),
 
/* number of (32-bit) long words in a marker event */
kMarkerEventLength = 1,
 
/* number of (32-bit) long words in a general event, minus its data */
kGeneralEventLength = 2
};
 
#define ERROR_BUF_SIZE 256
#define BUFFER_INCREMENT 5000
 
#define REST_IF_NECESSARY() do {\
int timeDiff = eventPos->time - lastEventTime; \
if(timeDiff) \
{ \
timeDiff = (int)(timeDiff*tick); \
qtma_StuffRestEvent(*tunePos, timeDiff); \
tunePos++; \
lastEventTime = eventPos->time; \
} \
} while(0)
 
 
static Uint32 *BuildTuneSequence(MIDIEvent *evntlist, int ppqn, int part_poly_max[32], int part_to_inst[32], int *numParts);
static Uint32 *BuildTuneHeader(int part_poly_max[32], int part_to_inst[32], int numParts);
 
/* The global TunePlayer instance */
static TunePlayer gTunePlayer = NULL;
static int gInstaceCount = 0;
static Uint32 *gCurrentTuneSequence = NULL;
static char gErrorBuffer[ERROR_BUF_SIZE] = "";
 
 
/* Check whether QuickTime is available */
int native_midi_detect()
{
/* TODO */
return 1;
}
 
NativeMidiSong *native_midi_loadsong_RW(SDL_RWops *rw, int freerw)
{
NativeMidiSong *song = NULL;
MIDIEvent *evntlist = NULL;
int part_to_inst[32];
int part_poly_max[32];
int numParts = 0;
Uint16 ppqn;
 
/* Init the arrays */
memset(part_poly_max,0,sizeof(part_poly_max));
memset(part_to_inst,-1,sizeof(part_to_inst));
/* Attempt to load the midi file */
evntlist = CreateMIDIEventList(rw, &ppqn);
if (!evntlist)
goto bail;
 
/* Allocate memory for the song struct */
song = malloc(sizeof(NativeMidiSong));
if (!song)
goto bail;
 
/* Build a tune sequence from the event list */
song->tuneSequence = BuildTuneSequence(evntlist, ppqn, part_poly_max, part_to_inst, &numParts);
if(!song->tuneSequence)
goto bail;
 
/* Now build a tune header from the data we collect above, create
all parts as needed and assign them the correct instrument.
*/
song->tuneHeader = BuildTuneHeader(part_poly_max, part_to_inst, numParts);
if(!song->tuneHeader)
goto bail;
/* Increment the instance count */
gInstaceCount++;
if (gTunePlayer == NULL)
gTunePlayer = OpenDefaultComponent(kTunePlayerComponentType, 0);
 
/* Finally, free the event list */
FreeMIDIEventList(evntlist);
 
if (freerw) {
SDL_RWclose(rw);
}
return song;
bail:
if (evntlist)
FreeMIDIEventList(evntlist);
if (song)
{
if(song->tuneSequence)
free(song->tuneSequence);
if(song->tuneHeader)
DisposePtr((Ptr)song->tuneHeader);
 
free(song);
}
if (freerw) {
SDL_RWclose(rw);
}
return NULL;
}
 
void native_midi_freesong(NativeMidiSong *song)
{
if(!song || !song->tuneSequence)
return;
 
/* If this is the currently playing song, stop it now */
if (song->tuneSequence == gCurrentTuneSequence)
native_midi_stop();
/* Finally, free the data storage */
free(song->tuneSequence);
DisposePtr((Ptr)song->tuneHeader);
free(song);
 
/* Increment the instance count */
gInstaceCount--;
if ((gTunePlayer != NULL) && (gInstaceCount == 0))
{
CloseComponent(gTunePlayer);
gTunePlayer = NULL;
}
}
 
void native_midi_start(NativeMidiSong *song, int loops)
{
UInt32 queueFlags = 0;
ComponentResult tpError;
assert (gTunePlayer != NULL);
 
/* FIXME: is this code even used anymore? */
assert (loops == 0);
SDL_PauseAudio(1);
SDL_UnlockAudio();
/* First, stop the currently playing music */
native_midi_stop();
/* Set up the queue flags */
queueFlags = kTuneStartNow;
 
/* Set the time scale (units per second), we want milliseconds */
tpError = TuneSetTimeScale(gTunePlayer, 1000);
if (tpError != noErr)
{
strncpy (gErrorBuffer, "MIDI error during TuneSetTimeScale", ERROR_BUF_SIZE);
goto done;
}
 
/* Set the header, to tell what instruments are used */
tpError = TuneSetHeader(gTunePlayer, (UInt32 *)song->tuneHeader);
if (tpError != noErr)
{
strncpy (gErrorBuffer, "MIDI error during TuneSetHeader", ERROR_BUF_SIZE);
goto done;
}
/* Have it allocate whatever resources are needed */
tpError = TunePreroll(gTunePlayer);
if (tpError != noErr)
{
strncpy (gErrorBuffer, "MIDI error during TunePreroll", ERROR_BUF_SIZE);
goto done;
}
 
/* We want to play at normal volume */
tpError = TuneSetVolume(gTunePlayer, 0x00010000);
if (tpError != noErr)
{
strncpy (gErrorBuffer, "MIDI error during TuneSetVolume", ERROR_BUF_SIZE);
goto done;
}
/* Finally, start playing the full song */
gCurrentTuneSequence = song->tuneSequence;
tpError = TuneQueue(gTunePlayer, (UInt32 *)song->tuneSequence, 0x00010000, 0, 0xFFFFFFFF, queueFlags, NULL, 0);
if (tpError != noErr)
{
strncpy (gErrorBuffer, "MIDI error during TuneQueue", ERROR_BUF_SIZE);
goto done;
}
done:
SDL_LockAudio();
SDL_PauseAudio(0);
}
 
void native_midi_stop()
{
if (gTunePlayer == NULL)
return;
 
/* Stop music */
TuneStop(gTunePlayer, 0);
/* Deallocate all instruments */
TuneUnroll(gTunePlayer);
}
 
int native_midi_active()
{
if (gTunePlayer != NULL)
{
TuneStatus ts;
 
TuneGetStatus(gTunePlayer,&ts);
return ts.queueTime != 0;
}
else
return 0;
}
 
void native_midi_setvolume(int volume)
{
if (gTunePlayer == NULL)
return;
 
/* QTMA olume may range from 0.0 to 1.0 (in 16.16 fixed point encoding) */
TuneSetVolume(gTunePlayer, (0x00010000 * volume)/SDL_MIX_MAXVOLUME);
}
 
const char *native_midi_error(void)
{
return gErrorBuffer;
}
 
Uint32 *BuildTuneSequence(MIDIEvent *evntlist, int ppqn, int part_poly_max[32], int part_to_inst[32], int *numParts)
{
int part_poly[32];
int channel_to_part[16];
int channel_pan[16];
int channel_vol[16];
int channel_pitch_bend[16];
int lastEventTime = 0;
int tempo = 500000;
double Ippqn = 1.0 / (1000*ppqn);
double tick = tempo * Ippqn;
MIDIEvent *eventPos = evntlist;
MIDIEvent *noteOffPos;
Uint32 *tunePos, *endPos;
Uint32 *tuneSequence;
size_t tuneSize;
/* allocate space for the tune header */
tuneSize = 5000;
tuneSequence = (Uint32 *)malloc(tuneSize * sizeof(Uint32));
if (tuneSequence == NULL)
return NULL;
/* Set starting position in our tune memory */
tunePos = tuneSequence;
endPos = tuneSequence + tuneSize;
 
/* Initialise the arrays */
memset(part_poly,0,sizeof(part_poly));
memset(channel_to_part,-1,sizeof(channel_to_part));
memset(channel_pan,-1,sizeof(channel_pan));
memset(channel_vol,-1,sizeof(channel_vol));
memset(channel_pitch_bend,-1,sizeof(channel_pitch_bend));
*numParts = 0;
/*
* Now the major work - iterate over all GM events,
* and turn them into QuickTime Music format.
* At the same time, calculate the max. polyphony for each part,
* and also the part->instrument mapping.
*/
while(eventPos)
{
int status = (eventPos->status&0xF0)>>4;
int channel = eventPos->status&0x0F;
int part = channel_to_part[channel];
int velocity, pitch;
int value, controller;
int bend;
int newInst;
/* Check if we are running low on space... */
if((tunePos+16) > endPos)
{
/* Resize our data storage. */
Uint32 *oldTuneSequence = tuneSequence;
 
tuneSize += BUFFER_INCREMENT;
tuneSequence = (Uint32 *)realloc(tuneSequence, tuneSize * sizeof(Uint32));
if(oldTuneSequence != tuneSequence)
tunePos += tuneSequence - oldTuneSequence;
endPos = tuneSequence + tuneSize;
}
switch (status)
{
case MIDI_STATUS_NOTE_OFF:
assert(part>=0 && part<=31);
 
/* Keep track of the polyphony of the current part */
part_poly[part]--;
break;
case MIDI_STATUS_NOTE_ON:
if (part < 0)
{
/* If no part is specified yet, we default to the first instrument, which
is piano (or the first drum kit if we are on the drum channel)
*/
int newInst;
if (channel == 9)
newInst = kFirstDrumkit + 1; /* the first drum kit is the "no drum" kit! */
else
newInst = kFirstGMInstrument;
part = channel_to_part[channel] = *numParts;
part_to_inst[(*numParts)++] = newInst;
}
/* TODO - add support for more than 32 parts using eXtended QTMA events */
assert(part<=31);
/* Decode pitch & velocity */
pitch = eventPos->data[0];
velocity = eventPos->data[1];
if (velocity == 0)
{
/* was a NOTE OFF in disguise, so we decrement the polyphony */
part_poly[part]--;
}
else
{
/* Keep track of the polyphony of the current part */
int foo = ++part_poly[part];
if (part_poly_max[part] < foo)
part_poly_max[part] = foo;
 
/* Now scan forward to find the matching NOTE OFF event */
for(noteOffPos = eventPos; noteOffPos; noteOffPos = noteOffPos->next)
{
if ((noteOffPos->status&0xF0)>>4 == MIDI_STATUS_NOTE_OFF
&& channel == (eventPos->status&0x0F)
&& pitch == noteOffPos->data[0])
break;
/* NOTE ON with velocity == 0 is the same as a NOTE OFF */
if ((noteOffPos->status&0xF0)>>4 == MIDI_STATUS_NOTE_ON
&& channel == (eventPos->status&0x0F)
&& pitch == noteOffPos->data[0]
&& 0 == noteOffPos->data[1])
break;
}
/* Did we find a note off? Should always be the case, but who knows... */
if (noteOffPos)
{
/* We found a NOTE OFF, now calculate the note duration */
int duration = (int)((noteOffPos->time - eventPos->time)*tick);
REST_IF_NECESSARY();
/* Now we need to check if we get along with a normal Note Event, or if we need an extended one... */
if (duration < 2048 && pitch>=32 && pitch<=95 && velocity>=0 && velocity<=127)
{
qtma_StuffNoteEvent(*tunePos, part, pitch, velocity, duration);
tunePos++;
}
else
{
qtma_StuffXNoteEvent(*tunePos, *(tunePos+1), part, pitch, velocity, duration);
tunePos+=2;
}
}
}
break;
case MIDI_STATUS_AFTERTOUCH:
/* NYI - use kControllerAfterTouch. But how are the parameters to be mapped? */
break;
case MIDI_STATUS_CONTROLLER:
controller = eventPos->data[0];
value = eventPos->data[1];
 
switch(controller)
{
case 0: /* bank change - igore for now */
break;
case kControllerVolume:
if(channel_vol[channel] != value<<8)
{
channel_vol[channel] = value<<8;
if(part>=0 && part<=31)
{
REST_IF_NECESSARY();
qtma_StuffControlEvent(*tunePos, part, kControllerVolume, channel_vol[channel]);
tunePos++;
}
}
break;
case kControllerPan:
if(channel_pan[channel] != (value << 1) + 256)
{
channel_pan[channel] = (value << 1) + 256;
if(part>=0 && part<=31)
{
REST_IF_NECESSARY();
qtma_StuffControlEvent(*tunePos, part, kControllerPan, channel_pan[channel]);
tunePos++;
}
}
break;
default:
/* No other controllers implemented yet */;
break;
}
break;
case MIDI_STATUS_PROG_CHANGE:
/* Instrument changed */
newInst = eventPos->data[0];
/* Channel 9 (the 10th channel) is different, it indicates a drum kit */
if (channel == 9)
newInst += kFirstDrumkit;
else
newInst += kFirstGMInstrument;
/* Only if the instrument for this channel *really* changed, add a new part. */
if(newInst != part_to_inst[part])
{
/* TODO maybe make use of kGeneralEventPartChange here,
to help QT reuse note channels?
*/
part = channel_to_part[channel] = *numParts;
part_to_inst[(*numParts)++] = newInst;
 
if(channel_vol[channel] >= 0)
{
REST_IF_NECESSARY();
qtma_StuffControlEvent(*tunePos, part, kControllerVolume, channel_vol[channel]);
tunePos++;
}
if(channel_pan[channel] >= 0)
{
REST_IF_NECESSARY();
qtma_StuffControlEvent(*tunePos, part, kControllerPan, channel_pan[channel]);
tunePos++;
}
if(channel_pitch_bend[channel] >= 0)
{
REST_IF_NECESSARY();
qtma_StuffControlEvent(*tunePos, part, kControllerPitchBend, channel_pitch_bend[channel]);
tunePos++;
}
}
break;
case MIDI_STATUS_PRESSURE:
/* NYI */
break;
case MIDI_STATUS_PITCH_WHEEL:
/* In the midi spec, 0x2000 = center, 0x0000 = - 2 semitones, 0x3FFF = +2 semitones
but for QTMA, we specify it as a 8.8 fixed point of semitones
TODO: detect "pitch bend range changes" & honor them!
*/
bend = (eventPos->data[0] & 0x7f) | ((eventPos->data[1] & 0x7f) << 7);
/* "Center" the bend */
bend -= 0x2000;
/* Move it to our format: */
bend <<= 4;
/* If it turns out the pitch bend didn't change, stop here */
if(channel_pitch_bend[channel] == bend)
break;
channel_pitch_bend[channel] = bend;
if(part>=0 && part<=31)
{
/* Stuff a control event */
REST_IF_NECESSARY();
qtma_StuffControlEvent(*tunePos, part, kControllerPitchBend, bend);
tunePos++;
}
break;
case MIDI_STATUS_SYSEX:
if (eventPos->status == 0xFF && eventPos->data[0] == 0x51) /* Tempo change */
{
tempo = (eventPos->extraData[0] << 16) +
(eventPos->extraData[1] << 8) +
eventPos->extraData[2];
tick = tempo * Ippqn;
}
break;
}
/* on to the next event */
eventPos = eventPos->next;
}
/* Finally, place an end marker */
*tunePos = kEndMarkerValue;
return tuneSequence;
}
 
Uint32 *BuildTuneHeader(int part_poly_max[32], int part_to_inst[32], int numParts)
{
Uint32 *myHeader;
Uint32 *myPos1, *myPos2; /* pointers to the head and tail long words of a music event */
NoteRequest *myNoteRequest;
NoteAllocator myNoteAllocator; /* for the NAStuffToneDescription call */
ComponentResult myErr = noErr;
int part;
 
myHeader = NULL;
myNoteAllocator = NULL;
 
/*
* Open up the Note Allocator
*/
myNoteAllocator = OpenDefaultComponent(kNoteAllocatorComponentType,0);
if (myNoteAllocator == NULL)
goto bail;
/*
* Allocate space for the tune header
*/
myHeader = (Uint32 *)
NewPtrClear((numParts * kNoteRequestEventLength + kMarkerEventLength) * sizeof(Uint32));
if (myHeader == NULL)
goto bail;
myPos1 = myHeader;
/*
* Loop over all parts
*/
for(part = 0; part < numParts; ++part)
{
/*
* Stuff request for the instrument with the given polyphony
*/
myPos2 = myPos1 + (kNoteRequestEventLength - 1); /* last longword of general event */
qtma_StuffGeneralEvent(*myPos1, *myPos2, part, kGeneralEventNoteRequest, kNoteRequestEventLength);
myNoteRequest = (NoteRequest *)(myPos1 + 1);
myNoteRequest->info.flags = 0;
/* I'm told by the Apple people that the Quicktime types were poorly designed and it was
* too late to change them. On little endian, the BigEndian(Short|Fixed) types are structs
* while on big endian they are primitive types. Furthermore, Quicktime failed to
* provide setter and getter functions. To get this to work, we need to case the
* code for the two possible situations.
* My assumption is that the right-side value was always expected to be BigEndian
* as it was written way before the Universal Binary transition. So in the little endian
* case, OSSwap is used.
*/
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
myNoteRequest->info.polyphony.bigEndianValue = OSSwapHostToBigInt16(part_poly_max[part]);
myNoteRequest->info.typicalPolyphony.bigEndianValue = OSSwapHostToBigInt32(0x00010000);
#else
myNoteRequest->info.polyphony = part_poly_max[part];
myNoteRequest->info.typicalPolyphony = 0x00010000;
#endif
myErr = NAStuffToneDescription(myNoteAllocator,part_to_inst[part],&myNoteRequest->tone);
if (myErr != noErr)
goto bail;
/* move pointer to beginning of next event */
myPos1 += kNoteRequestEventLength;
}
 
*myPos1 = kEndMarkerValue; /* end of sequence marker */
 
 
bail:
if(myNoteAllocator)
CloseComponent(myNoteAllocator);
 
/* if we encountered an error, dispose of the storage we allocated and return NULL */
if (myErr != noErr) {
DisposePtr((Ptr)myHeader);
myHeader = NULL;
}
 
return myHeader;
}
 
#endif /* MacOS native MIDI support */
/contrib/sdk/sources/SDL_mixer-1.2.12/native_midi/native_midi_macosx.c
0,0 → 1,322
/*
native_midi_macosx: Native Midi support on Mac OS X for the SDL_mixer library
Copyright (C) 2009 Ryan C. Gordon <icculus@icculus.org>
 
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
 
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
 
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
 
/* This is Mac OS X only, using Core MIDI.
Mac OS 9 support via QuickTime is in native_midi_mac.c */
 
#include "SDL_config.h"
 
#if __MACOSX__
 
#include <Carbon/Carbon.h>
#include <AudioToolbox/AudioToolbox.h>
#include <AvailabilityMacros.h>
 
#include "../SDL_mixer.h"
#include "SDL_endian.h"
#include "native_midi.h"
 
/* Native Midi song */
struct _NativeMidiSong
{
MusicPlayer player;
MusicSequence sequence;
MusicTimeStamp endTime;
AudioUnit audiounit;
int loops;
};
 
static NativeMidiSong *currentsong = NULL;
static int latched_volume = MIX_MAX_VOLUME;
 
static OSStatus
GetSequenceLength(MusicSequence sequence, MusicTimeStamp *_sequenceLength)
{
// http://lists.apple.com/archives/Coreaudio-api/2003/Jul/msg00370.html
// figure out sequence length
UInt32 ntracks, i;
MusicTimeStamp sequenceLength = 0;
OSStatus err;
 
err = MusicSequenceGetTrackCount(sequence, &ntracks);
if (err != noErr)
return err;
 
for (i = 0; i < ntracks; ++i)
{
MusicTrack track;
MusicTimeStamp tracklen = 0;
UInt32 tracklenlen = sizeof (tracklen);
 
err = MusicSequenceGetIndTrack(sequence, i, &track);
if (err != noErr)
return err;
 
err = MusicTrackGetProperty(track, kSequenceTrackProperty_TrackLength,
&tracklen, &tracklenlen);
if (err != noErr)
return err;
 
if (sequenceLength < tracklen)
sequenceLength = tracklen;
}
 
*_sequenceLength = sequenceLength;
 
return noErr;
}
 
 
/* we're looking for the sequence output audiounit. */
static OSStatus
GetSequenceAudioUnit(MusicSequence sequence, AudioUnit *aunit)
{
AUGraph graph;
UInt32 nodecount, i;
OSStatus err;
 
err = MusicSequenceGetAUGraph(sequence, &graph);
if (err != noErr)
return err;
 
err = AUGraphGetNodeCount(graph, &nodecount);
if (err != noErr)
return err;
 
for (i = 0; i < nodecount; i++) {
AUNode node;
 
if (AUGraphGetIndNode(graph, i, &node) != noErr)
continue; /* better luck next time. */
 
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 /* this is deprecated, but works back to 10.0 */
{
struct ComponentDescription desc;
UInt32 classdatasize = 0;
void *classdata = NULL;
err = AUGraphGetNodeInfo(graph, node, &desc, &classdatasize,
&classdata, aunit);
if (err != noErr)
continue;
else if (desc.componentType != kAudioUnitType_Output)
continue;
else if (desc.componentSubType != kAudioUnitSubType_DefaultOutput)
continue;
}
#else /* not deprecated, but requires 10.5 or later */
{
AudioComponentDescription desc;
if (AUGraphNodeInfo(graph, node, &desc, aunit) != noErr)
continue;
else if (desc.componentType != kAudioUnitType_Output)
continue;
else if (desc.componentSubType != kAudioUnitSubType_DefaultOutput)
continue;
}
#endif
 
return noErr; /* found it! */
}
 
return kAUGraphErr_NodeNotFound;
}
 
 
int native_midi_detect()
{
return 1; /* always available. */
}
 
NativeMidiSong *native_midi_loadsong_RW(SDL_RWops *rw, int freerw)
{
NativeMidiSong *retval = NULL;
void *buf = NULL;
int len = 0;
CFDataRef data = NULL;
 
if (SDL_RWseek(rw, 0, RW_SEEK_END) < 0)
goto fail;
len = SDL_RWtell(rw);
if (len < 0)
goto fail;
if (SDL_RWseek(rw, 0, RW_SEEK_SET) < 0)
goto fail;
 
buf = malloc(len);
if (buf == NULL)
goto fail;
 
if (SDL_RWread(rw, buf, len, 1) != 1)
goto fail;
 
retval = malloc(sizeof(NativeMidiSong));
if (retval == NULL)
goto fail;
 
memset(retval, '\0', sizeof (*retval));
 
if (NewMusicPlayer(&retval->player) != noErr)
goto fail;
if (NewMusicSequence(&retval->sequence) != noErr)
goto fail;
 
data = CFDataCreate(NULL, (const UInt8 *) buf, len);
if (data == NULL)
goto fail;
 
free(buf);
buf = NULL;
 
#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 /* this is deprecated, but works back to 10.3 */
if (MusicSequenceLoadSMFDataWithFlags(retval->sequence, data, 0) != noErr)
goto fail;
#else /* not deprecated, but requires 10.5 or later */
if (MusicSequenceFileLoadData(retval->sequence, data, 0, 0) != noErr)
goto fail;
#endif
 
CFRelease(data);
data = NULL;
 
if (GetSequenceLength(retval->sequence, &retval->endTime) != noErr)
goto fail;
 
if (MusicPlayerSetSequence(retval->player, retval->sequence) != noErr)
goto fail;
 
if (freerw)
SDL_RWclose(rw);
 
return retval;
 
fail:
if (retval) {
if (retval->sequence)
DisposeMusicSequence(retval->sequence);
if (retval->player)
DisposeMusicPlayer(retval->player);
free(retval);
}
 
if (data)
CFRelease(data);
 
if (buf)
free(buf);
 
if (freerw)
SDL_RWclose(rw);
 
return NULL;
}
 
void native_midi_freesong(NativeMidiSong *song)
{
if (song != NULL) {
if (currentsong == song)
currentsong = NULL;
MusicPlayerStop(song->player);
DisposeMusicSequence(song->sequence);
DisposeMusicPlayer(song->player);
free(song);
}
}
 
void native_midi_start(NativeMidiSong *song, int loops)
{
int vol;
 
if (song == NULL)
return;
 
SDL_PauseAudio(1);
SDL_UnlockAudio();
 
if (currentsong)
MusicPlayerStop(currentsong->player);
 
currentsong = song;
currentsong->loops = loops;
 
MusicPlayerPreroll(song->player);
MusicPlayerSetTime(song->player, 0);
MusicPlayerStart(song->player);
 
GetSequenceAudioUnit(song->sequence, &song->audiounit);
 
vol = latched_volume;
latched_volume++; /* just make this not match. */
native_midi_setvolume(vol);
 
SDL_LockAudio();
SDL_PauseAudio(0);
}
 
void native_midi_stop()
{
if (currentsong) {
SDL_PauseAudio(1);
SDL_UnlockAudio();
MusicPlayerStop(currentsong->player);
currentsong = NULL;
SDL_LockAudio();
SDL_PauseAudio(0);
}
}
 
int native_midi_active()
{
MusicTimeStamp currentTime = 0;
if (currentsong == NULL)
return 0;
 
MusicPlayerGetTime(currentsong->player, &currentTime);
if ((currentTime < currentsong->endTime) ||
(currentTime >= kMusicTimeStamp_EndOfTrack)) {
return 1;
} else if (currentsong->loops) {
--currentsong->loops;
MusicPlayerSetTime(currentsong->player, 0);
return 1;
}
return 0;
}
 
void native_midi_setvolume(int volume)
{
if (latched_volume == volume)
return;
 
latched_volume = volume;
if ((currentsong) && (currentsong->audiounit)) {
const float floatvol = ((float) volume) / ((float) MIX_MAX_VOLUME);
AudioUnitSetParameter(currentsong->audiounit, kHALOutputParam_Volume,
kAudioUnitScope_Global, 0, floatvol, 0);
}
}
 
const char *native_midi_error(void)
{
return ""; /* !!! FIXME */
}
 
#endif /* Mac OS X native MIDI support */
 
/contrib/sdk/sources/SDL_mixer-1.2.12/native_midi/native_midi_win32.c
0,0 → 1,312
/*
native_midi: Hardware Midi support for the SDL_mixer library
Copyright (C) 2000,2001 Florian 'Proff' Schulze <florian.proff.schulze@gmx.net>
 
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
 
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
 
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_config.h"
 
/* everything below is currently one very big bad hack ;) Proff */
 
#if __WIN32__
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include "native_midi.h"
#include "native_midi_common.h"
 
struct _NativeMidiSong {
int MusicLoaded;
int MusicPlaying;
int Loops;
int CurrentHdr;
MIDIHDR MidiStreamHdr[2];
MIDIEVENT *NewEvents;
Uint16 ppqn;
int Size;
int NewPos;
};
 
static UINT MidiDevice=MIDI_MAPPER;
static HMIDISTRM hMidiStream;
static NativeMidiSong *currentsong;
 
static int BlockOut(NativeMidiSong *song)
{
MMRESULT err;
int BlockSize;
MIDIHDR *hdr;
 
if ((song->MusicLoaded) && (song->NewEvents))
{
// proff 12/8/98: Added for safety
song->CurrentHdr = !song->CurrentHdr;
hdr = &song->MidiStreamHdr[song->CurrentHdr];
midiOutUnprepareHeader((HMIDIOUT)hMidiStream,hdr,sizeof(MIDIHDR));
if (song->NewPos>=song->Size)
return 0;
BlockSize=(song->Size-song->NewPos);
if (BlockSize<=0)
return 0;
if (BlockSize>36000)
BlockSize=36000;
hdr->lpData=(void *)((unsigned char *)song->NewEvents+song->NewPos);
song->NewPos+=BlockSize;
hdr->dwBufferLength=BlockSize;
hdr->dwBytesRecorded=BlockSize;
hdr->dwFlags=0;
hdr->dwOffset=0;
err=midiOutPrepareHeader((HMIDIOUT)hMidiStream,hdr,sizeof(MIDIHDR));
if (err!=MMSYSERR_NOERROR)
return 0;
err=midiStreamOut(hMidiStream,hdr,sizeof(MIDIHDR));
return 0;
}
return 1;
}
 
static void MIDItoStream(NativeMidiSong *song, MIDIEvent *evntlist)
{
int eventcount;
MIDIEvent *event;
MIDIEVENT *newevent;
 
eventcount=0;
event=evntlist;
while (event)
{
eventcount++;
event=event->next;
}
song->NewEvents=malloc(eventcount*3*sizeof(DWORD));
if (!song->NewEvents)
return;
memset(song->NewEvents,0,(eventcount*3*sizeof(DWORD)));
 
eventcount=0;
event=evntlist;
newevent=song->NewEvents;
while (event)
{
int status = (event->status&0xF0)>>4;
switch (status)
{
case MIDI_STATUS_NOTE_OFF:
case MIDI_STATUS_NOTE_ON:
case MIDI_STATUS_AFTERTOUCH:
case MIDI_STATUS_CONTROLLER:
case MIDI_STATUS_PROG_CHANGE:
case MIDI_STATUS_PRESSURE:
case MIDI_STATUS_PITCH_WHEEL:
newevent->dwDeltaTime=event->time;
newevent->dwEvent=(event->status|0x80)|(event->data[0]<<8)|(event->data[1]<<16)|(MEVT_SHORTMSG<<24);
newevent=(MIDIEVENT*)((char*)newevent+(3*sizeof(DWORD)));
eventcount++;
break;
 
case MIDI_STATUS_SYSEX:
if (event->status == 0xFF && event->data[0] == 0x51) /* Tempo change */
{
int tempo = (event->extraData[0] << 16) |
(event->extraData[1] << 8) |
event->extraData[2];
newevent->dwDeltaTime=event->time;
newevent->dwEvent=(MEVT_TEMPO<<24) | tempo;
newevent=(MIDIEVENT*)((char*)newevent+(3*sizeof(DWORD)));
eventcount++;
}
break;
}
 
event=event->next;
}
 
song->Size=eventcount*3*sizeof(DWORD);
 
{
int time;
int temptime;
 
song->NewPos=0;
time=0;
newevent=song->NewEvents;
while (song->NewPos<song->Size)
{
temptime=newevent->dwDeltaTime;
newevent->dwDeltaTime-=time;
time=temptime;
if ((song->NewPos+12)>=song->Size)
newevent->dwEvent |= MEVT_F_CALLBACK;
newevent=(MIDIEVENT*)((char*)newevent+(3*sizeof(DWORD)));
song->NewPos+=12;
}
}
song->NewPos=0;
song->MusicLoaded=1;
}
 
void CALLBACK MidiProc( HMIDIIN hMidi, UINT uMsg, DWORD_PTR dwInstance,
DWORD_PTR dwParam1, DWORD_PTR dwParam2 )
{
switch( uMsg )
{
case MOM_DONE:
if ((currentsong->MusicLoaded) && (dwParam1 == (DWORD_PTR)&currentsong->MidiStreamHdr[currentsong->CurrentHdr]))
BlockOut(currentsong);
break;
case MOM_POSITIONCB:
if ((currentsong->MusicLoaded) && (dwParam1 == (DWORD_PTR)&currentsong->MidiStreamHdr[currentsong->CurrentHdr])) {
if (currentsong->Loops) {
--currentsong->Loops;
currentsong->NewPos=0;
BlockOut(currentsong);
} else {
currentsong->MusicPlaying=0;
}
}
break;
default:
break;
}
}
 
int native_midi_detect()
{
MMRESULT merr;
HMIDISTRM MidiStream;
 
merr=midiStreamOpen(&MidiStream,&MidiDevice,(DWORD)1,(DWORD_PTR)MidiProc,(DWORD_PTR)0,CALLBACK_FUNCTION);
if (merr!=MMSYSERR_NOERROR)
return 0;
midiStreamClose(MidiStream);
return 1;
}
 
NativeMidiSong *native_midi_loadsong_RW(SDL_RWops *rw, int freerw)
{
NativeMidiSong *newsong;
MIDIEvent *evntlist = NULL;
 
newsong=malloc(sizeof(NativeMidiSong));
if (!newsong) {
if (freerw) {
SDL_RWclose(rw);
}
return NULL;
}
memset(newsong,0,sizeof(NativeMidiSong));
 
/* Attempt to load the midi file */
evntlist = CreateMIDIEventList(rw, &newsong->ppqn);
if (!evntlist)
{
free(newsong);
if (freerw) {
SDL_RWclose(rw);
}
return NULL;
}
 
MIDItoStream(newsong, evntlist);
 
FreeMIDIEventList(evntlist);
 
if (freerw) {
SDL_RWclose(rw);
}
return newsong;
}
 
void native_midi_freesong(NativeMidiSong *song)
{
if (hMidiStream)
{
midiStreamStop(hMidiStream);
midiStreamClose(hMidiStream);
}
if (song)
{
if (song->NewEvents)
free(song->NewEvents);
free(song);
}
}
 
void native_midi_start(NativeMidiSong *song, int loops)
{
MMRESULT merr;
MIDIPROPTIMEDIV mptd;
 
native_midi_stop();
if (!hMidiStream)
{
merr=midiStreamOpen(&hMidiStream,&MidiDevice,(DWORD)1,(DWORD_PTR)MidiProc,(DWORD_PTR)0,CALLBACK_FUNCTION);
if (merr!=MMSYSERR_NOERROR)
{
hMidiStream = NULL; // should I do midiStreamClose(hMidiStream) before?
return;
}
//midiStreamStop(hMidiStream);
currentsong=song;
currentsong->NewPos=0;
currentsong->MusicPlaying=1;
currentsong->Loops=loops;
mptd.cbStruct=sizeof(MIDIPROPTIMEDIV);
mptd.dwTimeDiv=currentsong->ppqn;
merr=midiStreamProperty(hMidiStream,(LPBYTE)&mptd,MIDIPROP_SET | MIDIPROP_TIMEDIV);
BlockOut(song);
merr=midiStreamRestart(hMidiStream);
}
}
 
void native_midi_stop()
{
if (!hMidiStream)
return;
midiStreamStop(hMidiStream);
midiStreamClose(hMidiStream);
currentsong=NULL;
hMidiStream = NULL;
}
 
int native_midi_active()
{
return currentsong->MusicPlaying;
}
 
void native_midi_setvolume(int volume)
{
int calcVolume;
if (volume > 128)
volume = 128;
if (volume < 0)
volume = 0;
calcVolume = (65535 * volume / 128);
 
midiOutSetVolume((HMIDIOUT)hMidiStream, MAKELONG(calcVolume , calcVolume));
}
 
const char *native_midi_error(void)
{
return "";
}
 
#endif /* Windows native MIDI support */
/contrib/sdk/sources/SDL_mixer-1.2.12/wavestream.c
0,0 → 1,526
/*
SDL_mixer: An audio mixer library based on the SDL library
Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
 
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
 
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
 
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
 
/* $Id$ */
 
/* This file supports streaming WAV files, without volume adjustment */
 
#include <stdlib.h>
#include <string.h>
 
#include "SDL_audio.h"
#include "SDL_mutex.h"
#include "SDL_rwops.h"
#include "SDL_endian.h"
 
#include "SDL_mixer.h"
#include "wavestream.h"
 
/*
Taken with permission from SDL_wave.h, part of the SDL library,
available at: http://www.libsdl.org/
and placed under the same license as this mixer library.
*/
 
/* WAVE files are little-endian */
 
/*******************************************/
/* Define values for Microsoft WAVE format */
/*******************************************/
#define RIFF 0x46464952 /* "RIFF" */
#define WAVE 0x45564157 /* "WAVE" */
#define FACT 0x74636166 /* "fact" */
#define LIST 0x5453494c /* "LIST" */
#define FMT 0x20746D66 /* "fmt " */
#define DATA 0x61746164 /* "data" */
#define PCM_CODE 1
#define ADPCM_CODE 2
#define WAVE_MONO 1
#define WAVE_STEREO 2
 
#define SDL_stack_alloc(type, count) (type*)SDL_malloc(sizeof(type)*(count))
 
/* Normally, these three chunks come consecutively in a WAVE file */
typedef struct WaveFMT {
/* Not saved in the chunk we read:
Uint32 FMTchunk;
Uint32 fmtlen;
*/
Uint16 encoding;
Uint16 channels; /* 1 = mono, 2 = stereo */
Uint32 frequency; /* One of 11025, 22050, or 44100 Hz */
Uint32 byterate; /* Average bytes per second */
Uint16 blockalign; /* Bytes per sample block */
Uint16 bitspersample; /* One of 8, 12, 16, or 4 for ADPCM */
} WaveFMT;
 
/* The general chunk found in the WAVE file */
typedef struct Chunk {
Uint32 magic;
Uint32 length;
Uint8 *data; /* Data includes magic and length */
} Chunk;
 
/*********************************************/
/* Define values for AIFF (IFF audio) format */
/*********************************************/
#define FORM 0x4d524f46 /* "FORM" */
#define AIFF 0x46464941 /* "AIFF" */
#define SSND 0x444e5353 /* "SSND" */
#define COMM 0x4d4d4f43 /* "COMM" */
 
 
/* Currently we only support a single stream at a time */
static WAVStream *music = NULL;
 
/* This is the format of the audio mixer data */
static SDL_AudioSpec mixer;
static int wavestream_volume = MIX_MAX_VOLUME;
 
/* Function to load the WAV/AIFF stream */
static SDL_RWops *LoadWAVStream (SDL_RWops *rw, SDL_AudioSpec *spec,
long *start, long *stop);
static SDL_RWops *LoadAIFFStream (SDL_RWops *rw, SDL_AudioSpec *spec,
long *start, long *stop);
 
/* Initialize the WAVStream player, with the given mixer settings
This function returns 0, or -1 if there was an error.
*/
int WAVStream_Init(SDL_AudioSpec *mixerfmt)
{
mixer = *mixerfmt;
return(0);
}
 
void WAVStream_SetVolume(int volume)
{
wavestream_volume = volume;
}
 
/* Load a WAV stream from the given RWops object */
WAVStream *WAVStream_LoadSong_RW(SDL_RWops *rw, const char *magic, int freerw)
{
WAVStream *wave;
SDL_AudioSpec wavespec;
 
if ( ! mixer.format ) {
Mix_SetError("WAV music output not started");
if ( freerw ) {
SDL_RWclose(rw);
}
return(NULL);
}
wave = (WAVStream *)SDL_malloc(sizeof *wave);
if ( wave ) {
memset(wave, 0, (sizeof *wave));
wave->freerw = freerw;
if ( strcmp(magic, "RIFF") == 0 ) {
wave->rw = LoadWAVStream(rw, &wavespec,
&wave->start, &wave->stop);
} else
if ( strcmp(magic, "FORM") == 0 ) {
wave->rw = LoadAIFFStream(rw, &wavespec,
&wave->start, &wave->stop);
} else {
Mix_SetError("Unknown WAVE format");
}
if ( wave->rw == NULL ) {
SDL_free(wave);
if ( freerw ) {
SDL_RWclose(rw);
}
return(NULL);
}
SDL_BuildAudioCVT(&wave->cvt,
wavespec.format, wavespec.channels, wavespec.freq,
mixer.format, mixer.channels, mixer.freq);
} else {
SDL_OutOfMemory();
if ( freerw ) {
SDL_RWclose(rw);
}
return(NULL);
}
return(wave);
}
 
/* Start playback of a given WAV stream */
void WAVStream_Start(WAVStream *wave)
{
SDL_RWseek (wave->rw, wave->start, RW_SEEK_SET);
music = wave;
}
 
/* Play some of a stream previously started with WAVStream_Start() */
int WAVStream_PlaySome(Uint8 *stream, int len)
{
long pos;
int left = 0;
 
if ( music && ((pos=SDL_RWtell(music->rw)) < music->stop) ) {
if ( music->cvt.needed ) {
int original_len;
 
original_len=(int)((double)len/music->cvt.len_ratio);
if ( music->cvt.len != original_len ) {
int worksize;
if ( music->cvt.buf != NULL ) {
SDL_free(music->cvt.buf);
}
worksize = original_len*music->cvt.len_mult;
music->cvt.buf=(Uint8 *)SDL_malloc(worksize);
if ( music->cvt.buf == NULL ) {
return 0;
}
music->cvt.len = original_len;
}
if ( (music->stop - pos) < original_len ) {
left = (original_len - (music->stop - pos));
original_len -= left;
left = (int)((double)left*music->cvt.len_ratio);
}
original_len = SDL_RWread(music->rw, music->cvt.buf,1,original_len);
/* At least at the time of writing, SDL_ConvertAudio()
does byte-order swapping starting at the end of the
buffer. Thus, if we are reading 16-bit samples, we
had better make damn sure that we get an even
number of bytes, or we'll get garbage.
*/
if ( (music->cvt.src_format & 0x0010) && (original_len & 1) ) {
original_len--;
}
music->cvt.len = original_len;
SDL_ConvertAudio(&music->cvt);
SDL_MixAudio(stream, music->cvt.buf, music->cvt.len_cvt, wavestream_volume);
} else {
Uint8 *data;
if ( (music->stop - pos) < len ) {
left = (len - (music->stop - pos));
len -= left;
}
data = SDL_stack_alloc(Uint8, len);
if (data)
{
SDL_RWread(music->rw, data, len, 1);
SDL_MixAudio(stream, data, len, wavestream_volume);
SDL_stack_free(data);
}
}
}
return left;
}
 
/* Stop playback of a stream previously started with WAVStream_Start() */
void WAVStream_Stop(void)
{
music = NULL;
}
 
/* Close the given WAV stream */
void WAVStream_FreeSong(WAVStream *wave)
{
if ( wave ) {
/* Clean up associated data */
if ( wave->cvt.buf ) {
SDL_free(wave->cvt.buf);
}
if ( wave->freerw ) {
SDL_RWclose(wave->rw);
}
SDL_free(wave);
}
}
 
/* Return non-zero if a stream is currently playing */
int WAVStream_Active(void)
{
int active;
 
active = 0;
if ( music && (SDL_RWtell(music->rw) < music->stop) ) {
active = 1;
}
return(active);
}
 
static int ReadChunk(SDL_RWops *src, Chunk *chunk, int read_data)
{
chunk->magic = SDL_ReadLE32(src);
chunk->length = SDL_ReadLE32(src);
if ( read_data ) {
chunk->data = (Uint8 *)SDL_malloc(chunk->length);
if ( chunk->data == NULL ) {
Mix_SetError("Out of memory");
return(-1);
}
if ( SDL_RWread(src, chunk->data, chunk->length, 1) != 1 ) {
Mix_SetError("Couldn't read chunk");
SDL_free(chunk->data);
return(-1);
}
} else {
SDL_RWseek(src, chunk->length, RW_SEEK_CUR);
}
return(chunk->length);
}
 
static SDL_RWops *LoadWAVStream (SDL_RWops *src, SDL_AudioSpec *spec,
long *start, long *stop)
{
int was_error;
Chunk chunk;
int lenread;
 
/* WAV magic header */
Uint32 RIFFchunk;
Uint32 wavelen;
Uint32 WAVEmagic;
 
/* FMT chunk */
WaveFMT *format = NULL;
 
was_error = 0;
 
/* Check the magic header */
RIFFchunk = SDL_ReadLE32(src);
wavelen = SDL_ReadLE32(src);
WAVEmagic = SDL_ReadLE32(src);
if ( (RIFFchunk != RIFF) || (WAVEmagic != WAVE) ) {
Mix_SetError("Unrecognized file type (not WAVE)");
was_error = 1;
goto done;
}
 
/* Read the audio data format chunk */
chunk.data = NULL;
do {
/* FIXME! Add this logic to SDL_LoadWAV_RW() */
if ( chunk.data ) {
SDL_free(chunk.data);
}
lenread = ReadChunk(src, &chunk, 1);
if ( lenread < 0 ) {
was_error = 1;
goto done;
}
} while ( (chunk.magic == FACT) || (chunk.magic == LIST) );
 
/* Decode the audio data format */
format = (WaveFMT *)chunk.data;
if ( chunk.magic != FMT ) {
SDL_free(chunk.data);
Mix_SetError("Complex WAVE files not supported");
was_error = 1;
goto done;
}
switch (SDL_SwapLE16(format->encoding)) {
case PCM_CODE:
/* We can understand this */
break;
default:
Mix_SetError("Unknown WAVE data format");
was_error = 1;
goto done;
}
memset(spec, 0, (sizeof *spec));
spec->freq = SDL_SwapLE32(format->frequency);
switch (SDL_SwapLE16(format->bitspersample)) {
case 8:
spec->format = AUDIO_U8;
break;
case 16:
spec->format = AUDIO_S16;
break;
default:
Mix_SetError("Unknown PCM data format");
was_error = 1;
goto done;
}
spec->channels = (Uint8) SDL_SwapLE16(format->channels);
spec->samples = 4096; /* Good default buffer size */
 
/* Set the file offset to the DATA chunk data */
chunk.data = NULL;
do {
*start = SDL_RWtell(src) + 2*sizeof(Uint32);
lenread = ReadChunk(src, &chunk, 0);
if ( lenread < 0 ) {
was_error = 1;
goto done;
}
} while ( chunk.magic != DATA );
*stop = SDL_RWtell(src);
 
done:
if ( format != NULL ) {
SDL_free(format);
}
if ( was_error ) {
return NULL;
}
return(src);
}
 
/* I couldn't get SANE_to_double() to work, so I stole this from libsndfile.
* I don't pretend to fully understand it.
*/
 
static Uint32 SANE_to_Uint32 (Uint8 *sanebuf)
{
/* Negative number? */
if (sanebuf[0] & 0x80)
return 0;
 
/* Less than 1? */
if (sanebuf[0] <= 0x3F)
return 1;
 
/* Way too big? */
if (sanebuf[0] > 0x40)
return 0x4000000;
 
/* Still too big? */
if (sanebuf[0] == 0x40 && sanebuf[1] > 0x1C)
return 800000000;
 
return ((sanebuf[2] << 23) | (sanebuf[3] << 15) | (sanebuf[4] << 7)
| (sanebuf[5] >> 1)) >> (29 - sanebuf[1]);
}
 
static SDL_RWops *LoadAIFFStream (SDL_RWops *src, SDL_AudioSpec *spec,
long *start, long *stop)
{
int was_error;
int found_SSND;
int found_COMM;
 
Uint32 chunk_type;
Uint32 chunk_length;
long next_chunk;
 
/* AIFF magic header */
Uint32 FORMchunk;
Uint32 AIFFmagic;
/* SSND chunk */
Uint32 offset;
Uint32 blocksize;
/* COMM format chunk */
Uint16 channels = 0;
Uint32 numsamples = 0;
Uint16 samplesize = 0;
Uint8 sane_freq[10];
Uint32 frequency = 0;
 
was_error = 0;
 
/* Check the magic header */
FORMchunk = SDL_ReadLE32(src);
chunk_length = SDL_ReadBE32(src);
AIFFmagic = SDL_ReadLE32(src);
if ( (FORMchunk != FORM) || (AIFFmagic != AIFF) ) {
Mix_SetError("Unrecognized file type (not AIFF)");
was_error = 1;
goto done;
}
 
/* From what I understand of the specification, chunks may appear in
* any order, and we should just ignore unknown ones.
*
* TODO: Better sanity-checking. E.g. what happens if the AIFF file
* contains compressed sound data?
*/
 
found_SSND = 0;
found_COMM = 0;
 
do {
chunk_type = SDL_ReadLE32(src);
chunk_length = SDL_ReadBE32(src);
next_chunk = SDL_RWtell(src) + chunk_length;
 
/* Paranoia to avoid infinite loops */
if (chunk_length == 0)
break;
 
switch (chunk_type) {
case SSND:
found_SSND = 1;
offset = SDL_ReadBE32(src);
blocksize = SDL_ReadBE32(src);
*start = SDL_RWtell(src) + offset;
break;
 
case COMM:
found_COMM = 1;
 
/* Read the audio data format chunk */
channels = SDL_ReadBE16(src);
numsamples = SDL_ReadBE32(src);
samplesize = SDL_ReadBE16(src);
SDL_RWread(src, sane_freq, sizeof(sane_freq), 1);
frequency = SANE_to_Uint32(sane_freq);
break;
 
default:
break;
}
} while ((!found_SSND || !found_COMM)
&& SDL_RWseek(src, next_chunk, RW_SEEK_SET) != -1);
 
if (!found_SSND) {
Mix_SetError("Bad AIFF file (no SSND chunk)");
was_error = 1;
goto done;
}
if (!found_COMM) {
Mix_SetError("Bad AIFF file (no COMM chunk)");
was_error = 1;
goto done;
}
 
*stop = *start + channels * numsamples * (samplesize / 8);
 
/* Decode the audio data format */
memset(spec, 0, (sizeof *spec));
spec->freq = frequency;
switch (samplesize) {
case 8:
spec->format = AUDIO_S8;
break;
case 16:
spec->format = AUDIO_S16MSB;
break;
default:
Mix_SetError("Unknown samplesize in data format");
was_error = 1;
goto done;
}
spec->channels = (Uint8) channels;
spec->samples = 4096; /* Good default buffer size */
 
done:
if ( was_error ) {
return NULL;
}
return(src);
}
 
/contrib/sdk/sources/SDL_mixer-1.2.12/wavestream.h
0,0 → 1,60
/*
SDL_mixer: An audio mixer library based on the SDL library
Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
 
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
 
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
 
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
 
/* $Id$ */
 
/* This file supports streaming WAV files, without volume adjustment */
 
#include <stdio.h>
 
typedef struct {
SDL_RWops *rw;
SDL_bool freerw;
long start;
long stop;
SDL_AudioCVT cvt;
} WAVStream;
 
/* Initialize the WAVStream player, with the given mixer settings
This function returns 0, or -1 if there was an error.
*/
extern int WAVStream_Init(SDL_AudioSpec *mixer);
 
/* Unimplemented */
extern void WAVStream_SetVolume(int volume);
 
/* Load a WAV stream from an SDL_RWops object */
extern WAVStream *WAVStream_LoadSong_RW(SDL_RWops *rw, const char *magic, int freerw);
 
/* Start playback of a given WAV stream */
extern void WAVStream_Start(WAVStream *wave);
 
/* Play some of a stream previously started with WAVStream_Start() */
extern int WAVStream_PlaySome(Uint8 *stream, int len);
 
/* Stop playback of a stream previously started with WAVStream_Start() */
extern void WAVStream_Stop(void);
 
/* Close the given WAV stream */
extern void WAVStream_FreeSong(WAVStream *wave);
 
/* Return non-zero if a stream is currently playing */
extern int WAVStream_Active(void);