/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), §ion); |
#else |
len = vorbis.ov_read(&music->vf, data, sizeof(data), 0, 2, 1, §ion); |
#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, ¤tPos); |
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, ¤tPos); |
/* 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, ¤tTime); |
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)¤tsong->MidiStreamHdr[currentsong->CurrentHdr])) |
BlockOut(currentsong); |
break; |
case MOM_POSITIONCB: |
if ((currentsong->MusicLoaded) && (dwParam1 == (DWORD_PTR)¤tsong->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); |