|
|
@@ -22,6 +22,93 @@ |
|
|
|
|
|
|
|
using namespace rack; |
|
|
|
|
|
|
|
namespace ripples |
|
|
|
{ |
|
|
|
|
|
|
|
// Frequency knob |
|
|
|
static const float kFreqKnobMin = 20.f; |
|
|
|
static const float kFreqKnobMax = 20000.f; |
|
|
|
static const float kFreqKnobVoltage = |
|
|
|
std::log2f(kFreqKnobMax / kFreqKnobMin); |
|
|
|
|
|
|
|
// Calculate base and multiplier values to pass to configParam so that the |
|
|
|
// knob value is labeled in Hz. |
|
|
|
// Model the knob as a generic V/oct input with 100k input impedance. |
|
|
|
// Assume the internal knob voltage `v` is on the interval [0, vmax] and |
|
|
|
// let `p` be the position of the knob varying linearly along [0, 1]. Then, |
|
|
|
// freq = fmin * 2^v |
|
|
|
// v = vmax * p |
|
|
|
// vmax = log2(fmax / fmin) |
|
|
|
// freq = fmin * 2^(log2(fmax / fmin) * p) |
|
|
|
// = fmin * (fmax / fmin)^p |
|
|
|
static const float kFreqKnobDisplayBase = kFreqKnobMax / kFreqKnobMin; |
|
|
|
static const float kFreqKnobDisplayMultiplier = kFreqKnobMin; |
|
|
|
|
|
|
|
// Frequency CV amplifier |
|
|
|
// The 2164's gain constant is -33mV/dB. Multiply by 6dB/1V to find the |
|
|
|
// nominal gain of the amplifier. |
|
|
|
static const float kVCAGainConstant = -33e-3f; |
|
|
|
static const float kPlus6dB = 20.f * std::log10(2.f); |
|
|
|
static const float kFreqAmpGain = kVCAGainConstant * kPlus6dB; |
|
|
|
static const float kFreqInputR = 100e3f; |
|
|
|
static const float kFreqAmpR = -kFreqAmpGain * kFreqInputR; |
|
|
|
static const float kFreqAmpC = 560e-12f; |
|
|
|
|
|
|
|
// Resonance CV amplifier |
|
|
|
static const float kResInputR = 22e3f; |
|
|
|
static const float kResKnobV = 12.f; |
|
|
|
static const float kResKnobR = 62e3f; |
|
|
|
static const float kResAmpR = 47e3f; |
|
|
|
static const float kResAmpC = 560e-12f; |
|
|
|
|
|
|
|
// Gain CV amplifier |
|
|
|
static const float kGainInputR = 27e3f; |
|
|
|
static const float kGainNormalV = 12.f; |
|
|
|
static const float kGainNormalR = 15e3f; |
|
|
|
static const float kGainAmpR = 47e3f; |
|
|
|
static const float kGainAmpC = 560e-12f; |
|
|
|
|
|
|
|
// Filter core |
|
|
|
static const float kFilterMaxCutoff = kFreqKnobMax; |
|
|
|
static const float kFilterCellR = 33e3f; |
|
|
|
static const float kFilterCellRC = |
|
|
|
1.f / (2.f * M_PI * kFilterMaxCutoff); |
|
|
|
static const float kFilterCellC = kFilterCellRC / kFilterCellR; |
|
|
|
static const float kFilterInputR = 100e3f; |
|
|
|
static const float kFilterInputGain = kFilterCellR / kFilterInputR; |
|
|
|
static const float kFilterCellSelfModulation = 0.01f; |
|
|
|
|
|
|
|
// Filter core feedback path |
|
|
|
static const float kFeedbackRt = 22e3f; |
|
|
|
static const float kFeedbackRb = 1e3f; |
|
|
|
static const float kFeedbackR = kFeedbackRt + kFeedbackRb; |
|
|
|
static const float kFeedbackGain = kFeedbackRb / kFeedbackR; |
|
|
|
|
|
|
|
// Filter core feedforward path |
|
|
|
static const float kFeedforwardRt = 300e3f; |
|
|
|
static const float kFeedforwardRb = 1e3f; |
|
|
|
static const float kFeedforwardR = kFeedforwardRt + kFeedforwardRb; |
|
|
|
static const float kFeedforwardGain = kFeedforwardRb / kFeedforwardR; |
|
|
|
static const float kFeedforwardC = 220e-9f; |
|
|
|
|
|
|
|
// Filter output amplifiers |
|
|
|
static const float kLP2Gain = -100e3f / 39e3f; |
|
|
|
static const float kLP4Gain = -100e3f / 33e3f; |
|
|
|
static const float kBP2Gain = -100e3f / 39e3f; |
|
|
|
|
|
|
|
// VCA |
|
|
|
static const float kVCAInputC = 4.7e-6f; |
|
|
|
static const float kVCAInputRt = 100e3f; |
|
|
|
static const float kVCAInputRb = 1e3f; |
|
|
|
static const float kVCAInputR = kVCAInputRt + kVCAInputRb; |
|
|
|
static const float kVCAInputGain = kVCAInputRb / kVCAInputR; |
|
|
|
static const float kVCAOutputR = 100e3f; |
|
|
|
|
|
|
|
// Voltage-to-current converters |
|
|
|
// Saturation voltage at BJT collector |
|
|
|
static const float kVtoICollectorVSat = -10.f; |
|
|
|
|
|
|
|
|
|
|
|
class RipplesEngine |
|
|
|
{ |
|
|
|
public: |
|
|
@@ -47,89 +134,6 @@ public: |
|
|
|
float lp4vca; |
|
|
|
}; |
|
|
|
|
|
|
|
// Frequency knob |
|
|
|
static constexpr float kFreqKnobMin = 20.f; |
|
|
|
static constexpr float kFreqKnobMax = 20000.f; |
|
|
|
static constexpr float kFreqKnobVoltage = |
|
|
|
std::log2f(kFreqKnobMax / kFreqKnobMin); |
|
|
|
|
|
|
|
// Calculate base and multiplier values to pass to configParam so that the |
|
|
|
// knob value is labeled in Hz. |
|
|
|
// Model the knob as a generic V/oct input with 100k input impedance. |
|
|
|
// Assume the internal knob voltage `v` is on the interval [0, vmax] and |
|
|
|
// let `p` be the position of the knob varying linearly along [0, 1]. Then, |
|
|
|
// freq = fmin * 2^v |
|
|
|
// v = vmax * p |
|
|
|
// vmax = log2(fmax / fmin) |
|
|
|
// freq = fmin * 2^(log2(fmax / fmin) * p) |
|
|
|
// = fmin * (fmax / fmin)^p |
|
|
|
static constexpr float kFreqKnobDisplayBase = kFreqKnobMax / kFreqKnobMin; |
|
|
|
static constexpr float kFreqKnobDisplayMultiplier = kFreqKnobMin; |
|
|
|
|
|
|
|
// Frequency CV amplifier |
|
|
|
// The 2164's gain constant is -33mV/dB. Multiply by 6dB/1V to find the |
|
|
|
// nominal gain of the amplifier. |
|
|
|
static constexpr float kVCAGainConstant = -33e-3f; |
|
|
|
static constexpr float kPlus6dB = 20.f * std::log10(2.f); |
|
|
|
static constexpr float kFreqAmpGain = kVCAGainConstant * kPlus6dB; |
|
|
|
static constexpr float kFreqInputR = 100e3f; |
|
|
|
static constexpr float kFreqAmpR = -kFreqAmpGain * kFreqInputR; |
|
|
|
static constexpr float kFreqAmpC = 560e-12f; |
|
|
|
|
|
|
|
// Resonance CV amplifier |
|
|
|
static constexpr float kResInputR = 22e3f; |
|
|
|
static constexpr float kResKnobV = 12.f; |
|
|
|
static constexpr float kResKnobR = 62e3f; |
|
|
|
static constexpr float kResAmpR = 47e3f; |
|
|
|
static constexpr float kResAmpC = 560e-12f; |
|
|
|
|
|
|
|
// Gain CV amplifier |
|
|
|
static constexpr float kGainInputR = 27e3f; |
|
|
|
static constexpr float kGainNormalV = 12.f; |
|
|
|
static constexpr float kGainNormalR = 15e3f; |
|
|
|
static constexpr float kGainAmpR = 47e3f; |
|
|
|
static constexpr float kGainAmpC = 560e-12f; |
|
|
|
|
|
|
|
// Filter core |
|
|
|
static constexpr float kFilterMaxCutoff = kFreqKnobMax; |
|
|
|
static constexpr float kFilterCellR = 33e3f; |
|
|
|
static constexpr float kFilterCellRC = |
|
|
|
1.f / (2.f * M_PI * kFilterMaxCutoff); |
|
|
|
static constexpr float kFilterCellC = kFilterCellRC / kFilterCellR; |
|
|
|
static constexpr float kFilterInputR = 100e3f; |
|
|
|
static constexpr float kFilterInputGain = kFilterCellR / kFilterInputR; |
|
|
|
static constexpr float kFilterCellSelfModulation = 0.01f; |
|
|
|
|
|
|
|
// Filter core feedback path |
|
|
|
static constexpr float kFeedbackRt = 22e3f; |
|
|
|
static constexpr float kFeedbackRb = 1e3f; |
|
|
|
static constexpr float kFeedbackR = kFeedbackRt + kFeedbackRb; |
|
|
|
static constexpr float kFeedbackGain = kFeedbackRb / kFeedbackR; |
|
|
|
|
|
|
|
// Filter core feedforward path |
|
|
|
static constexpr float kFeedforwardRt = 300e3f; |
|
|
|
static constexpr float kFeedforwardRb = 1e3f; |
|
|
|
static constexpr float kFeedforwardR = kFeedforwardRt + kFeedforwardRb; |
|
|
|
static constexpr float kFeedforwardGain = kFeedforwardRb / kFeedforwardR; |
|
|
|
static constexpr float kFeedforwardC = 220e-9f; |
|
|
|
|
|
|
|
// Filter output amplifiers |
|
|
|
static constexpr float kLP2Gain = -100e3f / 39e3f; |
|
|
|
static constexpr float kLP4Gain = -100e3f / 33e3f; |
|
|
|
static constexpr float kBP2Gain = -100e3f / 39e3f; |
|
|
|
|
|
|
|
// VCA |
|
|
|
static constexpr float kVCAInputC = 4.7e-6f; |
|
|
|
static constexpr float kVCAInputRt = 100e3f; |
|
|
|
static constexpr float kVCAInputRb = 1e3f; |
|
|
|
static constexpr float kVCAInputR = kVCAInputRt + kVCAInputRb; |
|
|
|
static constexpr float kVCAInputGain = kVCAInputRb / kVCAInputR; |
|
|
|
static constexpr float kVCAOutputR = 100e3f; |
|
|
|
|
|
|
|
// Voltage-to-current converters |
|
|
|
// Saturation voltage at BJT collector |
|
|
|
static constexpr float kVtoICollectorVSat = -10.f; |
|
|
|
|
|
|
|
RipplesEngine() |
|
|
|
{ |
|
|
|
setSampleRate(1.f); |
|
|
@@ -337,10 +341,10 @@ protected: |
|
|
|
// or equivalently, |
|
|
|
// i_out = i_abc * tanh(vi / (2vt)) |
|
|
|
|
|
|
|
constexpr float kTemperature = 40.f; // Silicon temperature in Celsius |
|
|
|
constexpr float kKoverQ = 8.617333262145e-5; |
|
|
|
constexpr float kKelvin = 273.15f; // 0C in K |
|
|
|
constexpr float kVt = kKoverQ * (kTemperature + kKelvin); |
|
|
|
const float kTemperature = 40.f; // Silicon temperature in Celsius |
|
|
|
const float kKoverQ = 8.617333262145e-5; |
|
|
|
const float kKelvin = 273.15f; // 0C in K |
|
|
|
const float kVt = kKoverQ * (kTemperature + kKelvin); |
|
|
|
|
|
|
|
T vi = vp - vn; |
|
|
|
T z = vi / (2 * kVt); |
|
|
@@ -353,3 +357,5 @@ protected: |
|
|
|
return i_abc * p; |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
} |