diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 9418f0a3f..8caf08be2 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -3,8 +3,7 @@ set(CORE_SOURCES ./audio/Buffer.cpp ./audio/Player.cpp ./audio/GaplessTransport.cpp - ./audio/DynamicStream.cpp - ./audio/FixedSizeStream.cpp + ./audio/Stream.cpp ./audio/Visualizer.cpp ./db/Connection.cpp ./db/ScopedTransaction.cpp diff --git a/src/core/audio/Buffer.cpp b/src/core/audio/Buffer.cpp index 011ffa398..6f47c1ed0 100644 --- a/src/core/audio/Buffer.cpp +++ b/src/core/audio/Buffer.cpp @@ -51,20 +51,21 @@ using namespace musik::core::audio; -Buffer::Buffer(void) +Buffer::Buffer(Flags flags) : buffer(nullptr) , sampleSize(0) , internalBufferSize(0) , sampleRate(44100) -, channels(2) { +, channels(2) +, flags(flags) { } Buffer::~Buffer() { delete[] this->buffer; } -BufferPtr Buffer::Create() { - return BufferPtr(new Buffer()); +BufferPtr Buffer::Create(Flags flags) { + return BufferPtr(new Buffer(flags)); } long Buffer::SampleRate() const { /* hertz */ @@ -81,7 +82,6 @@ int Buffer::Channels() const { void Buffer::SetChannels(int channels) { this->channels = channels; - this->ResizeBuffer(); } float* Buffer::BufferPointer() const { @@ -104,6 +104,10 @@ void Buffer::CopyFormat(BufferPtr fromBuffer) { void Buffer::ResizeBuffer() { if (this->sampleSize > this->internalBufferSize) { + if (flags & ImmutableSize && this->internalBufferSize > 0) { + throw std::runtime_error("buffer cannot be resized"); + } + delete[] this->buffer; this->buffer = new float[this->sampleSize]; this->internalBufferSize = this->sampleSize; @@ -177,7 +181,7 @@ bool Buffer::Fft(float* buffer, int size) { to = ((i % this->channels) * FFT_BUFFER_SIZE) + (i / count); deinterleaved[to] = this->buffer[i]; } - + /* if there's more than one set of interleaved data then allocate a scratch buffer. we'll use this for averaging the result */ @@ -190,7 +194,7 @@ bool Buffer::Fft(float* buffer, int size) { /* first FFT will go directly to the output buffer */ fft_perform(this->buffer, buffer, state); - + for (int i = 1; i < count; i++) { fft_perform(deinterleaved + (i * FFT_BUFFER_SIZE), scratch, state); diff --git a/src/core/audio/Buffer.h b/src/core/audio/Buffer.h index a2b1e0719..474efbe52 100644 --- a/src/core/audio/Buffer.h +++ b/src/core/audio/Buffer.h @@ -45,11 +45,13 @@ namespace musik { namespace core { namespace audio { typedef std::shared_ptr BufferPtr; class Buffer : public musik::core::sdk::IBuffer { - private: - Buffer(); - public: - static BufferPtr Create(); + enum Flags { + NoFlags = 0, + ImmutableSize = 1 + }; + + static BufferPtr Create(Flags flags = NoFlags); virtual ~Buffer(); @@ -70,6 +72,8 @@ namespace musik { namespace core { namespace audio { void CopyFormat(BufferPtr fromBuffer); private: + Buffer(Flags flags); + void ResizeBuffer(); float *buffer; @@ -78,6 +82,7 @@ namespace musik { namespace core { namespace audio { long sampleRate; int channels; double position; + Flags flags; }; } } } diff --git a/src/core/audio/Player.cpp b/src/core/audio/Player.cpp index 5d5d2a924..79ad631e2 100644 --- a/src/core/audio/Player.cpp +++ b/src/core/audio/Player.cpp @@ -36,8 +36,7 @@ #include #include -#include -#include +#include #include #include #include @@ -139,11 +138,10 @@ int Player::State() { void Player::ThreadLoop() { /* fixed size streams are better for visualizations because they provide - consistent buffer sizes. dynamic streams are more efficient otherwise + consistent buffer sizes. dynamic streams are more efficient otherwise because we don't need to worry about manually chunking data, we can just send audio data to the output straight from the decoder. */ - this->stream = vis::SelectedVisualizer() - ? FixedSizeStream::Create() : DynamicStream::Create(); + this->stream = Stream::Create(); BufferPtr buffer; diff --git a/src/core/audio/FixedSizeStream.cpp b/src/core/audio/Stream.cpp similarity index 86% rename from src/core/audio/FixedSizeStream.cpp rename to src/core/audio/Stream.cpp index 3ea8906b5..7865eccd8 100644 --- a/src/core/audio/FixedSizeStream.cpp +++ b/src/core/audio/Stream.cpp @@ -34,7 +34,7 @@ #include "pch.hpp" -#include "FixedSizeStream.h" +#include "Stream.h" #include #include #include @@ -43,28 +43,25 @@ using namespace musik::core::audio; using namespace musik::core::sdk; using musik::core::PluginFactory; -static std::string TAG = "FixedSizeStream"; +static std::string TAG = "Stream"; #define SET_OFFSET(target, offset) \ target->SetPosition( \ ((double) this->decoderSamplePosition + offset) / \ ((double) target->Channels()) / \ - ((double) this->decoderSampleRate)); + ((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) +Stream::Stream(int samplesPerChannel, int bufferCount, unsigned int options) : options(options) , samplesPerChannel(samplesPerChannel) , bufferCount(bufferCount) , decoderSampleRate(0) , decoderChannels(0) -, decoderSamplePosition(0) -, decoderBuffer(Buffer::Create()) -, dspBuffer(Buffer::Create()) -{ +, decoderSamplePosition(0) { if ((this->options & NoDSP) == 0) { typedef PluginFactory::DestroyDeleter Deleter; this->dsps = PluginFactory::Instance().QueryInterface("GetDSP"); @@ -75,16 +72,28 @@ FixedSizeStream::FixedSizeStream(int samplesPerChannel, int bufferCount, unsigne } this->LoadDecoderPlugins(); + this->dspBuffer = Buffer::Create(); + + /* note that the decoder buffer needs to have a pre-allocated, non-resizable buffer + in Windows due to the way heap allocations work cross-DLL. in theory this is a + surmountable problem, in practice we get heap corruption. the buffer is enough for + 8 channels worth of 2048 samples, which should be more than reasonable. */ +#ifdef WIN32 + this->decoderBuffer = Buffer::Create(Buffer::ImmutableSize); + this->decoderBuffer->SetSamples(2048 * 8); +#else + this->decoderBuffer = Buffer::Create(); +#endif } -FixedSizeStream::~FixedSizeStream() { +Stream::~Stream() { } -StreamPtr FixedSizeStream::Create(int samplesPerChannel, int bufferCount, unsigned int options) { - return StreamPtr(new FixedSizeStream(samplesPerChannel, bufferCount, options)); +StreamPtr Stream::Create(int samplesPerChannel, int bufferCount, unsigned int options) { + return StreamPtr(new Stream(samplesPerChannel, bufferCount, options)); } -double FixedSizeStream::SetPosition(double requestedSeconds) { +double Stream::SetPosition(double requestedSeconds) { double actualSeconds = this->decoder->SetPosition(requestedSeconds); if (actualSeconds != -1) { @@ -94,14 +103,14 @@ double FixedSizeStream::SetPosition(double requestedSeconds) { (uint64)(actualSeconds * rate) * this->decoderChannels; this->recycledBuffers.splice( - this->recycledBuffers.begin(), + this->recycledBuffers.begin(), this->filledBuffers); } return actualSeconds; } -bool FixedSizeStream::OpenStream(std::string uri) { +bool Stream::OpenStream(std::string uri) { musik::debug::info(TAG, "opening " + uri); /* use our file stream abstraction to open the data at the @@ -151,11 +160,11 @@ bool FixedSizeStream::OpenStream(std::string uri) { return true; } -void FixedSizeStream::OnBufferProcessedByPlayer(BufferPtr buffer) { +void Stream::OnBufferProcessedByPlayer(BufferPtr buffer) { this->RecycleBuffer(buffer); } -bool FixedSizeStream::GetNextBufferFromDecoder() { +bool Stream::GetNextBufferFromDecoder() { BufferPtr buffer = this->decoderBuffer; /* get a spare buffer, then ask the decoder for some data */ @@ -181,9 +190,9 @@ bool FixedSizeStream::GetNextBufferFromDecoder() { return true; } -inline BufferPtr FixedSizeStream::GetEmptyBuffer() { +inline BufferPtr Stream::GetEmptyBuffer() { BufferPtr target; - + if (recycledBuffers.size()) { target = recycledBuffers.back(); recycledBuffers.pop_back(); @@ -196,7 +205,7 @@ inline BufferPtr FixedSizeStream::GetEmptyBuffer() { return target; } -BufferPtr FixedSizeStream::GetNextProcessedOutputBuffer() { +BufferPtr Stream::GetNextProcessedOutputBuffer() { BufferPtr currentBuffer; /* ensure we have at least BUFFER_COUNT buffers, and that at least half of them @@ -284,11 +293,11 @@ BufferPtr FixedSizeStream::GetNextProcessedOutputBuffer() { } /* marks a used buffer as recycled so it can be re-used later. */ -void FixedSizeStream::RecycleBuffer(BufferPtr oldBuffer) { +void Stream::RecycleBuffer(BufferPtr oldBuffer) { this->recycledBuffers.push_back(oldBuffer); } -void FixedSizeStream::LoadDecoderPlugins() { +void Stream::LoadDecoderPlugins() { PluginFactory::DestroyDeleter typedef Deleter; this->decoderFactories = PluginFactory::Instance() diff --git a/src/core/audio/FixedSizeStream.h b/src/core/audio/Stream.h similarity index 95% rename from src/core/audio/FixedSizeStream.h rename to src/core/audio/Stream.h index df2769083..d982f06e4 100644 --- a/src/core/audio/FixedSizeStream.h +++ b/src/core/audio/Stream.h @@ -47,7 +47,7 @@ namespace musik { namespace core { namespace audio { - class FixedSizeStream : public IStream { + class Stream : public IStream { using IDSP = musik::core::sdk::IDSP; using IDecoder = musik::core::sdk::IDecoder; using IDecoderFactory = musik::core::sdk::IDecoderFactory; @@ -59,10 +59,10 @@ namespace musik { namespace core { namespace audio { unsigned int options = 0); private: - FixedSizeStream(int samplesPerChannel, int bufferCount, unsigned int options); + Stream(int samplesPerChannel, int bufferCount, unsigned int options); public: - virtual ~FixedSizeStream(); + virtual ~Stream(); virtual BufferPtr GetNextProcessedOutputBuffer(); virtual void OnBufferProcessedByPlayer(BufferPtr buffer); diff --git a/src/core/core.vcxproj b/src/core/core.vcxproj index 0889f6020..37d883ab4 100755 --- a/src/core/core.vcxproj +++ b/src/core/core.vcxproj @@ -84,7 +84,6 @@ - @@ -108,14 +107,13 @@ - + - @@ -161,7 +159,7 @@ - + diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters index 2cf75ecbd..5fb38be2e 100755 --- a/src/core/core.vcxproj.filters +++ b/src/core/core.vcxproj.filters @@ -109,10 +109,7 @@ src\library\track - - src\audio - - + src\audio @@ -276,10 +273,7 @@ src\audio - - src\audio - - + src\audio diff --git a/src/core/library/Indexer.cpp b/src/core/library/Indexer.cpp index 557791592..d23771a99 100644 --- a/src/core/library/Indexer.cpp +++ b/src/core/library/Indexer.cpp @@ -47,7 +47,7 @@ #include #include #include -#include +#include #include #include @@ -636,7 +636,7 @@ void Indexer::RunAnalyzers() { } if (!runningAnalyzers.empty()) { - audio::StreamPtr stream = audio::DynamicStream::Create(audio::IStream::NoDSP); + audio::StreamPtr stream = audio::Stream::Create(audio::IStream::NoDSP); if (stream) { if (stream->OpenStream(track.Uri())) {