2#include <ossia/network/context.hpp>
4#include <ossia-qt/protocols/utils.hpp>
11#include <libremidi/libremidi.hpp>
13#include <nano_observer.hpp>
35class qml_midi_outbound_socket
37 ,
public Nano::Observer
39 W_OBJECT(qml_midi_outbound_socket)
41 qml_midi_outbound_socket() { }
43 ~qml_midi_outbound_socket() { close(); }
45 void open(
const libremidi::port_information& pi)
50 libremidi::output_configuration config;
53 m_midi_out = std::make_unique<libremidi::midi_out>(config);
56 if(
auto err = m_midi_out->open_port(
static_cast<const libremidi::output_port&
>(pi));
59 if(onError.isCallable())
61 const auto& msg = err.message();
63 { onError.call({QString::fromUtf8(msg.data(), msg.size())}); });
71 if(onOpen.isCallable())
73 run_on_qt_thread({ onOpen.call({qjsEngine(
this)->newQObject(
this)}); });
76 catch(
const std::exception& e)
78 if(onError.isCallable())
80 run_on_qt_thread({ onError.call({QString::fromUtf8(e.what())}); });
90 m_observer = std::make_unique<libremidi::observer>();
93 auto ports = m_observer->get_output_ports();
97 if(onError.isCallable())
99 run_on_qt_thread({ onError.call({
"No MIDI output ports available"}); });
107 catch(
const std::exception& e)
109 if(onError.isCallable())
111 run_on_qt_thread({ onError.call({QString::fromUtf8(e.what())}); });
124 if(onClose.isCallable())
126 run_on_qt_thread({ onClose.call(); });
133 void sendMessage(QVariantList bytes)
135 if(!m_is_open || !m_midi_out)
138 libremidi::message msg;
139 for(
const auto&
byte : bytes)
141 msg.bytes.push_back(
static_cast<uint8_t
>(
byte.toInt()));
144 if(
auto err = m_midi_out->send_message(msg); err != stdx::error{})
146 if(onError.isCallable())
148 const auto& errmsg = err.message();
150 { onError.call({QString::fromUtf8(errmsg.data(), errmsg.size())}); });
157 void sendNoteOn(
int channel,
int note,
int velocity)
159 if(!m_is_open || !m_midi_out)
162 if(channel < 1 || channel > 16 || note < 0 || note > 127 || velocity < 0 || velocity > 127)
165 m_midi_out->send_message(0x90 | (channel - 1), note, velocity);
169 void sendNoteOff(
int channel,
int note,
int velocity)
171 if(!m_is_open || !m_midi_out)
174 if(channel < 1 || channel > 16 || note < 0 || note > 127 || velocity < 0 || velocity > 127)
177 m_midi_out->send_message(0x80 | (channel - 1), note, velocity);
181 void sendControlChange(
int channel,
int controller,
int value)
183 if(!m_is_open || !m_midi_out)
186 if(channel < 1 || channel > 16 || controller < 0 || controller > 127 || value < 0 || value > 127)
189 m_midi_out->send_message(0xB0 | (channel - 1), controller, value);
191 W_SLOT(sendControlChange)
193 void sendProgramChange(
int channel,
int program)
195 if(!m_is_open || !m_midi_out)
198 if(channel < 1 || channel > 16 || program < 0 || program > 127)
201 m_midi_out->send_message(0xC0 | (channel - 1), program);
203 W_SLOT(sendProgramChange)
205 void sendPitchBend(
int channel,
int value)
207 if(!m_is_open || !m_midi_out)
210 if(channel < 1 || channel > 16 || value < 0 || value > 16383)
213 m_midi_out->send_message(0xE0 | (channel - 1), value & 0x7F, (value >> 7) & 0x7F);
215 W_SLOT(sendPitchBend)
217 void sendSysex(QVariantList data)
219 if(!m_is_open || !m_midi_out)
222 libremidi::message msg;
223 msg.bytes.push_back(0xF0);
224 for(
const auto&
byte : data)
226 int val =
byte.toInt();
227 if(val >= 0 && val <= 127)
228 msg.bytes.push_back(
static_cast<uint8_t
>(val));
230 msg.bytes.push_back(0xF7);
232 if(
auto err = m_midi_out->send_message(msg); err != stdx::error{})
234 if(onError.isCallable())
236 const auto& errmsg = err.message();
238 { onError.call({QString::fromUtf8(errmsg.data(), errmsg.size())}); });
250 std::unique_ptr<libremidi::observer> m_observer;
251 std::unique_ptr<libremidi::midi_out> m_midi_out;
252 std::atomic_bool m_is_open{
false};
Definition qml_device.cpp:43