diff --git a/packages/math/include/math/MathFunc.h b/packages/math/include/math/MathFunc.h index 5b74ad42..3b74c50f 100644 --- a/packages/math/include/math/MathFunc.h +++ b/packages/math/include/math/MathFunc.h @@ -129,7 +129,7 @@ namespace l::math::functions { T mod(T val, T mod) { if constexpr (std::is_floating_point_v) { if constexpr (sizeof(T) == 4) { - return modff(val, mod); + return fmodf(val, mod); } else if constexpr (sizeof(T) == 8) { return fmod(val, mod); diff --git a/packages/nodegraph/include/nodegraph/NodeGraphSchema.h b/packages/nodegraph/include/nodegraph/NodeGraphSchema.h index 62e70205..9e6e25be 100644 --- a/packages/nodegraph/include/nodegraph/NodeGraphSchema.h +++ b/packages/nodegraph/include/nodegraph/NodeGraphSchema.h @@ -2,14 +2,15 @@ #include "logging/LoggingAll.h" -#include "nodegraph/NodeGraph.h" -#include "nodegraph/NodeGraphOpEffect.h" -#include "nodegraph/NodeGraphOpFilter.h" -#include "nodegraph/NodeGraphOpInput.h" -#include "nodegraph/NodeGraphOpLogic.h" -#include "nodegraph/NodeGraphOpNumeric.h" -#include "nodegraph/NodeGraphOpOutput.h" -#include "nodegraph/NodeGraphOpSource.h" +#include "nodegraph/core/NodeGraphGroup.h" +#include "nodegraph/operations/NodeGraphOpEffect.h" +#include "nodegraph/operations/NodeGraphOpFilter.h" +#include "nodegraph/operations/NodeGraphOpInput.h" +#include "nodegraph/operations/NodeGraphOpLogic.h" +#include "nodegraph/operations/NodeGraphOpNumeric.h" +#include "nodegraph/operations/NodeGraphOpOutput.h" +#include "nodegraph/operations/NodeGraphOpSource.h" +#include "nodegraph/operations/NodeGraphOpSignal.h" #include "hid/Midi.h" @@ -45,11 +46,6 @@ namespace l::nodegraph { RegisterNodeType("Source", 2, "Value [0,100]"); RegisterNodeType("Source", 3, "Value [-inf,inf]"); RegisterNodeType("Source", 4, "Time"); - RegisterNodeType("Source", 5, "Sine"); - RegisterNodeType("Source", 6, "Sine FM 1"); - RegisterNodeType("Source", 7, "Sine FM 2"); - RegisterNodeType("Source", 8, "Sine FM 3"); - RegisterNodeType("Source", 9, "Saw"); RegisterNodeType("Numeric", 50, "Add"); RegisterNodeType("Numeric", 51, "Subtract"); RegisterNodeType("Numeric", 52, "Negate"); @@ -62,6 +58,7 @@ namespace l::nodegraph { RegisterNodeType("Logic", 101, "Or"); RegisterNodeType("Logic", 102, "Xor"); RegisterNodeType("Filter", 150, "Lowpass"); + RegisterNodeType("Filter", 151, "Highpass"); RegisterNodeType("Output", 200, "Debug"); RegisterNodeType("Output", 201, "Speaker"); RegisterNodeType("Output", 202, "Plot"); @@ -81,6 +78,13 @@ namespace l::nodegraph { RegisterNodeType("Input", 305, "Midi Button Group 3"); RegisterNodeType("Input", 306, "Midi Button Group 4"); RegisterNodeType("Input", 307, "Midi Button Group 5"); + RegisterNodeType("Signal", 350, "Sine"); + RegisterNodeType("Signal", 351, "Sine FM 1"); + RegisterNodeType("Signal", 352, "Sine FM 2"); + RegisterNodeType("Signal", 353, "Sine FM 3"); + RegisterNodeType("Signal", 354, "Saw"); + RegisterNodeType("Signal", 355, "Sine 2"); + } ~NodeGraphSchema() = default; diff --git a/packages/nodegraph/include/nodegraph/NodeGraph.h b/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h similarity index 58% rename from packages/nodegraph/include/nodegraph/NodeGraph.h rename to packages/nodegraph/include/nodegraph/core/NodeGraphBase.h index 35a5b999..46564442 100644 --- a/packages/nodegraph/include/nodegraph/NodeGraph.h +++ b/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h @@ -11,9 +11,13 @@ #include "math/MathConstants.h" +#include "nodegraph/core/NodeGraphInput.h" +#include "nodegraph/core/NodeGraphOutput.h" + namespace l::nodegraph { int32_t CreateUniqueId(); + bool IsValidInOutNum(int8_t inoutNum, size_t inoutSize); enum class DataType { FLOAT32, @@ -21,107 +25,8 @@ namespace l::nodegraph { BITFIELD32 }; - enum class InputType { - INPUT_EMPTY, - INPUT_NODE, - INPUT_CONSTANT, - INPUT_VALUE, - INPUT_ARRAY - }; - - enum class InputBound { - INPUT_DONTCHANGE, - INPUT_UNBOUNDED, - INPUT_0_TO_1, - INPUT_0_TO_2, - INPUT_NEG_1_POS_1, - INPUT_0_100, - INPUT_CUSTOM, - }; - - enum class OutputType { - Default, // node will be processed if it is connected to the groups output by some route - ExternalOutput, // node does not have meaningful output for other nodes but should still be processed (ex speaker output only has input) - ExternalVisualOutput, - }; - - bool IsValidInOutNum(int8_t inoutNum, size_t inoutSize); - - class NodeGraphOutput { - public: - NodeGraphOutput() = default; - - float mOutput = 0.0f; - std::unique_ptr> mOutputBuf = nullptr; - std::unique_ptr mName = nullptr; - bool mOutputPolled = false; - - float& GetOutput(int32_t size = 1) { - if (!mOutputBuf) { - if (size <= 1) { - mOutputPolled = true; - return mOutput; - } - else { - mOutputBuf = std::make_unique>(); - } - } - if (static_cast(mOutputBuf->size()) < size) { - mOutputBuf->resize(size); - } - mOutputPolled = true; - return *mOutputBuf->data(); - } - - int32_t GetOutputSize() { - if (!mOutputBuf) { - return 1; - } - else { - return static_cast(mOutputBuf->size()); - } - } - - bool IsOutputPolled() { - return mOutputPolled; - } - - void ResetOutputPollState() { - mOutputPolled = false; - } - }; - - class NodeGraphBase; class NodeGraphGroup; - union Input { - NodeGraphBase* mInputNode = nullptr; - float* mInputFloat; - float mInputFloatConstant; - int32_t* mInputInt; - int32_t mInputIntConstant; - }; - - struct NodeGraphInput { - Input mInput; - InputType mInputType = InputType::INPUT_EMPTY; - - float mBoundMin = -l::math::constants::FLTMAX; - float mBoundMax = l::math::constants::FLTMAX; - InputBound mInputBound = InputBound::INPUT_UNBOUNDED; - - int8_t mInputFromOutputChannel = 0; - std::unique_ptr mName; - - // hack to get input buffers working - std::unique_ptr> mInputBuf = nullptr; - - void Reset(); - bool HasInputNode(); - float Get(); - float& Get(int32_t numSamples); - }; - class NodeGraphBase { public: NodeGraphBase(OutputType outputType) : mId(CreateUniqueId()), mOutputType(outputType) { @@ -232,16 +137,6 @@ namespace l::nodegraph { int8_t mNumConstants = 0; }; - class GraphDataCopy : public NodeGraphOp { - public: - GraphDataCopy(NodeGraphBase* node) : - NodeGraphOp(node, 0) - {} - virtual ~GraphDataCopy() = default; - - void Process(int32_t numSamples, std::vector& inputs, std::vector& outputs) override; - }; - template class NodeGraph : public NodeGraphBase { public: @@ -332,67 +227,5 @@ namespace l::nodegraph { T mOperation; }; - class NodeGraphGroup { - public: - NodeGraphGroup() : - mInputNode(OutputType::Default), - mOutputNode(OutputType::Default) - { - SetNumInputs(1); - SetNumOutputs(1); - mOutputNodes.push_back(&mOutputNode); - } - ~NodeGraphGroup() { - LOG(LogInfo) << "Node group destroyed"; - } - - void SetNumInputs(int8_t numInputs); - void SetNumOutputs(int8_t outputCount); - void SetInput(int8_t inputChannel, NodeGraphBase& source, int8_t sourceOutputChannel); - void SetInput(int8_t inputChannel, NodeGraphGroup& source, int8_t sourceOutputChannel); - void SetInput(int8_t inputChannel, float constant); - void SetInput(int8_t inputChannel, float* floatPtr); - - void SetOutput(int8_t outputChannel, NodeGraphBase& source, int8_t sourceOutputChannel); - void SetOutput(int8_t outputChannel, NodeGraphGroup& source, int8_t sourceOutputChannel); - - float GetOutput(int8_t outputChannel); - NodeGraphBase& GetInputNode(); - NodeGraphBase& GetOutputNode(); - - bool ContainsNode(int32_t id); - NodeGraphBase* GetNode(int32_t id); - - template>> - NodeGraph* GetTypedNode(int32_t id) { - auto p = GetNode(id); - return reinterpret_cast*>(p); - } - - bool RemoveNode(int32_t id); - - template>, class... Params> - l::nodegraph::NodeGraphBase* NewNode(OutputType nodeType, Params&&... params) { - mNodes.push_back(std::make_unique>(nodeType, std::forward(params)...)); - auto nodePtr = mNodes.back().get(); - if (nodeType == OutputType::ExternalOutput || nodeType == OutputType::ExternalVisualOutput) { - mOutputNodes.push_back(nodePtr); - } - return nodePtr; - } - - void ClearProcessFlags(); - void ProcessSubGraph(int32_t numSamples, bool recomputeSubGraphCache = true); - void Tick(int32_t tickCount, float elapsed); - protected: - NodeGraph mInputNode; - NodeGraph mOutputNode; - - std::vector> mNodes; - std::vector mOutputNodes; - - int32_t mLastTickCount = 0; - }; - } diff --git a/packages/nodegraph/include/nodegraph/core/NodeGraphGroup.h b/packages/nodegraph/include/nodegraph/core/NodeGraphGroup.h new file mode 100644 index 00000000..51d5955b --- /dev/null +++ b/packages/nodegraph/include/nodegraph/core/NodeGraphGroup.h @@ -0,0 +1,91 @@ +#pragma once + +#include "logging/LoggingAll.h" + +#include +#include +#include +#include +#include +#include + +#include "math/MathConstants.h" + +#include "nodegraph/core/NodeGraphBase.h" + +namespace l::nodegraph { + + class GraphDataCopy : public NodeGraphOp { + public: + GraphDataCopy(NodeGraphBase* node) : + NodeGraphOp(node, 0) + {} + virtual ~GraphDataCopy() = default; + + void Process(int32_t numSamples, std::vector& inputs, std::vector& outputs) override; + }; + + class NodeGraphGroup { + public: + NodeGraphGroup() : + mInputNode(OutputType::Default), + mOutputNode(OutputType::Default) + { + SetNumInputs(1); + SetNumOutputs(1); + mOutputNodes.push_back(&mOutputNode); + } + ~NodeGraphGroup() { + LOG(LogInfo) << "Node group destroyed"; + } + + void SetNumInputs(int8_t numInputs); + void SetNumOutputs(int8_t outputCount); + void SetInput(int8_t inputChannel, NodeGraphBase& source, int8_t sourceOutputChannel); + void SetInput(int8_t inputChannel, NodeGraphGroup& source, int8_t sourceOutputChannel); + void SetInput(int8_t inputChannel, float constant); + void SetInput(int8_t inputChannel, float* floatPtr); + + void SetOutput(int8_t outputChannel, NodeGraphBase& source, int8_t sourceOutputChannel); + void SetOutput(int8_t outputChannel, NodeGraphGroup& source, int8_t sourceOutputChannel); + + float GetOutput(int8_t outputChannel); + NodeGraphBase& GetInputNode(); + NodeGraphBase& GetOutputNode(); + + bool ContainsNode(int32_t id); + NodeGraphBase* GetNode(int32_t id); + + template>> + NodeGraph* GetTypedNode(int32_t id) { + auto p = GetNode(id); + return reinterpret_cast*>(p); + } + + bool RemoveNode(int32_t id); + + template>, class... Params> + l::nodegraph::NodeGraphBase* NewNode(OutputType nodeType, Params&&... params) { + mNodes.push_back(std::make_unique>(nodeType, std::forward(params)...)); + auto nodePtr = mNodes.back().get(); + if (nodeType == OutputType::ExternalOutput || nodeType == OutputType::ExternalVisualOutput) { + mOutputNodes.push_back(nodePtr); + } + return nodePtr; + } + + void ClearProcessFlags(); + void ProcessSubGraph(int32_t numSamples, bool recomputeSubGraphCache = true); + void Tick(int32_t tickCount, float elapsed); + protected: + NodeGraph mInputNode; + NodeGraph mOutputNode; + + std::vector> mNodes; + std::vector mOutputNodes; + + int32_t mLastTickCount = 0; + }; + +} + diff --git a/packages/nodegraph/include/nodegraph/core/NodeGraphInput.h b/packages/nodegraph/include/nodegraph/core/NodeGraphInput.h new file mode 100644 index 00000000..313185f3 --- /dev/null +++ b/packages/nodegraph/include/nodegraph/core/NodeGraphInput.h @@ -0,0 +1,65 @@ +#pragma once + +#include "logging/LoggingAll.h" + +#include +#include +#include +#include +#include +#include + +#include "math/MathConstants.h" + +namespace l::nodegraph { + + enum class InputType { + INPUT_EMPTY, + INPUT_NODE, + INPUT_CONSTANT, + INPUT_VALUE, + INPUT_ARRAY + }; + + enum class InputBound { + INPUT_DONTCHANGE, + INPUT_UNBOUNDED, + INPUT_0_TO_1, + INPUT_0_TO_2, + INPUT_NEG_1_POS_1, + INPUT_0_100, + INPUT_CUSTOM, + }; + + class NodeGraphBase; + + union Input { + NodeGraphBase* mInputNode = nullptr; + float* mInputFloat; + float mInputFloatConstant; + int32_t* mInputInt; + int32_t mInputIntConstant; + }; + + struct NodeGraphInput { + Input mInput; + InputType mInputType = InputType::INPUT_EMPTY; + + float mBoundMin = -l::math::constants::FLTMAX; + float mBoundMax = l::math::constants::FLTMAX; + InputBound mInputBound = InputBound::INPUT_UNBOUNDED; + + int8_t mInputFromOutputChannel = 0; + std::unique_ptr mName; + + // hack to get input buffers working + std::unique_ptr> mInputBuf = nullptr; + + void Reset(); + bool HasInputNode(); + float Get(); + float& Get(int32_t numSamples); + }; + +} + diff --git a/packages/nodegraph/include/nodegraph/core/NodeGraphOutput.h b/packages/nodegraph/include/nodegraph/core/NodeGraphOutput.h new file mode 100644 index 00000000..9e524481 --- /dev/null +++ b/packages/nodegraph/include/nodegraph/core/NodeGraphOutput.h @@ -0,0 +1,38 @@ +#pragma once + +#include "logging/LoggingAll.h" + +#include +#include +#include +#include +#include +#include + +#include "math/MathConstants.h" + +namespace l::nodegraph { + + enum class OutputType { + Default, // node will be processed if it is connected to the groups output by some route + ExternalOutput, // node does not have meaningful output for other nodes but should still be processed (ex speaker output only has input) + ExternalVisualOutput, + }; + + class NodeGraphOutput { + public: + NodeGraphOutput() = default; + + float mOutput = 0.0f; + std::unique_ptr> mOutputBuf = nullptr; + std::unique_ptr mName = nullptr; + bool mOutputPolled = false; + + float& GetOutput(int32_t size = 1); + int32_t GetOutputSize(); + bool IsOutputPolled(); + void ResetOutputPollState(); + }; + +} + diff --git a/packages/nodegraph/include/nodegraph/NodeGraphOpEffect.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpEffect.h similarity index 99% rename from packages/nodegraph/include/nodegraph/NodeGraphOpEffect.h rename to packages/nodegraph/include/nodegraph/operations/NodeGraphOpEffect.h index 6ad33142..d2f998f5 100644 --- a/packages/nodegraph/include/nodegraph/NodeGraphOpEffect.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpEffect.h @@ -1,5 +1,5 @@ #pragma once -#include "nodegraph/NodeGraph.h" +#include "nodegraph/core/NodeGraphBase.h" #include "logging/LoggingAll.h" diff --git a/packages/nodegraph/include/nodegraph/NodeGraphOpFilter.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpFilter.h similarity index 56% rename from packages/nodegraph/include/nodegraph/NodeGraphOpFilter.h rename to packages/nodegraph/include/nodegraph/operations/NodeGraphOpFilter.h index 8efca744..e7009ef5 100644 --- a/packages/nodegraph/include/nodegraph/NodeGraphOpFilter.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpFilter.h @@ -1,5 +1,5 @@ #pragma once -#include "nodegraph/NodeGraph.h" +#include "nodegraph/core/NodeGraphBase.h" #include "logging/LoggingAll.h" @@ -55,5 +55,36 @@ namespace l::nodegraph { float mState1 = 0.0f; }; + /*********************************************************************/ + class GraphFilterHighpass : public NodeGraphOp { + public: + std::string defaultInStrings[3] = { "Data", "Cutoff", "Resonance" }; + std::string defaultOutStrings[1] = { "Out" }; + + GraphFilterHighpass(NodeGraphBase* node) : + NodeGraphOp(node, 3, 1) + {} + + virtual ~GraphFilterHighpass() = default; + virtual void Reset() override; + virtual void Process(int32_t numSamples, std::vector& inputs, std::vector& outputs) override; + virtual bool IsDataVisible(int8_t) override { return true; } + virtual bool IsDataEditable(int8_t channel) override { return channel > 0 ? true : false; } + virtual std::string_view GetInputName(int8_t inputChannel) override { + return defaultInStrings[inputChannel]; + } + + virtual std::string_view GetOutputName(int8_t outputChannel) override { + return defaultOutStrings[outputChannel]; + } + + virtual std::string_view GetName() override { + return "Highpass"; + } + protected: + float mState0 = 0.0f; + float mState1 = 0.0f; + }; + } diff --git a/packages/nodegraph/include/nodegraph/NodeGraphOpInput.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpInput.h similarity index 99% rename from packages/nodegraph/include/nodegraph/NodeGraphOpInput.h rename to packages/nodegraph/include/nodegraph/operations/NodeGraphOpInput.h index 5bc75db0..dd497a9d 100644 --- a/packages/nodegraph/include/nodegraph/NodeGraphOpInput.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpInput.h @@ -1,5 +1,5 @@ #pragma once -#include "nodegraph/NodeGraph.h" +#include "nodegraph/core/NodeGraphBase.h" #include "logging/LoggingAll.h" diff --git a/packages/nodegraph/include/nodegraph/NodeGraphOpLogic.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpLogic.h similarity index 98% rename from packages/nodegraph/include/nodegraph/NodeGraphOpLogic.h rename to packages/nodegraph/include/nodegraph/operations/NodeGraphOpLogic.h index abba62a9..cee4967b 100644 --- a/packages/nodegraph/include/nodegraph/NodeGraphOpLogic.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpLogic.h @@ -1,5 +1,5 @@ #pragma once -#include "nodegraph/NodeGraph.h" +#include "nodegraph/core/NodeGraphBase.h" #include "logging/LoggingAll.h" diff --git a/packages/nodegraph/include/nodegraph/NodeGraphOpNumeric.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpNumeric.h similarity index 99% rename from packages/nodegraph/include/nodegraph/NodeGraphOpNumeric.h rename to packages/nodegraph/include/nodegraph/operations/NodeGraphOpNumeric.h index 04edf45b..67c63855 100644 --- a/packages/nodegraph/include/nodegraph/NodeGraphOpNumeric.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpNumeric.h @@ -1,5 +1,5 @@ #pragma once -#include "nodegraph/NodeGraph.h" +#include "nodegraph/core/NodeGraphBase.h" #include "logging/LoggingAll.h" diff --git a/packages/nodegraph/include/nodegraph/NodeGraphOpOutput.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpOutput.h similarity index 98% rename from packages/nodegraph/include/nodegraph/NodeGraphOpOutput.h rename to packages/nodegraph/include/nodegraph/operations/NodeGraphOpOutput.h index 8557b6a8..a37229c2 100644 --- a/packages/nodegraph/include/nodegraph/NodeGraphOpOutput.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpOutput.h @@ -1,5 +1,5 @@ #pragma once -#include "nodegraph/NodeGraph.h" +#include "nodegraph/core/NodeGraphBase.h" #include "logging/LoggingAll.h" diff --git a/packages/nodegraph/include/nodegraph/NodeGraphOpSource.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSignal.h similarity index 63% rename from packages/nodegraph/include/nodegraph/NodeGraphOpSource.h rename to packages/nodegraph/include/nodegraph/operations/NodeGraphOpSignal.h index 86571c87..87f4bd45 100644 --- a/packages/nodegraph/include/nodegraph/NodeGraphOpSource.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSignal.h @@ -1,5 +1,5 @@ #pragma once -#include "nodegraph/NodeGraph.h" +#include "nodegraph/core/NodeGraphBase.h" #include "logging/LoggingAll.h" @@ -22,78 +22,99 @@ namespace l::nodegraph { - /* Mathematical operations */ - - /*********************************************************************/ - class GraphSourceConstants : public NodeGraphOp { + class GraphSignalBase : public NodeGraphOp { public: - GraphSourceConstants(NodeGraphBase* node, int32_t mode) : - NodeGraphOp(node, 0, 4, 4), - mMode(mode) + + static const int8_t mNumDefaultInputs = 6; + 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) : + NodeGraphOp(node, mNumDefaultInputs + numInputs, mNumDefaultOutputs + numOutputs, numConstants), + mName(name) {} - virtual ~GraphSourceConstants() = default; - virtual void Reset(); - virtual void Process(int32_t numSamples, std::vector& inputs, std::vector& outputs) override; - virtual void Tick(int32_t, float) override; - virtual std::string_view GetName() override { - switch (mMode) { - case 0: - return "Constant [0,1]"; - case 1: - return "Constant [-1,1]"; - case 2: - return "Constant [0,100]"; - case 3: - return "Constant [-inf,inf]"; - }; + std::string defaultInStrings[mNumDefaultInputs] = { "Reset", "Freq", "Volume", "Smooth", "Cutoff", "Resonance"}; + std::string defaultOutStrings[mNumDefaultOutputs] = { "Out" }; + + virtual ~GraphSignalBase() = default; + virtual void Reset() override final; + virtual void Process(int32_t numSamples, std::vector& inputs, std::vector& outputs) override final; + virtual bool IsDataVisible(int8_t) override { return true; } + virtual bool IsDataEditable(int8_t) override { return true; } + virtual std::string_view GetInputName(int8_t inputChannel) override final { + if (inputChannel >= mNumDefaultInputs) return GetInputNameExtra(inputChannel - mNumDefaultInputs); + if (inputChannel >= 0) return defaultInStrings[static_cast(inputChannel)]; return ""; } - virtual bool IsDataVisible(int8_t) override {return true;} - virtual bool IsDataEditable(int8_t) override {return true;} + virtual std::string_view GetOutputName(int8_t outputChannel) override final { + if (outputChannel >= mNumDefaultOutputs) return GetOutputNameExtra(outputChannel - mNumDefaultOutputs); + return defaultOutStrings[outputChannel]; + } + virtual std::string_view GetName() override { + return mName; + } + + virtual std::string_view GetInputNameExtra(int8_t) { return ""; }; + virtual std::string_view GetOutputNameExtra(int8_t) { return ""; }; + virtual void ResetSignal() {}; + virtual void UpdateSignal(std::vector&, std::vector&) {}; + virtual float GenerateSignal(float deltaPhase) = 0; protected: - int32_t mMode; - float mMax = 1.0f; - float mMin = 0.0f; + std::string mName; + + float mReset = 0.0f; + float mFreq = 0.0f; + float mVolume = 0.0f; + float mSmooth = 0.5f; + float mSignal = 0.0f; + float mWave = 0.0f; + float mDeltaPhase = 0.0f; + float mDeltaTime = 0.0f; + float mVolumeTarget = 0.0f; + float mSamplesUntilUpdate = 0.0f; + float mUpdateSamples = 256.0f; + + // high pass + float mHPCutoff = 0.5f; + float mHPResonance = 0.0001f; + float mHPState0 = 0.0f; + float mHPState1 = 0.0f; }; /*********************************************************************/ - class GraphSourceTime : public NodeGraphOp { + class GraphSignalSine2 : public GraphSignalBase { public: - GraphSourceTime(NodeGraphBase* node) : - NodeGraphOp(node, 0, 2, 0) + GraphSignalSine2(NodeGraphBase* node) : + GraphSignalBase(node, "Sine 2", 2) {} + std::string extraString[2] = { "Fmod", "Phase" }; - std::string defaultOutStrings[2] = { "Audio Time", "Frame Time"}; - - virtual ~GraphSourceTime() = default; - virtual void Reset() override; - virtual void Process(int32_t numSamples, std::vector& inputs, std::vector& outputs) override; - virtual void Tick(int32_t, float) override; - virtual std::string_view GetOutputName(int8_t outputChannel) override { - return defaultOutStrings[outputChannel]; - } - virtual std::string_view GetName() override { - return "Time"; + virtual ~GraphSignalSine2() = default; + virtual std::string_view GetInputNameExtra(int8_t extraInputChannel) override { + if(extraInputChannel < 2) return extraString[static_cast(extraInputChannel)]; + return ""; } - virtual bool IsDataVisible(int8_t) override { return true; } - virtual bool IsDataEditable(int8_t) override { return true; } + void ResetSignal() override; + void UpdateSignal(std::vector& inputs, std::vector& outputs) override; + float GenerateSignal(float deltaPhase) override; protected: - float mAudioTime = 0.0f; - float mFrameTime = 0.0f; + float mFmod = 0.0f; + float mPmod = 0.0f; + float mPhase = 0.0f; + float mPhaseFmod = 0.0f; }; /*********************************************************************/ - class GraphSourceSine : public NodeGraphOp { + class GraphSignalSine : public NodeGraphOp { public: - GraphSourceSine(NodeGraphBase* node) : - NodeGraphOp(node, 5, 1) + GraphSignalSine(NodeGraphBase* node) : + NodeGraphOp(node, 6, 1) {} - std::string defaultInStrings[5] = { "Freq", "Volume", "Fmod", "Phase", "Reset"}; + std::string defaultInStrings[6] = { "Freq", "Volume", "Fmod", "Phase", "Smooth", "Reset"}; std::string defaultOutStrings[1] = { "Out"}; - virtual ~GraphSourceSine() = default; + virtual ~GraphSignalSine() = default; virtual void Reset() override; virtual void Process(int32_t numSamples, std::vector& inputs, std::vector& outputs) override; virtual bool IsDataVisible(int8_t) override { return true; } @@ -125,16 +146,16 @@ namespace l::nodegraph { }; /*********************************************************************/ - class GraphSourceSineFM : public NodeGraphOp { + class GraphSignalSineFM : public NodeGraphOp { public: - GraphSourceSineFM(NodeGraphBase* node) : - NodeGraphOp(node, 8, 1) + GraphSignalSineFM(NodeGraphBase* node) : + NodeGraphOp(node, 9, 1) {} - std::string defaultInStrings[8] = { "Freq", "Volume", "Fmod", "FmodFreq", "FmodVol", "FmodOfs", "FmodGain", "Reset"}; + std::string defaultInStrings[9] = { "Freq", "Volume", "Fmod", "FmodFreq", "FmodVol", "FmodOfs", "FmodGain", "Smooth", "Reset"}; std::string defaultOutStrings[1] = { "Out" }; - virtual ~GraphSourceSineFM() = default; + virtual ~GraphSignalSineFM() = default; virtual void Reset() override; virtual void Process(int32_t numSamples, std::vector& inputs, std::vector& outputs) override; virtual bool IsDataVisible(int8_t) override { return true; } @@ -171,16 +192,16 @@ namespace l::nodegraph { }; /*********************************************************************/ - class GraphSourceSineFM2 : public NodeGraphOp { + class GraphSignalSineFM2 : public NodeGraphOp { public: - GraphSourceSineFM2(NodeGraphBase* node) : - NodeGraphOp(node, 5, 1) + GraphSignalSineFM2(NodeGraphBase* node) : + NodeGraphOp(node, 6, 1) {} - std::string defaultInStrings[5] = { "Freq", "Volume", "FmodVol", "FmodFreq", "Reset" }; + std::string defaultInStrings[6] = { "Freq", "Volume", "FmodVol", "FmodFreq", "Smooth", "Reset" }; std::string defaultOutStrings[1] = { "Out" }; - virtual ~GraphSourceSineFM2() = default; + virtual ~GraphSignalSineFM2() = default; virtual void Reset() override; virtual void Process(int32_t numSamples, std::vector& inputs, std::vector& outputs) override; virtual bool IsDataVisible(int8_t) override { return true; } @@ -212,16 +233,16 @@ namespace l::nodegraph { }; /*********************************************************************/ - class GraphSourceSineFM3 : public NodeGraphOp { + class GraphSignalSineFM3 : public NodeGraphOp { public: - GraphSourceSineFM3(NodeGraphBase* node) : - NodeGraphOp(node, 4, 1) + GraphSignalSineFM3(NodeGraphBase* node) : + NodeGraphOp(node, 5, 1) {} - std::string defaultInStrings[4] = { "Freq", "Volume", "Fmod", "Reset" }; + std::string defaultInStrings[5] = { "Freq", "Volume", "Fmod", "Smooth", "Reset" }; std::string defaultOutStrings[1] = { "Out" }; - virtual ~GraphSourceSineFM3() = default; + virtual ~GraphSignalSineFM3() = default; virtual void Reset() override; virtual void Process(int32_t numSamples, std::vector& inputs, std::vector& outputs) override; virtual bool IsDataVisible(int8_t) override { return true; } @@ -250,16 +271,16 @@ namespace l::nodegraph { }; /*********************************************************************/ - class GraphSourceSaw : public NodeGraphOp { + class GraphSignalSaw : public NodeGraphOp { public: - GraphSourceSaw(NodeGraphBase* node) : - NodeGraphOp(node, 5, 1) + GraphSignalSaw(NodeGraphBase* node) : + NodeGraphOp(node, 6, 1) {} - std::string defaultInStrings[5] = { "Freq", "Volume", "Fmod", "Phase", "Reset" }; + std::string defaultInStrings[6] = { "Freq", "Volume", "Fmod", "Phase", "Smooth", "Reset" }; std::string defaultOutStrings[1] = { "Out" }; - virtual ~GraphSourceSaw() = default; + virtual ~GraphSignalSaw() = default; virtual void Reset() override; virtual void Process(int32_t numSamples, std::vector& inputs, std::vector& outputs) override; virtual bool IsDataVisible(int8_t) override { return true; } diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSource.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSource.h new file mode 100644 index 00000000..381b8ae8 --- /dev/null +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSource.h @@ -0,0 +1,85 @@ +#pragma once +#include "nodegraph/core/NodeGraphBase.h" + +#include "logging/LoggingAll.h" + +#include "hid/KeyboardPiano.h" +#include "hid/Midi.h" + +#include "audio/PortAudio.h" +#include "audio/AudioUtils.h" + +#include "math/MathFunc.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace l::nodegraph { + + /*********************************************************************/ + class GraphSourceConstants : public NodeGraphOp { + public: + GraphSourceConstants(NodeGraphBase* node, int32_t mode) : + NodeGraphOp(node, 0, 4, 4), + mMode(mode) + {} + + virtual ~GraphSourceConstants() = default; + virtual void Reset(); + virtual void Process(int32_t numSamples, std::vector& inputs, std::vector& outputs) override; + virtual void Tick(int32_t, float) override; + virtual std::string_view GetName() override { + switch (mMode) { + case 0: + return "Constant [0,1]"; + case 1: + return "Constant [-1,1]"; + case 2: + return "Constant [0,100]"; + case 3: + return "Constant [-inf,inf]"; + }; + return ""; + } + virtual bool IsDataVisible(int8_t) override {return true;} + virtual bool IsDataEditable(int8_t) override {return true;} + protected: + int32_t mMode; + float mMax = 1.0f; + float mMin = 0.0f; + }; + + /*********************************************************************/ + class GraphSourceTime : public NodeGraphOp { + public: + GraphSourceTime(NodeGraphBase* node) : + NodeGraphOp(node, 0, 2, 0) + {} + + std::string defaultOutStrings[2] = { "Audio Time", "Frame Time"}; + + virtual ~GraphSourceTime() = default; + virtual void Reset() override; + virtual void Process(int32_t numSamples, std::vector& inputs, std::vector& outputs) override; + virtual void Tick(int32_t, float) override; + virtual std::string_view GetOutputName(int8_t outputChannel) override { + return defaultOutStrings[outputChannel]; + } + virtual std::string_view GetName() override { + return "Time"; + } + virtual bool IsDataVisible(int8_t) override { return true; } + virtual bool IsDataEditable(int8_t) override { return true; } + protected: + float mAudioTime = 0.0f; + float mFrameTime = 0.0f; + }; + +} + diff --git a/packages/nodegraph/source/common/NodeGraphSchema.cpp b/packages/nodegraph/source/common/NodeGraphSchema.cpp index 3a08019f..527bf93a 100644 --- a/packages/nodegraph/source/common/NodeGraphSchema.cpp +++ b/packages/nodegraph/source/common/NodeGraphSchema.cpp @@ -40,21 +40,6 @@ namespace l::nodegraph { case 4: node = mMainNodeGraph.NewNode(OutputType::Default); break; - case 5: - node = mMainNodeGraph.NewNode(OutputType::Default); - break; - case 6: - node = mMainNodeGraph.NewNode(OutputType::Default); - break; - case 7: - node = mMainNodeGraph.NewNode(OutputType::Default); - break; - case 8: - node = mMainNodeGraph.NewNode(OutputType::Default); - break; - case 9: - node = mMainNodeGraph.NewNode(OutputType::Default); - break; case 50: node = mMainNodeGraph.NewNode(OutputType::Default); break; @@ -91,6 +76,9 @@ namespace l::nodegraph { case 150: node = mMainNodeGraph.NewNode(OutputType::Default); break; + case 151: + node = mMainNodeGraph.NewNode(OutputType::Default); + break; case 200: node = mMainNodeGraph.NewNode(OutputType::ExternalOutput); break; @@ -148,6 +136,25 @@ namespace l::nodegraph { case 307: node = mMainNodeGraph.NewNode(OutputType::Default, mMidiManager, 4); break; + case 350: + node = mMainNodeGraph.NewNode(OutputType::Default); + break; + case 351: + node = mMainNodeGraph.NewNode(OutputType::Default); + break; + case 352: + node = mMainNodeGraph.NewNode(OutputType::Default); + break; + case 353: + node = mMainNodeGraph.NewNode(OutputType::Default); + break; + case 354: + node = mMainNodeGraph.NewNode(OutputType::Default); + break; + case 355: + node = mMainNodeGraph.NewNode(OutputType::Default); + break; + default: ASSERT(typeId < 10000) << "Custom node id's begin at id 1000"; diff --git a/packages/nodegraph/source/common/NodeGraph.cpp b/packages/nodegraph/source/common/core/NodeGraphBase.cpp similarity index 65% rename from packages/nodegraph/source/common/NodeGraph.cpp rename to packages/nodegraph/source/common/core/NodeGraphBase.cpp index e6b27df3..ff495612 100644 --- a/packages/nodegraph/source/common/NodeGraph.cpp +++ b/packages/nodegraph/source/common/core/NodeGraphBase.cpp @@ -1,4 +1,5 @@ -#include "nodegraph/NodeGraph.h" +#include "nodegraph/core/NodeGraphBase.h" +#include "nodegraph/core/NodeGraphGroup.h" #include "logging/Log.h" @@ -6,15 +7,15 @@ namespace l::nodegraph { - bool IsValidInOutNum(int8_t inoutNum, size_t inoutSize) { - return inoutNum >= 0 && inoutSize < 256u && inoutNum < static_cast(inoutSize); - } - int32_t CreateUniqueId() { static int32_t id = 1; return id++; } + bool IsValidInOutNum(int8_t inoutNum, size_t inoutSize) { + return inoutNum >= 0 && inoutSize < 256u && inoutNum < static_cast(inoutSize); + } + void NodeGraphBase::SetNumInputs(int8_t numInputs) { mInputCount = numInputs; mInputs.resize(mInputCount + mConstantCount); @@ -173,6 +174,7 @@ namespace l::nodegraph { return false; } auto& input = mInputs.at(inputChannel); + constant = l::math::functions::clamp(constant, input.mBoundMin, input.mBoundMax); if (size <= 0) { input.mInput.mInputFloatConstant = constant; input.mInputType = InputType::INPUT_CONSTANT; @@ -358,191 +360,4 @@ namespace l::nodegraph { return ""; } - void GraphDataCopy::Process(int32_t, std::vector& inputs, std::vector& outputs) { - for (size_t i = 0; i < inputs.size() && i < outputs.size(); i++) { - outputs.at(i).mOutput = inputs.at(i).Get(); - } - } - - void NodeGraphInput::Reset() { - if (mInputType == InputType::INPUT_NODE || mInputType == InputType::INPUT_VALUE) { - mInput.mInputNode = nullptr; - mInputType = InputType::INPUT_EMPTY; - mInputFromOutputChannel = 0; - } - } - - bool NodeGraphInput::HasInputNode() { - if (mInputType == InputType::INPUT_NODE) { - return true; - } - return false; - } - - float NodeGraphInput::Get() { - float value = 0.0f; - switch (mInputType) { - case InputType::INPUT_NODE: - if (mInput.mInputNode != nullptr) { - value = mInput.mInputNode->GetOutput(mInputFromOutputChannel); - } - break; - case InputType::INPUT_CONSTANT: - value = mInput.mInputFloatConstant; - break; - case InputType::INPUT_ARRAY: - return *mInputBuf->data(); - case InputType::INPUT_VALUE: - value = *mInput.mInputFloat; - break; - case InputType::INPUT_EMPTY: - break; - } - return l::math::functions::clamp(value, mBoundMin, mBoundMax); - } - - float& NodeGraphInput::Get(int32_t size) { - switch (mInputType) { - case InputType::INPUT_NODE: - if (mInput.mInputNode != nullptr) { - return mInput.mInputNode->GetOutput(mInputFromOutputChannel, size); - } - break; - case InputType::INPUT_ARRAY: - if (!mInputBuf) { - mInputBuf = std::make_unique>(); - } - if (static_cast(mInputBuf->size()) < size) { - mInputBuf->resize(size); - } - return *mInputBuf->data(); - case InputType::INPUT_CONSTANT: - return mInput.mInputFloatConstant; - case InputType::INPUT_VALUE: - return *mInput.mInputFloat; - case InputType::INPUT_EMPTY: - break; - } - return mInput.mInputFloatConstant; - } - - void NodeGraphGroup::SetNumInputs(int8_t numInputs) { - mInputNode.SetNumInputs(numInputs); - mInputNode.SetNumOutputs(numInputs); - } - - void NodeGraphGroup::SetNumOutputs(int8_t outputCount) { - mOutputNode.SetNumInputs(outputCount); - mOutputNode.SetNumOutputs(outputCount); - } - - void NodeGraphGroup::SetInput(int8_t inputChannel, NodeGraphBase& source, int8_t sourceOutputChannel) { - mInputNode.SetInput(inputChannel, source, sourceOutputChannel); - } - - void NodeGraphGroup::SetInput(int8_t inputChannel, NodeGraphGroup& source, int8_t sourceOutputChannel) { - mInputNode.SetInput(inputChannel, source, sourceOutputChannel); - } - - void NodeGraphGroup::SetInput(int8_t inputChannel, float constant) { - mInputNode.SetInput(inputChannel, constant); - } - - void NodeGraphGroup::SetInput(int8_t inputChannel, float* floatPtr) { - mInputNode.SetInput(inputChannel, floatPtr); - } - - void NodeGraphGroup::SetOutput(int8_t outputChannel, NodeGraphBase& source, int8_t sourceOutputChannel) { - mOutputNode.SetInput(outputChannel, source, sourceOutputChannel); - mOutputNode.SetOutputName(outputChannel, source.GetOutputName(sourceOutputChannel)); - } - - void NodeGraphGroup::SetOutput(int8_t outputChannel, NodeGraphGroup& source, int8_t sourceOutputChannel) { - mOutputNode.SetInput(outputChannel, source, sourceOutputChannel); - mOutputNode.SetOutputName(outputChannel, source.GetOutputNode().GetOutputName(sourceOutputChannel)); - } - - float NodeGraphGroup::GetOutput(int8_t outputChannel) { - return mOutputNode.GetOutput(outputChannel); - } - - NodeGraphBase& NodeGraphGroup::GetInputNode() { - return mInputNode; - } - - NodeGraphBase& NodeGraphGroup::GetOutputNode() { - return mOutputNode; - } - - bool NodeGraphGroup::ContainsNode(int32_t id) { - auto it = std::find_if(mNodes.begin(), mNodes.end(), [&](const std::unique_ptr& node) { - if (node->GetId() == id) { - return true; - } - return false; - }); - if (it != mNodes.end()) { - return true; - } - return false; - } - - NodeGraphBase* NodeGraphGroup::GetNode(int32_t id) { - auto it = std::find_if(mNodes.begin(), mNodes.end(), [&](const std::unique_ptr& node) { - if (node->GetId() == id) { - return true; - } - return false; - }); - if (it != mNodes.end()) { - return it->get(); - } - return nullptr; - } - - bool NodeGraphGroup::RemoveNode(int32_t id) { - auto node = GetNode(id); - int32_t sourceCount = 0; - for (auto& it : mNodes) { - if (it->RemoveInput(node)) { - sourceCount++; - } - } - std::erase_if(mOutputNodes, [&](NodeGraphBase* nodePtr) { - if (nodePtr == node) { - return true; - } - return false; - }); - auto count = std::erase_if(mNodes, [&](const std::unique_ptr& node) { - if (node->GetId() == id) { - return true; - } - return false; - }); - return count > 0 ? true : false; - } - - void NodeGraphGroup::ClearProcessFlags() { - mOutputNode.ClearProcessFlags(); - } - - void NodeGraphGroup::ProcessSubGraph(int32_t numSamples, bool) { - for (auto& it : mOutputNodes) { - it->ClearProcessFlags(); - } - for (auto& it : mOutputNodes) { - it->ProcessSubGraph(numSamples, false); - } - } - - void NodeGraphGroup::Tick(int32_t tickCount, float elapsed) { - if (tickCount <= mLastTickCount) { - return; - } - for (auto& it : mNodes) { - it->Tick(tickCount, elapsed); - } - mLastTickCount = tickCount; - } } \ No newline at end of file diff --git a/packages/nodegraph/source/common/core/NodeGraphGroup.cpp b/packages/nodegraph/source/common/core/NodeGraphGroup.cpp new file mode 100644 index 00000000..7c6a3aab --- /dev/null +++ b/packages/nodegraph/source/common/core/NodeGraphGroup.cpp @@ -0,0 +1,135 @@ +#include "nodegraph/core/NodeGraphBase.h" +#include "nodegraph/core/NodeGraphGroup.h" + +#include "logging/Log.h" + +#include "math/MathFunc.h" + +namespace l::nodegraph { + + void GraphDataCopy::Process(int32_t, std::vector& inputs, std::vector& outputs) { + for (size_t i = 0; i < inputs.size() && i < outputs.size(); i++) { + outputs.at(i).mOutput = inputs.at(i).Get(); + } + } + + void NodeGraphGroup::SetNumInputs(int8_t numInputs) { + mInputNode.SetNumInputs(numInputs); + mInputNode.SetNumOutputs(numInputs); + } + + void NodeGraphGroup::SetNumOutputs(int8_t outputCount) { + mOutputNode.SetNumInputs(outputCount); + mOutputNode.SetNumOutputs(outputCount); + } + + void NodeGraphGroup::SetInput(int8_t inputChannel, NodeGraphBase& source, int8_t sourceOutputChannel) { + mInputNode.SetInput(inputChannel, source, sourceOutputChannel); + } + + void NodeGraphGroup::SetInput(int8_t inputChannel, NodeGraphGroup& source, int8_t sourceOutputChannel) { + mInputNode.SetInput(inputChannel, source, sourceOutputChannel); + } + + void NodeGraphGroup::SetInput(int8_t inputChannel, float constant) { + mInputNode.SetInput(inputChannel, constant); + } + + void NodeGraphGroup::SetInput(int8_t inputChannel, float* floatPtr) { + mInputNode.SetInput(inputChannel, floatPtr); + } + + void NodeGraphGroup::SetOutput(int8_t outputChannel, NodeGraphBase& source, int8_t sourceOutputChannel) { + mOutputNode.SetInput(outputChannel, source, sourceOutputChannel); + mOutputNode.SetOutputName(outputChannel, source.GetOutputName(sourceOutputChannel)); + } + + void NodeGraphGroup::SetOutput(int8_t outputChannel, NodeGraphGroup& source, int8_t sourceOutputChannel) { + mOutputNode.SetInput(outputChannel, source, sourceOutputChannel); + mOutputNode.SetOutputName(outputChannel, source.GetOutputNode().GetOutputName(sourceOutputChannel)); + } + + float NodeGraphGroup::GetOutput(int8_t outputChannel) { + return mOutputNode.GetOutput(outputChannel); + } + + NodeGraphBase& NodeGraphGroup::GetInputNode() { + return mInputNode; + } + + NodeGraphBase& NodeGraphGroup::GetOutputNode() { + return mOutputNode; + } + + bool NodeGraphGroup::ContainsNode(int32_t id) { + auto it = std::find_if(mNodes.begin(), mNodes.end(), [&](const std::unique_ptr& node) { + if (node->GetId() == id) { + return true; + } + return false; + }); + if (it != mNodes.end()) { + return true; + } + return false; + } + + NodeGraphBase* NodeGraphGroup::GetNode(int32_t id) { + auto it = std::find_if(mNodes.begin(), mNodes.end(), [&](const std::unique_ptr& node) { + if (node->GetId() == id) { + return true; + } + return false; + }); + if (it != mNodes.end()) { + return it->get(); + } + return nullptr; + } + + bool NodeGraphGroup::RemoveNode(int32_t id) { + auto node = GetNode(id); + int32_t sourceCount = 0; + for (auto& it : mNodes) { + if (it->RemoveInput(node)) { + sourceCount++; + } + } + std::erase_if(mOutputNodes, [&](NodeGraphBase* nodePtr) { + if (nodePtr == node) { + return true; + } + return false; + }); + auto count = std::erase_if(mNodes, [&](const std::unique_ptr& node) { + if (node->GetId() == id) { + return true; + } + return false; + }); + return count > 0 ? true : false; + } + + void NodeGraphGroup::ClearProcessFlags() { + mOutputNode.ClearProcessFlags(); + } + + void NodeGraphGroup::ProcessSubGraph(int32_t numSamples, bool) { + for (auto& it : mOutputNodes) { + it->ClearProcessFlags(); + } + for (auto& it : mOutputNodes) { + it->ProcessSubGraph(numSamples, false); + } + } + + void NodeGraphGroup::Tick(int32_t tickCount, float elapsed) { + if (tickCount <= mLastTickCount) { + return; + } + for (auto& it : mNodes) { + it->Tick(tickCount, elapsed); + } + mLastTickCount = tickCount; + } +} \ No newline at end of file diff --git a/packages/nodegraph/source/common/core/NodeGraphInput.cpp b/packages/nodegraph/source/common/core/NodeGraphInput.cpp new file mode 100644 index 00000000..51456423 --- /dev/null +++ b/packages/nodegraph/source/common/core/NodeGraphInput.cpp @@ -0,0 +1,71 @@ +#include "nodegraph/core/NodeGraphInput.h" +#include "nodegraph/core/NodeGraphBase.h" + +#include "logging/Log.h" + +#include "math/MathFunc.h" + +namespace l::nodegraph { + void NodeGraphInput::Reset() { + if (mInputType == InputType::INPUT_NODE || mInputType == InputType::INPUT_VALUE) { + mInput.mInputNode = nullptr; + mInputType = InputType::INPUT_EMPTY; + mInputFromOutputChannel = 0; + } + } + + bool NodeGraphInput::HasInputNode() { + if (mInputType == InputType::INPUT_NODE) { + return true; + } + return false; + } + + float NodeGraphInput::Get() { + float value = 0.0f; + switch (mInputType) { + case InputType::INPUT_NODE: + if (mInput.mInputNode != nullptr) { + value = mInput.mInputNode->GetOutput(mInputFromOutputChannel); + } + break; + case InputType::INPUT_CONSTANT: + value = mInput.mInputFloatConstant; + break; + case InputType::INPUT_ARRAY: + return *mInputBuf->data(); + case InputType::INPUT_VALUE: + value = *mInput.mInputFloat; + break; + case InputType::INPUT_EMPTY: + break; + } + return l::math::functions::clamp(value, mBoundMin, mBoundMax); + } + + float& NodeGraphInput::Get(int32_t size) { + switch (mInputType) { + case InputType::INPUT_NODE: + if (mInput.mInputNode != nullptr) { + return mInput.mInputNode->GetOutput(mInputFromOutputChannel, size); + } + break; + case InputType::INPUT_ARRAY: + if (!mInputBuf) { + mInputBuf = std::make_unique>(); + } + if (static_cast(mInputBuf->size()) < size) { + mInputBuf->resize(size); + } + return *mInputBuf->data(); + case InputType::INPUT_CONSTANT: + return mInput.mInputFloatConstant; + case InputType::INPUT_VALUE: + return *mInput.mInputFloat; + case InputType::INPUT_EMPTY: + break; + } + return mInput.mInputFloatConstant; + } + +} \ No newline at end of file diff --git a/packages/nodegraph/source/common/core/NodeGraphOutput.cpp b/packages/nodegraph/source/common/core/NodeGraphOutput.cpp new file mode 100644 index 00000000..1d1eff1c --- /dev/null +++ b/packages/nodegraph/source/common/core/NodeGraphOutput.cpp @@ -0,0 +1,42 @@ +#include "nodegraph/core/NodeGraphOutput.h" + +#include "logging/Log.h" + +#include "math/MathFunc.h" + +namespace l::nodegraph { + float& NodeGraphOutput::GetOutput(int32_t size) { + if (!mOutputBuf) { + if (size <= 1) { + mOutputPolled = true; + return mOutput; + } + else { + mOutputBuf = std::make_unique>(); + } + } + if (static_cast(mOutputBuf->size()) < size) { + mOutputBuf->resize(size); + } + mOutputPolled = true; + return *mOutputBuf->data(); + } + + int32_t NodeGraphOutput::GetOutputSize() { + if (!mOutputBuf) { + return 1; + } + else { + return static_cast(mOutputBuf->size()); + } + } + + bool NodeGraphOutput::IsOutputPolled() { + return mOutputPolled; + } + + void NodeGraphOutput::ResetOutputPollState() { + mOutputPolled = false; + } + +} \ No newline at end of file diff --git a/packages/nodegraph/source/common/NodeGraphOpEffect.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpEffect.cpp similarity index 99% rename from packages/nodegraph/source/common/NodeGraphOpEffect.cpp rename to packages/nodegraph/source/common/operations/NodeGraphOpEffect.cpp index f35dd0b2..c497b369 100644 --- a/packages/nodegraph/source/common/NodeGraphOpEffect.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpEffect.cpp @@ -1,4 +1,4 @@ -#include "nodegraph/NodeGraphOpEffect.h" +#include "nodegraph/operations/NodeGraphOpEffect.h" #include "logging/Log.h" #include "audio/AudioUtils.h" diff --git a/packages/nodegraph/source/common/NodeGraphOpFilter.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpFilter.cpp similarity index 52% rename from packages/nodegraph/source/common/NodeGraphOpFilter.cpp rename to packages/nodegraph/source/common/operations/NodeGraphOpFilter.cpp index 6c73d713..0bc5e164 100644 --- a/packages/nodegraph/source/common/NodeGraphOpFilter.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpFilter.cpp @@ -1,4 +1,4 @@ -#include "nodegraph/NodeGraphOpFilter.h" +#include "nodegraph/operations/NodeGraphOpFilter.h" #include "logging/Log.h" #include "audio/AudioUtils.h" @@ -35,4 +35,28 @@ namespace l::nodegraph { outputs.at(0).mOutput = -mState1; } + /*********************************************************************/ + void GraphFilterHighpass::Reset() { + mState0 = 0.0f; + mState1 = 0.0f; + mNode->SetInput(1, 0.99f); + mNode->SetInput(2, 0.01f); + mNode->SetInputBound(1, InputBound::INPUT_0_TO_1); + mNode->SetInputBound(2, InputBound::INPUT_0_TO_1); + } + + void GraphFilterHighpass::Process(int32_t, std::vector& inputs, std::vector& outputs) { + float inputValue = inputs.at(0).Get(); + float cutoff = inputs.at(1).Get(); + float resonance = 1.0f - inputs.at(2).Get(); + + cutoff *= cutoff; + float rc = 1.0f - resonance * cutoff; + + float v01 = mState0 - mState1; + mState0 += cutoff * (inputValue - mState0 + rc * v01); + mState1 += cutoff * v01; + + outputs.at(0).mOutput = inputValue - mState1; + } } diff --git a/packages/nodegraph/source/common/NodeGraphOpInput.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpInput.cpp similarity index 99% rename from packages/nodegraph/source/common/NodeGraphOpInput.cpp rename to packages/nodegraph/source/common/operations/NodeGraphOpInput.cpp index 618fa266..f8f2550b 100644 --- a/packages/nodegraph/source/common/NodeGraphOpInput.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpInput.cpp @@ -1,4 +1,4 @@ -#include "nodegraph/NodeGraphOpInput.h" +#include "nodegraph/operations/NodeGraphOpInput.h" #include "logging/Log.h" #include "audio/AudioUtils.h" diff --git a/packages/nodegraph/source/common/NodeGraphOpLogic.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpLogic.cpp similarity index 72% rename from packages/nodegraph/source/common/NodeGraphOpLogic.cpp rename to packages/nodegraph/source/common/operations/NodeGraphOpLogic.cpp index bdbc995d..fd92df2f 100644 --- a/packages/nodegraph/source/common/NodeGraphOpLogic.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpLogic.cpp @@ -1,4 +1,4 @@ -#include "nodegraph/NodeGraphOpLogic.h" +#include "nodegraph/operations/NodeGraphOpLogic.h" #include "logging/Log.h" #include "audio/AudioUtils.h" diff --git a/packages/nodegraph/source/common/NodeGraphOpNumeric.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpNumeric.cpp similarity index 71% rename from packages/nodegraph/source/common/NodeGraphOpNumeric.cpp rename to packages/nodegraph/source/common/operations/NodeGraphOpNumeric.cpp index 5235cb40..98b6df0e 100644 --- a/packages/nodegraph/source/common/NodeGraphOpNumeric.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpNumeric.cpp @@ -1,4 +1,4 @@ -#include "nodegraph/NodeGraphOpNumeric.h" +#include "nodegraph/operations/NodeGraphOpNumeric.h" #include "logging/Log.h" #include "audio/AudioUtils.h" diff --git a/packages/nodegraph/source/common/NodeGraphOpOutput.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpOutput.cpp similarity index 98% rename from packages/nodegraph/source/common/NodeGraphOpOutput.cpp rename to packages/nodegraph/source/common/operations/NodeGraphOpOutput.cpp index 2a7ae886..f15c0228 100644 --- a/packages/nodegraph/source/common/NodeGraphOpOutput.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpOutput.cpp @@ -1,4 +1,4 @@ -#include "nodegraph/NodeGraphOpOutput.h" +#include "nodegraph/operations/NodeGraphOpOutput.h" #include "logging/Log.h" #include "audio/AudioUtils.h" diff --git a/packages/nodegraph/source/common/NodeGraphOpSource.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpSignal.cpp similarity index 65% rename from packages/nodegraph/source/common/NodeGraphOpSource.cpp rename to packages/nodegraph/source/common/operations/NodeGraphOpSignal.cpp index 64eb49ca..d95b4c88 100644 --- a/packages/nodegraph/source/common/NodeGraphOpSource.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpSignal.cpp @@ -1,4 +1,4 @@ -#include "nodegraph/NodeGraphOpSource.h" +#include "nodegraph/operations/NodeGraphOpSignal.h" #include "logging/Log.h" #include "audio/AudioUtils.h" @@ -9,87 +9,150 @@ namespace l::nodegraph { - /* Mathematical operations */ - /*********************************************************************/ - void GraphSourceConstants::Reset() { - switch (mMode) { - case 0: - for (int8_t i = 0; i < 4; i++) { - mNode->SetInputBound(i, InputBound::INPUT_0_TO_1); - } - break; - case 1: - for (int8_t i = 0; i < 4; i++) { - mNode->SetInputBound(i, InputBound::INPUT_NEG_1_POS_1); - } - break; - case 2: - for (int8_t i = 0; i < 4; i++) { - mNode->SetInputBound(i, InputBound::INPUT_0_100); - } - break; - default: - for (int8_t i = 0; i < 4; i++) { - mNode->SetInputBound(i, InputBound::INPUT_UNBOUNDED); - } - break; - } - } + void GraphSignalBase::Reset() { + mFreq = 0.0f; + mVolumeTarget = 0.0f; + mSmooth = 0.5f; + mSignal = 0.0f; + mWave = 0.0f; + mDeltaPhase = 0.0f; + mDeltaTime = 0.0f; + mVolume = 0.0f; + mSamplesUntilUpdate = 0.0f; + mUpdateSamples = 256.0f; + mHPCutoff = 0.5f; + mHPResonance = 0.0001f; + mHPState0 = 0.0f; + mHPState1 = 0.0f; + mHPCutoff = 0.0f; - void GraphSourceConstants::Process(int32_t, std::vector& inputs, std::vector& outputs) { - for (int8_t i = 0; i < mNumOutputs; i++) { - outputs.at(i).mOutput = inputs.at(i).Get(); - } + 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->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); + + ResetSignal(); } - void GraphSourceConstants::Tick(int32_t, float) { - mNode->ProcessSubGraph(1); + void GraphSignalBase::Process(int32_t numSamples, std::vector& inputs, std::vector& outputs) { + float* output0 = &outputs.at(0).GetOutput(numSamples); + + mSamplesUntilUpdate = l::audio::BatchUpdate(mUpdateSamples, mSamplesUntilUpdate, 0, numSamples, + [&]() { + mDeltaTime = 1.0f / 44100.0f; + mReset = inputs.at(0).Get(); + mFreq = inputs.at(1).Get(); + mVolumeTarget = inputs.at(2).Get(); + mSmooth = 0.5f * inputs.at(3).Get(); + + mDeltaPhase = mDeltaTime * mFreq; + float deltaPhaseExpanded = l::math::functions::pow(mDeltaPhase, 0.125f); + 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) { + mVolumeTarget = 0.0f; + } + + UpdateSignal(inputs, outputs); + + }, + [&](int32_t start, int32_t end, bool) { + for (int32_t i = start; i < end; i++) { + float signalTarget = GenerateSignal(mDeltaPhase); + + // highpass filter + { + //float deltaPhase2 = l::math::functions::pow(mDeltaPhase, 0.125f); + float cutoff = mHPCutoff; + cutoff *= cutoff; + float rc = 1.0f - mHPResonance * cutoff; + float v01 = mHPState0 - mHPState1; + mHPState0 += cutoff * (signalTarget - mHPState0 + rc * v01); + mHPState1 += cutoff * v01; + + signalTarget = signalTarget - mHPState1; + } + + mSignal += mSmooth * (signalTarget - mSignal); + mVolume += (1.0f / 256.0f) * (mVolumeTarget - mVolume); + *output0++ = mVolume * mSignal; + } + } + ); } /*********************************************************************/ - void GraphSourceTime::Process(int32_t, std::vector&, std::vector& outputs) { - float rate = 44100.0f; - float phaseChange = 1.0f / rate; - mAudioTime += phaseChange; - outputs.at(0).mOutput = mAudioTime; - outputs.at(1).mOutput = mFrameTime; + void GraphSignalSine2::ResetSignal() { + mNode->SetInput(mNumDefaultInputs + 0, 0.5f); + mNode->SetInput(mNumDefaultInputs + 1, 0.0f); + mNode->SetInputBound(mNumDefaultInputs + 0, InputBound::INPUT_0_TO_1); + mNode->SetInputBound(mNumDefaultInputs + 1, InputBound::INPUT_0_TO_1); } - void GraphSourceTime::Tick(int32_t, float deltaTime) { - mFrameTime += deltaTime; + 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)); } - void GraphSourceTime::Reset() { - mAudioTime = 0.0f; - mFrameTime = 0.0f; + float GraphSignalSine2::GenerateSignal(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)); + + mPhase += deltaPhase * modulation; + mPhase = l::math::functions::mod(mPhase, 1.0f); + + float phaseMod = mPhase + mPmod; + phaseMod = l::math::functions::mod(phaseMod, 1.0f); + + mWave = mSmooth * (mPhase + phaseMod - mWave); + return l::math::functions::sin(l::math::constants::PI_f * mWave); } /*********************************************************************/ - void GraphSourceSine::Reset() { + void GraphSignalSine::Reset() { // { "Freq Hz", "Freq Mod", "Phase Mod", "Reset"}; mPhase = 0.0f; mNode->SetInput(0, 0.0f); mNode->SetInput(1, 0.0f); mNode->SetInput(2, 1.0f); mNode->SetInput(3, 0.0f); - mNode->SetInput(4, 0.0f); + mNode->SetInput(4, 0.5f); + mNode->SetInput(5, 0.0f); mNode->SetInputBound(0, InputBound::INPUT_UNBOUNDED); mNode->SetInputBound(1, InputBound::INPUT_0_100); mNode->SetInputBound(2, InputBound::INPUT_0_TO_2); mNode->SetInputBound(3, InputBound::INPUT_0_TO_1); mNode->SetInputBound(4, InputBound::INPUT_0_TO_1); + mNode->SetInputBound(5, InputBound::INPUT_0_TO_1); } - void GraphSourceSine::Process(int32_t numSamples, std::vector& inputs, std::vector& outputs) { + void GraphSignalSine::Process(int32_t numSamples, std::vector& inputs, std::vector& outputs) { float* output0 = &outputs.at(0).GetOutput(numSamples); mSamplesUntilUpdate = l::audio::BatchUpdate(256.0f, mSamplesUntilUpdate, 0, numSamples, [&]() { mFreq = l::math::functions::max(static_cast(inputs.at(0).Get()), 0.0); mVolume = inputs.at(1).Get(); - mReset = inputs.at(4).Get(); + mReset = inputs.at(5).Get(); if (mFreq == 0.0f) { mVolume = 0.0f; @@ -106,6 +169,7 @@ namespace l::nodegraph { mFmod = static_cast(inputs.at(2).Get()); mPmod = static_cast(inputs.at(3).Get()); + double smooth = 0.5 * static_cast(inputs.at(4).Get()); double fmodRange = 16.0; mFmod = mFmod > 1.0 ? fmodRange * (mFmod - 1.0) : 1.0 / (1.0 + fmodRange * (1.0 - mFmod)); @@ -129,8 +193,8 @@ namespace l::nodegraph { double phaseMod = mPhase + mPmod; phaseMod = l::math::functions::mod(phaseMod, 1.0); - double sine = l::math::functions::sin(l::math::constants::PI * (mPhase + phaseMod)); - + mWave += smooth * (mPhase + phaseMod - mWave); + double sine = l::math::functions::sin(l::math::constants::PI * mWave); /* double phaseDelta = mDeltaTime * mFreq; @@ -145,16 +209,14 @@ namespace l::nodegraph { mVol += (1.0f / 256.0f) * (mVolume - mVol); - mWave += 0.25 * (sine - mWave); - - *output0++ = mVol * static_cast(mWave); + *output0++ = mVol * static_cast(sine); } } ); } /*********************************************************************/ - void GraphSourceSineFM::Reset() { + void GraphSignalSineFM::Reset() { // { "Note", "Volume", "Fmod", "FmodFreq", "FmodVol", "FmodOfs", "Reset"} mPhase = 0.0f; mNode->SetInput(0, 0.0f); @@ -164,7 +226,8 @@ namespace l::nodegraph { mNode->SetInput(4, 0.0f); mNode->SetInput(5, 0.0f); mNode->SetInput(6, 0.0f); - mNode->SetInput(7, 0.0f); + mNode->SetInput(7, 0.5f); + mNode->SetInput(8, 0.0f); mNode->SetInputBound(0, InputBound::INPUT_UNBOUNDED); mNode->SetInputBound(1, InputBound::INPUT_0_100); mNode->SetInputBound(2, InputBound::INPUT_UNBOUNDED); @@ -173,16 +236,17 @@ namespace l::nodegraph { mNode->SetInputBound(5, InputBound::INPUT_UNBOUNDED); mNode->SetInputBound(6, InputBound::INPUT_0_TO_1); mNode->SetInputBound(7, InputBound::INPUT_0_TO_1); + mNode->SetInputBound(8, InputBound::INPUT_0_TO_1); } - void GraphSourceSineFM::Process(int32_t numSamples, std::vector& inputs, std::vector& outputs) { + void GraphSignalSineFM::Process(int32_t numSamples, std::vector& inputs, std::vector& outputs) { float* output0 = &outputs.at(0).GetOutput(numSamples); mSamplesUntilUpdate = l::audio::BatchUpdate(256.0f, mSamplesUntilUpdate, 0, numSamples, [&]() { mFreq = l::math::functions::max(static_cast(inputs.at(0).Get()), 0.0); mVolume = inputs.at(1).Get(); - mReset = inputs.at(7).Get(); + mReset = inputs.at(8).Get(); if (mReset > 0.0f || mVolume + mVol < 0.0000001f) { mPhase = 0.0; @@ -201,6 +265,7 @@ namespace l::nodegraph { mFmodVol = static_cast(inputs.at(4).Get()); mFmodOfs = static_cast(inputs.at(5).Get()); double fmodGain = static_cast(inputs.at(6).Get()); + double smooth = 0.5 * static_cast(inputs.at(7).Get()); for (int32_t i = start; i < end; i++) { double phaseDelta2 = mDeltaTime * mFreq * mFmodFrq; @@ -214,41 +279,44 @@ namespace l::nodegraph { phaseDelta = l::math::functions::clamp(phaseDelta, phaseDelta2, 0.5); mPhase += phaseDelta; mPhase = l::math::functions::mod(mPhase, 1.0); - double waveTarget = l::math::functions::sin(l::math::constants::PI * mPhase * 2.0); + + mWave += smooth * (mPhase - mWave); + double out = l::math::functions::sin(l::math::constants::PI * mWave * 2.0); mVol += (1.0f / 256.0f) * (mVolume - mVol); - mWave += (waveTarget - mWave) * 0.5; - *output0++ = mVol * static_cast(mWave); + *output0++ = mVol * static_cast(out); } } ); } /*********************************************************************/ - void GraphSourceSineFM2::Reset() { + void GraphSignalSineFM2::Reset() { // { "Note", "Volume", "FmodVol", "FmodOfs", "Reset"} mPhase = 0.0f; mNode->SetInput(0, 0.0f); mNode->SetInput(1, 0.5f); mNode->SetInput(2, 0.0f); mNode->SetInput(3, 0.0f); - mNode->SetInput(4, 0.0f); + mNode->SetInput(4, 0.5f); + mNode->SetInput(5, 0.0f); mNode->SetInputBound(0, InputBound::INPUT_UNBOUNDED); mNode->SetInputBound(1, InputBound::INPUT_0_100); mNode->SetInputBound(2, InputBound::INPUT_0_TO_1); mNode->SetInputBound(3, InputBound::INPUT_0_100); mNode->SetInputBound(4, InputBound::INPUT_0_TO_1); + mNode->SetInputBound(5, InputBound::INPUT_0_TO_1); } - void GraphSourceSineFM2::Process(int32_t numSamples, std::vector& inputs, std::vector& outputs) { + void GraphSignalSineFM2::Process(int32_t numSamples, std::vector& inputs, std::vector& outputs) { float* output0 = &outputs.at(0).GetOutput(numSamples); mSamplesUntilUpdate = l::audio::BatchUpdate(256.0f, mSamplesUntilUpdate, 0, numSamples, [&]() { mFreq = l::math::functions::max(static_cast(inputs.at(0).Get()), 0.0); mVolume = inputs.at(1).Get(); - mReset = inputs.at(4).Get(); + mReset = inputs.at(5).Get(); if (mReset > 0.0f || mVolume + mVol < 0.0000001f) { mPhase = 0.0; @@ -265,6 +333,7 @@ namespace l::nodegraph { double fmMod = static_cast(inputs.at(2).Get()); double fmFreq = static_cast(inputs.at(3).Get()); + double smooth = 0.5 * static_cast(inputs.at(4).Get()); double limitFmMod = 1.0 / l::math::functions::max(mFreq / 25.0, 1.0); fmMod = 800.0 * fmMod * fmMod * limitFmMod; @@ -285,25 +354,25 @@ namespace l::nodegraph { mPhase += phaseDelta; mPhase = l::math::functions::mod(mPhase, 1.0); - double waveTarget = l::math::functions::sin(l::math::constants::PI * mPhase * 2.0); + mWave += smooth * (mPhase - mWave); + double out = l::math::functions::sin(l::math::constants::PI * mWave * 2.0); mVol += (1.0f / 256.0f) * (mVolume - mVol); - mWave += (waveTarget - mWave) * 0.5; - *output0++ = mVol * static_cast(mWave); + *output0++ = mVol * static_cast(out); } } ); } /*********************************************************************/ - void GraphSourceSineFM3::Reset() { + void GraphSignalSineFM3::Reset() { // { "Note", "Volume", "Fmod", "Reset"} mPhase = 0.0f; mNode->SetInput(0, 0.0f); mNode->SetInput(1, 0.5f); - mNode->SetInput(2, 0.0f); + mNode->SetInput(2, 0.5f); mNode->SetInput(3, 0.0f); mNode->SetInputBound(0, InputBound::INPUT_UNBOUNDED); mNode->SetInputBound(1, InputBound::INPUT_0_100); @@ -311,14 +380,14 @@ namespace l::nodegraph { mNode->SetInputBound(3, InputBound::INPUT_0_TO_1); } - void GraphSourceSineFM3::Process(int32_t numSamples, std::vector& inputs, std::vector& outputs) { + void GraphSignalSineFM3::Process(int32_t numSamples, std::vector& inputs, std::vector& outputs) { float* output0 = &outputs.at(0).GetOutput(numSamples); mSamplesUntilUpdate = l::audio::BatchUpdate(16.0f, mSamplesUntilUpdate, 0, numSamples, [&]() { mFreq = l::math::functions::max(static_cast(inputs.at(0).Get()), 0.0); mVolume = inputs.at(1).Get(); - mReset = inputs.at(3).Get(); + mReset = inputs.at(4).Get(); if (mReset > 0.0f || mVolume < 0.0000001f) { mPhase = 0.0; @@ -333,7 +402,7 @@ namespace l::nodegraph { [&](int32_t start, int32_t end, bool) { double fmMod = static_cast(inputs.at(2).Get()); - + double smooth = 0.5 * static_cast(inputs.at(3).Get()); double limitFmMod = 1.0 / l::math::functions::max(mFreq / 25.0, 1.0); double fm = 800.0 * fmMod * fmMod * limitFmMod; @@ -346,42 +415,44 @@ namespace l::nodegraph { double phaseDelta = mDeltaTime * mFreq * modulation; mPhase += phaseDelta; mPhase = l::math::functions::mod(mPhase, 1.0); - double waveTarget = l::math::functions::sin(l::math::constants::PI * mPhase * 2.0); + mWave += smooth * (mPhase - mWave); + double out = l::math::functions::sin(l::math::constants::PI * mWave * 2.0); mVol += (1.0f / 256.0f) * (mVolume - mVol); - mWave += (waveTarget - mWave) * 0.5; - *output0++ = mVol * static_cast(mWave); + *output0++ = mVol * static_cast(out); } } ); } /*********************************************************************/ - void GraphSourceSaw::Reset() { + void GraphSignalSaw::Reset() { // { "Freq", "Volume", "Fmod", "Phase", "Reset"}; mPhase = 0.0f; mNode->SetInput(0, 0.0f); mNode->SetInput(1, 0.0f); mNode->SetInput(2, 1.0f); mNode->SetInput(3, 0.0f); - mNode->SetInput(4, 0.0f); + mNode->SetInput(4, 0.5f); + mNode->SetInput(5, 0.0f); mNode->SetInputBound(0, InputBound::INPUT_UNBOUNDED); mNode->SetInputBound(1, InputBound::INPUT_0_100); mNode->SetInputBound(2, InputBound::INPUT_0_TO_2); mNode->SetInputBound(3, InputBound::INPUT_0_TO_1); mNode->SetInputBound(4, InputBound::INPUT_0_TO_1); + mNode->SetInputBound(5, InputBound::INPUT_0_TO_1); } - void GraphSourceSaw::Process(int32_t numSamples, std::vector& inputs, std::vector& outputs) { + void GraphSignalSaw::Process(int32_t numSamples, std::vector& inputs, std::vector& outputs) { float* output0 = &outputs.at(0).GetOutput(numSamples); mSamplesUntilUpdate = l::audio::BatchUpdate(256.0f, mSamplesUntilUpdate, 0, numSamples, [&]() { mFreq = l::math::functions::max(static_cast(inputs.at(0).Get()), 0.0); mVolume = inputs.at(1).Get(); - mReset = inputs.at(4).Get(); + mReset = inputs.at(5).Get(); if (mFreq == 0.0f) { mVolume = 0.0f; @@ -398,6 +469,7 @@ namespace l::nodegraph { mFmod = static_cast(inputs.at(2).Get()); mPmod = static_cast(inputs.at(3).Get()); + double smooth = 0.5 * static_cast(inputs.at(4).Get()); double fmodRange = 16.0; mFmod = mFmod > 1.0 ? fmodRange * (mFmod - 1.0) : 1.0 / (1.0 + fmodRange * (1.0 - mFmod)); @@ -415,12 +487,12 @@ namespace l::nodegraph { double phaseMod = mPhase + mPmod; phaseMod = l::math::functions::mod(phaseMod, 1.0); - double saw = mPhase + phaseMod - 1.0; + double saw = mPhase + phaseMod; + mWave += smooth * (saw - mWave); mVol += (1.0f / 256.0f) * (mVolume - mVol); - mWave += 0.25 * (saw - mWave); - *output0++ = mVol * static_cast(mWave); + *output0++ = mVol * static_cast(mWave - 1.0); } } ); diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpSource.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpSource.cpp new file mode 100644 index 00000000..04539e65 --- /dev/null +++ b/packages/nodegraph/source/common/operations/NodeGraphOpSource.cpp @@ -0,0 +1,69 @@ +#include "nodegraph/operations/NodeGraphOpSource.h" + +#include "logging/Log.h" +#include "audio/AudioUtils.h" + +#include "math/MathFunc.h" + +#include + +namespace l::nodegraph { + + /* Mathematical operations */ + + /*********************************************************************/ + void GraphSourceConstants::Reset() { + switch (mMode) { + case 0: + for (int8_t i = 0; i < 4; i++) { + mNode->SetInputBound(i, InputBound::INPUT_0_TO_1); + } + break; + case 1: + for (int8_t i = 0; i < 4; i++) { + mNode->SetInputBound(i, InputBound::INPUT_NEG_1_POS_1); + } + break; + case 2: + for (int8_t i = 0; i < 4; i++) { + mNode->SetInputBound(i, InputBound::INPUT_0_100); + } + break; + default: + for (int8_t i = 0; i < 4; i++) { + mNode->SetInputBound(i, InputBound::INPUT_UNBOUNDED); + } + break; + } + } + + void GraphSourceConstants::Process(int32_t, std::vector& inputs, std::vector& outputs) { + for (int8_t i = 0; i < mNumOutputs; i++) { + outputs.at(i).mOutput = inputs.at(i).Get(); + } + } + + void GraphSourceConstants::Tick(int32_t, float) { + mNode->ProcessSubGraph(1); + } + + /*********************************************************************/ + void GraphSourceTime::Process(int32_t, std::vector&, std::vector& outputs) { + float rate = 44100.0f; + float phaseChange = 1.0f / rate; + mAudioTime += phaseChange; + + outputs.at(0).mOutput = mAudioTime; + outputs.at(1).mOutput = mFrameTime; + } + + void GraphSourceTime::Tick(int32_t, float deltaTime) { + mFrameTime += deltaTime; + } + + void GraphSourceTime::Reset() { + mAudioTime = 0.0f; + mFrameTime = 0.0f; + } + +} diff --git a/packages/nodegraph/tests/common/NodeGraphSchemaTest.cpp b/packages/nodegraph/tests/common/NodeGraphSchemaTest.cpp index b9181216..85fdd67a 100644 --- a/packages/nodegraph/tests/common/NodeGraphSchemaTest.cpp +++ b/packages/nodegraph/tests/common/NodeGraphSchemaTest.cpp @@ -1,7 +1,7 @@ #include "testing/Test.h" #include "logging/Log.h" -#include "nodegraph/NodeGraph.h" +#include "nodegraph/core/NodeGraphGroup.h" #include "nodegraph/NodeGraphSchema.h" using namespace l; diff --git a/packages/rendering/include/rendering/ui/UICreator.h b/packages/rendering/include/rendering/ui/UICreator.h index d431abbf..038e91e3 100644 --- a/packages/rendering/include/rendering/ui/UICreator.h +++ b/packages/rendering/include/rendering/ui/UICreator.h @@ -13,7 +13,7 @@ #include "implot/implot_internal.h" #include "rendering/ui/UIContainer.h" -#include "nodegraph/NodeGraph.h" +#include "nodegraph/core/NodeGraphBase.h" #include diff --git a/packages/rendering/include/rendering/ui/UINodeEditor.h b/packages/rendering/include/rendering/ui/UINodeEditor.h index 399def08..cccac28a 100644 --- a/packages/rendering/include/rendering/ui/UINodeEditor.h +++ b/packages/rendering/include/rendering/ui/UINodeEditor.h @@ -7,7 +7,6 @@ #include "rendering/ui/UIWindow.h" #include "rendering/ui/UICreator.h" -#include "nodegraph/NodeGraph.h" #include "nodegraph/NodeGraphSchema.h" #include