mirror of
https://codeberg.org/armin/horizont.git
synced 2026-09-01 04:10:46 +02:00
218 lines
5.9 KiB
C++
218 lines
5.9 KiB
C++
|
|
#include "HorizontEngine.h"
|
||
|
|
|
||
|
|
HorizontEngine::HorizontEngine()
|
||
|
|
{
|
||
|
|
prepare (44100.0);
|
||
|
|
}
|
||
|
|
|
||
|
|
void HorizontEngine::prepare (double sr)
|
||
|
|
{
|
||
|
|
sampleRate = sr;
|
||
|
|
const float srScale = (float) (sr / 44100.0);
|
||
|
|
|
||
|
|
for (int i = 0; i < 8; ++i)
|
||
|
|
{
|
||
|
|
baseLen[(size_t) i] = baseLen441[(size_t) i] * srScale;
|
||
|
|
baseLenR[(size_t) i] = (baseLen441[(size_t) i] + rightOffset[(size_t) i]) * srScale;
|
||
|
|
|
||
|
|
const int maxL = (int) std::ceil (baseLen441[(size_t) i] * 2.0f * srScale) + 8;
|
||
|
|
combL[(size_t) i].prepare (maxL);
|
||
|
|
combR[(size_t) i].prepare (maxL);
|
||
|
|
}
|
||
|
|
|
||
|
|
diffL1.prepare ((int) (221.0f * srScale));
|
||
|
|
diffL2.prepare ((int) (113.0f * srScale));
|
||
|
|
diffR1.prepare ((int) (229.0f * srScale));
|
||
|
|
diffR2.prepare ((int) (107.0f * srScale));
|
||
|
|
|
||
|
|
shiftL.prepare (sr);
|
||
|
|
shiftR.prepare (sr);
|
||
|
|
|
||
|
|
lowCutG.reset (sr, 0.04);
|
||
|
|
setLowCut (lowCutHz);
|
||
|
|
lowCutG.setCurrentAndTargetValue (lowCutG.getTargetValue());
|
||
|
|
|
||
|
|
highCutG.reset (sr, 0.04);
|
||
|
|
setHighCut (highCutHz);
|
||
|
|
highCutG.setCurrentAndTargetValue (highCutG.getTargetValue());
|
||
|
|
|
||
|
|
decayS.reset (sr, 0.06);
|
||
|
|
setDecay (decaySec);
|
||
|
|
decayS.setCurrentAndTargetValue (decayS.getTargetValue());
|
||
|
|
|
||
|
|
sizeS.reset (sr, 0.06);
|
||
|
|
setSize (sizeVal);
|
||
|
|
sizeS.setCurrentAndTargetValue (sizeS.getTargetValue());
|
||
|
|
|
||
|
|
diffS.reset (sr, 0.05);
|
||
|
|
setDiffusion (diffusionVal);
|
||
|
|
diffS.setCurrentAndTargetValue (diffS.getTargetValue());
|
||
|
|
|
||
|
|
dampS.reset (sr, 0.05);
|
||
|
|
setBrightness (brightnessVal);
|
||
|
|
dampS.setCurrentAndTargetValue (dampS.getTargetValue());
|
||
|
|
|
||
|
|
feedbackS.reset (sr, 0.06);
|
||
|
|
setFeedback (feedbackVal);
|
||
|
|
feedbackS.setCurrentAndTargetValue (feedbackS.getTargetValue());
|
||
|
|
|
||
|
|
ratioS.reset (sr, 0.08);
|
||
|
|
setPitch (pitchVal);
|
||
|
|
ratioS.setCurrentAndTargetValue (ratioS.getTargetValue());
|
||
|
|
|
||
|
|
wetS.reset (sr, 0.03);
|
||
|
|
setDryWet (dryWetVal);
|
||
|
|
wetS.setCurrentAndTargetValue (wetS.getTargetValue());
|
||
|
|
|
||
|
|
reset();
|
||
|
|
}
|
||
|
|
|
||
|
|
void HorizontEngine::reset()
|
||
|
|
{
|
||
|
|
for (auto& c : combL)
|
||
|
|
c.reset();
|
||
|
|
for (auto& c : combR)
|
||
|
|
c.reset();
|
||
|
|
|
||
|
|
diffL1.reset();
|
||
|
|
diffL2.reset();
|
||
|
|
diffR1.reset();
|
||
|
|
diffR2.reset();
|
||
|
|
|
||
|
|
hpL.reset();
|
||
|
|
lpL.reset();
|
||
|
|
hpR.reset();
|
||
|
|
lpR.reset();
|
||
|
|
|
||
|
|
dcL.reset();
|
||
|
|
dcR.reset();
|
||
|
|
|
||
|
|
shiftL.reset();
|
||
|
|
shiftR.reset();
|
||
|
|
|
||
|
|
lastWetL = 0.0f;
|
||
|
|
lastWetR = 0.0f;
|
||
|
|
}
|
||
|
|
|
||
|
|
void HorizontEngine::setLowCut (float hz)
|
||
|
|
{
|
||
|
|
lowCutHz = hz;
|
||
|
|
hz = juce::jmin (hz, (float) (sampleRate * 0.48));
|
||
|
|
lowCutG.setTargetValue (std::tan (juce::MathConstants<float>::pi * hz / (float) sampleRate));
|
||
|
|
}
|
||
|
|
|
||
|
|
void HorizontEngine::setHighCut (float hz)
|
||
|
|
{
|
||
|
|
highCutHz = hz;
|
||
|
|
hz = juce::jmin (hz, (float) (sampleRate * 0.48));
|
||
|
|
highCutG.setTargetValue (std::tan (juce::MathConstants<float>::pi * hz / (float) sampleRate));
|
||
|
|
}
|
||
|
|
|
||
|
|
void HorizontEngine::setDecay (float seconds)
|
||
|
|
{
|
||
|
|
decaySec = seconds;
|
||
|
|
decayS.setTargetValue (juce::jmax (0.1f, seconds));
|
||
|
|
}
|
||
|
|
|
||
|
|
void HorizontEngine::setSize (float size)
|
||
|
|
{
|
||
|
|
sizeVal = size;
|
||
|
|
sizeS.setTargetValue (juce::jlimit (0.2f, 2.5f, size));
|
||
|
|
}
|
||
|
|
|
||
|
|
void HorizontEngine::setDiffusion (float diffusion)
|
||
|
|
{
|
||
|
|
diffusionVal = diffusion;
|
||
|
|
diffS.setTargetValue (0.72f * juce::jlimit (0.0f, 1.0f, diffusion));
|
||
|
|
}
|
||
|
|
|
||
|
|
void HorizontEngine::setBrightness (float brightness)
|
||
|
|
{
|
||
|
|
brightnessVal = brightness;
|
||
|
|
const float b = juce::jlimit (0.0f, 1.0f, brightness);
|
||
|
|
float fc = 500.0f + 19500.0f * std::pow (b, 1.5f);
|
||
|
|
fc = juce::jmin (fc, (float) (sampleRate * 0.48f));
|
||
|
|
dampS.setTargetValue (1.0f - std::exp (-2.0f * juce::MathConstants<float>::pi * fc / (float) sampleRate));
|
||
|
|
}
|
||
|
|
|
||
|
|
void HorizontEngine::setFeedback (float feedback)
|
||
|
|
{
|
||
|
|
feedbackVal = feedback;
|
||
|
|
feedbackS.setTargetValue (juce::jlimit (0.0f, 0.99f, feedback));
|
||
|
|
}
|
||
|
|
|
||
|
|
void HorizontEngine::setPitch (float semitones)
|
||
|
|
{
|
||
|
|
pitchVal = semitones;
|
||
|
|
ratioS.setTargetValue (std::pow (2.0f, semitones / 12.0f));
|
||
|
|
}
|
||
|
|
|
||
|
|
void HorizontEngine::setDryWet (float dryWet)
|
||
|
|
{
|
||
|
|
dryWetVal = dryWet;
|
||
|
|
wetS.setTargetValue (juce::jlimit (0.0f, 1.0f, dryWet));
|
||
|
|
}
|
||
|
|
|
||
|
|
void HorizontEngine::processSample (float inL, float inR, float& outL, float& outR)
|
||
|
|
{
|
||
|
|
const float sizeCur = sizeS.getNextValue();
|
||
|
|
const float rtCur = decayS.getNextValue();
|
||
|
|
const float dampC = dampS.getNextValue();
|
||
|
|
const float diffG = diffS.getNextValue();
|
||
|
|
const float fbGain = feedbackS.getNextValue();
|
||
|
|
const float ratio = ratioS.getNextValue();
|
||
|
|
const float wetVal = wetS.getNextValue();
|
||
|
|
const float gLow = lowCutG.getNextValue();
|
||
|
|
const float gHigh = highCutG.getNextValue();
|
||
|
|
|
||
|
|
hpL.setG (gLow);
|
||
|
|
hpL.process (inL);
|
||
|
|
lpL.setG (gHigh);
|
||
|
|
lpL.process (hpL.high);
|
||
|
|
|
||
|
|
hpR.setG (gLow);
|
||
|
|
hpR.process (inR);
|
||
|
|
lpR.setG (gHigh);
|
||
|
|
lpR.process (hpR.high);
|
||
|
|
|
||
|
|
const float fl = lpL.low;
|
||
|
|
const float fr = lpR.low;
|
||
|
|
|
||
|
|
const float invRt = 1.0f / (rtCur * sizeCur * (float) sampleRate);
|
||
|
|
|
||
|
|
const float loopInvRt = invRt * (1.0f - 0.7f * fbGain);
|
||
|
|
|
||
|
|
const float gMax = std::exp (-6.907755f * baseLen[0] * sizeCur * loopInvRt);
|
||
|
|
|
||
|
|
const float fbL = fl + fbGain * 0.5f * (1.0f - gMax) * shiftL.process (lastWetL, ratio);
|
||
|
|
const float fbR = fr + fbGain * 0.5f * (1.0f - gMax) * shiftR.process (lastWetR, ratio);
|
||
|
|
|
||
|
|
const float dL = diffL2.process (diffL1.process (fbL, diffG), diffG);
|
||
|
|
const float dR = diffR2.process (diffR1.process (fbR, diffG), diffG);
|
||
|
|
|
||
|
|
float wetL = 0.0f;
|
||
|
|
float wetR = 0.0f;
|
||
|
|
|
||
|
|
for (int i = 0; i < 8; ++i)
|
||
|
|
{
|
||
|
|
const float lenL = baseLen[(size_t) i] * sizeCur;
|
||
|
|
const float gainL = std::exp (-6.907755f * lenL * loopInvRt);
|
||
|
|
wetL += 0.25f * combL[(size_t) i].process (dL, lenL, dampC, gainL);
|
||
|
|
|
||
|
|
const float lenR = baseLenR[(size_t) i] * sizeCur;
|
||
|
|
const float gainR = std::exp (-6.907755f * lenR * loopInvRt);
|
||
|
|
wetR += 0.25f * combR[(size_t) i].process (dR, lenR, dampC, gainR);
|
||
|
|
}
|
||
|
|
|
||
|
|
wetL = dcL.process (wetL);
|
||
|
|
wetR = dcR.process (wetR);
|
||
|
|
|
||
|
|
wetL = std::tanh (wetL);
|
||
|
|
wetR = std::tanh (wetR);
|
||
|
|
|
||
|
|
lastWetL = wetL;
|
||
|
|
lastWetR = wetR;
|
||
|
|
|
||
|
|
outL = inL * (1.0f - wetVal) + wetL * wetVal;
|
||
|
|
outR = inR * (1.0f - wetVal) + wetR * wetVal;
|
||
|
|
}
|