diff --git a/sound/imp/input_audiere.cpp b/sound/imp/input_audiere.cpp new file mode 100644 index 000000000..5ca85ffd9 --- /dev/null +++ b/sound/imp/input_audiere.cpp @@ -0,0 +1,119 @@ +#include "input_audiere.h" +#include + +// Exception handling +class Audiere_Exception : public std::exception +{ + std::string msg; + + public: + + Audiere_Exception(const std::string &m) : msg(m) {} + ~Audiere_Exception() throw() {} + virtual const char* what() const throw() { return msg.c_str(); } +}; + +static void fail(const std::string &msg) +{ + throw Audiere_Exception("Audiere exception: " + msg); +} + +using namespace audiere; +using namespace Mangle::Sound; + +// --- InputManager --- + +InputSource *AudiereInput::load(const std::string &file) +{ return new AudiereSource(file); } + +// --- InputSource --- + +AudiereSource::AudiereSource(const std::string &file) +{ + SampleSourcePtr sample = OpenSampleSource(file.c_str()); + if(!sample) + fail("Couldn't load file " + file); + + buf = CreateSampleBuffer(sample); +} + +InputStream *AudiereSource::getStream() +{ + return new AudiereStream(buf->openStream()); +} + +// --- InputStream --- + +AudiereStream::AudiereStream(SampleSourcePtr _sample) + : sample(_sample), pullSize(0) +{ + assert(sample); + + SampleFormat fmt; + int channels, rate; + sample->getFormat(channels, rate, fmt); + + // Calculate the size of one frame + frameSize = GetSampleSize(fmt) * channels; + + // Make sure that our pullover hack will work. Increase this size if + // this doesn't work in all cases. + assert(frameSize <= PSIZE); +} + +void AudiereStream::getInfo(int32_t *rate, int32_t *channels, int32_t *bits) +{ + SampleFormat fmt; + sample->getFormat(*channels, *rate, fmt); + if(fmt == SF_U8) + *bits = 8; + else if(fmt == SF_S16) + *bits = 16; + else assert(0); +} + +/* + Get data. Since Audiere operates with frames, not bytes, there's a + little conversion magic going on here. We need to make sure we're + reading a whole number of frames - if not, we need to store the + remainding part of the last frame and remember it for the next read + operation. + + */ +uint32_t AudiereStream::getData(void *_data, uint32_t length) +{ + char *data = (char*)_data; + + // Move the remains from the last operation first + if(pullSize) + { + // pullSize is how much was stored the last time, so skip that. + memcpy(data, pullOver+pullSize, PSIZE-pullSize); + length -= pullSize; + data += pullSize; + } + + // Determine the overshoot up front + pullSize = length % frameSize; + + // Number of whole frames + int frames = length / frameSize; + + // Read the data + int res = sample->read(frames, data); + + // Are we missing data? If resread(1, pullOver) != 0)) + { + // Now, move as much of it as we can fit into the output + // data + memcpy(data+length-pullSize, pullOver, pullSize); + } + else pullSize = 0; + + // Return the total number of bytes stored + return frameSize*res + pullSize; +} diff --git a/sound/imp/input_audiere.h b/sound/imp/input_audiere.h new file mode 100644 index 000000000..5acc1a73d --- /dev/null +++ b/sound/imp/input_audiere.h @@ -0,0 +1,52 @@ +#ifndef MANGLE_SOUND_AUDIERE_INPUT_H +#define MANGLE_SOUND_AUDIERE_INPUT_H + +#include "../input.h" + +#include + +namespace Mangle { +namespace Sound { + +/// Implementation of Sound::InputManager for Audiere +class AudiereInput : public InputManager +{ + public: + InputSource *load(const std::string &file); +}; + +/// Audiere InputSource implementation +class AudiereSource : public InputSource +{ + audiere::SampleBufferPtr buf; + + public: + AudiereSource(const std::string &file); + InputStream *getStream(); + void drop() { delete this; } +}; + +/// Audiere InputStream implementation +class AudiereStream : public InputStream +{ + audiere::SampleSourcePtr sample; + int frameSize; // Size of one frame, in bytes + + static const int PSIZE = 10; + + // Temporary storage for unevenly read samples. See the comment for + // getData() in the .cpp file. + char pullOver[PSIZE]; + // How much of the above buffer is in use + int pullSize; + + public: + AudiereStream(audiere::SampleSourcePtr _sample); + + void getInfo(int32_t *rate, int32_t *channels, int32_t *bits); + uint32_t getData(void *data, uint32_t length); + void drop() { delete this; } +}; + +}} // Namespace +#endif diff --git a/sound/imp/openal_audiere.h b/sound/imp/openal_audiere.h new file mode 100644 index 000000000..65947b22f --- /dev/null +++ b/sound/imp/openal_audiere.h @@ -0,0 +1,29 @@ +#ifndef MANGLE_FFMPEG_OPENAL_H +#define MANGLE_FFMPEG_OPENAL_H + +#include "input_filter.h" +#include "input_audiere.h" +#include "output_openal.h" + +namespace Mangle { +namespace Sound { + +/// A InputFilter that adds audiere decoding to OpenAL. Audiere has +/// it's own output, but OpenAL sports 3D and other advanced features. +class OpenAL_Audiere_Manager : public InputFilter +{ + public: + OpenAL_Audiere_Manager() + { + set(new OpenAL_Manager, + new AudiereInput); + } + ~OpenAL_Audiere_Manager() + { + delete snd; + delete inp; + } +}; + +}} +#endif diff --git a/sound/imp/openal_ffmpeg.h b/sound/imp/openal_ffmpeg.h index 80882d0f5..179d3cb70 100644 --- a/sound/imp/openal_ffmpeg.h +++ b/sound/imp/openal_ffmpeg.h @@ -8,7 +8,7 @@ namespace Mangle { namespace Sound { -/// A PairManager filter that adds FFmpeg decoding to OpenAL +/// An InputFilter that adds FFmpeg decoding to OpenAL class OpenAL_FFM_Manager : public InputFilter { public: diff --git a/sound/tests/Makefile b/sound/tests/Makefile index 4cdf5ab58..22da35432 100644 --- a/sound/tests/Makefile +++ b/sound/tests/Makefile @@ -1,15 +1,17 @@ GCC=g++ -I../ -I../imp/ -all: audiere_test ffmpeg_openal_test +all: audiere_test ffmpeg_openal_test openal_audiere_test L_FFMPEG=$(shell pkg-config --libs libavcodec libavformat) L_OPENAL=$(shell pkg-config --libs openal) - L_AUDIERE=-laudiere ffmpeg_openal_test: ffmpeg_openal_test.cpp ../imp/input_ffmpeg.cpp ../imp/output_openal.cpp $(GCC) $^ -o $@ $(L_FFMPEG) $(L_OPENAL) +openal_audiere_test: openal_audiere_test.cpp ../imp/input_audiere.cpp ../imp/output_openal.cpp + $(GCC) $^ -o $@ $(L_AUDIERE) $(L_OPENAL) + audiere_test: audiere_test.cpp ../imp/audiere_imp.cpp $(GCC) $^ -o $@ $(L_AUDIERE) diff --git a/sound/tests/openal_audiere_test.cpp b/sound/tests/openal_audiere_test.cpp new file mode 100644 index 000000000..c9011f48e --- /dev/null +++ b/sound/tests/openal_audiere_test.cpp @@ -0,0 +1,7 @@ +#include "openal_audiere.h" + +using namespace Mangle::Sound; + +OpenAL_Audiere_Manager mg; + +#include "common.cpp"