From bdcf327dfb6a62f42cd0525b681baf258e65dc21 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Tue, 5 Sep 2017 04:35:36 -0400 Subject: [PATCH] Some attempt at improving Delay --- src/Delay.cpp | 82 ++++++++++++++++++++++++++++++++++--------------- src/Scope.cpp | 22 +++++++++++++ src/VCMixer.cpp | 6 ++-- 3 files changed, 82 insertions(+), 28 deletions(-) diff --git a/src/Delay.cpp b/src/Delay.cpp index c25b09c..58a95df 100644 --- a/src/Delay.cpp +++ b/src/Delay.cpp @@ -27,7 +27,9 @@ struct Delay : Module { DoubleRingBuffer historyBuffer; DoubleRingBuffer outBuffer; SampleRateConverter<1> src; - float lastIndex = 0.0; + float lastWet = 0.0; + RCFilter lowpassFilter; + RCFilter highpassFilter; Delay(); @@ -42,39 +44,69 @@ Delay::Delay() { } void Delay::step() { - // Compute delay time + // Get input to delay block + float in = getf(inputs[IN_INPUT]); + float feedback = clampf(params[FEEDBACK_PARAM] + getf(inputs[FEEDBACK_INPUT]) / 10.0, 0.0, 0.99); + float dry = in + lastWet * feedback; + + // Compute delay time in seconds float delay = 1e-3 * powf(10.0 / 1e-3, clampf(params[TIME_PARAM] + getf(inputs[TIME_INPUT]) / 10.0, 0.0, 1.0)); + // Number of delay samples float index = delay * gSampleRate; - // lastIndex = crossf(lastIndex, index, 0.001); - // Read the history - int consume = (int)(historyBuffer.size() - index); + // TODO This is a horrible digital delay algorithm. Rewrite later. + + // Push dry sample into history buffer + if (!historyBuffer.full()) { + historyBuffer.push(dry); + } + + // How many samples do we need consume to catch up? + float consume = index - historyBuffer.size(); + // printf("%f\t%d\t%f\n", index, historyBuffer.size(), consume); + // printf("wanted: %f\tactual: %d\tdiff: %d\tratio: %f\n", index, historyBuffer.size(), consume, index / historyBuffer.size()); if (outBuffer.empty()) { - if (consume > 0) { - int inFrames = consume; - int outFrames = outBuffer.capacity(); - // printf("\t%d\t%d\n", inFrames, outFrames); - src.setRatioSmooth(index / historyBuffer.size()); - src.process((const Frame<1>*)historyBuffer.startData(), &inFrames, (Frame<1>*)outBuffer.endData(), &outFrames); - historyBuffer.startIncr(inFrames); - outBuffer.endIncr(outFrames); - // printf("\t%d\t%d\n", inFrames, outFrames); - // if (historyBuffer.size() >= index) - // outBuffer.push(historyBuffer.shift()); - } + // Idk wtf I'm doing + double ratio = 1.0; + if (consume <= -16) + ratio = 0.5; + else if (consume >= 16) + ratio = 2.0; + + // printf("%f\t%lf\n", consume, ratio); + int inFrames = mini(historyBuffer.size(), 16); + int outFrames = outBuffer.capacity(); + // printf(">\t%d\t%d\n", inFrames, outFrames); + src.setRatioSmooth(ratio); + src.process((const Frame<1>*)historyBuffer.startData(), &inFrames, (Frame<1>*)outBuffer.endData(), &outFrames); + historyBuffer.startIncr(inFrames); + outBuffer.endIncr(outFrames); + // printf("<\t%d\t%d\n", inFrames, outFrames); + // printf("====================================\n"); } - float out = 0.0; + float wet = 0.0; if (!outBuffer.empty()) { - out = outBuffer.shift(); + wet = outBuffer.shift(); } - // Write the history - float in = getf(inputs[IN_INPUT]); - historyBuffer.push(in + out * clampf(params[FEEDBACK_PARAM] + getf(inputs[FEEDBACK_INPUT]) / 10.0, 0.0, 1.0)); - out = crossf(in, out, clampf(params[MIX_PARAM] + getf(inputs[MIX_INPUT]) / 10.0, 0.0, 1.0)); - + // Apply color to delay wet output + // TODO Make it sound better + float color = clampf(params[COLOR_PARAM] + getf(inputs[COLOR_INPUT]) / 10.0, 0.0, 1.0); + float lowpassFreq = 10000.0 * powf(10.0, clampf(2.0*color, 0.0, 1.0)); + lowpassFilter.setCutoff(lowpassFreq / gSampleRate); + lowpassFilter.process(wet); + wet = lowpassFilter.lowpass(); + float highpassFreq = 10.0 * powf(100.0, clampf(2.0*color - 1.0, 0.0, 1.0)); + highpassFilter.setCutoff(highpassFreq / gSampleRate); + highpassFilter.process(wet); + wet = highpassFilter.highpass(); + + lastWet = wet; + + float mix = clampf(params[MIX_PARAM] + getf(inputs[MIX_INPUT]) / 10.0, 0.0, 1.0); + float out = crossf(in, wet, mix); setf(outputs[OUT_OUTPUT], out); } @@ -98,7 +130,7 @@ DelayWidget::DelayWidget() { addParam(createParam(Vec(67, 57), module, Delay::TIME_PARAM, 0.0, 1.0, 0.5)); addParam(createParam(Vec(67, 123), module, Delay::FEEDBACK_PARAM, 0.0, 1.0, 0.5)); - addParam(createParam(Vec(67, 190), module, Delay::COLOR_PARAM, -1.0, 1.0, 0.0)); + addParam(createParam(Vec(67, 190), module, Delay::COLOR_PARAM, 0.0, 1.0, 0.5)); addParam(createParam(Vec(67, 257), module, Delay::MIX_PARAM, 0.0, 1.0, 0.5)); addInput(createInput(Vec(14, 63), module, Delay::TIME_INPUT)); diff --git a/src/Scope.cpp b/src/Scope.cpp index 2646329..3685680 100644 --- a/src/Scope.cpp +++ b/src/Scope.cpp @@ -40,6 +40,28 @@ struct Scope : Module { Scope(); void step(); + + json_t *toJson() { + json_t *rootJ = json_object(); + json_object_set_new(rootJ, "sum", json_integer((int) sum)); + json_object_set_new(rootJ, "ext", json_integer((int) ext)); + return rootJ; + } + + void fromJson(json_t *rootJ) { + json_t *sumJ = json_object_get(rootJ, "sum"); + if (sumJ) + sum = json_integer_value(sumJ); + + json_t *extJ = json_object_get(rootJ, "ext"); + if (extJ) + ext = json_integer_value(extJ); + } + + void initialize() { + sum = false; + ext = false; + } }; diff --git a/src/VCMixer.cpp b/src/VCMixer.cpp index 8af442e..13e59e7 100644 --- a/src/VCMixer.cpp +++ b/src/VCMixer.cpp @@ -70,9 +70,9 @@ VCMixerWidget::VCMixerWidget() { addChild(createScrew(Vec(box.size.x-30, 365))); addParam(createParam(Vec(48, 55), module, VCMixer::MIX_PARAM, 0.0, 1.0, 0.5)); - addParam(createParam(Vec(57, 139), module, VCMixer::CH1_PARAM, 0.0, 1.0, 0.5)); - addParam(createParam(Vec(57, 219), module, VCMixer::CH2_PARAM, 0.0, 1.0, 0.5)); - addParam(createParam(Vec(57, 300), module, VCMixer::CH3_PARAM, 0.0, 1.0, 0.5)); + addParam(createParam(Vec(57, 139), module, VCMixer::CH1_PARAM, 0.0, 1.0, 0.0)); + addParam(createParam(Vec(57, 219), module, VCMixer::CH2_PARAM, 0.0, 1.0, 0.0)); + addParam(createParam(Vec(57, 300), module, VCMixer::CH3_PARAM, 0.0, 1.0, 0.0)); addInput(createInput(Vec(16, 69), module, VCMixer::MIX_CV_INPUT)); addInput(createInput(Vec(22, 129), module, VCMixer::CH1_INPUT));