Integrated Set type into existing infrastructure
This commit is contained in:
parent
f19240d931
commit
948243febd
@ -9,7 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
### Added
|
||||
|
||||
- `{}` notation for concurrently executing blocks
|
||||
- `{}` notation for concurrently executing blocks and describing set of values
|
||||
- `set` data type which contains an unordered collection of unique elements
|
||||
|
||||
### Fixed
|
||||
|
||||
|
@ -5,61 +5,63 @@ WIP implemntation
|
||||
oct 5, bpm 72, len (1/16),
|
||||
|
||||
subsection1 := (
|
||||
sim (a4 en) (a2 e3 a3),
|
||||
play (oct 4, c e a),
|
||||
{ a4 en, a2 e3 a3 },
|
||||
oct 4, c e a,
|
||||
|
||||
sim (b4 en) (e2 e3 g#3),
|
||||
play (oct 4, e g# b),
|
||||
{ b4 en, e2 e3 g#3 },
|
||||
oct 4, e g# b,
|
||||
|
||||
sim (c5 en) (a2 e3 a3),
|
||||
play (e4 e5 d#5),
|
||||
{ c5 en, a2 e3 a3 },
|
||||
e4 e5 d#5,
|
||||
|
||||
play e d# e b4 d c,
|
||||
oct 5, e d# e b4 d c,
|
||||
|
||||
sim (a4 en) (a2 e3 a3),
|
||||
play c4 e4 a4,
|
||||
{ a4 en, a2 e3 a3 },
|
||||
c4 e4 a4,
|
||||
|
||||
sim (b4 en) (e2 e3 g#3),
|
||||
play d4 c5 b4,
|
||||
{ b4 en, e2 e3 g#3 },
|
||||
d4 c5 b4,
|
||||
),
|
||||
|
||||
section1 := ( n |
|
||||
play e d#,
|
||||
play e d# e b4 d c,
|
||||
e d#,
|
||||
e d# e b4 d c,
|
||||
|
||||
call subsection1,
|
||||
|
||||
if (n == 1)
|
||||
( sim (a4 qn) (a2 e3 a3) )
|
||||
( sim (a4 en) (a2 e3 a3)
|
||||
, play b4 c5 d5
|
||||
{ a4 qn, a2 e3 a3 }
|
||||
( { a4 en, a2 e3 a3 }
|
||||
, b4 c5 d5
|
||||
)
|
||||
),
|
||||
|
||||
section2 := ( n |
|
||||
sim (e5 den) (c3 g3 c4),
|
||||
play g4 f e,
|
||||
{ e5 den, c3 g3 c4 },
|
||||
g4 f e,
|
||||
|
||||
sim (d 5 den) (g2 g3 b4),
|
||||
play f4 e d,
|
||||
{ d5 den, g2 g3 b4 },
|
||||
f4 e d,
|
||||
|
||||
sim (c5 den) (a2 e3 a3),
|
||||
play e4 d c,
|
||||
{ c5 den, a2 e3 a3 },
|
||||
e4 d c,
|
||||
|
||||
sim (b4 en) (e2 e3 e4),
|
||||
play (e4 e5 e4 e4 e5 e6 d#5 e5 d#5 e5 en),
|
||||
{ b4 en, e2 e3 e4 },
|
||||
e4 e5 e4 e4 e5 e6 d#5 e5 d#5 e5 en,
|
||||
|
||||
play d# e d# e d#,
|
||||
play e d# e b4 d c,
|
||||
d# e d# e d#,
|
||||
e d# e b4 d c,
|
||||
|
||||
call subsection1,
|
||||
|
||||
if (n == 1)
|
||||
( sim (a4 en) (a2 e3 a3)
|
||||
( { a4 en, a2 e3 a3 }
|
||||
, play (b4 c5 d5)
|
||||
)
|
||||
),
|
||||
|
||||
play (
|
||||
section1 1,
|
||||
section1 2,
|
||||
section2 1,
|
||||
)
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define MUSIQUE_COMMON_HH
|
||||
|
||||
#include <cstdint>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
@ -62,4 +63,6 @@ concept Three_Way_Comparable = requires (T const& lhs, T const& rhs) {
|
||||
{ lhs <=> rhs };
|
||||
};
|
||||
|
||||
extern std::mutex stdio_mutex;
|
||||
|
||||
#endif
|
||||
|
@ -49,20 +49,25 @@ std::optional<Error> Value_Formatter::format(std::ostream& os, Interpreter &inte
|
||||
return {};
|
||||
},
|
||||
[&](Block const& block) -> std::optional<Error> {
|
||||
if (block.body.arguments.front().type == Ast::Type::Concurrent)
|
||||
unimplemented("Nice printing of concurrent blocks is not implemented yet");
|
||||
|
||||
if (block.is_collection()) {
|
||||
os << '(';
|
||||
auto const [open, close] = block.body.type == Ast::Type::Concurrent
|
||||
? std::pair { '{', '}' }
|
||||
: std::pair { '(', ')' };
|
||||
|
||||
os << open;
|
||||
for (auto i = 0u; i < block.size(); ++i) {
|
||||
if (i > 0) {
|
||||
os << ", ";
|
||||
}
|
||||
Try(nest(Inside_Block).format(os, interpreter, Try(block.index(interpreter, i))));
|
||||
}
|
||||
os << ')';
|
||||
os << close;
|
||||
} else {
|
||||
os << "<block>";
|
||||
if (block.body.type == Ast::Type::Concurrent) {
|
||||
os << "<concurrent block>";
|
||||
} else {
|
||||
os << "<sequential block>";
|
||||
}
|
||||
}
|
||||
return {};
|
||||
},
|
||||
|
@ -1,7 +1,8 @@
|
||||
#include <musique/algo.hh>
|
||||
#include <musique/interpreter/env.hh>
|
||||
#include <musique/guard.hh>
|
||||
#include <musique/interpreter/env.hh>
|
||||
#include <musique/interpreter/interpreter.hh>
|
||||
#include <musique/scope_exit.hh>
|
||||
#include <musique/try.hh>
|
||||
|
||||
#include <chrono>
|
||||
@ -12,6 +13,7 @@
|
||||
#include <random>
|
||||
#include <thread>
|
||||
#include <unordered_set>
|
||||
#include <future>
|
||||
|
||||
/// Check if type has index method
|
||||
template<typename T>
|
||||
@ -254,6 +256,19 @@ static inline std::optional<Error> sequential_play(Interpreter &interpreter, Val
|
||||
}
|
||||
else if (auto chord = get_if<Chord>(v)) {
|
||||
return interpreter.play(*chord);
|
||||
} else if (auto set = get_if<Set>(v)) {
|
||||
std::vector<std::future<std::optional<Error>>> futures;
|
||||
for (auto&& value : set->elements) {
|
||||
futures.push_back(std::async(std::launch::async,
|
||||
[interpreter = interpreter.clone(), value = std::move(value)]() mutable {
|
||||
return sequential_play(interpreter, std::move(value));
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
for (auto &fut : futures) {
|
||||
Try(fut.get());
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
@ -267,27 +282,25 @@ static std::optional<Error> action_play(Interpreter &interpreter, Value v)
|
||||
}
|
||||
|
||||
/// Play notes
|
||||
template<With_Index_Operator Container = std::vector<Value>>
|
||||
static inline Result<Value> builtin_play(Interpreter &interpreter, Container args)
|
||||
static inline Result<Value> builtin_play(Interpreter &interpreter, std::span<Ast> args)
|
||||
{
|
||||
Try(ensure_midi_connection_available(interpreter, "play"));
|
||||
auto const previous_action = std::exchange(interpreter.default_action, action_play);
|
||||
auto const previous_context = std::exchange(interpreter.current_context,
|
||||
std::make_shared<Context>(*interpreter.current_context));
|
||||
|
||||
auto const finally = [&] {
|
||||
Scope_Exit {
|
||||
interpreter.default_action = std::move(previous_action);
|
||||
interpreter.current_context = previous_context;
|
||||
};
|
||||
|
||||
for (auto &el : args) {
|
||||
if (std::optional<Error> error = sequential_play(interpreter, std::move(el))) {
|
||||
finally();
|
||||
for (auto &node : args) {
|
||||
auto value = Try(interpreter.eval((Ast)node));
|
||||
if (std::optional<Error> error = sequential_play(interpreter, std::move(value))) {
|
||||
return *std::move(error);
|
||||
}
|
||||
}
|
||||
|
||||
finally();
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -316,14 +329,15 @@ static Result<Value> builtin_par(Interpreter &interpreter, std::vector<Value> ar
|
||||
}
|
||||
}
|
||||
|
||||
auto result = builtin_play(interpreter, std::span(args).subspan(1));
|
||||
unimplemented();
|
||||
// auto result = builtin_play(interpreter, std::span(args).subspan(1));
|
||||
|
||||
for (auto const& note : chord->notes) {
|
||||
if (note.base) {
|
||||
interpreter.midi_connection->send_note_off(0, *note.into_midi_note(), 127);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
// for (auto const& note : chord->notes) {
|
||||
// if (note.base) {
|
||||
// interpreter.midi_connection->send_note_off(0, *note.into_midi_note(), 127);
|
||||
// }
|
||||
// }
|
||||
// return result;
|
||||
}
|
||||
|
||||
/// Plays each argument simultaneously
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <musique/interpreter/env.hh>
|
||||
#include <musique/interpreter/interpreter.hh>
|
||||
#include <musique/options.hh>
|
||||
#include <musique/try.hh>
|
||||
|
||||
#include <chrono>
|
||||
@ -97,14 +98,14 @@ static Result<Value> eval_concurrent(Interpreter &interpreter, Ast &&ast)
|
||||
}));
|
||||
}
|
||||
|
||||
std::vector<Value> results;
|
||||
Set set;
|
||||
for (auto& future : futures) {
|
||||
if (error) {
|
||||
return *error;
|
||||
}
|
||||
results.push_back(future.get());
|
||||
set.elements.insert(future.get());
|
||||
}
|
||||
return results;
|
||||
return set;
|
||||
}
|
||||
|
||||
Result<Value> Interpreter::eval(Ast &&ast)
|
||||
@ -288,6 +289,11 @@ void Interpreter::leave_scope()
|
||||
|
||||
std::optional<Error> Interpreter::play(Chord chord)
|
||||
{
|
||||
if (global_options::dump_play_actions) {
|
||||
std::lock_guard guard{stdio_mutex};
|
||||
std::cerr << "[DEBUG] Interpreter::play " << chord << std::endl;
|
||||
}
|
||||
|
||||
Try(ensure_midi_connection_available(*this, "play"));
|
||||
auto &ctx = *current_context;
|
||||
|
||||
|
@ -35,15 +35,16 @@ private:
|
||||
Interpreter(Clone);
|
||||
public:
|
||||
|
||||
/// Explicit clone method
|
||||
Interpreter clone() const;
|
||||
|
||||
/// Try to evaluate given program tree
|
||||
Result<Value> eval(Ast &&ast);
|
||||
|
||||
// Enter scope by changing current environment
|
||||
/// Enter scope by changing current environment
|
||||
void enter_scope();
|
||||
|
||||
// Leave scope by changing current environment
|
||||
/// Leave scope by changing current environment
|
||||
void leave_scope();
|
||||
|
||||
/// Play note resolving any missing parameters with context via `midi_connection` member.
|
||||
|
@ -37,6 +37,8 @@ static bool ast_only_mode = false;
|
||||
static bool enable_repl = false;
|
||||
static unsigned repl_line_number = 1;
|
||||
|
||||
std::mutex stdio_mutex;
|
||||
|
||||
#define Ignore(Call) do { auto const ignore_ ## __LINE__ = (Call); (void) ignore_ ## __LINE__; } while(0)
|
||||
|
||||
/// Pop string from front of an array
|
||||
@ -190,7 +192,6 @@ struct Runner
|
||||
}
|
||||
|
||||
Env::global->force_define("print", +[](Interpreter &interpreter, std::vector<Value> args) -> Result<Value> {
|
||||
static std::mutex stdio_mutex;
|
||||
for (auto it = args.begin(); it != args.end(); ++it) {
|
||||
{
|
||||
auto result = Try(format(interpreter, *it));
|
||||
|
@ -4,6 +4,11 @@
|
||||
#include <musique/value/block.hh>
|
||||
#include <musique/value/value.hh>
|
||||
|
||||
inline bool is_ast_collection(Ast::Type type)
|
||||
{
|
||||
return type == Ast::Type::Sequence || type == Ast::Type::Concurrent;
|
||||
}
|
||||
|
||||
/// Helper that produces error when trying to access container with too few elements for given index
|
||||
static inline std::optional<Error> guard_index(unsigned index, unsigned size)
|
||||
{
|
||||
@ -17,18 +22,18 @@ static inline std::optional<Error> guard_index(unsigned index, unsigned size)
|
||||
Result<Value> Block::index(Interpreter &i, unsigned position) const
|
||||
{
|
||||
ensure(parameters.empty(), "cannot index into block with parameters (for now)");
|
||||
if (body.type != Ast::Type::Sequence) {
|
||||
Try(guard_index(position, 1));
|
||||
return i.eval((Ast)body);
|
||||
}
|
||||
|
||||
if (is_ast_collection(body.type)) {
|
||||
Try(guard_index(position, body.arguments.size()));
|
||||
return i.eval((Ast)body.arguments[position]);
|
||||
}
|
||||
|
||||
Try(guard_index(position, 1));
|
||||
return i.eval((Ast)body);
|
||||
}
|
||||
|
||||
usize Block::size() const
|
||||
{
|
||||
return body.type == Ast::Type::Sequence ? body.arguments.size() : 1;
|
||||
return is_ast_collection(body.type) ? body.arguments.size() : 1;
|
||||
}
|
||||
|
||||
Result<Value> Block::operator()(Interpreter &i, std::vector<Value> arguments) const
|
||||
|
Loading…
Reference in New Issue
Block a user