ssb22 / jianpu-ly

Jianpu in Lilypond
http://ssb22.user.srcf.net/mwrhome/jianpu-ly.html
Apache License 2.0
70 stars 18 forks source link

lyrics placement and the rests #29

Closed suntong closed 1 year ago

suntong commented 1 year ago

Originally posted by @ssb22 in https://github.com/ssb22/jianpu-ly/issues/27#issuecomment-1501147517

right now, that results in incorrect output (some of the words get placed under some of the rests)

Hmm..., how it should be working?

lyrics should not be placed under the rests normally right? Does it only work for crotchet notes, or should be working for the rest as well? (I'm thinking that it should be the latter)

ssb22 commented 1 year ago

Lyrics should not be placed under rests of any duration (because we can't sing silently), e.g.

q0 q5 s0 q4 s0 q0 q3 2 0 - 1 0
L: five four three two one
suntong commented 1 year ago

Thanks for the reply, in that case, please take a look at https://github.com/jianpu-ly/jianpu-st/blob/master/mmd-木棉道.jp

The last two rests,

q0 q6 6. q6 q6 q6 q5 q4 5 - ~ 5 q0 q6 6. q1' 5 q3 q2 1 - ~ 1
^^                              ^^

If you're able to look at the result, https://github.com/jianpu-ly/jianpu-st/blob/master/mmd-木棉道.png

you can see that lyrics are placed under the rests for both the cases.

Notes,

ssb22 commented 1 year ago

Ah. Bug.

Workaround for now is to run python jianpu-ly.py --noRestHack

(This is an undocumented option. There's a comment saying TODO: document next to the --noRestHack handler. But I'm tempted to change it anyway.)

The original point of rest-hack was that Lilypond 2.16 and 2.18 didn't always obey our beam overrides when we tried to beam a quaver rest to a quaver note. That mattered because we were telling Lilypond to always write the beam as a line under the notes (for jianpu), and we didn't want it to write a 5-line quaver "flag" instead. Lilypond's beam-override code is supposed to take care of that, but due to a Lilypond bug it didn't always work (at least not on 2.16 and 2.18).

So I put in "rest-hack" which is basically "pretend the short rests are notes". So we still see "0" on the page (we make it look like a rest), and we still write a rest to the MIDI output, but old-Lilypond's beaming algorithm "thinks" it's dealing with a note and doesn't mess up.

Turning the rests into notes is obviously going to cause a problem for lyrics, because Lilypond will try to attach a lyric to our fake note that's really a rest. So at first I put "auto turn off rest-hack if there's lyrics" (just don't do it and hope old versions of Lilypond won't mess up our beaming in this particular piece), but then I realised we can create a new Lilypond "voice" for the fake note, because Lilypond attaches its lyrics to only the main voice and not to any extra voice we put in (and we can still make it look the same on paper: you wouldn't know by looking at it that an extra Lilypond voice is being used for the rest).

So I guess the questions now are:

  1. does Lilypond still even need rest-hack? We already have code in jianpu-ly to detect which version of Lilypond is on our system, so it can do version-specific output when necessary (although I prefer to avoid this—maybe the .ly file will be typeset on another system—but we can do it if we have to e.g. Mac fonts); if we can figure out which version if Lilypond fixed the original bug that rest-hack was working around, then we could put in some logic saying "auto turn off rest-hack if we're above Lilypond version whatever" (which will make the headache of maintaining rest-hack go away in most real-world cases except maybe one or two users stuck on very old systems who can't upgrade past Lilypond 2.18), or we might even consider raising the minimum required version of Lilypond to whatever version fixed that bug & remove rest-hack completely.
  2. Assuming we want to keep rest-hack for now, why did it not create a \new Voice for the fake note in that particular input?
ssb22 commented 1 year ago

OK I know what the answer to question 2 is.

The logic to create the new voice for rest-hack is turned on only if the piece has lyrics. But the "check if the piece has lyrics" part just looks for L: or H: as a complete word within the input. So if you had written H: 紅 (with a space after the colon) it would have worked, but because you wrote H:紅 (no space after the colon) the lookahead part didn't see those lyrics coming (and therefore didn't turn on the creation of new voices for rest-hack), although the actual lyric handler could cope with no space when it got there, but by then it was too late because most of the Lilypond code had already been generated.

So the actual fix (for now) is just to make sure it checks for L: or H: with or without a space immediately after when it's looking ahead to see if there will be lyrics. (And of course I didn't run into this in testing because I automatically put a space after every colon I type....)