2#include <ossia/network/context.hpp> 
    4#include <ossia-qt/protocols/utils.hpp> 
   11#include <libremidi/libremidi.hpp> 
   13#include <nano_observer.hpp> 
   36class qml_ump_outbound_socket
 
   38    , 
public Nano::Observer
 
   40  W_OBJECT(qml_ump_outbound_socket)
 
   42  qml_ump_outbound_socket() { }
 
   44  ~qml_ump_outbound_socket() { close(); }
 
   46  void open(
const libremidi::port_information& pi)
 
   51      libremidi::output_configuration config;
 
   54      m_ump_out = std::make_unique<libremidi::midi_out>(
 
   55          config, libremidi::midi2::default_api());
 
   58      if(
auto err = m_ump_out->open_port(
static_cast<const libremidi::output_port&
>(pi));
 
   61        if(onError.isCallable())
 
   63          const auto& msg = err.message();
 
   65              { onError.call({QString::fromUtf8(msg.data(), msg.size())}); });
 
   73      if(onOpen.isCallable())
 
   75        run_on_qt_thread({ onOpen.call({qjsEngine(
this)->newQObject(
this)}); });
 
   78    catch(
const std::exception& e)
 
   80      if(onError.isCallable())
 
   82        run_on_qt_thread({ onError.call({QString::fromUtf8(e.what())}); });
 
   92      m_observer = std::make_unique<libremidi::observer>(
 
   93          libremidi::observer_configuration{}, libremidi::midi2::default_api());
 
   96      auto ports = m_observer->get_output_ports();
 
  100        if(onError.isCallable())
 
  102          run_on_qt_thread({ onError.call({
"No UMP output ports available"}); });
 
  110    catch(
const std::exception& e)
 
  112      if(onError.isCallable())
 
  114        run_on_qt_thread({ onError.call({QString::fromUtf8(e.what())}); });
 
  127      if(onClose.isCallable())
 
  129        run_on_qt_thread({ onClose.call(); });
 
  136  void sendMessage(QVariantList words)
 
  138    if(!m_is_open || !m_ump_out)
 
  141    if(words.size() != 4)
 
  143      if(onError.isCallable())
 
  145        run_on_qt_thread({ onError.call({
"UMP message must contain exactly 4 words"}); });
 
  152    for(
int i = 0; i < 4; ++i)
 
  154      msg.data[i] = 
static_cast<uint32_t
>(words[i].toUInt());
 
  157    if(
auto err = m_ump_out->send_ump(msg); err != stdx::error{})
 
  159      if(onError.isCallable())
 
  161        const auto& errmsg = err.message();
 
  163            { onError.call({QString::fromUtf8(errmsg.data(), errmsg.size())}); });
 
  170  void sendNoteOn(
int group, 
int channel, 
int note, 
int velocity, 
int attributeType, 
int attribute)
 
  172    if(!m_is_open || !m_ump_out)
 
  175    if(group < 1 || group > 16 || channel < 1 || channel > 16 || 
 
  176       note < 0 || note > 127 || velocity < 0 || velocity > 65535)
 
  182    msg.data[0] = (0x4 << 28) | ((group - 1) << 24) | (0x90 << 16) | ((channel - 1) << 16) | (note << 8) | attributeType;
 
  184    msg.data[1] = (velocity << 16) | (attribute & 0xFFFF);
 
  188    m_ump_out->send_ump(msg);
 
  192  void sendNoteOff(
int group, 
int channel, 
int note, 
int velocity, 
int attributeType, 
int attribute)
 
  194    if(!m_is_open || !m_ump_out)
 
  197    if(group < 1 || group > 16 || channel < 1 || channel > 16 || 
 
  198       note < 0 || note > 127 || velocity < 0 || velocity > 65535)
 
  204    msg.data[0] = (0x4 << 28) | ((group - 1) << 24) | (0x80 << 16) | ((channel - 1) << 16) | (note << 8) | attributeType;
 
  206    msg.data[1] = (velocity << 16) | (attribute & 0xFFFF);
 
  210    m_ump_out->send_ump(msg);
 
  214  void sendControlChange(
int group, 
int channel, 
int controller, 
int value)
 
  216    if(!m_is_open || !m_ump_out)
 
  219    if(group < 1 || group > 16 || channel < 1 || channel > 16 || 
 
  220       controller < 0 || controller > 127)
 
  226    msg.data[0] = (0x4 << 28) | ((group - 1) << 24) | (0xB0 << 16) | ((channel - 1) << 16) | (controller << 8);
 
  228    msg.data[1] = 
static_cast<uint32_t
>(value);
 
  232    m_ump_out->send_ump(msg);
 
  234  W_SLOT(sendControlChange)
 
  236  void sendProgramChange(
int group, 
int channel, 
int program, 
int bankMSB, 
int bankLSB)
 
  238    if(!m_is_open || !m_ump_out)
 
  241    if(group < 1 || group > 16 || channel < 1 || channel > 16 || 
 
  242       program < 0 || program > 127 || bankMSB < 0 || bankMSB > 127 || bankLSB < 0 || bankLSB > 127)
 
  248    msg.data[0] = (0x4 << 28) | ((group - 1) << 24) | (0xC0 << 16) | ((channel - 1) << 16);
 
  250    msg.data[1] = (program << 24) | (bankMSB << 8) | bankLSB;
 
  254    m_ump_out->send_ump(msg);
 
  256  W_SLOT(sendProgramChange)
 
  258  void sendPitchBend(
int group, 
int channel, 
int value)
 
  260    if(!m_is_open || !m_ump_out)
 
  263    if(group < 1 || group > 16 || channel < 1 || channel > 16)
 
  269    msg.data[0] = (0x4 << 28) | ((group - 1) << 24) | (0xE0 << 16) | ((channel - 1) << 16);
 
  271    msg.data[1] = 
static_cast<uint32_t
>(value);
 
  275    m_ump_out->send_ump(msg);
 
  277  W_SLOT(sendPitchBend)
 
  285  std::unique_ptr<libremidi::observer> m_observer;
 
  286  std::unique_ptr<libremidi::midi_out> m_ump_out;
 
  287  std::atomic_bool m_is_open{
false};
 
Definition qml_device.cpp:43