|
@@ -12,14 +12,12 @@
|
|
|
|
|
|
|
|
CMLSDelay::CMLSDelay() {
|
|
CMLSDelay::CMLSDelay() {
|
|
|
delayLengthRange = new juce::NormalisableRange<float>(0, MAX_DELAY_LENGTH);
|
|
delayLengthRange = new juce::NormalisableRange<float>(0, MAX_DELAY_LENGTH);
|
|
|
- feedbackRange = new juce::NormalisableRange<float>(0, MAX_FEEDBACK);
|
|
|
|
|
|
|
+ feedbackRange = new juce::NormalisableRange<float>(MIN_FEEDBACK, MAX_FEEDBACK);
|
|
|
|
|
|
|
|
this->delayLength = 0.0f;
|
|
this->delayLength = 0.0f;
|
|
|
- this->feedback = 0.75f;
|
|
|
|
|
- this->delayBufferLength = 1;
|
|
|
|
|
-
|
|
|
|
|
- this->delayReadPosition = 0;
|
|
|
|
|
- this->delayWritePosition = 0;
|
|
|
|
|
|
|
+ this->feedback = 0.0f;
|
|
|
|
|
+ this->amount = 0.0f;
|
|
|
|
|
+ this->dryWetProp = 0.0f;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
CMLSDelay::~CMLSDelay() {}
|
|
CMLSDelay::~CMLSDelay() {}
|
|
@@ -28,16 +26,23 @@ void CMLSDelay::reset() {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void CMLSDelay::prepare(const juce::dsp::ProcessSpec& spec) {
|
|
void CMLSDelay::prepare(const juce::dsp::ProcessSpec& spec) {
|
|
|
- this->delayBufferLength = (int) 2.0 * spec.sampleRate;
|
|
|
|
|
-
|
|
|
|
|
- if (this->delayBufferLength < 1) {
|
|
|
|
|
- this->delayBufferLength = 1;
|
|
|
|
|
|
|
+ this->effectDelaySamples = spec.sampleRate * MAX_DELAY_LENGTH;
|
|
|
|
|
+ this->delayLine.setMaximumDelayInSamples(this->effectDelaySamples);
|
|
|
|
|
+ this->linearDelay.setMaximumDelayInSamples(this->effectDelaySamples);
|
|
|
|
|
+
|
|
|
|
|
+ this->delayLine.prepare(spec);
|
|
|
|
|
+ this->linearDelay.prepare(spec);
|
|
|
|
|
+ this->mixer.prepare(spec);
|
|
|
|
|
+
|
|
|
|
|
+ for (auto& volume : this->delayFeedbackVolume) {
|
|
|
|
|
+ volume.reset(spec.sampleRate, 0.05f);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- this->delayBuffer.setSize(spec.numChannels, this->delayBufferLength);
|
|
|
|
|
- this->delayBuffer.clear();
|
|
|
|
|
|
|
+ this->mixer.reset();
|
|
|
|
|
+ this->mixer.setMixingRule(juce::dsp::DryWetMixingRule::linear);
|
|
|
|
|
|
|
|
- this->delayReadPosition = (int)(this->delayWritePosition - (this->delayLength * spec.sampleRate) + this->delayBufferLength) % this->delayBufferLength;
|
|
|
|
|
|
|
+ std::fill(this->delayValue.begin(), this->delayValue.end(), 0.0f);
|
|
|
|
|
+ std::fill(this->lastDelayOutput.begin(), this->lastDelayOutput.end(), 0.0f);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void CMLSDelay::process(const juce::dsp::ProcessContextReplacing<float>& context) {
|
|
void CMLSDelay::process(const juce::dsp::ProcessContextReplacing<float>& context) {
|
|
@@ -45,44 +50,43 @@ void CMLSDelay::process(const juce::dsp::ProcessContextReplacing<float>& context
|
|
|
auto numChannels = audioBlock.getNumChannels();
|
|
auto numChannels = audioBlock.getNumChannels();
|
|
|
const auto numSamples = audioBlock.getNumSamples();
|
|
const auto numSamples = audioBlock.getNumSamples();
|
|
|
|
|
|
|
|
- int dpr, dpw;
|
|
|
|
|
|
|
+ const auto& input = context.getInputBlock();
|
|
|
|
|
+ const auto& output = context.getOutputBlock();
|
|
|
|
|
|
|
|
- for (int channel = 0; channel < numChannels; ++channel) {
|
|
|
|
|
- float* channelData = audioBlock.getChannelPointer(channel);
|
|
|
|
|
- float* delayData = this->delayBuffer.getWritePointer(juce::jmin(channel, this->delayBuffer.getNumChannels() - 1));
|
|
|
|
|
|
|
+ this->mixer.pushDrySamples(input);
|
|
|
|
|
|
|
|
- dpr = this->delayReadPosition;
|
|
|
|
|
- dpw = this->delayWritePosition;
|
|
|
|
|
|
|
+ for (size_t channel = 0; channel < numChannels; ++channel) {
|
|
|
|
|
+ auto* samplesIn = input.getChannelPointer(channel);
|
|
|
|
|
+ auto* samplesOut = output.getChannelPointer(channel);
|
|
|
|
|
|
|
|
- for (int sample = 0; sample < numSamples; sample++) {
|
|
|
|
|
- const float in = channelData[sample];
|
|
|
|
|
- float out = 0.0f;
|
|
|
|
|
|
|
+ for (size_t sample = 0; sample < input.getNumSamples(); ++sample) {
|
|
|
|
|
+ auto input = samplesIn[sample] - this->lastDelayOutput[channel];
|
|
|
|
|
+ auto delayAmount = this->delayValue[channel];
|
|
|
|
|
|
|
|
- out = ((1-this->dryWetProp) * in + this->dryWetProp * delayData[dpr]);
|
|
|
|
|
- delayData[dpw] = in + (this->feedback * delayData[dpr]);
|
|
|
|
|
|
|
+ this->linearDelay.pushSample(channel, input);
|
|
|
|
|
+ this->linearDelay.setDelay(delayAmount);
|
|
|
|
|
+ samplesOut[sample] = this->linearDelay.popSample(channel);
|
|
|
|
|
|
|
|
- if (++dpr >= this->delayBufferLength) {
|
|
|
|
|
- dpr = 0;
|
|
|
|
|
- }
|
|
|
|
|
- if (++dpw >= this->delayBufferLength) {
|
|
|
|
|
- dpw = 0;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- channelData[sample] = out;
|
|
|
|
|
|
|
+ this->lastDelayOutput[channel] = samplesOut[sample] * this->delayFeedbackVolume[channel].getNextValue();
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- this->delayReadPosition = dpr;
|
|
|
|
|
- this->delayWritePosition = dpw;
|
|
|
|
|
|
|
+ this->mixer.mixWetSamples(output);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void CMLSDelay::setDryWet(float value) {
|
|
void CMLSDelay::setDryWet(float value) {
|
|
|
this->dryWetProp = value;
|
|
this->dryWetProp = value;
|
|
|
|
|
+ this->mixer.setWetMixProportion(this->dryWetProp);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void CMLSDelay::setAmount(float value) {
|
|
void CMLSDelay::setAmount(float value) {
|
|
|
this->delayLength = this->delayLengthRange->convertFrom0to1(value);
|
|
this->delayLength = this->delayLengthRange->convertFrom0to1(value);
|
|
|
this->feedback = this->delayLengthRange->convertFrom0to1(value);
|
|
this->feedback = this->delayLengthRange->convertFrom0to1(value);
|
|
|
|
|
+
|
|
|
|
|
+ std::fill(this->delayValue.begin(), this->delayValue.end(), this->delayLength * this->effectDelaySamples);
|
|
|
|
|
+ for (auto& volume : this->delayFeedbackVolume) {
|
|
|
|
|
+ volume.setTargetValue(this->feedback);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const float CMLSDelay::getDryWet() {
|
|
const float CMLSDelay::getDryWet() {
|