From a305095443c690aa9b3ef9f340b6caeb2da65914 Mon Sep 17 00:00:00 2001 From: Michael Fisher Date: Tue, 6 Jan 2026 11:23:05 -0500 Subject: [PATCH 1/2] fix: ensure IONode's parent graph has minimum port count on setParentGraph --- .github/copilot-instructions.md | 8 ++++++++ src/engine/ionode.cpp | 14 ++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 14838a957..035060009 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -12,3 +12,11 @@ - Write clear, readable code with descriptive names for variables, functions, and classes. - Maintain consistency with the existing codebase style and patterns. - Consider maintainability and future developers who will read the code. + +## Audio Graph Architecture + +- **IONodes** (audio/MIDI input/output) require a parent `GraphNode` to be set before ports can be properly initialized. +- `IONode::refreshPorts()` queries the parent graph's port count via `graph->getNumPorts()`. If the parent is null or has zero ports, the IONode will have zero ports. +- When adding IONodes, ensure the parent graph has a valid port count first using `graph->setNumPorts()`. +- Default port counts: 2 channels for audio (stereo), 1 channel for MIDI. +- Message flow for adding nodes: `AddPluginMessage` → `AddPluginAction::perform()` → `EngineService::addPlugin()` → `GraphManager::addNode()`. diff --git a/src/engine/ionode.cpp b/src/engine/ionode.cpp index e21f4fe80..0b9da4139 100644 --- a/src/engine/ionode.cpp +++ b/src/engine/ionode.cpp @@ -183,6 +183,20 @@ bool IONode::isOutput() const { return type == audioOutputNode || type == midiOu void IONode::setParentGraph (GraphNode* const newGraph) { graph = newGraph; + + // Ensure the parent graph has a minimum port count for this IONode's type. + // Default: 2 channels for audio (stereo), 1 channel for MIDI. + if (graph != nullptr) + { + const auto portType = getPortType(); + const int currentCount = graph->getNumPorts (portType, isInput()); + if (currentCount == 0) + { + const int defaultCount = (portType == PortType::Audio) ? 2 : 1; + graph->setNumPorts (portType, defaultCount, isInput(), false); + } + } + refreshPorts(); } From ac7b829a5ad8180d3631c425a4758ffaf15cefdc Mon Sep 17 00:00:00 2001 From: Michael Fisher Date: Tue, 6 Jan 2026 11:47:48 -0500 Subject: [PATCH 2/2] Add unit test for IONode minimum audio port count Verifies that Audio Input/Output nodes receive a minimum of 2 ports when added to a graph with zero audio ports configured. --- test/audioroutingtests.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/test/audioroutingtests.cpp b/test/audioroutingtests.cpp index faa40a136..eb4d47260 100644 --- a/test/audioroutingtests.cpp +++ b/test/audioroutingtests.cpp @@ -1032,4 +1032,33 @@ BOOST_AUTO_TEST_CASE (AudioFeedbackPrevention) BOOST_REQUIRE (! feedbackAllowed); } +BOOST_AUTO_TEST_CASE (IONodeMinimumAudioPortCount) +{ + // Test that Audio I/O nodes get a minimum port count when added to a graph with zero audio ports + // This prevents the bug where Audio Input/Output nodes appear with zero ports + + PreparedGraph fix; + GraphNode& graph = fix.graph; + + fix.graph.clear(); + graph.setNumPorts (PortType::Audio, 0, true, false); + graph.setNumPorts (PortType::Audio, 0, false, false); + + // Verify graph starts with zero audio ports configured + BOOST_REQUIRE_EQUAL (graph.getNumPorts (PortType::Audio, true), 0); + BOOST_REQUIRE_EQUAL (graph.getNumPorts (PortType::Audio, false), 0); + + // Add Audio Input node - should set graph audio inputs to minimum 2 (stereo) + auto* audioIn = new IONode (IONode::audioInputNode); + graph.addNode (audioIn); + BOOST_REQUIRE_EQUAL (graph.getNumPorts (PortType::Audio, true), 2); + BOOST_REQUIRE_EQUAL (audioIn->getNumPorts(), 2); + + // Add Audio Output node - should set graph audio outputs to minimum 2 (stereo) + auto* audioOut = new IONode (IONode::audioOutputNode); + graph.addNode (audioOut); + BOOST_REQUIRE_EQUAL (graph.getNumPorts (PortType::Audio, false), 2); + BOOST_REQUIRE_EQUAL (audioOut->getNumPorts(), 2); +} + BOOST_AUTO_TEST_SUITE_END()