Add wobble effect and remove frequency input from effect applications

pull/170/head
James Ball 2023-07-13 20:11:24 +01:00
rodzic 1d34763f2f
commit 6d048ce26e
28 zmienionych plików z 134 dodań i 86 usunięć

Wyświetl plik

@ -80,9 +80,19 @@ MainComponent::MainComponent(OscirenderAudioProcessor& p, OscirenderAudioProcess
addAndMakeVisible(visualiser); addAndMakeVisible(visualiser);
addAndMakeVisible(frequencyLabel); addAndMakeVisible(frequencyLabel);
callbackIndex = audioProcessor.pitchDetector.addCallback(
[this](float frequency) {
// round to nearest integer
int roundedFrequency = static_cast<int>(frequency + 0.5f);
frequencyLabel.setText(juce::String(roundedFrequency) + "Hz", juce::dontSendNotification);
}
);
} }
MainComponent::~MainComponent() {} MainComponent::~MainComponent() {
audioProcessor.pitchDetector.removeCallback(callbackIndex);
}
void MainComponent::updateFileLabel() { void MainComponent::updateFileLabel() {
if (audioProcessor.getCurrentFileIndex() == -1) { if (audioProcessor.getCurrentFileIndex() == -1) {

Wyświetl plik

@ -31,15 +31,7 @@ private:
VisualiserComponent visualiser{2, audioProcessor}; VisualiserComponent visualiser{2, audioProcessor};
juce::Label frequencyLabel; juce::Label frequencyLabel;
PitchDetector pitchDetector{ int callbackIndex = -1;
audioProcessor,
[this](float frequency) {
// round to nearest integer
int roundedFrequency = static_cast<int>(frequency + 0.5f);
frequencyLabel.setText(juce::String(roundedFrequency) + "Hz", juce::dontSendNotification);
}
};
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MainComponent) JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MainComponent)
}; };

Wyświetl plik

