kopia lustrzana https://github.com/jameshball/osci-render
Add wobble effect and remove frequency input from effect applications
rodzic
1d34763f2f
commit
6d048ce26e
|
@ -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) {
|
||||||
|
|
|
@ -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)
|
||||||
};
|
};
|
|
@ -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.
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
},
|
},
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
};
|
|
@ -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"/>
|
||||||
|
|
Ładowanie…
Reference in New Issue