kopia lustrzana https://github.com/jameshball/osci-render
Use a blocking queue instead of lock free to massively reduce CPU usage
rodzic
32b2d2d35d
commit
a6d25a122c
|
@ -444,8 +444,11 @@ void OscirenderAudioProcessor::processBlock(juce::AudioBuffer<float>& 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<float>& 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) {
|
||||
|
|
|
@ -9,6 +9,11 @@ ShapeSound::ShapeSound(std::shared_ptr<FileParser> 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<std::unique_ptr<Shape>>& 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<std::unique_ptr<Shape>>& 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;
|
||||
|
|
|
@ -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<FileParser> 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<std::unique_ptr<Shape>> frameBuffer[10];
|
||||
BlockingQueue frames{10};
|
||||
std::unique_ptr<FrameProducer> producer;
|
||||
double frameLength = 0.0;
|
||||
};
|
|
@ -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;
|
||||
}
|
||||
};
|
|
@ -2,10 +2,7 @@
|
|||
|
||||
FrameProducer::FrameProducer(FrameConsumer& fc, std::shared_ptr<FileParser> fs) : frameConsumer(fc), frameSource(fs), juce::Thread("producer", 0) {}
|
||||
|
||||
FrameProducer::~FrameProducer() {
|
||||
frameSource->disable();
|
||||
stopThread(-1);
|
||||
}
|
||||
FrameProducer::~FrameProducer() {}
|
||||
|
||||
void FrameProducer::run() {
|
||||
while (!threadShouldExit()) {
|
||||
|
|
|
@ -135,6 +135,7 @@
|
|||
file="Source/components/VolumeComponent.h"/>
|
||||
</GROUP>
|
||||
<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="Source/concurrency/BufferConsumer.h"/>
|
||||
</GROUP>
|
||||
|
|
Ładowanie…
Reference in New Issue