Use SDL_sound for the alstream example
This commit is contained in:
+21
-5
@@ -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}"
|
||||
|
||||
+22
-43
@@ -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)
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "AL/alc.h"
|
||||
#include "AL/al.h"
|
||||
#include "AL/alext.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* SDL_sound Decoder Helpers
|
||||
*
|
||||
* Copyright (c) 2013 by Chris Robinson <chris.kcat@gmail.com>
|
||||
*
|
||||
* 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 <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <SDL_sound.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#ifndef EXAMPLES_SDL_SOUND_H
|
||||
#define EXAMPLES_SDL_SOUND_H
|
||||
|
||||
#include "AL/al.h"
|
||||
|
||||
#include <SDL_sound.h>
|
||||
|
||||
#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 */
|
||||
Reference in New Issue
Block a user