From 7bdd68bdccf93bd14fcdf8ab9e2fb176679c7926 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Sun, 3 Nov 2024 03:48:49 +0100 Subject: [PATCH] json is loading, but does nothing yet --- .gitignore | 1 + src/datatypes.h | 82 ++++---- src/edge.h | 62 +++--- src/graph-item.h | 30 ++- src/graph-manager.h | 455 +++++++++++++++++++++---------------------- src/main.cpp | 48 +++-- src/midi-node.h | 297 ++++++++++++++-------------- src/midi.h | 181 ++++++++--------- src/moveable.h | 65 +++---- src/node.h | 59 +++--- src/signal-manager.h | 174 +++++++++-------- src/signal.h | 52 ++--- src/state-io.h | 230 ++++++++++++++-------- src/state-manager.h | 208 ++++++++++---------- src/ui.h | 326 ++++++++++++++++--------------- src/vmath.h | 8 +- 16 files changed, 1174 insertions(+), 1104 deletions(-) diff --git a/.gitignore b/.gitignore index b19ccac..ec5578d 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ build/** viseq viseq.exe compile_commands.json +state.json diff --git a/src/datatypes.h b/src/datatypes.h index 96276f6..fcd9cdf 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -27,64 +27,48 @@ using json = nlohmann::json; #include #include "libremidi/libremidi.hpp" -enum Distribution {GEOMETRIC, ROUNDROBIN, RANDOM}; - -// Types - -/*class GraphItem;*/ -/*class Node;*/ -/*class Edge;*/ -/*class Signal;*/ - #define RANGE_FILTER(L) std::ranges::views::filter(L) -/*typedef std::shared_ptr SPTR_GraphItem;*/ -/*typedef std::shared_ptr SPTR_Node;*/ -/*typedef std::shared_ptr SPTR_Edge;*/ -/**/ -/*typedef std::shared_ptr SPTR_Signal;*/ -/**/ -/*typedef std::vector VEC_SPTR_GraphItem;*/ -/*typedef std::vector VEC_SPTR_Node;*/ -/*typedef std::vector VEC_SPTR_Edge;*/ -/*typedef std::vector VEC_SPTR_Signal;*/ +namespace VISEQ::GRAPH::NODES { + enum Distribution {GEOMETRIC, ROUNDROBIN, RANDOM}; +} -// App Settings -struct AppSettings{ - int mode = 0; - int width; - int height; - float grid; - float bpm; - float fps; - float speed = 16.0f; - int gui_selected_midi_out; -}; +namespace VISEQ::APP{ + struct AppSettings{ + int mode = 0; + int width; + int height; + float grid; + float bpm; + float fps; + float speed = 16.0f; + int gui_selected_midi_out; + }; +} + +namespace VISEQ::GRAPH{ + enum GraphItemType {NODE, EDGE}; + enum NodeType {OSCNODE, MIDINODE}; +} -// Graph +namespace VISEQ::MIDI{ + struct MidiOutPort{ + libremidi::output_port port; + int number; + bool enabled; + }; -enum GraphItemType {NODE, EDGE}; -enum NodeType {OSCNODE, MIDINODE}; + struct MidiOut{ + libremidi::midi_out out; + int number; + }; -// MIDI + NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(MidiOut, number) + NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(MidiOutPort, number, enabled) -struct MidiOutPort{ - libremidi::output_port port; - int number; - bool enabled; -}; - -struct MidiOut{ - libremidi::midi_out out; - int number; -}; - -NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(MidiOut, number) -NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(MidiOutPort, number, enabled) - -namespace MIDI{ inline std::vector Fractions = {"1/32","1/16","3/32","1/8","5/32","3/16","7/32","1/4","9/32","5/16","11/32","3/8","13/32","7/16","15/32","1/2","17/32","9/16","19/32","5/8","21/32","11/16","23/32","3/4","25/32","13/16","27/32","7/8","29/32","15/16","31/32","1/1"}; + inline std::vector Notes = { "C-1", "C#-1", "D-1", "D#-1", "E-1", "F-1", "F#-1", "G-1", "G#-1", "A-1", "A#-1", "B-1", "C0", "C#0", "D0", "D#0", diff --git a/src/edge.h b/src/edge.h index b294280..82c05f8 100644 --- a/src/edge.h +++ b/src/edge.h @@ -1,38 +1,40 @@ #pragma once -#include "datatypes.h" #include "graph-item.h" +#include +#include "node.h" -class Edge : public GraphItem{ +using namespace VISEQ::GRAPH; - public: - Edge() {} - Edge(SPTR_Node start, SPTR_Node end) : start(start), end(end) {} +namespace VISEQ::GRAPH::EDGES { + class Edge : public GraphItem{ - SPTR_Node start; - SPTR_Node end; + public: + Edge() {} + Edge(std::shared_ptr start, std::shared_ptr end) : start(start), end(end) {} - bool pass_forward = true; - bool pass_backward = true; + std::shared_ptr start; + std::shared_ptr end; + + bool pass_forward = true; + bool pass_backward = true; + + bool active = false; + bool config = false; + bool split = false; + + float connector_offset = 8.0f; + float switches_offset = 25.0f; + + virtual bool GActive() {return active;} + + std::shared_ptr getNextNode(std::shared_ptr origin){ + return start == origin ? end : start; + } + + void draw(Vec2Df mouse_pos, Camera2D cam) {} + }; - bool active = false; - bool config = false; - bool split = false; - - float connector_offset = 8.0f; - float switches_offset = 25.0f; - - virtual bool GActive() {return active;} - - SPTR_Node getNextNode(SPTR_Node origin){ - return start == origin ? end : start; - } - - void draw(Vec2Df mouse_pos, Camera2D cam) {} -}; - - -/*typedef std::shared_ptr SPTR_Edge;*/ -/*typedef std::vector VEC_SPTR_Edge;*/ - -//NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Edge, id, start, end, pass_forward, pass_backward) + typedef std::shared_ptr SPTR_Edge; + typedef std::vector VEC_SPTR_Edge; +} diff --git a/src/graph-item.h b/src/graph-item.h index 98626b9..dbba9e8 100644 --- a/src/graph-item.h +++ b/src/graph-item.h @@ -5,26 +5,20 @@ #include #include -class GraphItem{ +namespace VISEQ::GRAPH { + class GraphItem{ - public: - GraphItem() {static int _id; id=_id++;} - std::vector> neighbors; - int id = 0; - GraphItemType graphItemType; + public: + GraphItem() {static int _id; id=_id++;} + std::vector> neighbors; + int id = 0; + GraphItemType graphItemType; - virtual void draw(Vec2Df mouse, Camera2D cam) {}; - virtual GraphItemType getType() {return graphItemType;} - virtual ~GraphItem() = default; + virtual void draw(Vec2Df mouse, Camera2D cam) {}; + virtual GraphItemType getType() {return graphItemType;} + virtual ~GraphItem() = default; - /*void to_json(json& j, const GraphItem& G){*/ - /* j = json{{"id",id},{"graphItemType",graphItemType},{"neighbors",neighbors}};*/ - /*}*/ + }; -}; +} - -/*typedef std::shared_ptr SPTR_GraphItem;*/ -/*typedef std::vector VEC_SPTR_GraphItem;*/ - -//NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(GraphItem, id, graphItemType, neighbors) diff --git a/src/graph-manager.h b/src/graph-manager.h index 3c5b128..d6f61b2 100644 --- a/src/graph-manager.h +++ b/src/graph-manager.h @@ -8,9 +8,9 @@ #include "nlohmann/json.hpp" #include "button.h" -#include "node.h" #include "midi-node.h" #include "edge.h" +#include "node.h" #include #include @@ -26,271 +26,264 @@ using json = nlohmann::json; -typedef std::shared_ptr SPTR_GraphItem; -typedef std::shared_ptr SPTR_Node; -typedef std::shared_ptr SPTR_Edge; +using namespace VISEQ::GRAPH::NODES; +using namespace VISEQ::GRAPH::EDGES; -typedef std::shared_ptr SPTR_Signal; +namespace VISEQ::GRAPH { -typedef std::vector VEC_SPTR_GraphItem; -typedef std::vector VEC_SPTR_Node; -typedef std::vector VEC_SPTR_Edge; -typedef std::vector VEC_SPTR_Signal; + class GraphManager{ -class GraphManager{ + public: - public: + GraphManager() {} - GraphManager() {} + NODES::VEC_SPTR_Node nodes; + EDGES::VEC_SPTR_Edge edges; - VEC_SPTR_Node nodes; - VEC_SPTR_Edge edges; + EDGES::VEC_SPTR_Edge remove_edges; + EDGES::VEC_SPTR_Edge split_edges; - VEC_SPTR_Edge remove_edges; - VEC_SPTR_Edge split_edges; + std::map counter; - std::map counter; + NODES::SPTR_Node getRandomNode(){ + VEC_SPTR_GraphItem o; + std::ranges::sample(nodes, std::back_inserter(o), 1, std::mt19937{std::random_device{}()}); + return std::dynamic_pointer_cast(o.front()); + } + + EDGES::SPTR_Edge getRandomEdge(){ + VEC_SPTR_GraphItem o; + std::ranges::sample(edges, std::back_inserter(o), 1, std::mt19937{std::random_device{}()}); + return std::dynamic_pointer_cast(o.front()); + } - /*void to_json(json& j, const GraphManager& G){*/ - /* j = json{{"nodes", G.nodes}, {"edges", G.edges}};*/ - /*}*/ - /**/ - /*void from_json(const json& j, GraphManager& G){*/ - /**/ - /*}*/ - - SPTR_Node getRandomNode(){ - VEC_SPTR_GraphItem o; - std::ranges::sample(nodes, std::back_inserter(o), 1, std::mt19937{std::random_device{}()}); - return std::dynamic_pointer_cast(o.front()); - } - - SPTR_Edge getRandomEdge(){ - VEC_SPTR_GraphItem o; - std::ranges::sample(edges, std::back_inserter(o), 1, std::mt19937{std::random_device{}()}); - return std::dynamic_pointer_cast(o.front()); - } - - void copyNodes(VEC_SPTR_Node _nodes, Vec2Df position){ - for(auto n: _nodes){ + void copyNodes(VEC_SPTR_Node _nodes, Vec2Df position){ + for(auto n: _nodes){ + nodes.insert(nodes.end(), std::make_shared(*n)); + nodes.back()->setPosition(position + nodes.back()->drag_offset); + nodes.back()->selected = false; + } + } + + void copyNodes(std::vector> _nodes, Vec2Df position){ + for(auto n: _nodes){ + nodes.insert(nodes.end(), std::make_shared(*n)); + nodes.back()->setPosition(position + nodes.back()->drag_offset); + nodes.back()->selected = false; + } + } + + SPTR_Node copyNode(SPTR_Node n, Vec2Df position){ + std::cout << "copy basenode" << std::endl; nodes.insert(nodes.end(), std::make_shared(*n)); - nodes.back()->setPosition(position + nodes.back()->drag_offset); - nodes.back()->selected = false; + nodes.back()->setPosition(position); + return nodes.back(); } - } - - void copyNodes(std::vector> _nodes, Vec2Df position){ - for(auto n: _nodes){ + + SPTR_Node copyNode(std::shared_ptr n, Vec2Df position){ + std::cout << "copy midinode" << std::endl; nodes.insert(nodes.end(), std::make_shared(*n)); - nodes.back()->setPosition(position + nodes.back()->drag_offset); - nodes.back()->selected = false; + nodes.back()->setPosition(position); + return nodes.back(); } - } - - SPTR_Node copyNode(SPTR_Node n, Vec2Df position){ - std::cout << "copy basenode" << std::endl; - nodes.insert(nodes.end(), std::make_shared(*n)); - nodes.back()->setPosition(position); - return nodes.back(); - } - - SPTR_Node copyNode(std::shared_ptr n, Vec2Df position){ - std::cout << "copy midinode" << std::endl; - nodes.insert(nodes.end(), std::make_shared(*n)); - nodes.back()->setPosition(position); - return nodes.back(); - } - - SPTR_Node addMidiNode(Vec2Df position){ - nodes.emplace_back(std::make_shared(position)); - return nodes.back(); - } - - void setNodeMode(int mode){ - for(auto n: nodes){ - n->SMode(mode); + + SPTR_Node addMidiNode(Vec2Df position){ + nodes.emplace_back(std::make_shared(position)); + return nodes.back(); } - } - void reset(){ - counter.clear(); - } - - SPTR_Node next(SPTR_Node current, SPTR_Node last){ - VEC_SPTR_Edge possible_connections = current->connections | RANGE_FILTER([current](SPTR_Edge c){ - return (c->start == current && c->pass_forward) || (c->end == current && c->pass_backward); - }) | std::ranges::to(); - - if(possible_connections.empty()) return SPTR_Node(nullptr); - - int return_path = 0; - float angle = -1; - if(current->distributionMode == Distribution::GEOMETRIC){ - Vec2Df coming_from = (current->position - last->position).norm(); - int i = 0; - for(auto n : possible_connections){ - SPTR_Node next_node = n->getNextNode(current); - float angle_v1_v2 = coming_from.norm().dot((next_node->position - current->position).norm()); - if(angle_v1_v2 > angle) { - return_path = i; - angle = angle_v1_v2; - } - ++i; + void setNodeMode(int mode){ + for(auto n: nodes){ + n->SMode(mode); } } - if(current->distributionMode == Distribution::ROUNDROBIN){ - if(counter.find(current) == counter.end()) { - counter[current] = 0; - } else { - counter[current] = (counter[current] + 1) % possible_connections.size(); - return_path = counter[current]; + void reset(){ + counter.clear(); + } + + SPTR_Node next(SPTR_Node current, SPTR_Node last){ + VEC_SPTR_Edge possible_connections = current->connections | RANGE_FILTER([current](SPTR_Edge c){ + return (c->start == current && c->pass_forward) || (c->end == current && c->pass_backward); + }) | std::ranges::to(); + + if(possible_connections.empty()) return SPTR_Node(nullptr); + + int return_path = 0; + float angle = -1; + if(current->distributionMode == Distribution::GEOMETRIC){ + Vec2Df coming_from = (current->position - last->position).norm(); + int i = 0; + for(auto n : possible_connections){ + SPTR_Node next_node = n->getNextNode(current); + float angle_v1_v2 = coming_from.norm().dot((next_node->position - current->position).norm()); + if(angle_v1_v2 > angle) { + return_path = i; + angle = angle_v1_v2; + } + ++i; + } + } + + if(current->distributionMode == Distribution::ROUNDROBIN){ + if(counter.find(current) == counter.end()) { + counter[current] = 0; + } else { + counter[current] = (counter[current] + 1) % possible_connections.size(); + return_path = counter[current]; + } + } + + if(current->distributionMode == Distribution::RANDOM){ + return_path = rand() % possible_connections.size(); + } + + //possible_connections.at(return_path)->active = true; + return possible_connections.at(return_path)->getNextNode(current); + } + + void addConnection(SPTR_Node from, SPTR_Node to){ + if(from != to) { + edges.emplace_back(std::make_shared()); + edges.back()->start = from; + edges.back()->end = to; + from->connections.push_back(edges.back()); + to->connections.push_back(edges.back()); } } - - if(current->distributionMode == Distribution::RANDOM){ - return_path = rand() % possible_connections.size(); + + void splitEdge(SPTR_Edge edge){ + split_edges.push_back(edge); } - //possible_connections.at(return_path)->active = true; - return possible_connections.at(return_path)->getNextNode(current); - } - - void addConnection(SPTR_Node from, SPTR_Node to){ - if(from != to) { - edges.emplace_back(std::make_shared()); - edges.back()->start = from; - edges.back()->end = to; - from->connections.push_back(edges.back()); - to->connections.push_back(edges.back()); + void splitEdges(){ + for(auto s : split_edges){ + Vec2Df center = s->end->position.center(s->start->position); + SPTR_Node cn = addMidiNode(center); + addConnection(s->start, cn); + addConnection(cn, s->end); + remove_edges.push_back(s); + } + split_edges.clear(); } - } - - void splitEdge(SPTR_Edge edge){ - split_edges.push_back(edge); - } - - void splitEdges(){ - for(auto s : split_edges){ - Vec2Df center = s->end->position.center(s->start->position); - SPTR_Node cn = addMidiNode(center); - addConnection(s->start, cn); - addConnection(cn, s->end); - remove_edges.push_back(s); - } - split_edges.clear(); - } - - void removeEdge(SPTR_Edge edge){ - remove_edges.push_back(edge); - } - - void removeEdges(){ - for(auto edge : remove_edges){ - std::erase(edge->start->connections, edge); - std::erase(edge->end->connections, edge); - std::erase(edges, edge); - } - remove_edges.clear(); - } - - void drawEdges(Vec2Df mouse_pos, Camera2D cam){ - if(!remove_edges.empty()) removeEdges(); - if(!split_edges.empty()) splitEdges(); - for(auto c : edges){ - Vec2Df v1_position = c->start->position - ((c->start->position - c->end->position)).norm() * (c->start->radius + c->connector_offset); - Vec2Df v2_position = c->end->position - ((c->end->position - c->start->position)).norm() * (c->end->radius + c->connector_offset); - float v1_v2_distance = v1_position.dist(&v2_position); - - float midi_gate_v1 = Clamp((4.f / 1000.f) * c->start->GGate(), 1.f, 4.f); - float midi_gate_v2 = Clamp((4.f / 1000.f) * c->end->GGate(), 1.f, 4.f); - // Line with small connector circles - - Color col = {229, 181, 103, 255}; - if(c->GActive()) col = {108, 153, 187, 255}; - DrawLine(v1_position.x, v1_position.y, v2_position.x, v2_position.y, col); - - if(midi_gate_v1 == 4.0f) col = VS_COLOR_RED; - DrawCircle(v1_position.x, v1_position.y, midi_gate_v1, col); - - col = {229, 181, 103, 255}; - if(midi_gate_v2 == 4.0f) col = VS_COLOR_RED; - DrawCircle(v2_position.x, v2_position.y, midi_gate_v2, col); - - if(v1_v2_distance < 100) c->switches_offset = v1_v2_distance/2.3f; - Vec2Df from_to_handle = c->start->position - ((c->start->position - c->end->position)).norm() * (c->start->radius + c->switches_offset); - Vec2Df to_from_handle = c->end->position - ((c->end->position - c->start->position)).norm() * (c->end->radius + c->switches_offset); - Vec2Df middle_handle = c->end->position - ((c->end->position - c->start->position))*0.4f; - Vec2Df middle_handle_2 = c->end->position - ((c->end->position - c->start->position))*0.6f; - Vec2Df 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); - Vec2Df flip_handle_2 = middle_handle_2 + (v1_position - v2_position).norm().orth() * (v1_v2_distance < 120.0f ? Clamp((120.0f - v1_v2_distance)*-0.2, -20.f, 0.f) : 1.0f); - // Dynamic opacity by distance to mouse - unsigned char opacity = 150.0f - Clamp(middle_handle.dist(mouse_pos), 0.0f, 150.0f); - unsigned char opacity_from = 250.0f - Clamp(from_to_handle.dist(mouse_pos), 0.0f, 220.0f); - unsigned char opacity_to = 250.0f - Clamp(to_from_handle.dist(mouse_pos), 0.0f, 220.0f); - - if(!c->start->dragging && !c->end->dragging){ - // On/Off switches on both sides - if(ViButton(mouse_pos, from_to_handle.x, from_to_handle.y, 8.0f, c->pass_forward ? (Color){120, 210, 115, opacity_from} : (Color){232, 50, 32, opacity_from} )) c->pass_forward = !c->pass_forward; - if(ViButton(mouse_pos, to_from_handle.x, to_from_handle.y, 8.0f, c->pass_backward ? (Color){120, 210, 115, opacity_to} : (Color){232, 50, 32, opacity_to} )) c->pass_backward = !c->pass_backward; + void removeEdge(SPTR_Edge edge){ + remove_edges.push_back(edge); + } - if(!c->pass_forward){ - Vec2Df block_point1 = (v1_position - v2_position).norm().orth()*4.0f + from_to_handle; - Vec2Df block_point2 = (v1_position - v2_position).norm().orth()*-4.0f + from_to_handle; - DrawLineEx(block_point1, block_point2, 2.0f, (Color){232,232,232,opacity_from}); - } + void removeEdges(){ + for(auto edge : remove_edges){ + std::erase(edge->start->connections, edge); + std::erase(edge->end->connections, edge); + std::erase(edges, edge); + } + remove_edges.clear(); + } + + void drawEdges(Vec2Df mouse_pos, Camera2D cam){ + if(!remove_edges.empty()) removeEdges(); + if(!split_edges.empty()) splitEdges(); + for(auto c : edges){ + Vec2Df v1_position = c->start->position - ((c->start->position - c->end->position)).norm() * (c->start->radius + c->connector_offset); + Vec2Df v2_position = c->end->position - ((c->end->position - c->start->position)).norm() * (c->end->radius + c->connector_offset); + float v1_v2_distance = v1_position.dist(&v2_position); + + float midi_gate_v1 = Clamp((4.f / 1000.f) * c->start->GGate(), 1.f, 4.f); + float midi_gate_v2 = Clamp((4.f / 1000.f) * c->end->GGate(), 1.f, 4.f); + // Line with small connector circles - if(!c->pass_backward){ - Vec2Df block_point1 = (v1_position - v2_position).norm().orth()*4.0f + to_from_handle; - Vec2Df block_point2 = (v1_position - v2_position).norm().orth()*-4.0f + to_from_handle; - DrawLineEx(block_point1, block_point2, 2.0f, (Color){232,232,232,opacity_to}); - } + Color col = {229, 181, 103, 255}; + if(c->GActive()) col = {108, 153, 187, 255}; + DrawLine(v1_position.x, v1_position.y, v2_position.x, v2_position.y, col); - if(ViButton(mouse_pos, flip_handle.x, flip_handle.y, 8.0f, (Color){232, 50, 32, opacity} )) removeEdge(c); - if(ViButton(mouse_pos, flip_handle_2.x, flip_handle_2.y, 8.0f, (Color){232, 125, 62, opacity} )) splitEdge(c); + if(midi_gate_v1 == 4.0f) col = VS_COLOR_RED; + DrawCircle(v1_position.x, v1_position.y, midi_gate_v1, col); + + col = {229, 181, 103, 255}; + if(midi_gate_v2 == 4.0f) col = VS_COLOR_RED; + DrawCircle(v2_position.x, v2_position.y, midi_gate_v2, col); + + if(v1_v2_distance < 100) c->switches_offset = v1_v2_distance/2.3f; + Vec2Df from_to_handle = c->start->position - ((c->start->position - c->end->position)).norm() * (c->start->radius + c->switches_offset); + Vec2Df to_from_handle = c->end->position - ((c->end->position - c->start->position)).norm() * (c->end->radius + c->switches_offset); + Vec2Df middle_handle = c->end->position - ((c->end->position - c->start->position))*0.4f; + Vec2Df middle_handle_2 = c->end->position - ((c->end->position - c->start->position))*0.6f; + Vec2Df 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); + Vec2Df flip_handle_2 = middle_handle_2 + (v1_position - v2_position).norm().orth() * (v1_v2_distance < 120.0f ? Clamp((120.0f - v1_v2_distance)*-0.2, -20.f, 0.f) : 1.0f); + + // Dynamic opacity by distance to mouse + unsigned char opacity = 150.0f - Clamp(middle_handle.dist(mouse_pos), 0.0f, 150.0f); + unsigned char opacity_from = 250.0f - Clamp(from_to_handle.dist(mouse_pos), 0.0f, 220.0f); + unsigned char opacity_to = 250.0f - Clamp(to_from_handle.dist(mouse_pos), 0.0f, 220.0f); + + if(!c->start->dragging && !c->end->dragging){ + // On/Off switches on both sides + if(ViButton(mouse_pos, from_to_handle.x, from_to_handle.y, 8.0f, c->pass_forward ? (Color){120, 210, 115, opacity_from} : (Color){232, 50, 32, opacity_from} )) c->pass_forward = !c->pass_forward; + if(ViButton(mouse_pos, to_from_handle.x, to_from_handle.y, 8.0f, c->pass_backward ? (Color){120, 210, 115, opacity_to} : (Color){232, 50, 32, opacity_to} )) c->pass_backward = !c->pass_backward; + + if(!c->pass_forward){ + Vec2Df block_point1 = (v1_position - v2_position).norm().orth()*4.0f + from_to_handle; + Vec2Df block_point2 = (v1_position - v2_position).norm().orth()*-4.0f + from_to_handle; + DrawLineEx(block_point1, block_point2, 2.0f, (Color){232,232,232,opacity_from}); + } + + if(!c->pass_backward){ + Vec2Df block_point1 = (v1_position - v2_position).norm().orth()*4.0f + to_from_handle; + Vec2Df block_point2 = (v1_position - v2_position).norm().orth()*-4.0f + to_from_handle; + DrawLineEx(block_point1, block_point2, 2.0f, (Color){232,232,232,opacity_to}); + } + + if(ViButton(mouse_pos, flip_handle.x, flip_handle.y, 8.0f, (Color){232, 50, 32, opacity} )) removeEdge(c); + if(ViButton(mouse_pos, flip_handle_2.x, flip_handle_2.y, 8.0f, (Color){232, 125, 62, opacity} )) splitEdge(c); + } } } - } - void drawNodes(Vec2Df mouse_pos, Camera2D camera){ - auto neighbors = nodes | RANGE_FILTER([](SPTR_Node n){ return !n->dragging && !n->selected;}) | std::ranges::to(); - float min_d = 480; - for(auto n : nodes){ - if(n->dragging){ - std::sort(neighbors.begin(), neighbors.end(), [n, mouse_pos](SPTR_Node na, SPTR_Node nb){ return na->position.dist(mouse_pos) < nb->position.dist(mouse_pos);}); - if(neighbors.size() > 1){ - min_d = neighbors.front()->position.dist(mouse_pos); - n->neighbor = neighbors.front(); - DrawCircleLinesV(n->neighbor->position, 20.0f, VS_COLOR_PINK); - for(auto nb : neighbors){ - float d = nb->position.dist(mouse_pos); - float dn = nb->position.dist(n->position); - if(d > 0 && d < min_d*1.5 && d < 960) { - std::string frac = MIDI::Fractions.at((int)Clamp(round(dn/60) - 1, 0, 31)); - Vector2 text_length = MeasureTextEx(GetFontDefault(), std::format("{:.1f}",dn).c_str(), 10.0f, 2.0f); - Vector2 text_length_frac = MeasureTextEx(GetFontDefault(), frac.c_str(), 10.0f, 2.0f); + void drawNodes(Vec2Df mouse_pos, Camera2D camera){ + auto neighbors = nodes | RANGE_FILTER([](SPTR_Node n){ return !n->dragging && !n->selected;}) | std::ranges::to(); + float min_d = 480; + for(auto n : nodes){ + if(n->dragging){ + std::sort(neighbors.begin(), neighbors.end(), [n, mouse_pos](SPTR_Node na, SPTR_Node nb){ return na->position.dist(mouse_pos) < nb->position.dist(mouse_pos);}); + if(neighbors.size() > 1){ + min_d = neighbors.front()->position.dist(mouse_pos); + n->neighbor = neighbors.front(); + DrawCircleLinesV(n->neighbor->position, 20.0f, VS_COLOR_PINK); + for(auto nb : neighbors){ + float d = nb->position.dist(mouse_pos); + float dn = nb->position.dist(n->position); + if(d > 0 && d < min_d*1.5 && d < 960) { + std::string frac = MIDI::Fractions.at((int)Clamp(round(dn/60) - 1, 0, 31)); + Vector2 text_length = MeasureTextEx(GetFontDefault(), std::format("{:.1f}",dn).c_str(), 10.0f, 2.0f); + Vector2 text_length_frac = MeasureTextEx(GetFontDefault(), frac.c_str(), 10.0f, 2.0f); + + Vec2Df middle_handle = nb->position + (n->position - nb->position) * ((dn - text_length.x)*0.5f)/dn; + Vec2Df middle_handle_frac = nb->position + (n->position - nb->position) * ((dn - text_length_frac.x)*0.5f)/dn; + Vec2Df text_position = middle_handle + (nb->position - n->position).norm().orth() * 12.0f; + Vec2Df text_position_frac = middle_handle_frac - (nb->position - n->position).norm().orth() * 4.0f; + + float rotation = Vector2Angle((Vector2){1,0}, (n->position - nb->position)) * RAD2DEG; + DrawTextPro(GetFontDefault(), std::format("{:.1f}",dn).c_str(), text_position, (Vector2){0,0}, rotation, 10.0f, 2.0f, VS_COLOR_PINK); + if(nb == neighbors.front() && IsKeyDown(KEY_LEFT_SHIFT)) DrawTextPro(GetFontDefault(), frac.c_str(), text_position_frac, (Vector2){0,0}, rotation, 10.0f, 2.0f, VS_COLOR_PINK); + Vec2Df n_position = n->position - ((n->position - nb->position)).norm() * 20.0f; + Vec2Df nb_position = nb->position - ((nb->position - n->position)).norm() * 20.0f; + DrawLineV(n_position, nb_position, VS_COLOR_PINK); + } - Vec2Df middle_handle = nb->position + (n->position - nb->position) * ((dn - text_length.x)*0.5f)/dn; - Vec2Df middle_handle_frac = nb->position + (n->position - nb->position) * ((dn - text_length_frac.x)*0.5f)/dn; - Vec2Df text_position = middle_handle + (nb->position - n->position).norm().orth() * 12.0f; - Vec2Df text_position_frac = middle_handle_frac - (nb->position - n->position).norm().orth() * 4.0f; - - float rotation = Vector2Angle((Vector2){1,0}, (n->position - nb->position)) * RAD2DEG; - DrawTextPro(GetFontDefault(), std::format("{:.1f}",dn).c_str(), text_position, (Vector2){0,0}, rotation, 10.0f, 2.0f, VS_COLOR_PINK); - if(nb == neighbors.front() && IsKeyDown(KEY_LEFT_SHIFT)) DrawTextPro(GetFontDefault(), frac.c_str(), text_position_frac, (Vector2){0,0}, rotation, 10.0f, 2.0f, VS_COLOR_PINK); - Vec2Df n_position = n->position - ((n->position - nb->position)).norm() * 20.0f; - Vec2Df nb_position = nb->position - ((nb->position - n->position)).norm() * 20.0f; - DrawLineV(n_position, nb_position, VS_COLOR_PINK); } - } } + n->draw(mouse_pos, camera); } - n->draw(mouse_pos, camera); } - } -}; + }; -NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(GraphManager, nodes, edges) + inline void to_json(json& j, const GraphManager& G){ + j = json{{"nodes", G.nodes}, {"edges", G.edges}}; + } + + inline void from_json(const json& j, GraphManager& G){ + j.at("nodes").get_to(G.nodes); // = json{{"nodes", G.nodes}, {"edges", G.edges}}; + } +} diff --git a/src/main.cpp b/src/main.cpp index bc58ddb..213fae1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,6 +6,10 @@ * */ +#include "graph-manager.h" +#include "vmath.h" +#include +#include #define RAYGUI_IMPLEMENTATION #include #include @@ -24,9 +28,11 @@ #include #include +#include "state-io.h" + using json = nlohmann::json; -AppState app; +VISEQ::APP::AppState app; Vec2Df mouse_pos; Vec2Df drag_start; @@ -72,19 +78,26 @@ int main(){ camera.rotation = 0.0f; camera.zoom = 1.0f; - for(int i = 0; i < 4; ++i){ - app.gm.addMidiNode(Vec2Df{(float)i * app.settings.grid*4 + 7 * app.settings.grid, 2 * app.settings.grid*4}); - } - for(int i = 3; i >= 0; --i){ - app.gm.addMidiNode(Vec2Df{(float)i * app.settings.grid*4 + 7 * app.settings.grid, 3 * app.settings.grid*4}); + if(std::filesystem::exists("state.json")){ + std::ifstream f("state.json"); + json graph = json::parse(f); + + app.gm = graph["graphmanager"].template get(); + + } else { + for(int i = 0; i < 4; ++i){ + app.gm.addMidiNode(Vec2Df{(float)i * app.settings.grid*4 + 7 * app.settings.grid, 2 * app.settings.grid*4}); + } + for(int i = 3; i >= 0; --i){ + app.gm.addMidiNode(Vec2Df{(float)i * app.settings.grid*4 + 7 * app.settings.grid, 3 * app.settings.grid*4}); + } + + for(int i = 0; i < 8; ++i){ + app.gm.addConnection(app.gm.nodes[i], app.gm.nodes[(i+1) % 8]); + } + app.sm.addSignalAtNode(app.gm.nodes.front()); } - for(int i = 0; i < 8; ++i){ - app.gm.addConnection(app.gm.nodes[i], app.gm.nodes[(i+1) % 8]); - } - - - app.sm.addSignalAtNode(app.gm.nodes.front()); app.sm.startSignalThread(); enum InteractionState {HOVER_CANVAS, HOVER_NODE, HOVER_CONNECTOR, DRAG_NODE, CONNECT_NODE, DRAW_SELECTION, DELETE_SELECTED_NODES, COPY_SELECTED_NODES, PASTE_SELECTED_NODES}; @@ -223,7 +236,7 @@ int main(){ float pol_r = steps; float pol_theta = Vector2Angle(Vec2Df{1,0},(mouse_pos - dragNode->neighbor->position)); - Vec2Df polar = VMath::polarToCartesian(pol_r, pol_theta); + Vec2Df polar = VISEQ::VMATH::polarToCartesian(pol_r, pol_theta); dragNode->position = dragNode->neighbor->position + polar; } else { dragNode->position = mouse_pos + dragNode->drag_offset; @@ -330,8 +343,8 @@ int main(){ midiNode->midi_pitch_bend += wheel; break;} }; - if(midiNode->midi_note < 0 ) midiNode->midi_note = app.sm.midi.midiNotes.size()-1; - if(midiNode->midi_note >= app.sm.midi.midiNotes.size() ) midiNode->midi_note = 0; + if(midiNode->midi_note < 0 ) midiNode->midi_note = VISEQ::MIDI::Notes.size()-1; + if(midiNode->midi_note >= VISEQ::MIDI::Notes.size() ) midiNode->midi_note = 0; if(midiNode->midi_cc < 0 ) midiNode->midi_cc = 127; if(midiNode->midi_cc > 127 ) midiNode->midi_cc = 0; @@ -390,7 +403,10 @@ int main(){ EndDrawing(); } - std::cout << std::setw(4) << json(app.gm) << std::endl; + std::ofstream file("state.json"); + file << json(app); + + std::cout << std::setw(4) << json(app) << std::endl; CloseWindow(); diff --git a/src/midi-node.h b/src/midi-node.h index 682261f..6057eeb 100644 --- a/src/midi-node.h +++ b/src/midi-node.h @@ -7,166 +7,165 @@ #define RADIUS 14.0f -struct NodeMidiOut{ - int i; - std::string name; - bool enabled; -}; +namespace VISEQ::GRAPH::NODES { -//NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(NodeMidiOut, i, name, enabled) - -class MidiNode : public Node{ - - public: - - MidiNode() {} - MidiNode(Vec2Df position) : Node(position) {} - - NodeType nodeType = NodeType::MIDINODE; - - bool send_note = true; - bool send_cc = false; - bool send_pc = false; - bool send_pitch_bend = false; - - int midi_out = -1; + class MidiNode : public Node{ - std::map midi_outs; - - bool gui_midi_channel_edit = false; - bool gui_midi_note_edit = false; - bool gui_midi_velocity_edit = false; - bool gui_midi_gate_edit = false; - - bool triggered = false; - - int mode = 0; - - int midi_note_channel = 1; - int midi_note = 48; - int midi_velocity = 60; - int midi_gate = 25; // gate time in milliseconds - - int midi_cc_channel = 0; - int midi_cc = 0; - int midi_cc_value = 0; - - int midi_pc_channel = 0; - int midi_pc = 0; - int midi_pc_value = 0; - - int midi_pitch_bend_channel = 0; - int midi_pitch_bend = 8192; - - float start = 0; - float fade = 0; - float time = 0; - float last = 0; - - virtual NodeType getNodeType() override {return nodeType;} - - void setMidiPort(int midi_port, bool state){ - midi_outs[midi_port].enabled = state; - } - - void trigger() override { - triggered = true; - start = GetTime(); - fade = midi_gate; - } - - void SMode(int _mode) override{ - mode = _mode; - } - - int Ggate(){ - return midi_gate; - } - - void draw(Vec2Df mouse, Camera2D cam) override { - last = time; - time = GetTime(); - if(time - start >= (float)midi_gate / 1000.0f){ - triggered = false; - fade = 0; - } else { - fade -= (time - last)*1000.0f; - } - - DrawRing(position, radius, radius+4, 0, 360, 24, (Color){60, 60, 60, 255}); - DrawRing(position, radius, radius+4, 0.0f - 90.0f, (360.0f/127.0f) * midi_velocity - 90.0f, 24, (Color){158, 134, 200, 255}); - DrawCircleLinesV(position, radius + 4, (Color){100, 100, 100, 255}); - - float midi_gate_map = round((255.f / midi_gate) * fade); - - Color gate_color = VS_COLOR_GREEN; - - switch(mode){ - case 0:{ - gate_color = ColorAlphaBlend(VS_COLOR_RED, (Color){180, 210, 115, (unsigned char)Clamp(255 - midi_gate_map, 0, 255)}, WHITE); - break;} - case 1:{ - gate_color = ColorAlphaBlend(VS_COLOR_RED, (Color){229, 181, 103, (unsigned char)Clamp(255 - midi_gate_map, 0, 255)}, WHITE); - break;} - case 2:{ - gate_color = ColorAlphaBlend(VS_COLOR_RED, (Color){232, 125, 62, (unsigned char)Clamp(255 - midi_gate_map, 0, 255)}, WHITE); - break;} - } - if(!dragging && !selected && !in_rect && !hovering) DrawCircle(position.x, position.y, radius, gate_color); - if(selected || dragging || in_rect || hovering) DrawCircle(position.x, position.y, radius, (Color){108, 153, 187, 255}); - - if(distributionMode == Distribution::RANDOM) DrawCircle(position.x, position.y, radius/2.0f, VS_COLOR_PINK); - if(distributionMode == Distribution::ROUNDROBIN) DrawCircle(position.x, position.y, radius/2.0f, VS_COLOR_YELLOW); + public: - if(selected) DrawCircleLinesV(position, radius+8, (Color){158, 255, 210, 255}); - - if(IsKeyDown(KEY_LEFT_ALT)){ - float value = 0; - int offset_gate = 0; - switch(mode){ - case 0: - value = (float)midi_gate/1000.0f; - offset_gate = MeasureText(std::format("{:.2f}", value).c_str(), 12); - DrawText(std::format("{:.2f}",value).c_str(), position.x-offset_gate/2.0f, position.y-5, 12, WHITE ); - break; - case 1: - value = (float)midi_cc_value; - offset_gate = MeasureText(std::format("{}", value).c_str(), 12); - DrawText(std::format("{}",value).c_str(), position.x-offset_gate/2.0f, position.y-5, 12, WHITE ); - break; - case 2: - value = (float)midi_pitch_bend; - offset_gate = MeasureText(std::format("{}", value).c_str(), 12); - DrawText(std::format("{}",value).c_str(), position.x-offset_gate/2.0f, position.y-5, 12, WHITE ); - break; + struct NodeMidiOut{ + int i; + std::string name; + bool enabled; + }; + + MidiNode() {} + MidiNode(Vec2Df position) : Node(position) {} + + NodeType nodeType = NodeType::MIDINODE; + + bool send_note = true; + bool send_cc = false; + bool send_pc = false; + bool send_pitch_bend = false; + + int midi_out = -1; + + std::map midi_outs; + + bool gui_midi_channel_edit = false; + bool gui_midi_note_edit = false; + bool gui_midi_velocity_edit = false; + bool gui_midi_gate_edit = false; + + bool triggered = false; + + int mode = 0; + + int midi_note_channel = 1; + int midi_note = 48; + int midi_velocity = 60; + int midi_gate = 25; // gate time in milliseconds + + int midi_cc_channel = 0; + int midi_cc = 0; + int midi_cc_value = 0; + + int midi_pc_channel = 0; + int midi_pc = 0; + int midi_pc_value = 0; + + int midi_pitch_bend_channel = 0; + int midi_pitch_bend = 8192; + + float start = 0; + float fade = 0; + float time = 0; + float last = 0; + + virtual NodeType getNodeType() const override {return nodeType;} + + void setMidiPort(int midi_port, bool state){ + midi_outs[midi_port].enabled = state; + } + + void trigger() override { + triggered = true; + start = GetTime(); + fade = midi_gate; + } + + void SMode(int _mode) override{ + mode = _mode; + } + + int Ggate(){ + return midi_gate; + } + + void draw(Vec2Df mouse, Camera2D cam) override { + last = time; + time = GetTime(); + if(time - start >= (float)midi_gate / 1000.0f){ + triggered = false; + fade = 0; + } else { + fade -= (time - last)*1000.0f; } - } else { + + DrawRing(position, radius, radius+4, 0, 360, 24, (Color){60, 60, 60, 255}); + DrawRing(position, radius, radius+4, 0.0f - 90.0f, (360.0f/127.0f) * midi_velocity - 90.0f, 24, (Color){158, 134, 200, 255}); + DrawCircleLinesV(position, radius + 4, (Color){100, 100, 100, 255}); + + float midi_gate_map = round((255.f / midi_gate) * fade); + + Color gate_color = VS_COLOR_GREEN; + switch(mode){ case 0:{ - int offset = MeasureText(MIDI::Notes[(int)midi_note].c_str(), 12); - DrawText(MIDI::Notes[midi_note].c_str(), position.x-offset/2.0f, position.y-5, 12, WHITE ); + gate_color = ColorAlphaBlend(VS_COLOR_RED, (Color){180, 210, 115, (unsigned char)Clamp(255 - midi_gate_map, 0, 255)}, WHITE); break;} case 1:{ - int offset = MeasureText(std::format("{}", midi_cc).c_str(), 12); - DrawText(std::format("{}", midi_cc).c_str(), position.x-offset/2.0f, position.y-5, 12, WHITE ); + gate_color = ColorAlphaBlend(VS_COLOR_RED, (Color){229, 181, 103, (unsigned char)Clamp(255 - midi_gate_map, 0, 255)}, WHITE); break;} case 2:{ - int offset = MeasureText(std::format("{}", midi_pitch_bend).c_str(), 12); - DrawText(std::format("{}", midi_pitch_bend).c_str(), position.x-offset/2.0f, position.y-5, 12, WHITE ); + gate_color = ColorAlphaBlend(VS_COLOR_RED, (Color){232, 125, 62, (unsigned char)Clamp(255 - midi_gate_map, 0, 255)}, WHITE); break;} } - } + if(!dragging && !selected && !in_rect && !hovering) DrawCircle(position.x, position.y, radius, gate_color); + if(selected || dragging || in_rect || hovering) DrawCircle(position.x, position.y, radius, (Color){108, 153, 187, 255}); - Vec2Df connector = position - ((position - mouse)).norm() * (radius + RADIUS); - float opacity = 150.0f - Clamp(position.dist(mouse), 0.0f, 150.0f); - - if(hover_connect){ - DrawCircle(connector.x, connector.y, 8.0f, (Color){108, 153, 187, 255}); - } else { - 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}); - } -}; + if(distributionMode == Distribution::RANDOM) DrawCircle(position.x, position.y, radius/2.0f, VS_COLOR_PINK); + if(distributionMode == Distribution::ROUNDROBIN) DrawCircle(position.x, position.y, radius/2.0f, VS_COLOR_YELLOW); + + if(selected) DrawCircleLinesV(position, radius+8, (Color){158, 255, 210, 255}); + + if(IsKeyDown(KEY_LEFT_ALT)){ + float value = 0; + int offset_gate = 0; + switch(mode){ + case 0: + value = (float)midi_gate/1000.0f; + offset_gate = MeasureText(std::format("{:.2f}", value).c_str(), 12); + DrawText(std::format("{:.2f}",value).c_str(), position.x-offset_gate/2.0f, position.y-5, 12, WHITE ); + break; + case 1: + value = (float)midi_cc_value; + offset_gate = MeasureText(std::format("{}", value).c_str(), 12); + DrawText(std::format("{}",value).c_str(), position.x-offset_gate/2.0f, position.y-5, 12, WHITE ); + break; + case 2: + value = (float)midi_pitch_bend; + offset_gate = MeasureText(std::format("{}", value).c_str(), 12); + DrawText(std::format("{}",value).c_str(), position.x-offset_gate/2.0f, position.y-5, 12, WHITE ); + break; + } + } else { + switch(mode){ + case 0:{ + int offset = MeasureText(MIDI::Notes[(int)midi_note].c_str(), 12); + DrawText(MIDI::Notes[midi_note].c_str(), position.x-offset/2.0f, position.y-5, 12, WHITE ); + break;} + case 1:{ + int offset = MeasureText(std::format("{}", midi_cc).c_str(), 12); + DrawText(std::format("{}", midi_cc).c_str(), position.x-offset/2.0f, position.y-5, 12, WHITE ); + break;} + case 2:{ + int offset = MeasureText(std::format("{}", midi_pitch_bend).c_str(), 12); + DrawText(std::format("{}", midi_pitch_bend).c_str(), position.x-offset/2.0f, position.y-5, 12, WHITE ); + break;} + } + } -//NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(MidiNode, id, nodeType, send_note, send_cc, send_pc, send_pitch_bend, midi_outs, mode, midi_note_channel, midi_note, midi_velocity, midi_gate, midi_cc_channel, midi_cc, midi_cc_value, midi_pc_channel, midi_pc, midi_pc_value, midi_pitch_bend_channel, midi_pitch_bend) + Vec2Df connector = position - ((position - mouse)).norm() * (radius + RADIUS); + float opacity = 150.0f - Clamp(position.dist(mouse), 0.0f, 150.0f); + + if(hover_connect){ + DrawCircle(connector.x, connector.y, 8.0f, (Color){108, 153, 187, 255}); + } else { + 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/midi.h b/src/midi.h index 7d24eca..ed4c672 100644 --- a/src/midi.h +++ b/src/midi.h @@ -8,122 +8,105 @@ #include #include #include -#include #include "datatypes.h" -struct NoteTimer{ - int midi_out; - int channel; - int note; - int velocity; - float start; - int gate; - bool erase = false; -}; +namespace VISEQ::MIDI { -class Midi { + struct NoteTimer{ + int midi_out; + int channel; + int note; + int velocity; + float start; + int gate; + bool erase = false; + }; - public: - Midi() { - enumerate(); - } + class Midi { - std::vector midiNotes = { - "C-1", "C#-1", "D-1", "D#-1", "E-1", "F-1", "F#-1", "G-1", - "G#-1", "A-1", "A#-1", "B-1", "C0", "C#0", "D0", "D#0", - "E0", "F0", "F#0", "G0", "G#0", "A0", "A#0", "B0", - "C1", "C#1", "D1", "D#1", "E1", "F1", "F#1", "G1", - "G#1", "A1", "A#1", "B1", "C2", "C#2", "D2", "D#2", - "E2", "F2", "F#2", "G2", "G#2", "A2", "A#2", "B2", - "C3", "C#3", "D3", "D#3", "E3", "F3", "F#3", "G3", - "G#3", "A3", "A#3", "B3", "C4", "C#4", "D4", "D#4", - "E4", "F4", "F#4", "G4", "G#4", "A4", "A#4", "B4", - "C5", "C#5", "D5", "D#5", "E5", "F5", "F#5", "G5", - "G#5", "A5", "A#5", "B5", "C6", "C#6", "D6", "D#6", - "E6", "F6", "F#6", "G6", "G#6", "A6", "A#6", "B6", - "C7", "C#7", "D7", "D#7", "E7", "F7", "F#7", "G7", - "G#7", "A7", "A#7", "B7", "C8", "C#8", "D8", "D#8", - "E8", "F8", "F#8", "G8", "G#8", "A8", "A#8", "B8", - "C9", "C#9", "D9", "D#9", "E9", "F9", "F#9", "G9", - "G#9", "A9", "A#9", "B9", "C10" - }; - - libremidi::observer obs; - - std::map> midi_outs; - std::vector midi_in_ports; - std::vector midi_out_ports; - - std::vector notes; - - float timer; - - void enumerate(){ - std::cout << (int)obs.get_current_api() << std::endl; - int i = 0; - midi_out_ports.clear(); - for(const libremidi::output_port& port : obs.get_output_ports()){ - midi_out_ports.push_back({port, i, false}); - i++; + public: + Midi() { + enumerate(); } - } - void open_midi_out(MidiOutPort *out_port){ - if(!midi_outs.contains(out_port->number)){ - auto out = std::make_shared(); - out->open_port(out_port->port); - midi_outs[out_port->number] = out; - } - } + libremidi::observer obs; + + std::map> midi_outs; + std::vector midi_in_ports; + std::vector midi_out_ports; + + std::vector notes; + + float timer; - void close_midi_out(MidiOutPort *out_port){ - if(midi_outs.contains(out_port->number)){ - midi_outs[out_port->number]->close_port(); - midi_outs.erase(out_port->number); + void enumerate(){ + std::cout << (int)obs.get_current_api() << std::endl; + int i = 0; + midi_out_ports.clear(); + for(const libremidi::output_port& port : obs.get_output_ports()){ + midi_out_ports.push_back({port, i, false}); + i++; + } } - } - void note(int midi_out, int channel, int note, int velocity, int gate){ - if(midi_outs.contains(midi_out)){ - if(midi_outs[midi_out]->is_port_open()){ - midi_outs[midi_out]->send_message(libremidi::channel_events::note_on(channel, note, velocity)); - notes.emplace_back(midi_out, channel, note, velocity, GetTime(), gate); + void open_midi_out(MidiOutPort *out_port){ + if(!midi_outs.contains(out_port->number)){ + auto out = std::make_shared(); + out->open_port(out_port->port); + midi_outs[out_port->number] = out; } } - } - - void cc(int midi_out, int channel, int cc, int value){ - if(midi_outs.contains(midi_out)){ - if(midi_outs[midi_out]->is_port_open()){ - midi_outs[midi_out]->send_message(libremidi::channel_events::control_change(channel, cc, value)); + + void close_midi_out(MidiOutPort *out_port){ + if(midi_outs.contains(out_port->number)){ + midi_outs[out_port->number]->close_port(); + midi_outs.erase(out_port->number); } } - } - - void pitch_bend(int midi_out, int channel, int pitch_value){ - if(midi_outs.contains(midi_out)){ - if(midi_outs[midi_out]->is_port_open()){ - midi_outs[midi_out]->send_message(libremidi::channel_events::pitch_bend(channel, pitch_value)); - } - } - } - void update(){ - float time = GetTime(); - for(auto &n : notes){ - if(time - n.start >= (float)n.gate / 1000.0f){ - if(midi_outs.contains(n.midi_out) && midi_outs[n.midi_out]->is_port_open()) midi_outs[n.midi_out]->send_message(libremidi::channel_events::note_off(n.channel, n.note, n.velocity)); - n.erase = true; + void note(int midi_out, int channel, int note, int velocity, int gate){ + if(midi_outs.contains(midi_out)){ + if(midi_outs[midi_out]->is_port_open()){ + midi_outs[midi_out]->send_message(libremidi::channel_events::note_on(channel, note, velocity)); + notes.emplace_back(midi_out, channel, note, velocity, GetTime(), gate); + } + } + } + + void cc(int midi_out, int channel, int cc, int value){ + if(midi_outs.contains(midi_out)){ + if(midi_outs[midi_out]->is_port_open()){ + midi_outs[midi_out]->send_message(libremidi::channel_events::control_change(channel, cc, value)); + } + } + } + + void pitch_bend(int midi_out, int channel, int pitch_value){ + if(midi_outs.contains(midi_out)){ + if(midi_outs[midi_out]->is_port_open()){ + midi_outs[midi_out]->send_message(libremidi::channel_events::pitch_bend(channel, pitch_value)); + } } } - std::erase_if(notes, [](const auto& item){return item.erase;}); - for(auto& p : midi_out_ports){ - if(p.enabled) { - open_midi_out(&p); - } else if(!p.enabled) { - close_midi_out(&p); + void update(){ + float time = GetTime(); + for(auto &n : notes){ + if(time - n.start >= (float)n.gate / 1000.0f){ + if(midi_outs.contains(n.midi_out) && midi_outs[n.midi_out]->is_port_open()) midi_outs[n.midi_out]->send_message(libremidi::channel_events::note_off(n.channel, n.note, n.velocity)); + n.erase = true; + } + } + std::erase_if(notes, [](const auto& item){return item.erase;}); + + for(auto& p : midi_out_ports){ + if(p.enabled) { + open_midi_out(&p); + } else if(!p.enabled) { + close_midi_out(&p); + } } } - } -}; + }; + +} diff --git a/src/moveable.h b/src/moveable.h index 6efc10d..3a635aa 100644 --- a/src/moveable.h +++ b/src/moveable.h @@ -2,44 +2,41 @@ #include "datatypes.h" +namespace VISEQ::BASE { + class Movable{ -class Movable{ + public: + Movable() {} + virtual ~Movable() {} - public: - Movable() {} - virtual ~Movable() {} + Movable(Vec2Df p, Vec2Df d, float s) : speed(s), position(p), direction(d) {} + Movable(Vec2Df p, float s) : speed(s), position(p) {} - Movable(Vec2Df p, Vec2Df d, float s) : speed(s), position(p), direction(d) {} - Movable(Vec2Df p, float s) : speed(s), position(p) {} + float speed = 1.0f; + + Vec2Df position; + Vec2Df direction; - float speed = 1.0f; - - Vec2Df position; - Vec2Df direction; + Vec2Df drag_offset; + + bool in_rect = false; + + bool picked_up = false; + bool dragging = false; + bool hover_connect = false; + bool hovering = false; + bool connecting = false; + bool selected = false; + bool highlighted = false; + bool copied = false; + + bool erase = false; - Vec2Df drag_offset; - - bool in_rect = false; - - bool picked_up = false; - bool dragging = false; - bool hover_connect = false; - bool hovering = false; - bool connecting = false; - bool selected = false; - bool highlighted = false; - bool copied = false; - - bool erase = false; + virtual void setPosition(Vec2Df _position) {position = _position;} + virtual Vec2Df getPosition() {return position;}; + virtual void update(double frametime) {}; + virtual void update() {}; - virtual void setPosition(Vec2Df _position) {position = _position;} - virtual Vec2Df getPosition() {return position;}; - virtual void update(double frametime) {}; - virtual void update() {}; + }; - /*virtual void to_json(json& j, const Movable& M){*/ - /* j = json{{"position", M.position}, {"direction", M.direction}, {"speed", M.speed}};*/ - /*}*/ -}; - -//NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Movable, position, direction, speed) +} diff --git a/src/node.h b/src/node.h index 6d8d9a2..4fc931a 100644 --- a/src/node.h +++ b/src/node.h @@ -3,51 +3,44 @@ #include #include -#include "nlohmann/json.hpp" - #include "datatypes.h" #include "graph-item.h" #include "moveable.h" -class Edge; +namespace VISEQ::GRAPH::EDGES{ + class Edge; +} -typedef std::shared_ptr SPTR_Edge; -typedef std::vector VEC_SPTR_Edge; +namespace VISEQ::GRAPH::NODES { -class Node : public Movable, public GraphItem{ + class Node : public BASE::Movable, public GraphItem{ - public: - Node() {} - Node(float x, float y) : Movable(Vec2Df(x, y), 0.0f) {} - Node(Vec2Df p) : Movable(p, 0.0f) {} + public: + Node() {} + Node(float x, float y) : Movable(Vec2Df(x, y), 0.0f) {} + Node(Vec2Df p) : Movable(p, 0.0f) {} - NodeType nodeType; + NodeType nodeType; - std::shared_ptr neighbor; - - VEC_SPTR_Edge connections; + std::shared_ptr neighbor; + + std::vector> connections; - Distribution distributionMode = Distribution::GEOMETRIC; + Distribution distributionMode = Distribution::GEOMETRIC; - float radius = 15.0f; - bool config = false; + float radius = 15.0f; + bool config = false; - virtual NodeType getNodeType() {return nodeType;} + virtual NodeType getNodeType() const {return nodeType;} - virtual void SMode(int mode) {}; - virtual int GGate() {return 0;}; - virtual int GActive() {return 0;}; - virtual void trigger() {}; - void draw(Vec2Df mouse_pos, Camera2D cam) override {} -}; + virtual void SMode(int mode) {}; + virtual int GGate() {return 0;}; + virtual int GActive() {return 0;}; + virtual void trigger() {}; + void draw(Vec2Df mouse_pos, Camera2D cam) override {} + }; -typedef std::shared_ptr SPTR_Node; -typedef std::vector VEC_SPTR_Node; + typedef std::shared_ptr SPTR_Node; + typedef std::vector VEC_SPTR_Node; - -/*inline void to_json(json& j, const std::shared_ptr& N){*/ -/* j = json{{"id", N->id}, {"nodeType",N->nodeType}};*/ -/*}*/ - -//NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Node, nodeType, neighbor, connections, distributionMode) -//NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Node, id, nodeType, distributionMode) +} diff --git a/src/signal-manager.h b/src/signal-manager.h index 647c83d..5dd31fb 100644 --- a/src/signal-manager.h +++ b/src/signal-manager.h @@ -10,107 +10,119 @@ #include #include -class SignalManager{ +using namespace VISEQ::GRAPH; - public: - SignalManager() {} - SignalManager(GraphManager *gm, std::mutex *mutex) : mutex(mutex), gm(gm) {} - - Midi midi; - - std::mutex *mutex; - GraphManager *gm; +namespace VISEQ::SIGNAL { - VEC_SPTR_Signal signals; + typedef std::shared_ptr SPTR_Signal; + typedef std::vector VEC_SPTR_Signal; - bool loop = true; - bool play = false; + class SignalManager{ - void pause(){ - play = false; - } + public: + SignalManager() {} + SignalManager(GraphManager *gm, std::mutex *mutex) : mutex(mutex), gm(gm) {} + + VISEQ::MIDI::Midi midi; + + std::mutex *mutex; + GraphManager *gm; - void stop(){ - play = false; - reset(); - } + VEC_SPTR_Signal signals; - void start(){ - play = true; - } - - void reset(){ - for(auto &s : signals){ - s->position = s->start->position + Vec2Df{0.1, 0.1}; - s->next = s->start; - s->last = s->start; + bool loop = true; + bool play = false; + + void pause(){ + play = false; } - gm->reset(); - } - void startSignalThread(){ - std::thread t1(&SignalManager::updateSignals, this); - t1.detach(); - } + void stop(){ + play = false; + reset(); + } - void stopSignalThread(){ - loop = false; - } - - void addSignalAtNode(SPTR_Node node){ - Color c = {(unsigned char)(20 + (rand() % 200)), 100, (unsigned char)(20 + (int)(rand() % 200)), 200}; - signals.emplace_back(std::make_shared(node->position + Vec2Df{0.5f, 0.5f}, 8.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 start(){ + play = true; + } + + void reset(){ + for(auto &s : signals){ + s->position = s->start->position + Vec2Df{0.1, 0.1}; + s->next = s->start; + s->last = s->start; + } + gm->reset(); + } - void removeSignal(int n){ - signals.erase(signals.begin() + n); - } + void startSignalThread(){ + std::thread t1(&SignalManager::updateSignals, this); + t1.detach(); + } - void updateSignals(){ - auto last = std::chrono::high_resolution_clock::now(); - while(loop){ - std::chrono::duration diff = std::chrono::high_resolution_clock::now() - last; - if((int)diff.count() >= 250){ - mutex->lock(); - if(play){ - for(auto& s : signals){ - s->direction = (s->next->position - s->position).norm(); - s->update(diff.count()); - if(s->position.dist(s->next->position) < 0.6f) { - SPTR_Node next_node = gm->next(s->next, s->last); - s->next->trigger(); + void stopSignalThread(){ + loop = false; + } + + void addSignalAtNode(SPTR_Node node){ + Color c = {(unsigned char)(20 + (rand() % 200)), 100, (unsigned char)(20 + (int)(rand() % 200)), 200}; + signals.emplace_back(std::make_shared(node->position + Vec2Df{0.5f, 0.5f}, 8.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; + } - if(next_node != s->next && next_node != SPTR_Node(nullptr) && s->next->getNodeType() == NodeType::MIDINODE) { - auto midinode = std::dynamic_pointer_cast(s->next); - for(auto &m : midinode->midi_outs){ - if(m.second.enabled) { - if(midinode->send_note) midi.note(m.second.i, midinode->midi_note_channel, midinode->midi_note, midinode->midi_velocity, midinode->midi_gate); - if(midinode->send_cc) midi.cc(m.second.i, midinode->midi_cc_channel, midinode->midi_cc, midinode->midi_cc_value); - if(midinode->send_pitch_bend) midi.pitch_bend(m.second.i, midinode->midi_pitch_bend_channel, midinode->midi_pitch_bend); + void removeSignal(int n){ + signals.erase(signals.begin() + n); + } + + void updateSignals(){ + auto last = std::chrono::high_resolution_clock::now(); + while(loop){ + std::chrono::duration diff = std::chrono::high_resolution_clock::now() - last; + if((int)diff.count() >= 250){ + mutex->lock(); + if(play){ + for(auto& s : signals){ + s->direction = (s->next->position - s->position).norm(); + s->update(diff.count()); + if(s->position.dist(s->next->position) < 0.6f) { + SPTR_Node next_node = gm->next(s->next, s->last); + s->next->trigger(); + + if(next_node != s->next && next_node != SPTR_Node(nullptr) && s->next->getNodeType() == NodeType::MIDINODE) { + auto midinode = std::dynamic_pointer_cast(s->next); + for(auto &m : midinode->midi_outs){ + if(m.second.enabled) { + if(midinode->send_note) midi.note(m.second.i, midinode->midi_note_channel, midinode->midi_note, midinode->midi_velocity, midinode->midi_gate); + if(midinode->send_cc) midi.cc(m.second.i, midinode->midi_cc_channel, midinode->midi_cc, midinode->midi_cc_value); + if(midinode->send_pitch_bend) midi.pitch_bend(m.second.i, midinode->midi_pitch_bend_channel, midinode->midi_pitch_bend); + } } + s->last = s->next; + s->next = next_node; } - s->last = s->next; - s->next = next_node; } } } + midi.update(); + mutex->unlock(); + last = std::chrono::high_resolution_clock::now(); } - midi.update(); - mutex->unlock(); - last = std::chrono::high_resolution_clock::now(); } } - } - void drawSignals(Vec2Df mouse_pos, Camera2D camera){ - for(auto s : signals){ - mutex->lock(); - s->draw(mouse_pos, camera); - mutex->unlock(); + void drawSignals(Vec2Df mouse_pos, Camera2D camera){ + for(auto s : signals){ + mutex->lock(); + s->draw(mouse_pos, camera); + mutex->unlock(); + } } - } -}; + }; + + inline void to_json(json& j, const SignalManager& G){ + j = json{{"signals", G.signals}}; + } +} diff --git a/src/signal.h b/src/signal.h index f487261..262454d 100644 --- a/src/signal.h +++ b/src/signal.h @@ -1,40 +1,44 @@ #pragma once #include -#include "datatypes.h" #include "moveable.h" #include "node.h" #include "edge.h" -class Signal : public Movable{ - public: +using namespace VISEQ::GRAPH; - Signal(); - Signal(Vec2Df position, float r, float _speed, Color color) : Movable(position, Vec2Df(0,0), _speed), radius(r), color(color) {} - - SPTR_Node next; - SPTR_Node last; - SPTR_Edge edge; +namespace VISEQ::SIGNAL { + class Signal : public BASE::Movable{ + public: - SPTR_Node start; + Signal(); + Signal(Vec2Df position, float r, float _speed, Color color) : Movable(position, Vec2Df(0,0), _speed), radius(r), color(color) {} + + NODES::SPTR_Node next; + NODES::SPTR_Node last; + EDGES::SPTR_Edge edge; - bool at_target = false; + NODES::SPTR_Node start; - float radius; + bool at_target = false; - float multiplier = 1.0f; + float radius; - Color color; + float multiplier = 1.0f; - void update(double t_delta){ - // 120px / 16th = 1920px / whole note - // whole note = 2s at 120bpm - // 960px / s - position += direction.norm() * speed * multiplier * (float)t_delta / 1000000.0f; - } + Color color; - void draw(Vec2Df mouse, Camera2D cam) { - DrawCircle(position.x, position.y, radius, color); - } -}; + void update(double t_delta){ + // 120px / 16th = 1920px / whole note + // whole note = 2s at 120bpm + // 960px / s + position += direction.norm() * speed * multiplier * (float)t_delta / 1000000.0f; + } + + void draw(Vec2Df mouse, Camera2D cam) { + DrawCircle(position.x, position.y, radius, color); + } + }; + +} diff --git a/src/state-io.h b/src/state-io.h index 734373b..0ba95ab 100644 --- a/src/state-io.h +++ b/src/state-io.h @@ -4,94 +4,170 @@ #include "graph-item.h" #include "node.h" #include "edge.h" -#include "graph-manager.h" +//#include "graph-manager.h" #include "datatypes.h" +#include "signal.h" +#include #include -/*namespace nlohmann { */ -/* template */ -/* struct adl_serializer> {*/ -/* static void to_json(json& j, const std::shared_ptr& opt){*/ -/* if (opt)*/ -/* {*/ -/* j = *opt;*/ -/* }*/ -/* else*/ -/* {*/ -/* j = nullptr;*/ -/* }*/ -/* }*/ -/**/ -/* static void from_json(const json& j, std::shared_ptr& opt){*/ -/* if (j.is_null())*/ -/* {*/ -/* opt = nullptr;*/ -/* }*/ -/* else*/ -/* {*/ -/* opt.reset(new T(j.get()));*/ -/* //opt = j.get();*/ -/* }*/ -/* }*/ -/* };*/ -/*}*/ +/*using namespace VISEQ::BASE;*/ +/*using namespace VISEQ::SIGNAL;*/ +/*using namespace VISEQ::GRAPH::NODES;*/ +/*using namespace VISEQ::GRAPH::EDGES;*/ +typedef std::shared_ptr SPTR_GraphItem; +typedef std::vector VEC_SPTR_GraphItem; +namespace VISEQ::GRAPH::EDGES { + using namespace VISEQ::GRAPH::NODES; -inline void to_json(json& j, const Edge& E){ - j = json{{"id",E.id}, {"start", E.start->id}, {"end",E.end->id}, {"pass_forward",E.pass_forward}, {"pass_backward", E.pass_backward}}; -} + inline void to_json(json& j, const VISEQ::GRAPH::EDGES::Edge& E){ + j = json{{"id",E.id}, {"start", E.start->id}, {"end",E.end->id}, {"pass_forward",E.pass_forward}, {"pass_backward", E.pass_backward}}; + } + + inline void from_json(const json& j, Edge& E){ + j.at("id").get_to(E.id); + j.at("pass_forward").get_to(E.pass_forward); + j.at("pass_backward").get_to(E.pass_backward); + } -inline void to_json(json& j, const SPTR_Edge& E){ - j = *E; -} - -inline void to_json(json& j, const MidiNode& N){ - std::vector conns; - std::ranges::transform(N.connections.begin(), N.connections.end(), std::back_inserter(conns), [](SPTR_Edge e){ return e->id;}); - j = json{{"id", N.id}, {"position", N.position}, {"distributionMode", N.distributionMode}, - {"midi_note_channel",N.midi_note_channel}, - {"midi_velocity",N.midi_velocity}, - {"midi_gatel",N.midi_gate}, - {"midi_cc_channel",N.midi_cc_channel}, - {"midi_cc",N.midi_cc}, - {"midi_cc_value",N.midi_cc_value}, - {"midi_pc_channel",N.midi_pc_channel}, - {"midi_pc_value",N.midi_pc_value}, - {"midi_pitch_bend_channel",N.midi_pitch_bend_channel}, - {"midi_pitch_bend",N.midi_pitch_bend}, - {"connections",conns}}; -} - -inline void to_json(json& j, const std::shared_ptr& N){ - j = *N; -} - -inline void to_json(json& j, const GraphItem& G){ - j = json{{"id", G.id}, {"type", G.graphItemType}}; -} - -inline void to_json(json& j, const SPTR_GraphItem& G){ - j = *G; -} - -inline void to_json(json& j, const MidiOutPort MO){ - j = json{{"port_id", MO.number}, {"enabled", MO.enabled}}; -} - -inline void to_json(json& j, const NodeMidiOut MO){ - j = json{{"port_id", MO.i}, {"enabled", MO.enabled}, {"name", MO.name}}; -} - -inline void to_json(json& j, const Node& N){ - if(N.nodeType == NodeType::MIDINODE){ - j = dynamic_cast(N); + inline void to_json(json& j, const VISEQ::GRAPH::EDGES::SPTR_Edge& E){ + j = *E; + } + + inline void from_json(const json& j, VISEQ::GRAPH::EDGES::SPTR_Edge& E){ + E.reset(new Edge(j.get())); } } -inline void to_json(json& j, const std::shared_ptr& N){ - j = *N; +namespace VISEQ::GRAPH::NODES { + + /* ------------------- MIDINODE ---------------------- */ + + inline void to_json(json& j, const MidiNode& N){ + std::vector conns; + std::ranges::transform(N.connections.begin(), N.connections.end(), std::back_inserter(conns), [](VISEQ::GRAPH::EDGES::SPTR_Edge e){ return e->id;}); + + j = json{ + {"id", N.id}, + {"position", N.position}, + {"distributionMode", N.distributionMode}, + {"nodeType", N.nodeType}, + {"midi_note_channel",N.midi_note_channel}, + {"midi_velocity",N.midi_velocity}, + {"midi_gate",N.midi_gate}, + {"midi_cc_channel",N.midi_cc_channel}, + {"midi_cc",N.midi_cc}, + {"midi_cc_value",N.midi_cc_value}, + {"midi_pc_channel",N.midi_pc_channel}, + {"midi_pc_value",N.midi_pc_value}, + {"midi_pitch_bend_channel",N.midi_pitch_bend_channel}, + {"midi_pitch_bend",N.midi_pitch_bend}, + {"connections",conns}}; + } + + inline void from_json(const json& j, MidiNode& N){ + j.at("id").get_to(N.id); + j.at("position").get_to(N.position); + j.at("distributionMode").get_to(N.distributionMode); + j.at("nodeType").get_to(N.nodeType); + j.at("midi_note_channel").get_to(N.midi_note_channel); + j.at("midi_velocity").get_to(N.midi_velocity); + j.at("midi_gate").get_to(N.midi_gate); + j.at("midi_cc_channel").get_to(N.midi_cc_channel); + j.at("midi_cc").get_to(N.midi_cc); + j.at("midi_cc_value").get_to(N.midi_cc_value); + j.at("midi_pc_channel").get_to(N.midi_pc_channel); + j.at("midi_pc_value").get_to(N.midi_pc_value); + j.at("midi_pitch_bend_channel").get_to(N.midi_pitch_bend_channel); + j.at("midi_pitch_bend").get_to(N.midi_pitch_bend); + + //j.at("connections").get_to(N.connections); + } + + inline void to_json(json& j, const std::shared_ptr& N){ + j = *N; + } + + inline void from_json(const json& j, std::shared_ptr& N){ + N.reset(new MidiNode(j.get())); + } + + + /* ------------------- NODE ---------------------- */ + + + inline void to_json(json& j, const Node& N){ + if(N.getNodeType() == NodeType::MIDINODE){ + j = dynamic_cast(N); + } + } + + inline void from_json(const json& j, Node& N){ + + if(j.at("nodeType") == NodeType::MIDINODE){ + std::cout << j.at("nodeType") << std::endl; + N = j.template get(); + } + + /*j.at("id").get_to(N.id);*/ + /*j.at("position").get_to(N.position);*/ + /*j.at("distributionMode").get_to(N.distributionMode);*/ + /*j.at("nodeType").get_to(N.nodeType);*/ + //j.at("connections").get_to(N.connections); + } + + inline void to_json(json& j, const SPTR_Node& N){ + j = *N; + } + + inline void to_json(json& j, const MidiNode::NodeMidiOut MO){ + j = json{{"port_id", MO.i}, {"enabled", MO.enabled}, {"name", MO.name}}; + } + + inline void from_json(const json& j, std::shared_ptr& N){ + N.reset(new Node(j.get())); + } + } + +namespace VISEQ::GRAPH { + inline void to_json(json& j, const GraphItem& G){ + j = json{{"id", G.id}, {"type", G.graphItemType}}; + } + + inline void to_json(json& j, const SPTR_GraphItem& G){ + j = *G; + } +} + +namespace VISEQ::BASE{ + inline void to_json(json& j, const Movable& G){ + j = json{{"position", G.position}}; + } + + inline void to_json(json& j, const std::shared_ptr& G){ + j = *G; + } +} + +namespace VISEQ::SIGNAL{ + inline void to_json(json& j, const Signal& G){ + j = json{{"position", G.position},{"start",G.start->id},{"speed",G.speed}}; + } + + inline void to_json(json& j, const std::shared_ptr& G){ + j = *G; + } +} + +namespace VISEQ::MIDI { + inline void to_json(json& j, const MidiOutPort MO){ + j = json{{"port_id", MO.number}, {"enabled", MO.enabled}}; + } +} + + diff --git a/src/state-manager.h b/src/state-manager.h index fd1acd0..826bcd5 100644 --- a/src/state-manager.h +++ b/src/state-manager.h @@ -1,6 +1,5 @@ #pragma once -#include "edge.h" #include "datatypes.h" #include "graph-manager.h" #include "midi-node.h" @@ -13,134 +12,145 @@ #include #include -class AppState{ - public: +namespace VISEQ::APP { - AppState() : sm(&gm, &mutex), ui(&settings, &sm, &gm) {} + class AppState{ + public: + + AppState() : sm(&gm, &mutex), ui(&settings, &sm, &gm) {} - enum States {IDLE, CONFIG}; - - AppSettings settings; + enum States {IDLE, CONFIG}; + + AppSettings settings; - States state; + States state; - std::mutex mutex; + std::mutex mutex; - GraphManager gm; - SignalManager sm; + VISEQ::GRAPH::GraphManager gm; + VISEQ::SIGNAL::SignalManager sm; - AppUI ui; + UI::AppUI ui; - void updateMidiPorts(){ - for(auto&n : gm.nodes | RANGE_FILTER([](SPTR_Node n){return n->getNodeType() == NodeType::MIDINODE;})){ - auto nc = std::dynamic_pointer_cast(n); - for(auto& mo : sm.midi.midi_out_ports){ - if(!nc->midi_outs.contains(mo.number) && mo.enabled){ - nc->midi_outs[mo.number] = {mo.number, mo.port.port_name, false}; - } - if(nc->midi_outs.contains(mo.number) && !mo.enabled){ - nc->midi_outs.erase(mo.number); + void updateMidiPorts(){ + for(auto&n : gm.nodes | RANGE_FILTER([](VISEQ::GRAPH::NODES::SPTR_Node n){return n->getNodeType() == NodeType::MIDINODE;})){ + auto nc = std::dynamic_pointer_cast(n); + for(auto& mo : sm.midi.midi_out_ports){ + if(!nc->midi_outs.contains(mo.number) && mo.enabled){ + nc->midi_outs[mo.number] = {mo.number, mo.port.port_name, false}; + } + if(nc->midi_outs.contains(mo.number) && !mo.enabled){ + nc->midi_outs.erase(mo.number); + } } } } - } - void copyNodesAndConnections(VEC_SPTR_Node nodes, Vec2Df position){ + void copyNodesAndConnections(VEC_SPTR_Node nodes, Vec2Df position){ - VEC_SPTR_Edge copy_connections; - for(auto n : nodes){ - for(auto c : n->connections){ - if(std::ranges::contains(nodes, c->start) && std::ranges::contains(nodes, c->end)) { - copy_connections.push_back(std::make_shared(*c)); + VEC_SPTR_Edge copy_connections; + for(auto n : nodes){ + for(auto c : n->connections){ + if(std::ranges::contains(nodes, c->start) && std::ranges::contains(nodes, c->end)) { + copy_connections.push_back(std::make_shared(*c)); + } } } - } - std::cout << copy_connections.size() << std::endl; + std::cout << copy_connections.size() << std::endl; - for(auto old_node : nodes){ - SPTR_Node new_node; + for(auto old_node : nodes){ + SPTR_Node new_node; - if(old_node->getNodeType() == NodeType::MIDINODE) { - new_node = gm.copyNode(std::dynamic_pointer_cast(old_node), position + old_node->drag_offset); - } else { - new_node = gm.copyNode(old_node, position + old_node->drag_offset); - } - - new_node->copied = false; - new_node->selected = false; - - for(auto c : copy_connections){ - if(c->start == old_node) { - c->start = new_node; - c->start->connections.push_back(c); + if(old_node->getNodeType() == NodeType::MIDINODE) { + new_node = gm.copyNode(std::dynamic_pointer_cast(old_node), position + old_node->drag_offset); + } else { + new_node = gm.copyNode(old_node, position + old_node->drag_offset); } - if(c->end == old_node) { - c->end = new_node; - c->end->connections.push_back(c); + + new_node->copied = false; + new_node->selected = false; + + for(auto c : copy_connections){ + if(c->start == old_node) { + c->start = new_node; + c->start->connections.push_back(c); + } + if(c->end == old_node) { + c->end = new_node; + c->end->connections.push_back(c); + } } } - } - std::ranges::copy(copy_connections.begin(), copy_connections.end(), std::back_inserter(gm.edges)); - } - - void removeNodes(VEC_SPTR_Node nodes){ - - for(auto n : gm.nodes){ - n->highlighted = false; + std::ranges::copy(copy_connections.begin(), copy_connections.end(), std::back_inserter(gm.edges)); } - auto erase_connections = gm.edges | RANGE_FILTER([nodes](SPTR_Edge c){ return std::ranges::contains(nodes, c->start) || std::ranges::contains(nodes, c->end);}); + void removeNodes(VEC_SPTR_Node nodes){ - VEC_SPTR_Node adjacent_nodes; + for(auto n : gm.nodes){ + n->highlighted = false; + } - for(auto c : erase_connections){ - if(!c->start->selected) adjacent_nodes.push_back(c->start); - if(!c->end->selected) adjacent_nodes.push_back(c->end); - } + auto erase_connections = gm.edges | RANGE_FILTER([nodes](SPTR_Edge c){ return std::ranges::contains(nodes, c->start) || std::ranges::contains(nodes, c->end);}); - auto reroute_signals = sm.signals | RANGE_FILTER([nodes](SPTR_Signal s){return std::ranges::contains(nodes, s->next);}); + VEC_SPTR_Node adjacent_nodes; + + for(auto c : erase_connections){ + if(!c->start->selected) adjacent_nodes.push_back(c->start); + if(!c->end->selected) adjacent_nodes.push_back(c->end); + } + + auto reroute_signals = sm.signals | RANGE_FILTER([nodes](SIGNAL::SPTR_Signal s){return std::ranges::contains(nodes, s->next);}); + + for(auto s : reroute_signals){ + float dist = 10000000; + SPTR_Node next_node; + for(auto n : adjacent_nodes){ + if(n->position.dist(s->position) < dist) { + dist = n->position.dist(s->position); + next_node = n; + } + } + s->next = next_node; + s->last = next_node; + } + + auto rebase_signals = sm.signals | RANGE_FILTER([nodes](SIGNAL::SPTR_Signal s){return std::ranges::contains(nodes, s->start);}); + + for(auto s : rebase_signals){ + s->start = s->next; + } - for(auto s : reroute_signals){ - float dist = 10000000; - SPTR_Node next_node; for(auto n : adjacent_nodes){ - if(n->position.dist(s->position) < dist) { - dist = n->position.dist(s->position); - next_node = n; - } + std::erase_if(n->connections, [n, nodes](VISEQ::GRAPH::EDGES::SPTR_Edge c){ return std::ranges::contains(nodes, c->start) || std::ranges::contains(nodes, c->end);}); } - s->next = next_node; - s->last = next_node; + + for(auto n : nodes){ + std::erase_if(gm.edges, [n](SPTR_Edge c){ return c->start == n || c->end == n;}); + } + std::erase_if(gm.nodes, [nodes](SPTR_Node n){ return std::ranges::contains(nodes, n);}); } - auto rebase_signals = sm.signals | RANGE_FILTER([nodes](SPTR_Signal s){return std::ranges::contains(nodes, s->start);}); - - for(auto s : rebase_signals){ - s->start = s->next; + void draw(Vec2Df mouse_pos, Camera2D camera){ + mutex.lock(); + updateMidiPorts(); + mutex.unlock(); + gm.drawNodes(mouse_pos, camera); + gm.drawEdges(mouse_pos, camera); + sm.drawSignals(mouse_pos, camera); } - for(auto n : adjacent_nodes){ - std::erase_if(n->connections, [n, nodes](SPTR_Edge c){ return std::ranges::contains(nodes, c->start) || std::ranges::contains(nodes, c->end);}); + void drawUI(Vec2Df *mouse_pos, Camera2D *camera){ + mutex.lock(); + ui.draw(mouse_pos, camera); + mutex.unlock(); } - - for(auto n : nodes){ - std::erase_if(gm.edges, [n](SPTR_Edge c){ return c->start == n || c->end == n;}); - } - std::erase_if(gm.nodes, [nodes](SPTR_Node n){ return std::ranges::contains(nodes, n);}); - } - - void draw(Vec2Df mouse_pos, Camera2D camera){ - mutex.lock(); - updateMidiPorts(); - mutex.unlock(); - gm.drawNodes(mouse_pos, camera); - gm.drawEdges(mouse_pos, camera); - sm.drawSignals(mouse_pos, camera); - } + }; - void drawUI(Vec2Df *mouse_pos, Camera2D *camera){ - mutex.lock(); - ui.draw(mouse_pos, camera); - mutex.unlock(); - } -}; + inline void to_json(json& j, const AppState& A){ + j = json{{"graphmanager", A.gm}, {"signalmanager", A.sm}}; + } + + inline void from_json(const json& j, AppState& A){ + j.at("graphmanager").get_to(A.gm); // = json{{"graphmanager", A.gm}, {"signalmanager", A.sm}}; + } +} diff --git a/src/ui.h b/src/ui.h index 5263483..8b03244 100644 --- a/src/ui.h +++ b/src/ui.h @@ -12,176 +12,178 @@ #include #include -class AppUI{ - public: +namespace VISEQ::APP::UI{ + class AppUI{ + public: + AppUI() {} + AppUI(AppSettings *settings, SIGNAL::SignalManager *sm, GraphManager *gm) : settings(settings), gm(gm), sm(sm) {} - AppUI(AppSettings *settings, SignalManager *sm, GraphManager *gm) : settings(settings), gm(gm), sm(sm) {} + AppSettings *settings; + GraphManager *gm; + SIGNAL::SignalManager *sm; - AppSettings *settings; - GraphManager *gm; - SignalManager *sm; - - void init(){ - GuiLoadStyleDark(); - } - - void drawSideBar(){ - - GuiPanel((Rectangle){-1,-30,280,(float)settings->height + 31}, ""); - const int s_controls = 25; - //GuiSetStyle(BUTTON, STATE_FOCUSED, 0xFF0000FF); - if(GuiButton((Rectangle){20, (float)s_controls, 80, 30}, "PLAY")) sm->play ? sm->pause() : sm->start(); - if(GuiButton((Rectangle){120, (float)s_controls, 60, 30}, "STOP")) sm->stop(); - if(GuiButton((Rectangle){200, (float)s_controls, 60, 30}, "RESET")) sm->reset(); - - const int s_bpm = s_controls + 45; - GuiLabel((Rectangle){20, (float)s_bpm, 120, 20}, "TIMING"); - GuiLabel((Rectangle){200, (float)s_bpm, 40, 20}, std::format("{}",settings->bpm).c_str()); - float _bpm = (float)settings->bpm; - GuiSlider((Rectangle){20, (float)s_bpm + 25, 240, 20}, "", "", &_bpm, 1, 300); - settings->bpm = _bpm; - - int s_midi = s_bpm + 75; - GuiLabel((Rectangle){20, (float)s_midi, 240, 20}, "MIDI OUT"); - if(GuiButton((Rectangle){200, (float)s_midi, 60, 20}, "RELOAD")) sm->midi.enumerate(); - - int i = 0; - for(auto& mo : sm->midi.midi_out_ports){ - GuiCheckBox((Rectangle){20, (float)s_midi + 25 + i*20.0f, 20, 20}, mo.port.port_name.substr(0,32).c_str(), &mo.enabled); - i++; + void init(){ + GuiLoadStyleDark(); } - if(GuiButton((Rectangle){20, (float)s_midi + 45 + i*20.0f, 240, 20}, "ENABLE FOR ALL")) { - for(auto &midis : sm->midi.midi_out_ports){ - if(midis.enabled){ - for(auto n : gm->nodes){ - if(n->getNodeType() == NodeType::MIDINODE) std::dynamic_pointer_cast(n)->setMidiPort(midis.number, true); + void drawSideBar(){ + + GuiPanel((Rectangle){-1,-30,280,(float)settings->height + 31}, ""); + const int s_controls = 25; + //GuiSetStyle(BUTTON, STATE_FOCUSED, 0xFF0000FF); + if(GuiButton((Rectangle){20, (float)s_controls, 80, 30}, "PLAY")) sm->play ? sm->pause() : sm->start(); + if(GuiButton((Rectangle){120, (float)s_controls, 60, 30}, "STOP")) sm->stop(); + if(GuiButton((Rectangle){200, (float)s_controls, 60, 30}, "RESET")) sm->reset(); + + const int s_bpm = s_controls + 45; + GuiLabel((Rectangle){20, (float)s_bpm, 120, 20}, "TIMING"); + GuiLabel((Rectangle){200, (float)s_bpm, 40, 20}, std::format("{}",settings->bpm).c_str()); + float _bpm = (float)settings->bpm; + GuiSlider((Rectangle){20, (float)s_bpm + 25, 240, 20}, "", "", &_bpm, 1, 300); + settings->bpm = _bpm; + + int s_midi = s_bpm + 75; + GuiLabel((Rectangle){20, (float)s_midi, 240, 20}, "MIDI OUT"); + if(GuiButton((Rectangle){200, (float)s_midi, 60, 20}, "RELOAD")) sm->midi.enumerate(); + + int i = 0; + for(auto& mo : sm->midi.midi_out_ports){ + GuiCheckBox((Rectangle){20, (float)s_midi + 25 + i*20.0f, 20, 20}, mo.port.port_name.substr(0,32).c_str(), &mo.enabled); + i++; + } + + if(GuiButton((Rectangle){20, (float)s_midi + 45 + i*20.0f, 240, 20}, "ENABLE FOR ALL")) { + for(auto &midis : sm->midi.midi_out_ports){ + if(midis.enabled){ + for(auto n : gm->nodes){ + if(n->getNodeType() == NodeType::MIDINODE) std::dynamic_pointer_cast(n)->setMidiPort(midis.number, true); + } + } + } + } + + int s_signal = s_midi + 100 + i*20; + GuiLabel((Rectangle){20, (float)s_signal, 240, 20}, "SIGNALS"); + if(GuiButton((Rectangle){20, (float)s_signal + 35, 240, 20}, "ADD RANDOM SIGNAL")){ + std::shared_ptr ni = gm->getRandomNode(); + sm->addSignalAtNode(ni); + } + + int signal_configs = 0; + for(auto &s : sm->signals){ + if(GuiButton((Rectangle){20,(float)s_signal+70 + signal_configs*20, 20, 20},"X")) sm->removeSignal(signal_configs); + DrawCircle(55, s_signal+80 + signal_configs*20, 6.0F, s->color); + float s_multiplier = round(s->multiplier*10.0f)/10.0f; + float signal_bpm = settings->bpm * s->multiplier; + GuiSlider((Rectangle){70, (float)s_signal+70 + signal_configs*20, 160, 20}, "", std::format("{:.1f}",signal_bpm).c_str(), &s_multiplier, 0.1, 10); + s->multiplier = s_multiplier; + s->speed = settings->speed; + signal_configs++; + } + + int s_nodes = s_signal + 70 + 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")){ + gm->addMidiNode(Vec2Df{200.0f, 200.0f}); + } + DrawText(std::format("{}", gm->nodes.size()).c_str(), 20, settings->height - 70, 15, VS_COLOR_WHITE); + DrawFPS(20, settings->height - 30); + } + + void drawPerNodeConfig(Camera2D *camera){ + for(auto& n : gm->nodes | std::views::filter([](std::shared_ptr 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"); + + int option = n->distributionMode; + GuiToggleGroup((Rectangle){ np.x + 20, np.y + 40, 73, 20 }, "GEO;RR;RAND", &option); + n->distributionMode = (Distribution)option; + + 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); + } + + int y_midi = 120; + GuiLabel((Rectangle){np.x + 20, np.y + y_midi, 220, 20}, "MIDI OUT"); + + int i = 0; + if(n->getNodeType() == NodeType::MIDINODE){ + std::shared_ptr mn = std::dynamic_pointer_cast(n); + for(auto& mo : mn->midi_outs){ + GuiCheckBox((Rectangle){np.x + 20, np.y + y_midi + 20 + i*20.0f, 20, 20}, mo.second.name.c_str(), &mo.second.enabled); + i++; + } + + int y_channel = y_midi + 30 + i*20; + GuiCheckBox((Rectangle){np.x + 20, np.y + y_channel, 20, 20}, "NOTE", &mn->send_note); + GuiCheckBox((Rectangle){np.x + 90, np.y + y_channel, 20, 20}, "CC", &mn->send_cc); + GuiCheckBox((Rectangle){np.x + 160, np.y + y_channel, 20, 20}, "PITCH", &mn->send_pitch_bend); + + int y_cc_note = y_channel + 120; + switch(settings->mode){ + case 0:{ + GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note - 75, 220, 20}, "NOTE CHANNEL"); + GuiToggleGroup((Rectangle){np.x + 20, np.y + y_cc_note - 50, 25, 20}, "1;2;3;4;5;6;7;8\n9;10;11;12;13;14;15;16", &mn->midi_note_channel); + + GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note , 100, 20}, "NOTE"); + float v = mn->midi_note; + GuiLabel((Rectangle){np.x + 210, np.y + y_cc_note , 20, 20}, MIDI::Notes[(int)round(v)].c_str()); + GuiLabel((Rectangle){np.x + 160, np.y + y_cc_note , 40, 20}, std::format("{}",mn->midi_note).c_str()); + GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 30, 220, 20}, "", "", &v, 0, 127); + mn->midi_note = round(v); + + GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note + 60, 100, 20}, "VELOCITY"); + v = mn->midi_velocity; + GuiLabel((Rectangle){np.x + 210, np.y + y_cc_note + 60, 20, 20}, std::format("{}",mn->midi_velocity).c_str()); + GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 90, 220, 20}, "", "", &v, 0, 127); + mn->midi_velocity = round(v); + + GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note + 120, 100, 20}, "GATE"); + v = mn->midi_gate; + GuiLabel((Rectangle){np.x + 210, np.y + y_cc_note + 120, 20, 20}, std::format("{}",(float)mn->midi_gate/1000.0f).c_str()); + GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 150, 220, 20}, "", "", &v, 0, 30000); + mn->midi_gate = round(v); + break;} + case 1: + { + GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note - 75, 220, 20}, "CC CHANNEL"); + GuiToggleGroup((Rectangle){np.x + 20, np.y + y_cc_note - 50, 25, 20}, "1;2;3;4;5;6;7;8\n9;10;11;12;13;14;15;16", &mn->midi_cc_channel); + + GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note , 100, 20}, "CC"); + float v = mn->midi_cc; + GuiLabel((Rectangle){np.x + 160, np.y + y_cc_note , 40, 20}, std::format("{}",mn->midi_cc).c_str()); + GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 30, 220, 20}, "", "", &v, 0, 127); + mn->midi_cc = round(v); + + GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note + 60, 100, 20}, "CC VALUE"); + v = mn->midi_cc_value; + GuiLabel((Rectangle){np.x + 210, np.y + y_cc_note + 60, 20, 20}, std::format("{}",mn->midi_cc_value).c_str()); + GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 90, 220, 20}, "", "", &v, 0, 127); + mn->midi_cc_value = round(v); + + break;} + case 2: + { + GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note - 75, 220, 20}, "PITCH BEND CHANNEL"); + GuiToggleGroup((Rectangle){np.x + 20, np.y + y_cc_note - 50, 25, 20}, "1;2;3;4;5;6;7;8\n9;10;11;12;13;14;15;16", &mn->midi_pitch_bend_channel); + + GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note , 100, 20}, "CC"); + float v = mn->midi_pitch_bend; + GuiLabel((Rectangle){np.x + 160, np.y + y_cc_note , 40, 20}, std::format("{}",mn->midi_pitch_bend).c_str()); + GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 30, 220, 20}, "", "", &v, 0, 16383); + mn->midi_pitch_bend = round(v); + break;} } } } } - int s_signal = s_midi + 100 + i*20; - GuiLabel((Rectangle){20, (float)s_signal, 240, 20}, "SIGNALS"); - if(GuiButton((Rectangle){20, (float)s_signal + 35, 240, 20}, "ADD RANDOM SIGNAL")){ - std::shared_ptr ni = gm->getRandomNode(); - sm->addSignalAtNode(ni); + void draw(Vec2Df *mouse_pos, Camera2D *camera){ + drawSideBar(); + drawPerNodeConfig(camera); } - - int signal_configs = 0; - for(auto &s : sm->signals){ - if(GuiButton((Rectangle){20,(float)s_signal+70 + signal_configs*20, 20, 20},"X")) sm->removeSignal(signal_configs); - DrawCircle(55, s_signal+80 + signal_configs*20, 6.0F, s->color); - float s_multiplier = round(s->multiplier*10.0f)/10.0f; - float signal_bpm = settings->bpm * s->multiplier; - GuiSlider((Rectangle){70, (float)s_signal+70 + signal_configs*20, 160, 20}, "", std::format("{:.1f}",signal_bpm).c_str(), &s_multiplier, 0.1, 10); - s->multiplier = s_multiplier; - s->speed = settings->speed; - signal_configs++; - } - - int s_nodes = s_signal + 70 + 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")){ - gm->addMidiNode(Vec2Df{200.0f, 200.0f}); - } - DrawText(std::format("{}", gm->nodes.size()).c_str(), 20, settings->height - 70, 15, VS_COLOR_WHITE); - DrawFPS(20, settings->height - 30); - } - void drawPerNodeConfig(Camera2D *camera){ - for(auto& n : gm->nodes | std::views::filter([](std::shared_ptr 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"); - - int option = n->distributionMode; - GuiToggleGroup((Rectangle){ np.x + 20, np.y + 40, 73, 20 }, "GEO;RR;RAND", &option); - n->distributionMode = (Distribution)option; - - 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); - } - - int y_midi = 120; - GuiLabel((Rectangle){np.x + 20, np.y + y_midi, 220, 20}, "MIDI OUT"); - - int i = 0; - if(n->getNodeType() == NodeType::MIDINODE){ - std::shared_ptr mn = std::dynamic_pointer_cast(n); - for(auto& mo : mn->midi_outs){ - GuiCheckBox((Rectangle){np.x + 20, np.y + y_midi + 20 + i*20.0f, 20, 20}, mo.second.name.c_str(), &mo.second.enabled); - i++; - } - - int y_channel = y_midi + 30 + i*20; - GuiCheckBox((Rectangle){np.x + 20, np.y + y_channel, 20, 20}, "NOTE", &mn->send_note); - GuiCheckBox((Rectangle){np.x + 90, np.y + y_channel, 20, 20}, "CC", &mn->send_cc); - GuiCheckBox((Rectangle){np.x + 160, np.y + y_channel, 20, 20}, "PITCH", &mn->send_pitch_bend); - - int y_cc_note = y_channel + 120; - switch(settings->mode){ - case 0:{ - GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note - 75, 220, 20}, "NOTE CHANNEL"); - GuiToggleGroup((Rectangle){np.x + 20, np.y + y_cc_note - 50, 25, 20}, "1;2;3;4;5;6;7;8\n9;10;11;12;13;14;15;16", &mn->midi_note_channel); - - GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note , 100, 20}, "NOTE"); - float v = mn->midi_note; - GuiLabel((Rectangle){np.x + 210, np.y + y_cc_note , 20, 20}, sm->midi.midiNotes[(int)round(v)].c_str()); - GuiLabel((Rectangle){np.x + 160, np.y + y_cc_note , 40, 20}, std::format("{}",mn->midi_note).c_str()); - GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 30, 220, 20}, "", "", &v, 0, 127); - mn->midi_note = round(v); - - GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note + 60, 100, 20}, "VELOCITY"); - v = mn->midi_velocity; - GuiLabel((Rectangle){np.x + 210, np.y + y_cc_note + 60, 20, 20}, std::format("{}",mn->midi_velocity).c_str()); - GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 90, 220, 20}, "", "", &v, 0, 127); - mn->midi_velocity = round(v); - - GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note + 120, 100, 20}, "GATE"); - v = mn->midi_gate; - GuiLabel((Rectangle){np.x + 210, np.y + y_cc_note + 120, 20, 20}, std::format("{}",(float)mn->midi_gate/1000.0f).c_str()); - GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 150, 220, 20}, "", "", &v, 0, 30000); - mn->midi_gate = round(v); - break;} - case 1: - { - GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note - 75, 220, 20}, "CC CHANNEL"); - GuiToggleGroup((Rectangle){np.x + 20, np.y + y_cc_note - 50, 25, 20}, "1;2;3;4;5;6;7;8\n9;10;11;12;13;14;15;16", &mn->midi_cc_channel); - - GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note , 100, 20}, "CC"); - float v = mn->midi_cc; - GuiLabel((Rectangle){np.x + 160, np.y + y_cc_note , 40, 20}, std::format("{}",mn->midi_cc).c_str()); - GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 30, 220, 20}, "", "", &v, 0, 127); - mn->midi_cc = round(v); - - GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note + 60, 100, 20}, "CC VALUE"); - v = mn->midi_cc_value; - GuiLabel((Rectangle){np.x + 210, np.y + y_cc_note + 60, 20, 20}, std::format("{}",mn->midi_cc_value).c_str()); - GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 90, 220, 20}, "", "", &v, 0, 127); - mn->midi_cc_value = round(v); - - break;} - case 2: - { - GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note - 75, 220, 20}, "PITCH BEND CHANNEL"); - GuiToggleGroup((Rectangle){np.x + 20, np.y + y_cc_note - 50, 25, 20}, "1;2;3;4;5;6;7;8\n9;10;11;12;13;14;15;16", &mn->midi_pitch_bend_channel); - - GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note , 100, 20}, "CC"); - float v = mn->midi_pitch_bend; - GuiLabel((Rectangle){np.x + 160, np.y + y_cc_note , 40, 20}, std::format("{}",mn->midi_pitch_bend).c_str()); - GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 30, 220, 20}, "", "", &v, 0, 16383); - mn->midi_pitch_bend = round(v); - break;} - } - } - } - } - - void draw(Vec2Df *mouse_pos, Camera2D *camera){ - drawSideBar(); - drawPerNodeConfig(camera); - } - -}; + }; +} diff --git a/src/vmath.h b/src/vmath.h index 39d34a8..3a23c46 100644 --- a/src/vmath.h +++ b/src/vmath.h @@ -7,7 +7,7 @@ using json = nlohmann::json; -namespace VMath{ +namespace VISEQ::VMATH{ template class Vec2D{ @@ -158,4 +158,8 @@ namespace VMath{ } } -using Vec2Df = VMath::Vec2D; +using Vec2Df = VISEQ::VMATH::Vec2D; + + + +