Transposition with Enharmonic Changes (Part 3)

Part 1 of this tutorial displayed a case of complicated transposition of a song that needed enharmonic change in order to avoid running into impossible key signatures.
Part 2 improved the solution and made it somewhat more generic by some refactoring of the file.

This time we will proceed one major step further and create a solution that allows to have an arbitrary number of different versions of the song side by side. This makes use of a technique I would call “adaptor class files”.

Let’s begin our exploration by splitting the example from the previous lecture into individual files:

% music.ily

beginning = \relative c'' {
  \key as \major
  % music 1
}
middlesection = \relative gis'{
  \key e \major
  % music 2
}
end = \relative c'' {
  \key as \major
  % music 3
}
% enharmonic-change.ily

middlesection = \transpose e fes \middlesection
% assemble-parts.ily

music = {
  \beginning
  \middlesection
  \end
}
% score.ily

\score {
  \new Staff \music
  \layout {}
}

You’ll notice that we used .ily file extension, which by convention indicates included files that aren’t meant to be compiled directly. For that purpose we create a new file:

% widmung-g.ly

\include "music.ily"
\include "enharmonic-change.ily"
\include "assemble-parts.ily"
\transpose as g \music
\include "score.ily"

First we include the music definitions, then apply the enharmonic change to the middle section and assemble the three parts. Before finally using the \score block we apply the overall transposition to g major.

The task we wanted to solve was to add another transposition to g flat major. You may recall from part 2 that we don’t need the enharmonic change for that destination key. Therefore we can write another file for the new transposition that simply omits the enharmonic change:

% widmung-ges.ly

\include "music.ily"
\include "assemble-parts.ily"
\transpose as ges \music
\include "score.ily"

And, by the way, to print the song in the original key you can use yet another file that does not even apply any transposition. For any further transpositions you can simply determine if they need enharmonic change or not and write an appropriate file. This way you have several include files that are used by the compilable .ly files, one for each desired destination key.

Remember the question from part 1, about a transposition to a major? Let’s see: beginning and end are transposed from a flat to a, no problem. The middle section would be transposed from e to e sharp major, ouch! So if we apply the above enharmonic change the middle section will first be transposed to f flat and then to f major, and everybody’s happy :-)

Of course all used examples are slightly simplified because in real scores you will usually have more than one layer of music (in a song you’ll have at least one layer for the vocal line and two for the piano hands, and often more than one layer for each hand). And you may have to split up the music in more than just three segments, so your actual files will be more complex than the ones from this tutorial – but this is exactly why it’s useful to have several files and include them. The repetitive tasks of enharmonically changing several variables or assembling parts are nicely stuffed away in their respective include files while your compilable main files remain as clean and concise as the shown examples.

In the fourth and last part of this tutorial I will finally show you a few special cases and pitfalls you may run into when transposing complicated music.

