#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::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::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::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; }