Browse Source

Reimplement LFO functionality for new design.

tags/v2.0.1
Andrew Belt 3 years ago
parent
commit
3254fda966
2 changed files with 176 additions and 253 deletions
  1. +172
    -251
      src/LFO.cpp
  2. +4
    -2
      src/WTLFO.cpp

+ 172
- 251
src/LFO.cpp View File

@@ -4,100 +4,24 @@
using simd::float_4; using simd::float_4;




template <typename T>
struct LowFrequencyOscillator {
T phase = 0.f;
T pw = 0.5f;
T freq = 1.f;
bool invert = false;
bool bipolar = false;
T resetState = T::mask();

void setPitch(T pitch) {
pitch = simd::fmin(pitch, 10.f);
freq = dsp::approxExp2_taylor5(pitch + 30.f) / std::pow(2.f, 30.f);
}
void setPulseWidth(T pw) {
const T pwMin = 0.01f;
this->pw = clamp(pw, pwMin, 1.f - pwMin);
}
void setReset(T reset) {
reset = simd::rescale(reset, 0.1f, 2.f, 0.f, 1.f);
T on = (reset >= 1.f);
T off = (reset <= 0.f);
T triggered = ~resetState & on;
resetState = simd::ifelse(off, 0.f, resetState);
resetState = simd::ifelse(on, T::mask(), resetState);
phase = simd::ifelse(triggered, 0.f, phase);
}
void step(float dt) {
T deltaPhase = simd::fmin(freq * dt, 0.5f);
phase += deltaPhase;
phase -= (phase >= 1.f) & 1.f;
}
T sin() {
T p = phase;
if (!bipolar)
p -= 0.25f;
T v = simd::sin(2 * M_PI * p);
if (invert)
v *= -1.f;
if (!bipolar)
v += 1.f;
return v;
}
T tri() {
T p = phase;
if (bipolar)
p += 0.25f;
T v = 4.f * simd::fabs(p - simd::round(p)) - 1.f;
if (invert)
v *= -1.f;
if (!bipolar)
v += 1.f;
return v;
}
T saw() {
T p = phase;
if (!bipolar)
p -= 0.5f;
T v = 2.f * (p - simd::round(p));
if (invert)
v *= -1.f;
if (!bipolar)
v += 1.f;
return v;
}
T sqr() {
T v = simd::ifelse(phase < pw, 1.f, -1.f);
if (invert)
v *= -1.f;
if (!bipolar)
v += 1.f;
return v;
}
T light() {
return simd::sin(2 * T(M_PI) * phase);
}
};


