par
improvement: allow actions like octave changes inside
This is implemented with default action idea. During evaluation of expresions sequence all but return expressions is passed to default_action. Par sets default action to `action_play` which plays given value if it's musical value.
This commit is contained in:
parent
2452b95a90
commit
5c47b7b808
@ -5,6 +5,7 @@
|
||||
#include <concepts>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <ostream>
|
||||
@ -956,6 +957,8 @@ struct Interpreter
|
||||
/// There is always at least one context
|
||||
std::vector<Context> context_stack;
|
||||
|
||||
std::function<Result<void>(Interpreter&, Value)> default_action;
|
||||
|
||||
struct Incoming_Midi_Callbacks;
|
||||
std::unique_ptr<Incoming_Midi_Callbacks> callbacks;
|
||||
void register_callbacks();
|
||||
|
@ -62,7 +62,7 @@ static inline Result<void> create_chord(std::vector<Note> &chord, Interpreter &i
|
||||
}
|
||||
|
||||
template<Iterable T>
|
||||
static inline Result<void> play_notes(Interpreter &interpreter, T args)
|
||||
static inline Result<void> builtin_play(Interpreter &interpreter, T args)
|
||||
{
|
||||
for (auto i = 0u; i < args.size(); ++i) {
|
||||
Value arg;
|
||||
@ -75,7 +75,7 @@ static inline Result<void> play_notes(Interpreter &interpreter, T args)
|
||||
switch (arg.type) {
|
||||
case Value::Type::Array:
|
||||
case Value::Type::Block:
|
||||
Try(play_notes(interpreter, std::move(arg)));
|
||||
Try(builtin_play(interpreter, std::move(arg)));
|
||||
break;
|
||||
|
||||
case Value::Type::Music:
|
||||
@ -238,6 +238,17 @@ static auto builtin_program_change(Interpreter &i, std::vector<Value> args) -> R
|
||||
};
|
||||
}
|
||||
|
||||
static Result<void> action_play(Interpreter &i, Value v)
|
||||
{
|
||||
if (v.type == Value::Type::Music) {
|
||||
Try(i.play(std::move(v).chord));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
/// Plays sequentialy notes walking into arrays and evaluation blocks
|
||||
///
|
||||
/// @invariant default_action is play one
|
||||
static inline Result<void> sequential_play(Interpreter &i, Value v)
|
||||
{
|
||||
switch (v.type) {
|
||||
@ -246,7 +257,7 @@ static inline Result<void> sequential_play(Interpreter &i, Value v)
|
||||
Try(sequential_play(i, std::move(el)));
|
||||
|
||||
break; case Value::Type::Block:
|
||||
unimplemented(); // waits for eval support
|
||||
Try(sequential_play(i, Try(i.eval(std::move(v).blk.body))));
|
||||
|
||||
break; case Value::Type::Music:
|
||||
return i.play(v.chord);
|
||||
@ -270,16 +281,21 @@ static Result<Value> builtin_par(Interpreter &i, std::vector<Value> args) {
|
||||
// Create chord that should sustain during playing of all other notes
|
||||
auto &ctx = i.context_stack.back();
|
||||
auto chord = std::move(args.front()).chord;
|
||||
std::transform(chord.notes.begin(), chord.notes.end(), chord.notes.begin(), [&](Note note) { return ctx.fill(note); });
|
||||
std::for_each(chord.notes.begin(), chord.notes.end(), [&](Note ¬e) { note = ctx.fill(note); });
|
||||
|
||||
for (auto const& note : chord.notes) {
|
||||
i.midi_connection->send_note_on(0, *note.into_midi_note(), 127);
|
||||
}
|
||||
|
||||
auto previous_action = std::exchange(i.default_action, action_play);
|
||||
i.context_stack.push_back(i.context_stack.back());
|
||||
|
||||
auto const chord_off = [&] {
|
||||
for (auto const& note : chord.notes) {
|
||||
i.midi_connection->send_note_off(0, *note.into_midi_note(), 127);
|
||||
}
|
||||
i.default_action = std::move(previous_action);
|
||||
i.context_stack.pop_back();
|
||||
};
|
||||
|
||||
for (auto it = std::next(args.begin()); it != args.end(); ++it) {
|
||||
@ -368,7 +384,7 @@ error:
|
||||
});
|
||||
|
||||
global.force_define("play", +[](Interpreter &i, std::vector<Value> args) -> Result<Value> {
|
||||
Try(play_notes(i, std::move(args)));
|
||||
Try(builtin_play(i, std::move(args)));
|
||||
return Value{};
|
||||
});
|
||||
|
||||
|
@ -142,8 +142,12 @@ Result<Value> Interpreter::eval(Ast &&ast)
|
||||
case Ast::Type::Sequence:
|
||||
{
|
||||
Value v;
|
||||
for (auto &a : ast.arguments)
|
||||
bool first = true;
|
||||
for (auto &a : ast.arguments) {
|
||||
if (!first && default_action) Try(default_action(*this, v));
|
||||
v = Try(eval(std::move(a)));
|
||||
first = false;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user