forked from mirror/openmw-tes3mp
Rewrote audiere to use new sample_reader
This commit is contained in:
parent
3db61c8bdd
commit
a69938364f
5 changed files with 130 additions and 89 deletions
|
@ -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 ---
|
// --- Constructors ---
|
||||||
|
|
||||||
AudiereSource::AudiereSource(const std::string &file)
|
AudiereSource::AudiereSource(const std::string &file)
|
||||||
|
@ -95,7 +36,7 @@ AudiereSource::AudiereSource(const std::string &file)
|
||||||
if(!sample)
|
if(!sample)
|
||||||
fail("Couldn't load file " + file);
|
fail("Couldn't load file " + file);
|
||||||
|
|
||||||
setup();
|
doSetup();
|
||||||
}
|
}
|
||||||
|
|
||||||
AudiereSource::AudiereSource(StreamPtr input)
|
AudiereSource::AudiereSource(StreamPtr input)
|
||||||
|
@ -106,15 +47,15 @@ AudiereSource::AudiereSource(StreamPtr input)
|
||||||
if(!sample)
|
if(!sample)
|
||||||
fail("Couldn't load stream");
|
fail("Couldn't load stream");
|
||||||
|
|
||||||
setup();
|
doSetup();
|
||||||
}
|
}
|
||||||
|
|
||||||
AudiereSource::AudiereSource(audiere::SampleSourcePtr src)
|
AudiereSource::AudiereSource(audiere::SampleSourcePtr src)
|
||||||
: sample(src)
|
: sample(src)
|
||||||
{ assert(sample); setup(); }
|
{ assert(sample); doSetup(); }
|
||||||
|
|
||||||
// Common function called from all constructors
|
// Common function called from all constructors
|
||||||
void AudiereSource::setup()
|
void AudiereSource::doSetup()
|
||||||
{
|
{
|
||||||
assert(sample);
|
assert(sample);
|
||||||
|
|
||||||
|
@ -122,14 +63,8 @@ void AudiereSource::setup()
|
||||||
int channels, rate;
|
int channels, rate;
|
||||||
sample->getFormat(channels, rate, fmt);
|
sample->getFormat(channels, rate, fmt);
|
||||||
|
|
||||||
pullSize = 0;
|
// Calculate the size of one frame, and pass it to SampleReader.
|
||||||
|
setup(GetSampleSize(fmt) * channels);
|
||||||
// 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);
|
|
||||||
|
|
||||||
isSeekable = sample->isSeekable();
|
isSeekable = sample->isSeekable();
|
||||||
hasPosition = true;
|
hasPosition = true;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef MANGLE_SOUND_AUDIERE_SOURCE_H
|
#ifndef MANGLE_SOUND_AUDIERE_SOURCE_H
|
||||||
#define MANGLE_SOUND_AUDIERE_SOURCE_H
|
#define MANGLE_SOUND_AUDIERE_SOURCE_H
|
||||||
|
|
||||||
#include "../source.hpp"
|
#include "sample_reader.hpp"
|
||||||
|
|
||||||
#include <audiere.h>
|
#include <audiere.h>
|
||||||
|
|
||||||
|
@ -9,24 +9,14 @@ namespace Mangle {
|
||||||
namespace Sound {
|
namespace Sound {
|
||||||
|
|
||||||
/// A sample source that decodes files using Audiere
|
/// A sample source that decodes files using Audiere
|
||||||
class AudiereSource : public SampleSource
|
class AudiereSource : public SampleReader
|
||||||
{
|
{
|
||||||
audiere::SampleSourcePtr sample;
|
audiere::SampleSourcePtr sample;
|
||||||
|
|
||||||
// Number of bytes we cache between reads. This should correspond to
|
size_t readSamples(void *data, size_t length)
|
||||||
// the maximum possible value of frameSize.
|
{ return sample->read(length, data); }
|
||||||
static const int PSIZE = 10;
|
|
||||||
|
|
||||||
// Size of one frame, in bytes
|
void doSetup();
|
||||||
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();
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Decode the given sound file
|
/// Decode the given sound file
|
||||||
|
@ -39,7 +29,6 @@ class AudiereSource : public SampleSource
|
||||||
AudiereSource(audiere::SampleSourcePtr src);
|
AudiereSource(audiere::SampleSourcePtr src);
|
||||||
|
|
||||||
void getInfo(int32_t *rate, int32_t *channels, int32_t *bits);
|
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); }
|
void seek(size_t pos) { sample->setPosition(pos/frameSize); }
|
||||||
size_t tell() const { return sample->getPosition()*frameSize; }
|
size_t tell() const { return sample->getPosition()*frameSize; }
|
||||||
|
|
75
sound/sources/sample_reader.cpp
Normal file
75
sound/sources/sample_reader.cpp
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
#include "sample_reader.hpp"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
42
sound/sources/sample_reader.hpp
Normal file
42
sound/sources/sample_reader.hpp
Normal file
|
@ -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
|
|
@ -7,7 +7,7 @@ I_FFMPEG=-I/usr/include/libavcodec -I/usr/include/libavformat
|
||||||
L_OPENAL=$(shell pkg-config --libs openal)
|
L_OPENAL=$(shell pkg-config --libs openal)
|
||||||
L_AUDIERE=-laudiere
|
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)
|
$(GCC) $^ -o $@ $(L_AUDIERE) $(L_OPENAL)
|
||||||
|
|
||||||
openal_ffmpeg_test: openal_ffmpeg_test.cpp ../sources/ffmpeg_source.cpp ../outputs/openal_out.cpp
|
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
|
openal_output_test: openal_output_test.cpp ../outputs/openal_out.cpp
|
||||||
$(GCC) $^ -o $@ $(L_OPENAL)
|
$(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)
|
$(GCC) $^ -o $@ $(L_AUDIERE)
|
||||||
|
|
||||||
ffmpeg_source_test: ffmpeg_source_test.cpp ../sources/ffmpeg_source.cpp
|
ffmpeg_source_test: ffmpeg_source_test.cpp ../sources/ffmpeg_source.cpp
|
||||||
|
|
Loading…
Reference in a new issue