10 thoughts on “Transposition with Enharmonic Changes (Part 3)

  1. Kristóf Marussy

    While this might be for a bit more advanced users that those who this tutorial targets, I think it is important to note that this kind of “late-binding” (i.e. allowing changes in a variable to propagate to other variables) can be easily achieved by using arity-0 music functions instead of plain variables, such as the following Gist illustrates: https://gist.github.com/kris7topher/6038247

    This approach has the benefit that there is no need for an additional file, thus logically related code can be kept in the same file. One could also create a music function that takes a boolean parameter and enharmonically transposes the section of music with problematic key signature at will. This has the added benefit that enharmonic transpositions do not affect “raw” music variables at all.

    Reply
    1. Kristóf Marussy

      Unfortunately, there is no edit feature here…

      The code I posted was slightly incorrect, and had little generality. I created a new revision at GitHub (same link), with a Scheme function (i.e. LilyPond function that returns Scheme code). You can pass any quoted music expression between #’#{ and #} to it, and it returns an arity-0 music function. The returned music function, when called, evaluates the music expression in the current parser context, which effectively late-binds any referenced variables. While the calling synax

      music = \late #'#{ ... #}

      is slightly arcane, this provides a simple interface for defferred parsing and evaluation.

      Sidenote: It is a shame LilyPond does not have “music macros” or “scheme macros” that could take music expressions as strings (or even better, as parse trees). I guess it would overcomplicate music functions, but stil…

      Reply
      1. Kristóf Marussy

        Oh well, seems like I managed to do this in a needlessly complex way. There is no need to ly:clone-parser to parse the expression, the parser instance supplied by the quoted music expression will do just as fine (see updated Gist). :-)

        The basic idea is that pieces of LilyPond code embedded into Scheme code (i.e. #( … #{ … #} ) stuff) are just syntactic sugar for invoking the parser to parse a string of LilyPond code, plus some convenience parameters like current source file and line number. Once LilyPond code is parsed, a music expression is returned: variables are substituted and referenced music functions and embedded Scheme code are invoked.

        Of course, the call to the LilyPond parser with the string of code between #{ … #} is just plain Scheme code. Thus ‘#{ … #} is a quoted Scheme list (homoiconicity ftw!), which can be later (eval)’d. In simpler terms, #{ … #} and (eval ‘#{ … #} (interaction-environment)) are exactly the same. The trick is that ‘#{ … #} can be assigned to a variable or passed as a music/scheme function parameter (if we assigned or passed #{ … #}, it would first get parsed into a music expression).

        By capturing a quoted music expression, we can defer variable substitution until the time the variables have the values we want. (More or less. Embedded music expressions may refer to closures so that music expressions inside music functions can access the music function’s parameters. Although one could overwrite even the closure, if that is needed.) Note that LilyPond’s grammar is heavily context-dependent: it is impossible to create a “parse tree” for a piece of code describing music expression without turning it into a music expression (i.e. the Scheme data structure that hold music properties), because music/scheme functions may do all sorts of crazy things. Therefore, to defer variable substitution, we have to defer parsing. (One could do lexing, I guess. But I couldn’t find any way in the Internals Reference to invoke the lexer directly.)

        The rest of \late is just the invocation of the macro (define-music-function). If \late was a Scheme macro, this whould be easier, but LilyPond has no support for music macros. (Due to the context-dependence of the grammar, they would be incredibly hard to support. Although I haven’t looked at the revant source files of LilyPond, so I might be entierly mistaken.) The return value is a music function (a Scheme object), that can be assigned to a variable just like music expressions can.

        Reply
        1. Janek Warchoł

          Wow! This is very impressive. Took me some time to digest, and i probably still hadn’t understood everything, but i really appreciate it :) Might be enormously useful.

          Actually, your comment is a very good material for a post, Kristóf! If you’d like to write one, feel invited :) especially if you have some example where using this function would be the only reasonable way of achieving something :)

          Reply
        2. Urs Liska

          Hey, sorry but I haven’t found a reasonable moment of time to dig into this. But I second Janek’s proposal to pour that material into a regular blog post.

          Reply
  2. Kristóf Marussy

    I don’t really know whether this can be reasonably explained to non-programmers in the context and length limitations of blog post. I started writing a tutorial-like thing (like the Creating Songbooks tutorial), which makes heavy use of the scheme-sandbox show stuff about how music expressions work in LilyPond. Although that is not the part I am most familiar with (I was hacking around the MIDI output part, especially DynamicsPerformer and StaffPerformer some time ago. While those patches are not yet mature enough that I submit them to the mailing list, I did gain some familiarity with LilyPond’s source), I think I could write something reasonably and digestible. Although, to tell the truth, writing Scheme did have a pronounced effect on my technical writing skills (especially throwing aroud parethetical expression (even recursively (like this)) for no good reason). :-)

    I am planning to publish the tutorial or at least a rough draft as soon as I find time to finish it, in either pdf or html format, as well as the emacs org-mode source files of it (under something line CC-BY 3.0).

    Reply
    1. Urs Liska

      We’d be happy to publish a tutorial here, be it in the form of a blog post or in the form of a pdf tutorial. It is of course also ‘valid’ to write something that only programmers will understand. Although writing something of that complexity in a way that even non-programmers will benefit from would be awesome :-) .

      Reply
  3. Pingback: 7 Transpose Music Blogs - Pop Revelations

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>