lilypond-devel
[Top][All Lists]
Advanced

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

Some engraver brainstorming (was: Following voices in chords?)


From: David Kastrup
Subject: Some engraver brainstorming (was: Following voices in chords?)
Date: Sat, 08 May 2010 08:32:36 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/24.0.50 (gnu/linux)

Had a rather sleepless night after starting coding yesterday evening.
And came up with some ideas.

Idea#1 (that which I started coding on) is rather straightforward:
replace all the data structures in the glissando_engraver by deques and
work with them in the obvious manner.

Now what if I want two glissando lines from a 3-note chord to another
one.  Think think think.  So maybe make the engraver just responsible
for one glissando.  Then I write

<c g e>\glissando \glissando<d g f>

and have two lines connecting c-d and g-g.  How to do that?  Well,
simplest is by using two engravers.  One accepts notes until it is full
and leaves the rest for the next engraver, and the same thing for the
connecting notes.  Nice thing is that you can tweak both glissandi
separately.

However, two engravers is an ugly interface, and one might to need more.
So the next idea is that the engraver derives from a base class
"cloneable_engraver" and the additional engraver instances are handled
mostly automatically.

The engraver can just check if it has resources free and if it doesn't,
it says something like:

  if (line) // we already started a line
    clone.delegate(event);

delegate checks whether there is a clone already, and if so delegates
the event to it.  If not, it creates a clone.

And if we are at the end note time, we have something like
  if (!end_line) // we already ended the line
    clone.finish(...)

This is all rather half-baked and fuzzy, but the idea is to just keep
most of the existing code around and just deal with cloning when
necessary.

Now here comes the interesting thing: basically, all stuff that works
with \new Voice { \hideNotes repeat-what-we-already-did-elsewhere } is
an incredibly ugly crutch.

And hard to do, to boot.  So why not obliterate it completely?  For most
tweakable constructs, there is some motivation to use them in a separate
instance without moving everything around.

So how about the ultimate tweak: using a separate engraver?  We can't
have overlapping slurs with a single engraver, for example.  But if we
write something like

<c( address@hidden( g> <address@hidden) f)>

and use @1 with the scope of a tweak, and let it use the engraver of
subvoice 1 (a subvoice having its own engraver copies that get to handle
basic events just from its own subvoice), then it becomes possible to
use parallel slurs in one voice.

That way, the individual engravers need just to cater for a single
entity at one time, as they do now.  More generality, code as simple as
previously.

It might even be conceivable to move events to a subvoice of a different
Voice/Staff and do cross-staff beams/voices in that way.  However, that
would be a non-local operation and likely quite harder to get right
reliably.

Of course, all this tastes of "goto" in that it would be a nightmare to
translate into MusicXML and its ilk.  But the \hideNotes in separate
Voice construct works just by chance (as long as the hidden constructs
are similar enough to have exactly the same spacing) and also is not
nice to put into MusicXML.  And a pain to document in snippets.

And make no mistake: something like this is _needed_ all the time.

So much for the nightly brainstorm.  Have to go to a rehearsal now.

-- 
David Kastrup





reply via email to

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