Browse Source

std::log2 etc aren't constexpr in C++11. Treating them as such breaks that Mac build. Move to namespace-level `static const`.

tags/v1.4.0
Andrew Belt 5 years ago
parent
commit
4056917d94
2 changed files with 98 additions and 92 deletions
  1. +5
    -5
      src/Ripples.cpp
  2. +93
    -87
      src/Ripples/ripples.hpp

+ 5
- 5
src/Ripples.cpp View File

@@ -28,12 +28,12 @@ struct Ripples : Module {
NUM_LIGHTS
};

RipplesEngine engines[16];
ripples::RipplesEngine engines[16];

Ripples() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
configParam(RES_PARAM, 0.f, 1.f, 0.f, "Resonance", "%", 0, 100);
configParam(FREQ_PARAM, std::log2(RipplesEngine::kFreqKnobMin), std::log2(RipplesEngine::kFreqKnobMax), std::log2(RipplesEngine::kFreqKnobMax), "Frequency", " Hz", 2.f);
configParam(FREQ_PARAM, std::log2(ripples::kFreqKnobMin), std::log2(ripples::kFreqKnobMax), std::log2(ripples::kFreqKnobMax), "Frequency", " Hz", 2.f);
configParam(FM_PARAM, -1.f, 1.f, 0.f, "Frequency modulation", "%", 0, 100);

onSampleRateChange();
@@ -54,9 +54,9 @@ struct Ripples : Module {
int channels = std::max(inputs[IN_INPUT].getChannels(), 1);

// Reuse the same frame object for multiple engines because the params aren't touched.
RipplesEngine::Frame frame;
ripples::RipplesEngine::Frame frame;
frame.res_knob = params[RES_PARAM].getValue();
frame.freq_knob = rescale(params[FREQ_PARAM].getValue(), std::log2(RipplesEngine::kFreqKnobMin), std::log2(RipplesEngine::kFreqKnobMax), 0.f, 1.f);
frame.freq_knob = rescale(params[FREQ_PARAM].getValue(), std::log2(ripples::kFreqKnobMin), std::log2(ripples::kFreqKnobMax), 0.f, 1.f);
frame.fm_knob = params[FM_PARAM].getValue();
frame.gain_cv_present = inputs[GAIN_INPUT].isConnected();

@@ -72,7 +72,7 @@ struct Ripples : Module {
// Although rare, using extreme parameters, I've been able to produce nonfinite floats with the filter model, so detect them and reset the state.
if (!std::isfinite(frame.bp2)) {
// A reset() method would be nice, but we can just reinitialize it.
engines[c] = RipplesEngine();
engines[c] = ripples::RipplesEngine();
engines[c].setSampleRate(args.sampleRate);
}
else {


+ 93
- 87
src/Ripples/ripples.hpp View File

@@ -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;
}
};

}

Loading…
Cancel
Save