virtual ports working - ui needs some work
This commit is contained in:
+19
-4
@@ -3,6 +3,7 @@
|
|||||||
#include "interaction-manager.h"
|
#include "interaction-manager.h"
|
||||||
#include "nlohmann/json.hpp"
|
#include "nlohmann/json.hpp"
|
||||||
#include "graph-manager.h"
|
#include "graph-manager.h"
|
||||||
|
#include "signal-manager.h"
|
||||||
#include "midi-node.h"
|
#include "midi-node.h"
|
||||||
#include "state.h"
|
#include "state.h"
|
||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
@@ -22,6 +23,12 @@ namespace VISEQ::APP{
|
|||||||
std::ofstream file("state.json");
|
std::ofstream file("state.json");
|
||||||
file << json(*this);
|
file << json(*this);
|
||||||
std::cout << std::setw(4) << json(*this) << std::endl;
|
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(){
|
void AppManager::startSignals(){
|
||||||
@@ -110,11 +117,19 @@ namespace VISEQ::APP{
|
|||||||
for(auto& n : gm->getMidiNodes()){
|
for(auto& n : gm->getMidiNodes()){
|
||||||
auto nc = std::dynamic_pointer_cast<MidiNode>(n.lock());
|
auto nc = std::dynamic_pointer_cast<MidiNode>(n.lock());
|
||||||
for(auto& mo : sm->midi.midi_out_ports){
|
for(auto& mo : sm->midi.midi_out_ports){
|
||||||
if(!nc->midi_outs.contains(mo.number) && mo.enabled){
|
if(!nc->selected_midi_outs.contains(mo.number) && mo.enabled){
|
||||||
nc->midi_outs[mo.number] = {mo.number, mo.port.port_name, false};
|
nc->selected_midi_outs[mo.number] = {mo.number, false, mo.port.port_name};
|
||||||
}
|
}
|
||||||
if(nc->midi_outs.contains(mo.number) && !mo.enabled){
|
if(nc->selected_midi_outs.contains(mo.number) && !mo.enabled){
|
||||||
nc->midi_outs.erase(mo.number);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,6 +88,12 @@ namespace VISEQ::MIDI{
|
|||||||
int number;
|
int number;
|
||||||
bool enabled;
|
bool enabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct VirtualMidiOutPort{
|
||||||
|
int number;
|
||||||
|
bool enabled;
|
||||||
|
std::string name;
|
||||||
|
};
|
||||||
|
|
||||||
struct MidiOut{
|
struct MidiOut{
|
||||||
libremidi::midi_out out;
|
libremidi::midi_out out;
|
||||||
|
|||||||
+2
-1
@@ -62,7 +62,8 @@ int main(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
app.close();
|
app.close();
|
||||||
|
app.sm->midi.update();
|
||||||
|
|
||||||
CloseWindow();
|
CloseWindow();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
+2
-1
@@ -54,7 +54,8 @@ namespace VISEQ::GRAPH::NODES {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MidiNode::setMidiPort(int midi_port, bool _state){
|
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() {
|
void MidiNode::trigger() {
|
||||||
|
|||||||
+2
-2
@@ -33,8 +33,8 @@ namespace VISEQ::GRAPH::NODES {
|
|||||||
|
|
||||||
struct NodeMidiOut{
|
struct NodeMidiOut{
|
||||||
int i;
|
int i;
|
||||||
std::string name;
|
|
||||||
bool enabled;
|
bool enabled;
|
||||||
|
std::string name;
|
||||||
};
|
};
|
||||||
|
|
||||||
MidiNode() {init();}
|
MidiNode() {init();}
|
||||||
@@ -51,7 +51,7 @@ namespace VISEQ::GRAPH::NODES {
|
|||||||
|
|
||||||
int midi_out = -1;
|
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_channel_edit = false;
|
||||||
bool gui_midi_note_edit = false;
|
bool gui_midi_note_edit = false;
|
||||||
|
|||||||
+43
-10
@@ -5,26 +5,29 @@
|
|||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <sstream>
|
||||||
#include "datatypes.h"
|
#include "datatypes.h"
|
||||||
|
|
||||||
namespace VISEQ::MIDI {
|
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(){
|
void Midi::enumerate(){
|
||||||
std::cout << (int)obs.get_current_api() << std::endl;
|
std::cout << (int)obs.get_current_api() << std::endl;
|
||||||
|
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
midi_out_ports.clear();
|
midi_out_ports.clear();
|
||||||
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, i, false});
|
midi_out_ports.push_back({port, i, false});
|
||||||
i++;
|
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){
|
void Midi::open_midi_out(MidiOutPort *out_port){
|
||||||
@@ -41,16 +44,31 @@ namespace VISEQ::MIDI {
|
|||||||
midi_outs.erase(out_port->number);
|
midi_outs.erase(out_port->number);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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){
|
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.contains(midi_out)){
|
||||||
if(midi_outs[midi_out]->is_port_open()){
|
if(midi_outs[midi_out]->is_port_open()){
|
||||||
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(), gate);
|
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){
|
void Midi::cc(int midi_out, int channel, int cc, int value){
|
||||||
@@ -69,16 +87,31 @@ 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(){
|
void Midi::update(){
|
||||||
float time = GetTime();
|
float time = GetTime();
|
||||||
for(auto &n : notes){
|
for(auto &n : notes){
|
||||||
if(time - n.start >= (float)n.gate / 1000.0f){
|
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));
|
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;
|
n.erase = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::erase_if(notes, [](const auto& item){return item.erase;});
|
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){
|
for(auto& p : midi_out_ports){
|
||||||
if(p.enabled) {
|
if(p.enabled) {
|
||||||
|
|||||||
+8
-2
@@ -26,6 +26,7 @@ namespace VISEQ::MIDI {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
Midi() {
|
Midi() {
|
||||||
|
init();
|
||||||
enumerate();
|
enumerate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,19 +35,24 @@ namespace VISEQ::MIDI {
|
|||||||
std::map<int, 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<MidiOutPort> midi_out_ports;
|
std::vector<MidiOutPort> midi_out_ports;
|
||||||
|
std::vector<VirtualMidiOutPort> virtual_midi_out_ports;
|
||||||
|
|
||||||
libremidi::midi_out virtual_midi_out;
|
|
||||||
|
|
||||||
std::vector<NoteTimer> notes;
|
std::vector<NoteTimer> notes;
|
||||||
|
|
||||||
float timer;
|
float timer;
|
||||||
|
|
||||||
|
void init();
|
||||||
|
|
||||||
void enumerate();
|
void enumerate();
|
||||||
void open_midi_out(MidiOutPort *out_port);
|
void open_midi_out(MidiOutPort *out_port);
|
||||||
void close_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 note(int midi_out, int channel, int note, int velocity, int gate);
|
||||||
void cc(int midi_out, int channel, int cc, int value);
|
void cc(int midi_out, int channel, int cc, int value);
|
||||||
void pitch_bend(int midi_out, int channel, int pitch_value);
|
void pitch_bend(int midi_out, int channel, int pitch_value);
|
||||||
|
void all_notes_off();
|
||||||
void update();
|
void update();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -98,14 +98,14 @@ namespace VISEQ::SIGNAL {
|
|||||||
|
|
||||||
if(next_node.lock() != s->next.lock() && !next_node.expired() && s->next.lock()->getNodeType() == NodeType::MIDINODE) {
|
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());
|
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(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_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_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_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->last = s->next;
|
||||||
s->next = next_node;
|
s->next = next_node;
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-1
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
namespace VISEQ::APP::UI{
|
namespace VISEQ::APP::UI{
|
||||||
void AppUI::init(){
|
void AppUI::init(){
|
||||||
@@ -37,6 +38,11 @@ namespace VISEQ::APP::UI{
|
|||||||
if(GuiButton((Rectangle){200, (float)s_midi, 60, 20}, "RELOAD")) sm->midi.enumerate();
|
if(GuiButton((Rectangle){200, (float)s_midi, 60, 20}, "RELOAD")) sm->midi.enumerate();
|
||||||
|
|
||||||
int i = 0;
|
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){
|
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);
|
GuiCheckBox((Rectangle){20, (float)s_midi + 25 + i*20.0f, 20, 20}, mo.port.port_name.substr(0,32).c_str(), &mo.enabled);
|
||||||
i++;
|
i++;
|
||||||
@@ -48,6 +54,11 @@ namespace VISEQ::APP::UI{
|
|||||||
gm->setMidiPortForAll(midis.number, true);
|
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;
|
int s_signal = s_midi + 100 + i*20;
|
||||||
@@ -119,7 +130,7 @@ namespace VISEQ::APP::UI{
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
if(n->getNodeType() == NodeType::MIDINODE){
|
if(n->getNodeType() == NodeType::MIDINODE){
|
||||||
std::shared_ptr<MidiNode> mn = std::dynamic_pointer_cast<MidiNode>(n);
|
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);
|
GuiCheckBox((Rectangle){np.x + 20, np.y + y_midi + 20 + i*20.0f, 20, 20}, mo.second.name.c_str(), &mo.second.enabled);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user