commit 28c7763e6deb296bb373ab87f03ff04171b70176
parent de4d71f50145de05dc07a86b3d05afb8e78602ae
Author: Matt Demanett <matt@demanett.net>
Date: Sun, 10 Jun 2018 17:26:54 -0400
Performance improvements; some slew limit fixes; etc fixes.
Diffstat:
18 files changed, 165 insertions(+), 70 deletions(-)
diff --git a/Makefile b/Makefile
@@ -28,7 +28,7 @@ BENCHMARK_OBJECTS = $(patsubst %, build/%.o, $(BENCHMARK_SOURCES))
BENCHMARK_DEPS = $(patsubst %, build/%.d, $(BENCHMARK_SOURCES))
-include $(BENCHMARK_DEPS)
benchmark: $(BENCHMARK_OBJECTS)
- $(CXX) -o $@ $^ ../../build/src/util.cpp.o -lbenchmark -lpthread
+ $(CXX) -o $@ $^ -lbenchmark -lpthread
benchmark_clean:
rm -f benchmark $(BENCHMARK_OBJECTS)
diff --git a/src/Detune.cpp b/src/Detune.cpp
@@ -8,35 +8,33 @@ void Detune::step() {
float cents = params[CENTS_PARAM].value;
if (inputs[CV_INPUT].active) {
- cents *= clamp(inputs[CV_INPUT].value, 0.0f, 10.0f) / 10.0;
+ cents *= clamp(inputs[CV_INPUT].value / 10.0f, 0.0f, 1.0f);
cents = roundf(cents);
}
- cents /= 100.0;
+ cents /= 100.0f;
+ float inCV = 0.0f;
if (inputs[IN_INPUT].active) {
- float cv = inputs[IN_INPUT].value;
- outputs[THRU_OUTPUT].value = cv;
- if (cents < 0.001) {
- outputs[OUT_PLUS_OUTPUT].value = cv;
- outputs[OUT_MINUS_OUTPUT].value = cv;
- }
- else {
- float semitone = cvToSemitone(cv);
- outputs[OUT_PLUS_OUTPUT].value = semitoneToCV(semitone + cents);
- outputs[OUT_MINUS_OUTPUT].value = semitoneToCV(semitone - cents);
- }
+ inCV = inputs[IN_INPUT].value;
}
- else {
- outputs[THRU_OUTPUT].value = 0.0;
- if (cents < 0.001) {
- outputs[OUT_PLUS_OUTPUT].value = 0.0;
- outputs[OUT_MINUS_OUTPUT].value = 0.0;
+
+ if (_cents != cents || _inCV != inCV) {
+ _cents = cents;
+ _inCV = inCV;
+ if (_cents < 0.001f) {
+ _plusCV = _inCV;
+ _minusCV = _inCV;
}
else {
- outputs[OUT_PLUS_OUTPUT].value = semitoneToCV(referenceSemitone + cents);
- outputs[OUT_MINUS_OUTPUT].value = semitoneToCV(referenceSemitone - cents);
+ float semitone = cvToSemitone(_inCV);
+ _plusCV = semitoneToCV(semitone + cents);
+ _minusCV = semitoneToCV(semitone - cents);
}
}
+
+ outputs[THRU_OUTPUT].value = _inCV;
+ outputs[OUT_PLUS_OUTPUT].value = _plusCV;
+ outputs[OUT_MINUS_OUTPUT].value = _minusCV;
}
struct DetuneWidget : ModuleWidget {
diff --git a/src/Detune.hpp b/src/Detune.hpp
@@ -32,6 +32,11 @@ struct Detune : Module {
NUM_LIGHTS
};
+ float _cents = -1.0f;
+ float _inCV = -1000.0f;
+ float _plusCV;
+ float _minusCV;
+
Detune() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
}
diff --git a/src/FMOp.cpp b/src/FMOp.cpp
@@ -15,7 +15,6 @@ void FMOp::onSampleRateChange() {
float sampleRate = engineGetSampleRate();
_envelope.setSampleRate(sampleRate);
_phasor.setSampleRate(sampleRate);
- _sineTable.setSampleRate(sampleRate);
_decimator.setParams(sampleRate, oversample);
_maxFrequency = 0.475f * sampleRate;
_feedbackSL.setParams(sampleRate, slewLimitTime);
@@ -127,11 +126,18 @@ void FMOp::step() {
if (_feedbackEnvelopeOn) {
feedback *= envelope;
}
+ bool feedbackOn = feedback > 0.001f;
+
+ float out = _levelSL.next(_level);
+ if (_levelEnvelopeOn) {
+ out *= envelope;
+ }
float offset = 0.0f;
- if (feedback > 0.001f) {
+ if (feedbackOn) {
offset = feedback * _feedbackDelayedSample;
}
+
if (inputs[FM_INPUT].active) {
float depth = _depthSL.next(_depth);
if (_depthEnvelopeOn) {
@@ -139,23 +145,47 @@ void FMOp::step() {
}
offset += inputs[FM_INPUT].value * depth * 2.0f;
}
- for (int i = 0; i < oversample; ++i) {
- _phasor.advancePhase();
- _buffer[i] = _sineTable.nextFromPhasor(_phasor, Phasor::radiansToPhase(offset));
- }
- float out = _levelSL.next(_level);
- if (_levelEnvelopeOn) {
- out *= envelope;
- }
- if (_linearLevel) {
- out *= _decimator.next(_buffer);
+
+ float sample = 0.0f;
+ if (out > 0.0001f) {
+ Phasor::phase_delta_t o = offset > 0.0f ? Phasor::radiansToPhase(offset) : 0;
+ if (feedbackOn) {
+ if (_oversampleMix < 1.0f) {
+ _oversampleMix += oversampleMixIncrement;
+ }
+ }
+ else if (_oversampleMix > 0.0f) {
+ _oversampleMix -= oversampleMixIncrement;
+ }
+
+ if (_oversampleMix > 0.0f) {
+ for (int i = 0; i < oversample; ++i) {
+ _phasor.advancePhase();
+ _buffer[i] = _sineTable.nextFromPhasor(_phasor, o);
+ }
+ sample = _oversampleMix * _decimator.next(_buffer);
+ }
+ else {
+ _phasor.advancePhase(oversample);
+ }
+ if (_oversampleMix < 1.0f) {
+ sample += (1.0f - _oversampleMix) * _sineTable.nextFromPhasor(_phasor, o);
+ }
+
+ if (_linearLevel) {
+ sample *= out;
+ }
+ else {
+ out = (1.0f - out) * Amplifier::minDecibels;
+ _amplifier.setLevel(out);
+ sample = _amplifier.next(sample);
+ }
}
else {
- out = (1.0f - out) * Amplifier::minDecibels;
- _amplifier.setLevel(out);
- out = _amplifier.next(_decimator.next(_buffer));
+ _phasor.advancePhase(oversample);
}
- outputs[AUDIO_OUTPUT].value = _feedbackDelayedSample = amplitude * out;
+
+ outputs[AUDIO_OUTPUT].value = _feedbackDelayedSample = amplitude * sample;
}
struct LinearLevelMenuItem : MenuItem {
diff --git a/src/FMOp.hpp b/src/FMOp.hpp
@@ -56,6 +56,7 @@ struct FMOp : Module {
const int modulationSteps = 100;
static constexpr int oversample = 8;
const float slewLimitTime = 1.0f;
+ const float oversampleMixIncrement = 0.01f;
int _steps = 0;
float _feedback = 0.0f;
float _feedbackDelayedSample = 0.0f;
@@ -67,10 +68,11 @@ struct FMOp : Module {
bool _depthEnvelopeOn = false;
float _maxFrequency = 0.0f;
float _buffer[oversample];
+ float _oversampleMix = 0.0f;
ADSR _envelope;
Phasor _phasor;
SineTableOscillator _sineTable;
- LPFDecimator _decimator;
+ CICDecimator _decimator;
SchmittTrigger _gateTrigger;
SlewLimiter _feedbackSL;
SlewLimiter _depthSL;
diff --git a/src/Pan.cpp b/src/Pan.cpp
@@ -2,8 +2,8 @@
#include "Pan.hpp"
void Pan::onSampleRateChange() {
- _slew1.setParams(engineGetSampleRate(), 2.0f);
- _slew2.setParams(engineGetSampleRate(), 2.0f);
+ _slew1.setParams(engineGetSampleRate(), 100.0f);
+ _slew2.setParams(engineGetSampleRate(), 100.0f);
}
void Pan::step() {
diff --git a/src/Reftone.cpp b/src/Reftone.cpp
@@ -6,13 +6,20 @@ void Reftone::step() {
const int referencePitch = 0;
const int referenceOctave = 4;
- _pitch = params[PITCH_PARAM].value;
- _octave = params[OCTAVE_PARAM].value;
- _fine = params[FINE_PARAM].value;
- _frequency = semitoneToFrequency(referenceSemitone + 12*(_octave - referenceOctave) + (_pitch - referencePitch) + _fine);
+ if (!(
+ _pitch == params[PITCH_PARAM].value &&
+ _octave == params[OCTAVE_PARAM].value &&
+ _fine == params[FINE_PARAM].value
+ )) {
+ _pitch = params[PITCH_PARAM].value;
+ _octave = params[OCTAVE_PARAM].value;
+ _fine = params[FINE_PARAM].value;
+ _frequency = semitoneToFrequency(referenceSemitone + 12*(_octave - referenceOctave) + (_pitch - referencePitch) + _fine);
+ _cv = frequencyToCV(_frequency);
+ }
if (outputs[CV_OUTPUT].active) {
- outputs[CV_OUTPUT].value = frequencyToCV(_frequency);
+ outputs[CV_OUTPUT].value = _cv;
}
else {
outputs[CV_OUTPUT].value = 0.0;
@@ -172,7 +179,6 @@ float ReftoneDisplay::textRenderWidth(NVGcontext* vg, const char* s, int size) {
return strlen(s) * (size / 2.1);
}
-
struct ReftoneWidget : ModuleWidget {
ReftoneWidget(Reftone* module) : ModuleWidget(module) {
box.size = Vec(RACK_GRID_WIDTH * 3, RACK_GRID_HEIGHT);
diff --git a/src/Reftone.hpp b/src/Reftone.hpp
@@ -34,8 +34,9 @@ struct Reftone : Module {
int _pitch = 9;
int _octave = 4;
- float _fine = 0.0;
- float _frequency = 440.0;
+ float _fine = 0.0f;
+ float _frequency = 440.0f;
+ float _cv = frequencyToCV(_frequency);
SineOscillator _sine;
Reftone() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
diff --git a/src/Stack.cpp b/src/Stack.cpp
@@ -16,15 +16,27 @@ void Stack::step() {
semitones = roundf(semitones);
}
+ float inCV = 0.0f;
if (inputs[IN_INPUT].active) {
- float cv = clamp(inputs[IN_INPUT].value, _minCVOut, _maxCVOut);
- outputs[THRU_OUTPUT].value = cv;
- outputs[OUT_OUTPUT].value = clamp(semitoneToCV(cvToSemitone(cv) + semitones + params[FINE_PARAM].value), _minCVOut, _maxCVOut);
+ inCV = clamp(inputs[IN_INPUT].value, _minCVOut, _maxCVOut);
+ }
+
+ float fine = params[FINE_PARAM].value;
+
+ if (_semitones != semitones || _inCV != inCV || _fine != fine) {
+ _semitones = semitones;
+ _inCV = inCV;
+ _fine = fine;
+ _outCV = clamp(semitoneToCV((_inCV != 0.0f ? cvToSemitone(_inCV) : referenceSemitone) + _semitones + _fine), _minCVOut, _maxCVOut);
+ }
+
+ if (inputs[IN_INPUT].active) {
+ outputs[THRU_OUTPUT].value = _inCV;
}
else {
- outputs[THRU_OUTPUT].value = semitones / 10.0;
- outputs[OUT_OUTPUT].value = clamp(semitoneToCV(referenceSemitone + semitones + params[FINE_PARAM].value), _minCVOut, _maxCVOut);
+ outputs[THRU_OUTPUT].value = _semitones / 10.0;
}
+ outputs[OUT_OUTPUT].value = _outCV;
}
struct StackWidget : ModuleWidget {
diff --git a/src/Stack.hpp b/src/Stack.hpp
@@ -38,6 +38,11 @@ struct Stack : Module {
const float _minCVOut = semitoneToCV(24.0); // C1
const float _maxCVOut = semitoneToCV(120.0); // C9
+ float _semitones = -1000.0f;
+ float _inCV = -1000.0f;
+ float _fine = -1000.0f;
+ float _outCV;
+
Stack() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
}
diff --git a/src/VCA.cpp b/src/VCA.cpp
@@ -1,19 +1,26 @@
#include "VCA.hpp"
+void VCA::onSampleRateChange() {
+ float sampleRate = engineGetSampleRate();
+ _levelSL1.setParams(sampleRate, 100.0f);
+ _levelSL2.setParams(sampleRate, 100.0f);
+}
+
void VCA::step() {
bool linear = params[LINEAR_PARAM].value > 0.5f;
lights[LINEAR_LIGHT].value = linear;
- channelStep(inputs[IN1_INPUT], outputs[OUT1_OUTPUT], params[LEVEL1_PARAM], inputs[CV1_INPUT], _amplifier1, linear);
- channelStep(inputs[IN2_INPUT], outputs[OUT2_OUTPUT], params[LEVEL2_PARAM], inputs[CV2_INPUT], _amplifier2, linear);
+ channelStep(inputs[IN1_INPUT], outputs[OUT1_OUTPUT], params[LEVEL1_PARAM], inputs[CV1_INPUT], _amplifier1, _levelSL1, linear);
+ channelStep(inputs[IN2_INPUT], outputs[OUT2_OUTPUT], params[LEVEL2_PARAM], inputs[CV2_INPUT], _amplifier2, _levelSL1, linear);
}
-void VCA::channelStep(Input& input, Output& output, Param& knob, Input& cv, Amplifier& amplifier, bool linear) {
+void VCA::channelStep(Input& input, Output& output, Param& knob, Input& cv, Amplifier& amplifier, SlewLimiter& levelSL, bool linear) {
if (input.active && output.active) {
float level = knob.value;
if (cv.active) {
level *= clamp(cv.value / 10.0f, 0.0f, 1.0f);
}
+ level = levelSL.next(level);
if (linear) {
output.value = level * input.value;
}
diff --git a/src/VCA.hpp b/src/VCA.hpp
@@ -37,12 +37,17 @@ struct VCA : Module {
};
Amplifier _amplifier1;
+ SlewLimiter _levelSL1;
Amplifier _amplifier2;
+ SlewLimiter _levelSL2;
- VCA() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
+ VCA() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
+ onSampleRateChange();
+ }
+ void onSampleRateChange() override;
void step() override;
- void channelStep(Input& input, Output& output, Param& knob, Input& cv, Amplifier& amplifier, bool linear);
+ void channelStep(Input& input, Output& output, Param& knob, Input& cv, Amplifier& amplifier, SlewLimiter& levelSL, bool linear);
};
} // namespace bogaudio
diff --git a/src/VCAmp.cpp b/src/VCAmp.cpp
@@ -2,7 +2,9 @@
#include "VCAmp.hpp"
void VCAmp::onSampleRateChange() {
- _rms.setSampleRate(engineGetSampleRate());
+ float sampleRate = engineGetSampleRate();
+ _levelSL.setParams(sampleRate, 10.0f);
+ _rms.setSampleRate(sampleRate);
}
void VCAmp::step() {
@@ -13,7 +15,7 @@ void VCAmp::step() {
}
level *= maxDecibels - minDecibels;
level += minDecibels;
- _amplifier.setLevel(level);
+ _amplifier.setLevel(_levelSL.next(level));
outputs[OUT_OUTPUT].value = _amplifier.next(inputs[IN_INPUT].value);
_rmsLevel = _rms.next(outputs[OUT_OUTPUT].value / 5.0f);
}
diff --git a/src/VCAmp.hpp b/src/VCAmp.hpp
@@ -33,6 +33,7 @@ struct VCAmp : Module {
const float maxDecibels = 12.0f;
const float minDecibels = Amplifier::minDecibels;
Amplifier _amplifier;
+ SlewLimiter _levelSL;
RootMeanSquare _rms;
float _rmsLevel = 0.0f;
diff --git a/src/XFade.cpp b/src/XFade.cpp
@@ -1,24 +1,39 @@
#include "XFade.hpp"
+void XFade::onSampleRateChange() {
+ _mixSL.setParams(engineGetSampleRate(), 100.0f);
+}
+
void XFade::step() {
bool linear = params[LINEAR_PARAM].value > 0.5f;
lights[LINEAR_LIGHT].value = linear;
+ if (!outputs[OUT_OUTPUT].active) {
+ return;
+ }
float mix = params[MIX_PARAM].value;
if (inputs[MIX_INPUT].active) {
mix *= clamp(inputs[MIX_INPUT].value / 5.0f, -1.0f, 1.0f);
}
+ mix = _mixSL.next(mix);
+
+ float curveIn = params[CURVE_PARAM].value;
+
+ if (_linear != linear || _mix != mix || _curveIn != curveIn) {
+ _linear = linear;
+ _mix = mix;
+ _curveIn = curveIn;
+ if (!linear) {
+ curveIn = powf(params[CURVE_PARAM].value, 0.082f);
+ }
+ curveIn *= 2.0f;
+ curveIn -= 1.0f;
- float curve = params[CURVE_PARAM].value;
- if (!linear) {
- curve = powf(params[CURVE_PARAM].value, 0.082f);
+ _mixer.setParams(mix, curveIn, linear);
}
- curve *= 2.0f;
- curve -= 1.0f;
- _mix.setParams(mix, curve, linear);
- outputs[OUT_OUTPUT].value = _mix.next(inputs[A_INPUT].value, inputs[B_INPUT].value);
+ outputs[OUT_OUTPUT].value = _mixer.next(inputs[A_INPUT].value, inputs[B_INPUT].value);
}
struct XFadeWidget : ModuleWidget {
diff --git a/src/XFade.hpp b/src/XFade.hpp
@@ -34,11 +34,17 @@ struct XFade : Module {
NUM_LIGHTS
};
- CrossFader _mix;
+ bool _linear = false;
+ float _mix = 0.0f;
+ float _curveIn = -1.0f;
+ SlewLimiter _mixSL;
+ CrossFader _mixer;
XFade() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
+ onSampleRateChange();
}
+ void onSampleRateChange() override;
void step() override;
};
diff --git a/src/dsp/signal.hpp b/src/dsp/signal.hpp
@@ -124,7 +124,7 @@ struct SlewLimiter {
setParams(sampleRate, milliseconds);
}
- void setParams(float sampleRate, float milliseconds);
+ void setParams(float sampleRate, float milliseconds = 1.0f);
float next(float sample);
};
diff --git a/src/mixer.cpp b/src/mixer.cpp
@@ -3,7 +3,7 @@
const float MixerChannel::maxDecibels = 6.0f;
const float MixerChannel::minDecibels = Amplifier::minDecibels;
-const float MixerChannel::slewTimeMS = 1.0f;
+const float MixerChannel::slewTimeMS = 10.0f;
void MixerChannel::setSampleRate(float sampleRate) {
_slewLimiter.setParams(sampleRate, slewTimeMS);