staff-rs / staff

Music theory and score rendering library with midi, notes, chords, scales, and more.
https://staff-rs.github.io
MIT License
253 stars 11 forks source link

Add support for chord names #13

Open matthunz opened 1 year ago

matthunz commented 1 year ago

LilyPond uses the \ChordNames command to display chords. This looks hard to implement because it writes them in parallel.

Rendering chord names should align with the beats of a measure, and grow the beat's width to fit the text. Names should be able to be attached to beats with no chords or in between them.

example

wztvm commented 4 months ago

There are a few subproblems to this as I see it.

  1. Compute the width of a set of elements that form a unit (in this example: chords, notes and lyrics) with individual preferred width constraints. How easy or hard this is depends on:

    • Data is represented
    • Complexity of constraints
    • Algorithm A simple case might be something like having a representation that is or can be turned into an iterator that would return something like (chord, note, syllable), compute the minimal width of each of those, pick the maximum of those and add padding. When the width of a row reaches some maximal width decide to make a line break. There are choices to be made there. Is padding flexible? Is it nicer to squeeze the content a little and fit in an extra block or to add space to fill out the row. It's very similar to the tradeoffs in justifying text. One can start with simple choice to get something working and then build from there.
  2. To support something like LilyPond notation for an end user, the task would be to convert the input data into a form that is easy to layout. I the goal is to allow the user to separately specify a melody, chords, and lyrics; then the user needs a way to combine those so that they internally can be turned into whatever representation is easy to layout. In the best of worlds that can be done fully automatically. LilyPond-notation allows specifying how many beats a chord should be active so that should be enough information probably. Well, there is an issue. What happens when a chord and a note overlap but does not start or end in tandem. Say we have a half note and half way through that we specify a chord shift. Some issues: Notationally shifting the chord right or left above a half note wouldn't really indicate when it's supposed to start playing anyway. So in that case one would probably want to split the note or the chord or both so that they match up. Split notes should then receive an indicator that they are connected to not mess up how notes match to syllables etc.
    There might be a few such things to manage. If it's tricky to figure out what one want's to do in general cases one can always, start by just assuming that the pieces line up and then eventually try to reduce the general case to that.

  3. Having convenient ways to specify chords. The layout above was about just figuring out how wide a given text label is. One could just manually specify a text label. But one might for example want to specify a set of notes and get a chord suggested based on that. That can be done as an isolated problem thought.

Do any of those things seem like more viable subproblems?