kopia lustrzana https://github.com/jameshball/osci-render
Merge pull request #41 from jameshball/smooth-effects
Most effects now change smoothly between values, making the visuals MUCH smoother when using sliderspull/170/head
commit
02d5aef922
|
@ -10,13 +10,10 @@ EffectsComponent::EffectsComponent(OscirenderAudioProcessor& p) : audioProcessor
|
||||||
|
|
||||||
frequency.slider.setSkewFactorFromMidPoint(500.0);
|
frequency.slider.setSkewFactorFromMidPoint(500.0);
|
||||||
frequency.slider.setTextValueSuffix("Hz");
|
frequency.slider.setTextValueSuffix("Hz");
|
||||||
frequency.slider.setValue(audioProcessor.frequency, juce::dontSendNotification);
|
frequency.slider.setValue(audioProcessor.frequencyEffect->getValue(), juce::dontSendNotification);
|
||||||
|
|
||||||
frequency.slider.onValueChange = [this] {
|
frequency.slider.onValueChange = [this] {
|
||||||
audioProcessor.frequency = frequency.slider.getValue();
|
audioProcessor.frequencyEffect->setValue(frequency.slider.getValue());
|
||||||
if (audioProcessor.currentSampleRate > 0.0) {
|
|
||||||
audioProcessor.updateAngleDelta();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,7 +23,7 @@ private:
|
||||||
EffectsListBoxModel listBoxModel;
|
EffectsListBoxModel listBoxModel;
|
||||||
DraggableListBox listBox;
|
DraggableListBox listBox;
|
||||||
|
|
||||||
EffectComponent frequency = EffectComponent(0.0, 12000.0, 0.1, 400, "Frequency", "frequency");
|
EffectComponent frequency = EffectComponent(0.0, 12000.0, 0.1, *audioProcessor.frequencyEffect, false);
|
||||||
|
|
||||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(EffectsComponent)
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(EffectsComponent)
|
||||||
};
|
};
|
|
@ -16,8 +16,8 @@ ObjComponent::ObjComponent(OscirenderAudioProcessor& p, OscirenderAudioProcessor
|
||||||
|
|
||||||
focalLength.slider.onValueChange = [this] {
|
focalLength.slider.onValueChange = [this] {
|
||||||
juce::SpinLock::ScopedLockType lock(audioProcessor.parsersLock);
|
juce::SpinLock::ScopedLockType lock(audioProcessor.parsersLock);
|
||||||
audioProcessor.focalLength.setValue(focalLength.slider.getValue());
|
audioProcessor.focalLength->setValue(focalLength.slider.getValue());
|
||||||
audioProcessor.focalLength.apply();
|
audioProcessor.focalLength->apply();
|
||||||
};
|
};
|
||||||
|
|
||||||
auto onRotationChange = [this]() {
|
auto onRotationChange = [this]() {
|
||||||
|
@ -25,23 +25,21 @@ ObjComponent::ObjComponent(OscirenderAudioProcessor& p, OscirenderAudioProcessor
|
||||||
double x = fixedRotateX->getToggleState() ? 0 : rotateX.slider.getValue();
|
double x = fixedRotateX->getToggleState() ? 0 : rotateX.slider.getValue();
|
||||||
double y = fixedRotateY->getToggleState() ? 0 : rotateY.slider.getValue();
|
double y = fixedRotateY->getToggleState() ? 0 : rotateY.slider.getValue();
|
||||||
double z = fixedRotateZ->getToggleState() ? 0 : rotateZ.slider.getValue();
|
double z = fixedRotateZ->getToggleState() ? 0 : rotateZ.slider.getValue();
|
||||||
audioProcessor.rotateX.setValue(x);
|
audioProcessor.rotateX->setValue(x);
|
||||||
audioProcessor.rotateY.setValue(y);
|
audioProcessor.rotateY->setValue(y);
|
||||||
audioProcessor.rotateZ.setValue(z);
|
audioProcessor.rotateZ->setValue(z);
|
||||||
// all the rotate apply functions are the same
|
|
||||||
audioProcessor.rotateX.apply();
|
|
||||||
|
|
||||||
if (fixedRotateX->getToggleState()) {
|
if (fixedRotateX->getToggleState()) {
|
||||||
audioProcessor.currentRotateX.setValue(rotateX.slider.getValue());
|
audioProcessor.currentRotateX->setValue(rotateX.slider.getValue());
|
||||||
audioProcessor.currentRotateX.apply();
|
audioProcessor.currentRotateX->apply();
|
||||||
}
|
}
|
||||||
if (fixedRotateY->getToggleState()) {
|
if (fixedRotateY->getToggleState()) {
|
||||||
audioProcessor.currentRotateY.setValue(rotateY.slider.getValue());
|
audioProcessor.currentRotateY->setValue(rotateY.slider.getValue());
|
||||||
audioProcessor.currentRotateY.apply();
|
audioProcessor.currentRotateY->apply();
|
||||||
}
|
}
|
||||||
if (fixedRotateZ->getToggleState()) {
|
if (fixedRotateZ->getToggleState()) {
|
||||||
audioProcessor.currentRotateZ.setValue(rotateZ.slider.getValue());
|
audioProcessor.currentRotateZ->setValue(rotateZ.slider.getValue());
|
||||||
audioProcessor.currentRotateZ.apply();
|
audioProcessor.currentRotateZ->apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
audioProcessor.fixedRotateX = fixedRotateX->getToggleState();
|
audioProcessor.fixedRotateX = fixedRotateX->getToggleState();
|
||||||
|
@ -55,8 +53,8 @@ ObjComponent::ObjComponent(OscirenderAudioProcessor& p, OscirenderAudioProcessor
|
||||||
|
|
||||||
rotateSpeed.slider.onValueChange = [this] {
|
rotateSpeed.slider.onValueChange = [this] {
|
||||||
juce::SpinLock::ScopedLockType lock(audioProcessor.parsersLock);
|
juce::SpinLock::ScopedLockType lock(audioProcessor.parsersLock);
|
||||||
audioProcessor.rotateSpeed.setValue(rotateSpeed.slider.getValue());
|
audioProcessor.rotateSpeed->setValue(rotateSpeed.slider.getValue());
|
||||||
audioProcessor.rotateSpeed.apply();
|
audioProcessor.rotateSpeed->apply();
|
||||||
};
|
};
|
||||||
|
|
||||||
addAndMakeVisible(resetRotation);
|
addAndMakeVisible(resetRotation);
|
||||||
|
@ -75,12 +73,12 @@ ObjComponent::ObjComponent(OscirenderAudioProcessor& p, OscirenderAudioProcessor
|
||||||
mouseRotate.setToggleState(false, juce::NotificationType::dontSendNotification);
|
mouseRotate.setToggleState(false, juce::NotificationType::dontSendNotification);
|
||||||
|
|
||||||
juce::SpinLock::ScopedLockType lock(audioProcessor.parsersLock);
|
juce::SpinLock::ScopedLockType lock(audioProcessor.parsersLock);
|
||||||
audioProcessor.currentRotateX.setValue(0);
|
audioProcessor.currentRotateX->setValue(0);
|
||||||
audioProcessor.currentRotateY.setValue(0);
|
audioProcessor.currentRotateY->setValue(0);
|
||||||
audioProcessor.currentRotateZ.setValue(0);
|
audioProcessor.currentRotateZ->setValue(0);
|
||||||
audioProcessor.currentRotateX.apply();
|
audioProcessor.currentRotateX->apply();
|
||||||
audioProcessor.currentRotateY.apply();
|
audioProcessor.currentRotateY->apply();
|
||||||
audioProcessor.currentRotateZ.apply();
|
audioProcessor.currentRotateZ->apply();
|
||||||
};
|
};
|
||||||
|
|
||||||
auto doc = juce::XmlDocument::parse(BinaryData::fixed_rotate_svg);
|
auto doc = juce::XmlDocument::parse(BinaryData::fixed_rotate_svg);
|
||||||
|
|
|
@ -17,11 +17,11 @@ private:
|
||||||
OscirenderAudioProcessor& audioProcessor;
|
OscirenderAudioProcessor& audioProcessor;
|
||||||
OscirenderAudioProcessorEditor& pluginEditor;
|
OscirenderAudioProcessorEditor& pluginEditor;
|
||||||
|
|
||||||
EffectComponent focalLength{0, 2, 0.01, audioProcessor.focalLength, false};
|
EffectComponent focalLength{0, 2, 0.001, *audioProcessor.focalLength, false};
|
||||||
EffectComponent rotateX{-1, 1, 0.01, audioProcessor.rotateX, false};
|
EffectComponent rotateX{-1, 1, 0.001, *audioProcessor.rotateX, false};
|
||||||
EffectComponent rotateY{-1, 1, 0.01, audioProcessor.rotateY, false};
|
EffectComponent rotateY{-1, 1, 0.001, *audioProcessor.rotateY, false};
|
||||||
EffectComponent rotateZ{-1, 1, 0.01, audioProcessor.rotateZ, false};
|
EffectComponent rotateZ{-1, 1, 0.001, *audioProcessor.rotateZ, false};
|
||||||
EffectComponent rotateSpeed{-1, 1, 0.01, audioProcessor.rotateSpeed, false};
|
EffectComponent rotateSpeed{-1, 1, 0.001, *audioProcessor.rotateSpeed, false};
|
||||||
|
|
||||||
juce::TextButton resetRotation{"Reset Rotation"};
|
juce::TextButton resetRotation{"Reset Rotation"};
|
||||||
juce::ToggleButton mouseRotate{"Rotate with Mouse (Esc to disable)"};
|
juce::ToggleButton mouseRotate{"Rotate with Mouse (Esc to disable)"};
|
||||||
|
|
|
@ -35,24 +35,33 @@ OscirenderAudioProcessor::OscirenderAudioProcessor()
|
||||||
|
|
||||||
juce::SpinLock::ScopedLockType lock(effectsLock);
|
juce::SpinLock::ScopedLockType lock(effectsLock);
|
||||||
|
|
||||||
allEffects.push_back(std::make_shared<Effect>(std::make_shared<BitCrushEffect>(), "Bit Crush", "bitCrush"));
|
allEffects.push_back(std::make_shared<Effect>(std::make_shared<BitCrushEffect>(), "Bit Crush", "bitCrush", true));
|
||||||
allEffects.push_back(std::make_shared<Effect>(std::make_shared<BulgeEffect>(), "Bulge", "bulge"));
|
allEffects.push_back(std::make_shared<Effect>(std::make_shared<BulgeEffect>(), "Bulge", "bulge", true));
|
||||||
allEffects.push_back(std::make_shared<Effect>(std::make_shared<RotateEffect>(), "2D Rotate Speed", "rotateSpeed"));
|
allEffects.push_back(std::make_shared<Effect>(std::make_shared<RotateEffect>(), "2D Rotate Speed", "rotateSpeed", true));
|
||||||
allEffects.push_back(std::make_shared<Effect>(std::make_shared<VectorCancellingEffect>(), "Vector cancelling", "vectorCancelling"));
|
allEffects.push_back(std::make_shared<Effect>(std::make_shared<VectorCancellingEffect>(), "Vector cancelling", "vectorCancelling", true));
|
||||||
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", true));
|
||||||
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", true));
|
||||||
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", true));
|
||||||
allEffects.push_back(std::make_shared<Effect>(wobbleEffect, "Wobble", "wobble"));
|
allEffects.push_back(std::make_shared<Effect>(wobbleEffect, "Wobble", "wobble", true));
|
||||||
allEffects.push_back(std::make_shared<Effect>(
|
allEffects.push_back(std::make_shared<Effect>(
|
||||||
delayEffect,
|
delayEffect,
|
||||||
std::vector<EffectDetails>{
|
std::vector<EffectDetails>{
|
||||||
EffectDetails{ "Delay Decay", "delayDecay", 0 },
|
EffectDetails{ "Delay Decay", "delayDecay", 0 },
|
||||||
EffectDetails{ "Delay Length", "delayEchoLength", 0.5 }
|
EffectDetails{ "Delay Length", "delayEchoLength", 0.5 }
|
||||||
}
|
}, true
|
||||||
));
|
));
|
||||||
allEffects.push_back(traceMax);
|
allEffects.push_back(traceMax);
|
||||||
allEffects.push_back(traceMin);
|
allEffects.push_back(traceMin);
|
||||||
|
|
||||||
|
permanentEffects.push_back(frequencyEffect);
|
||||||
|
permanentEffects.push_back(volumeEffect);
|
||||||
|
permanentEffects.push_back(thresholdEffect);
|
||||||
|
permanentEffects.push_back(rotateSpeed);
|
||||||
|
permanentEffects.push_back(rotateX);
|
||||||
|
permanentEffects.push_back(rotateY);
|
||||||
|
permanentEffects.push_back(rotateZ);
|
||||||
|
permanentEffects.push_back(focalLength);
|
||||||
|
|
||||||
for (int i = 0; i < 5; i++) {
|
for (int i = 0; i < 5; i++) {
|
||||||
addLuaSlider();
|
addLuaSlider();
|
||||||
}
|
}
|
||||||
|
@ -113,7 +122,6 @@ void OscirenderAudioProcessor::changeProgramName(int index, const juce::String&
|
||||||
void OscirenderAudioProcessor::prepareToPlay(double sampleRate, int samplesPerBlock) {
|
void OscirenderAudioProcessor::prepareToPlay(double sampleRate, int samplesPerBlock) {
|
||||||
currentSampleRate = sampleRate;
|
currentSampleRate = sampleRate;
|
||||||
pitchDetector.setSampleRate(sampleRate);
|
pitchDetector.setSampleRate(sampleRate);
|
||||||
updateAngleDelta();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OscirenderAudioProcessor::releaseResources() {
|
void OscirenderAudioProcessor::releaseResources() {
|
||||||
|
@ -158,7 +166,7 @@ void OscirenderAudioProcessor::addLuaSlider() {
|
||||||
sliderNum = (sliderNum - mod) / 26;
|
sliderNum = (sliderNum - mod) / 26;
|
||||||
}
|
}
|
||||||
|
|
||||||
luaEffects.push_back(std::make_shared<Effect>(std::make_shared<LuaEffect>(sliderName, *this), "Lua " + sliderName, "lua" + sliderName));
|
luaEffects.push_back(std::make_shared<Effect>(std::make_shared<LuaEffect>(sliderName, *this), "Lua " + sliderName, "lua" + sliderName, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
// effectsLock should be held when calling this
|
// effectsLock should be held when calling this
|
||||||
|
@ -170,14 +178,11 @@ void OscirenderAudioProcessor::updateLuaValues() {
|
||||||
|
|
||||||
// parsersLock should be held when calling this
|
// parsersLock should be held when calling this
|
||||||
void OscirenderAudioProcessor::updateObjValues() {
|
void OscirenderAudioProcessor::updateObjValues() {
|
||||||
focalLength.apply();
|
focalLength->apply();
|
||||||
rotateX.apply();
|
rotateX->apply();
|
||||||
rotateSpeed.apply();
|
rotateY->apply();
|
||||||
}
|
rotateZ->apply();
|
||||||
|
rotateSpeed->apply();
|
||||||
void OscirenderAudioProcessor::updateAngleDelta() {
|
|
||||||
auto cyclesPerSample = frequency / currentSampleRate;
|
|
||||||
thetaDelta = cyclesPerSample * 2.0 * juce::MathConstants<double>::pi;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// effectsLock MUST be held when calling this
|
// effectsLock MUST be held when calling this
|
||||||
|
@ -365,7 +370,7 @@ void OscirenderAudioProcessor::updateLengthIncrement() {
|
||||||
lengthIncrement = juce::jmax(proportionalLength / (currentSampleRate / frequency), MIN_LENGTH_INCREMENT);
|
lengthIncrement = juce::jmax(proportionalLength / (currentSampleRate / frequency), MIN_LENGTH_INCREMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OscirenderAudioProcessor::processBlock (juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midiMessages)
|
void OscirenderAudioProcessor::processBlock(juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midiMessages)
|
||||||
{
|
{
|
||||||
juce::ScopedNoDenormals noDenormals;
|
juce::ScopedNoDenormals noDenormals;
|
||||||
auto totalNumInputChannels = getTotalNumInputChannels();
|
auto totalNumInputChannels = getTotalNumInputChannels();
|
||||||
|
@ -429,6 +434,9 @@ void OscirenderAudioProcessor::processBlock (juce::AudioBuffer<float>& buffer, j
|
||||||
for (auto& effect : enabledEffects) {
|
for (auto& effect : enabledEffects) {
|
||||||
channels = effect->apply(sample, channels);
|
channels = effect->apply(sample, channels);
|
||||||
}
|
}
|
||||||
|
for (auto& effect : permanentEffects) {
|
||||||
|
channels = effect->apply(sample, channels);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
x = channels.x;
|
x = channels.x;
|
||||||
|
@ -450,8 +458,8 @@ void OscirenderAudioProcessor::processBlock (juce::AudioBuffer<float>& buffer, j
|
||||||
|
|
||||||
audioProducer.write(x, y);
|
audioProducer.write(x, y);
|
||||||
|
|
||||||
actualTraceMax = juce::jmax(actualTraceMin + MIN_TRACE, juce::jmin(traceMax->getValue(), 1.0));
|
actualTraceMax = juce::jmax(actualTraceMin + MIN_TRACE, juce::jmin(traceMaxValue, 1.0));
|
||||||
actualTraceMin = juce::jmax(MIN_TRACE, juce::jmin(traceMin->getValue(), actualTraceMax - MIN_TRACE));
|
actualTraceMin = juce::jmax(MIN_TRACE, juce::jmin(traceMinValue, actualTraceMax - MIN_TRACE));
|
||||||
|
|
||||||
if (!renderingSample) {
|
if (!renderingSample) {
|
||||||
incrementShapeDrawing();
|
incrementShapeDrawing();
|
||||||
|
|
|
@ -68,10 +68,6 @@ public:
|
||||||
void getStateInformation (juce::MemoryBlock& destData) override;
|
void getStateInformation (juce::MemoryBlock& destData) override;
|
||||||
void setStateInformation (const void* data, int sizeInBytes) override;
|
void setStateInformation (const void* data, int sizeInBytes) override;
|
||||||
|
|
||||||
std::atomic<float> frequency = 440.0f;
|
|
||||||
std::atomic<double> volume = 1.0;
|
|
||||||
std::atomic<double> threshold = 1.0;
|
|
||||||
|
|
||||||
std::atomic<double> currentSampleRate = 0.0;
|
std::atomic<double> currentSampleRate = 0.0;
|
||||||
|
|
||||||
juce::SpinLock effectsLock;
|
juce::SpinLock effectsLock;
|
||||||
|
@ -79,88 +75,107 @@ public:
|
||||||
std::vector<std::shared_ptr<Effect>> enabledEffects;
|
std::vector<std::shared_ptr<Effect>> enabledEffects;
|
||||||
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
|
std::shared_ptr<Effect> frequencyEffect = std::make_shared<Effect>(
|
||||||
std::function<Vector2(int, Vector2, std::vector<EffectDetails>, double)> onRotationChange = [this](int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) {
|
[this](int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
||||||
if (getCurrentFileIndex() != -1) {
|
frequency = values[0];
|
||||||
auto obj = getCurrentFileParser()->getObject();
|
return input;
|
||||||
if (obj == nullptr) return input;
|
}, "Frequency", "frequency", 440
|
||||||
obj->setBaseRotation(
|
);
|
||||||
rotateX.getValue() * std::numbers::pi,
|
|
||||||
rotateY.getValue() * std::numbers::pi,
|
|
||||||
rotateZ.getValue() * std::numbers::pi
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return input;
|
|
||||||
};
|
|
||||||
|
|
||||||
Effect focalLength{
|
std::shared_ptr<Effect> volumeEffect = std::make_shared<Effect>(
|
||||||
[this](int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) {
|
[this](int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
||||||
|
volume = values[0];
|
||||||
|
return input;
|
||||||
|
}, "Volume", "volume", 1
|
||||||
|
);
|
||||||
|
|
||||||
|
std::shared_ptr<Effect> thresholdEffect = std::make_shared<Effect>(
|
||||||
|
[this](int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
||||||
|
threshold = values[0];
|
||||||
|
return input;
|
||||||
|
}, "Threshold", "threshold", 3
|
||||||
|
);
|
||||||
|
|
||||||
|
std::shared_ptr<Effect> focalLength = std::make_shared<Effect>(
|
||||||
|
[this](int index, Vector2 input, const std::vector<double>& values, 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;
|
||||||
camera->setFocalLength(details[0].value);
|
camera->setFocalLength(values[0]);
|
||||||
}
|
}
|
||||||
return input;
|
return input;
|
||||||
},
|
}, "Focal length", "focalLength", 1
|
||||||
"Focal length",
|
);
|
||||||
"focalLength",
|
std::shared_ptr<Effect> rotateX = std::make_shared<Effect>(
|
||||||
1
|
[this](int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
||||||
};
|
|
||||||
Effect rotateX{onRotationChange, "Rotate x", "rotateX", 1};
|
|
||||||
Effect rotateY{onRotationChange, "Rotate y", "rotateY", 1};
|
|
||||||
Effect rotateZ{onRotationChange, "Rotate z", "rotateZ", 0};
|
|
||||||
Effect currentRotateX{
|
|
||||||
[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;
|
||||||
obj->setCurrentRotationX(details[0].value * std::numbers::pi);
|
obj->setBaseRotationX(values[0] * std::numbers::pi);
|
||||||
}
|
}
|
||||||
return input;
|
return input;
|
||||||
},
|
}, "Rotate x", "rotateX", 1
|
||||||
"Current Rotate x",
|
);
|
||||||
"currentRotateX",
|
std::shared_ptr<Effect> rotateY = std::make_shared<Effect>(
|
||||||
0
|
[this](int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
||||||
};
|
|
||||||
Effect currentRotateY{
|
|
||||||
[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;
|
||||||
obj->setCurrentRotationY(details[0].value * std::numbers::pi);
|
obj->setBaseRotationY(values[0] * std::numbers::pi);
|
||||||
}
|
}
|
||||||
return input;
|
return input;
|
||||||
},
|
}, "Rotate y", "rotateY", 1
|
||||||
"Current Rotate y",
|
);
|
||||||
"currentRotateY",
|
std::shared_ptr<Effect> rotateZ = std::make_shared<Effect>(
|
||||||
0
|
[this](int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
||||||
};
|
|
||||||
Effect currentRotateZ{
|
|
||||||
[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;
|
||||||
obj->setCurrentRotationZ(details[0].value * std::numbers::pi);
|
obj->setBaseRotationZ(values[0] * std::numbers::pi);
|
||||||
}
|
}
|
||||||
return input;
|
return input;
|
||||||
},
|
}, "Rotate z", "rotateZ", 0
|
||||||
"Current Rotate z",
|
);
|
||||||
"currentRotateZ",
|
std::shared_ptr<Effect> currentRotateX = std::make_shared<Effect>(
|
||||||
0
|
[this](int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
||||||
};
|
|
||||||
Effect rotateSpeed{
|
|
||||||
[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;
|
||||||
obj->setRotationSpeed(details[0].value);
|
obj->setCurrentRotationX(values[0] * std::numbers::pi);
|
||||||
}
|
}
|
||||||
return input;
|
return input;
|
||||||
},
|
}, "Current Rotate x", "currentRotateX", 0, false
|
||||||
"Rotate speed",
|
);
|
||||||
"rotateSpeed",
|
std::shared_ptr<Effect> currentRotateY = std::make_shared<Effect>(
|
||||||
0
|
[this](int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
||||||
};
|
if (getCurrentFileIndex() != -1) {
|
||||||
|
auto obj = getCurrentFileParser()->getObject();
|
||||||
|
if (obj == nullptr) return input;
|
||||||
|
obj->setCurrentRotationY(values[0] * std::numbers::pi);
|
||||||
|
}
|
||||||
|
return input;
|
||||||
|
}, "Current Rotate y", "currentRotateY", 0, false
|
||||||
|
);
|
||||||
|
std::shared_ptr<Effect> currentRotateZ = std::make_shared<Effect>(
|
||||||
|
[this](int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
||||||
|
if (getCurrentFileIndex() != -1) {
|
||||||
|
auto obj = getCurrentFileParser()->getObject();
|
||||||
|
if (obj == nullptr) return input;
|
||||||
|
obj->setCurrentRotationZ(values[0] * std::numbers::pi);
|
||||||
|
}
|
||||||
|
return input;
|
||||||
|
}, "Current Rotate z", "currentRotateZ", 0, false
|
||||||
|
);
|
||||||
|
std::shared_ptr<Effect> rotateSpeed = std::make_shared<Effect>(
|
||||||
|
[this](int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
||||||
|
if (getCurrentFileIndex() != -1) {
|
||||||
|
auto obj = getCurrentFileParser()->getObject();
|
||||||
|
if (obj == nullptr) return input;
|
||||||
|
obj->setRotationSpeed(values[0]);
|
||||||
|
}
|
||||||
|
return input;
|
||||||
|
}, "Rotate speed", "rotateSpeed", 0
|
||||||
|
);
|
||||||
std::atomic<bool> fixedRotateX = false;
|
std::atomic<bool> fixedRotateX = false;
|
||||||
std::atomic<bool> fixedRotateY = false;
|
std::atomic<bool> fixedRotateY = false;
|
||||||
std::atomic<bool> fixedRotateZ = false;
|
std::atomic<bool> fixedRotateZ = false;
|
||||||
|
@ -181,7 +196,6 @@ public:
|
||||||
std::shared_ptr<WobbleEffect> wobbleEffect = std::make_shared<WobbleEffect>(pitchDetector);
|
std::shared_ptr<WobbleEffect> wobbleEffect = std::make_shared<WobbleEffect>(pitchDetector);
|
||||||
|
|
||||||
void addLuaSlider();
|
void addLuaSlider();
|
||||||
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;
|
||||||
void enableEffect(std::shared_ptr<Effect> effect);
|
void enableEffect(std::shared_ptr<Effect> effect);
|
||||||
void disableEffect(std::shared_ptr<Effect> effect);
|
void disableEffect(std::shared_ptr<Effect> effect);
|
||||||
|
@ -198,8 +212,9 @@ public:
|
||||||
juce::String getFileName(int index);
|
juce::String getFileName(int index);
|
||||||
std::shared_ptr<juce::MemoryBlock> getFileBlock(int index);
|
std::shared_ptr<juce::MemoryBlock> getFileBlock(int index);
|
||||||
private:
|
private:
|
||||||
double theta = 0.0;
|
std::atomic<float> frequency = 440.0f;
|
||||||
double thetaDelta = 0.0;
|
std::atomic<double> volume = 1.0;
|
||||||
|
std::atomic<double> threshold = 1.0;
|
||||||
|
|
||||||
juce::AbstractFifo frameFifo{ 10 };
|
juce::AbstractFifo frameFifo{ 10 };
|
||||||
std::vector<std::unique_ptr<Shape>> frameBuffer[10];
|
std::vector<std::unique_ptr<Shape>> frameBuffer[10];
|
||||||
|
@ -214,27 +229,27 @@ private:
|
||||||
double lengthIncrement = 0.0;
|
double lengthIncrement = 0.0;
|
||||||
bool invalidateFrameBuffer = false;
|
bool invalidateFrameBuffer = false;
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<Effect>> permanentEffects;
|
||||||
|
|
||||||
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 sampleRate) {
|
[this](int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
||||||
|
traceMaxValue = values[0];
|
||||||
traceMaxEnabled = true;
|
traceMaxEnabled = true;
|
||||||
return input;
|
return input;
|
||||||
},
|
}, "Trace max", "traceMax", 1, true
|
||||||
"Trace max",
|
|
||||||
"traceMax",
|
|
||||||
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 sampleRate) {
|
[this](int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
||||||
|
traceMinValue = values[0];
|
||||||
traceMinEnabled = true;
|
traceMinEnabled = true;
|
||||||
return input;
|
return input;
|
||||||
},
|
}, "Trace min", "traceMin", 0, true
|
||||||
"Trace min",
|
|
||||||
"traceMin",
|
|
||||||
0
|
|
||||||
);
|
);
|
||||||
const double MIN_TRACE = 0.005;
|
const double MIN_TRACE = 0.005;
|
||||||
double actualTraceMax = traceMax->getValue();
|
double traceMaxValue = traceMax->getValue();
|
||||||
double actualTraceMin = traceMin->getValue();
|
double traceMinValue = traceMin->getValue();
|
||||||
|
double actualTraceMax = traceMaxValue;
|
||||||
|
double actualTraceMin = traceMinValue;
|
||||||
bool traceMaxEnabled = false;
|
bool traceMaxEnabled = false;
|
||||||
bool traceMinEnabled = false;
|
bool traceMinEnabled = false;
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,8 @@ 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 sampleRate) {
|
Vector2 BitCrushEffect::apply(int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
||||||
double value = details[0].value;
|
double value = values[0];
|
||||||
// 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;
|
||||||
double powValue = pow(2.0f, 1.0 - rangedValue) - 1.0;
|
double powValue = pow(2.0f, 1.0 - rangedValue) - 1.0;
|
||||||
|
|
|
@ -7,5 +7,5 @@ public:
|
||||||
BitCrushEffect();
|
BitCrushEffect();
|
||||||
~BitCrushEffect();
|
~BitCrushEffect();
|
||||||
|
|
||||||
Vector2 apply(int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) override;
|
Vector2 apply(int index, Vector2 input, const std::vector<double>& values, double sampleRate) override;
|
||||||
};
|
};
|
|
@ -4,8 +4,8 @@ BulgeEffect::BulgeEffect() {}
|
||||||
|
|
||||||
BulgeEffect::~BulgeEffect() {}
|
BulgeEffect::~BulgeEffect() {}
|
||||||
|
|
||||||
Vector2 BulgeEffect::apply(int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) {
|
Vector2 BulgeEffect::apply(int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
||||||
double value = details[0].value;
|
double value = values[0];
|
||||||
double translatedBulge = -value + 1;
|
double translatedBulge = -value + 1;
|
||||||
|
|
||||||
double r = input.magnitude();
|
double r = input.magnitude();
|
||||||
|
|
|
@ -7,5 +7,5 @@ public:
|
||||||
BulgeEffect();
|
BulgeEffect();
|
||||||
~BulgeEffect();
|
~BulgeEffect();
|
||||||
|
|
||||||
Vector2 apply(int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) override;
|
Vector2 apply(int index, Vector2 input, const std::vector<double>&, double sampleRate) override;
|
||||||
};
|
};
|
|
@ -4,9 +4,9 @@ DelayEffect::DelayEffect() {}
|
||||||
|
|
||||||
DelayEffect::~DelayEffect() {}
|
DelayEffect::~DelayEffect() {}
|
||||||
|
|
||||||
Vector2 DelayEffect::apply(int index, Vector2 vector, std::vector<EffectDetails> details, double sampleRate) {
|
Vector2 DelayEffect::apply(int index, Vector2 vector, const std::vector<double>& values, double sampleRate) {
|
||||||
double decay = details[0].value;
|
double decay = values[0];
|
||||||
double decayLength = details[1].value;
|
double decayLength = values[1];
|
||||||
int delayBufferLength = (int)(sampleRate * decayLength);
|
int delayBufferLength = (int)(sampleRate * decayLength);
|
||||||
if (head >= delayBuffer.size()){
|
if (head >= delayBuffer.size()){
|
||||||
head = 0;
|
head = 0;
|
||||||
|
|
|
@ -7,7 +7,7 @@ public:
|
||||||
DelayEffect();
|
DelayEffect();
|
||||||
~DelayEffect();
|
~DelayEffect();
|
||||||
|
|
||||||
Vector2 apply(int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) override;
|
Vector2 apply(int index, Vector2 input, const std::vector<double>& values, double sampleRate) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const static int MAX_DELAY = 192000 * 10;
|
const static int MAX_DELAY = 192000 * 10;
|
||||||
|
|
|
@ -4,8 +4,8 @@ DistortEffect::DistortEffect(bool vertical) : vertical(vertical) {}
|
||||||
|
|
||||||
DistortEffect::~DistortEffect() {}
|
DistortEffect::~DistortEffect() {}
|
||||||
|
|
||||||
Vector2 DistortEffect::apply(int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) {
|
Vector2 DistortEffect::apply(int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
||||||
double value = details[0].value;
|
double value = values[0];
|
||||||
int vertical = (int)this->vertical;
|
int vertical = (int)this->vertical;
|
||||||
if (index % 2 == 0) {
|
if (index % 2 == 0) {
|
||||||
input.translate((1 - vertical) * value, vertical * value);
|
input.translate((1 - vertical) * value, vertical * value);
|
||||||
|
|
|
@ -7,7 +7,7 @@ public:
|
||||||
DistortEffect(bool vertical);
|
DistortEffect(bool vertical);
|
||||||
~DistortEffect();
|
~DistortEffect();
|
||||||
|
|
||||||
Vector2 apply(int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) override;
|
Vector2 apply(int index, Vector2 input, const std::vector<double>& values, double sampleRate) override;
|
||||||
private:
|
private:
|
||||||
bool vertical;
|
bool vertical;
|
||||||
};
|
};
|
|
@ -1,32 +1,44 @@
|
||||||
#include "Effect.h"
|
#include "Effect.h"
|
||||||
|
|
||||||
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, bool smoothValueChange) : effectApplication(effectApplication), details(details), smoothValueChange(smoothValueChange) {
|
||||||
|
smoothValues = std::vector<double>(details.size(), 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
Effect::Effect(std::function<Vector2(int, Vector2, std::vector<EffectDetails>, double)> application, std::vector<EffectDetails> details) : application(application), details(details) {}
|
Effect::Effect(std::function<Vector2(int, Vector2, const std::vector<double>&, double)> application, std::vector<EffectDetails> details, bool smoothValueChange) : application(application), details(details), smoothValueChange(smoothValueChange) {
|
||||||
|
smoothValues = std::vector<double>(details.size(), 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
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, bool smoothValueChange) : smoothValueChange(smoothValueChange) {
|
||||||
this->effectApplication = effectApplication;
|
this->effectApplication = effectApplication;
|
||||||
details = std::vector<EffectDetails>(1, EffectDetails{name, id, 0.0});
|
details = std::vector<EffectDetails>(1, EffectDetails{name, id, 0.0});
|
||||||
|
smoothValues = std::vector<double>(details.size(), 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Effect::Effect(juce::String name, juce::String id, double value) {
|
Effect::Effect(juce::String name, juce::String id, double value, bool smoothValueChange) : smoothValueChange(smoothValueChange) {
|
||||||
details = std::vector<EffectDetails>(1, EffectDetails{name, id, value});
|
details = std::vector<EffectDetails>(1, EffectDetails{name, id, value});
|
||||||
|
smoothValues = std::vector<double>(details.size(), 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Effect::Effect(juce::String name, juce::String id) {
|
Effect::Effect(juce::String name, juce::String id, bool smoothValueChange) : smoothValueChange(smoothValueChange) {
|
||||||
details = std::vector<EffectDetails>(1, EffectDetails{name, id, 0.0});
|
details = std::vector<EffectDetails>(1, EffectDetails{name, id, 0.0});
|
||||||
|
smoothValues = std::vector<double>(details.size(), 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Effect::Effect(std::function<Vector2(int, Vector2, std::vector<EffectDetails> values, double)> application, juce::String name, juce::String id, double value) {
|
Effect::Effect(std::function<Vector2(int, Vector2, const std::vector<double>& values, double)> application, juce::String name, juce::String id, double value, bool smoothValueChange) : smoothValueChange(smoothValueChange) {
|
||||||
details = std::vector<EffectDetails>(1, EffectDetails{name, id, value});
|
details = std::vector<EffectDetails>(1, EffectDetails{name, id, value});
|
||||||
|
smoothValues = std::vector<double>(details.size(), 0.0);
|
||||||
this->application = application;
|
this->application = application;
|
||||||
};
|
};
|
||||||
|
|
||||||
Vector2 Effect::apply(int index, Vector2 input) {
|
Vector2 Effect::apply(int index, Vector2 input) {
|
||||||
|
double weight = smoothValueChange ? 0.0005 : 1.0;
|
||||||
|
for (int i = 0; i < details.size(); i++) {
|
||||||
|
smoothValues[i] = (1.0 - weight) * smoothValues[i] + weight * details[i].value;
|
||||||
|
}
|
||||||
if (application) {
|
if (application) {
|
||||||
return application(index, input, details, sampleRate);
|
return application(index, input, smoothValues, sampleRate);
|
||||||
} else if (effectApplication != nullptr) {
|
} else if (effectApplication != nullptr) {
|
||||||
return effectApplication->apply(index, input, details, sampleRate);
|
return effectApplication->apply(index, input, smoothValues, sampleRate);
|
||||||
}
|
}
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,12 +5,12 @@
|
||||||
|
|
||||||
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, bool smoothValueChange = true);
|
||||||
Effect(std::function<Vector2(int, Vector2, std::vector<EffectDetails>, double)> application, std::vector<EffectDetails> details);
|
Effect(std::function<Vector2(int, Vector2, const std::vector<double>&, double)> application, std::vector<EffectDetails> details, bool smoothValueChange = true);
|
||||||
Effect(std::shared_ptr<EffectApplication> effectApplication, juce::String name, juce::String id);
|
Effect(std::shared_ptr<EffectApplication> effectApplication, juce::String name, juce::String id, bool smoothValueChange = true);
|
||||||
Effect(juce::String name, juce::String id, double value);
|
Effect(juce::String name, juce::String id, double value, bool smoothValueChange = true);
|
||||||
Effect(juce::String name, juce::String id);
|
Effect(juce::String name, juce::String id, bool smoothValueChange = true);
|
||||||
Effect(std::function<Vector2(int, Vector2, std::vector<EffectDetails>, double)> application, juce::String name, juce::String id, double value);
|
Effect(std::function<Vector2(int, Vector2, const std::vector<double>&, double)> application, juce::String name, juce::String id, double value, bool smoothValueChange = true);
|
||||||
|
|
||||||
Vector2 apply(int index, Vector2 input);
|
Vector2 apply(int index, Vector2 input);
|
||||||
void apply();
|
void apply();
|
||||||
|
@ -26,10 +26,12 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<EffectDetails> details;
|
std::vector<EffectDetails> details;
|
||||||
|
std::vector<double> smoothValues;
|
||||||
|
bool smoothValueChange = true;
|
||||||
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)> application;
|
std::function<Vector2(int, Vector2, const std::vector<double>&, 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 sampleRate) = 0;
|
virtual Vector2 apply(int index, Vector2 input, const std::vector<double>& values, double sampleRate) = 0;
|
||||||
|
|
||||||
void resetPhase();
|
void resetPhase();
|
||||||
double nextPhase(double frequency, double sampleRate);
|
double nextPhase(double frequency, double sampleRate);
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
#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 sampleRate) {
|
Vector2 LuaEffect::apply(int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
||||||
int fileIndex = audioProcessor.getCurrentFileIndex();
|
int fileIndex = audioProcessor.getCurrentFileIndex();
|
||||||
if (fileIndex == -1) {
|
if (fileIndex == -1) {
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
std::shared_ptr<LuaParser> parser = audioProcessor.getCurrentFileParser()->getLua();
|
std::shared_ptr<LuaParser> parser = audioProcessor.getCurrentFileParser()->getLua();
|
||||||
if (parser != nullptr) {
|
if (parser != nullptr) {
|
||||||
parser->setVariable("slider_" + name.toLowerCase(), details[0].value);
|
parser->setVariable("slider_" + name.toLowerCase(), values[0]);
|
||||||
}
|
}
|
||||||
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 sampleRate) override;
|
Vector2 apply(int index, Vector2 input, const std::vector<double>& values, double sampleRate) override;
|
||||||
private:
|
private:
|
||||||
OscirenderAudioProcessor& audioProcessor;
|
OscirenderAudioProcessor& audioProcessor;
|
||||||
juce::String name;
|
juce::String name;
|
||||||
|
|
|
@ -4,7 +4,7 @@ RotateEffect::RotateEffect() {}
|
||||||
|
|
||||||
RotateEffect::~RotateEffect() {}
|
RotateEffect::~RotateEffect() {}
|
||||||
|
|
||||||
Vector2 RotateEffect::apply(int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) {
|
Vector2 RotateEffect::apply(int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
||||||
input.rotate(nextPhase(details[0].value, sampleRate));
|
input.rotate(nextPhase(values[0], 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 sampleRate) override;
|
Vector2 apply(int index, Vector2 input, const std::vector<double>& values, double sampleRate) override;
|
||||||
};
|
};
|
|
@ -4,10 +4,10 @@ SmoothEffect::SmoothEffect() {}
|
||||||
|
|
||||||
SmoothEffect::~SmoothEffect() {}
|
SmoothEffect::~SmoothEffect() {}
|
||||||
|
|
||||||
Vector2 SmoothEffect::apply(int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) {
|
Vector2 SmoothEffect::apply(int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
||||||
double weight = details[0].value;
|
double weight = values[0];
|
||||||
weight *= 0.95;
|
weight *= 0.95;
|
||||||
double strength = 1000000;
|
double strength = 10;
|
||||||
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!
|
// TODO: This doesn't consider the sample rate!
|
||||||
leftAvg = weight * leftAvg + (1 - weight) * input.x;
|
leftAvg = weight * leftAvg + (1 - weight) * input.x;
|
||||||
|
|
|
@ -7,7 +7,7 @@ public:
|
||||||
SmoothEffect();
|
SmoothEffect();
|
||||||
~SmoothEffect();
|
~SmoothEffect();
|
||||||
|
|
||||||
Vector2 apply(int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) override;
|
Vector2 apply(int index, Vector2 input, const std::vector<double>& values, double sampleRate) override;
|
||||||
private:
|
private:
|
||||||
double leftAvg = 0;
|
double leftAvg = 0;
|
||||||
double rightAvg = 0;
|
double rightAvg = 0;
|
||||||
|
|
|
@ -4,8 +4,8 @@ VectorCancellingEffect::VectorCancellingEffect() {}
|
||||||
|
|
||||||
VectorCancellingEffect::~VectorCancellingEffect() {}
|
VectorCancellingEffect::~VectorCancellingEffect() {}
|
||||||
|
|
||||||
Vector2 VectorCancellingEffect::apply(int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) {
|
Vector2 VectorCancellingEffect::apply(int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
||||||
double value = details[0].value;
|
double value = values[0];
|
||||||
if (value < 0.001) {
|
if (value < 0.001) {
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ public:
|
||||||
VectorCancellingEffect();
|
VectorCancellingEffect();
|
||||||
~VectorCancellingEffect();
|
~VectorCancellingEffect();
|
||||||
|
|
||||||
Vector2 apply(int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) override;
|
Vector2 apply(int index, Vector2 input, const std::vector<double>& values, double sampleRate) override;
|
||||||
private:
|
private:
|
||||||
int lastIndex = 0;
|
int lastIndex = 0;
|
||||||
double nextInvert = 0;
|
double nextInvert = 0;
|
||||||
|
|
|
@ -4,11 +4,11 @@ WobbleEffect::WobbleEffect(PitchDetector& pitchDetector) : pitchDetector(pitchDe
|
||||||
|
|
||||||
WobbleEffect::~WobbleEffect() {}
|
WobbleEffect::~WobbleEffect() {}
|
||||||
|
|
||||||
Vector2 WobbleEffect::apply(int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) {
|
Vector2 WobbleEffect::apply(int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
||||||
// TODO: this doesn't consider sample rate
|
// TODO: this doesn't consider sample rate
|
||||||
smoothedFrequency = smoothedFrequency * 0.99995 + pitchDetector.frequency * 0.00005;
|
smoothedFrequency = smoothedFrequency * 0.99995 + pitchDetector.frequency * 0.00005;
|
||||||
double theta = nextPhase(smoothedFrequency, sampleRate);
|
double theta = nextPhase(smoothedFrequency, sampleRate);
|
||||||
double delta = details[0].value * std::sin(theta);
|
double delta = values[0] * std::sin(theta);
|
||||||
double x = input.x + delta;
|
double x = input.x + delta;
|
||||||
double y = input.y + delta;
|
double y = input.y + delta;
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ public:
|
||||||
WobbleEffect(PitchDetector& pitchDetector);
|
WobbleEffect(PitchDetector& pitchDetector);
|
||||||
~WobbleEffect();
|
~WobbleEffect();
|
||||||
|
|
||||||
Vector2 apply(int index, Vector2 input, std::vector<EffectDetails> details, double sampleRate) override;
|
Vector2 apply(int index, Vector2 input, const std::vector<double>& values, double sampleRate) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PitchDetector& pitchDetector;
|
PitchDetector& pitchDetector;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include "LuaListComponent.h"
|
#include "LuaListComponent.h"
|
||||||
|
|
||||||
LuaListComponent::LuaListComponent(OscirenderAudioProcessor& p, Effect& effect) {
|
LuaListComponent::LuaListComponent(OscirenderAudioProcessor& p, Effect& effect) {
|
||||||
effectComponent = std::make_shared<EffectComponent>(0.0, 1.0, 0.01, effect);
|
effectComponent = std::make_shared<EffectComponent>(0.0, 1.0, 0.001, effect);
|
||||||
effectComponent->setCheckboxVisible(false);
|
effectComponent->setCheckboxVisible(false);
|
||||||
|
|
||||||
effectComponent->slider.onValueChange = [this, &effect, &p] {
|
effectComponent->slider.onValueChange = [this, &effect, &p] {
|
||||||
|
|
|
@ -33,10 +33,12 @@ void VisualiserComponent::paint(juce::Graphics& g) {
|
||||||
|
|
||||||
g.setColour(waveformColour);
|
g.setColour(waveformColour);
|
||||||
juce::SpinLock::ScopedLockType scope(lock);
|
juce::SpinLock::ScopedLockType scope(lock);
|
||||||
paintXY(g, r.removeFromRight(r.getHeight()));
|
if (buffer.size() > 0) {
|
||||||
|
paintXY(g, r.removeFromRight(r.getHeight()));
|
||||||
|
|
||||||
for (int i = 0; i < numChannels; ++i) {
|
for (int i = 0; i < numChannels; ++i) {
|
||||||
paintChannel(g, r.removeFromTop(channelHeight), i);
|
paintChannel(g, r.removeFromTop(channelHeight), i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,11 +28,11 @@ VolumeComponent::VolumeComponent(OscirenderAudioProcessor& p) : audioProcessor(p
|
||||||
thresholdSlider.setColour(juce::Slider::ColourIds::thumbColourId, juce::Colours::black);
|
thresholdSlider.setColour(juce::Slider::ColourIds::thumbColourId, juce::Colours::black);
|
||||||
|
|
||||||
volumeSlider.onValueChange = [this]() {
|
volumeSlider.onValueChange = [this]() {
|
||||||
audioProcessor.volume = volumeSlider.getValue();
|
audioProcessor.volumeEffect->setValue(volumeSlider.getValue());
|
||||||
};
|
};
|
||||||
|
|
||||||
thresholdSlider.onValueChange = [this]() {
|
thresholdSlider.onValueChange = [this]() {
|
||||||
audioProcessor.threshold = thresholdSlider.getValue();
|
audioProcessor.thresholdEffect->setValue(thresholdSlider.getValue());
|
||||||
};
|
};
|
||||||
|
|
||||||
auto doc = juce::XmlDocument::parse(BinaryData::volume_svg);
|
auto doc = juce::XmlDocument::parse(BinaryData::volume_svg);
|
||||||
|
|
|
@ -3,6 +3,35 @@
|
||||||
#include <JuceHeader.h>
|
#include <JuceHeader.h>
|
||||||
#include "BufferConsumer.h"
|
#include "BufferConsumer.h"
|
||||||
|
|
||||||
|
// This is needed over juce::SpinLock because juce::SpinLock yeilds, which
|
||||||
|
// leads to some consumers never holding the lock.
|
||||||
|
// TODO: verify that this is a legitimate solution.
|
||||||
|
struct crude_spinlock {
|
||||||
|
std::atomic<bool> lock_ = {0};
|
||||||
|
|
||||||
|
void lock() noexcept {
|
||||||
|
for (;;) {
|
||||||
|
// Optimistically assume the lock is free on the first try
|
||||||
|
if (!lock_.exchange(true, std::memory_order_acquire)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Wait for lock to be released without generating cache misses
|
||||||
|
while (lock_.load(std::memory_order_relaxed)) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool try_lock() noexcept {
|
||||||
|
// First do a relaxed load to check if lock is free in order to prevent
|
||||||
|
// unnecessary cache misses if someone does while(!try_lock())
|
||||||
|
return !lock_.load(std::memory_order_relaxed) &&
|
||||||
|
!lock_.exchange(true, std::memory_order_acquire);
|
||||||
|
}
|
||||||
|
|
||||||
|
void unlock() noexcept {
|
||||||
|
lock_.store(false, std::memory_order_release);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class BufferProducer {
|
class BufferProducer {
|
||||||
public:
|
public:
|
||||||
BufferProducer() {}
|
BufferProducer() {}
|
||||||
|
@ -13,16 +42,17 @@ public:
|
||||||
// being written to.
|
// being written to.
|
||||||
// This is only called by the thread that owns the consumer thread.
|
// This is only called by the thread that owns the consumer thread.
|
||||||
void registerConsumer(std::shared_ptr<BufferConsumer> consumer) {
|
void registerConsumer(std::shared_ptr<BufferConsumer> consumer) {
|
||||||
juce::SpinLock::ScopedLockType scope(lock);
|
lock.lock();
|
||||||
consumers.push_back(consumer);
|
consumers.push_back(consumer);
|
||||||
bufferPositions.push_back(0);
|
bufferPositions.push_back(0);
|
||||||
consumer->getBuffer(true);
|
consumer->getBuffer(true);
|
||||||
|
lock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is only called by the thread that owns the consumer thread.
|
// This is only called by the thread that owns the consumer thread.
|
||||||
// This can't happen at the same time as write() it locks the producer lock.
|
// This can't happen at the same time as write() it locks the producer lock.
|
||||||
void unregisterConsumer(std::shared_ptr<BufferConsumer> consumer) {
|
void unregisterConsumer(std::shared_ptr<BufferConsumer> consumer) {
|
||||||
juce::SpinLock::ScopedLockType scope(lock);
|
lock.lock();
|
||||||
for (int i = 0; i < consumers.size(); i++) {
|
for (int i = 0; i < consumers.size(); i++) {
|
||||||
if (consumers[i] == consumer) {
|
if (consumers[i] == consumer) {
|
||||||
consumer->releaseLock();
|
consumer->releaseLock();
|
||||||
|
@ -31,11 +61,12 @@ public:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
lock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes a sample to the current buffer for all consumers.
|
// Writes a sample to the current buffer for all consumers.
|
||||||
void write(float left, float right) {
|
void write(float left, float right) {
|
||||||
juce::SpinLock::ScopedLockType scope(lock);
|
lock.lock();
|
||||||
for (int i = 0; i < consumers.size(); i++) {
|
for (int i = 0; i < consumers.size(); i++) {
|
||||||
std::shared_ptr<std::vector<float>> buffer = consumers[i]->getBuffer(false);
|
std::shared_ptr<std::vector<float>> buffer = consumers[i]->getBuffer(false);
|
||||||
if (buffer == nullptr) {
|
if (buffer == nullptr) {
|
||||||
|
@ -54,10 +85,11 @@ public:
|
||||||
consumers[i]->finishedWriting();
|
consumers[i]->finishedWriting();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
lock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
juce::SpinLock lock;
|
crude_spinlock lock;
|
||||||
std::vector<std::shared_ptr<BufferConsumer>> consumers;
|
std::vector<std::shared_ptr<BufferConsumer>> consumers;
|
||||||
std::vector<int> bufferPositions;
|
std::vector<int> bufferPositions;
|
||||||
};
|
};
|
|
@ -207,10 +207,16 @@ WorldObject::WorldObject(std::string obj_string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldObject::setBaseRotation(double x, double y, double z) {
|
void WorldObject::setBaseRotationX(double x) {
|
||||||
baseRotateX = x;
|
baseRotateX = x;
|
||||||
baseRotateY = y;
|
}
|
||||||
baseRotateZ = z;
|
|
||||||
|
void WorldObject::setBaseRotationY(double y) {
|
||||||
|
baseRotateY = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldObject::setBaseRotationZ(double z) {
|
||||||
|
baseRotateZ = z;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldObject::setCurrentRotationX(double x) {
|
void WorldObject::setCurrentRotationX(double x) {
|
||||||
|
|
|
@ -6,7 +6,9 @@ class WorldObject {
|
||||||
public:
|
public:
|
||||||
WorldObject(std::string);
|
WorldObject(std::string);
|
||||||
|
|
||||||
void setBaseRotation(double x, double y, double z);
|
void setBaseRotationX(double x);
|
||||||
|
void setBaseRotationY(double y);
|
||||||
|
void setBaseRotationZ(double z);
|
||||||
void setCurrentRotationX(double x);
|
void setCurrentRotationX(double x);
|
||||||
void setCurrentRotationY(double y);
|
void setCurrentRotationY(double y);
|
||||||
void setCurrentRotationZ(double z);
|
void setCurrentRotationZ(double z);
|
||||||
|
|
Ładowanie…
Reference in New Issue