Cleaned up FixedSizeStream to ensure the buffer size is ALWAYS the

requested buffer size, except for maybe the last buffer in the stream.
This commit is contained in:
casey langen 2016-11-27 15:46:54 -08:00
parent d41f44deaf
commit d28cfcfd52
5 changed files with 106 additions and 73 deletions

View File

@ -61,7 +61,7 @@ Buffer::Buffer(void)
} }
Buffer::~Buffer() { Buffer::~Buffer() {
delete this->buffer; delete[] this->buffer;
} }
BufferPtr Buffer::Create() { BufferPtr Buffer::Create() {
@ -106,8 +106,8 @@ void Buffer::CopyFormat(BufferPtr fromBuffer) {
void Buffer::ResizeBuffer() { void Buffer::ResizeBuffer() {
if (this->sampleSize > this->internalBufferSize) { if (this->sampleSize > this->internalBufferSize) {
if (this->buffer) { if (this->buffer) {
delete this->buffer; delete[] this->buffer;
this->buffer = NULL; this->buffer = nullptr;
} }
this->buffer = new float[this->sampleSize]; this->buffer = new float[this->sampleSize];
@ -132,7 +132,7 @@ void Buffer::Copy(float* buffer, long samples) {
if (samples > this->internalBufferSize) { if (samples > this->internalBufferSize) {
float *newBuffer = new float[samples]; float *newBuffer = new float[samples];
CopyFloat(newBuffer, buffer, samples); CopyFloat(newBuffer, buffer, samples);
delete this->buffer; delete[] this->buffer;
this->buffer = newBuffer; this->buffer = newBuffer;
this->internalBufferSize = samples; this->internalBufferSize = samples;
} }
@ -143,45 +143,36 @@ void Buffer::Copy(float* buffer, long samples) {
this->sampleSize = samples; this->sampleSize = samples;
} }
bool Buffer::Append(BufferPtr appendBuffer) { void Buffer::Append(float* src, long samples) {
if (this->SampleRate() == appendBuffer->SampleRate() &&
this->Channels() == appendBuffer->Channels())
{
/* number of floats (not bytes) in buffer */ /* number of floats (not bytes) in buffer */
long newBufferSize = (this->Samples() + appendBuffer->Samples()); long newBufferSize = (this->Samples() + samples);
if (newBufferSize > this->internalBufferSize) { /* resize, then copy, if too small */ if (newBufferSize > this->internalBufferSize) { /* resize, then copy, if too small */
float *newBuffer = new float[newBufferSize]; float *newBuffer = new float[newBufferSize];
CopyFloat(newBuffer, this->buffer, this->sampleSize); CopyFloat(newBuffer, this->buffer, this->sampleSize);
float *dst = &newBuffer[this->sampleSize]; float *dst = &newBuffer[this->sampleSize];
float *src = appendBuffer->BufferPointer(); CopyFloat(dst, src, samples);
long count = appendBuffer->Samples();
CopyFloat(dst, src, count); delete[] this->buffer;
delete this->buffer;
#if DEBUG > 0
std::cerr << "resized with realloc old: " << this->internalBufferSize << " new: " << newBufferSize << "\n";
#endif
this->buffer = newBuffer; this->buffer = newBuffer;
this->internalBufferSize = newBufferSize; this->internalBufferSize = newBufferSize;
} }
else { /* append, no resize required */ else { /* append, no resize required */
float *dst = &this->buffer[this->sampleSize]; float *dst = &this->buffer[this->sampleSize];
float *src = appendBuffer->BufferPointer(); CopyFloat(dst, src, samples);
long count = appendBuffer->Samples(); this->internalBufferSize += samples;
CopyFloat(dst, src, count);
#if DEBUG > 0
std::cerr << "appended " << count << " floats to existing buffer, logical bytes=" << newBufferSize << "\n";
#endif
} }
this->sampleSize = newBufferSize; this->sampleSize = newBufferSize;
}
bool Buffer::Append(BufferPtr appendBuffer) {
if (this->SampleRate() == appendBuffer->SampleRate() &&
this->Channels() == appendBuffer->Channels())
{
this->Append(appendBuffer->BufferPointer(), appendBuffer->Samples());
return true; return true;
} }

View File

@ -66,6 +66,7 @@ namespace musik { namespace core { namespace audio {
void SetPosition(double position); void SetPosition(double position);
void Copy(float* buffer, long samples); void Copy(float* buffer, long samples);
void Append(float* buffer, long samples);
bool Append(BufferPtr appendBuffer); bool Append(BufferPtr appendBuffer);
void CopyFormat(BufferPtr fromBuffer); void CopyFormat(BufferPtr fromBuffer);

View File

@ -45,6 +45,16 @@ using musik::core::PluginFactory;
static std::string TAG = "FixedSizeStream"; static std::string TAG = "FixedSizeStream";
#define SET_OFFSET(target, offset) \
target->SetPosition( \
((double) this->decoderSamplePosition + offset) / \
((double) target->Channels()) / \
((double) this->decoderSampleRate));
#define COPY_BUFFER(target, current, count, offset) \
target->Copy(&current->BufferPointer()[offset], count); \
SET_OFFSET(target, offset) \
FixedSizeStream::FixedSizeStream(int samplesPerChannel, int bufferCount, unsigned int options) FixedSizeStream::FixedSizeStream(int samplesPerChannel, int bufferCount, unsigned int options)
: options(options) : options(options)
, samplesPerChannel(samplesPerChannel) , samplesPerChannel(samplesPerChannel)
@ -52,7 +62,7 @@ FixedSizeStream::FixedSizeStream(int samplesPerChannel, int bufferCount, unsigne
, decoderSampleRate(0) , decoderSampleRate(0)
, decoderChannels(0) , decoderChannels(0)
, decoderSamplePosition(0) , decoderSamplePosition(0)
, currentBuffer(Buffer::Create()) , decoderBuffer(Buffer::Create())
, dspBuffer(Buffer::Create()) , dspBuffer(Buffer::Create())
{ {
if ((this->options & NoDSP) == 0) { if ((this->options & NoDSP) == 0) {
@ -60,6 +70,10 @@ FixedSizeStream::FixedSizeStream(int samplesPerChannel, int bufferCount, unsigne
this->dsps = PluginFactory::Instance().QueryInterface<IDSP, Deleter>("GetDSP"); this->dsps = PluginFactory::Instance().QueryInterface<IDSP, Deleter>("GetDSP");
} }
for (int i = 0; i < bufferCount; i++) {
this->recycledBuffers.push_back(Buffer::Create());
}
this->LoadDecoderPlugins(); this->LoadDecoderPlugins();
} }
@ -78,6 +92,10 @@ double FixedSizeStream::SetPosition(double requestedSeconds) {
this->decoderSamplePosition = this->decoderSamplePosition =
(uint64)(actualSeconds * rate) * this->decoderChannels; (uint64)(actualSeconds * rate) * this->decoderChannels;
this->recycledBuffers.splice(
this->recycledBuffers.begin(),
this->filledBuffers);
} }
return actualSeconds; return actualSeconds;
@ -137,12 +155,12 @@ void FixedSizeStream::OnBufferProcessedByPlayer(BufferPtr buffer) {
this->RecycleBuffer(buffer); this->RecycleBuffer(buffer);
} }
BufferPtr FixedSizeStream::GetNextBufferFromDecoder() { bool FixedSizeStream::GetNextBufferFromDecoder() {
BufferPtr buffer = this->currentBuffer; BufferPtr buffer = this->decoderBuffer;
/* get a spare buffer, then ask the decoder for some data */ /* get a spare buffer, then ask the decoder for some data */
if (!this->decoder->GetBuffer(buffer.get())) { if (!this->decoder->GetBuffer(buffer.get())) {
return BufferPtr(); return false;
} }
/* remember the sample rate so we can calculate the current time-position */ /* remember the sample rate so we can calculate the current time-position */
@ -160,7 +178,7 @@ BufferPtr FixedSizeStream::GetNextBufferFromDecoder() {
((double) buffer->Channels()) / ((double) buffer->Channels()) /
((double) this->decoderSampleRate)); ((double) this->decoderSampleRate));
return buffer; return true;
} }
inline BufferPtr FixedSizeStream::GetEmptyBuffer() { inline BufferPtr FixedSizeStream::GetEmptyBuffer() {
@ -172,53 +190,67 @@ inline BufferPtr FixedSizeStream::GetEmptyBuffer() {
} }
else { else {
target = Buffer::Create(); target = Buffer::Create();
target->CopyFormat(this->currentBuffer); target->CopyFormat(this->decoderBuffer);
} }
return target; return target;
} }
#define COPY_BUFFER(target, current, count, offset) \
target->Copy(&current->BufferPointer()[offset], count); \
target->SetPosition( \
((double) this->decoderSamplePosition + offset) / \
((double) current->Channels()) / \
((double) this->decoderSampleRate)); \
this->filledBuffers.push_back(target);
BufferPtr FixedSizeStream::GetNextProcessedOutputBuffer() { BufferPtr FixedSizeStream::GetNextProcessedOutputBuffer() {
BufferPtr currentBuffer; BufferPtr currentBuffer;
/* ensure we have at least BUFFER_COUNT buffers, and that at least half of them /* ensure we have at least BUFFER_COUNT buffers, and that at least half of them
are filled with data! */ are filled with data! */
while (this->filledBuffers.size() < (this->bufferCount / 2) || while (this->filledBuffers.size() < (this->bufferCount / 2)) {
this->filledBuffers.size() + this->recycledBuffers.size() < this->bufferCount)
{
/* ask the decoder for the next buffer */ /* ask the decoder for the next buffer */
currentBuffer = this->GetNextBufferFromDecoder(); if (!GetNextBufferFromDecoder()) {
break;
if (!currentBuffer) {
break; /* important... bust out of the loop when we're done! */
} }
/* break the buffer into 512 sample per channel buffers. this will currentBuffer = this->decoderBuffer;
help us ensure visualizer data is uniform. note that the last buffer
may not be exactly 512 -- that should be fine, generally. */
BufferPtr target;
int floatsPerBuffer = this->samplesPerChannel * currentBuffer->Channels(); int floatsPerBuffer = this->samplesPerChannel * currentBuffer->Channels();
int buffers = currentBuffer->Samples() / floatsPerBuffer;
BufferPtr target;
int offset = 0; int offset = 0;
for (int i = 0; i < buffers; i++) { /* if we have a partial / remainder buffer hanging out from the last time
through, let's fill it up with the head of the new buffer. */
if (remainder) {
long desired = floatsPerBuffer - remainder->Samples();
long actual = std::min(currentBuffer->Samples(), desired);
remainder->Append(currentBuffer->BufferPointer(), actual);
SET_OFFSET(remainder, 0);
if (remainder->Samples() == floatsPerBuffer) {
/* normal case: we were able to fill it; add it to the list of
filled buffers and continue to fill some more... */
this->filledBuffers.push_back(remainder);
offset += actual;
remainder.reset();
}
else {
continue; /* already consumed all of the decoder buffer. go back
to the top of the loop to get some more data. */
}
}
/* now that the remainder is taken care of, break the rest of the data
into uniform chunks */
int buffersToFill = (currentBuffer->Samples() - offset) / floatsPerBuffer;
for (int i = 0; i < buffersToFill; i++) {
target = this->GetEmptyBuffer(); target = this->GetEmptyBuffer();
COPY_BUFFER(target, currentBuffer, floatsPerBuffer, offset); COPY_BUFFER(target, currentBuffer, floatsPerBuffer, offset);
this->filledBuffers.push_back(target);
offset += floatsPerBuffer; offset += floatsPerBuffer;
} }
if (offset < this->currentBuffer->Samples()) { if (offset < currentBuffer->Samples()) {
target = this->GetEmptyBuffer(); remainder = this->GetEmptyBuffer();
COPY_BUFFER(target, currentBuffer, this->currentBuffer->Samples() - offset, offset); COPY_BUFFER(remainder, currentBuffer, currentBuffer->Samples() - offset, offset);
} }
} }
@ -241,6 +273,13 @@ BufferPtr FixedSizeStream::GetNextProcessedOutputBuffer() {
return currentBuffer; return currentBuffer;
} }
/* final remainder */
if (remainder) {
BufferPtr result = remainder;
remainder.reset();
return result;
}
return BufferPtr(); return BufferPtr();
} }

View File

@ -71,7 +71,7 @@ namespace musik { namespace core { namespace audio {
private: private:
void RecycleBuffer(BufferPtr oldBuffer); void RecycleBuffer(BufferPtr oldBuffer);
BufferPtr GetNextBufferFromDecoder(); bool GetNextBufferFromDecoder();
BufferPtr GetEmptyBuffer(); BufferPtr GetEmptyBuffer();
void LoadDecoderPlugins(); void LoadDecoderPlugins();
@ -90,9 +90,11 @@ namespace musik { namespace core { namespace audio {
BufferList recycledBuffers; BufferList recycledBuffers;
BufferList filledBuffers; BufferList filledBuffers;
BufferPtr currentBuffer; BufferPtr decoderBuffer;
BufferPtr dspBuffer; BufferPtr dspBuffer;
BufferPtr remainder;
unsigned int options; unsigned int options;
int samplesPerChannel; int samplesPerChannel;
int bufferCount; int bufferCount;

View File

@ -139,7 +139,7 @@ int Player::State() {
void Player::ThreadLoop() { void Player::ThreadLoop() {
/* create and open the stream */ /* create and open the stream */
this->stream = DynamicStream::Create(); this->stream = FixedSizeStream::Create();
BufferPtr buffer; BufferPtr buffer;