Open noteflakes opened 9 years ago
As preparation for this feature, and also for being able to do vertical editing in interactive mode (see #50), we need to have a context. We can use the opts object as context. Since every file is parsed separately, and usually represents a separate part, we can safely do the time calculation in the parsing stage, at least for 99% of use cases. The other 1% could be dealt with by preserving the current time in the opts object passed to LydownParser.parse
.
Actually, trying to assign times to each event in a lydown stream is too problematic. There's problem with time signatures changed in mid stream, duration macros, named macros, and a global stream with measure indicators and time signature changes, that would cause an implementation based on the parsing stage to be a total chaos.
Therefore, we are left with the option of doing the time calculation during the translation stage, which creates the actual lilypond code. What we can do is instead of assigning a time for each event, rather create a hash mapping musical time to a line, column tuple.
We add a MusicalTime class:
class MusicalTime
attr_reader :measure, :time
def initialize(measure, time)
@measure, @time = measure, time
end
end
The way the algorithm works, it assigns the next time value to the first duration/note/rest/silence event that it finds.
A simple example:
4c8eg2c
Should lead to the following map (where time is expressed in Rational values):
(1 0) => [1,2] # c
(1 1/4) => [1,4] # e
(1 3/8) => [1,5] # g
(1 2/4) => [1,7] # c
An example with a duration macro:
{8_6__}cdedef2e
And the time map:
(1 0) => [1,8] # c
(1 1/8) => [1,9] # d
(1 3/16) => [1,10] # e
(1 2/8) => [1,11] # d
(1 3/8) => [1,12] # e
(1 7/16) => [1,13] # f
(1 2/4) => [1,15] # e
An example with multiple lines:
4c8d6e3fg4ab
8.c6d8.e6f2g
The time map:
(1 0) => [1,2] # 4c
(1 1/4) => [1,4] # 8d
(1 3/8) => [1,6] # 6e
(1 7/16) => [1,8] # 3f
(1 15/32) => [1,9] # 3g
(1 1/2) => [1,11] # 4a
(1 3/4) => [1,12] # 4b
(2 0) => [2,3] # 8.c
...
Measure number indicators are used signify the absolute position of anything that comes after the indicator in terms of the referenced measure. Lydown should automatically add rests (for actual parts) or silences (for the global context - see #37).
An example:
The
(end)
measure indicator requires lydown to go over the other parts in the same movement and to calculate the maximum number of measures.