diff --git a/examples/ode-to-joy.mq b/examples/ode-to-joy.mq index 8ba4d56..e356450 100644 --- a/examples/ode-to-joy.mq +++ b/examples/ode-to-joy.mq @@ -2,12 +2,12 @@ var C = chord (c 3 1) (g 3 1) (c 4 1); var G = chord (g 3 1) (d 4 1) (g 4 1); oct 5; -par (C) e e f g; -par (G) g f e d; -par (C) c c d e; -par (G) (e 5 (3/8)) (d 5 (1/8)) (d 5 (1/2)); -par (C) e e f g; -par (G) g f e d; -par (C) c c d e; -par (G) (d 5 (1/2)) (c 5 (1/8)); -par (C) (c 5 1); +par C e e f g; +par G g f e d; +par C c c d e; +par G (e 5 (3/8) d 5 (1/8) d 5 (1/2)); +par C e e f g; +par G g f e d; +par C c c d e; +par G (d 5 (1/2) c 5 (1/8)); +par C (c 5 1); diff --git a/include/musique.hh b/include/musique.hh index 1f975cc..a62bba7 100644 --- a/include/musique.hh +++ b/include/musique.hh @@ -811,6 +811,9 @@ struct Chord static Chord from(std::string_view source); bool operator==(Chord const&) const = default; + + /// Fill length and octave or sequence multiple chords + Result operator()(Interpreter &i, std::vector args); }; std::ostream& operator<<(std::ostream& os, Chord const& chord); diff --git a/src/value.cc b/src/value.cc index 03c31e0..44a1d1d 100644 --- a/src/value.cc +++ b/src/value.cc @@ -161,22 +161,7 @@ Result Value::operator()(Interpreter &i, std::vector args) switch (type) { case Type::Intrinsic: return intr(i, std::move(args)); case Type::Block: return blk(i, std::move(args)); - case Type::Music: - { - assert(args.size() == 1 || args.size() == 2, "music value can be called only in form note []"); // TODO(assert) - assert(args[0].type == Type::Number, "expected octave to be a number"); // TODO(assert) - - assert(args.size() == 2 ? args[1].type == Type::Number : true, "expected length to be a number"); // TODO(assert) - for (auto ¬e : chord.notes) { - note.octave = args[0].n.as_int(); - if (args.size() == 2) { - note.length = args[1].n; - } - note.simplify_inplace(); - } - - return *this; - } + case Type::Music: return chord(i, std::move(args)); default: return Error { .details = errors::Not_Callable { .type = type_name(type) }, @@ -509,6 +494,51 @@ Chord Chord::from(std::string_view source) return chord; } +Result Chord::operator()(Interpreter&, std::vector args) +{ + std::vector array; + Chord *current = this; + enum State { + Waiting_For_Octave, + Waiting_For_Length, + Waiting_For_Note + } state = Waiting_For_Octave; + + for (auto &arg : args) { + if (arg.type == Value::Type::Number) { + switch (state) { + break; case Waiting_For_Octave: + std::for_each(current->notes.begin(), current->notes.end(), + [&arg](Note &n) { n.octave = arg.n.floor().as_int(); }); + state = Waiting_For_Length; + continue; + + break; case Waiting_For_Length: + std::for_each(current->notes.begin(), current->notes.end(), + [&arg](Note &n) { n.length = arg.n; }); + state = Waiting_For_Note; + continue; + + default: + unimplemented(); + } + } + + if (arg.type == Value::Type::Music) { + if (array.empty()) { + array.push_back(Value::from(std::move(*current))); + } + array.push_back(std::move(arg)); + current = &array.back().chord; + state = Waiting_For_Octave; + } + } + + return array.empty() + ? Value::from(*current) + : Value::from(Array{array}); +} + std::ostream& operator<<(std::ostream& os, Chord const& chord) { if (chord.notes.size() == 1) {