Overhaul of chord call semantics to support easy sequencing
This commit is contained in:
parent
98a88c3acc
commit
676f41909f
@ -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);
|
||||
|
@ -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<Value> operator()(Interpreter &i, std::vector<Value> args);
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, Chord const& chord);
|
||||
|
62
src/value.cc
62
src/value.cc
@ -161,22 +161,7 @@ Result<Value> Value::operator()(Interpreter &i, std::vector<Value> 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 <octave> [<length>]"); // 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<Value> Chord::operator()(Interpreter&, std::vector<Value> args)
|
||||
{
|
||||
std::vector<Value> 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) {
|
||||
|
Loading…
Reference in New Issue
Block a user