Fix/dag preset connectivity and layout#202
Conversation
…and drag-and-drop wiring
…and drag-and-drop wiring
…and drag-and-drop wiring
- Synchronize loaded graph nodes with engine dummy_effects_ so UI widgets persist. - Dynamically parse pedal->name() to ensure accurate UI string matching. - Anchor 'Input' and 'Output' nodes explicitly during preset load to ensure graph reachability. - Map legacy preset UI coordinates consistently across all nodes.
|
Warning Review limit reached
More reviews will be available in 37 minutes and 32 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (9)
📝 WalkthroughWalkthroughAdds format-v2 graph-aware preset model and JSON converters; implements PresetManager graph_to_json/graph_from_json and switches save/load to persist full AudioGraph (nodes, links, positions); syncs GUI positions, adds AudioGraph num_inputs, and expands tests for roundtrips and error cases. ChangesGraph Persistence and Serialization
UI State Synchronization and Rendering
AudioGraph API
Tests: serialization, graph behavior, integration
Sequence DiagramsequenceDiagram
participant UI as Gui (PedalBoard / GuiGraphState)
participant PM as PresetManager
participant AG as AudioGraph
participant FS as Filesystem
UI->>PM: save_preset(graph) -> graph_to_json(nodes, links, positions)
PM->>AG: read node positions and topology
PM->>FS: write JSON (format_version=2, routing="graph")
FS-->>PM: file stored
PM-->>UI: confirm saved
UI->>PM: load_preset(file)
PM->>FS: read JSON
FS-->>PM: JSON content
PM->>AG: graph_from_json(recreate nodes, pins, links, positions)
AG-->>PM: graph recreated (or false on failure)
PM-->>UI: restore GUI positions and effects state
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related issues
Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (2)
tests/test_json_serialization.cpp (1)
231-232: ⚡ Quick winAvoid order-dependent endpoint assertions (
front()/back()).At Line 231 and Line 232, this assumes node storage order equals semantic graph order. Prefer counting flagged endpoints so valid reorderings don’t create false failures.
Suggested fix
- ASSERT_TRUE(graph.get_nodes().front().is_graph_input); - ASSERT_TRUE(graph.get_nodes().back().is_graph_output); + size_t input_count = 0, output_count = 0; + for (const auto& n : graph.get_nodes()) { + if (n.is_graph_input) ++input_count; + if (n.is_graph_output) ++output_count; + } + ASSERT_EQ(input_count, 1u); + ASSERT_EQ(output_count, 1u);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/test_json_serialization.cpp` around lines 231 - 232, The assertions using graph.get_nodes().front() and .back() are order-dependent; instead iterate over graph.get_nodes() and count nodes where is_graph_input is true and where is_graph_output is true (using the get_nodes() vector and the is_graph_input / is_graph_output flags) then assert the expected counts (e.g., at least one input and one output or exact expected numbers) so tests pass regardless of node ordering.tests/test_preset_manager.cpp (1)
365-367: ⚡ Quick winUse a real Amp Sim effect here to validate the intended load path.
Using
Overdriveas an “Amp Sim” proxy means this test does not actually exercise the Amp Sim-specific mapping/output-endpoint behavior in preset load logic. Prefer constructing the real Amp Sim effect type in this integration test.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/test_preset_manager.cpp` around lines 365 - 367, The test currently adds amp nodes using Overdrive as a proxy (graph.add_node(..., std::make_shared<Overdrive>())), which won't exercise Amp Sim-specific mapping; replace the proxy with the real amp-sim effect type (e.g., std::make_shared<AmpSim>() or the actual Amp Sim class used in production) for the nodes created by add_node ("Amp Sim") so the preset load logic routes and output endpoints for Amp Sim are actually validated; update the two instances where Overdrive is passed to add_node to construct the real Amp Sim effect instead.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/preset_json.cpp`:
- Around line 395-400: The ADL JSON serializers omit PresetData::NodeData::mix,
causing mix to be lost on round-trips; update the ADL path by adding the "mix"
field to the node object in to_json(nlohmann::json&, const PresetData&) (e.g.,
include {"mix", node.mix} alongside id/type/position/enabled when building jn)
and read it back in from_json(const nlohmann::json&, PresetData&) by extracting
node["mix"] into NodeData::mix so the ADL (to_json/from_json) graph
serialization preserves mix just like the ext path does.
In `@src/preset_manager_io.cpp`:
- Around line 425-430: The parse_pin logic calls std::stoi on substrings for
"out..." and "in..." without guarding against invalid input; wrap the std::stoi
calls inside a try/catch (catch std::invalid_argument and std::out_of_range)
around the parsing in the branches that handle "out" and "in" so that on any
exception you return -1 (or the same sentinel used for failure) instead of
letting the exception propagate, updating the branches that reference
node->output_pin_ids and node->input_pin_ids so they only access by idx after
successful parsing.
- Around line 293-296: In PresetManager::graph_to_json, the pedal mix value is
not being serialized (nd.mix is never set) so roundtripping loses the mix; set
nd.mix from the pedal's current mix (e.g., call the pedal's mix getter such as
mix() or get_mix()) alongside nd.enabled and nd.params so that graph_from_json
can restore it via pedal->set_mix(node.mix).
In `@tests/test_preset_manager.cpp`:
- Around line 313-314: The test currently clears
GuiGraphState::get_instance().node_positions only at the start; to avoid leaking
singleton state add symmetric teardown cleanup (or a RAII/test fixture) that
clears GuiGraphState::get_instance().node_positions at the end of the test (and
do the same for the other test around lines 354-355); implement this by adding a
tearDown/fixture destructor or an explicit clear call after assertions so
node_positions is reset for subsequent tests.
- Around line 126-130: The loop counting graph nodes is using a loose predicate
(n.routing_type != NodeRoutingType::StandardEffect || n.pedal != nullptr) which
also counts splitters/mixers; change the condition that increments
graph_node_count to only count real effect nodes, e.g. require n.routing_type ==
NodeRoutingType::StandardEffect && n.pedal != nullptr (update the increment site
that references n.routing_type and n.pedal and keep the ASSERT_EQ against
orig_effects_count).
---
Nitpick comments:
In `@tests/test_json_serialization.cpp`:
- Around line 231-232: The assertions using graph.get_nodes().front() and
.back() are order-dependent; instead iterate over graph.get_nodes() and count
nodes where is_graph_input is true and where is_graph_output is true (using the
get_nodes() vector and the is_graph_input / is_graph_output flags) then assert
the expected counts (e.g., at least one input and one output or exact expected
numbers) so tests pass regardless of node ordering.
In `@tests/test_preset_manager.cpp`:
- Around line 365-367: The test currently adds amp nodes using Overdrive as a
proxy (graph.add_node(..., std::make_shared<Overdrive>())), which won't exercise
Amp Sim-specific mapping; replace the proxy with the real amp-sim effect type
(e.g., std::make_shared<AmpSim>() or the actual Amp Sim class used in
production) for the nodes created by add_node ("Amp Sim") so the preset load
logic routes and output endpoints for Amp Sim are actually validated; update the
two instances where Overdrive is passed to add_node to construct the real Amp
Sim effect instead.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 35dc5030-0f23-4d28-bc36-a4017a6a35be
📒 Files selected for processing (11)
src/audio/audio_engine.hsrc/audio/audio_engine_chain.cppsrc/audio/audio_graph.cppsrc/audio/audio_graph.hsrc/gui/pedal_board_chain.cppsrc/preset_json.cppsrc/preset_manager.hsrc/preset_manager_io.cpptests/test_audio_graph.cpptests/test_json_serialization.cpptests/test_preset_manager.cpp
| GuiGraphState::get_instance().node_positions.clear(); | ||
|
|
There was a problem hiding this comment.
Reset GuiGraphState::node_positions at test end as well.
These tests mutate global singleton state; clearing only at start can leak state into later tests in the suite. Add end-of-test cleanup (or a small guard fixture) for isolation.
Also applies to: 354-355
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tests/test_preset_manager.cpp` around lines 313 - 314, The test currently
clears GuiGraphState::get_instance().node_positions only at the start; to avoid
leaking singleton state add symmetric teardown cleanup (or a RAII/test fixture)
that clears GuiGraphState::get_instance().node_positions at the end of the test
(and do the same for the other test around lines 354-355); implement this by
adding a tearDown/fixture destructor or an explicit clear call after assertions
so node_positions is reset for subsequent tests.
Code Coverage Report 📊Line Coverage: 85.2% ✅ Coverage meets threshold: 85.2% >= 60% Full Coverage Summary |
PR Preview RemovedThe GitHub Pages preview for this PR has been removed because the PR was closed. |
sudip-mondal-2002
left a comment
There was a problem hiding this comment.
LGTM, but from next time Add comments for long code blocks so i can just dont have to go through everything
What does this PR do?
Resolves a critical backend/frontend synchronization bug preventing modular Directed Acyclic Graph (DAG) presets from correctly loading into the audio engine. Specifically, this PR:
dummy_effects_immediately after parsingpreset.nodesviaengine.restore_effects_state(). This prevents the GUI sync loop from aggressively treating active loaded pedals as orphaned nodes and deleting them on load."Input","Output", and"Amp Sim"nodes by flagging them asis_graph_inputandis_graph_outputduring reconstruction. This ensures theAudioGraphExecutorrecognizes the pathways and correctly compiles the audio topology without defaulting to an unreachableDISCONNECTEDstate.pedal->name()to ensure accurate string mapping so pedals render properly as interactive widgets rather than generic utility blocks.InputandOutputdummy nodes during legacy linear preset loading, assigning consistent 2D coordinate spacing so they no longer overlap dynamically generated pedals visually.Related Issue
Fixes #148
Type of Change
How Was This Tested?
make -j4 && ./tests/test_amplitron.json.DISCONNECTEDstate.linearpreset file and ensured all sequential pedals, Input block, and Amp block snapped to a grid evenly across the horizontal canvas axis without overlapping.Checklist
./tests/test_amplitron)std::mutex::lock()on the hot path)Summary by CodeRabbit
New Features
Bug Fixes
Tests
UI