mirror of
https://codeberg.org/armin/horizont.git
synced 2026-09-01 12:20:47 +02:00
218 lines
5.5 KiB
C
218 lines
5.5 KiB
C
|
|
#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;
|
||
|
|
};
|