gregorio-project / gregorio

The Gregorio Project
http://gregorio-project.github.io
Other
164 stars 43 forks source link

Update each line's vertical spacing #59

Closed rpspringuel closed 9 years ago

rpspringuel commented 9 years ago

Apparently the Solesmes scores only move the lyric text down only on lines where the a low element (note a', a, b', or b) is present. Currently gregorio moves the lyrics down for the whole score when this happens. A user would like to be able to imitate the Solesmes behavior.

This will probably require making two passes per line. The first to figure out what the lowest note on the line is, the second to actually set the lines. Perhaps the first pass populates two boxes (one for staff and neumes, the other for text), then the second can simply place them on the page. However, there might be alignment issues in this approach.

eroux commented 9 years ago

To develop a little bit: TeX has its own complex line-breaking algorithm, so we can't just do things at line level easily, though there are some experiments to do it in Lua, but it's really not mature enough, and it will make everything noticeably slower. So let's not count on it and do what we can.

What I propose is the following solution:

Do you see what I mean?

eroux commented 9 years ago

Note that this won't work in the case where a line breaks in the middle of a syllable and the lowest note is not well placed, but as it will fix 90% of the cases, it's already a good improvement. But if you or I work on it, it would be good to make gregorio also pass lowest note to each glyph, so that we can refine the algorithm later at glyph level, in order to avoid the case I described before.

rpspringuel commented 9 years ago

Some discussions I was having today about the Gregorio inspired the following idea:

  1. At the beginning of each line, check with the aux file to see how much space is required for this line. On a first pass of the file, the lack of an aux file would mean that spacing defaults to assuming there were no low notes, and thus lead to overlapping text and notes.
  2. Define a tracking variable that would know what the lowest note encountered so far is. At the end of every line, write the current value of this tracking variable to a line (and score) specific variable in the aux file and then reset it to zero.
  3. Each glyph printing algorithm would check the tracking variable to see if it specifies enough space for it. If the glyph needs more space than the tracking variable would allocate, then it increases the tracking variable accordingly.

This would require two passes through LuaTeX to get the spacing correct, but that's already a fairly normal operation for TeX users (for instance, to get cross references right).

I think this is similar to what @eroux proposed above, but would be entirely done in the TeX.

eroux commented 9 years ago

Yes, I'm also thinking about this solution, but it's quite a lot of work too... For instance: how do you know what to write to the aux file? I don't think you can get a line per line information in the aux file simply... It would certainly require some pass in a lua callback too, or do you have something else in mind? But anyway, having two pass for this feature is no problem, so if it works that way, let's do it.

rpspringuel commented 9 years ago

I'd probably go this way for implementation:

First, we define two counters scorecounter and linecounter which track the score and lines within the score (i.e. the second counter is a sub-counter of the first). We also have a tracking variable current_line_space which tracks the lowest note encountered so far in this line.

At the beginning of each line (for instance, when drawing the staff lines or the clef that starts each line) go through the following steps:

  1. Unless this is the first line of the score (i.e. linecounter=0), write the value of current_line_space to scorecounter_linecounter_space in the aux file. This represents the needed space for the line we just ended.
  2. Increment linecounter.
  3. Reset current_line_space to 0.
  4. Set the vertical spacing for the line based on the value of scorecounter_linecounter_space which was loaded when the previous run's aux file was loaded at the beginning of the run (this is automatic). Default to 0 when the variable is not found.

Basically, I can detect the beginning of each line from processes that are already done on a line by line bases (printing staff lines or the clef at the beginning of each line). That tells me when to write to the aux file. By then continually monitoring the amount of space needed for a line and resetting that tracking information whenever I write to the aux file, I can know what to write to the aux file. Combine the two (along with a counter system to track which information goes with which line) and I should be able to write information to the aux file on a line by line basis and retrieve it accordingly.

eroux commented 9 years ago

Quoting you:

Basically, I can detect the beginning of each line from processes that are already done on a line by line bases (printing staff lines or the clef at the beginning of each line).

