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

View File

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

View File

@ -45,6 +45,16 @@ using musik::core::PluginFactory;
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)
: options(options)
, samplesPerChannel(samplesPerChannel)
@ -52,7 +62,7 @@ FixedSizeStream::FixedSizeStream(int samplesPerChannel, int bufferCount, unsigne
, decoderSampleRate(0)
, decoderChannels(0)
, decoderSamplePosition(0)
, currentBuffer(Buffer::Create())
, decoderBuffer(Buffer::Create())
, dspBuffer(Buffer::Create())
{
if ((this->options & NoDSP) == 0) {
@ -60,6 +70,10 @@ FixedSizeStream::FixedSizeStream(int samplesPerChannel, int bufferCount, unsigne
this->dsps = PluginFactory::Instance().QueryInterface<IDSP, Deleter>("GetDSP");
}
for (int i = 0; i < bufferCount; i++) {
this->recycledBuffers.push_back(Buffer::Create());
}
this->LoadDecoderPlugins();
}
@ -78,6 +92,10 @@ double FixedSizeStream::SetPosition(double requestedSeconds) {
this->decoderSamplePosition =
(uint64)(actualSeconds * rate) * this->decoderChannels;
this->recycledBuffers.splice(
this->recycledBuffers.begin(),
this->filledBuffers);
}
return actualSeconds;
@ -137,12 +155,12 @@ void FixedSizeStream::OnBufferProcessedByPlayer(BufferPtr buffer) {
this->RecycleBuffer(buffer);
}
BufferPtr FixedSizeStream::GetNextBufferFromDecoder() {
BufferPtr buffer = this->currentBuffer;
bool FixedSizeStream::GetNextBufferFromDecoder() {
BufferPtr buffer = this->decoderBuffer;
/* get a spare buffer, then ask the decoder for some data */
if (!this->decoder->GetBuffer(buffer.get())) {
return BufferPtr();
return false;
}
/* remember the sample rate so we can calculate the current time-position */
@ -160,7 +178,7 @@ BufferPtr FixedSizeStream::GetNextBufferFromDecoder() {
((double) buffer->Channels()) /
((double) this->decoderSampleRate));
return buffer;
return true;
}
inline BufferPtr FixedSizeStream::GetEmptyBuffer() {
@ -172,53 +190,67 @@ inline BufferPtr FixedSizeStream::GetEmptyBuffer() {
}
else {
target = Buffer::Create();
target->CopyFormat(this->currentBuffer);
target->CopyFormat(this->decoderBuffer);
}
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 currentBuffer;
/* ensure we have at least BUFFER_COUNT buffers, and that at least half of them
are filled with data! */
while (this->filledBuffers.size() < (this->bufferCount / 2) ||
this->filledBuffers.size() + this->recycledBuffers.size() < this->bufferCount)
{
while (this->filledBuffers.size() < (this->bufferCount / 2)) {
/* ask the decoder for the next buffer */
currentBuffer = this->GetNextBufferFromDecoder();
if (!currentBuffer) {
break; /* important... bust out of the loop when we're done! */
if (!GetNextBufferFromDecoder()) {
break;
}
/* break the buffer into 512 sample per channel buffers. this will
help us ensure visualizer data is uniform. note that the last buffer
may not be exactly 512 -- that should be fine, generally. */
BufferPtr target;
currentBuffer = this->decoderBuffer;
int floatsPerBuffer = this->samplesPerChannel * currentBuffer->Channels();
int buffers = currentBuffer->Samples() / floatsPerBuffer;
BufferPtr target;
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();
COPY_BUFFER(target, currentBuffer, floatsPerBuffer, offset);
this->filledBuffers.push_back(target);
offset += floatsPerBuffer;
}
if (offset < this->currentBuffer->Samples()) {
target = this->GetEmptyBuffer();
COPY_BUFFER(target, currentBuffer, this->currentBuffer->Samples() - offset, offset);
if (offset < currentBuffer->Samples()) {
remainder = this->GetEmptyBuffer();
COPY_BUFFER(remainder, currentBuffer, currentBuffer->Samples() - offset, offset);
}
}
@ -241,6 +273,13 @@ BufferPtr FixedSizeStream::GetNextProcessedOutputBuffer() {
return currentBuffer;
}
/* final remainder */
if (remainder) {
BufferPtr result = remainder;
remainder.reset();
return result;
}
return BufferPtr();
}

View File

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

View File

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