diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index bbd0a7a..271a651 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -444,8 +444,11 @@ void OscirenderAudioProcessor::processBlock(juce::AudioBuffer& buffer, ju } prevMidiEnabled = usingMidi; + + const double EPSILON = 0.00001; - { + + if (volume > EPSILON) { juce::SpinLock::ScopedLockType lock1(parsersLock); juce::SpinLock::ScopedLockType lock2(effectsLock); synth.renderNextBlock(buffer, midiMessages, 0, buffer.getNumSamples()); @@ -460,9 +463,11 @@ void OscirenderAudioProcessor::processBlock(juce::AudioBuffer& buffer, ju { juce::SpinLock::ScopedLockType lock1(parsersLock); juce::SpinLock::ScopedLockType lock2(effectsLock); - for (auto& effect : toggleableEffects) { - if (effect->enabled->getValue()) { - channels = effect->apply(sample, channels); + if (volume > EPSILON) { + for (auto& effect : toggleableEffects) { + if (effect->enabled->getValue()) { + channels = effect->apply(sample, channels); + } } } for (auto& effect : permanentEffects) { diff --git a/Source/audio/ShapeSound.cpp b/Source/audio/ShapeSound.cpp index 5ad6db9..152f9ba 100644 --- a/Source/audio/ShapeSound.cpp +++ b/Source/audio/ShapeSound.cpp @@ -9,6 +9,11 @@ ShapeSound::ShapeSound(std::shared_ptr parser) : parser(parser) { producer->startThread(); } +ShapeSound::~ShapeSound() { + frames.kill(); + producer->stopThread(1000); +} + bool ShapeSound::appliesToNote(int note) { return true; } @@ -18,36 +23,12 @@ bool ShapeSound::appliesToChannel(int channel) { } void ShapeSound::addFrame(std::vector>& frame) { - const auto scope = frameFifo.write(1); - - if (scope.blockSize1 > 0) { - frameBuffer[scope.startIndex1].clear(); - for (auto& shape : frame) { - frameBuffer[scope.startIndex1].push_back(std::move(shape)); - } - } - - if (scope.blockSize2 > 0) { - frameBuffer[scope.startIndex2].clear(); - for (auto& shape : frame) { - frameBuffer[scope.startIndex2].push_back(std::move(shape)); - } - } + frames.push(std::move(frame)); } double ShapeSound::updateFrame(std::vector>& frame) { - if (frameFifo.getNumReady() > 0) { - { - const auto scope = frameFifo.read(1); - - if (scope.blockSize1 > 0) { - frame.swap(frameBuffer[scope.startIndex1]); - } else if (scope.blockSize2 > 0) { - frame.swap(frameBuffer[scope.startIndex2]); - } - - frameLength = Shape::totalLength(frame); - } + if (frames.try_pop(frame)) { + frameLength = Shape::totalLength(frame); } return frameLength; diff --git a/Source/audio/ShapeSound.h b/Source/audio/ShapeSound.h index bdafebc..9757573 100644 --- a/Source/audio/ShapeSound.h +++ b/Source/audio/ShapeSound.h @@ -3,10 +3,12 @@ #include "../parser/FileParser.h" #include "../parser/FrameProducer.h" #include "../parser/FrameConsumer.h" +#include "../concurrency/BlockingQueue.h" class ShapeSound : public juce::SynthesiserSound, public FrameConsumer { public: ShapeSound(std::shared_ptr parser); + ~ShapeSound() override; bool appliesToNote(int note) override; bool appliesToChannel(int channel) override; @@ -19,8 +21,7 @@ public: private: - juce::AbstractFifo frameFifo{ 10 }; - std::vector> frameBuffer[10]; + BlockingQueue frames{10}; std::unique_ptr producer; double frameLength = 0.0; }; \ No newline at end of file diff --git a/Source/concurrency/BlockingQueue.h b/Source/concurrency/BlockingQueue.h new file mode 100644 index 0000000..574c29f --- /dev/null +++ b/Source/concurrency/BlockingQueue.h @@ -0,0 +1,81 @@ +#pragma once + +#include +#include +#include + +typedef std::vector> Frame; +class BlockingQueue { + std::vector content; + std::atomic size = 0; + int head = 0; + std::atomic killed = false; + + std::mutex mutex; + std::condition_variable not_empty; + std::condition_variable not_full; + + BlockingQueue(const BlockingQueue &) = delete; + BlockingQueue(BlockingQueue &&) = delete; + BlockingQueue &operator = (const BlockingQueue &) = delete; + BlockingQueue &operator = (BlockingQueue &&) = delete; + +public: + BlockingQueue(size_t capacity) { + content = std::vector(capacity); + } + + void kill() { + killed = true; + not_empty.notify_all(); + not_full.notify_all(); + } + + void push(Frame &&item) { + { + std::unique_lock lk(mutex); + not_full.wait(lk, [this]() { return size < content.size() || killed; }); + content[head] = std::move(item); + size++; + } + not_empty.notify_one(); + } + + bool try_push(Frame &&item) { + { + std::unique_lock lk(mutex); + if (size == content.size()) { + return false; + } + content[head] = std::move(item); + size++; + } + not_empty.notify_one(); + return true; + } + + void pop(Frame &item) { + { + std::unique_lock lk(mutex); + not_empty.wait(lk, [this]() { return size > 0 || killed; }); + content[head].swap(item); + head = (head + 1) % content.size(); + size--; + } + not_full.notify_one(); + } + + bool try_pop(Frame &item) { + { + std::unique_lock lk(mutex); + if (size == 0) { + return false; + } + content[head].swap(item); + head = (head + 1) % content.size(); + size--; + } + not_full.notify_one(); + return true; + } +}; \ No newline at end of file diff --git a/Source/parser/FrameProducer.cpp b/Source/parser/FrameProducer.cpp index 755fe0f..9f4788b 100644 --- a/Source/parser/FrameProducer.cpp +++ b/Source/parser/FrameProducer.cpp @@ -2,10 +2,7 @@ FrameProducer::FrameProducer(FrameConsumer& fc, std::shared_ptr fs) : frameConsumer(fc), frameSource(fs), juce::Thread("producer", 0) {} -FrameProducer::~FrameProducer() { - frameSource->disable(); - stopThread(-1); -} +FrameProducer::~FrameProducer() {} void FrameProducer::run() { while (!threadShouldExit()) { diff --git a/osci-render.jucer b/osci-render.jucer index a905709..5005673 100644 --- a/osci-render.jucer +++ b/osci-render.jucer @@ -135,6 +135,7 @@ file="Source/components/VolumeComponent.h"/> +