diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index e66f2d3..e1730c5 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -47,10 +47,11 @@ OscirenderAudioProcessor::OscirenderAudioProcessor() : CommonAudioProcessor(Buse toggleableEffects.push_back(TranslateEffectApp().build()); toggleableEffects.push_back(SwirlEffectApp().build()); toggleableEffects.push_back(SmoothEffect().build()); - toggleableEffects.push_back(WobbleEffect(*this).build()); + toggleableEffects.push_back(TwistEffect().build()); toggleableEffects.push_back(DelayEffect().build()); toggleableEffects.push_back(DashedLineEffect(*this).build()); - toggleableEffects.push_back(TwistEffect().build()); + toggleableEffects.push_back(TraceEffect(*this).build()); + toggleableEffects.push_back(WobbleEffect(*this).build()); auto scaleEffect = ScaleEffectApp().build(); booleanParameters.push_back(scaleEffect->linked); @@ -63,11 +64,6 @@ OscirenderAudioProcessor::OscirenderAudioProcessor() : CommonAudioProcessor(Buse custom->setIcon(BinaryData::lua_svg); toggleableEffects.push_back(custom); - trace->setName("Trace"); - trace->setIcon(BinaryData::trace_svg); - toggleableEffects.push_back(trace); - // LFO default for traceLength will be encoded in its constructor defaults (see header) - for (int i = 0; i < toggleableEffects.size(); i++) { auto effect = toggleableEffects[i]; effect->markSelectable(false); diff --git a/Source/PluginProcessor.h b/Source/PluginProcessor.h index 1a5a8a1..548ad64 100644 --- a/Source/PluginProcessor.h +++ b/Source/PluginProcessor.h @@ -72,20 +72,6 @@ public: "frequency", VERSION_HINT, 220.0, 0.0, 4200.0)); - std::shared_ptr trace = std::make_shared( - std::vector{ - new osci::EffectParameter( - "Trace Start", - "Defines how far into the frame the drawing is started at. This has the effect of 'tracing' out the image from a single dot when animated. By default, we start drawing from the beginning of the frame, so this value is 0.0.", - "traceStart", - VERSION_HINT, 0.0, 0.0, 1.0, 0.001), - new osci::EffectParameter( - "Trace Length", - "Defines how much of the frame is drawn per cycle. This has the effect of 'tracing' out the image from a single dot when animated. By default, we draw the whole frame, corresponding to a value of 1.0.", - "traceLength", - VERSION_HINT, 1.0, 0.0, 1.0, 0.001, osci::LfoType::Sawtooth), - }); - std::shared_ptr delayEffect = std::make_shared(); std::function errorCallback = [this](int lineNum, juce::String fileName, juce::String error) { notifyErrorListeners(lineNum, fileName, error); }; @@ -94,13 +80,7 @@ public: customEffect, new osci::EffectParameter("Lua Effect", "Controls the strength of the custom Lua effect applied. You can write your own custom effect using Lua by pressing the edit button on the right.", "customEffectStrength", VERSION_HINT, 1.0, 0.0, 1.0)); - std::shared_ptr perspectiveEffect = std::make_shared(); - std::shared_ptr perspective = std::make_shared( - perspectiveEffect, - std::vector{ - new osci::EffectParameter("Perspective", "Controls the strength of the 3D perspective projection.", "perspectiveStrength", VERSION_HINT, 1.0, 0.0, 1.0), - new osci::EffectParameter("FOV", "Controls the camera's field of view in degrees. A lower field of view makes the image look more flat, and a higher field of view makes the image look more 3D.", "perspectiveFov", VERSION_HINT, 50.0, 5.0, 130.0), - }); + std::shared_ptr perspective = PerspectiveEffect().build(); osci::BooleanParameter* midiEnabled = new osci::BooleanParameter("MIDI Enabled", "midiEnabled", VERSION_HINT, false, "Enable MIDI input for the synth. If disabled, the synth will play a constant tone, as controlled by the frequency slider."); osci::BooleanParameter* inputEnabled = new osci::BooleanParameter("Audio Input Enabled", "inputEnabled", VERSION_HINT, false, "Enable to use input audio, instead of the generated audio."); diff --git a/Source/audio/DashedLineEffect.h b/Source/audio/DashedLineEffect.h index ddaf4b5..aaaa084 100644 --- a/Source/audio/DashedLineEffect.h +++ b/Source/audio/DashedLineEffect.h @@ -16,8 +16,8 @@ public: dashCount = juce::jmax(1.0, values[i++].load()); // Dashes per cycle } - double dashCoverage = juce::jlimit(0.0, 1.0, values[i++].load()); double dashOffset = values[i++]; + double dashCoverage = juce::jlimit(0.0, 1.0, values[i++].load()); double dashLengthSamples = (sampleRate / audioProcessor.frequency) / dashCount; double dashPhase = framePhase * dashCount - dashOffset; @@ -47,8 +47,8 @@ public: std::make_shared(audioProcessor), std::vector{ new osci::EffectParameter("Dash Count", "Controls the number of dashed lines in the drawing.", "dashCount", VERSION_HINT, 16.0, 1.0, 32.0), - new osci::EffectParameter("Dash Width", "Controls how much each dash unit is drawn.", "dashWidth", VERSION_HINT, 0.5, 0.0, 1.0), new osci::EffectParameter("Dash Offset", "Offsets the location of the dashed lines.", "dashOffset", VERSION_HINT, 0.0, 0.0, 1.0, 0.0001f, osci::LfoType::Sawtooth, 1.0f), + new osci::EffectParameter("Dash Width", "Controls how much each dash unit is drawn.", "dashWidth", VERSION_HINT, 0.5, 0.0, 1.0), } ); eff->setName("Dash"); @@ -56,10 +56,39 @@ public: return eff; } -private: +protected: OscirenderAudioProcessor &audioProcessor; +private: const static int MAX_BUFFER = 192000; std::vector buffer = std::vector(MAX_BUFFER); int bufferIndex = 0; double framePhase = 0.0; // [0, 1] }; + +class TraceEffect : public DashedLineEffect { +public: + TraceEffect(OscirenderAudioProcessor& p) : DashedLineEffect(p) {} + + std::shared_ptr build() const override { + auto eff = std::make_shared( + std::make_shared(audioProcessor), + std::vector{ + new osci::EffectParameter( + "Trace Start", + "Defines how far into the frame the drawing is started at. This has the effect of 'tracing' out the image from a single dot when animated. By default, we start drawing from the beginning of the frame, so this value is 0.0.", + "traceStart", + VERSION_HINT, 0.0, 0.0, 1.0, 0.001 + ), + new osci::EffectParameter( + "Trace Length", + "Defines how much of the frame is drawn per cycle. This has the effect of 'tracing' out the image from a single dot when animated. By default, we draw the whole frame, corresponding to a value of 1.0.", + "traceLength", + VERSION_HINT, 1.0, 0.0, 1.0, 0.001, osci::LfoType::Sawtooth + ) + } + ); + eff->setName("Trace"); + eff->setIcon(BinaryData::trace_svg); + return eff; + } +}; diff --git a/Source/audio/PerspectiveEffect.h b/Source/audio/PerspectiveEffect.h index 6ffc2cc..3e047d0 100644 --- a/Source/audio/PerspectiveEffect.h +++ b/Source/audio/PerspectiveEffect.h @@ -30,7 +30,7 @@ public: std::make_shared(), std::vector{ new osci::EffectParameter("Perspective", "Controls the strength of the 3D perspective projection.", "perspectiveStrength", VERSION_HINT, 1.0, 0.0, 1.0), - new osci::EffectParameter("Focal Length", "Controls the focal length of the 3D perspective effect. A higher focal length makes the image look more flat, and a lower focal length makes the image look more 3D.", "perspectiveFocalLength", VERSION_HINT, 2.0, 0.0, 10.0), + new osci::EffectParameter("FOV", "Controls the camera's field of view in degrees. A lower field of view makes the image look more flat, and a higher field of view makes the image look more 3D.", "perspectiveFov", VERSION_HINT, 50.0, 5.0, 130.0), } ); return eff; diff --git a/Source/audio/ShapeVoice.cpp b/Source/audio/ShapeVoice.cpp index 84bf915..e980f7d 100644 --- a/Source/audio/ShapeVoice.cpp +++ b/Source/audio/ShapeVoice.cpp @@ -1,10 +1,7 @@ #include "ShapeVoice.h" #include "../PluginProcessor.h" -ShapeVoice::ShapeVoice(OscirenderAudioProcessor& p, juce::AudioSampleBuffer& externalAudio) : audioProcessor(p), externalAudio(externalAudio) { - actualTraceStart = audioProcessor.trace->getValue(0); - actualTraceLength = audioProcessor.trace->getValue(1); -} +ShapeVoice::ShapeVoice(OscirenderAudioProcessor& p, juce::AudioSampleBuffer& externalAudio) : audioProcessor(p), externalAudio(externalAudio) {} bool ShapeVoice::canPlaySound(juce::SynthesiserSound* sound) { return dynamic_cast (sound) != nullptr; @@ -93,14 +90,7 @@ void ShapeVoice::renderNextBlock(juce::AudioSampleBuffer& outputBuffer, int star } for (auto sample = startSample; sample < startSample + numSamples; ++sample) { - bool traceEnabled = audioProcessor.trace->enabled->getBoolValue() - || (audioProcessor.previewEffect && audioProcessor.previewEffect == audioProcessor.trace); - - // update length increment - double traceLen = traceEnabled ? actualTraceLength : 1.0; - double traceMin = traceEnabled ? actualTraceStart : 0.0; - double proportionalLength = std::max(0.001, traceLen) * frameLength; - lengthIncrement = juce::jmax(proportionalLength / (audioProcessor.currentSampleRate / actualFrequency), MIN_LENGTH_INCREMENT); + lengthIncrement = juce::jmax(frameLength / (audioProcessor.currentSampleRate / actualFrequency), MIN_LENGTH_INCREMENT); osci::Point channels; double x = 0.0; @@ -164,27 +154,11 @@ void ShapeVoice::renderNextBlock(juce::AudioSampleBuffer& outputBuffer, int star outputBuffer.addSample(0, sample, x * gain); } - double traceStartValue = audioProcessor.trace->getActualValue(0); - double traceLengthValue = audioProcessor.trace->getActualValue(1); - traceLengthValue = traceEnabled ? traceLengthValue : 1.0; - traceStartValue = traceEnabled ? traceStartValue : 0.0; - actualTraceLength = std::max(0.01, traceLengthValue); - actualTraceStart = traceStartValue; - if (actualTraceStart < 0) { - actualTraceStart = 0; - } - if (!renderingSample) { incrementShapeDrawing(); } - double drawnFrameLength = frameLength; - bool willLoopOver = false; - if (traceEnabled) { - drawnFrameLength *= actualTraceLength + actualTraceStart; - } - - if (!renderingSample && frameDrawn >= drawnFrameLength) { + if (!renderingSample && frameDrawn >= frameLength) { double currentShapeLength = 0; if (currentShape < frame.size()) { currentShapeLength = frame[currentShape]->len; @@ -192,22 +166,9 @@ void ShapeVoice::renderNextBlock(juce::AudioSampleBuffer& outputBuffer, int star if (sound.load() != nullptr && currentlyPlaying) { frameLength = sound.load()->updateFrame(frame); } - frameDrawn -= drawnFrameLength; - if (traceEnabled) { - shapeDrawn = juce::jlimit(0.0, currentShapeLength, frameDrawn); - } + double prevFrameLength = frameLength; + frameDrawn -= prevFrameLength; currentShape = 0; - - // TODO: updateFrame already iterates over all the shapes, - // so we can improve performance by calculating frameDrawn - // and shapeDrawn directly. frameDrawn is simply actualTraceStart * frameLength - // but shapeDrawn is the amount of the current shape that has been drawn so - // we need to iterate over all the shapes to calculate it. - if (traceEnabled) { - while (frameDrawn < actualTraceStart * frameLength) { - incrementShapeDrawing(); - } - } } } } diff --git a/Source/audio/ShapeVoice.h b/Source/audio/ShapeVoice.h index 3e9f110..b99c4ad 100644 --- a/Source/audio/ShapeVoice.h +++ b/Source/audio/ShapeVoice.h @@ -21,14 +21,11 @@ public: bool renderingSample = false; private: - const double MIN_TRACE = 0.005; const double MIN_LENGTH_INCREMENT = 0.000001; OscirenderAudioProcessor& audioProcessor; std::vector> frame; std::atomic sound = nullptr; - double actualTraceStart; - double actualTraceLength; double frameLength = 0.0; int currentShape = 0; diff --git a/osci-render.jucer b/osci-render.jucer index 244dea0..eef1e34 100644 --- a/osci-render.jucer +++ b/osci-render.jucer @@ -814,13 +814,14 @@ microphonePermissionNeeded="1" frameworkSearchPaths="/Library/Frameworks" extraCustomFrameworks="/Library/Frameworks/Syphon.framework" hardenedRuntime="1" hardenedRuntimeOptions="com.apple.security.cs.disable-library-validation,com.apple.security.device.audio-input" - userNotes="D86A3M3H2L"> + iosDevelopmentTeamID="D86A3M3H2L"> - +