From 37df15927e2a8eaf730abf205952eea620c4028a Mon Sep 17 00:00:00 2001 From: lnd3 Date: Wed, 11 Sep 2024 22:12:50 +0200 Subject: [PATCH] Fix fm synthesis. --- packages/math/include/math/MathFunc.h | 13 +++++ .../nodegraph/operations/NodeGraphOpEffect.h | 8 ++- .../nodegraph/operations/NodeGraphOpSignal.h | 8 +-- .../common/operations/NodeGraphOpEffect.cpp | 9 ++- .../common/operations/NodeGraphOpSignal.cpp | 56 +++++++++---------- 5 files changed, 56 insertions(+), 38 deletions(-) diff --git a/packages/math/include/math/MathFunc.h b/packages/math/include/math/MathFunc.h index 3b74c50f..eebbb8c2 100644 --- a/packages/math/include/math/MathFunc.h +++ b/packages/math/include/math/MathFunc.h @@ -125,6 +125,19 @@ namespace l::math::functions { } } + + template + T cos(T val) { + if constexpr (std::is_floating_point_v) { + if constexpr (sizeof(T) == 4) { + return cosf(val); + } + else if constexpr (sizeof(T) == 8) { + return ::cos(val); + } + } + } + template T mod(T val, T mod) { if constexpr (std::is_floating_point_v) { diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpEffect.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpEffect.h index d2f998f5..51e35055 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpEffect.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpEffect.h @@ -331,11 +331,11 @@ namespace l::nodegraph { /*********************************************************************/ class GraphEffectArpeggio: public NodeGraphOp { public: - std::string defaultInStrings[7] = { "Note On Id", "Note Off Id", "Velocity", "Bpm", "Fmod", "Attack", "Drift Sync"}; + std::string defaultInStrings[8] = { "Note On Id", "Note Off Id", "Velocity", "Bpm", "Fmod", "Attack", "Smooth", "Drift Sync"}; std::string defaultOutStrings[3] = { "Freq", "Volume" }; GraphEffectArpeggio(NodeGraphBase* node) : - NodeGraphOp(node, 7, 2, 0) + NodeGraphOp(node, 8, 2, 0) {} virtual ~GraphEffectArpeggio() = default; @@ -364,7 +364,9 @@ namespace l::nodegraph { float mGainSmoothing = 0.01f; float mGainSmoothingNeg = 0.01f; - float mCurrentNoteFreq = 0.0f; + float mFreqSmoothing = 0.1f; + float mFreqTarget = 0.0f; + float mFreq = 0.0f; std::vector mNotes; int32_t mNoteIndex = 0; }; diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSignal.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSignal.h index 87f4bd45..a78978da 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSignal.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSignal.h @@ -25,7 +25,7 @@ namespace l::nodegraph { class GraphSignalBase : public NodeGraphOp { public: - static const int8_t mNumDefaultInputs = 6; + static const int8_t mNumDefaultInputs = 7; static const int8_t mNumDefaultOutputs = 1; GraphSignalBase(NodeGraphBase* node, std::string_view name, int32_t numInputs = 0, int32_t numOutputs = 0, int32_t numConstants = 0) : @@ -33,7 +33,7 @@ namespace l::nodegraph { mName(name) {} - std::string defaultInStrings[mNumDefaultInputs] = { "Reset", "Freq", "Volume", "Smooth", "Cutoff", "Resonance"}; + std::string defaultInStrings[mNumDefaultInputs] = { "Reset", "Freq", "Volume", "Smooth", "Cutoff", "Resonance", "Phase expansion"}; std::string defaultOutStrings[mNumDefaultOutputs] = { "Out" }; virtual ~GraphSignalBase() = default; @@ -58,7 +58,7 @@ namespace l::nodegraph { virtual std::string_view GetOutputNameExtra(int8_t) { return ""; }; virtual void ResetSignal() {}; virtual void UpdateSignal(std::vector&, std::vector&) {}; - virtual float GenerateSignal(float deltaPhase) = 0; + virtual float GenerateSignal(float deltaTime, float freq, float deltaPhase) = 0; protected: std::string mName; @@ -96,7 +96,7 @@ namespace l::nodegraph { } void ResetSignal() override; void UpdateSignal(std::vector& inputs, std::vector& outputs) override; - float GenerateSignal(float deltaPhase) override; + float GenerateSignal(float deltaTime, float freq, float deltaPhase) override; protected: float mFmod = 0.0f; float mPmod = 0.0f; diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpEffect.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpEffect.cpp index c497b369..a6c92ccb 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpEffect.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpEffect.cpp @@ -519,7 +519,7 @@ namespace l::nodegraph { float fmod = inputs.at(4).Get(); float attack = inputs.at(5).Get(); - if (inputs.at(6).Get() > 0.5f) { + if (inputs.at(7).Get() > 0.5f) { mSamplesUntilUpdate = 0.0f; } @@ -565,9 +565,11 @@ namespace l::nodegraph { } else { mNoteIndex = mNoteIndex % mNotes.size(); - mCurrentNoteFreq = l::audio::GetFrequencyFromNote(static_cast(mNotes.at(mNoteIndex))); + mFreqTarget = l::audio::GetFrequencyFromNote(static_cast(mNotes.at(mNoteIndex))); mNoteIndex++; mGainTarget = velocity; + mFreqSmoothing = inputs.at(6).Get(); + mFreqSmoothing *= mFreqSmoothing * 0.5f; } }, [&](int32_t start, int32_t end, bool) { @@ -580,7 +582,8 @@ namespace l::nodegraph { mGain += mGainSmoothingNeg * (-l::math::smooth::smootPolyh3(-delta)); } - outputs.at(0).mOutput = mCurrentNoteFreq; + mFreq += mFreqSmoothing * (mFreqTarget - mFreq); + outputs.at(0).mOutput = mFreq; outputs.at(1).mOutput = mGain; } }); diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpSignal.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpSignal.cpp index d95b4c88..2f0f2d58 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpSignal.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpSignal.cpp @@ -20,7 +20,7 @@ namespace l::nodegraph { mDeltaTime = 0.0f; mVolume = 0.0f; mSamplesUntilUpdate = 0.0f; - mUpdateSamples = 256.0f; + mUpdateSamples = 16.0f; mHPCutoff = 0.5f; mHPResonance = 0.0001f; mHPState0 = 0.0f; @@ -30,15 +30,17 @@ namespace l::nodegraph { mNode->SetInput(0, 0.0f); mNode->SetInput(1, 0.0f); mNode->SetInput(2, 0.5f); - mNode->SetInput(3, 0.5f); - mNode->SetInput(4, 0.5f); - mNode->SetInput(5, 0.0001f); + mNode->SetInput(3, 1.0f); + mNode->SetInput(4, 0.0f); + mNode->SetInput(5, 0.0f); + mNode->SetInput(6, 0.5f); mNode->SetInputBound(0, InputBound::INPUT_0_TO_1); mNode->SetInputBound(1, InputBound::INPUT_CUSTOM, 0.0f, l::math::constants::FLTMAX); mNode->SetInputBound(2, InputBound::INPUT_0_100); mNode->SetInputBound(3, InputBound::INPUT_0_TO_1); mNode->SetInputBound(4, InputBound::INPUT_0_TO_1); mNode->SetInputBound(5, InputBound::INPUT_0_TO_1); + mNode->SetInputBound(6, InputBound::INPUT_0_TO_1); ResetSignal(); } @@ -53,18 +55,15 @@ namespace l::nodegraph { mFreq = inputs.at(1).Get(); mVolumeTarget = inputs.at(2).Get(); mSmooth = 0.5f * inputs.at(3).Get(); + float phaseExpansion = inputs.at(6).Get(); mDeltaPhase = mDeltaTime * mFreq; - float deltaPhaseExpanded = l::math::functions::pow(mDeltaPhase, 0.125f); + //float deltaPhaseExpanded = l::math::functions::pow(mDeltaPhase, phaseExpansion); + float deltaPhaseExpanded = l::math::functions::pow(mDeltaPhase, 0.4f - phaseExpansion * mDeltaPhase * 6.0f); mHPCutoff = deltaPhaseExpanded + (1.0f - deltaPhaseExpanded) * inputs.at(4).Get(); mHPResonance = 1.0f - inputs.at(5).Get(); - if (mFreq == 0.0f) { - mVolumeTarget = 0.0f; - outputs.at(0).mOutput = 0.0f; - return; - } - if (mReset > 0.5f) { + if (mFreq == 0.0f || mReset > 0.5f) { mVolumeTarget = 0.0f; } @@ -73,7 +72,7 @@ namespace l::nodegraph { }, [&](int32_t start, int32_t end, bool) { for (int32_t i = start; i < end; i++) { - float signalTarget = GenerateSignal(mDeltaPhase); + float signalTarget = GenerateSignal(mDeltaTime, mFreq, mDeltaPhase); // highpass filter { @@ -99,32 +98,33 @@ namespace l::nodegraph { /*********************************************************************/ void GraphSignalSine2::ResetSignal() { - mNode->SetInput(mNumDefaultInputs + 0, 0.5f); + mNode->SetInput(mNumDefaultInputs + 0, 0.0f); mNode->SetInput(mNumDefaultInputs + 1, 0.0f); mNode->SetInputBound(mNumDefaultInputs + 0, InputBound::INPUT_0_TO_1); mNode->SetInputBound(mNumDefaultInputs + 1, InputBound::INPUT_0_TO_1); + mUpdateSamples = 16.0f; } void GraphSignalSine2::UpdateSignal(std::vector& inputs, std::vector&) { mFmod = inputs.at(mNumDefaultInputs + 0).Get(); mPmod = inputs.at(mNumDefaultInputs + 1).Get(); - float fmodRange = 16.0f; - mFmod = mFmod > 0.5f ? 1.0f + fmodRange * (mFmod - 0.5f) : 1.0f / (1.0f + fmodRange * (0.5f - mFmod)); + mFmod *= 0.25f * 0.25f * 0.5f * 44100.0f / l::math::functions::max(mFreq, 1.0f); } - float GraphSignalSine2::GenerateSignal(float deltaPhase) { + float GraphSignalSine2::GenerateSignal(float, float, float deltaPhase) { mPhaseFmod += deltaPhase; mPhaseFmod = l::math::functions::mod(mPhaseFmod, 1.0f); - float modulation = mFmod * (1.0f + 0.5f * l::math::functions::sin(l::math::constants::PI_f * mPhaseFmod * 2.0f)); + float modulation = l::math::functions::cos(l::math::constants::PI_f * mPhaseFmod * 2.0f); - mPhase += deltaPhase * modulation; - mPhase = l::math::functions::mod(mPhase, 1.0f); + mPhase = mPhaseFmod; + mPhase += mFmod * modulation; + mPhase -= l::math::functions::floor(mPhase); - float phaseMod = mPhase + mPmod; - phaseMod = l::math::functions::mod(phaseMod, 1.0f); + float phaseMod = mPhaseFmod + mPmod; + phaseMod -= l::math::functions::floor(phaseMod); - mWave = mSmooth * (mPhase + phaseMod - mWave); - return l::math::functions::sin(l::math::constants::PI_f * mWave); + //mWave = mSmooth * (mPhase + phaseMod - mWave); + return 0.5f * (l::math::functions::sin(l::math::constants::PI_f * mPhase * 2.0f) + l::math::functions::sin(l::math::constants::PI_f * phaseMod * 2.0f)); } /*********************************************************************/ @@ -137,7 +137,7 @@ namespace l::nodegraph { mNode->SetInput(3, 0.0f); mNode->SetInput(4, 0.5f); mNode->SetInput(5, 0.0f); - mNode->SetInputBound(0, InputBound::INPUT_UNBOUNDED); + mNode->SetInputBound(0, InputBound::INPUT_CUSTOM, 0.0f, l::math::constants::FLTMAX); mNode->SetInputBound(1, InputBound::INPUT_0_100); mNode->SetInputBound(2, InputBound::INPUT_0_TO_2); mNode->SetInputBound(3, InputBound::INPUT_0_TO_1); @@ -228,7 +228,7 @@ namespace l::nodegraph { mNode->SetInput(6, 0.0f); mNode->SetInput(7, 0.5f); mNode->SetInput(8, 0.0f); - mNode->SetInputBound(0, InputBound::INPUT_UNBOUNDED); + mNode->SetInputBound(0, InputBound::INPUT_CUSTOM, 0.0f, l::math::constants::FLTMAX); mNode->SetInputBound(1, InputBound::INPUT_0_100); mNode->SetInputBound(2, InputBound::INPUT_UNBOUNDED); mNode->SetInputBound(3, InputBound::INPUT_UNBOUNDED); @@ -301,7 +301,7 @@ namespace l::nodegraph { mNode->SetInput(3, 0.0f); mNode->SetInput(4, 0.5f); mNode->SetInput(5, 0.0f); - mNode->SetInputBound(0, InputBound::INPUT_UNBOUNDED); + mNode->SetInputBound(0, InputBound::INPUT_CUSTOM, 0.0f, l::math::constants::FLTMAX); mNode->SetInputBound(1, InputBound::INPUT_0_100); mNode->SetInputBound(2, InputBound::INPUT_0_TO_1); mNode->SetInputBound(3, InputBound::INPUT_0_100); @@ -374,7 +374,7 @@ namespace l::nodegraph { mNode->SetInput(1, 0.5f); mNode->SetInput(2, 0.5f); mNode->SetInput(3, 0.0f); - mNode->SetInputBound(0, InputBound::INPUT_UNBOUNDED); + mNode->SetInputBound(0, InputBound::INPUT_CUSTOM, 0.0f, l::math::constants::FLTMAX); mNode->SetInputBound(1, InputBound::INPUT_0_100); mNode->SetInputBound(2, InputBound::INPUT_0_TO_1); mNode->SetInputBound(3, InputBound::INPUT_0_TO_1); @@ -437,7 +437,7 @@ namespace l::nodegraph { mNode->SetInput(3, 0.0f); mNode->SetInput(4, 0.5f); mNode->SetInput(5, 0.0f); - mNode->SetInputBound(0, InputBound::INPUT_UNBOUNDED); + mNode->SetInputBound(0, InputBound::INPUT_CUSTOM, 0.0f, l::math::constants::FLTMAX); mNode->SetInputBound(1, InputBound::INPUT_0_100); mNode->SetInputBound(2, InputBound::INPUT_0_TO_2); mNode->SetInputBound(3, InputBound::INPUT_0_TO_1);