From c25d5b2a1a13a62535f319d8e88b5dcc61902bff Mon Sep 17 00:00:00 2001 From: Sebastian Date: Sat, 26 Oct 2024 02:14:41 +0200 Subject: [PATCH] node deletion with connection deletion and signal redistribution implemented --- Makefile | 2 +- src/connection-manager.h | 25 ++++++++------- src/connection.h | 23 +++++++------- src/main.cpp | 38 +++++++++++------------ src/node-manager.h | 34 ++++++++++++-------- src/node.h | 12 +++++-- src/signal-manager.h | 30 +++++++++--------- src/signal.h | 7 ++--- src/state-manager.h | 67 ++++++++++++++++++++++++++++++++++++++-- src/ui.h | 13 ++++---- 10 files changed, 167 insertions(+), 84 deletions(-) diff --git a/Makefile b/Makefile index 958deb2..13c4406 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ CXX = g++ -CXXFLAGS = -std=c++20 -Wall -g -fno-omit-frame-pointer -gdwarf-4 -Og -Wnarrowing -DLIBREMIDI_ALSA=1 +CXXFLAGS = -std=c++23 -Wall -g -fno-omit-frame-pointer -gdwarf-4 -Og -Wnarrowing -DLIBREMIDI_ALSA=1 CXXINC = -Iinclude LDLIBS = -lraylib -lasound -pthread diff --git a/src/connection-manager.h b/src/connection-manager.h index b764aab..50f67fc 100644 --- a/src/connection-manager.h +++ b/src/connection-manager.h @@ -1,6 +1,7 @@ #pragma once #include "connection.h" +#include "node-manager.h" #include "raylib.h" #include #include @@ -9,40 +10,42 @@ class ConnectionManager{ public: - ConnectionManager() {} + ConnectionManager(NodeManager *nm) : nm(nm) {} + + NodeManager *nm; std::vector connections; - std::map counter; + std::map counter; void reset(){ counter.clear(); } - Node* next(Node* current, Node* last){ + int next(int current, int last){ std::vector paths; - std::vector nodes; + std::vector node_ids; for(auto& p : connections){ if((p.v1 == current && p.v1_v2) || (p.v2 == current && p.v2_v1)) { p.active = false; paths.push_back(&p); - nodes.push_back( p.v1 == current ? p.v2 : p.v1 ); + node_ids.push_back( p.v1 == current ? p.v2 : p.v1 ); } } if(paths.size() == 2) { - Node* next = nodes[0] == last ? nodes[1] : nodes[0]; + int next = node_ids[0] == last ? node_ids[1] : node_ids[0]; if(paths[0]->v1 == next || paths[0]->v2 == next) paths[0]->active = true; if(paths[1]->v1 == next || paths[1]->v2 == next) paths[1]->active = true; return next; } - if(paths.empty()) return nullptr; + if(paths.empty()) return -1; int return_path = 0; - if(current->mode == Distribution::ROUNDROBIN){ + if(nm->nodes.at(current).mode == Distribution::ROUNDROBIN){ if(counter.find(current) == counter.end()) { counter[current] = 0; } else { @@ -50,15 +53,15 @@ class ConnectionManager{ return_path = counter[current]; } } - if(current->mode == Distribution::RANDOM){ + if(nm->nodes.at(current).mode == Distribution::RANDOM){ return_path = rand() % paths.size(); } paths.at(return_path)->active = true; return paths.at(return_path)->v1 == current ? paths.at(return_path)->v2 : paths.at(return_path)->v1; } - void addConnection(Node *from, Node *to){ - connections.emplace_back(from, to); + void addConnection(int from, int to){ + connections.emplace_back(&nm->nodes, from, to); } void drawConnections(Vec2D *mouse_pos, Camera2D *cam){ diff --git a/src/connection.h b/src/connection.h index b2901b9..6401fc4 100644 --- a/src/connection.h +++ b/src/connection.h @@ -7,11 +7,12 @@ class Connection{ public: - Connection() {} - Connection(Node* v1, Node* v2) : v1(v1), v2(v2) {} + Connection(std::map *nodes, int v1, int v2) : v1(v1), v2(v2), nodes(nodes) {} - Node* v1; - Node* v2; + int v1; + int v2; + + std::map *nodes; bool v1_v2 = true; bool v2_v1 = true; @@ -23,14 +24,14 @@ class Connection{ float switches_offset = 25.0f; void flip(){ - Node* vt = v1; + int vt = v1; v1 = v2; v2 = vt; } void draw(Vec2D *mouse_pos, Camera2D *cam){ - Vec2D v1_position = v1->position - ((v1->position - v2->position)).norm() * (v1->radius + connector_offset); - Vec2D v2_position = v2->position - ((v2->position - v1->position)).norm() * (v2->radius + connector_offset); + Vec2D v1_position = nodes->at(v1).position - ((nodes->at(v1).position - nodes->at(v2).position)).norm() * (nodes->at(v1).radius + connector_offset); + Vec2D v2_position = nodes->at(v2).position - ((nodes->at(v2).position - nodes->at(v1).position)).norm() * (nodes->at(v2).radius + connector_offset); float v1_v2_distance = v1_position.dist(&v2_position); // Line with small connector circles @@ -41,10 +42,10 @@ class Connection{ DrawCircle(v2_position.x, v2_position.y, 2.0f, c); if(v1_v2_distance < 100) switches_offset = v1_v2_distance/2.3f; - Vec2D from_to_handle = v1->position - ((v1->position - v2->position)).norm() * (v1->radius + switches_offset); - Vec2D to_from_handle = v2->position - ((v2->position - v1->position)).norm() * (v2->radius + switches_offset); - Vec2D middle_handle = v2->position - ((v2->position - v1->position))*0.5f; -// Vec2D config_handle = v2->position - ((v2->position - v1->position))*0.66f; + Vec2D from_to_handle = nodes->at(v1).position - ((nodes->at(v1).position - nodes->at(v2).position)).norm() * (nodes->at(v1).radius + switches_offset); + Vec2D to_from_handle = nodes->at(v2).position - ((nodes->at(v2).position - nodes->at(v1).position)).norm() * (nodes->at(v2).radius + switches_offset); + Vec2D middle_handle = nodes->at(v2).position - ((nodes->at(v2).position - nodes->at(v1).position))*0.5f; +// Vec2D config_handle = nodes.at(v2)->position - ((nodes.at(v2)->position - nodes.at(v1)->position))*0.66f; Vec2D flip_handle = middle_handle + (v1_position - v2_position).norm().orth() * (v1_v2_distance < 120.0f ? Clamp((120.0f - v1_v2_distance)*0.2, 0.f, 20.f) : 1.0f); diff --git a/src/main.cpp b/src/main.cpp index 8eece87..b480be4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -50,7 +50,7 @@ int main(){ app.ui.init(); - int monitor = 0; //GetCurrentMonitor(); + int monitor = 1; //GetCurrentMonitor(); SetWindowMonitor(monitor); @@ -83,10 +83,10 @@ int main(){ } for(int i = 0; i < 8; ++i){ - app.cm.addConnection(&app.nm.nodes[i], &app.nm.nodes[(i+1) % 8]); + app.cm.addConnection(app.nm.nodes[i].id, app.nm.nodes[(i+1) % 8].id); } - app.sm.addSignalAtNode(&app.nm.nodes.front()); + app.sm.addSignalAtNode((app.nm.nodes | std::views::values).front().id); app.sm.startSignalThread(); @@ -110,7 +110,7 @@ int main(){ BeginDrawing(); ClearBackground((Color){46,46,46}); BeginMode2D(camera); - //app.settings.mutex.lock(); + app.settings.speed = (app.settings.grid * 8.0f) * (app.settings.bpm / 120.f); Vector2 mp = GetScreenToWorld2D(GetMousePosition(), camera); @@ -128,11 +128,11 @@ int main(){ Vec2D mouse_delta = {GetMouseDelta().x, GetMouseDelta().y}; Vec2D delta = mouse_delta * (-1.0f/camera.zoom); - auto dragging_nodes = app.nm.nodes | std::ranges::views::filter([](Node n) { return n.dragging;}); - auto connecting_nodes = app.nm.nodes | std::ranges::views::filter([](Node n) { return n.connecting;}); - auto selected_nodes = app.nm.nodes | std::ranges::views::filter([](Node n) { return n.selected && !n.dragging;}); - auto hovering_nodes = app.nm.nodes | std::ranges::views::filter([&mouse_pos](Node n) { return CheckCollisionPointCircle(mouse_pos, n.position, n.radius);}); - auto hovering_connectors = app.nm.nodes | std::ranges::views::filter([&mouse_pos](Node n) { return CheckCollisionPointCircle(mouse_pos, (n.position - ((n.position - mouse_pos)).norm() * (n.radius + 14.0f)), 8.0f);}); + auto dragging_nodes = app.nm.nodes | std::ranges::views::values | std::ranges::views::filter([](Node n) { return n.dragging;}); + auto connecting_nodes = app.nm.nodes | std::ranges::views::values| std::ranges::views::filter([](Node n) { return n.connecting;}); + auto selected_nodes = app.nm.nodes | std::ranges::views::values| std::ranges::views::filter([](Node n) { return n.selected && !n.dragging;}); + auto hovering_nodes = app.nm.nodes | std::ranges::views::values| std::ranges::views::filter([&mouse_pos](Node n) { return CheckCollisionPointCircle(mouse_pos, n.position, n.radius);}); + auto hovering_connectors = app.nm.nodes | std::ranges::views::values| std::ranges::views::filter([&mouse_pos](Node n) { return CheckCollisionPointCircle(mouse_pos, (n.position - ((n.position - mouse_pos)).norm() * (n.radius + 14.0f)), 8.0f);}); if(!mouse_down && !mouse_right_down && dragging_nodes.empty() && connecting_nodes.empty() && hovering_nodes.empty() && hovering_connectors.empty()) istate = InteractionState::HOVER_CANVAS; if((mouse_clicked || mouse_down || mouse_released) && !mouse_right_down && dragging_nodes.empty() && connecting_nodes.empty() && hovering_nodes.empty() && hovering_connectors.empty()) istate = InteractionState::DRAW_SELECTION; @@ -163,7 +163,7 @@ int main(){ DrawRectangleLines(select1.x, select1.y, select2.x, select2.y, (Color){150,150,150,150}); selection = (Rectangle){select1.x, select1.y, select2.x, select2.y}; - for(auto& n : app.nm.nodes){ + for(auto& n : app.nm.nodes | std::views::values){ if(CheckCollisionPointRec(n.position, selection)) { n.in_rect = true; } else { @@ -173,7 +173,7 @@ int main(){ } if(mouse_released){ - for(auto& n : app.nm.nodes){ + for(auto& n : app.nm.nodes | std::views::values){ if(CheckCollisionPointRec(n.position, selection)) { n.selected = true; n.in_rect = false; @@ -236,24 +236,25 @@ int main(){ if(mouse_released) { if(&hovering_nodes.front() != &connecting_nodes.front() && &connecting_nodes.front() != &hovering_connectors.front()){ if(!hovering_nodes.empty()){ - app.cm.addConnection(&connecting_nodes.front(), &hovering_nodes.front()); + app.cm.addConnection(connecting_nodes.front().id, hovering_nodes.front().id); } else if(!hovering_connectors.empty()){ - app.cm.addConnection(&connecting_nodes.front(), &hovering_connectors.front()); + app.cm.addConnection(connecting_nodes.front().id, hovering_connectors.front().id); } else { - app.nm.addNode(mouse_pos.x, mouse_pos.y); - app.cm.addConnection(&connecting_nodes.front(), &app.nm.nodes.back()); + int id = app.nm.addNode(mouse_pos.x, mouse_pos.y); + app.cm.addConnection(connecting_nodes.front().id, id); } } connecting_nodes.front().connecting = false; + istate = InteractionState::HOVER_CANVAS; } break; } case InteractionState::DELETE_SELECTED_NODES: { - for(auto &n : app.nm.nodes){ + for(auto &n : selected_nodes){ n.erase = true; } - app.nm.removeNodes(); + app.removeNodes(); break; } }; @@ -279,8 +280,7 @@ int main(){ DrawPixel(x, y, (Color){130,130,130,200}); } } - - + app.draw(&mouse_pos, &camera); EndMode2D(); diff --git a/src/node-manager.h b/src/node-manager.h index c77aae7..e76ee84 100644 --- a/src/node-manager.h +++ b/src/node-manager.h @@ -1,31 +1,39 @@ #pragma once #include "node.h" +#include +#include +#include #include class NodeManager{ public: - NodeManager() { - nodes.reserve(1000); + NodeManager() {} + + std::map nodes; + std::vector keys; + int iterator = 0; + + int getRandomNode(){ + std::vector o; + std::ranges::sample(keys, std::back_inserter(o), 1, std::mt19937{std::random_device{}()}); + return o.front(); } - std::vector nodes; - - void addNode(float x, float y){ - addNode(Vec2D(x,y)); + int addNode(float x, float y){ + return addNode(Vec2D(x,y)); } - void addNode(Vec2D position){ - nodes.emplace_back(position, 15.0f); - } - - void removeNodes(){ - std::erase_if(nodes, [](Node n){ return n.erase;}); + int addNode(Vec2D position){ + nodes.emplace(std::make_pair(iterator, Node(iterator, position, 15.0f))); + keys.push_back(iterator); + iterator++; + return iterator - 1; } void drawNodes(Vec2D *mouse_pos, Camera2D *camera){ - for(auto& n : nodes){ + for(auto& n : nodes | std::ranges::views::values ){ n.draw(mouse_pos, camera); } } diff --git a/src/node.h b/src/node.h index 8235fea..20d13f5 100644 --- a/src/node.h +++ b/src/node.h @@ -19,11 +19,13 @@ class Node : public Movable{ public: Node() {} - Node(float x, float y, float r) : Movable(Vec2D(x, y), 0.0f), radius(r) {} - Node(Vec2D p, float r) : Movable(p, 0.0f), radius(r) {} + Node(int id, float x, float y, float r) : Movable(Vec2D(x, y), 0.0f), radius(r), id(id) {} + Node(int id, Vec2D p, float r) : Movable(p, 0.0f), radius(r), id(id) {} float radius; + int id; + bool picked_up = false; bool dragging = false; bool in_rect = false; @@ -33,6 +35,7 @@ class Node : public Movable{ bool config = false; bool selected = false; bool erase = false; + bool highlighted = false; int midi_out = -1; @@ -60,7 +63,9 @@ class Node : public Movable{ void draw(Vec2D *mouse, Camera2D *cam) { if(!dragging && !selected && !in_rect && !hovering) DrawCircle(position.x, position.y, radius, (Color){180, 210, 115, 255}); - if(dragging || selected || in_rect || hovering) DrawCircle(position.x, position.y, radius, (Color){108, 153, 187, 255}); + if(selected || dragging || in_rect || hovering) DrawCircle(position.x, position.y, radius, (Color){108, 153, 187, 255}); + if(selected) DrawCircleLinesV(position, radius+1, (Color){158, 255, 210, 255}); + int offset = MeasureText(MIDI::Notes[midi_note].c_str(), 10); DrawText(MIDI::Notes[midi_note].c_str(), position.x-offset/2.0f, position.y-5, 10, WHITE ); @@ -76,5 +81,6 @@ class Node : public Movable{ DrawCircleLines(position.x, position.y, radius + R, (Color){108, 153, 187, (unsigned char)opacity}); DrawCircle(connector.x, connector.y, 8.0f, (Color){108, 153, 187, (unsigned char)opacity}); } + if(highlighted) DrawCircleLinesV(position, radius+2, (Color){255, 0, 0, 200}); } }; diff --git a/src/signal-manager.h b/src/signal-manager.h index ea1b796..8027dc7 100644 --- a/src/signal-manager.h +++ b/src/signal-manager.h @@ -2,6 +2,7 @@ #include "connection-manager.h" #include "datatypes.h" +#include "node-manager.h" #include "signal.h" #include "node.h" #include "midi.h" @@ -13,12 +14,13 @@ class SignalManager{ public: SignalManager() {} - SignalManager(ConnectionManager *cm, std::mutex *mutex) : mutex(mutex), cm(cm) {} + SignalManager(NodeManager *nm, ConnectionManager *cm, std::mutex *mutex) : mutex(mutex), cm(cm), nm(nm) {} Midi midi; std::mutex *mutex; ConnectionManager *cm; + NodeManager *nm; std::vector signals; @@ -40,7 +42,7 @@ class SignalManager{ void reset(){ for(auto &s : signals){ - s.position = s.start->position + Vec2D{0.1, 0.1}; + s.position = nm->nodes[s.start].position + Vec2D{0.1, 0.1}; s.next = s.start; s.last = s.start; } @@ -56,12 +58,12 @@ class SignalManager{ loop = false; } - void addSignalAtNode(Node *node){ - Color c = {(unsigned char)(232 - (rand() % 120)), (unsigned char)(125 + (int)(rand() % 120)), 62, 255}; - signals.emplace(signals.end(), Signal(node->position.x+1, node->position.y+1, 5.0f, 0, c)); // position + 1 or else it does not render. why? no idea! - signals.back().next = node; - signals.back().last = node; - signals.back().start = node; + void addSignalAtNode(int node_id){ + Color c = {(unsigned char)(232 - (rand() % 120)), 50, (unsigned char)(20 + (int)(rand() % 120)), 255}; + signals.emplace(signals.end(), Signal(nm->nodes[node_id].position.x+1, nm->nodes[node_id].position.y+1, 5.0f, 0, c)); // position + 1 or else it does not render. why? no idea! + signals.back().next = node_id; + signals.back().last = node_id; + signals.back().start = node_id; } void removeSignal(int n){ @@ -76,14 +78,14 @@ class SignalManager{ mutex->lock(); if(play){ for(auto& s : signals){ - s.direction = (s.next->position - s.position).norm(); + s.direction = (nm->nodes[s.next].position - s.position).norm(); s.update(diff.count()); - if(s.position.dist(&s.next->position) < 1.0f) { - Node* n = cm->next(s.next, s.last); + if(s.position.dist(&nm->nodes[s.next].position) < 1.0f) { + int n = cm->next(s.next, s.last); - if(n != s.next && n != nullptr) { - for(auto &m : s.next->midi_outs){ - if(m.second.enabled) midi.note(m.second.i, s.next->midi_channel, s.next->midi_note, s.next->midi_velocity, s.next->midi_gate); + if(n != s.next && n != -1) { + for(auto &m : nm->nodes[s.next].midi_outs){ + if(m.second.enabled) midi.note(m.second.i, nm->nodes[s.next].midi_channel, nm->nodes[s.next].midi_note, nm->nodes[s.next].midi_velocity, nm->nodes[s.next].midi_gate); } s.last = s.next; s.next = n; diff --git a/src/signal.h b/src/signal.h index a32232c..8758720 100644 --- a/src/signal.h +++ b/src/signal.h @@ -4,7 +4,6 @@ #include "datatypes.h" #include "moveable.h" -#include "node.h" class Signal : public Movable{ public: @@ -14,10 +13,10 @@ class Signal : public Movable{ int id = 0; - Node *next; - Node *last; + int next; + int last; - Node *start; + int start; bool at_target = false; int target_node_id = 1; diff --git a/src/state-manager.h b/src/state-manager.h index 967aec8..082d637 100644 --- a/src/state-manager.h +++ b/src/state-manager.h @@ -1,15 +1,21 @@ #pragma once +#include "connection.h" #include "datatypes.h" #include "node-manager.h" #include "connection-manager.h" #include "signal-manager.h" #include "ui.h" +#include +#include +#include +#include +#include class AppState{ public: - AppState() : sm(&cm, &mutex), ui(&settings, &nm, &cm, &sm) {} + AppState() : cm(&nm), sm(&nm, &cm, &mutex), ui(&settings, &nm, &cm, &sm) {} enum States {IDLE, CONFIG}; @@ -26,7 +32,7 @@ class AppState{ AppUI ui; void updateMidiPorts(){ - for(auto&n : nm.nodes){ + for(auto&n : nm.nodes | std::views::values){ for(auto& mo : sm.midi.midi_out_ports){ if(!n.midi_outs.contains(mo.number) && mo.enabled){ n.midi_outs[mo.number] = {mo.number, mo.port.port_name, false}; @@ -38,6 +44,63 @@ class AppState{ } } + void removeNodes(){ + + for(auto &n : nm.nodes){ + n.second.highlighted = false; + } + + auto erase_nodes = nm.nodes | std::ranges::views::values | std::ranges::views::filter([](Node n){return n.erase;}); + + std::vector erase_nodes_ids; + for(auto &e : erase_nodes){ + erase_nodes_ids.push_back(e.id); + } + + auto erase_connections = cm.connections | std::ranges::views::filter([erase_nodes_ids](Connection c){ return std::ranges::contains(erase_nodes_ids, c.v1) || std::ranges::contains(erase_nodes_ids, c.v2);}); + + std::vector adjacent_nodes_ids; + + for(auto &c : erase_connections){ + if(!nm.nodes.at(c.v1).selected) adjacent_nodes_ids.push_back(c.v1); + if(!nm.nodes.at(c.v2).selected) adjacent_nodes_ids.push_back(c.v2); + } + +// std::ranges::for_each(adjacent_nodes_ids, [this](int id){ nm.nodes.at(id).highlighted = true;} ); + + auto reroute_signals = sm.signals | std::ranges::views::filter([erase_nodes_ids](Signal s){ + return std::ranges::contains(erase_nodes_ids, s.next); + }); + + for(auto &s : reroute_signals){ + float dist = 10000000; + int next_id = -1; + for(int i : adjacent_nodes_ids){ + if(nm.nodes.at(i).position.dist(&s.position) < dist) { + dist = nm.nodes.at(i).position.dist(&s.position); + next_id = i; + } + } + s.next = next_id; + s.last = next_id; + } + + auto rebase_signals = sm.signals | std::ranges::views::filter([erase_nodes_ids](Signal s){ + return std::ranges::contains(erase_nodes_ids, s.start); + }); + + for(auto &s : rebase_signals){ + s.start = s.next; + } + + for(auto &n : erase_nodes){ + std::erase_if(cm.connections, [n](Connection c){ return c.v1 == n.id || c.v2 == n.id;}); + } + std::erase_if(nm.nodes, [](std::pair n){ return n.second.erase;}); + nm.keys.clear(); + std::ranges::copy(nm.nodes | std::ranges::views::keys, std::back_inserter(nm.keys)); + } + void draw(Vec2D *mouse_pos, Camera2D *camera){ mutex.lock(); updateMidiPorts(); diff --git a/src/ui.h b/src/ui.h index fa1028f..2ba131a 100644 --- a/src/ui.h +++ b/src/ui.h @@ -53,7 +53,7 @@ class AppUI{ for(auto &midis : sm->midi.midi_out_ports){ if(midis.enabled){ for(auto &n : nm->nodes){ - n.setMidiPort(midis.number, true); + n.second.setMidiPort(midis.number, true); } } } @@ -62,8 +62,8 @@ class AppUI{ int s_signal = s_midi + 90 + i*20; GuiLabel((Rectangle){20, (float)s_signal, 240, 20}, "SIGNALS"); if(GuiButton((Rectangle){20, (float)s_signal + 35, 240, 20}, "ADD RANDOM SIGNAL")){ - int ni = rand() % nm->nodes.size(); - sm->addSignalAtNode(&nm->nodes[ni]); + int ni = nm->getRandomNode(); + sm->addSignalAtNode(ni); } int signal_configs = 0; @@ -81,7 +81,8 @@ class AppUI{ int s_nodes = s_signal + 60 + signal_configs*20; GuiLabel((Rectangle){20, (float)s_nodes + 30, 240, 20}, "NODES"); if(GuiButton((Rectangle){20, (float)s_nodes + 60, 240, 20}, "ADD RANDOM NODE")){ - nm->nodes.emplace_back(200.0f, 200.0f, 15.0f); + nm->addNode(200.0f, 200.0f); +// nm->nodes.emplace_back(200.0f, 200.0f, 15.0f); } DrawFPS(20, settings->height - 30); @@ -89,7 +90,7 @@ class AppUI{ } void drawPerNodeConfig(Camera2D *camera){ - for(auto& n : nm->nodes | std::ranges::views::filter([](Node n){ return n.config; })){ + for(auto& n : nm->nodes | std::ranges::views::values | std::views::filter([](Node n){ return n.config; })){ Vector2 np = GetWorldToScreen2D((Vector2){n.position.x, n.position.y}, *camera); n.config = !GuiWindowBox((Rectangle){np.x + 10, np.y + 10, 240, 440}, "config"); @@ -100,7 +101,7 @@ class AppUI{ GuiLabel((Rectangle){np.x + 20, np.y + 65, 220, 20}, "SIGNALS"); if(GuiButton((Rectangle){np.x + 20, np.y + 90, 220, 20}, "ADD SIGNAL")){ - sm->addSignalAtNode(&n); + sm->addSignalAtNode(n.id); } int y_midi = 120;