Use a blocking queue instead of lock free to massively reduce CPU usage

pull/170/head
James Ball 2023-09-09 15:32:03 +01:00
rodzic 32b2d2d35d
commit a6d25a122c
6 zmienionych plików z 103 dodań i 37 usunięć

Wyświetl plik

@ -444,8 +444,11 @@ void OscirenderAudioProcessor::processBlock(juce::AudioBuffer<float>& buffer, ju
} }
prevMidiEnabled = usingMidi; prevMidiEnabled = usingMidi;
const double EPSILON = 0.00001;
{
if (volume > EPSILON) {
juce::SpinLock::ScopedLockType lock1(parsersLock); juce::SpinLock::ScopedLockType lock1(parsersLock);
juce::SpinLock::ScopedLockType lock2(effectsLock); juce::SpinLock::ScopedLockType lock2(effectsLock);
synth.renderNextBlock(buffer, midiMessages, 0, buffer.getNumSamples()); synth.renderNextBlock(buffer, midiMessages, 0, buffer.getNumSamples());
@ -460,9 +463,11 @@ void OscirenderAudioProcessor::processBlock(juce::AudioBuffer<float>& buffer, ju
{ {
juce::SpinLock::ScopedLockType lock1(parsersLock); juce::SpinLock::ScopedLockType lock1(parsersLock);
juce::SpinLock::ScopedLockType lock2(effectsLock); juce::SpinLock::ScopedLockType lock2(effectsLock);
for (auto& effect : toggleableEffects) { if (volume > EPSILON) {
if (effect->enabled->getValue()) { for (auto& effect : toggleableEffects) {
channels = effect->apply(sample, channels); if (effect->enabled->getValue()) {
channels = effect->apply(sample, channels);
}
} }
} }
for (auto& effect : permanentEffects) { for (auto& effect : permanentEffects) {

Wyświetl plik

@ -9,6 +9,11 @@ ShapeSound::ShapeSound(std::shared_ptr<FileParser> parser) : parser(parser) {
producer->startThread(); producer->startThread();
} }
ShapeSound::~ShapeSound() {
frames.kill();
producer->stopThread(1000);
}
bool ShapeSound::appliesToNote(int note) { bool ShapeSound::appliesToNote(int note) {
return true; return true;
} }
@ -18,36 +23,12 @@ bool ShapeSound::appliesToChannel(int channel) {
} }
void ShapeSound::addFrame(std::vector<std::unique_ptr<Shape>>& frame) { void ShapeSound::addFrame(std::vector<std::unique_ptr<Shape>>& frame) {
const auto scope = frameFifo.write(1); frames.push(std::move(frame));
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));
}
}
} }
double ShapeSound::updateFrame(std::vector<std::unique_ptr<Shape>>& frame) { double ShapeSound::updateFrame(std::vector<std::unique_ptr<Shape>>& frame) {
if (frameFifo.getNumReady() > 0) { if (frames.try_pop(frame)) {
{ frameLength = Shape::totalLength(frame);
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);
}
} }
return frameLength; return frameLength;

Wyświetl plik

@ -3,10 +3,12 @@
#include "../parser/FileParser.h" #include "../parser/FileParser.h"
#include "../parser/FrameProducer.h" #include "../parser/FrameProducer.h"
#include "../parser/FrameConsumer.h" #include "../parser/FrameConsumer.h"
#include "../concurrency/BlockingQueue.h"
class ShapeSound : public juce::SynthesiserSound, public FrameConsumer { class ShapeSound : public juce::SynthesiserSound, public FrameConsumer {
public: public:
ShapeSound(std::shared_ptr<FileParser> parser); ShapeSound(std::shared_ptr<FileParser> parser);
~ShapeSound() override;
bool appliesToNote(int note) override; bool appliesToNote(int note) override;
bool appliesToChannel(int channel) override; bool appliesToChannel(int channel) override;
@ -19,8 +21,7 @@ public:
private: private:
juce::AbstractFifo frameFifo{ 10 }; BlockingQueue frames{10};
std::vector<std::unique_ptr<Shape>> frameBuffer[10];
std::unique_ptr<FrameProducer> producer; std::unique_ptr<FrameProducer> producer;
double frameLength = 0.0; double frameLength = 0.0;
}; };

Wyświetl plik

@ -0,0 +1,81 @@
#pragma once
#include <mutex>
#include <condition_variable>
#include <queue>
typedef std::vector<std::unique_ptr<Shape>> Frame;
class BlockingQueue {
std::vector<Frame> content;
std::atomic<int> size = 0;
int head = 0;
std::atomic<bool> 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<Frame>(capacity);
}
void kill() {
killed = true;
not_empty.notify_all();
not_full.notify_all();
}
void push(Frame &&item) {
{
std::unique_lock<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> lk(mutex);
if (size == 0) {
return false;
}
content[head].swap(item);
head = (head + 1) % content.size();
size--;
}
not_full.notify_one();
return true;
}
};

Wyświetl plik

@ -2,10 +2,7 @@
FrameProducer::FrameProducer(FrameConsumer& fc, std::shared_ptr<FileParser> fs) : frameConsumer(fc), frameSource(fs), juce::Thread("producer", 0) {} FrameProducer::FrameProducer(FrameConsumer& fc, std::shared_ptr<FileParser> fs) : frameConsumer(fc), frameSource(fs), juce::Thread("producer", 0) {}
FrameProducer::~FrameProducer() { FrameProducer::~FrameProducer() {}
frameSource->disable();
stopThread(-1);
}
void FrameProducer::run() { void FrameProducer::run() {
while (!threadShouldExit()) { while (!threadShouldExit()) {

Wyświetl plik

@ -135,6 +135,7 @@
file="Source/components/VolumeComponent.h"/> file="Source/components/VolumeComponent.h"/>
</GROUP> </GROUP>
<GROUP id="{9F5970A9-8094-E7F3-7AC1-812AE5589B9F}" name="concurrency"> <GROUP id="{9F5970A9-8094-E7F3-7AC1-812AE5589B9F}" name="concurrency">
<FILE id="F5kUMH" name="BlockingQueue.h" compile="0" resource="0" file="Source/concurrency/BlockingQueue.h"/>
<FILE id="WQ2W15" name="BufferConsumer.h" compile="0" resource="0" <FILE id="WQ2W15" name="BufferConsumer.h" compile="0" resource="0"
file="Source/concurrency/BufferConsumer.h"/> file="Source/concurrency/BufferConsumer.h"/>
</GROUP> </GROUP>