Infrastructure for incoming MIDI messages ready
This commit is contained in:
parent
bf3f388acb
commit
7a3d211d09
2
Makefile
2
Makefile
@ -6,7 +6,7 @@ DEBUG_FLAGS=-O0 -ggdb -fsanitize=undefined
|
||||
CXX=g++
|
||||
|
||||
LDFLAGS=-L./lib/midi/
|
||||
LDLIBS=-lmidi-alsa -lasound -lreadline
|
||||
LDLIBS=-lmidi-alsa -lasound -lpthread
|
||||
|
||||
Obj= \
|
||||
context.o \
|
||||
|
@ -5,6 +5,46 @@
|
||||
#include <random>
|
||||
#include <thread>
|
||||
|
||||
struct Interpreter::Incoming_Midi_Callbacks
|
||||
{
|
||||
Value note_on{};
|
||||
Value note_off{};
|
||||
|
||||
Incoming_Midi_Callbacks() = default;
|
||||
|
||||
Incoming_Midi_Callbacks(Incoming_Midi_Callbacks &&) = delete;
|
||||
Incoming_Midi_Callbacks(Incoming_Midi_Callbacks const&) = delete;
|
||||
|
||||
Incoming_Midi_Callbacks& operator=(Incoming_Midi_Callbacks &&) = delete;
|
||||
Incoming_Midi_Callbacks& operator=(Incoming_Midi_Callbacks const&) = delete;
|
||||
|
||||
void add_callbacks(midi::Connection &midi, Interpreter &interpreter)
|
||||
{
|
||||
register_callback(midi.note_on_callback, note_on, interpreter);
|
||||
register_callback(midi.note_off_callback, note_off, interpreter);
|
||||
}
|
||||
|
||||
template<typename ...T>
|
||||
void register_callback(std::function<void(T...)> &target, Value &callback, Interpreter &i)
|
||||
{
|
||||
target = [interpreter = &i, callback = &callback](T ...source_args)
|
||||
{
|
||||
std::cout << "hello from callback!" << std::endl;
|
||||
if (callback->type != Value::Type::Nil) {
|
||||
auto result = (*callback)(*interpreter, { Value::from(Number(source_args))... });
|
||||
// We discard this since callback is running in another thread.
|
||||
(void) result;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
void Interpreter::register_callbacks()
|
||||
{
|
||||
assert(callbacks != nullptr, "Interpreter constructor should initialize this field");
|
||||
callbacks->add_callbacks(*midi_connection, *this);
|
||||
}
|
||||
|
||||
/// Intrinsic implementation primitive providing a short way to check if arguments match required type signature
|
||||
static inline bool typecheck(std::vector<Value> const& args, auto const& ...expected_types)
|
||||
{
|
||||
@ -340,6 +380,9 @@ Interpreter::Interpreter()
|
||||
assert(!bool(Env::global), "Only one instance of interpreter can be at one time");
|
||||
env = Env::global = Env::make();
|
||||
}
|
||||
{ // MIDI input callbacks initialization
|
||||
callbacks = std::make_unique<Interpreter::Incoming_Midi_Callbacks>();
|
||||
}
|
||||
{ // Global default functions initialization
|
||||
auto &global = *Env::global;
|
||||
|
||||
|
22
src/main.cc
22
src/main.cc
@ -4,6 +4,7 @@
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <span>
|
||||
#include <thread>
|
||||
|
||||
#include <musique.hh>
|
||||
#include <midi.hh>
|
||||
@ -79,10 +80,12 @@ struct Runner
|
||||
|
||||
midi::ALSA alsa;
|
||||
Interpreter interpreter;
|
||||
std::thread midi_input_event_loop;
|
||||
|
||||
/// Setup interpreter and midi connection with given port
|
||||
Runner(std::string input_port, std::string output_port)
|
||||
: alsa("musique")
|
||||
, interpreter{}
|
||||
{
|
||||
assert(the == nullptr, "Only one instance of runner is supported");
|
||||
the = this;
|
||||
@ -92,8 +95,18 @@ struct Runner
|
||||
alsa.init_sequencer();
|
||||
interpreter.midi_connection = &alsa;
|
||||
}
|
||||
if (output_port.size()) alsa.connect_output(output_port);
|
||||
if (input_port.size()) alsa.connect_input(input_port);
|
||||
if (output_port.size()) {
|
||||
std::cout << "Connected MIDI output to port " << output_port << ". Ready to play!" << std::endl;
|
||||
alsa.connect_output(output_port);
|
||||
}
|
||||
if (input_port.size()) {
|
||||
std::cout << "Connected MIDI input to port " << input_port << ". Ready for incoming messages!" << std::endl;
|
||||
alsa.connect_input(input_port);
|
||||
}
|
||||
if (alsa_go) {
|
||||
interpreter.register_callbacks();
|
||||
midi_input_event_loop = std::thread([this] { handle_midi_event_loop(); });
|
||||
}
|
||||
|
||||
Env::global->force_define("say", +[](Interpreter&, std::vector<Value> args) -> Result<Value> {
|
||||
for (auto it = args.begin(); it != args.end(); ++it) {
|
||||
@ -111,6 +124,11 @@ struct Runner
|
||||
Runner& operator=(Runner const&) = delete;
|
||||
Runner& operator=(Runner &&) = delete;
|
||||
|
||||
void handle_midi_event_loop()
|
||||
{
|
||||
alsa.input_event_loop();
|
||||
}
|
||||
|
||||
/// Run given source
|
||||
Result<void> run(std::string_view source, std::string_view filename, bool output = false)
|
||||
{
|
||||
|
@ -920,6 +920,10 @@ struct Interpreter
|
||||
/// There is always at least one context
|
||||
std::vector<Context> context_stack;
|
||||
|
||||
struct Incoming_Midi_Callbacks;
|
||||
std::unique_ptr<Incoming_Midi_Callbacks> callbacks;
|
||||
void register_callbacks();
|
||||
|
||||
Interpreter();
|
||||
~Interpreter();
|
||||
Interpreter(Interpreter const&) = delete;
|
||||
|
Loading…
Reference in New Issue
Block a user