…on a different note…
Here is a proposed API for that library I mentioned before. I’m
tentatively calling it “SDL_voice”. It’s an abstraction over decoding
various audio file formats. Think of it as the audio equivalent of
SDL_Image.
Once discussion on the API (er…what little of it there is) settles down,
I’ll write it, and get the initial decoders worked out.
The goal for a 1.0 release is to support decoding from at least all of the
file formats that SDL_mixer currently does.
Once SDL_voice is stable, I’ll be removing all the decoders from
SDL_mixer, and replacing them with a single dependency to SDL_voice. Part
of the benefit is the blurring of SDL_mixer’s current distinction between
"music" and “sound”, so that you can mix multiple MP3s as regular
channels, or use a VOC file for the music channel. Actually, the "music"
channel will mostly become a matter of backward compatibility, since all
the channels will be treated equally at that point.
(Actually…hhm…native midi music will probably have to be kept separate
on that channel, unless you want to use Timidity through SDL_voice to mix
it into a wave buffer…anyhow…that’s future stuff.)
Also, as a side tangent, SDL_voice gets its data through SDL_RWops. It
would be interesting to see a support library for more than just
file and memory RWops. I’m envisioning things like an SDL_RWops
implementation that reads from an http connection or (really wacky),
interfaces to XMMS plugins to expand the number of supported decoders.
It’s one to think about, but it’s only vaguely related to this API at the
moment.
Finally, this header file hasn’t been run through ANY compiler, so it
might have minor syntax errors at the moment. Bare with me.
Here it is. Please comment.
–ryan.
/*
- SDL_voice – An abstract sound format decoding API.
- Copyright © 2001 Ryan C. Gordon.*
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 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
- Lesser General Public License for more details.
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/**
- The basic gist of SDL_Voice is that you use an SDL_RWops to get sound data
- into this library, and SDL_Voice will take that data, in one of several
- popular formats, and decode it into raw waveform data in the format of
- your choice. This gives you a nice abstraction for getting sound into your
- game or application; just feed it to SDL_Voice, and it will handle
- decoding and converting, so you can just pass it to your SDL audio
- callback (or whatever). Since it gets data from a SDL_RWops, you can get
- the initial sound data from any number of sources: file, memory buffer,
- network connection, etc.
- As the name implies, this library depends on SDL: Simple Directmedia Layer,
- which is a powerful, free, and cross-platform multimedia library. It can
- be found at http://www.libsdl.org/
- Support is in place or planned for the following sound formats:
-
- .WAV (Microsoft WAVfile RIFF data, internal.)
-
- .VOC (Creative Labs’ Voice format, internal.)
-
- .MP3 (MPEG-1 layer 3 support, via the SMPEG library.)
-
- .MID (MIDI music converted to Waveform data, via Timidity.)
-
- .MOD (MOD files, via MikMod.)
-
- .OGG (Ogg files, via Ogg Vorbis libraries.)
-
- .RAWDATA (Raw sound data in any format, internal.)
-
- .CDA (CD audio read into a sound buffer, internal.)
- (…and more to come…)
- Please see the file LICENSE in the source’s root directory.
- This file written by Ryan C. Gordon. (icculus at clutteredmind.org)
*/
#ifndef INCLUDE_SDL_VOICE_H
#define INCLUDE_SDL_VOICE_H
#include “SDL.h”
#ifdef __cplusplus
extern “C” {
#endif
/* Stupid DLL stuff… */
#if (defined _MSC_VER)
#define EXPORT __declspec(dllexport)
#else
#define EXPORT
#endif
/*
-
These are flags that are used in a Voice_Sample (below) to show various
-
states.
-
To use: “if (sample->flags & VOICE_SAMPLEFLAGS_ERROR) { dosomething(); }”
/
typedef enum VOICE_SAMPLEFLAGS
{
VOICE_SAMPLEFLAG_NONE = 0, / Null flag. *//* these are set at sample creation time… /
VOICE_SAMPLEFLAG_NEEDSEEK = 1, / SDL_RWops must be able to seek. /
VOICE_SAMPLEFLAG_STREAMING = 1 << 1, / source is streaming (no EOF). *//* these are set during decoding… /
VOICE_SAMPLEFLAG_EOF = 1 << 29, / end of input stream. /
VOICE_SAMPLEFLAG_ERROR = 1 << 30, / unrecoverable error. /
VOICE_SAMPLEFLAG_AGAIN = 1 << 31 / couldn’t read without blocking. */
} Voice_SampleFlags;
/*
- The Voice_Sample structure is the heart of SDL_Voice. This holds
- information about a source of sound data as it is being decoded.
- EVERY FIELD IN THIS IS READ-ONLY. Please use the API functions to
- change them.
*/
typedef struct VOICE_SAMPLE
{
void opaque; / Internal use only. */
Voice_DecoderInfo decoder; / Decoder used for this sample. /
SDL_AudioSpec desired; / Desired audio format for conversion. /
SDL_AudioSpec actual; / Actual audio format of sample. */
void buffer; / Decoded sound data lands in here. /
Uint32 buffer_size; / Current size of (buffer), in bytes. /
Voice_SampleFlags flags; / Flags relating to this sample. */
} Voice_Sample;
/*
- Each decoder sets up one of these structs, which can be retrieved via
- the Voice_AvailableDecoders() function.
*/
typedef struct PHYSFS_ARCHIVEINFO
{
const char extension; / Case sensitive standard file extension. */
const char description; / Human readable description of decoder. */
const char author; / “Name Of Author (email at emailhost.dom)” */
const char url; / URL specific to this decoder. */
} PHYSFS_ArchiveInfo;
/*
- Just what it says: a x.y.z style version number…
*/
typedef struct VOICE_VERSION
{
int major;
int minor;
int patch;
} Voice_Version;
/* functions and macros… */
#define VOICE_VER_MAJOR 0
#define VOICE_VER_MINOR 0
#define VOICE_VER_PATCH 1
#define VOICE_VERSION(x) {
(x)->major = VOICE_VER_MAJOR;
(x)->minor = VOICE_VER_MINOR;
(x)->patch = VOICE_VER_PATCH;
}
/**
- Get the version of SDL_Voice that is linked against your program. If you
- are using a shared library (DLL) version of SDL_Voice, then it is possible
- that it will be different than the version you compiled against.
- This is a real function; the macro VOICE_VERSION tells you what version
- of SDL_Voice you compiled against:
- Voice_Version compiled;
- Voice_Version linked;
- VOICE_VERSION(&compiled);
- Voice_GetLinkedVersion(&linked);
- printf(“We compiled against SDL_Voice version %d.%d.%d …\n”,
-
compiled.major, compiled.minor, compiled.patch);
- printf(“But we linked against SDL_Voice version %d.%d.%d.\n”,
-
linked.major, linked.minor, linked.patch);
- This function may be called safely at any time, even before Voice_Init().
*/
EXPORT void Voice_GetLinkedVersion(Voice_Version *ver);
/**
- Initialize SDL_Voice. This must be called before any other SDL_Voice
- function (except perhaps Voice_GetLinkedVersion()). You should call
- SDL_Init() before calling this. Voice_Init() will attempt to call
- SDL_Init(SDL_INIT_AUDIO), just in case. This is a safe behaviour, but it
- may not configure SDL to your liking by itself.
- @return nonzero on success, zero on error. Specifics of the error can be
-
gleaned from Voice_GetLastError().
*/
EXPORT int Voice_Init(void);
/**
- Shutdown SDL_Voice. This closes any SDL_RWops that were being used as
- sound sources, and frees any resources in use by SDL_Voice.
- All Voice_Sample pointers you had prior to this call are INVALIDATED.
- Once successfully deinitialized, Voice_Init() can be called again to
- restart the subsystem. All defaults API states are restored at this
- point.
- You should call this BEFORE SDL_Quit(). This will NOT call SDL_Quit()
- for you!
- @return nonzero on success, zero on error. Specifics of the error can be
-
gleaned from Voice_GetLastError(). If failure, state of SDL_Voice
-
is undefined, and probably badly screwed up.
*/
EXPORT int Voice_Quit(void);
/**
- Get a list of sound formats supported by this implementation of SDL_Voice.
- This is for informational purposes only. Note that the extension listed is
- merely convention: if we list “MP3”, you can open an MPEG Audio layer 3
- file with an extension of “XYZ”, if you like. The file extensions are
- informational, and only required as a hint to choosing the correct
- decoder, since the sound data may not be coming from a file at all, thanks
- to the abstraction that an SDL_RWops provides.
- The returned value is an array of pointers to Voice_DecoderInfo structures,
- with a NULL entry to signify the end of the list:
- Voice_DecoderInfo **i;
- for (i = Voice_AvailableDecoders(); *i != NULL; i++)
- {
-
printf("Supported sound format: [%s], which is [%s].\n",
-
i->extension, i->description);
-
// ...and other fields...
- }
- The return values are pointers to static internal memory, and should
- be considered READ ONLY, and never freed.
-
@return READ ONLY Null-terminated array of READ ONLY structures.
*/
EXPORT const Voice_DecoderInfo **Voice_AvailableDecoders(void);
/**
- Get the last SDL_Voice error message as a null-terminated string.
- This will be NULL if there’s been no error since the last call to this
- function. The pointer returned by this call points to an internal buffer.
- Each thread has a unique error state associated with it, but each time
- a new error message is set, it will overwrite the previous one associated
- with that thread. It is safe to call this function at anytime, even
- before Voice_Init().
-
@return READ ONLY string of last error message.
*/
EXPORT const char *Voice_GetLastError(void);
/**
- Start decoding a new sound sample. The data is read via an SDL_RWops
- structure (see SDL_rwops.h in the SDL include directory), so it may be
- coming from memory, disk, network stream, etc. The (ext) parameter is
- merely a hint to determining the correct decoder; if you specify, for
- example, “mp3” for an extension, and one of the decoders lists that
- (case sensitive) as a handled extension, then that decoder is given
- first shot at trying to claim the data for decoding. If none of the
- extensions match (or the extension is NULL), then every decoder examines
- the data to determine if it can handle it, until one accepts it.
- If no decoders can handle the data, a NULL value is returned, and a human
- readable error message can be fetched from Voice_GetLastError().
- Optionally, a desired audio format can be specified. If the incoming data
- is in a different format, SDL_Voice will convert it to the desired format
- on the fly. Note that this can be an expensive operation, so it may be
- wise to convert data before you need to play it back, if possible, or
- make sure your data is initially in the format that you need it in.
- If you don’t want to convert the data, you can specify NULL for a desired
- format. The incoming format of the data, preconversion, can be found
- in the Voice_Sample structure.
- Note that the raw sound data “decoder” needs you to specify both the
- extension “RAWDATA” and a “desired” format, or it will refuse to handle
- the data.
- Finally, specify an initial buffer size; this is the number of bytes that
- will be allocated to store each read from the sound buffer. The more you
- can safely allocate, the more decoding can be done in one block, but the
- more resources you have to use up, and the longer each decoding call will
- take. Note that different data formats require more or less space to
- store. This buffer can be resized via Voice_SetBufferSize() …
- When you are done with this Voice_Sample pointer, you can dispose of it
- via Voice_FreeSample().
- @param rw SDL_RWops with sound data.
- @param ext File extension normally associated with a data format.
-
Can usually be NULL.
- @param desired Format to convert sound data into. Can usually be NULL,
-
if you don't need conversion.
- @return Voice_Sample pointer, which is used as a handle to several other
-
SDL_Voice APIs. NULL on error. If error, use
-
Voice_GetLastError() to see what went wrong.
*/
EXPORT Voice_Sample *Voice_NewSample(SDL_RWops *rw, const char *ext,
SDL_AudioInfo *desired,
Uint32 bufferSize);
/**
- Dispose of a Voice_Sample pointer that was returned from Voice_NewSample().
- This will also close/dispose of the SDL_RWops that was used at creation
- time, so there’s no need to keep a reference to that around.
- The Voice_Sample pointer is invalid after this call, and will almost
- certainly result in a crash if you attempt to keep using it.
-
@param sample The Voice_Sample to delete.
*/
EXPORT void Voice_FreeSample(Voice_Sample *sample);
/**
- Decode more of the sound data in a Voice_Sample. It will decode at most
- sample->buffer_size bytes into sample->buffer in the desired format, and
- return the number of decoded bytes.
- If sample->buffer_size bytes could not be decoded, then please refer to
- sample->flags to determine if this was an End-of-stream or error condition.
- @param sample Do more decoding to this Voice_Sample.
- @return number of bytes decoded into sample->buffer. If it is less than
-
sample->buffer_size, then you should check sample->flags to see
-
what the current state of the sample is (EOF, error, read again).
*/
EXPORT Uint32 Voice_Decode(Voice_Sample *sample);
#ifdef __cplusplus
}
#endif
#endif /* !defined INCLUDE_SDL_VOICE_H */
/* end of SDL_voice.h … */