diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index 6e25aaec..50cfb10d 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -17,6 +17,7 @@ #include "audio/MultiplexEffect.h" #include "audio/SmoothEffect.h" #include "audio/WobbleEffect.h" +#include "audio/HarmonicDuplicatorEffect.h" #include "audio/DashedLineEffect.h" #include "audio/VectorCancellingEffect.h" #include "audio/ScaleEffect.h" @@ -48,6 +49,7 @@ OscirenderAudioProcessor::OscirenderAudioProcessor() : CommonAudioProcessor(Buse toggleableEffects.push_back(DashedLineEffect(*this).build()); toggleableEffects.push_back(TraceEffect(*this).build()); toggleableEffects.push_back(WobbleEffect(*this).build()); + toggleableEffects.push_back(HarmonicDuplicatorEffect(*this).build()); #if OSCI_PREMIUM toggleableEffects.push_back(MultiplexEffect(*this).build()); diff --git a/Source/audio/HarmonicDuplicatorEffect.h b/Source/audio/HarmonicDuplicatorEffect.h new file mode 100644 index 00000000..5c3f50d9 --- /dev/null +++ b/Source/audio/HarmonicDuplicatorEffect.h @@ -0,0 +1,42 @@ +#pragma once +#include +#include "../PluginProcessor.h" + +class HarmonicDuplicatorEffect : public osci::EffectApplication { +public: + HarmonicDuplicatorEffect(OscirenderAudioProcessor& p) : audioProcessor(p) {} + + osci::Point apply(int index, osci::Point input, const std::vector>& values, double sampleRate) override { + const double twoPi = juce::MathConstants::twoPi; + double copies = juce::jmax(1.0, values[0].load()); + double dist = juce::jlimit(0.0, 1.0, values[1].load()); + double angleOffset = values[2].load() * juce::MathConstants::twoPi; + + double theta = std::floor(framePhase * copies) / copies * twoPi + angleOffset; + osci::Point offset(std::cos(theta), std::sin(theta), 0.0); + + framePhase += audioProcessor.frequency / copies / sampleRate; + framePhase = framePhase - std::floor(framePhase); + + return (1 - dist) * input + dist * offset; + } + + std::shared_ptr build() const override { + auto eff = std::make_shared( + std::make_shared(audioProcessor), + std::vector{ + // TODO ID strings + new osci::EffectParameter("Copies", "Controls the number of copies of the input shape to draw.", "rdCopies", VERSION_HINT, 3.0, 1.0, 10.0), + new osci::EffectParameter("Distance", "Controls the distance between copies of the input shape.", "rdMix", VERSION_HINT, 0.5, 0.0, 1.0), + new osci::EffectParameter("Angle Offset", "Rotates the offsets between copies without rotating the input shape.", "rdAngle", VERSION_HINT, 0.0, 0.0, 1.0, 0.0001, osci::LfoType::Sawtooth, 1.0) + } + ); + eff->setName("Radial Duplicator"); + eff->setIcon(BinaryData::kaleidoscope_svg); + return eff; + } + +private: + OscirenderAudioProcessor &audioProcessor; + double framePhase = 0.0; // [0, 1] +}; \ No newline at end of file diff --git a/osci-render.jucer b/osci-render.jucer index 98a4786c..00da3164 100644 --- a/osci-render.jucer +++ b/osci-render.jucer @@ -165,6 +165,8 @@ +