I admit I'd be curious to know how... Can you show a minimal example of this?

rpspringuel commented 9 years ago

Perhaps detect is the wrong word. Rather I'd piggy back on the code that draws the lines by inserting code which would do the above. A quick glance at the code tells me that's in localleftbox, so I'd probably prefix the contents of that box with the necessary code. I'll work on a short example when I get the chance.

eroux commented 9 years ago

I'm affraid you'll be a bit surprised by the result... but let's give it a try, I might be!

eroux commented 9 years ago

@henryso there is something you could do here that would be very useful: making the \greglyph macro aware of the highest and lowest level of what it typesets (including signs). This could be by adding \greglyphhighestlevel{x} and \greglyphlowestlevel{y} in the #5th argument of \greglyph or by adding two new arguments... It would be straightforward if it was only the notes, but I think you're the person knowing best the C code on signs heights, and it's the most difficult part... What do you think?

henryso commented 9 years ago

I can do it. Which way (argument #5 or additional arguments) would work best for you?

eroux commented 9 years ago

Let's start with additional arguments to #5

eroux commented 9 years ago

and you ca define \greglyph(highest|below)level to macros that just don't do anything, we'll complete them later

henryso commented 9 years ago

Choral signs generally pass the height of the note. If the note is on a line and it's a high choral sign, it passes the height of the note + 2. How should I adjust the height for choral signs?

Should I even account for signs at all? Wouldn't it be cleaner to instrument the sign macros to maintain the computation in TeX?

Also, I intend to only create one macro which takes two arguments. Let me know if that's a bad idea.

eroux commented 9 years ago

The idea of instrumenting sign macros is interesting, this would be less intrusive indeed!

Or for having one macro.

henryso commented 9 years ago

Changes for this are in #440, ready for review. However, #440 piggybacks on #439, so merging #440 would merge the changes from #439 as well.

As mentioned above, I am only passing the low/high pitches to the new macro, called \GreGlyphHeights (to follow the convention in #383).

henryso commented 9 years ago

@rpspringuel Did you have any luck using localleftbox to reset things at the beginning of a line?

rpspringuel commented 9 years ago

I actually haven't had a chance to try yet.

henryso commented 9 years ago

@eroux Having a better understanding of what you want to implement, I understand better why you wanted to take signs into account for the min/max height calculation in gregorio. I will make this change. By the time the sign macros get to it, the attributes on the main glyph node would have already been set.

henryso commented 9 years ago

Before I go off the deep end with this implementation, please check what I've done so far in the https://github.com/gregorio-project/gregorio/tree/fix-59 branch and let me know if I'm on the right track.

The code is really rough at this point, though it seems to work in my limited testing.

This is not yet ready to be a pull request. I need to do cleanup, remove dead code, add better comments, document the changes, and test more. But I would really like at least a high level review to prevent needless meandering.

henryso commented 9 years ago

Note: there's additional discussion on this topic in #515, #517, and #518.

henryso commented 9 years ago

Should the default be the old uniform-line-height behavior or the new variable-line-height behavior?

eroux commented 9 years ago

the new one will be better for beginners and will make Gregorio easier, we should just document that it might have a performance impact.

henryso commented 9 years ago

I have to report, after testing, that the old line-height behavior is not actually uniform. It's controlled by values passed by gregorio (the executable), and gregorio is a bit inconsistent (or perhaps just plain wrong) about the values it passes on the first line and around forced line breaks. I suppose I should fix this as well, to make it truly uniform. Or should I just let sleeping dogs lie?

henryso commented 9 years ago

As of #520, the implementation is more-or-less complete. If you have time, please review and let me know if there's anything I should change.

The last remaining thing before I create a pull request for https://github.com/gregorio-project/gregorio/tree/fix-59 into master is documentation.

eroux commented 9 years ago

I think it would be best to fix the old line height system, it will certainly still be used... That's all I see, you did a very good job!