horizont/Source/HorizontEngine.h

218 lines
5.5 KiB
C
Raw Permalink Normal View History

2026-08-10 12:55:02 +02:00
#pragma once
#include <JuceHeader.h>
#include <array>
#include "PitchShifter.h"
class HorizontEngine
{
public:
HorizontEngine();
void prepare (double sampleRate);
void reset();
void setLowCut (float hz);
void setHighCut (float hz);
void setDecay (float seconds);
void setSize (float size);
void setDiffusion (float diffusion);
void setBrightness (float brightness);
void setFeedback (float feedback);
void setPitch (float semitones);
void setDryWet (float dryWet);
void processSample (float inL, float inR, float& outL, float& outR);
float getLastWetL() const noexcept { return lastWetL; }
float getLastWetR() const noexcept { return lastWetR; }
private:
struct SVF
{
void reset()
{
ic1 = 0.0f;
ic2 = 0.0f;
g = 0.0f;
}
void setG (float gIn)
{
g = gIn;
a1 = 1.0f / (1.0f + g * (g + k));
a2 = g * a1;
}
void process (float x)
{
const float v3 = x - ic2;
const float v1 = a1 * ic1 + a2 * v3;
const float v2 = ic2 + g * v1;
ic1 = 2.0f * v1 - ic1;
ic2 = 2.0f * v2 - ic2;
low = v2;
high = x - k * v1 - v2;
}
float g = 0.0f;
float k = 1.41421356f;
float a1 = 0.0f;
float a2 = 0.0f;
float ic1 = 0.0f;
float ic2 = 0.0f;
float low = 0.0f;
float high = 0.0f;
};
struct Allpass
{
void prepare (int length)
{
len = length;
xb.assign ((size_t) len + 1, 0.0f);
yb.assign ((size_t) len + 1, 0.0f);
writePos = 0;
}
void reset()
{
std::fill (xb.begin(), xb.end(), 0.0f);
std::fill (yb.begin(), yb.end(), 0.0f);
writePos = 0;
}
float process (float x, float g)
{
int rp = writePos - len;
if (rp < 0)
rp += len + 1;
const float xd = xb[(size_t) rp];
const float yd = yb[(size_t) rp];
xb[(size_t) writePos] = x;
const float y = -g * x + xd + g * yd;
yb[(size_t) writePos] = y;
++writePos;
if (writePos > len)
writePos = 0;
return y;
}
std::vector<float> xb;
std::vector<float> yb;
int len = 0;
int writePos = 0;
};
struct Comb
{
void prepare (int maxLength)
{
buffer.assign ((size_t) maxLength + 4, 0.0f);
maxLen = maxLength;
writePos = 0;
dampState = 0.0f;
}
void reset()
{
std::fill (buffer.begin(), buffer.end(), 0.0f);
dampState = 0.0f;
writePos = 0;
}
float process (float input, float delayLen, float dampCoef, float gain)
{
const float rp = (float) writePos - delayLen;
int i0 = (int) std::floor (rp);
const float frac = rp - (float) i0;
i0 %= maxLen;
if (i0 < 0)
i0 += maxLen;
int i1 = i0 + 1;
if (i1 >= maxLen)
i1 -= maxLen;
const float y = buffer[(size_t) i0] + frac * (buffer[(size_t) i1] - buffer[(size_t) i0]);
buffer[(size_t) writePos] = input + dampState * gain;
dampState += dampCoef * (y - dampState);
++writePos;
if (writePos >= maxLen)
writePos = 0;
return dampState;
}
std::vector<float> buffer;
int maxLen = 0;
int writePos = 0;
float dampState = 0.0f;
};
struct DCBlock
{
void reset()
{
xm = 0.0f;
ym = 0.0f;
}
float process (float x)
{
const float y = x - xm + 0.999f * ym;
xm = x;
ym = y;
return y;
}
float xm = 0.0f;
float ym = 0.0f;
};
static constexpr std::array<float, 8> baseLen441 = { 1553.f, 1787.f, 2017.f, 2237.f, 2437.f, 2657.f, 2879.f, 3073.f };
static constexpr std::array<float, 8> rightOffset = { 79.f, 67.f, 53.f, 41.f, 29.f, 23.f, 13.f, 7.f };
double sampleRate = 44100.0;
juce::SmoothedValue<float, juce::ValueSmoothingTypes::Linear> lowCutG;
juce::SmoothedValue<float, juce::ValueSmoothingTypes::Linear> highCutG;
juce::SmoothedValue<float, juce::ValueSmoothingTypes::Linear> decayS;
juce::SmoothedValue<float, juce::ValueSmoothingTypes::Linear> sizeS;
juce::SmoothedValue<float, juce::ValueSmoothingTypes::Linear> diffS;
juce::SmoothedValue<float, juce::ValueSmoothingTypes::Linear> dampS;
juce::SmoothedValue<float, juce::ValueSmoothingTypes::Linear> feedbackS;
juce::SmoothedValue<float, juce::ValueSmoothingTypes::Linear> ratioS;
juce::SmoothedValue<float, juce::ValueSmoothingTypes::Linear> wetS;
SVF hpL, lpL, hpR, lpR;
DCBlock dcL, dcR;
Allpass diffL1, diffL2, diffR1, diffR2;
PitchShifter shiftL, shiftR;
std::array<Comb, 8> combL;
std::array<Comb, 8> combR;
std::array<float, 8> baseLen;
std::array<float, 8> baseLenR;
float lowCutHz = 40.0f;
float highCutHz = 14000.0f;
float decaySec = 3.5f;
float sizeVal = 1.0f;
float diffusionVal = 0.6f;
float brightnessVal = 0.75f;
float feedbackVal = 0.6f;
float pitchVal = 0.0f;
float dryWetVal = 0.35f;
float lastWetL = 0.0f;
float lastWetR = 0.0f;
};