struct LFO : Module { struct LFO : Module {
enum ParamIds { enum ParamIds {
OFFSET_PARAM, OFFSET_PARAM,
INVERT_PARAM, INVERT_PARAM,
FREQ_PARAM, FREQ_PARAM,
FM1_PARAM,
FM_PARAM,
FM2_PARAM, // removed FM2_PARAM, // removed
PW_PARAM, PW_PARAM,
PWM_PARAM, PWM_PARAM,
NUM_PARAMS NUM_PARAMS
}; };
enum InputIds { enum InputIds {
FM1_INPUT,
FM_INPUT,
FM2_INPUT, // removed FM2_INPUT, // removed
RESET_INPUT, RESET_INPUT,
PW_INPUT, PW_INPUT,
// added in 2.0
CLOCK_INPUT,
NUM_INPUTS NUM_INPUTS
}; };
enum OutputIds { enum OutputIds {
@@ -109,72 +33,161 @@ struct LFO : Module {
}; };
enum LightIds { enum LightIds {
ENUMS(PHASE_LIGHT, 3), ENUMS(PHASE_LIGHT, 3),
INVERT_LIGHT,
OFFSET_LIGHT,
NUM_LIGHTS NUM_LIGHTS
}; };


LowFrequencyOscillator<float_4> oscillators[4];
bool offset = false;
bool invert = false;

float_4 phases[4];
dsp::TSchmittTrigger<float_4> clockTriggers[4];
dsp::TSchmittTrigger<float_4> resetTriggers[4];
dsp::SchmittTrigger clockTrigger;
float clockFreq = 1.f;
dsp::Timer clockTimer;

dsp::BooleanTrigger offsetTrigger;
dsp::BooleanTrigger invertTrigger;
dsp::ClockDivider lightDivider; dsp::ClockDivider lightDivider;


LFO() { LFO() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
configSwitch(OFFSET_PARAM, 0.f, 1.f, 1.f, "Offset", {"Bipolar", "Unipolar"});
configSwitch(INVERT_PARAM, 0.f, 1.f, 1.f, "Orientation", {"Inverted", "Normal"});
configButton(OFFSET_PARAM, "Offset 0-10V");
configButton(INVERT_PARAM, "Invert");
configParam(FREQ_PARAM, -8.f, 10.f, 1.f, "Frequency", " Hz", 2, 1); configParam(FREQ_PARAM, -8.f, 10.f, 1.f, "Frequency", " Hz", 2, 1);
configParam(FM1_PARAM, 0.f, 1.f, 0.f, "Frequency modulation 1", "%", 0.f, 100.f);
configParam(FM_PARAM, -1.f, 1.f, 0.f, "Frequency modulation", "%", 0.f, 100.f);
getParamQuantity(FM_PARAM)->randomizeEnabled = false;
configParam(PW_PARAM, 0.01f, 0.99f, 0.5f, "Pulse width", "%", 0.f, 100.f); configParam(PW_PARAM, 0.01f, 0.99f, 0.5f, "Pulse width", "%", 0.f, 100.f);
configParam(FM2_PARAM, 0.f, 1.f, 0.f, "Frequency modulation 2", "%", 0.f, 100.f);
configParam(PWM_PARAM, 0.f, 1.f, 0.f, "Pulse width modulation", "%", 0.f, 100.f);
configInput(FM1_INPUT, "Frequency modulation 1");
configInput(FM2_INPUT, "Frequency modulation 2");
configParam(PWM_PARAM, -1.f, 1.f, 0.f, "Pulse width modulation", "%", 0.f, 100.f);
getParamQuantity(PWM_PARAM)->randomizeEnabled = false;

configInput(FM_INPUT, "Frequency modulation");
configInput(CLOCK_INPUT, "Clock");
configInput(RESET_INPUT, "Reset"); configInput(RESET_INPUT, "Reset");
configInput(PW_INPUT, "Pulse width modulation"); configInput(PW_INPUT, "Pulse width modulation");

configOutput(SIN_OUTPUT, "Sine"); configOutput(SIN_OUTPUT, "Sine");
configOutput(TRI_OUTPUT, "Triangle"); configOutput(TRI_OUTPUT, "Triangle");
configOutput(SAW_OUTPUT, "Sawtooth"); configOutput(SAW_OUTPUT, "Sawtooth");
configOutput(SQR_OUTPUT, "Square"); configOutput(SQR_OUTPUT, "Square");

configLight(PHASE_LIGHT, "Phase"); configLight(PHASE_LIGHT, "Phase");
lightInfos[PHASE_LIGHT]->description = "Tracks the sine output.\nGreen if positive, red if negative, blue if polyphonic.";


lightDivider.setDivision(16); lightDivider.setDivision(16);
onReset();
}

void onReset() override {
offset = false;
invert = false;
for (int c = 0; c < 16; c += 4) {
phases[c / 4] = 0.f;
}
clockFreq = 1.f;
clockTimer.reset();
} }


void process(const ProcessArgs& args) override { void process(const ProcessArgs& args) override {
float freqParam = params[FREQ_PARAM].getValue(); float freqParam = params[FREQ_PARAM].getValue();
float fm1Param = params[FM1_PARAM].getValue();
float fm2Param = params[FM2_PARAM].getValue();
float fmParam = params[FM_PARAM].getValue();
float pwParam = params[PW_PARAM].getValue(); float pwParam = params[PW_PARAM].getValue();
float pwmParam = params[PWM_PARAM].getValue(); float pwmParam = params[PWM_PARAM].getValue();


int channels = std::max(1, inputs[FM1_INPUT].getChannels());
// Buttons
if (offsetTrigger.process(params[OFFSET_PARAM].getValue() > 0.f)) {
offset ^= true;
}
if (invertTrigger.process(params[INVERT_PARAM].getValue() > 0.f)) {
invert ^= true;
}


for (int c = 0; c < channels; c += 4) {
auto* oscillator = &oscillators[c / 4];
oscillator->invert = (params[INVERT_PARAM].getValue() == 0.f);
oscillator->bipolar = (params[OFFSET_PARAM].getValue() == 0.f);
// Clock
if (inputs[CLOCK_INPUT].isConnected()) {
clockTimer.process(args.sampleTime);


if (clockTrigger.process(inputs[CLOCK_INPUT].getVoltage(), 0.1f, 2.f)) {
float clockFreq = 1.f / clockTimer.getTime();
clockTimer.reset();
if (0.001f <= clockFreq && clockFreq <= 1000.f) {
this->clockFreq = clockFreq;
}
}
}
else {
// Default frequency when clock is unpatched
clockFreq = 2.f;
}

int channels = std::max(1, inputs[FM_INPUT].getChannels());

for (int c = 0; c < channels; c += 4) {
// Pitch and frequency
float_4 pitch = freqParam; float_4 pitch = freqParam;
// FM1, polyphonic
pitch += inputs[FM1_INPUT].getVoltageSimd<float_4>(c) * fm1Param;
// FM2, polyphonic or monophonic
pitch += inputs[FM2_INPUT].getPolyVoltageSimd<float_4>(c) * fm2Param;
oscillator->setPitch(pitch);
pitch += inputs[FM_INPUT].getVoltageSimd<float_4>(c) * fmParam;
float_4 freq = clockFreq / 2.f * dsp::approxExp2_taylor5(pitch + 30.f) / std::pow(2.f, 30.f);


// Pulse width // Pulse width
float_4 pw = pwParam + inputs[PW_INPUT].getPolyVoltageSimd<float_4>(c) / 10.f * pwmParam;
oscillator->setPulseWidth(pw);

oscillator->step(args.sampleTime);
oscillator->setReset(inputs[RESET_INPUT].getPolyVoltageSimd<float_4>(c));

// Outputs
if (outputs[SIN_OUTPUT].isConnected())
outputs[SIN_OUTPUT].setVoltageSimd(5.f * oscillator->sin(), c);
if (outputs[TRI_OUTPUT].isConnected())
outputs[TRI_OUTPUT].setVoltageSimd(5.f * oscillator->tri(), c);
if (outputs[SAW_OUTPUT].isConnected())
outputs[SAW_OUTPUT].setVoltageSimd(5.f * oscillator->saw(), c);
if (outputs[SQR_OUTPUT].isConnected())
outputs[SQR_OUTPUT].setVoltageSimd(5.f * oscillator->sqr(), c);
float_4 pw = pwParam;
pw += inputs[PW_INPUT].getPolyVoltageSimd<float_4>(c) / 10.f * pwmParam;
pw = clamp(pw, 0.01f, 0.99f);

// Advance phase
float_4 deltaPhase = simd::fmin(freq * args.sampleTime, 0.5f);
phases[c / 4] += deltaPhase;
phases[c / 4] -= simd::trunc(phases[c / 4]);

// Reset
float_4 reset = inputs[RESET_INPUT].getPolyVoltageSimd<float_4>(c);
float_4 resetTriggered = resetTriggers[c / 4].process(reset, 0.1f, 2.f);
phases[c / 4] = simd::ifelse(resetTriggered, 0.f, phases[c / 4]);

// Sine
if (outputs[SIN_OUTPUT].isConnected()) {
float_4 p = phases[c / 4];
if (offset)
p -= 0.25f;
float_4 v = simd::sin(2 * M_PI * p);
if (invert)
v *= -1.f;
if (offset)
v += 1.f;
outputs[SIN_OUTPUT].setVoltageSimd(5.f * v, c);
}
// Triangle
if (outputs[TRI_OUTPUT].isConnected()) {
float_4 p = phases[c / 4];
if (!offset)
p += 0.25f;
float_4 v = 4.f * simd::fabs(p - simd::round(p)) - 1.f;
if (invert)
v *= -1.f;
if (offset)
v += 1.f;
outputs[TRI_OUTPUT].setVoltageSimd(5.f * v, c);
}
// Sawtooth
if (outputs[SAW_OUTPUT].isConnected()) {
float_4 p = phases[c / 4];
if (offset)
p -= 0.5f;
float_4 v = 2.f * (p - simd::round(p));
if (invert)
v *= -1.f;
if (offset)
v += 1.f;
outputs[SAW_OUTPUT].setVoltageSimd(5.f * v, c);
}
// Square
if (outputs[SQR_OUTPUT].isConnected()) {
float_4 v = simd::ifelse(phases[c / 4] < pw, 1.f, -1.f);
if (invert)
v *= -1.f;
if (offset)
v += 1.f;
outputs[SQR_OUTPUT].setVoltageSimd(5.f * v, c);
}
} }


outputs[SIN_OUTPUT].setChannels(channels); outputs[SIN_OUTPUT].setChannels(channels);
@@ -185,9 +198,9 @@ struct LFO : Module {
// Light // Light
if (lightDivider.process()) { if (lightDivider.process()) {
if (channels == 1) { if (channels == 1) {
float lightValue = oscillators[0].light().s[0];
lights[PHASE_LIGHT + 0].setSmoothBrightness(-lightValue, args.sampleTime * lightDivider.getDivision());
lights[PHASE_LIGHT + 1].setSmoothBrightness(lightValue, args.sampleTime * lightDivider.getDivision());
float b = 1.f - phases[0][0];
lights[PHASE_LIGHT + 0].setSmoothBrightness(b, args.sampleTime * lightDivider.getDivision());
lights[PHASE_LIGHT + 1].setSmoothBrightness(b, args.sampleTime * lightDivider.getDivision());
lights[PHASE_LIGHT + 2].setBrightness(0.f); lights[PHASE_LIGHT + 2].setBrightness(0.f);
} }
else { else {
@@ -195,6 +208,41 @@ struct LFO : Module {
lights[PHASE_LIGHT + 1].setBrightness(0.f); lights[PHASE_LIGHT + 1].setBrightness(0.f);
lights[PHASE_LIGHT + 2].setBrightness(1.f); lights[PHASE_LIGHT + 2].setBrightness(1.f);
} }
lights[OFFSET_LIGHT].setBrightness(offset);
lights[INVERT_LIGHT].setBrightness(invert);
}
}

json_t* dataToJson() override {
json_t* rootJ = json_object();
// offset
json_object_set_new(rootJ, "offset", json_boolean(offset));
// invert
json_object_set_new(rootJ, "invert", json_boolean(invert));
return rootJ;
}

void dataFromJson(json_t* rootJ) override {
// offset
json_t* offsetJ = json_object_get(rootJ, "offset");
if (offsetJ)
offset = json_boolean_value(offsetJ);
// invert
json_t* invertJ = json_object_get(rootJ, "invert");
if (invertJ)
invert = json_boolean_value(invertJ);
}

void paramsFromJson(json_t* rootJ) override {
Module::paramsFromJson(rootJ);
// In <2.0, OFFSET_PARAM and INVERT_PARAM were toggle switches instead of momentary buttons, so if params are on after deserializing, set boolean states instead.
if (params[OFFSET_PARAM].getValue() > 0.f) {
offset = true;
params[OFFSET_PARAM].setValue(0.f);
}
if (params[INVERT_PARAM].getValue() > 0.f) {
invert = true;
params[INVERT_PARAM].setValue(0.f);
} }
} }
}; };
@@ -212,13 +260,13 @@ struct LFOWidget : ModuleWidget {


addParam(createParamCentered<RoundHugeBlackKnob>(mm2px(Vec(22.902, 29.803)), module, LFO::FREQ_PARAM)); addParam(createParamCentered<RoundHugeBlackKnob>(mm2px(Vec(22.902, 29.803)), module, LFO::FREQ_PARAM));
addParam(createParamCentered<RoundLargeBlackKnob>(mm2px(Vec(22.861, 56.388)), module, LFO::PW_PARAM)); addParam(createParamCentered<RoundLargeBlackKnob>(mm2px(Vec(22.861, 56.388)), module, LFO::PW_PARAM));
addParam(createParamCentered<Trimpot>(mm2px(Vec(6.604, 80.603)), module, LFO::FM1_PARAM));
// addParam(createParamCentered<LEDButton>(mm2px(Vec(17.441, 80.603)), module, LFO::INV_PARAM));
// addParam(createParamCentered<LEDButton>(mm2px(Vec(28.279, 80.603)), module, LFO::OFST_PARAM));
addParam(createParamCentered<Trimpot>(mm2px(Vec(6.604, 80.603)), module, LFO::FM_PARAM));
addParam(createLightParamCentered<LEDLightButton<MediumSimpleLight<YellowLight>>>(mm2px(Vec(17.441, 80.603)), module, LFO::INVERT_PARAM, LFO::INVERT_LIGHT));
addParam(createLightParamCentered<LEDLightButton<MediumSimpleLight<YellowLight>>>(mm2px(Vec(28.279, 80.603)), module, LFO::OFFSET_PARAM, LFO::OFFSET_LIGHT));
addParam(createParamCentered<Trimpot>(mm2px(Vec(39.116, 80.603)), module, LFO::PWM_PARAM)); addParam(createParamCentered<Trimpot>(mm2px(Vec(39.116, 80.603)), module, LFO::PWM_PARAM));


addInput(createInputCentered<PJ301MPort>(mm2px(Vec(6.604, 96.859)), module, LFO::FM1_INPUT));
// addInput(createInputCentered<PJ301MPort>(mm2px(Vec(17.441, 96.859)), module, LFO::CLK_INPUT));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(6.604, 96.859)), module, LFO::FM_INPUT));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(17.441, 96.859)), module, LFO::CLOCK_INPUT));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(28.279, 96.819)), module, LFO::RESET_INPUT)); addInput(createInputCentered<PJ301MPort>(mm2px(Vec(28.279, 96.819)), module, LFO::RESET_INPUT));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(39.116, 96.819)), module, LFO::PW_INPUT)); addInput(createInputCentered<PJ301MPort>(mm2px(Vec(39.116, 96.819)), module, LFO::PW_INPUT));


@@ -233,130 +281,3 @@ struct LFOWidget : ModuleWidget {




Model* modelLFO = createModel<LFO, LFOWidget>("LFO"); Model* modelLFO = createModel<LFO, LFOWidget>("LFO");


#if 0
struct LFO2 : Module {
enum ParamIds {
OFFSET_PARAM,
INVERT_PARAM,
FREQ_PARAM,
WAVE_PARAM,
FM_PARAM,
NUM_PARAMS
};
enum InputIds {
FM_INPUT,
RESET_INPUT,
WAVE_INPUT,
NUM_INPUTS
};
enum OutputIds {
INTERP_OUTPUT,
NUM_OUTPUTS
};
enum LightIds {
ENUMS(PHASE_LIGHT, 3),
NUM_LIGHTS
};

LowFrequencyOscillator<float_4> oscillators[4];
dsp::ClockDivider lightDivider;

LFO2() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
configSwitch(OFFSET_PARAM, 0.f, 1.f, 1.f, "Offset", {"Bipolar", "Unipolar"});
configSwitch(INVERT_PARAM, 0.f, 1.f, 1.f, "Orientation", {"Inverted", "Normal"});
configParam(FREQ_PARAM, -8.f, 10.f, 1.f, "Frequency", " Hz", 2, 1);
configParam(WAVE_PARAM, 0.f, 3.f, 1.5f, "Wave");
configParam(FM_PARAM, 0.f, 1.f, 1.f, "Frequency modulation", "%", 0.f, 100.f);
configInput(FM_INPUT, "Frequency modulation");
configInput(RESET_INPUT, "Reset");
configInput(WAVE_INPUT, "Wave type");
configOutput(INTERP_OUTPUT, "Audio");
configLight(PHASE_LIGHT, "Phase");
lightInfos[PHASE_LIGHT]->description = "Tracks the sine output.\nGreen if positive, red if negative, blue if polyphonic.";

lightDivider.setDivision(16);
}

void process(const ProcessArgs& args) override {
float freqParam = params[FREQ_PARAM].getValue();
float fmParam = params[FM_PARAM].getValue();
float waveParam = params[WAVE_PARAM].getValue();

int channels = std::max(1, inputs[FM_INPUT].getChannels());

for (int c = 0; c < channels; c += 4) {
auto* oscillator = &oscillators[c / 4];
oscillator->invert = (params[INVERT_PARAM].getValue() == 0.f);
oscillator->bipolar = (params[OFFSET_PARAM].getValue() == 0.f);

float_4 pitch = freqParam + inputs[FM_INPUT].getVoltageSimd<float_4>(c) * fmParam;
oscillator->setPitch(pitch);

oscillator->step(args.sampleTime);
oscillator->setReset(inputs[RESET_INPUT].getPolyVoltageSimd<float_4>(c));

// Outputs
if (outputs[INTERP_OUTPUT].isConnected()) {
float_4 wave = simd::clamp(waveParam + inputs[WAVE_INPUT].getPolyVoltageSimd<float_4>(c) / 10.f * 3.f, 0.f, 3.f);
float_4 v = 0.f;
v += oscillator->sin() * simd::fmax(0.f, 1.f - simd::fabs(wave - 0.f));
v += oscillator->tri() * simd::fmax(0.f, 1.f - simd::fabs(wave - 1.f));
v += oscillator->saw() * simd::fmax(0.f, 1.f - simd::fabs(wave - 2.f));
v += oscillator->sqr() * simd::fmax(0.f, 1.f - simd::fabs(wave - 3.f));
outputs[INTERP_OUTPUT].setVoltageSimd(5.f * v, c);
}
}

outputs[INTERP_OUTPUT].setChannels(channels);

// Light
if (lightDivider.process()) {
if (channels == 1) {
float lightValue = oscillators[0].light().s[0];
lights[PHASE_LIGHT + 0].setSmoothBrightness(-lightValue, args.sampleTime * lightDivider.getDivision());
lights[PHASE_LIGHT + 1].setSmoothBrightness(lightValue, args.sampleTime * lightDivider.getDivision());
lights[PHASE_LIGHT + 2].setBrightness(0.f);
}
else {
lights[PHASE_LIGHT + 0].setBrightness(0.f);
lights[PHASE_LIGHT + 1].setBrightness(0.f);
lights[PHASE_LIGHT + 2].setBrightness(1.f);
}
}
}
};


struct LFO2Widget : ModuleWidget {
LFO2Widget(LFO2* module) {
setModule(module);
setPanel(createPanel(asset::plugin(pluginInstance, "res/WTLFO.svg")));

addChild(createWidget<ScrewSilver>(Vec(15, 0)));
addChild(createWidget<ScrewSilver>(Vec(box.size.x - 30, 0)));
addChild(createWidget<ScrewSilver>(Vec(15, 365)));
addChild(createWidget<ScrewSilver>(Vec(box.size.x - 30, 365)));

addParam(createParam<CKSS>(Vec(62, 150), module, LFO2::OFFSET_PARAM));
addParam(createParam<CKSS>(Vec(62, 215), module, LFO2::INVERT_PARAM));

addParam(createParam<RoundHugeBlackKnob>(Vec(18, 60), module, LFO2::FREQ_PARAM));
addParam(createParam<RoundLargeBlackKnob>(Vec(11, 142), module, LFO2::WAVE_PARAM));
addParam(createParam<RoundLargeBlackKnob>(Vec(11, 207), module, LFO2::FM_PARAM));

addInput(createInput<PJ301MPort>(Vec(11, 276), module, LFO2::FM_INPUT));
addInput(createInput<PJ301MPort>(Vec(54, 276), module, LFO2::RESET_INPUT));
addInput(createInput<PJ301MPort>(Vec(11, 319), module, LFO2::WAVE_INPUT));

addOutput(createOutput<PJ301MPort>(Vec(54, 319), module, LFO2::INTERP_OUTPUT));

addChild(createLight<SmallLight<RedGreenBlueLight>>(Vec(68, 42.5f), module, LFO2::PHASE_LIGHT));
}
};


Model* modelLFO2 = createModel<LFO2, LFO2Widget>("LFO2");
#endif

+ 4
- 2
src/WTLFO.cpp View File

@@ -96,6 +96,8 @@ struct WTLFO : Module {
for (int c = 0; c < 16; c += 4) { for (int c = 0; c < 16; c += 4) {
phases[c / 4] = 0.f; phases[c / 4] = 0.f;
} }
clockFreq = 1.f;
clockTimer.reset();
} }


void onRandomize(const RandomizeEvent& e) override { void onRandomize(const RandomizeEvent& e) override {
@@ -137,7 +139,7 @@ struct WTLFO : Module {
if (inputs[CLOCK_INPUT].isConnected()) { if (inputs[CLOCK_INPUT].isConnected()) {
clockTimer.process(args.sampleTime); clockTimer.process(args.sampleTime);


if (clockTrigger.process(rescale(inputs[CLOCK_INPUT].getVoltage(), 0.1f, 2.f, 0.f, 1.f))) {
if (clockTrigger.process(inputs[CLOCK_INPUT].getVoltage(), 0.1f, 2.f)) {
float clockFreq = 1.f / clockTimer.getTime(); float clockFreq = 1.f / clockTimer.getTime();
clockTimer.reset(); clockTimer.reset();
if (0.001f <= clockFreq && clockFreq <= 1000.f) { if (0.001f <= clockFreq && clockFreq <= 1000.f) {
@@ -170,7 +172,7 @@ struct WTLFO : Module {
for (int c = 0; c < channels; c += 4) { for (int c = 0; c < channels; c += 4) {
// Calculate frequency in Hz // Calculate frequency in Hz
float_4 pitch = freqParam + inputs[FM_INPUT].getVoltageSimd<float_4>(c) * fmParam; float_4 pitch = freqParam + inputs[FM_INPUT].getVoltageSimd<float_4>(c) * fmParam;
float_4 freq = clockFreq / 2.f * simd::pow(2.f, pitch);
float_4 freq = clockFreq / 2.f * dsp::approxExp2_taylor5(pitch + 30.f) / std::pow(2.f, 30.f);
freq = simd::fmin(freq, 1024.f); freq = simd::fmin(freq, 1024.f);


// Accumulate phase // Accumulate phase


Loading…
Cancel
Save