Merge pull request #309 from ahall99/dash-improvements

Make dash frequency invariant and smoother
pull/308/head^2
James H Ball 2025-08-16 14:44:58 +01:00 zatwierdzone przez GitHub
commit 1aa561db18
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
3 zmienionych plików z 38 dodań i 27 usunięć

Wyświetl plik

@ -14,6 +14,7 @@
#include "audio/DistortEffect.h"
#include "audio/MultiplexEffect.h"
#include "audio/SmoothEffect.h"
#include "audio/DashedLineEffect.h"
#include "audio/VectorCancellingEffect.h"
#include "parser/FileParser.h"
#include "parser/FrameProducer.h"
@ -137,11 +138,16 @@ OscirenderAudioProcessor::OscirenderAudioProcessor() : CommonAudioProcessor(Buse
std::vector<osci::EffectParameter*>{
new osci::EffectParameter("Delay Decay", "Adds repetitions, delays, or echos to the audio. This slider controls the volume of the echo.", "delayDecay", VERSION_HINT, 0.4, 0.0, 1.0),
new osci::EffectParameter("Delay Length", "Controls the time in seconds between echos.", "delayLength", VERSION_HINT, 0.5, 0.0, 1.0)}));
toggleableEffects.push_back(std::make_shared<osci::Effect>(
dashedLineEffect,
auto dashedLineEffect = std::make_shared<osci::Effect>(
std::make_shared<DashedLineEffect>(*this),
std::vector<osci::EffectParameter*>{
new osci::EffectParameter("Dash Length", "Controls the length of the dashed line.", "dashLength", VERSION_HINT, 0.2, 0.0, 1.0),
}));
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 Coverage", "Controls the fraction of each dash unit that is drawn.", "dashCoverage", 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),
});
dashedLineEffect->getParameter("dashOffset")->lfo->setUnnormalisedValueNotifyingHost((int)osci::LfoType::Sawtooth);
dashedLineEffect->getParameter("dashOffset")->lfoRate->setUnnormalisedValueNotifyingHost(1.0);
toggleableEffects.push_back(dashedLineEffect);
toggleableEffects.push_back(custom);
toggleableEffects.push_back(trace);
trace->getParameter("traceLength")->lfo->setUnnormalisedValueNotifyingHost((int)osci::LfoType::Sawtooth);

Wyświetl plik

@ -18,7 +18,6 @@
#include "UGen/Env.h"
#include "UGen/ugen_JuceEnvelopeComponent.h"
#include "audio/CustomEffect.h"
#include "audio/DashedLineEffect.h"
#include "audio/DelayEffect.h"
#include "audio/PerspectiveEffect.h"
#include "audio/PublicSynthesiser.h"
@ -90,8 +89,6 @@ public:
std::shared_ptr<DelayEffect> delayEffect = std::make_shared<DelayEffect>();
std::shared_ptr<DashedLineEffect> dashedLineEffect = std::make_shared<DashedLineEffect>();
std::function<void(int, juce::String, juce::String)> errorCallback = [this](int lineNum, juce::String fileName, juce::String error) { notifyErrorListeners(lineNum, fileName, error); };
std::shared_ptr<CustomEffect> customEffect = std::make_shared<CustomEffect>(errorCallback, luaValues);
std::shared_ptr<osci::Effect> custom = std::make_shared<osci::Effect>(

Wyświetl plik

@ -1,34 +1,42 @@
#pragma once
#include <JuceHeader.h>
#include "../PluginProcessor.h"
class DashedLineEffect : public osci::EffectApplication {
public:
osci::Point apply(int index, osci::Point vector, const std::vector<std::atomic<double>>& values, double sampleRate) override {
// dash length in seconds
double dashLength = values[0] / 400;
int dashLengthSamples = (int)(dashLength * sampleRate);
dashLengthSamples = juce::jmin(dashLengthSamples, MAX_BUFFER);
if (dashIndex >= dashLengthSamples) {
dashIndex = 0;
DashedLineEffect(OscirenderAudioProcessor& p) : audioProcessor(p) {}
osci::Point apply(int index, osci::Point input, const std::vector<std::atomic<double>>& values, double sampleRate) override {
double dashCount = juce::jmax(1.0, values[0].load()); // Dashes per cycle
double dashCoverage = juce::jlimit(0.0, 1.0, values[1].load());
double dashOffset = values[2];
double dashLengthSamples = (sampleRate / audioProcessor.frequency) / dashCount;
double dashPhase = framePhase * dashCount - dashOffset;
dashPhase = dashPhase - std::floor(dashPhase); // Wrap
buffer[bufferIndex] = input;
// Linear interpolation works much better than nearest for this
double samplePos = bufferIndex - dashLengthSamples * dashPhase * (1 - dashCoverage);
samplePos = samplePos - buffer.size() * std::floor(samplePos / buffer.size()); // Wrap to [0, size]
int lowIndex = (int)std::floor(samplePos) % buffer.size();
int highIndex = (lowIndex + 1) % buffer.size();
double mixFactor = samplePos - std::floor(samplePos); // Fractional part
osci::Point output = (1 - mixFactor) * buffer[lowIndex] + mixFactor * buffer[highIndex];
bufferIndex++;
if (bufferIndex >= buffer.size()) {
bufferIndex = 0;
}
framePhase += audioProcessor.frequency / sampleRate;
framePhase = framePhase - std::floor(framePhase);
buffer[bufferIndex] = vector;
bufferIndex++;
vector = buffer[dashIndex];
if (index % 2 == 0) {
dashIndex++;
}
return vector;
return output;
}
private:
OscirenderAudioProcessor &audioProcessor;
const static int MAX_BUFFER = 192000;
std::vector<osci::Point> buffer = std::vector<osci::Point>(MAX_BUFFER);
int dashIndex = 0;
int bufferIndex = 0;
};
double framePhase = 0.0; // [0, 1]
};