virtual ports working - ui needs some work

This commit is contained in:
Sebastian
2026-06-24 00:38:49 +02:00
parent 3de17a3b43
commit ce675b1430
9 changed files with 96 additions and 23 deletions
+19 -4
View File
@@ -3,6 +3,7 @@
#include "interaction-manager.h"
#include "nlohmann/json.hpp"
#include "graph-manager.h"
#include "signal-manager.h"
#include "midi-node.h"
#include "state.h"
#include "ui.h"
@@ -22,6 +23,12 @@ namespace VISEQ::APP{
std::ofstream file("state.json");
file << json(*this);
std::cout << std::setw(4) << json(*this) << std::endl;
sm->midi.all_notes_off();
for(auto &p : sm->midi.midi_outs){
p.second->close_port();
}
}
void AppManager::startSignals(){
@@ -110,11 +117,19 @@ namespace VISEQ::APP{
for(auto& n : gm->getMidiNodes()){
auto nc = std::dynamic_pointer_cast<MidiNode>(n.lock());
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->selected_midi_outs.contains(mo.number) && mo.enabled){
nc->selected_midi_outs[mo.number] = {mo.number, false, mo.port.port_name};
}
if(nc->midi_outs.contains(mo.number) && !mo.enabled){
nc->midi_outs.erase(mo.number);
if(nc->selected_midi_outs.contains(mo.number) && !mo.enabled){
nc->selected_midi_outs.erase(mo.number);
}
}
for(auto& mo : sm->midi.virtual_midi_out_ports){
if(!nc->selected_midi_outs.contains(mo.number) && mo.enabled){
nc->selected_midi_outs[mo.number] = {mo.number, false, mo.name};
}
if(nc->selected_midi_outs.contains(mo.number) && !mo.enabled){
nc->selected_midi_outs.erase(mo.number);
}
}
}
+6
View File
@@ -89,6 +89,12 @@ namespace VISEQ::MIDI{
bool enabled;
};
struct VirtualMidiOutPort{
int number;
bool enabled;
std::string name;
};
struct MidiOut{
libremidi::midi_out out;
int number;
+1
View File
@@ -62,6 +62,7 @@ int main(){
}
app.close();
app.sm->midi.update();
CloseWindow();
+2 -1
View File
@@ -54,7 +54,8 @@ namespace VISEQ::GRAPH::NODES {
}
void MidiNode::setMidiPort(int midi_port, bool _state){
midi_outs[midi_port].enabled = _state;
selected_midi_outs[midi_port].enabled = _state;
std::cout << midi_port << " " << _state << std::endl;
}
void MidiNode::trigger() {
+2 -2
View File
@@ -33,8 +33,8 @@ namespace VISEQ::GRAPH::NODES {
struct NodeMidiOut{
int i;
std::string name;
bool enabled;
std::string name;
};
MidiNode() {init();}
@@ -51,7 +51,7 @@ namespace VISEQ::GRAPH::NODES {
int midi_out = -1;
std::map<int, NodeMidiOut> midi_outs;
std::map<int, NodeMidiOut> selected_midi_outs;
bool gui_midi_channel_edit = false;
bool gui_midi_note_edit = false;
+43 -10
View File
@@ -5,26 +5,29 @@
#include <iostream>
#include <memory>
#include <sstream>
#include "datatypes.h"
namespace VISEQ::MIDI {
void Midi::init(){
auto out_conf = libremidi::midi1::out_default_configuration();
for(int i = 0; i < 5; i++){
std::ostringstream port_name;
port_name << "viseq midi out " << i;
virtual_midi_out_ports.push_back({i+2000, false, port_name.str()});
}
}
void Midi::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++;
}
auto out_conf = libremidi::midi1::out_default_configuration();
virtual_midi_out = libremidi::midi_out(libremidi::output_configuration(), out_conf);
virtual_midi_out.open_virtual_port("viseq out");
//midi_out_ports.push_back({&virtual_midi_out, 99, false});
}
void Midi::open_midi_out(MidiOutPort *out_port){
@@ -42,15 +45,30 @@ namespace VISEQ::MIDI {
}
}
void Midi::open_midi_out(VirtualMidiOutPort *out_port){
if(!midi_outs.contains(out_port->number)){
auto out = std::make_shared<libremidi::midi_out>();
out->open_virtual_port(out_port->name);
midi_outs[out_port->number] = out;
}
}
void Midi::close_midi_out(VirtualMidiOutPort *out_port){
if(midi_outs.contains(out_port->number)){
midi_outs[out_port->number]->close_port();
midi_outs.erase(out_port->number);
}
}
void Midi::note(int midi_out, int channel, int note, int velocity, int gate){
std::cout << "note on " << midi_out << " " << midi_outs.contains(midi_out) << std::endl;
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);
std::cout << "note on " << midi_out << std::endl;
}
}
virtual_midi_out.send_message(libremidi::channel_events::note_on(channel, note, velocity));
notes.emplace_back(99, channel, note, velocity, GetTime(), gate);
}
void Midi::cc(int midi_out, int channel, int cc, int value){
@@ -69,17 +87,32 @@ namespace VISEQ::MIDI {
}
}
void Midi::all_notes_off(){
for(auto &n : notes){
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;});
}
void Midi::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));
virtual_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 : virtual_midi_out_ports){
if(p.enabled) {
open_midi_out(&p);
} else if(!p.enabled) {
close_midi_out(&p);
}
}
for(auto& p : midi_out_ports){
if(p.enabled) {
open_midi_out(&p);
+7 -1
View File
@@ -26,6 +26,7 @@ namespace VISEQ::MIDI {
public:
Midi() {
init();
enumerate();
}
@@ -34,19 +35,24 @@ namespace VISEQ::MIDI {
std::map<int, std::shared_ptr<libremidi::midi_out>> midi_outs;
std::vector<libremidi::input_port> midi_in_ports;
std::vector<MidiOutPort> midi_out_ports;
std::vector<VirtualMidiOutPort> virtual_midi_out_ports;
libremidi::midi_out virtual_midi_out;
std::vector<NoteTimer> notes;
float timer;
void init();
void enumerate();
void open_midi_out(MidiOutPort *out_port);
void close_midi_out(MidiOutPort *out_port);
void open_midi_out(VirtualMidiOutPort *out_port);
void close_midi_out(VirtualMidiOutPort *out_port);
void note(int midi_out, int channel, int note, int velocity, int gate);
void cc(int midi_out, int channel, int cc, int value);
void pitch_bend(int midi_out, int channel, int pitch_value);
void all_notes_off();
void update();
};
+2 -2
View File
@@ -98,14 +98,14 @@ namespace VISEQ::SIGNAL {
if(next_node.lock() != s->next.lock() && !next_node.expired() && s->next.lock()->getNodeType() == NodeType::MIDINODE) {
auto midinode = std::dynamic_pointer_cast<MidiNode>(s->next.lock());
for(auto &m : midinode->midi_outs){
for(auto &m : midinode->selected_midi_outs){
std::cout << m.second.name << " " << m.second.i << " " << m.second.enabled << std::endl;
if(m.second.enabled) {
if(midinode->send_note) midi.note(m.second.i, midinode->getNotes().channel, (int)Clamp(midinode->getNotes().note + s->midi_note_offset, 0, 127), midinode->getNotes().velocity, midinode->getNotes().gate);
if(midinode->send_cc) midi.cc(m.second.i, midinode->getCC().channel, midinode->getCC().control, (int)Clamp(midinode->getCC().value + s->midi_cc_offset, 0, 127));
if(midinode->send_pitch_bend) midi.pitch_bend(m.second.i, midinode->getPitchBend().channel, midinode->getPitchBend().value);
}
}
if(midinode->send_note) midi.note(99, midinode->getNotes().channel, (int)Clamp(midinode->getNotes().note + s->midi_note_offset, 0, 127), midinode->getNotes().velocity, midinode->getNotes().gate);
s->last = s->next;
s->next = next_node;
}
+12 -1
View File
@@ -9,6 +9,7 @@
#include <memory>
#include <ranges>
#include <sstream>
namespace VISEQ::APP::UI{
void AppUI::init(){
@@ -37,6 +38,11 @@ namespace VISEQ::APP::UI{
if(GuiButton((Rectangle){200, (float)s_midi, 60, 20}, "RELOAD")) sm->midi.enumerate();
int i = 0;
for(auto& vo : sm->midi.virtual_midi_out_ports){
GuiCheckBox((Rectangle){20, (float)s_midi + 25 + i*20.0f, 20, 20}, vo.name.substr(0,32).c_str(), &vo.enabled);
i++;
}
i++;
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++;
@@ -48,6 +54,11 @@ namespace VISEQ::APP::UI{
gm->setMidiPortForAll(midis.number, true);
}
}
for(auto &midis : sm->midi.virtual_midi_out_ports){
if(midis.enabled){
gm->setMidiPortForAll(midis.number, true);
}
}
}
int s_signal = s_midi + 100 + i*20;
@@ -119,7 +130,7 @@ namespace VISEQ::APP::UI{
int i = 0;
if(n->getNodeType() == NodeType::MIDINODE){
std::shared_ptr<MidiNode> mn = std::dynamic_pointer_cast<MidiNode>(n);
for(auto& mo : mn->midi_outs){
for(auto& mo : mn->selected_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++;
}