@ -42,6 +42,7 @@ OscirenderAudioProcessor::OscirenderAudioProcessor()
allEffects.push_back(std::make_shared<Effect>(std::make_shared<DistortEffect>(true), "Vertical shift", "verticalDistort")); allEffects.push_back(std::make_shared<Effect>(std::make_shared<DistortEffect>(true), "Vertical shift", "verticalDistort"));
allEffects.push_back(std::make_shared<Effect>(std::make_shared<DistortEffect>(false), "Horizontal shift", "horizontalDistort")); allEffects.push_back(std::make_shared<Effect>(std::make_shared<DistortEffect>(false), "Horizontal shift", "horizontalDistort"));
allEffects.push_back(std::make_shared<Effect>(std::make_shared<SmoothEffect>(), "Smoothing", "smoothing")); allEffects.push_back(std::make_shared<Effect>(std::make_shared<SmoothEffect>(), "Smoothing", "smoothing"));
allEffects.push_back(std::make_shared<Effect>(wobbleEffect, "Wobble", "wobble"));
allEffects.push_back(std::make_shared<Effect>( allEffects.push_back(std::make_shared<Effect>(
delayEffect, delayEffect,
std::vector<EffectDetails>{ std::vector<EffectDetails>{
@ -57,18 +58,13 @@ OscirenderAudioProcessor::OscirenderAudioProcessor()
} }
} }
OscirenderAudioProcessor::~OscirenderAudioProcessor() OscirenderAudioProcessor::~OscirenderAudioProcessor() {}
{
}
//============================================================================== const juce::String OscirenderAudioProcessor::getName() const {
const juce::String OscirenderAudioProcessor::getName() const
{
return JucePlugin_Name; return JucePlugin_Name;
} }
bool OscirenderAudioProcessor::acceptsMidi() const bool OscirenderAudioProcessor::acceptsMidi() const {
{
#if JucePlugin_WantsMidiInput #if JucePlugin_WantsMidiInput
return true; return true;
#else #else
@ -76,8 +72,7 @@ bool OscirenderAudioProcessor::acceptsMidi() const
#endif #endif
} }
bool OscirenderAudioProcessor::producesMidi() const bool OscirenderAudioProcessor::producesMidi() const {
{
#if JucePlugin_ProducesMidiOutput #if JucePlugin_ProducesMidiOutput
return true; return true;
#else #else
@ -85,8 +80,7 @@ bool OscirenderAudioProcessor::producesMidi() const
#endif #endif
} }
bool OscirenderAudioProcessor::isMidiEffect() const bool OscirenderAudioProcessor::isMidiEffect() const {
{
#if JucePlugin_IsMidiEffect #if JucePlugin_IsMidiEffect
return true; return true;
#else #else
@ -94,43 +88,35 @@ bool OscirenderAudioProcessor::isMidiEffect() const
#endif #endif
} }
double OscirenderAudioProcessor::getTailLengthSeconds() const double OscirenderAudioProcessor::getTailLengthSeconds() const {
{
return 0.0; return 0.0;
} }
int OscirenderAudioProcessor::getNumPrograms() int OscirenderAudioProcessor::getNumPrograms() {
{
return 1; // NB: some hosts don't cope very well if you tell them there are 0 programs, return 1; // NB: some hosts don't cope very well if you tell them there are 0 programs,
// so this should be at least 1, even if you're not really implementing programs. // so this should be at least 1, even if you're not really implementing programs.
} }
int OscirenderAudioProcessor::getCurrentProgram() int OscirenderAudioProcessor::getCurrentProgram() {
{
return 0; return 0;
} }
void OscirenderAudioProcessor::setCurrentProgram (int index) void OscirenderAudioProcessor::setCurrentProgram(int index) {
{
} }
const juce::String OscirenderAudioProcessor::getProgramName (int index) const juce::String OscirenderAudioProcessor::getProgramName(int index) {
{
return {}; return {};
} }
void OscirenderAudioProcessor::changeProgramName (int index, const juce::String& newName) void OscirenderAudioProcessor::changeProgramName(int index, const juce::String& newName) {}
{
}
//============================================================================== void OscirenderAudioProcessor::prepareToPlay(double sampleRate, int samplesPerBlock) {
void OscirenderAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock) {
currentSampleRate = sampleRate; currentSampleRate = sampleRate;
pitchDetector.setSampleRate(sampleRate);
updateAngleDelta(); updateAngleDelta();
} }
void OscirenderAudioProcessor::releaseResources() void OscirenderAudioProcessor::releaseResources() {
{
// When playback stops, you can use this as an opportunity to free up any // When playback stops, you can use this as an opportunity to free up any
// spare memory, etc. // spare memory, etc.
} }

Wyświetl plik

