[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Scheme function to print out active Voice context during interpretat

From: Trevor Bača
Subject: Re: Scheme function to print out active Voice context during interpretation?
Date: Mon, 15 Dec 2008 16:12:25 -0600

On Mon, Dec 15, 2008 at 2:09 PM, Han-Wen Nienhuys <address@hidden> wrote:
On Mon, Dec 15, 2008 at 5:25 PM, Carl D. Sorensen <address@hidden> wrote:
> On 12/15/08 7:18 AM, "Han-Wen Nienhuys" <address@hidden> wrote:
>> Try not to form mental models.  Use the source instead.
> Unfortunately, not very many of us understand the source completely, and so
> we need mental models to work in LilyPond.  Of course, our mental models
> will be incorrect in some detail, and we'll need to revise them from time to
> time.

sure, but if you spend a lot of time and effort on theorizing (like
Trevor did), you might as well invest that time & effort into looking
at the source code itself.

I think both are good: wanton speculation taken together with digging through source.


I've been digging through source this morning ... and I'm understanding much better ... but still unable to resolve at least one example, which I've included at the end of this message.

What I've found so far:

* There are 22 files with Music_iterator being the base class from which the others all directly (or, more usually, indirectly) inherit. (Simple_music_iterator, Music_wrapper_iterator and Sequential_iterator are all popular choices to derive from, too, but all three inherit from Music_iterator at base.) Concrete iterators exist to iterate over regular stuff like EventChord and and 'simple music' (which parser.yy makes me think means basically notes and rests). Iterators also exist to iterate over more complex music expressions like grace music, time-scaled music, voltas, and music expressions passed to the \unfold command. My understanding of this flock of iterators available in the C++ source is as a type of realization of the visitor pattern that separates traversal from other activities like calculation and modification.

* Additionally, both the comments at the head of music-iterator.hh and Erik's thesis make it clear that the object over which the different iterators iterate is a (conceptual) queue of music events *that all happen at the same moment*. That is, when it comes time to iterate, the first thing that happens is that the entire context tree (starting from the Global context and proceeding all the way to bottom-level voice contexts) are *prepared* for Moment 0; then iterators iterate over all events that happen at Moment 0 *no matter at which level of the context tree those different events occur*. This helps because I was assuming (wrongly) earlier that iteration would be a depth-first search starting from the root of the _expression_ tree; if that were the case then each context would be visited before any of its children. But, in fact, section 9.4 of Erik's thesis says "One of the consequences of a OneTimeStep stream event, is that all contexts are visited in a post-order tree walk; i.e., each context is visited after all its children have been visited." I haven't been able to verify this in the code, however.

* I've also found that a pronouncement like "\new Voice { c'4 }" is actually THREE expressions. The "\new Voice" is actually a music _expression_ all by itself (of type ContextSpeccedMusic). There is a Context_specced_music_iterator defined in an eponymous .cc file and inheriting from Music_wrapper_iterator. The purpose of the Context_specced_music_iterator is to descend to the one (and only one) child that each ContextSpeccedMusic like "\new Voice" music have: something like Sequential is the usual option. So the parser (which I only understand vaguely) decomposes "\new Voice { c'4 }" into three expressions with "\new Voice" parsed as ContextSpeccedMusic, with "{ }" parsed as Sequential, with "c'4" parsed as EventChord (I think). Further, the parser builds the resulting music _expression_ such that ContextSpeccedMusic is the parent of Sequential which is, in turn, the parent of EventChord.

* Also, all parsing is done before any iteration is done.

* OK, so based on this understanding, can somebody please correct my understanding of the parsing (not the iteration, just the parsing) of the following _expression_ (which is the same as my original example #2):

    \new Voice {
      c'8 c'8 c'8 c'8
    d'8 d'8 d'8 d'8

If I'm understanding how the parser works, then what should result here is a music _expression_ that looks like this:

               \new Score
               \new Staff
               \new Voice
    \new Voice, d'8, d'8, d'8, d'8
c'8, c'8, c'8, c'8

If I'm counting correctly, that's 15 total nodes in the _expression_ tree. Eight atomic nodes and seven internal nodes. The Global, \new Score, \new Staff and the first \new Voice are all created implicitly.

I know that the next part in the process is iteration. But I want to stop and check my understanding here: am I understanding the output of the parser correctly at this point?


Trevor Bača

reply via email to

[Prev in Thread] Current Thread [Next in Thread]