From ad7b0e45247e5ba507e273485080068dd1671d95 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Wed, 30 Oct 2024 02:00:40 +0100 Subject: [PATCH] GEO mode for signals takes direction of next connection into account --- src/connection-manager.h | 59 +++++++++++++++++---------- src/connection.h | 4 +- src/datatypes.h | 7 +++- src/main.cpp | 59 ++++++++++++++++++++++----- src/midi.h | 17 ++++++++ src/node-manager.h | 6 +++ src/node.h | 79 +++++++++++++++++++++++++++++++----- src/signal-manager.h | 6 ++- src/ui.h | 87 ++++++++++++++++++++++++++++------------ 9 files changed, 251 insertions(+), 73 deletions(-) diff --git a/src/connection-manager.h b/src/connection-manager.h index 50f67fc..e286f12 100644 --- a/src/connection-manager.h +++ b/src/connection-manager.h @@ -3,6 +3,7 @@ #include "connection.h" #include "node-manager.h" #include "raylib.h" +#include "raymath.h" #include #include @@ -23,41 +24,57 @@ class ConnectionManager{ } int next(int current, int last){ - std::vector paths; - std::vector node_ids; + std::vector possible_connections; + std::vector next_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); - node_ids.push_back( p.v1 == current ? p.v2 : p.v1 ); + for(auto& c : connections){ + if((c.v1 == current && c.v1_v2) || (c.v2 == current && c.v2_v1)) { + c.active = false; + possible_connections.push_back(&c); + next_node_ids.push_back( c.v1 == current ? c.v2 : c.v1 ); } } - if(paths.size() == 2) { - 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(possible_connections.size() == 2) {*/ + /* int next = next_node_ids[0] == last ? next_node_ids[1] : next_node_ids[0];*/ + /* if(possible_connections[0]->v1 == next || possible_connections[0]->v2 == next) possible_connections[0]->active = true;*/ + /* if(possible_connections[1]->v1 == next || possible_connections[1]->v2 == next) possible_connections[1]->active = true;*/ + /* return next;*/ + /*}*/ - if(paths.empty()) return -1; + if(possible_connections.empty()) return -1; int return_path = 0; - - if(nm->nodes.at(current).mode == Distribution::ROUNDROBIN){ + float angle = -1; + if(nm->nodes.at(current).distributionMode == Distribution::GEOMETRIC){ + Vec2D coming_from = (nm->nodes.at(current).position - nm->nodes.at(last).position).norm(); + int i = 0; + for(auto n : possible_connections){ + int next_position = n->v1 == current ? n->v2 : n->v1; + float angle_v1_v2 = coming_from.norm().dot((nm->nodes.at(next_position).position - nm->nodes.at(current).position).norm()); + if(angle_v1_v2 > angle) { + return_path = i; + angle = angle_v1_v2; + } + ++i; + } + } + + if(nm->nodes.at(current).distributionMode == Distribution::ROUNDROBIN){ if(counter.find(current) == counter.end()) { counter[current] = 0; } else { - counter[current] = (counter[current] + 1) % paths.size(); + counter[current] = (counter[current] + 1) % possible_connections.size(); return_path = counter[current]; } } - if(nm->nodes.at(current).mode == Distribution::RANDOM){ - return_path = rand() % paths.size(); + + if(nm->nodes.at(current).distributionMode == Distribution::RANDOM){ + return_path = rand() % possible_connections.size(); } - paths.at(return_path)->active = true; - return paths.at(return_path)->v1 == current ? paths.at(return_path)->v2 : paths.at(return_path)->v1; + + possible_connections.at(return_path)->active = true; + return possible_connections.at(return_path)->v1 == current ? possible_connections.at(return_path)->v2 : possible_connections.at(return_path)->v1; } void addConnection(int from, int to){ diff --git a/src/connection.h b/src/connection.h index 3fcffa8..d5c29ad 100644 --- a/src/connection.h +++ b/src/connection.h @@ -60,8 +60,8 @@ class Connection{ // 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, 120.0f); - unsigned char opacity_to = 250.0f - Clamp(to_from_handle.dist(mouse_pos), 0.0f, 120.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); // On/Off switches on both sides if(ViButton(mouse_pos, from_to_handle.x, from_to_handle.y, 8.0f, v1_v2 ? (Color){120, 210, 115, opacity_from} : (Color){232, 50, 32, opacity_from} )) v1_v2 = !v1_v2; diff --git a/src/datatypes.h b/src/datatypes.h index 0a31ca7..6b33460 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -25,7 +25,7 @@ #include "libremidi/libremidi.hpp" #include "raylib.h" -enum Distribution {ROUNDROBIN, RANDOM}; +enum Distribution {GEOMETRIC, ROUNDROBIN, RANDOM}; // 2D Vectors @@ -57,6 +57,10 @@ class Vec2D{ T dot(Vec2D &v){ return (x*v.x) + (y*v.y); }; + + T dot(Vec2D v){ + return (x*v.x) + (y*v.y); + }; operator Vector2() const { return (Vector2){x,y}; @@ -152,6 +156,7 @@ Vec2D operator*(const Vec2D& left, T scalar){ // App Settings struct AppSettings{ + int mode = 0; int width; int height; float grid; diff --git a/src/main.cpp b/src/main.cpp index 3e3aab0..f27e13a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -63,9 +63,9 @@ int main(){ app.settings.fps = 60.0f; app.settings.bpm = 120.0f; - app.settings.grid = 120.0f; // 120px for a 16th note + app.settings.grid = 60.0f; // 120px for a 16th note - app.settings.speed = (app.settings.grid * 8.0f) * (app.settings.bpm / 120.f); + app.settings.speed = (app.settings.grid * 16.0f) * (app.settings.bpm / 120.f); app.settings.width = monitor_width - 300; app.settings.height = monitor_height - 300; @@ -78,10 +78,10 @@ int main(){ camera.zoom = 1.0f; for(int i = 0; i < 4; ++i){ - app.nm.addNode((float)i * app.settings.grid + 10 * app.settings.grid, 5 * app.settings.grid); + app.nm.addNode((float)i * app.settings.grid*4 + 10 * app.settings.grid, 5 * app.settings.grid*4); } for(int i = 3; i >= 0; --i){ - app.nm.addNode((float)i * app.settings.grid + 10 * app.settings.grid, 6 * app.settings.grid); + app.nm.addNode((float)i * app.settings.grid*4 + 10 * app.settings.grid, 6 * app.settings.grid*4); } for(int i = 0; i < 8; ++i){ @@ -104,7 +104,7 @@ int main(){ ClearBackground((Color){46,46,46}); BeginMode2D(camera); - app.settings.speed = (app.settings.grid * 8.0f) * (app.settings.bpm / 120.f); + app.settings.speed = (app.settings.grid * 16.0f) * (app.settings.bpm / 120.f); Vector2 mp = GetScreenToWorld2D(GetMousePosition(), camera); Vec2D mouse_pos = {(float)mp.x, (float)mp.y}; @@ -146,6 +146,11 @@ int main(){ if(!copied_nodes.empty() && IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_V)) istate = InteractionState::PASTE_SELECTED_NODES; + if(IsKeyPressed(KEY_TAB)) { + app.settings.mode = (app.settings.mode + 1) % 3; + app.nm.setNodeMode(app.settings.mode); + } + switch(istate){ case InteractionState::HOVER_CANVAS: { @@ -214,7 +219,7 @@ int main(){ if(IsKeyDown(KEY_LEFT_CONTROL)) { dragging_nodes.front().position = (Vec2D){round((mouse_pos.x+dragging_nodes.front().drag_offset.x)/app.settings.grid)*app.settings.grid, round((mouse_pos.y+dragging_nodes.front().drag_offset.y)/app.settings.grid)*app.settings.grid}; } else if(IsKeyDown(KEY_LEFT_SHIFT)){ - float steps = round(dragging_nodes.front().neighbor->position.dist(mouse_pos) / 60.0f) * 60.0f; + float steps = round(dragging_nodes.front().neighbor->position.dist(mouse_pos) / app.settings.grid) * app.settings.grid; Vec2D polar = dragging_nodes.front().neighbor->position - (dragging_nodes.front().neighbor->position - (mouse_pos + dragging_nodes.front().drag_offset)).norm() * steps; dragging_nodes.front().position = polar; } else { @@ -311,17 +316,49 @@ int main(){ float wheel = GetMouseWheelMove(); if(wheel != 0){ if(!hovering_nodes.empty() && IsKeyDown(KEY_LEFT_CONTROL) && !IsKeyDown(KEY_LEFT_ALT)){ - hovering_nodes.front().midi_note += wheel; + switch(app.settings.mode){ + case 0:{ + hovering_nodes.front().midi_note += wheel; + break;} + case 1:{ + hovering_nodes.front().midi_cc += wheel; + break;} + case 2:{ + hovering_nodes.front().midi_pitch_bend += wheel; + break;} + }; if(hovering_nodes.front().midi_note < 0 ) hovering_nodes.front().midi_note = app.sm.midi.midiNotes.size()-1; - if(hovering_nodes.front().midi_note >= app.sm.midi.midiNotes.size() ) hovering_nodes.front().midi_note = 0; + if(hovering_nodes.front().midi_note >= app.sm.midi.midiNotes.size() ) hovering_nodes.front().midi_note = 0; + + if(hovering_nodes.front().midi_cc < 0 ) hovering_nodes.front().midi_cc = 127; + if(hovering_nodes.front().midi_cc > 127 ) hovering_nodes.front().midi_cc = 0; + + if(hovering_nodes.front().midi_pitch_bend < 0 ) hovering_nodes.front().midi_pitch_bend = 0; + if(hovering_nodes.front().midi_pitch_bend > 16383 ) hovering_nodes.front().midi_pitch_bend = 16383; + } else if(!hovering_nodes.empty() && IsKeyDown(KEY_LEFT_SHIFT) && !IsKeyDown(KEY_LEFT_ALT)) { hovering_nodes.front().midi_velocity += wheel; if(hovering_nodes.front().midi_velocity < 0 ) hovering_nodes.front().midi_velocity = 127; if(hovering_nodes.front().midi_velocity > 127 ) hovering_nodes.front().midi_velocity = 0; } else if(!hovering_nodes.empty() && IsKeyDown(KEY_LEFT_ALT)) { - float incr = (float)wheel * (IsKeyDown(KEY_LEFT_SHIFT) ? 100.0f : IsKeyDown(KEY_LEFT_CONTROL) ? 1000.0f : 10.0f); - hovering_nodes.front().midi_gate += incr; - if(hovering_nodes.front().midi_gate < 0 ) hovering_nodes.front().midi_gate = 0; + switch(app.settings.mode){ + case 0:{ + float incr = (float)wheel * (IsKeyDown(KEY_LEFT_SHIFT) ? 100.0f : IsKeyDown(KEY_LEFT_CONTROL) ? 1000.0f : 10.0f); + hovering_nodes.front().midi_gate += incr; + if(hovering_nodes.front().midi_gate < 0 ) hovering_nodes.front().midi_gate = 0; + break;} + case 1:{ + hovering_nodes.front().midi_cc_value += wheel; + if(hovering_nodes.front().midi_cc_value < 0 ) hovering_nodes.front().midi_cc_value = 0; + if(hovering_nodes.front().midi_cc_value > 127 ) hovering_nodes.front().midi_cc_value = 127; + break;} + case 2:{ + float incr = (float)wheel * (IsKeyDown(KEY_LEFT_SHIFT) ? 100.0f : IsKeyDown(KEY_LEFT_CONTROL) ? 1000.0f : 10.0f); + hovering_nodes.front().midi_pitch_bend += incr; + if(hovering_nodes.front().midi_pitch_bend < 0 ) hovering_nodes.front().midi_pitch_bend = 0; + if(hovering_nodes.front().midi_pitch_bend > 16383 ) hovering_nodes.front().midi_pitch_bend = 16383; + break;} + }; } else { Vector2 mouseWorldPos = GetScreenToWorld2D(GetMousePosition(), camera); camera.offset = GetMousePosition(); diff --git a/src/midi.h b/src/midi.h index 22363ff..5a35e05 100644 --- a/src/midi.h +++ b/src/midi.h @@ -8,6 +8,7 @@ #include #include #include +#include #include "datatypes.h" struct NoteTimer{ @@ -90,6 +91,22 @@ class Midi { } } } + + 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)); + } + } + } void update(){ float time = GetTime(); diff --git a/src/node-manager.h b/src/node-manager.h index d320c07..6997aee 100644 --- a/src/node-manager.h +++ b/src/node-manager.h @@ -50,6 +50,12 @@ class NodeManager{ return iterator - 1; } + void setNodeMode(int mode){ + for(auto &n : nodes | std::ranges::views::values){ + n.mode = mode; + } + } + int addNode(float x, float y){ return addNode(Vec2D(x,y)); } diff --git a/src/node.h b/src/node.h index 06ae5fb..7fdff5f 100644 --- a/src/node.h +++ b/src/node.h @@ -22,7 +22,6 @@ class Node : public Movable{ 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) {} - Node *neighbor = nullptr; float radius; @@ -42,6 +41,11 @@ class Node : public Movable{ bool copied = false; bool triggered = false; + bool send_note = true; + bool send_cc = false; + bool send_pc = false; + bool send_pitch_bend = false; + int midi_out = -1; Vec2D drag_offset; @@ -53,18 +57,30 @@ class Node : public Movable{ bool gui_midi_velocity_edit = false; bool gui_midi_gate_edit = false; - int midi_channel = 1; + int mode = 0; + + int midi_note_channel = 1; int midi_note = 48; int midi_velocity = 60; - int midi_gate = 100; + 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; - Distribution mode = Distribution::ROUNDROBIN; + Distribution distributionMode = Distribution::GEOMETRIC; void setMidiPort(int midi_port, bool state){ midi_outs[midi_port].enabled = state; @@ -89,22 +105,65 @@ class Node : public Movable{ 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}); - if(mode == Distribution::RANDOM) DrawCircle(position.x, position.y, radius/2.0f, VS_COLOR_PINK); float midi_gate_map = round((255.f / midi_gate) * fade); - Color gate_color = ColorAlphaBlend(VS_COLOR_RED, (Color){180, 210, 115, (unsigned char)Clamp(255 - midi_gate_map, 0, 255)}, WHITE); + 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); + if(selected) DrawCircleLinesV(position, radius+8, (Color){158, 255, 210, 255}); if(IsKeyDown(KEY_LEFT_ALT)){ - int offset_gate = MeasureText(std::format("{:.2f}", (float)midi_gate/1000.0f).c_str(), 12); - DrawText(std::format("{:.2f}",(float)midi_gate/1000.0f).c_str(), position.x-offset_gate/2.0f, position.y-5, 12, WHITE ); + 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 { - int offset = MeasureText(MIDI::Notes[midi_note].c_str(), 12); - DrawText(MIDI::Notes[midi_note].c_str(), position.x-offset/2.0f, position.y-5, 12, WHITE ); + 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;} + } } Vec2D connector = position - ((position - *mouse)).norm() * (radius + R); diff --git a/src/signal-manager.h b/src/signal-manager.h index 65d4635..0b15dc9 100644 --- a/src/signal-manager.h +++ b/src/signal-manager.h @@ -60,7 +60,7 @@ class SignalManager{ void addSignalAtNode(int node_id){ Color c = {(unsigned char)(20 + (rand() % 200)), 100, (unsigned char)(20 + (int)(rand() % 200)), 200}; - 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.emplace(signals.end(), Signal(nm->nodes[node_id].position.x+1, nm->nodes[node_id].position.y+1, 8.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; @@ -87,7 +87,9 @@ class SignalManager{ 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); + if(nm->nodes[s.next].send_note) midi.note(m.second.i, nm->nodes[s.next].midi_note_channel, nm->nodes[s.next].midi_note, nm->nodes[s.next].midi_velocity, nm->nodes[s.next].midi_gate); + if(nm->nodes[s.next].send_cc) midi.cc(m.second.i, nm->nodes[s.next].midi_cc_channel, nm->nodes[s.next].midi_cc, nm->nodes[s.next].midi_cc_value); + if(nm->nodes[s.next].send_pitch_bend) midi.pitch_bend(m.second.i, nm->nodes[s.next].midi_pitch_bend_channel, nm->nodes[s.next].midi_pitch_bend); } } s.last = s.next; diff --git a/src/ui.h b/src/ui.h index 59840ff..58aca8e 100644 --- a/src/ui.h +++ b/src/ui.h @@ -95,9 +95,9 @@ class AppUI{ n.config = !GuiWindowBox((Rectangle){np.x + 10, np.y + 10, 240, 440}, "config"); - int option = n.mode; - GuiToggleGroup((Rectangle){ np.x + 20, np.y + 40, 110, 20 }, "Round Robin;Random", &option); - n.mode = (Distribution)option; + 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")){ @@ -114,30 +114,65 @@ class AppUI{ } int y_channel = y_midi + 30 + i*20; - GuiLabel((Rectangle){np.x + 20, np.y + y_channel, 220, 20}, "CHANNEL"); - GuiToggleGroup((Rectangle){np.x + 20, np.y + y_channel + 30, 25, 20}, "1;2;3;4;5;6;7;8\n9;10;11;12;13;14;15;16", &n.midi_channel); + GuiCheckBox((Rectangle){np.x + 20, np.y + y_channel, 20, 20}, "NOTE", &n.send_note); + GuiCheckBox((Rectangle){np.x + 90, np.y + y_channel, 20, 20}, "CC", &n.send_cc); + GuiCheckBox((Rectangle){np.x + 160, np.y + y_channel, 20, 20}, "PITCH", &n.send_pitch_bend); - GuiLabel((Rectangle){np.x + 20, np.y + y_channel + 90, 100, 20}, "NOTE"); - float v = n.midi_note; - GuiLabel((Rectangle){np.x + 210, np.y + y_channel + 90, 20, 20}, sm->midi.midiNotes[(int)round(v)].c_str()); - GuiLabel((Rectangle){np.x + 160, np.y + y_channel + 90, 40, 20}, std::format("{}",n.midi_note).c_str()); - GuiSlider((Rectangle){np.x + 20, np.y + y_channel + 120, 220, 20}, "", "", &v, 0, 127); - n.midi_note = round(v); - - GuiLabel((Rectangle){np.x + 20, np.y + y_channel + 150, 100, 20}, "VELOCITY"); - v = n.midi_velocity; - GuiLabel((Rectangle){np.x + 210, np.y + y_channel + 150, 20, 20}, std::format("{}",n.midi_velocity).c_str()); - GuiSlider((Rectangle){np.x + 20, np.y + y_channel + 180, 220, 20}, "", "", &v, 0, 127); - n.midi_velocity = round(v); - - GuiLabel((Rectangle){np.x + 20, np.y + y_channel + 210, 100, 20}, "GATE"); - v = n.midi_gate; - GuiLabel((Rectangle){np.x + 210, np.y + y_channel + 210, 20, 20}, std::format("{}",(float)n.midi_gate/1000.0f).c_str()); - GuiSlider((Rectangle){np.x + 20, np.y + y_channel + 240, 220, 20}, "", "", &v, 0, 30000); - n.midi_gate = round(v); - - //if(GuiValueBox((Rectangle){n.position.x + 100, n.position.y + y_channel + 40, 140, 20}, "VELOCITY", &n.midi_velocity, 0, 127, n.gui_midi_velocity_edit)) n.gui_midi_velocity_edit = !n.gui_midi_velocity_edit; - //if(GuiValueBox((Rectangle){n.position.x + 100, n.position.y + y_channel + 60, 140, 20}, "GATE", &n.midi_gate, 0, 5000, n.gui_midi_gate_edit)) n.gui_midi_gate_edit = !n.gui_midi_gate_edit; + 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", &n.midi_note_channel); + + GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note , 100, 20}, "NOTE"); + float v = n.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("{}",n.midi_note).c_str()); + GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 30, 220, 20}, "", "", &v, 0, 127); + n.midi_note = round(v); + + GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note + 60, 100, 20}, "VELOCITY"); + v = n.midi_velocity; + GuiLabel((Rectangle){np.x + 210, np.y + y_cc_note + 60, 20, 20}, std::format("{}",n.midi_velocity).c_str()); + GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 90, 220, 20}, "", "", &v, 0, 127); + n.midi_velocity = round(v); + + GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note + 120, 100, 20}, "GATE"); + v = n.midi_gate; + GuiLabel((Rectangle){np.x + 210, np.y + y_cc_note + 120, 20, 20}, std::format("{}",(float)n.midi_gate/1000.0f).c_str()); + GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 150, 220, 20}, "", "", &v, 0, 30000); + n.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", &n.midi_cc_channel); + + GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note , 100, 20}, "CC"); + float v = n.midi_cc; + GuiLabel((Rectangle){np.x + 160, np.y + y_cc_note , 40, 20}, std::format("{}",n.midi_cc).c_str()); + GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 30, 220, 20}, "", "", &v, 0, 127); + n.midi_cc = round(v); + + GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note + 60, 100, 20}, "CC VALUE"); + v = n.midi_cc_value; + GuiLabel((Rectangle){np.x + 210, np.y + y_cc_note + 60, 20, 20}, std::format("{}",n.midi_cc_value).c_str()); + GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 90, 220, 20}, "", "", &v, 0, 127); + n.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", &n.midi_pitch_bend_channel); + + GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note , 100, 20}, "CC"); + float v = n.midi_pitch_bend; + GuiLabel((Rectangle){np.x + 160, np.y + y_cc_note , 40, 20}, std::format("{}",n.midi_pitch_bend).c_str()); + GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 30, 220, 20}, "", "", &v, 0, 16383); + n.midi_pitch_bend = round(v); + break;} + } } }