[bugui] refactor and add bugui submodule
This commit is contained in:
parent
b1c9378732
commit
e0ad7c817b
7 changed files with 31 additions and 312 deletions
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "Hardware/3rdparty/bugui"]
|
||||||
|
path = Hardware/3rdparty/bugui
|
||||||
|
url = https://codeberg.org/bugui/bugui.git
|
|
@ -9,18 +9,17 @@ if(NOT TARGET libremidi)
|
||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
score_common_setup()
|
score_common_setup()
|
||||||
|
|
||||||
set(HDRS
|
add_subdirectory(Hardware/3rdparty/bugui)
|
||||||
"Hardware/Controller.hpp"
|
|
||||||
"Hardware/MidiController.hpp"
|
|
||||||
|
|
||||||
|
set(HDRS
|
||||||
"Hardware/Settings/Model.hpp"
|
"Hardware/Settings/Model.hpp"
|
||||||
"Hardware/Settings/Presenter.hpp"
|
"Hardware/Settings/Presenter.hpp"
|
||||||
"Hardware/Settings/View.hpp"
|
"Hardware/Settings/View.hpp"
|
||||||
"Hardware/Settings/Factory.hpp"
|
"Hardware/Settings/Factory.hpp"
|
||||||
|
|
||||||
|
"Hardware/Controller.hpp"
|
||||||
"Hardware/DocumentPlugin.hpp"
|
"Hardware/DocumentPlugin.hpp"
|
||||||
"Hardware/ApplicationPlugin.hpp"
|
"Hardware/ApplicationPlugin.hpp"
|
||||||
|
|
||||||
|
@ -28,24 +27,22 @@ set(HDRS
|
||||||
)
|
)
|
||||||
|
|
||||||
set(SRCS
|
set(SRCS
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/Hardware/Controller.cpp"
|
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/Hardware/MidiController.cpp"
|
|
||||||
|
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/Hardware/Settings/Model.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/Hardware/Settings/Model.cpp"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/Hardware/Settings/Presenter.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/Hardware/Settings/Presenter.cpp"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/Hardware/Settings/View.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/Hardware/Settings/View.cpp"
|
||||||
|
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/Hardware/Controller.cpp"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/Hardware/DocumentPlugin.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/Hardware/DocumentPlugin.cpp"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/Hardware/ApplicationPlugin.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/Hardware/ApplicationPlugin.cpp"
|
||||||
|
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/score_addon_hardware.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/score_addon_hardware.cpp"
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(${PROJECT_NAME} ${SRCS} ${HDRS} ${QRCS})
|
add_library(${PROJECT_NAME} ${SRCS} ${HDRS})
|
||||||
|
|
||||||
target_link_libraries(${PROJECT_NAME} PUBLIC
|
target_link_libraries(${PROJECT_NAME} PUBLIC
|
||||||
score_plugin_scenario
|
score_plugin_scenario
|
||||||
libremidi
|
bugui
|
||||||
)
|
)
|
||||||
|
|
||||||
setup_score_plugin(${PROJECT_NAME})
|
setup_score_plugin(${PROJECT_NAME})
|
||||||
|
|
1
Hardware/3rdparty/bugui
vendored
Submodule
1
Hardware/3rdparty/bugui
vendored
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit f97533d59cd0db29221dda683d845120617ae8a3
|
|
@ -1,37 +1,30 @@
|
||||||
#include <wobjectimpl.h>
|
|
||||||
|
|
||||||
#include <score/application/ApplicationContext.hpp>
|
#include <score/application/ApplicationContext.hpp>
|
||||||
#include <score/actions/ActionManager.hpp>
|
#include <score/actions/ActionManager.hpp>
|
||||||
#include <Scenario/Application/ScenarioActions.hpp>
|
#include <Scenario/Application/ScenarioActions.hpp>
|
||||||
|
|
||||||
#include "MidiController.hpp"
|
|
||||||
|
|
||||||
#include "Controller.hpp"
|
#include "Controller.hpp"
|
||||||
|
|
||||||
namespace Hardware
|
namespace Hardware
|
||||||
{
|
{
|
||||||
Controller::Controller(const score::DocumentContext& doc)
|
Controller::Controller(const score::DocumentContext& doc)
|
||||||
: h_ofset{0.} // initial horizontal ofset
|
: bugui::controller{[&doc, this]
|
||||||
, v_ofset{0.} // initial verticalal ofset
|
(commands com, const bool& shift)
|
||||||
, h_zoom{.125} // initial horizontal zoom
|
|
||||||
, v_zoom{1.1} // initial verticalal zoom
|
|
||||||
{
|
{
|
||||||
commandCallback = [&doc, this](Controller::Commands com, const bool& shift) {
|
|
||||||
switch (com)
|
switch (com)
|
||||||
{
|
{
|
||||||
case Controller::Play:
|
case Play:
|
||||||
if (shift)
|
if (shift)
|
||||||
doc.app.actions.action<Actions::PlayGlobal>().action()->trigger();
|
doc.app.actions.action<Actions::PlayGlobal>().action()->trigger();
|
||||||
else
|
else
|
||||||
doc.app.actions.action<Actions::Play>().action()->trigger();
|
doc.app.actions.action<Actions::Play>().action()->trigger();
|
||||||
break;
|
break;
|
||||||
case Controller::Stop:
|
case Stop:
|
||||||
if (shift)
|
if (shift)
|
||||||
doc.app.actions.action<Actions::Reinitialize>().action()->trigger();
|
doc.app.actions.action<Actions::Reinitialize>().action()->trigger();
|
||||||
else
|
else
|
||||||
doc.app.actions.action<Actions::Stop>().action()->trigger();
|
doc.app.actions.action<Actions::Stop>().action()->trigger();
|
||||||
break;
|
break;
|
||||||
case Controller::Up:
|
case Up:
|
||||||
if (shift)
|
if (shift)
|
||||||
{
|
{
|
||||||
v_zoom += .2;
|
v_zoom += .2;
|
||||||
|
@ -43,7 +36,7 @@ Controller::Controller(const score::DocumentContext& doc)
|
||||||
draw_intervals();
|
draw_intervals();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Controller::Down:
|
case Down:
|
||||||
if (shift)
|
if (shift)
|
||||||
{
|
{
|
||||||
if (v_zoom > .2)
|
if (v_zoom > .2)
|
||||||
|
@ -58,7 +51,7 @@ Controller::Controller(const score::DocumentContext& doc)
|
||||||
draw_intervals();
|
draw_intervals();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Controller::Left:
|
case Left:
|
||||||
if (shift)
|
if (shift)
|
||||||
{
|
{
|
||||||
if (h_zoom > .02)
|
if (h_zoom > .02)
|
||||||
|
@ -76,7 +69,7 @@ Controller::Controller(const score::DocumentContext& doc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Controller::Right:
|
case Right:
|
||||||
if (shift)
|
if (shift)
|
||||||
{
|
{
|
||||||
h_zoom += .02;
|
h_zoom += .02;
|
||||||
|
@ -96,15 +89,9 @@ Controller::Controller(const score::DocumentContext& doc)
|
||||||
// qDebug() << "v_zoom: " << v_zoom;
|
// qDebug() << "v_zoom: " << v_zoom;
|
||||||
// qDebug() << "h_ofset: " << h_ofset;
|
// qDebug() << "h_ofset: " << h_ofset;
|
||||||
// qDebug() << "h_zoom: " << h_ofset;
|
// qDebug() << "h_zoom: " << h_ofset;
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller::setup()
|
|
||||||
{
|
|
||||||
ctl = new MidiController{};
|
|
||||||
ctl->on_command = commandCallback;
|
|
||||||
ctl->setup();
|
|
||||||
}
|
}
|
||||||
|
{}
|
||||||
|
|
||||||
void Controller::setup_scenario(Scenario::ProcessModel* s)
|
void Controller::setup_scenario(Scenario::ProcessModel* s)
|
||||||
{
|
{
|
||||||
|
@ -135,11 +122,13 @@ void Controller::draw_intervals()
|
||||||
auto def = c.duration.defaultDuration().sec() * h_zoom;
|
auto def = c.duration.defaultDuration().sec() * h_zoom;
|
||||||
auto st = (c.date().sec() * h_zoom) - h_ofset;
|
auto st = (c.date().sec() * h_zoom) - h_ofset;
|
||||||
auto y = (c.heightPercentage() * v_zoom) + v_ofset;
|
auto y = (c.heightPercentage() * v_zoom) + v_ofset;
|
||||||
ctl->draw_line({st, y}, {st + def, y});
|
draw_line({st, y}, {st + def, y});
|
||||||
}
|
}
|
||||||
|
|
||||||
ctl->update_grid();
|
update_grid();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <wobjectimpl.h>
|
||||||
W_OBJECT_IMPL(Hardware::Controller)
|
W_OBJECT_IMPL(Hardware::Controller)
|
||||||
|
|
|
@ -5,44 +5,27 @@
|
||||||
#include <Scenario/Document/Interval/IntervalModel.hpp>
|
#include <Scenario/Document/Interval/IntervalModel.hpp>
|
||||||
#include <Scenario/Process/ScenarioModel.hpp>
|
#include <Scenario/Process/ScenarioModel.hpp>
|
||||||
|
|
||||||
|
#include <controller.hpp>
|
||||||
|
|
||||||
namespace Hardware
|
namespace Hardware
|
||||||
{
|
{
|
||||||
class MidiController;
|
|
||||||
|
|
||||||
class SCORE_ADDON_HARDWARE_EXPORT Controller
|
class SCORE_ADDON_HARDWARE_EXPORT Controller
|
||||||
: public QObject
|
: public bugui::controller
|
||||||
|
, public QObject
|
||||||
{
|
{
|
||||||
W_OBJECT(Controller)
|
W_OBJECT(Controller)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Controller(const score::DocumentContext& doc);
|
explicit Controller(const score::DocumentContext& doc);
|
||||||
|
|
||||||
enum Commands
|
|
||||||
{
|
|
||||||
Play = 0,
|
|
||||||
Stop,
|
|
||||||
Left,
|
|
||||||
Right,
|
|
||||||
Up,
|
|
||||||
Down
|
|
||||||
};
|
|
||||||
|
|
||||||
void setup();
|
|
||||||
void setup_scenario(Scenario::ProcessModel* s);
|
void setup_scenario(Scenario::ProcessModel* s);
|
||||||
void draw_intervals();
|
void draw_intervals();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
double h_ofset;
|
|
||||||
double v_ofset;
|
|
||||||
double h_zoom;
|
|
||||||
double v_zoom;
|
|
||||||
|
|
||||||
MidiController* ctl;
|
|
||||||
Scenario::ProcessModel* scenar;
|
Scenario::ProcessModel* scenar;
|
||||||
|
|
||||||
std::function<void(Controller::Commands, const bool&)> commandCallback;
|
|
||||||
|
|
||||||
void on_interval_changed(const Scenario::IntervalModel &);
|
void on_interval_changed(const Scenario::IntervalModel &);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,183 +0,0 @@
|
||||||
#include <libremidi/libremidi.hpp>
|
|
||||||
|
|
||||||
#include "MidiController.hpp"
|
|
||||||
|
|
||||||
namespace Hardware
|
|
||||||
{
|
|
||||||
MidiController::MidiController()
|
|
||||||
: grid{GRID}
|
|
||||||
, previous_grid{BLACK}
|
|
||||||
, current_grid{BLACK}
|
|
||||||
, m_output{}
|
|
||||||
, m_input{{.on_message = [this] (const libremidi::message& message)
|
|
||||||
{
|
|
||||||
if (message.get_message_type() == libremidi::message_type::CONTROL_CHANGE)
|
|
||||||
switch (message.bytes[1])
|
|
||||||
{
|
|
||||||
case SHIFT:
|
|
||||||
shift = message.bytes[2] > 0;
|
|
||||||
break;
|
|
||||||
case PLAY:
|
|
||||||
if (message.bytes[2] > 0)
|
|
||||||
on_command(Controller::Play, shift);
|
|
||||||
break;
|
|
||||||
case STOP:
|
|
||||||
if (message.bytes[2] > 0)
|
|
||||||
on_command(Controller::Stop, shift);
|
|
||||||
break;
|
|
||||||
case UP:
|
|
||||||
if (message.bytes[2] > 0)
|
|
||||||
on_command(Controller::Up, shift);
|
|
||||||
break;
|
|
||||||
case DOWN:
|
|
||||||
if (message.bytes[2] > 0)
|
|
||||||
on_command(Controller::Down, shift);
|
|
||||||
break;
|
|
||||||
case LEFT:
|
|
||||||
if (message.bytes[2] > 0)
|
|
||||||
on_command(Controller::Left, shift);
|
|
||||||
break;
|
|
||||||
case RIGHT:
|
|
||||||
if (message.bytes[2] > 0)
|
|
||||||
on_command(Controller::Right, shift);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.ignore_sensing = false,
|
|
||||||
.ignore_timing = false,
|
|
||||||
.ignore_sysex = false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{}
|
|
||||||
|
|
||||||
MidiController::~MidiController()
|
|
||||||
{
|
|
||||||
m_input.close_port();
|
|
||||||
m_output.close_port();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MidiController::setup(const QString& deviceName)
|
|
||||||
{
|
|
||||||
open_port_by_name(deviceName);
|
|
||||||
|
|
||||||
if (m_output.is_port_open())
|
|
||||||
{
|
|
||||||
using namespace libremidi;
|
|
||||||
using e = channel_events;
|
|
||||||
|
|
||||||
m_output.send_message(message PROGRAMER_MODE);
|
|
||||||
|
|
||||||
m_output.send_message(e::note_on(1, u_int8_t{SHIFT}, u_int8_t{WHITE}));
|
|
||||||
m_output.send_message(e::note_on(1, u_int8_t{PLAY}, u_int8_t{GREEN}));
|
|
||||||
m_output.send_message(e::note_on(1, u_int8_t{STOP}, u_int8_t{ORANGE}));
|
|
||||||
|
|
||||||
clear_grid();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MidiController::update_grid()
|
|
||||||
{
|
|
||||||
for (int i{0}; i <= MAX_COLUMN_INDEX; i++)
|
|
||||||
for (int j{0}; j <= MAX_ROW_INDEX; j++)
|
|
||||||
{
|
|
||||||
if (current_grid[i][j] != previous_grid[i][j])
|
|
||||||
m_output.send_message(libremidi::channel_events::note_on(1,
|
|
||||||
grid[i][j],
|
|
||||||
current_grid[i][j]));
|
|
||||||
previous_grid[i][j] = current_grid[i][j];
|
|
||||||
current_grid[i][j] = BLACK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MidiController::clear_grid()
|
|
||||||
{
|
|
||||||
for (int i{0}; i <= MAX_COLUMN_INDEX; i++)
|
|
||||||
for (int j{0}; j <= MAX_ROW_INDEX; j++)
|
|
||||||
{
|
|
||||||
current_grid[i][j] = BLACK;
|
|
||||||
m_output.send_message(libremidi::channel_events::note_on(1,
|
|
||||||
grid[i][j],
|
|
||||||
BLACK));
|
|
||||||
previous_grid[i][j] = BLACK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MidiController::draw_line(const std::array<double, 2>& p1,
|
|
||||||
const std::array<double, 2>& p2)
|
|
||||||
{
|
|
||||||
int p1x = int(p1[0] * MAX_ROW_INDEX);
|
|
||||||
int p2x = int(p2[0] * MAX_ROW_INDEX);
|
|
||||||
int p1y = int(p1[1] * MAX_COLUMN_INDEX);
|
|
||||||
int p2y = int(p2[1] * MAX_COLUMN_INDEX);
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
using namespace libremidi;
|
|
||||||
using e = channel_events;
|
|
||||||
|
|
||||||
// qDebug() << "p1y: " << p1y;
|
|
||||||
// qDebug() << "p2y: " << p2y;
|
|
||||||
|
|
||||||
if (p1y == p2y) // draw horizontal lines
|
|
||||||
{
|
|
||||||
if (p1y < 0 || p1y > MAX_COLUMN_INDEX) // vertical position out of range
|
|
||||||
return;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int start{min(p1x, p2x)};
|
|
||||||
int end{max(p1x, p2x)};
|
|
||||||
|
|
||||||
if (start > MAX_ROW_INDEX || end < 0) // horizonal position out of range
|
|
||||||
return;
|
|
||||||
|
|
||||||
int last{min(MAX_ROW_INDEX, end)}; // last index in range
|
|
||||||
|
|
||||||
for (int i{max(0, start)}; i <= last; i++) // itterate from first index in range
|
|
||||||
current_grid[p1y][i] = LIGHT_BLUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (p1x == p2x) // draw verticatl lines
|
|
||||||
{
|
|
||||||
if (p1x < 0 || p1x > MAX_ROW_INDEX) // horizontal position out of range
|
|
||||||
return;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int start{min(p1y, p2y)};
|
|
||||||
int end{max(p1y, p2y)};
|
|
||||||
|
|
||||||
if (start > MAX_COLUMN_INDEX || end < 0) // vertical position out of range
|
|
||||||
return;
|
|
||||||
|
|
||||||
int last{min(MAX_COLUMN_INDEX, end)}; // last index in range
|
|
||||||
|
|
||||||
for (int i{max(0, start)}; i <= last; i++) // itterate from first index in range
|
|
||||||
current_grid[p1y][i] = LIGHT_BLUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MidiController::open_port_by_name(const QString& deviceName)
|
|
||||||
{
|
|
||||||
libremidi::observer obs;
|
|
||||||
|
|
||||||
for (const auto& input : obs.get_input_ports())
|
|
||||||
{
|
|
||||||
if (deviceName == QString::fromStdString(input.port_name).split(":").back())
|
|
||||||
m_input.open_port(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO : error handling here
|
|
||||||
if (!m_input.is_port_connected()) return;
|
|
||||||
|
|
||||||
for (const auto& output : obs.get_output_ports())
|
|
||||||
{
|
|
||||||
if (deviceName == QString::fromStdString(output.port_name).split(":").back())
|
|
||||||
m_output.open_port(output);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO : error handling here
|
|
||||||
if (!m_output.is_port_connected()) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,71 +0,0 @@
|
||||||
#ifndef MIDICONTROLLER_HPP
|
|
||||||
#define MIDICONTROLLER_HPP
|
|
||||||
|
|
||||||
#include <Scenario/Application/ScenarioActions.hpp>
|
|
||||||
#include <score/actions/ActionManager.hpp>
|
|
||||||
|
|
||||||
#include <libremidi/libremidi.hpp>
|
|
||||||
|
|
||||||
#include "Controller.hpp"
|
|
||||||
|
|
||||||
// Macros to temporarly act as the device description file
|
|
||||||
#define PROGRAMER_MODE {240, 0, 32, 41, 2, 16, 44, 3, 247}
|
|
||||||
|
|
||||||
#define SHIFT 80
|
|
||||||
#define PLAY 19
|
|
||||||
#define STOP 8
|
|
||||||
#define UP 91
|
|
||||||
#define DOWN 92
|
|
||||||
#define LEFT 93
|
|
||||||
#define RIGHT 94
|
|
||||||
|
|
||||||
#define BLACK 0
|
|
||||||
#define WHITE 2
|
|
||||||
#define LIGHT_BLUE 36
|
|
||||||
#define GREEN 64
|
|
||||||
#define ORANGE 9
|
|
||||||
|
|
||||||
// Grid
|
|
||||||
#define GRID \
|
|
||||||
{81, 82, 83, 84, 85, 86, 87, 88}, \
|
|
||||||
{71, 72, 73, 74, 75, 76, 77, 78}, \
|
|
||||||
{61, 62, 63, 64, 65, 66, 67, 68}, \
|
|
||||||
{51, 52, 53, 54, 55, 56, 57, 58}, \
|
|
||||||
{41, 42, 43, 44, 45, 46, 47, 48}, \
|
|
||||||
{31, 32, 33, 34, 35, 36, 37, 38}, \
|
|
||||||
{21, 22, 23, 24, 25, 26, 27, 28}, \
|
|
||||||
{11, 12, 13, 14, 15, 16, 17, 18}
|
|
||||||
|
|
||||||
#define MAX_ROW_INDEX 7
|
|
||||||
#define MAX_COLUMN_INDEX 7
|
|
||||||
|
|
||||||
namespace Hardware
|
|
||||||
{
|
|
||||||
class MidiController
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MidiController();
|
|
||||||
~MidiController();
|
|
||||||
|
|
||||||
std::function<void(Controller::Commands, const bool&)> on_command;
|
|
||||||
|
|
||||||
void setup(const QString& deviceName = "Launchpad Pro Standalone Port");
|
|
||||||
void update_grid();
|
|
||||||
void clear_grid();
|
|
||||||
void draw_line(const std::array<double, 2>& p1, const std::array<double, 2>& p2);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void open_port_by_name(const QString& deviceName);
|
|
||||||
|
|
||||||
u_int8_t grid[MAX_ROW_INDEX + 1][MAX_COLUMN_INDEX + 1];
|
|
||||||
u_int8_t previous_grid[MAX_ROW_INDEX + 1][MAX_COLUMN_INDEX + 1];
|
|
||||||
u_int8_t current_grid[MAX_ROW_INDEX + 1][MAX_COLUMN_INDEX + 1];
|
|
||||||
bool shift{false};
|
|
||||||
|
|
||||||
libremidi::midi_out m_output;
|
|
||||||
libremidi::midi_in m_input;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // MIDICONTROLLER_HPP
|
|
Loading…
Add table
Reference in a new issue