From 056fa2a47443eb40cf40eadae5721c847015813e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 5 Jun 2013 19:44:42 -0700 Subject: Use SDL_sound for the alstream example --- CMakeLists.txt | 26 ++++++-- examples/alstream.c | 65 +++++++------------ examples/common/alhelpers.h | 4 ++ examples/common/sdl_sound.c | 149 ++++++++++++++++++++++++++++++++++++++++++++ examples/common/sdl_sound.h | 43 +++++++++++++ 5 files changed, 239 insertions(+), 48 deletions(-) create mode 100644 examples/common/sdl_sound.c create mode 100644 examples/common/sdl_sound.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 8fbf775b..792bf393 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -766,6 +766,11 @@ SET(BACKENDS "${BACKENDS} Null") IF(ALSOFT_EXAMPLES) # Might be able to use earlier versions, but these definitely work PKG_CHECK_MODULES(FFMPEG libavcodec>=53.61.100 libavformat>=53.32.100 libavutil>=51.35.100) + + FIND_PACKAGE(SDL) + IF(SDL_FOUND) + FIND_PACKAGE(SDL_sound) + ENDIF() ENDIF() IF(LIBTYPE STREQUAL "STATIC") @@ -864,13 +869,24 @@ IF(ALSOFT_UTILS) ENDIF() IF(ALSOFT_EXAMPLES) - IF(FFMPEG_FOUND) + IF(SDL_FOUND AND SDL_SOUND_FOUND) ADD_EXECUTABLE(alstream examples/common/alhelpers.c - examples/common/alffmpeg.c + examples/common/sdl_sound.c examples/alstream.c) - TARGET_LINK_LIBRARIES(alstream ${FFMPEG_LIBRARIES} ${LIBNAME}) - SET_TARGET_PROPERTIES(alstream PROPERTIES COMPILE_FLAGS "${FFMPEG_CFLAGS}") + TARGET_LINK_LIBRARIES(alstream ${SDL_SOUND_LIBRARIES} ${LIBNAME}) + SET_TARGET_PROPERTIES(alstream PROPERTIES INCLUDE_DIRECTORIES "${SDL_SOUND_INCLUDE_DIR}") + INSTALL(TARGETS alstream + RUNTIME DESTINATION bin + LIBRARY DESTINATION "lib${LIB_SUFFIX}" + ARCHIVE DESTINATION "lib${LIB_SUFFIX}" + ) + + MESSAGE(STATUS "Building SDL_sound example programs") + MESSAGE(STATUS "") + ENDIF() + + IF(FFMPEG_FOUND) ADD_EXECUTABLE(alreverb examples/common/alhelpers.c examples/common/alffmpeg.c examples/alreverb.c) @@ -883,7 +899,7 @@ IF(ALSOFT_EXAMPLES) TARGET_LINK_LIBRARIES(allatency ${FFMPEG_LIBRARIES} ${LIBNAME}) SET_TARGET_PROPERTIES(allatency PROPERTIES COMPILE_FLAGS "${FFMPEG_CFLAGS}") - INSTALL(TARGETS alstream alreverb allatency + INSTALL(TARGETS alreverb allatency RUNTIME DESTINATION bin LIBRARY DESTINATION "lib${LIB_SUFFIX}" ARCHIVE DESTINATION "lib${LIB_SUFFIX}" diff --git a/examples/alstream.c b/examples/alstream.c index 809d37bb..2972d375 100644 --- a/examples/alstream.c +++ b/examples/alstream.c @@ -35,32 +35,26 @@ #include "AL/alext.h" #include "common/alhelpers.h" -#include "common/alffmpeg.h" +#include "common/sdl_sound.h" static LPALBUFFERSAMPLESSOFT alBufferSamplesSOFT = wrap_BufferSamples; static LPALISBUFFERFORMATSUPPORTEDSOFT alIsBufferFormatSupportedSOFT; -/* Define the number of buffers and buffer size (in samples) to use. 4 buffers - * with 8192 samples each gives a nice per-chunk size, and lets the queue last - * for almost 3/4ths of a second for a 44.1khz stream. */ +/* Define the number of buffers and buffer size (in milliseconds) to use. 4 + * buffers with 200ms each gives a nice per-chunk size, and lets the queue last + * for almost one second. */ #define NUM_BUFFERS 4 -#define BUFFER_SIZE 8192 +#define BUFFER_TIME_MS 200 typedef struct StreamPlayer { /* These are the buffers and source to play out through OpenAL with */ ALuint buffers[NUM_BUFFERS]; ALuint source; - /* Handles for the audio stream */ + /* Handle for the audio file */ FilePtr file; - StreamPtr stream; - - /* A temporary data buffer for readAVAudioData to write to and pass to - * OpenAL with */ - ALbyte *data; - ALsizei datasize; /* The format of the output stream */ ALenum format; @@ -128,17 +122,15 @@ static int OpenPlayerFile(StreamPlayer *player, const char *filename) ClosePlayerFile(player); /* Open the file and get the first stream from it */ - player->file = openAVFile(filename); - player->stream = getAVAudioStream(player->file, 0); - if(!player->stream) + player->file = openAudioFile(filename, BUFFER_TIME_MS); + if(!player->file) { fprintf(stderr, "Could not open audio in %s\n", filename); goto error; } /* Get the stream format, and figure out the OpenAL format */ - if(getAVAudioInfo(player->stream, &player->rate, &player->channels, - &player->type) != 0) + if(getAudioInfo(player->file, &player->rate, &player->channels, &player->type) != 0) { fprintf(stderr, "Error getting audio info for %s\n", filename); goto error; @@ -153,23 +145,11 @@ static int OpenPlayerFile(StreamPlayer *player, const char *filename) goto error; } - /* Allocate enough space for the temp buffer, given the format */ - player->datasize = FramesToBytes(BUFFER_SIZE, player->channels, - player->type); - player->data = malloc(player->datasize); - if(player->data == NULL) - { - fprintf(stderr, "Error allocating %d bytes\n", player->datasize); - goto error; - } - return 1; error: - closeAVFile(player->file); + closeAudioFile(player->file); player->file = NULL; - player->stream = NULL; - player->datasize = 0; return 0; } @@ -177,20 +157,15 @@ error: /* Closes the audio file stream */ static void ClosePlayerFile(StreamPlayer *player) { - closeAVFile(player->file); + closeAudioFile(player->file); player->file = NULL; - player->stream = NULL; - - free(player->data); - player->data = NULL; - player->datasize = 0; } /* Prebuffers some audio from the file, and starts playing the source */ static int StartPlayer(StreamPlayer *player) { - size_t i, got; + size_t i; /* Rewind the source position and clear the buffer queue */ alSourceRewind(player->source); @@ -199,13 +174,16 @@ static int StartPlayer(StreamPlayer *player) /* Fill the buffer queue */ for(i = 0;i < NUM_BUFFERS;i++) { + uint8_t *data; + size_t got; + /* Get some data to give it to the buffer */ - got = readAVAudioData(player->stream, player->data, player->datasize); - if(got == 0) break; + data = getAudioData(player->file, &got); + if(!data) break; alBufferSamplesSOFT(player->buffers[i], player->rate, player->format, BytesToFrames(got, player->channels, player->type), - player->channels, player->type, player->data); + player->channels, player->type, data); } if(alGetError() != AL_NO_ERROR) { @@ -242,6 +220,7 @@ static int UpdatePlayer(StreamPlayer *player) while(processed > 0) { ALuint bufid; + uint8_t *data; size_t got; alSourceUnqueueBuffers(player->source, 1, &bufid); @@ -249,12 +228,12 @@ static int UpdatePlayer(StreamPlayer *player) /* Read the next chunk of data, refill the buffer, and queue it * back on the source */ - got = readAVAudioData(player->stream, player->data, player->datasize); - if(got > 0) + data = getAudioData(player->file, &got); + if(data != NULL) { alBufferSamplesSOFT(bufid, player->rate, player->format, BytesToFrames(got, player->channels, player->type), - player->channels, player->type, player->data); + player->channels, player->type, data); alSourceQueueBuffers(player->source, 1, &bufid); } if(alGetError() != AL_NO_ERROR) diff --git a/examples/common/alhelpers.h b/examples/common/alhelpers.h index eda8925e..62ed5be2 100644 --- a/examples/common/alhelpers.h +++ b/examples/common/alhelpers.h @@ -9,6 +9,10 @@ #include #endif +#include "AL/alc.h" +#include "AL/al.h" +#include "AL/alext.h" + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/examples/common/sdl_sound.c b/examples/common/sdl_sound.c new file mode 100644 index 00000000..9e9f1d62 --- /dev/null +++ b/examples/common/sdl_sound.c @@ -0,0 +1,149 @@ +/* + * SDL_sound Decoder Helpers + * + * Copyright (c) 2013 by Chris Robinson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/* This file contains routines for helping to decode audio using SDL_sound. + * There's very little OpenAL-specific code here. + */ +#include "sdl_sound.h" + +#include +#include +#include +#include +#include + +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/alext.h" + +#include "alhelpers.h" + + +static int done_init = 0; + +FilePtr openAudioFile(const char *fname, size_t buftime_ms) +{ + FilePtr file; + ALuint rate; + Uint32 bufsize; + ALenum chans, type; + + /* We need to make sure SDL_sound is initialized. */ + if(!done_init) + { + Sound_Init(); + done_init = 1; + } + + file = Sound_NewSampleFromFile(fname, NULL, 0); + if(!file) + { + fprintf(stderr, "Failed to open %s: %s\n", fname, Sound_GetError()); + return NULL; + } + + if(getAudioInfo(file, &rate, &chans, &type) != 0) + { + Sound_FreeSample(file); + return NULL; + } + + bufsize = FramesToBytes((ALsizei)(buftime_ms/1000.0*rate), chans, type); + if(Sound_SetBufferSize(file, bufsize) == 0) + { + fprintf(stderr, "Failed to set buffer size to %u bytes: %s\n", bufsize, Sound_GetError()); + Sound_FreeSample(file); + return NULL; + } + + return file; +} + +void closeAudioFile(FilePtr file) +{ + if(file) + Sound_FreeSample(file); +} + + +int getAudioInfo(FilePtr file, ALuint *rate, ALenum *channels, ALenum *type) +{ + if(file->actual.channels == 1) + *channels = AL_MONO_SOFT; + else if(file->actual.channels == 2) + *channels = AL_STEREO_SOFT; + else + { + fprintf(stderr, "Unsupported channel count: %d\n", file->actual.channels); + return 1; + } + + if(file->actual.format == AUDIO_U8) + *type = AL_UNSIGNED_BYTE_SOFT; + else if(file->actual.format == AUDIO_S8) + *type = AL_BYTE_SOFT; + else if(file->actual.format == AUDIO_U16SYS) + *type = AL_UNSIGNED_SHORT_SOFT; + else if(file->actual.format == AUDIO_S16SYS) + *type = AL_SHORT_SOFT; + else + { + fprintf(stderr, "Unsupported sample format: 0x%04x\n", file->actual.format); + return 1; + } + + *rate = file->actual.rate; + + return 0; +} + + +uint8_t *getAudioData(FilePtr file, size_t *length) +{ + *length = Sound_Decode(file); + if(*length == 0) + return NULL; + return file->buffer; +} + +void *decodeAudioStream(FilePtr file, size_t *length) +{ + Uint32 got; + char *mem; + + got = Sound_DecodeAll(file); + if(got == 0) + { + *length = 0; + return NULL; + } + + mem = malloc(got); + memcpy(mem, file->buffer, got); + + *length = got; + return mem; +} diff --git a/examples/common/sdl_sound.h b/examples/common/sdl_sound.h new file mode 100644 index 00000000..e93ab92b --- /dev/null +++ b/examples/common/sdl_sound.h @@ -0,0 +1,43 @@ +#ifndef EXAMPLES_SDL_SOUND_H +#define EXAMPLES_SDL_SOUND_H + +#include "AL/al.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Opaque handles to files and streams. Apps don't need to concern themselves + * with the internals */ +typedef Sound_Sample *FilePtr; + +/* Opens a file with SDL_sound, and specifies the size of the sample buffer in + * milliseconds. */ +FilePtr openAudioFile(const char *fname, size_t buftime_ms); + +/* Closes/frees an opened file */ +void closeAudioFile(FilePtr file); + +/* Returns information about the given audio stream. Returns 0 on success. */ +int getAudioInfo(FilePtr file, ALuint *rate, ALenum *channels, ALenum *type); + +/* Returns a pointer to the next available chunk of decoded audio. The size (in + * bytes) of the returned data buffer is stored in 'length', and the returned + * pointer is only valid until the next call to getAudioData. */ +uint8_t *getAudioData(FilePtr file, size_t *length); + +/* Decodes all remaining data from the stream and returns a buffer containing + * the audio data, with the size stored in 'length'. The returned pointer must + * be freed with a call to free(). Note that since this decodes the whole + * stream, using it on lengthy streams (eg, music) will use a lot of memory. + * Such streams are better handled using getAudioData to keep smaller chunks in + * memory at any given time. */ +void *decodeAudioStream(FilePtr, size_t *length); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* EXAMPLES_SDL_SOUND_H */ -- cgit v1.2.3