Implemented start synchronization
This commit is contained in:
parent
99f89c2e8b
commit
8d86dde405
@ -1583,6 +1583,18 @@ static Result<Value> builtin_call(Interpreter &i, std::vector<Value> args)
|
|||||||
return callable(i, std::move(args));
|
return callable(i, std::move(args));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Result<Value> builtin_start(Interpreter &interpreter, std::span<Ast> args)
|
||||||
|
{
|
||||||
|
interpreter.starter.start();
|
||||||
|
auto result = algo::fold(args, Value{}, [&interpreter](auto const&, Ast const& ast)
|
||||||
|
-> Result<Value>
|
||||||
|
{
|
||||||
|
return Try(interpreter.eval((Ast)ast));
|
||||||
|
});
|
||||||
|
interpreter.starter.stop();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void Interpreter::register_builtin_functions()
|
void Interpreter::register_builtin_functions()
|
||||||
{
|
{
|
||||||
auto &global = *Env::global;
|
auto &global = *Env::global;
|
||||||
@ -1627,6 +1639,7 @@ void Interpreter::register_builtin_functions()
|
|||||||
global.force_define("shuffle", builtin_shuffle);
|
global.force_define("shuffle", builtin_shuffle);
|
||||||
global.force_define("sim", builtin_sim);
|
global.force_define("sim", builtin_sim);
|
||||||
global.force_define("sort", builtin_sort);
|
global.force_define("sort", builtin_sort);
|
||||||
|
global.force_define("start", builtin_start);
|
||||||
global.force_define("try", builtin_try);
|
global.force_define("try", builtin_try);
|
||||||
global.force_define("typeof", builtin_typeof);
|
global.force_define("typeof", builtin_typeof);
|
||||||
global.force_define("uniq", builtin_uniq);
|
global.force_define("uniq", builtin_uniq);
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
#ifndef MUSIQUE_INTERPRETER_HH
|
#ifndef MUSIQUE_INTERPRETER_HH
|
||||||
#define MUSIQUE_INTERPRETER_HH
|
#define MUSIQUE_INTERPRETER_HH
|
||||||
|
|
||||||
#include <musique/midi/midi.hh>
|
|
||||||
#include <musique/interpreter/context.hh>
|
#include <musique/interpreter/context.hh>
|
||||||
|
#include <musique/interpreter/starter.hh>
|
||||||
|
#include <musique/midi/midi.hh>
|
||||||
#include <musique/value/value.hh>
|
#include <musique/value/value.hh>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
@ -25,6 +26,8 @@ struct Interpreter
|
|||||||
|
|
||||||
std::function<std::optional<Error>(Interpreter&, Value)> default_action;
|
std::function<std::optional<Error>(Interpreter&, Value)> default_action;
|
||||||
|
|
||||||
|
Starter starter;
|
||||||
|
|
||||||
Interpreter();
|
Interpreter();
|
||||||
~Interpreter();
|
~Interpreter();
|
||||||
Interpreter(Interpreter &&) = delete;
|
Interpreter(Interpreter &&) = delete;
|
||||||
|
81
musique/interpreter/starter.cc
Normal file
81
musique/interpreter/starter.cc
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
#include <musique/interpreter/starter.hh>
|
||||||
|
#include <ableton/Link.hpp>
|
||||||
|
#include <musique/errors.hh>
|
||||||
|
|
||||||
|
struct Starter::Implementation
|
||||||
|
{
|
||||||
|
ableton::Link link = {30};
|
||||||
|
|
||||||
|
Implementation()
|
||||||
|
{
|
||||||
|
link.enable(true);
|
||||||
|
link.enableStartStopSync(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Starter::Starter()
|
||||||
|
: impl{std::make_shared<Starter::Implementation>()}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
struct State
|
||||||
|
{
|
||||||
|
ableton::Link *link;
|
||||||
|
std::mutex mutex;
|
||||||
|
std::condition_variable condition;
|
||||||
|
};
|
||||||
|
|
||||||
|
void Starter::start()
|
||||||
|
{
|
||||||
|
ensure(impl != nullptr, "Starter wasn't initialized properly");
|
||||||
|
auto &link = impl->link;
|
||||||
|
|
||||||
|
auto const quantum = 4;
|
||||||
|
|
||||||
|
auto const sessionState = link.captureAppSessionState();
|
||||||
|
|
||||||
|
// If we already started continue
|
||||||
|
if (sessionState.isPlaying()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto state = std::make_shared<State>();
|
||||||
|
state->link = &link;
|
||||||
|
|
||||||
|
link.setStartStopCallback([state = state](bool is_playing)
|
||||||
|
{
|
||||||
|
if (is_playing) {
|
||||||
|
state->condition.notify_all();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
std::jthread starter([quantum = quantum, state = state](std::stop_token token)
|
||||||
|
{
|
||||||
|
auto counter = 0;
|
||||||
|
while (!token.stop_requested()) {
|
||||||
|
auto const time = state->link->clock().micros();
|
||||||
|
auto sessionState = state->link->captureAppSessionState();
|
||||||
|
if (counter == 2) {
|
||||||
|
sessionState.setIsPlaying(true, time);
|
||||||
|
state->link->commitAppSessionState(sessionState);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto const phase = sessionState.phaseAtTime(time, quantum);
|
||||||
|
counter += phase == 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
std::unique_lock lock(state->mutex);
|
||||||
|
state->condition.wait(lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Starter::stop()
|
||||||
|
{
|
||||||
|
ensure(impl != nullptr, "Starter wasn't initialized properly");
|
||||||
|
auto &link = impl->link;
|
||||||
|
|
||||||
|
auto const time = link.clock().micros();
|
||||||
|
auto sessionState = link.captureAppSessionState();
|
||||||
|
sessionState.setIsPlaying(false, time);
|
||||||
|
link.commitAppSessionState(sessionState);
|
||||||
|
}
|
17
musique/interpreter/starter.hh
Normal file
17
musique/interpreter/starter.hh
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#ifndef MUSIQUE_STARTER_HH
|
||||||
|
#define MUSIQUE_STARTER_HH
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
struct Starter
|
||||||
|
{
|
||||||
|
Starter();
|
||||||
|
void start();
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
struct Implementation;
|
||||||
|
std::shared_ptr<Implementation> impl;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // MUSIQUE_STARTER_HH
|
Loading…
Reference in New Issue
Block a user