[bugui] refactor and add bugui submodule

This commit is contained in:
thibaud keller 2024-10-08 16:12:35 +01:00
parent b1c9378732
commit e0ad7c817b
7 changed files with 31 additions and 312 deletions

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "Hardware/3rdparty/bugui"]
path = Hardware/3rdparty/bugui
url = https://codeberg.org/bugui/bugui.git

View file

@ -9,18 +9,17 @@ if(NOT TARGET libremidi)
return()
endif()
score_common_setup()
set(HDRS
"Hardware/Controller.hpp"
"Hardware/MidiController.hpp"
add_subdirectory(Hardware/3rdparty/bugui)
set(HDRS
"Hardware/Settings/Model.hpp"
"Hardware/Settings/Presenter.hpp"
"Hardware/Settings/View.hpp"
"Hardware/Settings/Factory.hpp"
"Hardware/Controller.hpp"
"Hardware/DocumentPlugin.hpp"
"Hardware/ApplicationPlugin.hpp"
@ -28,24 +27,22 @@ set(HDRS
)
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/Presenter.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/ApplicationPlugin.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
score_plugin_scenario
libremidi
bugui
)
setup_score_plugin(${PROJECT_NAME})

1
Hardware/3rdparty/bugui vendored Submodule

@ -0,0 +1 @@
Subproject commit f97533d59cd0db29221dda683d845120617ae8a3

View file

@ -1,37 +1,30 @@
#include <wobjectimpl.h>
#include <score/application/ApplicationContext.hpp>
#include <score/actions/ActionManager.hpp>
#include <Scenario/Application/ScenarioActions.hpp>
#include "MidiController.hpp"
#include "Controller.hpp"
namespace Hardware
{
Controller::Controller(const score::DocumentContext& doc)
: h_ofset{0.} // initial horizontal ofset
, v_ofset{0.} // initial verticalal ofset
, h_zoom{.125} // initial horizontal zoom
, v_zoom{1.1} // initial verticalal zoom
{
commandCallback = [&doc, this](Controller::Commands com, const bool& shift) {
: bugui::controller{[&doc, this]
(commands com, const bool& shift)
{
switch (com)
{
case Controller::Play:
case Play:
if (shift)
doc.app.actions.action<Actions::PlayGlobal>().action()->trigger();
else
doc.app.actions.action<Actions::Play>().action()->trigger();
break;
case Controller::Stop:
case Stop:
if (shift)
doc.app.actions.action<Actions::Reinitialize>().action()->trigger();
else
doc.app.actions.action<Actions::Stop>().action()->trigger();
break;
case Controller::Up:
case Up:
if (shift)
{
v_zoom += .2;
@ -43,7 +36,7 @@ Controller::Controller(const score::DocumentContext& doc)
draw_intervals();
}
break;
case Controller::Down:
case Down:
if (shift)
{
if (v_zoom > .2)
@ -58,7 +51,7 @@ Controller::Controller(const score::DocumentContext& doc)
draw_intervals();
}
break;
case Controller::Left:
case Left:
if (shift)
{
if (h_zoom > .02)
@ -76,7 +69,7 @@ Controller::Controller(const score::DocumentContext& doc)
}
}
break;
case Controller::Right:
case Right:
if (shift)
{
h_zoom += .02;
@ -96,15 +89,9 @@ Controller::Controller(const score::DocumentContext& doc)
// qDebug() << "v_zoom: " << v_zoom;
// qDebug() << "h_ofset: " << 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)
{
@ -135,11 +122,13 @@ void Controller::draw_intervals()
auto def = c.duration.defaultDuration().sec() * h_zoom;
auto st = (c.date().sec() * h_zoom) - h_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)

View file

@ -5,44 +5,27 @@
#include <Scenario/Document/Interval/IntervalModel.hpp>
#include <Scenario/Process/ScenarioModel.hpp>
#include <controller.hpp>
namespace Hardware
{
class MidiController;
class SCORE_ADDON_HARDWARE_EXPORT Controller
: public QObject
: public bugui::controller
, public QObject
{
W_OBJECT(Controller)
public:
explicit Controller(const score::DocumentContext& doc);
enum Commands
{
Play = 0,
Stop,
Left,
Right,
Up,
Down
};
void setup();
void setup_scenario(Scenario::ProcessModel* s);
void draw_intervals();
private:
double h_ofset;
double v_ofset;
double h_zoom;
double v_zoom;
MidiController* ctl;
Scenario::ProcessModel* scenar;
std::function<void(Controller::Commands, const bool&)> commandCallback;
void on_interval_changed(const Scenario::IntervalModel &);
};
}

View file

@ -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;
}
}

View file

@ -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