commit ed22f3221686792f2269e5ed600d931b8685e60b
parent 3a0fa09839b4085258974a39eb1fde240cd845a8
Author: Matt Demanett <matt@demanett.net>
Date: Thu, 26 Sep 2019 18:47:15 -0400
Poly: ADDITATOR.
Diffstat:
M | src/Additator.cpp | | | 182 | ++++++++++++++++++++++++++++++++++++++++++++++--------------------------------- |
M | src/Additator.hpp | | | 89 | +++++++++++++++++++++++++++++++++++++++++++------------------------------------ |
2 files changed, 155 insertions(+), 116 deletions(-)
diff --git a/src/Additator.cpp b/src/Additator.cpp
@@ -1,130 +1,149 @@
#include "Additator.hpp"
-void Additator::reset() {
- _syncTrigger.reset();
- _phase = PHASE_RESET;
+void Additator::Engine::reset() {
+ syncTrigger.reset();
+ phase = PHASE_RESET;
}
-void Additator::sampleRateChange() {
+void Additator::Engine::sampleRateChange() {
float sampleRate = APP->engine->getSampleRate();
- _oscillator.setSampleRate(sampleRate);
- _maxFrequency = 0.475f * sampleRate;
- _phase = PHASE_RESET;
- _widthSL.setParams(sampleRate, slewLimitTime, maxWidth);
- _oddSkewSL.setParams(sampleRate, slewLimitTime, 2.0f * maxSkew);
- _evenSkewSL.setParams(sampleRate, slewLimitTime, 2.0f * maxSkew);
- _amplitudeNormalizationSL.setParams(sampleRate, slewLimitTime, maxAmplitudeNormalization - minAmplitudeNormalization);
- _decaySL.setParams(sampleRate, slewLimitTime, maxDecay - minDecay);
- _balanceSL.setParams(sampleRate, slewLimitTime, 2.0f);
- _filterSL.setParams(sampleRate, slewLimitTime, maxFilter - minFilter);
+ oscillator.setSampleRate(sampleRate);
+ maxFrequency = 0.475f * sampleRate;
+ phase = PHASE_RESET;
+ widthSL.setParams(sampleRate, slewLimitTime, maxWidth);
+ oddSkewSL.setParams(sampleRate, slewLimitTime, 2.0f * maxSkew);
+ evenSkewSL.setParams(sampleRate, slewLimitTime, 2.0f * maxSkew);
+ amplitudeNormalizationSL.setParams(sampleRate, slewLimitTime, maxAmplitudeNormalization - minAmplitudeNormalization);
+ decaySL.setParams(sampleRate, slewLimitTime, maxDecay - minDecay);
+ balanceSL.setParams(sampleRate, slewLimitTime, 2.0f);
+ filterSL.setParams(sampleRate, slewLimitTime, maxFilter - minFilter);
}
-float Additator::cvValue(Input& cv, bool dc) {
- if (!cv.isConnected()) {
- return dc ? 1.0f : 0.0f;
+void Additator::reset() {
+ for (int c = 0; c < _channels; ++c) {
+ _engines[c]->reset();
}
- if (dc) {
- return clamp(cv.getVoltage() / 10.0f, 0.0f, 1.0f);
+}
+
+void Additator::sampleRateChange() {
+ for (int c = 0; c < _channels; ++c) {
+ _engines[c]->sampleRateChange();
}
- return clamp(cv.getVoltage() / 5.0f, -1.0f, 1.0f);
}
bool Additator::active() {
return outputs[AUDIO_OUTPUT].isConnected();
}
-void Additator::modulate() {
- float width = _widthSL.next(clamp(params[WIDTH_PARAM].getValue() + (maxWidth / 2.0f) * cvValue(inputs[WIDTH_INPUT]), 0.0f, maxWidth));
- float oddSkew = _oddSkewSL.next(clamp(params[ODD_SKEW_PARAM].getValue() + cvValue(inputs[ODD_SKEW_INPUT]), -maxSkew, maxSkew));
- float evenSkew = _evenSkewSL.next(clamp(params[EVEN_SKEW_PARAM].getValue() + cvValue(inputs[EVEN_SKEW_INPUT]), -maxSkew, maxSkew));
+int Additator::channels() {
+ return std::max(1, inputs[PITCH_INPUT].getChannels());
+}
+
+void Additator::addEngine(int c) {
+ _engines[c] = new Engine();
+ _engines[c]->reset();
+ _engines[c]->sampleRateChange();
+}
+
+void Additator::removeEngine(int c) {
+ delete _engines[c];
+ _engines[c] = NULL;
+}
+
+void Additator::modulateChannel(int c) {
+ Engine& e = *_engines[c];
+
+ float width = e.widthSL.next(clamp(params[WIDTH_PARAM].getValue() + (maxWidth / 2.0f) * cvValue(c, inputs[WIDTH_INPUT]), 0.0f, maxWidth));
+ float oddSkew = e.oddSkewSL.next(clamp(params[ODD_SKEW_PARAM].getValue() + cvValue(c, inputs[ODD_SKEW_INPUT]), -maxSkew, maxSkew));
+ float evenSkew = e.evenSkewSL.next(clamp(params[EVEN_SKEW_PARAM].getValue() + cvValue(c, inputs[EVEN_SKEW_INPUT]), -maxSkew, maxSkew));
if (
- _width != width ||
- _oddSkew != oddSkew ||
- _evenSkew != evenSkew
+ e.width != width ||
+ e.oddSkew != oddSkew ||
+ e.evenSkew != evenSkew
) {
- _width = width;
- _oddSkew = oddSkew;
- _evenSkew = evenSkew;
+ e.width = width;
+ e.oddSkew = oddSkew;
+ e.evenSkew = evenSkew;
float multiple = 1.0f;
- _oscillator.setPartialFrequencyRatio(1, multiple);
- _activePartials = 1;
- for (int i = 2, n = _oscillator.partialCount(); i <= n; ++i) {
+ e.oscillator.setPartialFrequencyRatio(1, multiple);
+ e.activePartials = 1;
+ for (int i = 2, n = e.oscillator.partialCount(); i <= n; ++i) {
float ii = i;
if (i % 2 == 0) {
- ii += _evenSkew;
+ ii += e.evenSkew;
}
else {
- ii += _oddSkew;
+ ii += e.oddSkew;
}
- if (_oscillator.setPartialFrequencyRatio(i, powf(ii, _width))) {
- _activePartials = i;
+ if (e.oscillator.setPartialFrequencyRatio(i, powf(ii, e.width))) {
+ e.activePartials = i;
}
}
}
- int partials = clamp((int)roundf(params[PARTIALS_PARAM].getValue() * cvValue(inputs[PARTIALS_INPUT], true)), 0, maxPartials);
- float amplitudeNormalization = _amplitudeNormalizationSL.next(clamp(params[GAIN_PARAM].getValue() + ((maxAmplitudeNormalization - minAmplitudeNormalization) / 2.0f) * cvValue(inputs[GAIN_INPUT]), minAmplitudeNormalization, maxAmplitudeNormalization));
- float decay = _decaySL.next(clamp(params[DECAY_PARAM].getValue() + ((maxDecay - minDecay) / 2.0f) * cvValue(inputs[DECAY_INPUT]), minDecay, maxDecay));
- float balance = _balanceSL.next(clamp(params[BALANCE_PARAM].getValue() + cvValue(inputs[BALANCE_INPUT]), -1.0f, 1.0f));
- float filter = _filterSL.next(clamp(params[FILTER_PARAM].getValue() + cvValue(inputs[FILTER_INPUT]), minFilter, maxFilter));
+ int partials = clamp((int)roundf(params[PARTIALS_PARAM].getValue() * cvValue(c, inputs[PARTIALS_INPUT], true)), 0, maxPartials);
+ float amplitudeNormalization = e.amplitudeNormalizationSL.next(clamp(params[GAIN_PARAM].getValue() + ((maxAmplitudeNormalization - minAmplitudeNormalization) / 2.0f) * cvValue(c, inputs[GAIN_INPUT]), minAmplitudeNormalization, maxAmplitudeNormalization));
+ float decay = e.decaySL.next(clamp(params[DECAY_PARAM].getValue() + ((maxDecay - minDecay) / 2.0f) * cvValue(c, inputs[DECAY_INPUT]), minDecay, maxDecay));
+ float balance = e.balanceSL.next(clamp(params[BALANCE_PARAM].getValue() + cvValue(c, inputs[BALANCE_INPUT]), -1.0f, 1.0f));
+ float filter = e.filterSL.next(clamp(params[FILTER_PARAM].getValue() + cvValue(c, inputs[FILTER_INPUT]), minFilter, maxFilter));
if (
- _partials != partials ||
- _amplitudeNormalization != amplitudeNormalization ||
- _decay != decay ||
- _balance != balance ||
- _filter != filter
+ e.partials != partials ||
+ e.amplitudeNormalization != amplitudeNormalization ||
+ e.decay != decay ||
+ e.balance != balance ||
+ e.filter != filter
) {
- int envelopes = _partials != partials ? std::max(_partials, partials) : 0;
- _partials = partials;
- _amplitudeNormalization = amplitudeNormalization;
- _decay = decay;
- _balance = balance;
- _filter = filter;
+ int envelopes = e.partials != partials ? std::max(e.partials, partials) : 0;
+ e.partials = partials;
+ e.amplitudeNormalization = amplitudeNormalization;
+ e.decay = decay;
+ e.balance = balance;
+ e.filter = filter;
float as[maxPartials + 1];
float total = as[1] = 1.0f;
- filter = log10f(_filter) + 1.0f;
- int np = std::min(_partials, _activePartials);
- for (int i = 2, n = _oscillator.partialCount(); i <= n; ++i) {
+ filter = log10f(e.filter) + 1.0f;
+ int np = std::min(e.partials, e.activePartials);
+ for (int i = 2, n = e.oscillator.partialCount(); i <= n; ++i) {
as[i] = 0.0f;
if (i <= np) {
- as[i] = powf(i, -_decay) * powf(_filter, i);
+ as[i] = powf(i, -e.decay) * powf(e.filter, i);
if (i % 2 == 0) {
- if (_balance > 0.0f) {
- as[i] *= 1.0f - _balance;
+ if (e.balance > 0.0f) {
+ as[i] *= 1.0f - e.balance;
}
}
else {
- if (_balance < 0.0f) {
- as[i] *= 1.0f + _balance;
+ if (e.balance < 0.0f) {
+ as[i] *= 1.0f + e.balance;
}
}
total += as[i];
}
}
- float norm = std::max(np / (float)_oscillator.partialCount(), 0.1f);
- norm = 1.0f + (_amplitudeNormalization - 1.0f) * norm;
+ float norm = std::max(np / (float)e.oscillator.partialCount(), 0.1f);
+ norm = 1.0f + (e.amplitudeNormalization - 1.0f) * norm;
norm = std::max(total / norm, 0.7f);
- for (int i = 1, n = _oscillator.partialCount(); i <= n; ++i) {
+ for (int i = 1, n = e.oscillator.partialCount(); i <= n; ++i) {
as[i] /= norm;
- _oscillator.setPartialAmplitude(i, as[i], i <= envelopes);
+ e.oscillator.setPartialAmplitude(i, as[i], i <= envelopes);
}
}
float frequency = params[FREQUENCY_PARAM].getValue();
frequency += params[FINE_PARAM].getValue() / 12.0f;;
if (inputs[PITCH_INPUT].isConnected()) {
- frequency += clamp(inputs[PITCH_INPUT].getVoltage(), -5.0f, 5.0f);
+ frequency += clamp(inputs[PITCH_INPUT].getVoltage(c), -5.0f, 5.0f);
}
- frequency = clamp(cvToFrequency(frequency), 20.0f, _maxFrequency);
- _oscillator.setFrequency(frequency);
+ frequency = clamp(cvToFrequency(frequency), 20.0f, e.maxFrequency);
+ e.oscillator.setFrequency(frequency);
Phase phase = params[PHASE_PARAM].getValue() > 1.5f ? PHASE_COSINE : PHASE_SINE;
- if (_phase != phase) {
- _phase = phase;
- _oscillator.syncToPhase(_phase == PHASE_SINE ? 0.0f : M_PI / 2.0f);
+ if (e.phase != phase) {
+ e.phase = phase;
+ e.oscillator.syncToPhase(e.phase == PHASE_SINE ? 0.0f : M_PI / 2.0f);
}
}
@@ -134,11 +153,24 @@ void Additator::always(const ProcessArgs& args) {
lights[COSINE_LIGHT].value = phase == PHASE_COSINE;
}
-void Additator::processChannel(const ProcessArgs& args, int _c) {
- if (_syncTrigger.next(inputs[SYNC_INPUT].getVoltage())) {
- _oscillator.syncToPhase(_phase == PHASE_SINE ? 0.0f : M_PI / 2.0f);
+void Additator::processChannel(const ProcessArgs& args, int c) {
+ Engine& e = *_engines[c];
+
+ if (e.syncTrigger.next(inputs[SYNC_INPUT].getPolyVoltage(c))) {
+ e.oscillator.syncToPhase(e.phase == PHASE_SINE ? 0.0f : M_PI / 2.0f);
+ }
+ outputs[AUDIO_OUTPUT].setChannels(_channels);
+ outputs[AUDIO_OUTPUT].setVoltage(e.oscillator.next() * 5.0, c);
+}
+
+float Additator::cvValue(int c, Input& cv, bool dc) {
+ if (!cv.isConnected()) {
+ return dc ? 1.0f : 0.0f;
+ }
+ if (dc) {
+ return clamp(cv.getPolyVoltage(c) / 10.0f, 0.0f, 1.0f);
}
- outputs[AUDIO_OUTPUT].setVoltage(_oscillator.next() * 5.0);
+ return clamp(cv.getPolyVoltage(c) / 5.0f, -1.0f, 1.0f);
}
struct AdditatorWidget : ModuleWidget {
diff --git a/src/Additator.hpp b/src/Additator.hpp
@@ -58,41 +58,48 @@ struct Additator : BGModule {
PHASE_COSINE
};
- const int maxPartials = 100;
- const float maxWidth = 2.0f;
- const float maxSkew = 0.99f;
- const float minAmplitudeNormalization = 1.0f;
- const float maxAmplitudeNormalization = 5.0f;
- const float minDecay = -1.0f;
- const float maxDecay = 3.0f;
- const float minFilter = 0.1;
- const float maxFilter = 1.9;
- const float slewLimitTime = 1.0f;
-
- int _partials = 0;
- float _width = 0.0f;
- float _oddSkew = 0.0f;
- float _evenSkew = 0.0f;
- float _amplitudeNormalization = 0.0f;
- float _decay = 0.0f;
- float _balance = 0.0f;
- float _filter = 0.0f;
- Phase _phase = PHASE_RESET;
- float _maxFrequency = 0.0f;
- int _activePartials = 1;
- SineBankOscillator _oscillator;
- PositiveZeroCrossing _syncTrigger;
- bogaudio::dsp::SlewLimiter _widthSL;
- bogaudio::dsp::SlewLimiter _oddSkewSL;
- bogaudio::dsp::SlewLimiter _evenSkewSL;
- bogaudio::dsp::SlewLimiter _amplitudeNormalizationSL;
- bogaudio::dsp::SlewLimiter _decaySL;
- bogaudio::dsp::SlewLimiter _balanceSL;
- bogaudio::dsp::SlewLimiter _filterSL;
-
- Additator()
- : _oscillator(1000.0f, 100.0f, maxPartials)
- {
+ static constexpr int maxPartials = 100;
+ static constexpr float maxWidth = 2.0f;
+ static constexpr float maxSkew = 0.99f;
+ static constexpr float minAmplitudeNormalization = 1.0f;
+ static constexpr float maxAmplitudeNormalization = 5.0f;
+ static constexpr float minDecay = -1.0f;
+ static constexpr float maxDecay = 3.0f;
+ static constexpr float minFilter = 0.1;
+ static constexpr float maxFilter = 1.9;
+ static constexpr float slewLimitTime = 1.0f;
+
+ struct Engine {
+ int partials = 0;
+ float width = 0.0f;
+ float oddSkew = 0.0f;
+ float evenSkew = 0.0f;
+ float amplitudeNormalization = 0.0f;
+ float decay = 0.0f;
+ float balance = 0.0f;
+ float filter = 0.0f;
+ Phase phase = PHASE_RESET;
+ float maxFrequency = 0.0f;
+ int activePartials = 1;
+ SineBankOscillator oscillator;
+ PositiveZeroCrossing syncTrigger;
+ bogaudio::dsp::SlewLimiter widthSL;
+ bogaudio::dsp::SlewLimiter oddSkewSL;
+ bogaudio::dsp::SlewLimiter evenSkewSL;
+ bogaudio::dsp::SlewLimiter amplitudeNormalizationSL;
+ bogaudio::dsp::SlewLimiter decaySL;
+ bogaudio::dsp::SlewLimiter balanceSL;
+ bogaudio::dsp::SlewLimiter filterSL;
+
+ Engine() : oscillator(1000.0f, 100.0f, maxPartials) {}
+
+ void reset();
+ void sampleRateChange();
+ };
+
+ Engine* _engines[maxChannels] {};
+
+ Additator() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
configParam<FrequencyParamQuantity>(FREQUENCY_PARAM, -3.0f, 6.0f, 0.0f, "Frequency", " Hz");
configParam(PARTIALS_PARAM, 1.0f, Additator::maxPartials, Additator::maxPartials / 5.0f, "Partials");
@@ -105,18 +112,18 @@ struct Additator : BGModule {
configParam(BALANCE_PARAM, -1.0f, 1.0f, 0.0f, "Balance", "%", 0.0f, 100.0f);
configParam(FILTER_PARAM, minFilter, maxFilter, (maxFilter - minFilter) / 2.0 + minFilter, "Filter");
configParam(PHASE_PARAM, 1.0f, 2.0f, 1.0f, "Phase");
-
- reset();
- sampleRateChange();
}
void reset() override;
void sampleRateChange() override;
bool active() override;
- void modulate() override;
- float cvValue(Input& cv, bool dc = false);
+ int channels() override;
+ void addEngine(int c) override;
+ void removeEngine(int c) override;
+ void modulateChannel(int c) override;
void always(const ProcessArgs& args) override;
- void processChannel(const ProcessArgs& args, int _c) override;
+ void processChannel(const ProcessArgs& args, int c) override;
+ float cvValue(int c, Input& cv, bool dc = false);
};
} // namespace bogaudio