From a69938364fdbabee5c2c56248906a59225e43cff Mon Sep 17 00:00:00 2001 From: Nicolay Korslund Date: Mon, 16 Aug 2010 14:13:13 +0200 Subject: [PATCH] Rewrote audiere to use new sample_reader --- sound/sources/audiere_source.cpp | 77 +++----------------------------- sound/sources/audiere_source.hpp | 21 +++------ sound/sources/sample_reader.cpp | 75 +++++++++++++++++++++++++++++++ sound/sources/sample_reader.hpp | 42 +++++++++++++++++ sound/tests/Makefile | 4 +- 5 files changed, 130 insertions(+), 89 deletions(-) create mode 100644 sound/sources/sample_reader.cpp create mode 100644 sound/sources/sample_reader.hpp diff --git a/sound/sources/audiere_source.cpp b/sound/sources/audiere_source.cpp index 6fde40c07..1f11272b0 100644 --- a/sound/sources/audiere_source.cpp +++ b/sound/sources/audiere_source.cpp @@ -27,65 +27,6 @@ void AudiereSource::getInfo(int32_t *rate, int32_t *channels, int32_t *bits) } } -/* - 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. - */ -size_t AudiereSource::read(void *_data, size_t length) -{ - if(isEof) return 0; - - 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); - - if(res < frames) - isEof = true; - - // Are we missing data? If we're at the end of the stream, then this - // doesn't apply. - if(!isEof && pullSize) - { - // Read one more sample - if(sample->read(1, pullOver) != 0) - { - // Then, move as much of it as we can fit into the output - // data - memcpy(data+length-pullSize, pullOver, pullSize); - } - else - // Failed reading, we're out of data - isEof = true; - } - - // If we're at the end of the stream, then no data remains to be - // pulled over - if(isEof) - pullSize = 0; - - // Return the total number of bytes stored - return frameSize*res + pullSize; -} - // --- Constructors --- AudiereSource::AudiereSource(const std::string &file) @@ -95,7 +36,7 @@ AudiereSource::AudiereSource(const std::string &file) if(!sample) fail("Couldn't load file " + file); - setup(); + doSetup(); } AudiereSource::AudiereSource(StreamPtr input) @@ -106,15 +47,15 @@ AudiereSource::AudiereSource(StreamPtr input) if(!sample) fail("Couldn't load stream"); - setup(); + doSetup(); } AudiereSource::AudiereSource(audiere::SampleSourcePtr src) : sample(src) -{ assert(sample); setup(); } +{ assert(sample); doSetup(); } // Common function called from all constructors -void AudiereSource::setup() +void AudiereSource::doSetup() { assert(sample); @@ -122,14 +63,8 @@ void AudiereSource::setup() int channels, rate; sample->getFormat(channels, rate, fmt); - pullSize = 0; - - // 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); + // Calculate the size of one frame, and pass it to SampleReader. + setup(GetSampleSize(fmt) * channels); isSeekable = sample->isSeekable(); hasPosition = true; diff --git a/sound/sources/audiere_source.hpp b/sound/sources/audiere_source.hpp index 476546af3..d0189b710 100644 --- a/sound/sources/audiere_source.hpp +++ b/sound/sources/audiere_source.hpp @@ -1,7 +1,7 @@ #ifndef MANGLE_SOUND_AUDIERE_SOURCE_H #define MANGLE_SOUND_AUDIERE_SOURCE_H -#include "../source.hpp" +#include "sample_reader.hpp" #include @@ -9,24 +9,14 @@ namespace Mangle { namespace Sound { /// A sample source that decodes files using Audiere -class AudiereSource : public SampleSource +class AudiereSource : public SampleReader { audiere::SampleSourcePtr sample; - // Number of bytes we cache between reads. This should correspond to - // the maximum possible value of frameSize. - static const int PSIZE = 10; + size_t readSamples(void *data, size_t length) + { return sample->read(length, data); } - // Size of one frame, in bytes - int frameSize; - - // Temporary storage for unevenly read samples. See the comment for - // read() in the .cpp file. - char pullOver[PSIZE]; - // How much of the above buffer is in use - int pullSize; - - void setup(); + void doSetup(); public: /// Decode the given sound file @@ -39,7 +29,6 @@ class AudiereSource : public SampleSource AudiereSource(audiere::SampleSourcePtr src); void getInfo(int32_t *rate, int32_t *channels, int32_t *bits); - size_t read(void *data, size_t length); void seek(size_t pos) { sample->setPosition(pos/frameSize); } size_t tell() const { return sample->getPosition()*frameSize; } diff --git a/sound/sources/sample_reader.cpp b/sound/sources/sample_reader.cpp new file mode 100644 index 000000000..7cf5b0e00 --- /dev/null +++ b/sound/sources/sample_reader.cpp @@ -0,0 +1,75 @@ +#include "sample_reader.hpp" + +#include + +using namespace Mangle::Sound; + +void SampleReader::setup(int size) +{ + pullSize = 0; + frameSize = size; + pullOver = new char[size]; +} + +SampleReader::~SampleReader() +{ + if(pullOver) + delete[] pullOver; +} + +size_t SampleReader::read(void *_data, size_t length) +{ + if(isEof) return 0; + char *data = (char*)_data; + + // Move the remains from the last operation first + if(pullSize) + { + // pullSize is how much was stored the last time. The data is + // stored at the end of the buffer. + memcpy(data, pullOver+(frameSize-pullSize), pullSize); + length -= pullSize; + data += pullSize; + pullSize = 0; + } + + // Number of whole frames + size_t frames = length / frameSize; + + // Read the data + size_t res = readSamples(data, frames); + + // Total bytes read + size_t num = res*frameSize; + data += num; + + if(res < frames) + { + // End of stream. + isEof = true; + // Determine how much we read + return data-(char*)_data; + } + + // Determine the overshoot + pullSize = length - num; + + // Are we missing data? + if(pullSize) + { + // Fill in one sample + res = readSamples(pullOver,1); + if(res) + { + // Move as much as we can into the output buffer + memcpy(data, pullOver, pullSize); + data += pullSize; + } + else + // Failed reading, we're out of data + isEof = true; + } + + // Return the total number of bytes stored + return data-(char*)_data; +} diff --git a/sound/sources/sample_reader.hpp b/sound/sources/sample_reader.hpp new file mode 100644 index 000000000..16b98bee3 --- /dev/null +++ b/sound/sources/sample_reader.hpp @@ -0,0 +1,42 @@ +#ifndef MANGLE_SOUND_SAMPLE_READER_H +#define MANGLE_SOUND_SAMPLE_READER_H + +#include "../source.hpp" + +namespace Mangle { +namespace Sound { + + /* This is a helper base class for other SampleSource + implementations. Certain sources (like Audiere and libsndfile) + insist on reading whole samples rather than bytes. This class + compensates for that, and allows you to read bytes rather than + samples. + */ +class SampleReader : public SampleSource +{ + // Pullover buffer + char* pullOver; + + // How much of the above buffer is in use. + int pullSize; + +protected: + // Size of one frame, in bytes. This is also the size of the + // pullOver buffer. + int frameSize; + + // MUST be called by base class constructor. The parameter gives the + // size of one sample/frame, in bytes. + void setup(int); + + // Read the given number of samples, in multiples of frameSize. Does + // not have to set or respect isEof. + virtual size_t readSamples(void *data, size_t num) = 0; + + public: + SampleReader() : pullOver(NULL) {} + ~SampleReader(); + size_t read(void *data, size_t length); +}; +}} // Namespace +#endif diff --git a/sound/tests/Makefile b/sound/tests/Makefile index 1c6c1fda5..0ad946fa9 100644 --- a/sound/tests/Makefile +++ b/sound/tests/Makefile @@ -7,7 +7,7 @@ I_FFMPEG=-I/usr/include/libavcodec -I/usr/include/libavformat L_OPENAL=$(shell pkg-config --libs openal) L_AUDIERE=-laudiere -openal_audiere_test: openal_audiere_test.cpp ../sources/audiere_source.cpp ../outputs/openal_out.cpp ../../stream/clients/audiere_file.cpp +openal_audiere_test: openal_audiere_test.cpp ../sources/audiere_source.cpp ../sources/sample_reader.cpp ../outputs/openal_out.cpp ../../stream/clients/audiere_file.cpp $(GCC) $^ -o $@ $(L_AUDIERE) $(L_OPENAL) openal_ffmpeg_test: openal_ffmpeg_test.cpp ../sources/ffmpeg_source.cpp ../outputs/openal_out.cpp @@ -19,7 +19,7 @@ openal_mpg123_test: openal_mpg123_test.cpp ../sources/mpg123_source.cpp ../outpu openal_output_test: openal_output_test.cpp ../outputs/openal_out.cpp $(GCC) $^ -o $@ $(L_OPENAL) -audiere_source_test: audiere_source_test.cpp ../sources/audiere_source.cpp ../../stream/clients/audiere_file.cpp +audiere_source_test: audiere_source_test.cpp ../sources/audiere_source.cpp ../../stream/clients/audiere_file.cpp ../sources/sample_reader.cpp $(GCC) $^ -o $@ $(L_AUDIERE) ffmpeg_source_test: ffmpeg_source_test.cpp ../sources/ffmpeg_source.cpp