From a342b799dba027892010d13fa87b4393084c5c6d Mon Sep 17 00:00:00 2001 From: hemmer <915048+hemmer@users.noreply.github.com> Date: Fri, 10 Sep 2021 18:11:00 +0100 Subject: [PATCH] EvenVCO: remove DC offset from pulse out Sampling Modulator: avoid processing if outputs/inputs not connected Misc: updated docs --- CHANGELOG.md | 5 +++ README.md | 2 +- src/EvenVCO.cpp | 1 + src/SamplingModulator.cpp | 68 ++++++++++++++++++++++++++------------- 4 files changed, 52 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26a2f9f..4bd0bc4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Change Log +## v1.2.0 (unreleased) + + * Released new modules: Muxlicer, Mex, Morphader, VC ADSR, Sampling Modulator, ST Mix + * Removed DC offset from EvenVCO pulse output + ## v1.1.1 * Fixed issue with A*B+C summing logic diff --git a/README.md b/README.md index 929d223..69eee2d 100644 --- a/README.md +++ b/README.md @@ -15,4 +15,4 @@ We have tried to make the VCV implementations as authentic as possible, however * Chopping Kinky hardward is DC coupled, but we add the option (default disabled) to remove this offset. -* The hardware Muxlicer assigns multiple functions to the "Speed Div/Mult" dial, that cannot be reproduced with a single mouse click. Some of these have been moved to the context menu, specifically: quadratic gates, the "All In" normalled voltage, and the input/output clock division/mult. The "Speed Div/Mult" dial remains only as a tap-tempo button. \ No newline at end of file +* The hardware Muxlicer assigns multiple functions to the "Speed Div/Mult" dial, that cannot be reproduced with a single mouse click. Some of these have been moved to the context menu, specifically: quadratic gates, the "All In" normalled voltage, and the input/output clock division/mult. The "Speed Div/Mult" dial remains only for main clock div/mult. \ No newline at end of file diff --git a/src/EvenVCO.cpp b/src/EvenVCO.cpp index fa2c4b3..34d97f6 100644 --- a/src/EvenVCO.cpp +++ b/src/EvenVCO.cpp @@ -186,6 +186,7 @@ struct EvenVCO : Module { square[c / 4] = simd::ifelse((phase[c / 4] < pw[c / 4]), -1.f, +1.f); square[c / 4] += squareMinBlepOut[c / 4]; + square[c / 4] += 2.f * (pw[c / 4] - 0.5); // DC offset correction square[c / 4] *= 5.f; // Set outputs diff --git a/src/SamplingModulator.cpp b/src/SamplingModulator.cpp index dc96048..f2e7257 100644 --- a/src/SamplingModulator.cpp +++ b/src/SamplingModulator.cpp @@ -104,6 +104,10 @@ struct SamplingModulator : Module { void process(const ProcessArgs& args) override { bool advanceStep = false; + const bool isHoldOutRequired = outputs[OUT_OUTPUT].isConnected() && inputs[IN_INPUT].isConnected(); + const bool isClockOutRequired = outputs[CLOCK_OUTPUT].isConnected(); + const bool isTriggOutRequired = outputs[TRIGG_OUTPUT].isConnected(); + if (params[INT_EXT_PARAM].getValue() == CLOCK_EXTERNAL) { // if external mode, the SYNC/EXT. CLOCK input acts as a clock advanceStep = clock.process(rescale(inputs[SYNC_INPUT].getVoltage(), 0.1f, 2.f, 0.f, 1.f)); @@ -140,14 +144,17 @@ struct SamplingModulator : Module { const float minDialFrequency = 1.0f; const float frequency = minDialFrequency * simd::pow(2.f, pitch); - float oldPhase = stepPhase; + const float oldPhase = stepPhase; float deltaPhase = clamp(args.sampleTime * frequency, 1e-6f, 0.5f); stepPhase += deltaPhase; if (!halfPhase && stepPhase >= 0.5) { + float crossing = -(stepPhase - 0.5) / deltaPhase; - squareMinBlep.insertDiscontinuity(crossing, -2.f); - if (stepStates[currentStep] == STATE_ON) { + if (isClockOutRequired) { + squareMinBlep.insertDiscontinuity(crossing, -2.f); + } + if (isTriggOutRequired && stepStates[currentStep] == STATE_ON) { triggMinBlep.insertDiscontinuity(crossing, -2.f); } @@ -156,8 +163,11 @@ struct SamplingModulator : Module { if (stepPhase >= 1.0f) { stepPhase -= 1.0f; - float crossing = -stepPhase / deltaPhase; - squareMinBlep.insertDiscontinuity(crossing, +2.f); + + if (isClockOutRequired) { + float crossing = -stepPhase / deltaPhase; + squareMinBlep.insertDiscontinuity(crossing, +2.f); + } halfPhase = false; @@ -173,7 +183,8 @@ struct SamplingModulator : Module { const float crossing = -(oldPhase + deltaPhase - 1.0) / deltaPhase; triggMinBlep.insertDiscontinuity(crossing, +2.f); triggerGenerator.trigger(); - if (!holdDetector.isHigh()) { + + if (!holdDetector.isHigh() && isHoldOutRequired) { float oldHeldValue = heldValue; heldValue = inputs[IN_INPUT].getVoltage(); holdMinBlep.insertDiscontinuity(crossing, heldValue - oldHeldValue); @@ -181,28 +192,39 @@ struct SamplingModulator : Module { } } - float output = heldValue + holdMinBlep.process(); - outputs[OUT_OUTPUT].setVoltage(output); - - float square = (stepPhase < 0.5) ? 2.f : 0.f; - square += squareMinBlep.process(); - - float trigger = (stepPhase < 0.5 && stepStates[currentStep] == STATE_ON) ? 2.f : 0.f; - trigger += triggMinBlep.process(); + const float holdOutput = isHoldOutRequired ? (heldValue + holdMinBlep.process()) : 0.f; + outputs[OUT_OUTPUT].setVoltage(holdOutput); - if (removeDC) { - trigger -= 1.0f; - square -= 1.0f; - if (numEffectiveSteps > 0) { - trigger += (float)(numEffectiveSteps - numActiveSteps) / (numEffectiveSteps); - } + if (isClockOutRequired) { + float square = (stepPhase < 0.5) ? 2.f : 0.f; + square += squareMinBlep.process(); + square -= 1.0f * removeDC; + outputs[CLOCK_OUTPUT].setVoltage(5.f * square); + } + else { + outputs[CLOCK_OUTPUT].setVoltage(0.f); } - outputs[CLOCK_OUTPUT].setVoltage(5.f * square); if (params[INT_EXT_PARAM].getValue() == CLOCK_INTERNAL) { - outputs[TRIGG_OUTPUT].setVoltage(5.f * trigger); + if (isTriggOutRequired) { + float trigger = (stepPhase < 0.5 && stepStates[currentStep] == STATE_ON) ? 2.f : 0.f; + trigger += triggMinBlep.process(); + + if (removeDC) { + trigger -= 1.0f; + if (numEffectiveSteps > 0) { + trigger += (float)(numEffectiveSteps - numActiveSteps) / (numEffectiveSteps); + } + } + + outputs[TRIGG_OUTPUT].setVoltage(5.f * trigger); + } + else { + outputs[TRIGG_OUTPUT].setVoltage(0.f); + } } - else { + else { + // if externally clocked, just give standard triggers outputs[TRIGG_OUTPUT].setVoltage(10.f * triggerGenerator.process(args.sampleTime)); }