From 6fcef1e339e4d0d8aa2437575699bc80ede0792a Mon Sep 17 00:00:00 2001 From: Daniel Walz Date: Thu, 18 Apr 2024 00:06:13 +0200 Subject: [PATCH] Improved dsp chain setup --- .../DSP/foleys_BuiltinNodes.h | 24 +++---- .../foleys_dsp_magic/DSP/foleys_DspNode.cpp | 41 ++++++++---- modules/foleys_dsp_magic/DSP/foleys_DspNode.h | 36 +++++++--- .../DSP/foleys_DspProgram.cpp | 67 +++++++++++++++++-- .../foleys_dsp_magic/DSP/foleys_DspProgram.h | 19 +++++- .../DSP/foleys_MagicDspBuilder.cpp | 10 ++- .../DSP/foleys_MagicDspBuilder.h | 10 +-- .../Nodes/foleys_Analyser.cpp | 2 +- .../foleys_dsp_magic/Nodes/foleys_Analyser.h | 2 +- .../foleys_dsp_magic/Nodes/foleys_Noise.cpp | 2 +- modules/foleys_dsp_magic/Nodes/foleys_Noise.h | 2 +- .../Nodes/foleys_Oscillator.cpp | 2 +- .../Nodes/foleys_Oscillator.h | 2 +- .../Nodes/foleys_PlotOutput.cpp | 2 +- .../Nodes/foleys_PlotOutput.h | 2 +- 15 files changed, 168 insertions(+), 55 deletions(-) diff --git a/modules/foleys_dsp_magic/DSP/foleys_BuiltinNodes.h b/modules/foleys_dsp_magic/DSP/foleys_BuiltinNodes.h index 5fcb4543..f5b7a3a8 100644 --- a/modules/foleys_dsp_magic/DSP/foleys_BuiltinNodes.h +++ b/modules/foleys_dsp_magic/DSP/foleys_BuiltinNodes.h @@ -15,11 +15,11 @@ class MagicDspBuilder; class AudioInput : public DspNode { public: - AudioInput (MagicDspBuilder& builder, const juce::ValueTree& node) : DspNode (builder, node) { } + AudioInput (DspProgram& program, const juce::ValueTree& node) : DspNode (program, node) { } [[nodiscard]] juce::String getCategory() const override { return Category::Audio; } - void prepare (juce::dsp::ProcessSpec spec) override { } - void process (juce::dsp::AudioBlock& buffer, juce::MidiBuffer& midi) override { } + void prepare ([[maybe_unused]] juce::dsp::ProcessSpec spec) override { } + void process ([[maybe_unused]] juce::dsp::AudioBlock& buffer, [[maybe_unused]] juce::MidiBuffer& midi) override { } void release() override { } FOLEYS_DECLARE_DSP_FACTORY (AudioInput) @@ -30,11 +30,11 @@ class AudioInput : public DspNode class AudioOutput : public DspNode { public: - AudioOutput (MagicDspBuilder& builder, const juce::ValueTree& node) : DspNode (builder, node) { } + AudioOutput (DspProgram& program, const juce::ValueTree& node) : DspNode (program, node) { } [[nodiscard]] juce::String getCategory() const override { return Category::Audio; } - void prepare (juce::dsp::ProcessSpec spec) override { } - void process (juce::dsp::AudioBlock& buffer, juce::MidiBuffer& midi) override { } + void prepare ([[maybe_unused]] juce::dsp::ProcessSpec spec) override { } + void process ([[maybe_unused]] juce::dsp::AudioBlock& buffer, [[maybe_unused]] juce::MidiBuffer& midi) override { } void release() override { } FOLEYS_DECLARE_DSP_FACTORY (AudioOutput) @@ -45,11 +45,11 @@ class AudioOutput : public DspNode class MidiInput : public DspNode { public: - MidiInput (MagicDspBuilder& builder, const juce::ValueTree& node) : DspNode (builder, node) { } + MidiInput (DspProgram& program, const juce::ValueTree& node) : DspNode (program, node) { } [[nodiscard]] juce::String getCategory() const override { return Category::Audio; } - void prepare (juce::dsp::ProcessSpec spec) override { } - void process (juce::dsp::AudioBlock& buffer, juce::MidiBuffer& midi) override { } + void prepare ([[maybe_unused]] juce::dsp::ProcessSpec spec) override { } + void process ([[maybe_unused]] juce::dsp::AudioBlock& buffer, [[maybe_unused]] juce::MidiBuffer& midi) override { } void release() override { } FOLEYS_DECLARE_DSP_FACTORY (MidiInput) @@ -60,11 +60,11 @@ class MidiInput : public DspNode class MidiOutput : public DspNode { public: - MidiOutput (MagicDspBuilder& builder, const juce::ValueTree& node) : DspNode (builder, node) { } + MidiOutput (DspProgram& program, const juce::ValueTree& node) : DspNode (program, node) { } [[nodiscard]] juce::String getCategory() const override { return Category::Audio; } - void prepare (juce::dsp::ProcessSpec spec) override { } - void process (juce::dsp::AudioBlock& buffer, juce::MidiBuffer& midi) override { } + void prepare ([[maybe_unused]] juce::dsp::ProcessSpec spec) override { } + void process ([[maybe_unused]] juce::dsp::AudioBlock& buffer, [[maybe_unused]] juce::MidiBuffer& midi) override { } void release() override { } FOLEYS_DECLARE_DSP_FACTORY (MidiOutput) diff --git a/modules/foleys_dsp_magic/DSP/foleys_DspNode.cpp b/modules/foleys_dsp_magic/DSP/foleys_DspNode.cpp index 1496d722..8f4b925f 100644 --- a/modules/foleys_dsp_magic/DSP/foleys_DspNode.cpp +++ b/modules/foleys_dsp_magic/DSP/foleys_DspNode.cpp @@ -11,22 +11,11 @@ namespace NodeIDs { DECLARE_ID (name) DECLARE_ID (uid) -} +} // namespace NodeIDs -DspNode::DspNode (MagicDspBuilder& builder, const juce::ValueTree& node) : config (node) +DspNode::DspNode (DspProgram& program, const juce::ValueTree& node) : config (node) { - nodeName = node.getProperty (NodeIDs::name, "noname"); nodeType = node.getType().toString(); - if (config.hasProperty(NodeIDs::uid)) - { - uid = config.getProperty(NodeIDs::uid); - builder.setNextUID(uid); - } - else - { - uid = builder.nextUID(); - config.setProperty(NodeIDs::uid, uid, nullptr); - } } DspNode::~DspNode() @@ -34,5 +23,31 @@ DspNode::~DspNode() masterReference.clear(); } +/* static */ +int DspNode::getUID (const juce::ValueTree& tree) +{ + return tree.getProperty (NodeIDs::uid, 0); +} + +juce::String DspNode::getName() const +{ + return config.getProperty (NodeIDs::name, "unnamed").toString(); +} + +int DspNode::getUID() const +{ + return config.getProperty (NodeIDs::uid, 0); +} + +void DspNode::setName (const juce::String& newName) +{ + config.setProperty (NodeIDs::name, newName, nullptr); +} + +void DspNode::setUID (int newUID) +{ + config.setProperty (NodeIDs::uid, newUID, nullptr); +} + } // namespace foleys::dsp diff --git a/modules/foleys_dsp_magic/DSP/foleys_DspNode.h b/modules/foleys_dsp_magic/DSP/foleys_DspNode.h index 8687365d..ea348156 100644 --- a/modules/foleys_dsp_magic/DSP/foleys_DspNode.h +++ b/modules/foleys_dsp_magic/DSP/foleys_DspNode.h @@ -7,7 +7,7 @@ namespace foleys::dsp { -class MagicDspBuilder; +class DspProgram; namespace Category { @@ -19,38 +19,58 @@ static constexpr auto Filters = "Filters"; static constexpr auto Scripts = "Scripts"; } + class DspNode { public: - explicit DspNode (MagicDspBuilder& builder, const juce::ValueTree& node); + enum ConnectionType + { + Invalid = 0, + Audio, + MIDI, + Parameter + }; + + explicit DspNode (DspProgram& program, const juce::ValueTree& node); virtual ~DspNode(); [[nodiscard]] virtual juce::String getCategory() const = 0; - [[nodiscard]] juce::String getName() const { return nodeName; } [[nodiscard]] juce::String getType() const { return nodeType; } - [[nodiscard]] int getUID() const { return uid; } + [[nodiscard]] juce::String getName() const; + [[nodiscard]] int getUID() const; + + void setName (const juce::String& newName); + void setUID (int newUID); virtual void prepare (juce::dsp::ProcessSpec spec) = 0; virtual void process (juce::dsp::AudioBlock& buffer, juce::MidiBuffer& midi) = 0; virtual void release() = 0; + // throw-away default implementation, make pure virtual + virtual int getNumAudioInputs() { return 1; } + virtual int getNumAudioOutputs() { return 1; } + virtual int getNumParameterInputs() { return 5; } + virtual int getNumParameterOutputs() { return 1; } + virtual bool hasMidiInput() { return true; } + virtual bool hasMidiOutput() { return true; } + [[nodiscard]] const juce::ValueTree& getConfig() const { return config; } + static int getUID (const juce::ValueTree& tree); + private: juce::ValueTree config; - juce::String nodeName; juce::String nodeType; - int uid = 0; JUCE_DECLARE_WEAK_REFERENCEABLE (DspNode) JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DspNode) }; #define FOLEYS_DECLARE_DSP_FACTORY(itemName) \ - static inline std::unique_ptr factory (foleys::dsp::MagicDspBuilder& builder, const juce::ValueTree& node) \ + static inline std::unique_ptr factory (foleys::dsp::DspProgram& program, const juce::ValueTree& node) \ { \ - return std::make_unique (builder, node); \ + return std::make_unique (program, node); \ } \ static constexpr auto ID = #itemName; diff --git a/modules/foleys_dsp_magic/DSP/foleys_DspProgram.cpp b/modules/foleys_dsp_magic/DSP/foleys_DspProgram.cpp index 35f925e3..2e145e2d 100644 --- a/modules/foleys_dsp_magic/DSP/foleys_DspProgram.cpp +++ b/modules/foleys_dsp_magic/DSP/foleys_DspProgram.cpp @@ -8,16 +8,13 @@ namespace foleys::dsp { -DspProgram::DspProgram (MagicDspBuilder& builder, const juce::ValueTree& tree) +DspProgram::DspProgram (MagicDspBuilder& builder) : dspBuilder (builder) { } + +DspProgram::DspProgram (MagicDspBuilder& builder, const juce::ValueTree& tree) : dspBuilder (builder), dspConfig (tree) { for (auto node: tree) { - auto child = builder.createNode (node); - if (child) - { - nodeLookup[child->getUID()] = child.get(); - nodes.push_back (std::move (child)); - } + createNode (node); } for (const auto& node: nodes) @@ -33,6 +30,53 @@ DspProgram::DspProgram (MagicDspBuilder& builder, const juce::ValueTree& tree) } } +bool DspProgram::addNode (const juce::ValueTree& newNode) +{ + auto success = createNode (newNode); + if (success) + dspConfig.appendChild (newNode, nullptr); + + return success; +} + +bool DspProgram::createNode (const juce::ValueTree& newNode) +{ + auto child = dspBuilder.createNode (*this, newNode); + if (child) + { + auto uid = child->getUID(); + if (uid > 0) + { + if (nodeLookup.find (uid) != nodeLookup.cend()) + { + /* + * This uid already exists! + */ + jassertfalse; + return false; + } + } + else + { + uid = uidCounter + 1; + child->setUID (uid); + } + uidCounter = std::max (uidCounter, uid); + + nodeLookup[child->getUID()] = child.get(); + nodes.push_back (std::move (child)); + + return true; + } + return false; +} + +bool DspProgram::connectNodes (DspNode::ConnectionType connectionType, int sourceUID, int sourceIndex, int targetUID, int targetIndex) +{ + +} + + void DspProgram::prepareToPlay (double sampleRate, int expectedNumSamples) { juce::dsp::ProcessSpec spec { sampleRate, static_cast (expectedNumSamples), 2 }; @@ -49,5 +93,14 @@ void DspProgram::releaseResources() node->release(); } +DspNode* DspProgram::getNodeWithUID (int uid) +{ + const auto& it = std::find_if (nodes.begin(), nodes.end(), [uid] (const auto& node) { return node->getUID() == uid; }); + if (it != nodes.end()) + return it->get(); + + return nullptr; +} + } // namespace foleys::dsp diff --git a/modules/foleys_dsp_magic/DSP/foleys_DspProgram.h b/modules/foleys_dsp_magic/DSP/foleys_DspProgram.h index 6570eae3..566c41ea 100644 --- a/modules/foleys_dsp_magic/DSP/foleys_DspProgram.h +++ b/modules/foleys_dsp_magic/DSP/foleys_DspProgram.h @@ -14,7 +14,13 @@ namespace foleys::dsp class DspProgram { public: - explicit DspProgram (MagicDspBuilder& builder, const juce::ValueTree& tree); + explicit DspProgram (MagicDspBuilder& builder); + DspProgram (MagicDspBuilder& builder, const juce::ValueTree& tree); + + bool addNode (const juce::ValueTree& newNode); + bool createNode (const juce::ValueTree& newNode); + + bool connectNodes (DspNode::ConnectionType connectionType, int sourceUID, int sourceIndex, int targetUID, int targetIndex); void prepareToPlay (double sampleRate, int expectedNumSamples); void processBlock (juce::AudioBuffer& buffer, juce::MidiBuffer& midi); @@ -24,9 +30,20 @@ class DspProgram bool producesMidi() const { return midiOutput != nullptr; } bool isMidiEffect() const { return acceptsMidi() && producesMidi(); } + DspNode* getNodeWithUID (int uid); + + std::vector>::const_iterator begin() { return nodes.cbegin(); } + std::vector>::const_iterator end() { return nodes.cend(); } + + juce::ValueTree getConfig() const { return dspConfig; } + private: + MagicDspBuilder& dspBuilder; + juce::ValueTree dspConfig { "Program" }; + std::vector> nodes; std::map nodeLookup; + int uidCounter = 0; juce::WeakReference midiInput; juce::WeakReference midiOutput; diff --git a/modules/foleys_dsp_magic/DSP/foleys_MagicDspBuilder.cpp b/modules/foleys_dsp_magic/DSP/foleys_MagicDspBuilder.cpp index 8f2c8761..05aaae08 100644 --- a/modules/foleys_dsp_magic/DSP/foleys_MagicDspBuilder.cpp +++ b/modules/foleys_dsp_magic/DSP/foleys_MagicDspBuilder.cpp @@ -46,12 +46,12 @@ std::unique_ptr MagicDspBuilder::createProgram (const juce::ValueTre return std::make_unique (*this, tree); } -std::unique_ptr MagicDspBuilder::createNode (const juce::ValueTree& node) +std::unique_ptr MagicDspBuilder::createNode (DspProgram& program, const juce::ValueTree& node) { auto factory = factories.find (node.getType()); if (factory != factories.end()) { - auto item = factory->second (*this, node); + auto item = factory->second (program, node); return item; } @@ -59,6 +59,12 @@ std::unique_ptr MagicDspBuilder::createNode (const juce::ValueTree& nod return {}; } +bool MagicDspBuilder::canCreate (const juce::ValueTree& node) const +{ + auto factory = factories.find (node.getType()); + return (factory != factories.end()); +} + MagicGUIState& MagicDspBuilder::getMagicState() { return magicState; diff --git a/modules/foleys_dsp_magic/DSP/foleys_MagicDspBuilder.h b/modules/foleys_dsp_magic/DSP/foleys_MagicDspBuilder.h index 5c879fbf..20baa1e4 100644 --- a/modules/foleys_dsp_magic/DSP/foleys_MagicDspBuilder.h +++ b/modules/foleys_dsp_magic/DSP/foleys_MagicDspBuilder.h @@ -13,7 +13,7 @@ namespace foleys::dsp class MagicDspBuilder { public: - using DspFactory = std::function (MagicDspBuilder& builder, const juce::ValueTree& node)>; + using DspFactory = std::function (DspProgram& program, const juce::ValueTree& node)>; explicit MagicDspBuilder (MagicGUIState& magicState); @@ -23,15 +23,17 @@ class MagicDspBuilder std::unique_ptr createProgram (const juce::ValueTree& tree); - std::unique_ptr createNode (const juce::ValueTree& node); + std::unique_ptr createNode (DspProgram& program, const juce::ValueTree& node); + + bool canCreate (const juce::ValueTree& node) const; MagicGUIState& getMagicState(); [[nodiscard]] int nextUID(); void setNextUID (int uid); - std::map::iterator begin() {return factories.begin();} - std::map::iterator end() {return factories.end();} + std::map::iterator begin() { return factories.begin(); } + std::map::iterator end() { return factories.end(); } private: MagicGUIState& magicState; diff --git a/modules/foleys_dsp_magic/Nodes/foleys_Analyser.cpp b/modules/foleys_dsp_magic/Nodes/foleys_Analyser.cpp index 1d7e5a92..5b0e9901 100644 --- a/modules/foleys_dsp_magic/Nodes/foleys_Analyser.cpp +++ b/modules/foleys_dsp_magic/Nodes/foleys_Analyser.cpp @@ -7,7 +7,7 @@ namespace foleys::dsp { -Analyser::Analyser (MagicDspBuilder& builder, const juce::ValueTree& config) : DspNode (builder, config) { } +Analyser::Analyser (DspProgram& program, const juce::ValueTree& config) : DspNode (program, config) { } } // namespace foleys::dsp diff --git a/modules/foleys_dsp_magic/Nodes/foleys_Analyser.h b/modules/foleys_dsp_magic/Nodes/foleys_Analyser.h index 66bb10b3..79983967 100644 --- a/modules/foleys_dsp_magic/Nodes/foleys_Analyser.h +++ b/modules/foleys_dsp_magic/Nodes/foleys_Analyser.h @@ -12,7 +12,7 @@ namespace foleys::dsp class Analyser : public DspNode { public: - Analyser (MagicDspBuilder& builder, const juce::ValueTree& config); + Analyser (DspProgram& program, const juce::ValueTree& config); [[nodiscard]] juce::String getCategory() const override { return Category::Visualisers; } void prepare (juce::dsp::ProcessSpec spec) override { } diff --git a/modules/foleys_dsp_magic/Nodes/foleys_Noise.cpp b/modules/foleys_dsp_magic/Nodes/foleys_Noise.cpp index a5aa6b33..f91b4dd0 100644 --- a/modules/foleys_dsp_magic/Nodes/foleys_Noise.cpp +++ b/modules/foleys_dsp_magic/Nodes/foleys_Noise.cpp @@ -7,7 +7,7 @@ namespace foleys::dsp { -Noise::Noise (MagicDspBuilder& builder, const juce::ValueTree& config) : DspNode (builder, config) { } +Noise::Noise (DspProgram& program, const juce::ValueTree& config) : DspNode (program, config) { } void Noise::prepare (juce::dsp::ProcessSpec spec) { diff --git a/modules/foleys_dsp_magic/Nodes/foleys_Noise.h b/modules/foleys_dsp_magic/Nodes/foleys_Noise.h index 4d93caf9..9dcc80b2 100644 --- a/modules/foleys_dsp_magic/Nodes/foleys_Noise.h +++ b/modules/foleys_dsp_magic/Nodes/foleys_Noise.h @@ -12,7 +12,7 @@ namespace foleys::dsp class Noise : public DspNode { public: - Noise (MagicDspBuilder& builder, const juce::ValueTree& config); + Noise (DspProgram& program, const juce::ValueTree& config); [[nodiscard]] juce::String getCategory() const override { return Category::Generators; } void prepare (juce::dsp::ProcessSpec spec) override; diff --git a/modules/foleys_dsp_magic/Nodes/foleys_Oscillator.cpp b/modules/foleys_dsp_magic/Nodes/foleys_Oscillator.cpp index 9859e930..5f4cfdfb 100644 --- a/modules/foleys_dsp_magic/Nodes/foleys_Oscillator.cpp +++ b/modules/foleys_dsp_magic/Nodes/foleys_Oscillator.cpp @@ -7,7 +7,7 @@ namespace foleys::dsp { -Oscillator::Oscillator (MagicDspBuilder& builder, const juce::ValueTree& config) : DspNode (builder, config) { } +Oscillator::Oscillator (DspProgram& program, const juce::ValueTree& config) : DspNode (program, config) { } void Oscillator::prepare (juce::dsp::ProcessSpec spec) { diff --git a/modules/foleys_dsp_magic/Nodes/foleys_Oscillator.h b/modules/foleys_dsp_magic/Nodes/foleys_Oscillator.h index 65113f8e..05937615 100644 --- a/modules/foleys_dsp_magic/Nodes/foleys_Oscillator.h +++ b/modules/foleys_dsp_magic/Nodes/foleys_Oscillator.h @@ -12,7 +12,7 @@ namespace foleys::dsp class Oscillator : public DspNode { public: - Oscillator (MagicDspBuilder& builder, const juce::ValueTree& config); + Oscillator (DspProgram& program, const juce::ValueTree& config); [[nodiscard]] juce::String getCategory() const override { return Category::Generators; } void prepare (juce::dsp::ProcessSpec spec) override; diff --git a/modules/foleys_dsp_magic/Nodes/foleys_PlotOutput.cpp b/modules/foleys_dsp_magic/Nodes/foleys_PlotOutput.cpp index e8618fac..852d1535 100644 --- a/modules/foleys_dsp_magic/Nodes/foleys_PlotOutput.cpp +++ b/modules/foleys_dsp_magic/Nodes/foleys_PlotOutput.cpp @@ -7,7 +7,7 @@ namespace foleys::dsp { -PlotOutput::PlotOutput (MagicDspBuilder& builder, const juce::ValueTree& config) : DspNode (builder, config) { } +PlotOutput::PlotOutput (DspProgram& program, const juce::ValueTree& config) : DspNode (program, config) { } } // namespace foleys::dsp diff --git a/modules/foleys_dsp_magic/Nodes/foleys_PlotOutput.h b/modules/foleys_dsp_magic/Nodes/foleys_PlotOutput.h index 2602aa11..416462bf 100644 --- a/modules/foleys_dsp_magic/Nodes/foleys_PlotOutput.h +++ b/modules/foleys_dsp_magic/Nodes/foleys_PlotOutput.h @@ -12,7 +12,7 @@ namespace foleys::dsp class PlotOutput : public DspNode { public: - PlotOutput (MagicDspBuilder& builder, const juce::ValueTree& config); + PlotOutput (DspProgram& program, const juce::ValueTree& config); [[nodiscard]] juce::String getCategory() const override { return Category::Visualisers; } void prepare (juce::dsp::ProcessSpec spec) override { }