kopia lustrzana https://github.com/jameshball/osci-render
95 wiersze
3.8 KiB
C++
95 wiersze
3.8 KiB
C++
#pragma once
|
|
#include <JuceHeader.h>
|
|
#include "../PluginProcessor.h"
|
|
|
|
class DashedLineEffect : public osci::EffectApplication {
|
|
public:
|
|
DashedLineEffect(OscirenderAudioProcessor& p) : audioProcessor(p) {}
|
|
|
|
osci::Point apply(int index, osci::Point input, const std::vector<std::atomic<double>>& values, double sampleRate) override {
|
|
// if only 2 parameters are provided, this is being used as a 'trace effect'
|
|
// where the dash count is 1.
|
|
double dashCount = 1.0;
|
|
int i = 0;
|
|
|
|
if (values.size() > 2) {
|
|
dashCount = juce::jmax(1.0, values[i++].load()); // Dashes per cycle
|
|
}
|
|
|
|
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;
|
|
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);
|
|
|
|
return output;
|
|
}
|
|
|
|
std::shared_ptr<osci::Effect> build() const override {
|
|
auto eff = std::make_shared<osci::Effect>(
|
|
std::make_shared<DashedLineEffect>(audioProcessor),
|
|
std::vector<osci::EffectParameter*>{
|
|
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 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");
|
|
eff->setIcon(BinaryData::dash_svg);
|
|
return eff;
|
|
}
|
|
|
|
protected:
|
|
OscirenderAudioProcessor &audioProcessor;
|
|
private:
|
|
const static int MAX_BUFFER = 192000;
|
|
std::vector<osci::Point> buffer = std::vector<osci::Point>(MAX_BUFFER);
|
|
int bufferIndex = 0;
|
|
double framePhase = 0.0; // [0, 1]
|
|
};
|
|
|
|
class TraceEffect : public DashedLineEffect {
|
|
public:
|
|
TraceEffect(OscirenderAudioProcessor& p) : DashedLineEffect(p) {}
|
|
|
|
std::shared_ptr<osci::Effect> build() const override {
|
|
auto eff = std::make_shared<osci::Effect>(
|
|
std::make_shared<TraceEffect>(audioProcessor),
|
|
std::vector<osci::EffectParameter*>{
|
|
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;
|
|
}
|
|
};
|