mirror of
https://github.com/clangen/musikcube.git
synced 2024-10-02 13:02:35 +00:00
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:
parent
d41f44deaf
commit
d28cfcfd52
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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(¤t->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(¤t->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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user