in between working states, switchting to multi midi out per node
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
CXX = g++-13
|
CXX = g++
|
||||||
CXXFLAGS = -std=c++20 -Wall -g -fno-omit-frame-pointer -gdwarf-4 -Og -DLIBREMIDI_ALSA=1 -Wnarrowing
|
CXXFLAGS = -std=c++20 -Wall -g -fno-omit-frame-pointer -gdwarf-4 -Og -DLIBREMIDI_ALSA=1 -Wnarrowing
|
||||||
CXXINC = -I/usr/lib/gcc/x86_64-pc-linux-gnu/13.3.0/include -Iinclude
|
CXXINC = -I/usr/lib/gcc/x86_64-pc-linux-gnu/13.3.0/include -Iinclude
|
||||||
|
|
||||||
|
|||||||
@@ -16,17 +16,23 @@ class ConnectionManager{
|
|||||||
|
|
||||||
Node* next(Node* current, Node* last){
|
Node* next(Node* current, Node* last){
|
||||||
std::vector<Connection*> paths;
|
std::vector<Connection*> paths;
|
||||||
bool last_ok = false;
|
std::vector<Node*> nodes;
|
||||||
|
|
||||||
for(auto& p : connections){
|
for(auto& p : connections){
|
||||||
if(((p.v1 == current && p.v1_v2) || (p.v2 == current && p.v2_v1)) && (p.v1 != last || p.v2 != last)) {
|
if(((p.v1 == current && p.v1_v2) || (p.v2 == current && p.v2_v1))) {
|
||||||
p.active = false;
|
p.active = false;
|
||||||
paths.push_back(&p);
|
paths.push_back(&p);
|
||||||
|
nodes.push_back( p.v1 == current ? p.v2 : p.v1 );
|
||||||
}
|
}
|
||||||
if(((p.v1 == last && p.v2_v1) || (p.v2 == last && p.v1_v2))) last_ok = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(paths.empty() && last_ok) return last;
|
if(paths.size() == 2) {
|
||||||
|
Node* next = nodes[0] == last ? nodes[1] : nodes[0];
|
||||||
|
if(paths[0]->v1 == next || paths[0]->v2 == next) paths[0]->active = true;
|
||||||
|
if(paths[1]->v1 == next || paths[1]->v2 == next) paths[1]->active = true;
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
if(paths.empty()) return nullptr;
|
if(paths.empty()) return nullptr;
|
||||||
|
|
||||||
int return_path = 0;
|
int return_path = 0;
|
||||||
|
|||||||
@@ -18,6 +18,12 @@ class Connection{
|
|||||||
bool remove = false;
|
bool remove = false;
|
||||||
bool config = false;
|
bool config = false;
|
||||||
|
|
||||||
|
void flip(){
|
||||||
|
Node* vt = v1;
|
||||||
|
v1 = v2;
|
||||||
|
v2 = vt;
|
||||||
|
}
|
||||||
|
|
||||||
void draw(){
|
void draw(){
|
||||||
Vec2D<float> v1_position = v1->position - ((v1->position - v2->position)).norm() * (v1->radius + 10.0f);
|
Vec2D<float> v1_position = v1->position - ((v1->position - v2->position)).norm() * (v1->radius + 10.0f);
|
||||||
Vec2D<float> v2_position = v2->position - ((v2->position - v1->position)).norm() * (v2->radius + 10.0f);
|
Vec2D<float> v2_position = v2->position - ((v2->position - v1->position)).norm() * (v2->radius + 10.0f);
|
||||||
@@ -30,6 +36,7 @@ class Connection{
|
|||||||
Vec2D<float> to_from_handle = v2->position - ((v2->position - v1->position)).norm() * (v2->radius + 35);
|
Vec2D<float> to_from_handle = v2->position - ((v2->position - v1->position)).norm() * (v2->radius + 35);
|
||||||
Vec2D<float> middle_handle = v2->position - ((v2->position - v1->position))*0.5f;
|
Vec2D<float> middle_handle = v2->position - ((v2->position - v1->position))*0.5f;
|
||||||
Vec2D<float> config_handle = v2->position - ((v2->position - v1->position))*0.66f;
|
Vec2D<float> config_handle = v2->position - ((v2->position - v1->position))*0.66f;
|
||||||
|
Vec2D<float> flip_handle = (v1_position - v2_position).norm().orth()*20.0f;
|
||||||
|
|
||||||
if(ViButton(from_to_handle.x, from_to_handle.y, 8.0f, v1_v2 ? (Color){232, 125, 62, 255} : (Color){232, 50, 32, 255} )) v1_v2 = !v1_v2;
|
if(ViButton(from_to_handle.x, from_to_handle.y, 8.0f, v1_v2 ? (Color){232, 125, 62, 255} : (Color){232, 50, 32, 255} )) v1_v2 = !v1_v2;
|
||||||
if(ViButton(to_from_handle.x, to_from_handle.y, 8.0f, v2_v1 ? (Color){232, 125, 62, 255} : (Color){232, 50, 32, 255} )) v2_v1 = !v2_v1;
|
if(ViButton(to_from_handle.x, to_from_handle.y, 8.0f, v2_v1 ? (Color){232, 125, 62, 255} : (Color){232, 50, 32, 255} )) v2_v1 = !v2_v1;
|
||||||
@@ -37,5 +44,8 @@ class Connection{
|
|||||||
if(ViButton(middle_handle.x, middle_handle.y, 8.0f, (Color){232, 50, 32, 255} )) remove = true;
|
if(ViButton(middle_handle.x, middle_handle.y, 8.0f, (Color){232, 50, 32, 255} )) remove = true;
|
||||||
|
|
||||||
if(ViButton(config_handle.x, config_handle.y, 8.0f, (Color){158, 134, 200, 255})) config = !config;
|
if(ViButton(config_handle.x, config_handle.y, 8.0f, (Color){158, 134, 200, 255})) config = !config;
|
||||||
|
|
||||||
|
|
||||||
|
if(ViButton(config_handle.x + flip_handle.x, config_handle.y + flip_handle.y, 8.0f, (Color){158, 0, 200, 255})) flip();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -37,8 +37,17 @@ class Vec2D{
|
|||||||
return (x*v.x) + (y*v.y);
|
return (x*v.x) + (y*v.y);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Vec2D orth(Vec2D &v){
|
||||||
|
return Vec2D(-v.y, v.x);
|
||||||
|
};
|
||||||
|
|
||||||
|
Vec2D orth(){
|
||||||
|
return Vec2D(-y, x);
|
||||||
|
};
|
||||||
|
|
||||||
Vec2D norm() { return *this / length();};
|
Vec2D norm() { return *this / length();};
|
||||||
|
|
||||||
|
|
||||||
Vec2D& operator=(const Vec2D& vec){
|
Vec2D& operator=(const Vec2D& vec){
|
||||||
if (this == &vec){
|
if (this == &vec){
|
||||||
return *this;
|
return *this;
|
||||||
|
|||||||
+25
-8
@@ -53,6 +53,7 @@ enum States {IDLE, CONFIG};
|
|||||||
struct AppState{
|
struct AppState{
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
|
int gui_selected_midi_out;
|
||||||
States state;
|
States state;
|
||||||
} app;
|
} app;
|
||||||
|
|
||||||
@@ -195,21 +196,30 @@ int main(){
|
|||||||
midi.note(s.next->midi_out, 1, 50, 50, 500);
|
midi.note(s.next->midi_out, 1, 50, 50, 500);
|
||||||
s.last = s.next;
|
s.last = s.next;
|
||||||
s.next = n;
|
s.next = n;
|
||||||
//std::cout << s.last << " " << s.next << std::endl;
|
|
||||||
//midi_out.send_message(libremidi::channel_events::control_change(2, 10, 50));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.draw(&mouse_pos);
|
s.draw(&mouse_pos);
|
||||||
}
|
}
|
||||||
|
midi.update();
|
||||||
EndMode2D();
|
EndMode2D();
|
||||||
GuiWindowBox((Rectangle){0,0,280,600}, "config");
|
|
||||||
|
|
||||||
if(GuiButton((Rectangle){20, 60, 240, 20}, "button")){
|
// Main Config Window
|
||||||
|
GuiWindowBox((Rectangle){0,0,280,(float)app.height}, "config");
|
||||||
|
{
|
||||||
|
GuiLabel((Rectangle){20, 60, 240, 20}, "MIDI OUT");
|
||||||
|
int i = 0;
|
||||||
|
for(auto& mo : midi.midi_out_ports){
|
||||||
|
GuiCheckBox((Rectangle){20, 80 + i*20.0f, 20, 20}, mo.port.port_name.c_str(), &mo.enabled);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if(GuiButton((Rectangle){20, 100 + (float)midi.midi_out_ports.size()*20, 240, 20}, "OPEN PORT")) midi.open_midi_out(app.gui_selected_midi_out);
|
||||||
|
|
||||||
|
if(GuiButton((Rectangle){20, 60, 240, 20}, "ADD SIGNAL")){
|
||||||
signals.emplace_back(Signal(nodes.front().position.x + 1, nodes.front().position.y + 1, 5.0f, 2.0f)); // position + 1 or else it does not render. why? no idea!
|
signals.emplace_back(Signal(nodes.front().position.x + 1, nodes.front().position.y + 1, 5.0f, 2.0f)); // position + 1 or else it does not render. why? no idea!
|
||||||
signals.back().next = &nodes[0];
|
signals.back().next = &nodes[0];
|
||||||
signals.back().last = &nodes[0];
|
signals.back().last = &nodes[0];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for(auto& n : nodes){
|
for(auto& n : nodes){
|
||||||
if(n.config){
|
if(n.config){
|
||||||
@@ -217,14 +227,21 @@ int main(){
|
|||||||
int option = n.mode;
|
int option = n.mode;
|
||||||
GuiComboBox((Rectangle){ n.position.x + 20, n.position.y + 40, 220, 20 }, "Round Robin;Random", &option);
|
GuiComboBox((Rectangle){ n.position.x + 20, n.position.y + 40, 220, 20 }, "Round Robin;Random", &option);
|
||||||
n.mode = (Distribution)option;
|
n.mode = (Distribution)option;
|
||||||
std::string toggle_out_ports = "";
|
|
||||||
|
int i = 0;
|
||||||
for(auto& mo : midi.midi_out_ports){
|
for(auto& mo : midi.midi_out_ports){
|
||||||
toggle_out_ports += mo.port_name + "\n";
|
GuiCheckBox((Rectangle){20, 80 + i*20.0f, 20, 20}, mo.port.port_name.c_str(), &mo.enabled);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string toggle_out_ports = "";
|
||||||
|
for(auto& mo : midi.midi_outs){
|
||||||
|
toggle_out_ports += midi.midi_out_ports[mo.first].port.port_name + "\n";
|
||||||
}
|
}
|
||||||
toggle_out_ports = toggle_out_ports.substr(0, toggle_out_ports.size()-2);
|
toggle_out_ports = toggle_out_ports.substr(0, toggle_out_ports.size()-2);
|
||||||
GuiLabel((Rectangle){n.position.x + 20, n.position.y + 60, 220, 20}, "MIDI OUT");
|
GuiLabel((Rectangle){n.position.x + 20, n.position.y + 60, 220, 20}, "MIDI OUT");
|
||||||
GuiToggleGroup((Rectangle){n.position.x + 20, n.position.y + 80, 220, 20}, toggle_out_ports.c_str(), &n.midi_out);
|
GuiToggleGroup((Rectangle){n.position.x + 20, n.position.y + 80, 220, 20}, toggle_out_ports.c_str(), &n.midi_out);
|
||||||
if(GuiButton((Rectangle){n.position.x + 20, n.position.y + 100 + midi.midi_out_ports.size()*20, 220, 20}, "OPEN PORT")) midi.open_midi_out(n.midi_out);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+36
-20
@@ -6,6 +6,7 @@
|
|||||||
#include "raylib.h"
|
#include "raylib.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
|
||||||
@@ -15,55 +16,70 @@ struct NoteTimer{
|
|||||||
int channel;
|
int channel;
|
||||||
int note;
|
int note;
|
||||||
int velocity;
|
int velocity;
|
||||||
int start;
|
float start;
|
||||||
int length;
|
int gate;
|
||||||
|
bool erase = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct MidiOutPort{
|
||||||
|
libremidi::output_port port;
|
||||||
|
int number;
|
||||||
|
bool enabled;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MidiOut{
|
||||||
|
libremidi::midi_out out;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
class Midi {
|
class Midi {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Midi() {
|
Midi() {
|
||||||
|
int i = 0;
|
||||||
for(const libremidi::input_port& port : obs.get_input_ports()){
|
|
||||||
midi_in_ports.push_back(port);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(const libremidi::output_port& port : obs.get_output_ports()){
|
for(const libremidi::output_port& port : obs.get_output_ports()){
|
||||||
midi_out_ports.push_back(port);
|
midi_out_ports.push_back({port, i, false});
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
std::cout << midi_out_ports.size() << std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
libremidi::observer obs;
|
libremidi::observer obs;
|
||||||
|
|
||||||
std::vector<std::shared_ptr<libremidi::midi_out>> midi_outs;
|
std::map<int, std::shared_ptr<libremidi::midi_out>> midi_outs;
|
||||||
std::vector<libremidi::input_port> midi_in_ports;
|
std::vector<libremidi::input_port> midi_in_ports;
|
||||||
std::vector<libremidi::output_port> midi_out_ports;
|
std::vector<MidiOutPort> midi_out_ports;
|
||||||
|
|
||||||
std::vector<NoteTimer> notes;
|
std::vector<NoteTimer> notes;
|
||||||
|
|
||||||
float timer;
|
float timer;
|
||||||
|
|
||||||
void open_midi_out(int midi_n){
|
void open_midi_out(MidiOutPort *out_port){
|
||||||
std::cout << midi_n << std::endl;
|
if(!midi_outs.contains(out_port->number)){
|
||||||
|
|
||||||
auto out = std::make_shared<libremidi::midi_out>();
|
auto out = std::make_shared<libremidi::midi_out>();
|
||||||
out->open_port(midi_out_ports[midi_n]);
|
out->open_port(out_port->port);
|
||||||
midi_outs.push_back(out);
|
midi_outs[out_port->number] = out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void note(int midi_out, int channel, int note, int velocity, int length){
|
void note(int midi_out, int channel, int note, int velocity, int gate){
|
||||||
|
if(!midi_outs.empty()){
|
||||||
midi_outs[midi_out]->send_message(libremidi::channel_events::note_on(channel, note, velocity));
|
midi_outs[midi_out]->send_message(libremidi::channel_events::note_on(channel, note, velocity));
|
||||||
notes.emplace_back(midi_out, channel, note, velocity, GetTime(), length);
|
notes.emplace_back(midi_out, channel, note, velocity, GetTime(), gate);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void update(){
|
void update(){
|
||||||
float time = GetTime();
|
float time = GetTime();
|
||||||
for(auto it = notes.begin(); it != notes.end(); ++it){
|
for(auto it = notes.begin(); it != notes.end(); ++it){
|
||||||
if(time - it->start > ((float)it->length / 1000.0f)){
|
if(time - it->start >= (float)it->gate / 1000.0f){
|
||||||
midi_outs[it->midi_out]->send_message(libremidi::channel_events::note_off(it->channel, it->note, it->velocity));
|
midi_outs[it->midi_out]->send_message(libremidi::channel_events::note_off(it->channel, it->note, it->velocity));
|
||||||
notes.erase(it);
|
it->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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-1
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <raylib.h>
|
#include <raylib.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "datatypes.h"
|
#include "datatypes.h"
|
||||||
#include "moveable.h"
|
#include "moveable.h"
|
||||||
@@ -21,7 +22,9 @@ class Node : public Movable{
|
|||||||
bool connecting = false;
|
bool connecting = false;
|
||||||
bool config = false;
|
bool config = false;
|
||||||
|
|
||||||
int midi_out = 0;
|
int midi_out = -1;
|
||||||
|
|
||||||
|
std::vector<int> midi_outs;
|
||||||
|
|
||||||
int midi_note = 0;
|
int midi_note = 0;
|
||||||
int midi_cc = 0;
|
int midi_cc = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user