@ -18,6 +18,8 @@
#include "concurrency/BufferProducer.h" #include "concurrency/BufferProducer.h"
#include "audio/AudioWebSocketServer.h" #include "audio/AudioWebSocketServer.h"
#include "audio/DelayEffect.h" #include "audio/DelayEffect.h"
#include "audio/PitchDetector.h"
#include "audio/WobbleEffect.h"
//============================================================================== //==============================================================================
/** /**
@ -78,7 +80,7 @@ public:
std::vector<std::shared_ptr<Effect>> luaEffects; std::vector<std::shared_ptr<Effect>> luaEffects;
// TODO see if there is a way to move this code to .cpp // TODO see if there is a way to move this code to .cpp
std::function<Vector2(int, Vector2, std::vector<EffectDetails>, double, int)> onRotationChange = [this](int index, Vector2 input, std::vector<EffectDetails> details, double frequency, double sampleRate) { std::function<Vector2(int, Vector2, std::vector<EffectDetails>, double)> onRotationChange = [this](int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) {
if (getCurrentFileIndex() != -1) { if (getCurrentFileIndex() != -1) {
auto obj = getCurrentFileParser()->getObject(); auto obj = getCurrentFileParser()->getObject();
if (obj == nullptr) return input; if (obj == nullptr) return input;
@ -92,7 +94,7 @@ public:
}; };
Effect focalLength{ Effect focalLength{
[this](int index, Vector2 input, std::vector<EffectDetails> details, double frequency, double sampleRate) { [this](int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) {
if (getCurrentFileIndex() != -1) { if (getCurrentFileIndex() != -1) {
auto camera = getCurrentFileParser()->getCamera(); auto camera = getCurrentFileParser()->getCamera();
if (camera == nullptr) return input; if (camera == nullptr) return input;
@ -108,7 +110,7 @@ public:
Effect rotateY{onRotationChange, "Rotate y", "rotateY", 1}; Effect rotateY{onRotationChange, "Rotate y", "rotateY", 1};
Effect rotateZ{onRotationChange, "Rotate z", "rotateZ", 0}; Effect rotateZ{onRotationChange, "Rotate z", "rotateZ", 0};
Effect currentRotateX{ Effect currentRotateX{
[this](int index, Vector2 input, std::vector<EffectDetails> details, double frequency, double sampleRate) { [this](int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) {
if (getCurrentFileIndex() != -1) { if (getCurrentFileIndex() != -1) {
auto obj = getCurrentFileParser()->getObject(); auto obj = getCurrentFileParser()->getObject();
if (obj == nullptr) return input; if (obj == nullptr) return input;
@ -121,7 +123,7 @@ public:
0 0
}; };
Effect currentRotateY{ Effect currentRotateY{
[this](int index, Vector2 input, std::vector<EffectDetails> details, double frequency, double sampleRate) { [this](int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) {
if (getCurrentFileIndex() != -1) { if (getCurrentFileIndex() != -1) {
auto obj = getCurrentFileParser()->getObject(); auto obj = getCurrentFileParser()->getObject();
if (obj == nullptr) return input; if (obj == nullptr) return input;
@ -134,7 +136,7 @@ public:
0 0
}; };
Effect currentRotateZ{ Effect currentRotateZ{
[this](int index, Vector2 input, std::vector<EffectDetails> details, double frequency, double sampleRate) { [this](int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) {
if (getCurrentFileIndex() != -1) { if (getCurrentFileIndex() != -1) {
auto obj = getCurrentFileParser()->getObject(); auto obj = getCurrentFileParser()->getObject();
if (obj == nullptr) return input; if (obj == nullptr) return input;
@ -147,7 +149,7 @@ public:
0 0
}; };
Effect rotateSpeed{ Effect rotateSpeed{
[this](int index, Vector2 input, std::vector<EffectDetails> details, double frequency, double sampleRate) { [this](int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) {
if (getCurrentFileIndex() != -1) { if (getCurrentFileIndex() != -1) {
auto obj = getCurrentFileParser()->getObject(); auto obj = getCurrentFileParser()->getObject();
if (obj == nullptr) return input; if (obj == nullptr) return input;
@ -175,6 +177,9 @@ public:
BufferProducer audioProducer; BufferProducer audioProducer;
PitchDetector pitchDetector{audioProducer};
std::shared_ptr<WobbleEffect> wobbleEffect = std::make_shared<WobbleEffect>(pitchDetector);
void addLuaSlider(); void addLuaSlider();
void updateAngleDelta(); void updateAngleDelta();
void addFrame(std::vector<std::unique_ptr<Shape>> frame, int fileIndex) override; void addFrame(std::vector<std::unique_ptr<Shape>> frame, int fileIndex) override;
@ -210,7 +215,7 @@ private:
bool invalidateFrameBuffer = false; bool invalidateFrameBuffer = false;
std::shared_ptr<Effect> traceMax = std::make_shared<Effect>( std::shared_ptr<Effect> traceMax = std::make_shared<Effect>(
[this](int index, Vector2 input, std::vector<EffectDetails> details, double frequency, double sampleRate) { [this](int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) {
traceMaxEnabled = true; traceMaxEnabled = true;
return input; return input;
}, },
@ -219,7 +224,7 @@ private:
1 1
); );
std::shared_ptr<Effect> traceMin = std::make_shared<Effect>( std::shared_ptr<Effect> traceMin = std::make_shared<Effect>(
[this](int index, Vector2 input, std::vector<EffectDetails> details, double frequency, double sampleRate) { [this](int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) {
traceMinEnabled = true; traceMinEnabled = true;
return input; return input;
}, },

Wyświetl plik

@ -5,7 +5,7 @@ BitCrushEffect::BitCrushEffect() {}
BitCrushEffect::~BitCrushEffect() {} BitCrushEffect::~BitCrushEffect() {}
// algorithm from https://www.kvraudio.com/forum/viewtopic.php?t=163880 // algorithm from https://www.kvraudio.com/forum/viewtopic.php?t=163880
Vector2 BitCrushEffect::apply(int index, Vector2 input, std::vector<EffectDetails> details, double frequency, double sampleRate) { Vector2 BitCrushEffect::apply(int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) {
double value = details[0].value; double value = details[0].value;
// change rage of value from 0-1 to 0.0-0.78 // change rage of value from 0-1 to 0.0-0.78
double rangedValue = value * 0.78; double rangedValue = value * 0.78;

Wyświetl plik

@ -7,5 +7,5 @@ public:
BitCrushEffect(); BitCrushEffect();
~BitCrushEffect(); ~BitCrushEffect();
Vector2 apply(int index, Vector2 input, std::vector<EffectDetails> details, double frequency, double sampleRate) override; Vector2 apply(int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) override;
}; };

Wyświetl plik

@ -4,7 +4,7 @@ BulgeEffect::BulgeEffect() {}
BulgeEffect::~BulgeEffect() {} BulgeEffect::~BulgeEffect() {}
Vector2 BulgeEffect::apply(int index, Vector2 input, std::vector<EffectDetails> details, double frequency, double sampleRate) { Vector2 BulgeEffect::apply(int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) {
double value = details[0].value; double value = details[0].value;
double translatedBulge = -value + 1; double translatedBulge = -value + 1;

Wyświetl plik

@ -7,5 +7,5 @@ public:
BulgeEffect(); BulgeEffect();
~BulgeEffect(); ~BulgeEffect();
Vector2 apply(int index, Vector2 input, std::vector<EffectDetails> details, double frequency, double sampleRate) override; Vector2 apply(int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) override;
}; };

Wyświetl plik

@ -4,7 +4,7 @@ DelayEffect::DelayEffect() {}
DelayEffect::~DelayEffect() {} DelayEffect::~DelayEffect() {}
Vector2 DelayEffect::apply(int index, Vector2 vector, std::vector<EffectDetails> details, double frequency, double sampleRate) { Vector2 DelayEffect::apply(int index, Vector2 vector, std::vector<EffectDetails> details, double sampleRate) {
double decay = details[0].value; double decay = details[0].value;
double decayLength = details[1].value; double decayLength = details[1].value;
int delayBufferLength = (int)(sampleRate * decayLength); int delayBufferLength = (int)(sampleRate * decayLength);

Wyświetl plik

@ -7,7 +7,7 @@ public:
DelayEffect(); DelayEffect();
~DelayEffect(); ~DelayEffect();
Vector2 apply(int index, Vector2 input, std::vector<EffectDetails> details, double frequency, double sampleRate) override; Vector2 apply(int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) override;
private: private:
const static int MAX_DELAY = 192000 * 10; const static int MAX_DELAY = 192000 * 10;

Wyświetl plik

@ -4,7 +4,7 @@ DistortEffect::DistortEffect(bool vertical) : vertical(vertical) {}
DistortEffect::~DistortEffect() {} DistortEffect::~DistortEffect() {}
Vector2 DistortEffect::apply(int index, Vector2 input, std::vector<EffectDetails> details, double frequency, double sampleRate) { Vector2 DistortEffect::apply(int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) {
double value = details[0].value; double value = details[0].value;
int vertical = (int)this->vertical; int vertical = (int)this->vertical;
if (index % 2 == 0) { if (index % 2 == 0) {

Wyświetl plik

@ -7,7 +7,7 @@ public:
DistortEffect(bool vertical); DistortEffect(bool vertical);
~DistortEffect(); ~DistortEffect();
Vector2 apply(int index, Vector2 input, std::vector<EffectDetails> details, double frequency, double sampleRate) override; Vector2 apply(int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) override;
private: private:
bool vertical; bool vertical;
}; };

Wyświetl plik

@ -2,7 +2,7 @@
Effect::Effect(std::shared_ptr<EffectApplication> effectApplication, std::vector<EffectDetails> details) : effectApplication(effectApplication), details(details) {} Effect::Effect(std::shared_ptr<EffectApplication> effectApplication, std::vector<EffectDetails> details) : effectApplication(effectApplication), details(details) {}
Effect::Effect(std::function<Vector2(int, Vector2, std::vector<EffectDetails>, double, int)> application, std::vector<EffectDetails> details) : application(application), details(details) {} Effect::Effect(std::function<Vector2(int, Vector2, std::vector<EffectDetails>, double)> application, std::vector<EffectDetails> details) : application(application), details(details) {}
Effect::Effect(std::shared_ptr<EffectApplication> effectApplication, juce::String name, juce::String id) { Effect::Effect(std::shared_ptr<EffectApplication> effectApplication, juce::String name, juce::String id) {
this->effectApplication = effectApplication; this->effectApplication = effectApplication;
@ -17,16 +17,16 @@ Effect::Effect(juce::String name, juce::String id) {
details = std::vector<EffectDetails>(1, EffectDetails{name, id, 0.0}); details = std::vector<EffectDetails>(1, EffectDetails{name, id, 0.0});
} }
Effect::Effect(std::function<Vector2(int, Vector2, std::vector<EffectDetails> values, double, int)> application, juce::String name, juce::String id, double value) { Effect::Effect(std::function<Vector2(int, Vector2, std::vector<EffectDetails> values, double)> application, juce::String name, juce::String id, double value) {
details = std::vector<EffectDetails>(1, EffectDetails{name, id, value}); details = std::vector<EffectDetails>(1, EffectDetails{name, id, value});
this->application = application; this->application = application;
}; };
Vector2 Effect::apply(int index, Vector2 input) { Vector2 Effect::apply(int index, Vector2 input) {
if (application) { if (application) {
return application(index, input, details, frequency, sampleRate); return application(index, input, details, sampleRate);
} else if (effectApplication != nullptr) { } else if (effectApplication != nullptr) {
return effectApplication->apply(index, input, details, frequency, sampleRate); return effectApplication->apply(index, input, details, sampleRate);
} }
return input; return input;
} }
@ -55,10 +55,6 @@ void Effect::setValue(double value) {
setValue(0, value); setValue(0, value);
} }
void Effect::setFrequency(double frequency) {
this->frequency = frequency;
}
int Effect::getPrecedence() { int Effect::getPrecedence() {
return precedence; return precedence;
} }

Wyświetl plik

@ -6,11 +6,11 @@
class Effect { class Effect {
public: public:
Effect(std::shared_ptr<EffectApplication> effectApplication, std::vector<EffectDetails> details); Effect(std::shared_ptr<EffectApplication> effectApplication, std::vector<EffectDetails> details);
Effect(std::function<Vector2(int, Vector2, std::vector<EffectDetails>, double, int)> application, std::vector<EffectDetails> details); Effect(std::function<Vector2(int, Vector2, std::vector<EffectDetails>, double)> application, std::vector<EffectDetails> details);
Effect(std::shared_ptr<EffectApplication> effectApplication, juce::String name, juce::String id); Effect(std::shared_ptr<EffectApplication> effectApplication, juce::String name, juce::String id);
Effect(juce::String name, juce::String id, double value); Effect(juce::String name, juce::String id, double value);
Effect(juce::String name, juce::String id); Effect(juce::String name, juce::String id);
Effect(std::function<Vector2(int, Vector2, std::vector<EffectDetails>, double, int)> application, juce::String name, juce::String id, double value); Effect(std::function<Vector2(int, Vector2, std::vector<EffectDetails>, double)> application, juce::String name, juce::String id, double value);
Vector2 apply(int index, Vector2 input); Vector2 apply(int index, Vector2 input);
void apply(); void apply();
@ -19,7 +19,6 @@ public:
std::vector<EffectDetails> getDetails(); std::vector<EffectDetails> getDetails();
void setValue(int index, double value); void setValue(int index, double value);
void setValue(double value); void setValue(double value);
void setFrequency(double frequency);
int getPrecedence(); int getPrecedence();
void setPrecedence(int precedence); void setPrecedence(int precedence);
juce::String getId(); juce::String getId();
@ -30,7 +29,7 @@ private:
double frequency = 1.0; double frequency = 1.0;
int precedence = -1; int precedence = -1;
int sampleRate = 192000; int sampleRate = 192000;
std::function<Vector2(int, Vector2, std::vector<EffectDetails>, double, int)> application; std::function<Vector2(int, Vector2, std::vector<EffectDetails>, double)> application;
std::shared_ptr<EffectApplication> effectApplication; std::shared_ptr<EffectApplication> effectApplication;
}; };

Wyświetl plik

@ -12,7 +12,7 @@ class EffectApplication {
public: public:
EffectApplication() {}; EffectApplication() {};
virtual Vector2 apply(int index, Vector2 input, std::vector<EffectDetails> details, double frequency, double sampleRate) = 0; virtual Vector2 apply(int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) = 0;
void resetPhase(); void resetPhase();
double nextPhase(double frequency, double sampleRate); double nextPhase(double frequency, double sampleRate);

Wyświetl plik

@ -1,7 +1,7 @@
#include "LuaEffect.h" #include "LuaEffect.h"
#include "../lua/LuaParser.h" #include "../lua/LuaParser.h"
Vector2 LuaEffect::apply(int index, Vector2 input, std::vector<EffectDetails> details, double frequency, double sampleRate) { Vector2 LuaEffect::apply(int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) {
int fileIndex = audioProcessor.getCurrentFileIndex(); int fileIndex = audioProcessor.getCurrentFileIndex();
if (fileIndex == -1) { if (fileIndex == -1) {
return input; return input;

Wyświetl plik

@ -8,7 +8,7 @@ class LuaEffect : public EffectApplication {
public: public:
LuaEffect(juce::String name, OscirenderAudioProcessor& p) : audioProcessor(p), name(name) {}; LuaEffect(juce::String name, OscirenderAudioProcessor& p) : audioProcessor(p), name(name) {};
Vector2 apply(int index, Vector2 input, std::vector<EffectDetails> details, double frequency, double sampleRate) override; Vector2 apply(int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) override;
private: private:
OscirenderAudioProcessor& audioProcessor; OscirenderAudioProcessor& audioProcessor;
juce::String name; juce::String name;

Wyświetl plik

@ -1,17 +1,17 @@
#include "PitchDetector.h" #include "PitchDetector.h"
#include "PitchDetector.h" #include "PitchDetector.h"
PitchDetector::PitchDetector(OscirenderAudioProcessor& p, std::function<void(float)> frequencyCallback) : juce::Thread("PitchDetector"), audioProcessor(p), frequencyCallback(frequencyCallback) { PitchDetector::PitchDetector(BufferProducer& producer) : juce::Thread("PitchDetector"), producer(producer) {
startThread(); startThread();
} }
PitchDetector::~PitchDetector() { PitchDetector::~PitchDetector() {
audioProcessor.audioProducer.unregisterConsumer(consumer); producer.unregisterConsumer(consumer);
stopThread(1000); stopThread(1000);
} }
void PitchDetector::run() { void PitchDetector::run() {
audioProcessor.audioProducer.registerConsumer(consumer); producer.registerConsumer(consumer);
while (!threadShouldExit()) { while (!threadShouldExit()) {
auto buffer = consumer->startProcessing(); auto buffer = consumer->startProcessing();
@ -44,10 +44,28 @@ void PitchDetector::run() {
} }
void PitchDetector::handleAsyncUpdate() { void PitchDetector::handleAsyncUpdate() {
frequencyCallback(frequency); juce::SpinLock::ScopedLockType scope(lock);
for (auto& callback : callbacks) {
callback(frequency);
}
}
int PitchDetector::addCallback(std::function<void(float)> callback) {
juce::SpinLock::ScopedLockType scope(lock);
callbacks.push_back(callback);
return callbacks.size() - 1;
}
void PitchDetector::removeCallback(int index) {
juce::SpinLock::ScopedLockType scope(lock);
callbacks.erase(callbacks.begin() + index);
}
void PitchDetector::setSampleRate(float sampleRate) {
this->sampleRate = sampleRate;
} }
float PitchDetector::frequencyFromIndex(int index) { float PitchDetector::frequencyFromIndex(int index) {
auto binWidth = audioProcessor.currentSampleRate / fftSize; auto binWidth = sampleRate / fftSize;
return index * binWidth; return index * binWidth;
} }

Wyświetl plik

@ -1,15 +1,19 @@
#pragma once #pragma once
#include <JuceHeader.h> #include <JuceHeader.h>
#include "../concurrency/BufferConsumer.h" #include "../concurrency/BufferConsumer.h"
#include "../PluginProcessor.h" #include "../concurrency/BufferProducer.h"
class PitchDetector : public juce::Thread, public juce::AsyncUpdater { class PitchDetector : public juce::Thread, public juce::AsyncUpdater {
public: public:
PitchDetector(OscirenderAudioProcessor& p, std::function<void(float)> frequencyCallback); PitchDetector(BufferProducer& producer);
~PitchDetector(); ~PitchDetector();
void run() override; void run() override;
void handleAsyncUpdate() override; void handleAsyncUpdate() override;
int addCallback(std::function<void(float)> callback);
void removeCallback(int index);
void setSampleRate(float sampleRate);
std::atomic<float> frequency = 0.0f; std::atomic<float> frequency = 0.0f;
@ -20,8 +24,10 @@ private:
std::shared_ptr<BufferConsumer> consumer = std::make_shared<BufferConsumer>(fftSize); std::shared_ptr<BufferConsumer> consumer = std::make_shared<BufferConsumer>(fftSize);
juce::dsp::FFT forwardFFT{fftOrder}; juce::dsp::FFT forwardFFT{fftOrder};
std::array<float, fftSize * 2> fftData; std::array<float, fftSize * 2> fftData;
OscirenderAudioProcessor& audioProcessor; BufferProducer& producer;
std::function<void(float)> frequencyCallback; std::vector<std::function<void(float)>> callbacks;
juce::SpinLock lock;
float sampleRate = 192000.0f;
float frequencyFromIndex(int index); float frequencyFromIndex(int index);

Wyświetl plik

@ -4,7 +4,7 @@ RotateEffect::RotateEffect() {}
RotateEffect::~RotateEffect() {} RotateEffect::~RotateEffect() {}
Vector2 RotateEffect::apply(int index, Vector2 input, std::vector<EffectDetails> details, double frequency, double sampleRate) { Vector2 RotateEffect::apply(int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) {
input.rotate(nextPhase(details[0].value, sampleRate)); input.rotate(nextPhase(details[0].value, sampleRate));
return input; return input;
} }

Wyświetl plik

@ -7,5 +7,5 @@ public:
RotateEffect(); RotateEffect();
~RotateEffect(); ~RotateEffect();
Vector2 apply(int index, Vector2 input, std::vector<EffectDetails> details, double frequency, double sampleRate) override; Vector2 apply(int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) override;
}; };

Wyświetl plik

@ -4,11 +4,12 @@ SmoothEffect::SmoothEffect() {}
SmoothEffect::~SmoothEffect() {} SmoothEffect::~SmoothEffect() {}
Vector2 SmoothEffect::apply(int index, Vector2 input, std::vector<EffectDetails> details, double frequency, double sampleRate) { Vector2 SmoothEffect::apply(int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) {
double weight = details[0].value; double weight = details[0].value;
weight *= 0.95; weight *= 0.95;
double strength = 1000000; double strength = 1000000;
weight = std::log(strength * weight + 1) / std::log(strength + 1); weight = std::log(strength * weight + 1) / std::log(strength + 1);
// TODO: This doesn't consider the sample rate!
leftAvg = weight * leftAvg + (1 - weight) * input.x; leftAvg = weight * leftAvg + (1 - weight) * input.x;
rightAvg = weight * rightAvg + (1 - weight) * input.y; rightAvg = weight * rightAvg + (1 - weight) * input.y;
return Vector2(leftAvg, rightAvg); return Vector2(leftAvg, rightAvg);

Wyświetl plik

@ -7,7 +7,7 @@ public:
SmoothEffect(); SmoothEffect();
~SmoothEffect(); ~SmoothEffect();
Vector2 apply(int index, Vector2 input, std::vector<EffectDetails> details, double frequency, double sampleRate) override; Vector2 apply(int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) override;
private: private:
double leftAvg = 0; double leftAvg = 0;
double rightAvg = 0; double rightAvg = 0;

Wyświetl plik

@ -4,12 +4,12 @@ VectorCancellingEffect::VectorCancellingEffect() {}
VectorCancellingEffect::~VectorCancellingEffect() {} VectorCancellingEffect::~VectorCancellingEffect() {}
Vector2 VectorCancellingEffect::apply(int index, Vector2 input, std::vector<EffectDetails> details, double frequency, double sampleRate) { Vector2 VectorCancellingEffect::apply(int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) {
double value = details[0].value; double value = details[0].value;
if (value < 0.001) { if (value < 0.001) {
return input; return input;
} }
frequency = 1.0 + 9.0 * value; double frequency = 1.0 + 9.0 * value;
if (index < lastIndex) { if (index < lastIndex) {
nextInvert = nextInvert - lastIndex + frequency; nextInvert = nextInvert - lastIndex + frequency;
} }

Wyświetl plik

@ -7,7 +7,7 @@ public:
VectorCancellingEffect(); VectorCancellingEffect();
~VectorCancellingEffect(); ~VectorCancellingEffect();
Vector2 apply(int index, Vector2 input, std::vector<EffectDetails> details, double frequency, double sampleRate) override; Vector2 apply(int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) override;
private: private:
int lastIndex = 0; int lastIndex = 0;
double nextInvert = 0; double nextInvert = 0;

Wyświetl plik

@ -0,0 +1,16 @@
#include "WobbleEffect.h"
WobbleEffect::WobbleEffect(PitchDetector& pitchDetector) : pitchDetector(pitchDetector) {}
WobbleEffect::~WobbleEffect() {}
Vector2 WobbleEffect::apply(int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) {
// TODO: this doesn't consider sample rate
smoothedFrequency = smoothedFrequency * 0.99995 + pitchDetector.frequency * 0.00005;
double theta = nextPhase(smoothedFrequency, sampleRate);
double delta = details[0].value * std::sin(theta);
double x = input.x + delta;
double y = input.y + delta;
return Vector2(x, y);
}

Wyświetl plik

@ -0,0 +1,16 @@
#pragma once
#include "EffectApplication.h"
#include "../shape/Vector2.h"
#include "PitchDetector.h"
class WobbleEffect : public EffectApplication {
public:
WobbleEffect(PitchDetector& pitchDetector);
~WobbleEffect();
Vector2 apply(int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) override;
private:
PitchDetector& pitchDetector;
double smoothedFrequency = 0;
};

Wyświetl plik

@ -63,6 +63,9 @@
file="Source/audio/VectorCancellingEffect.cpp"/> file="Source/audio/VectorCancellingEffect.cpp"/>
<FILE id="Be21D0" name="VectorCancellingEffect.h" compile="0" resource="0" <FILE id="Be21D0" name="VectorCancellingEffect.h" compile="0" resource="0"
file="Source/audio/VectorCancellingEffect.h"/> file="Source/audio/VectorCancellingEffect.h"/>
<FILE id="emm2Cy" name="WobbleEffect.cpp" compile="1" resource="0"
file="Source/audio/WobbleEffect.cpp"/>
<FILE id="sgdTlo" name="WobbleEffect.h" compile="0" resource="0" file="Source/audio/WobbleEffect.h"/>
</GROUP> </GROUP>
<GROUP id="{2A41BAF3-5E83-B018-5668-39D89ABFA00C}" name="chinese_postman"> <GROUP id="{2A41BAF3-5E83-B018-5668-39D89ABFA00C}" name="chinese_postman">
<FILE id="LcDpwe" name="BinaryHeap.cpp" compile="1" resource="0" file="Source/chinese_postman/BinaryHeap.cpp"/> <FILE id="LcDpwe" name="BinaryHeap.cpp" compile="1" resource="0" file="Source/chinese_postman/BinaryHeap.cpp"/>