|
|
@@ -27,7 +27,9 @@ struct Delay : Module { |
|
|
|
DoubleRingBuffer<float, HISTORY_SIZE> historyBuffer; |
|
|
|
DoubleRingBuffer<float, 16> 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<Davies1900hBlackKnob>(Vec(67, 57), module, Delay::TIME_PARAM, 0.0, 1.0, 0.5)); |
|
|
|
addParam(createParam<Davies1900hBlackKnob>(Vec(67, 123), module, Delay::FEEDBACK_PARAM, 0.0, 1.0, 0.5)); |
|
|
|
addParam(createParam<Davies1900hBlackKnob>(Vec(67, 190), module, Delay::COLOR_PARAM, -1.0, 1.0, 0.0)); |
|
|
|
addParam(createParam<Davies1900hBlackKnob>(Vec(67, 190), module, Delay::COLOR_PARAM, 0.0, 1.0, 0.5)); |
|
|
|
addParam(createParam<Davies1900hBlackKnob>(Vec(67, 257), module, Delay::MIX_PARAM, 0.0, 1.0, 0.5)); |
|
|
|
|
|
|
|
addInput(createInput<PJ301MPort>(Vec(14, 63), module, Delay::TIME_INPUT)); |
|
|
|