0

I'm trying to display the harmonic series, and highlight the interval between each note and the octave below them. I'm imagining dimension lines as used in blue-prints. I could use some hints on how to do this.

enter image description here

My first try was to use Voice.TupletBracket.

{
  \clef bass
  \override Staff.TimeSignature.stencil = ##f
  \override Score.BarLine.stencil = ##f
  \time 16/4
  \tupletUp
  bes,,,4_"1"
  \tuplet 5/5 { bes,,_"2" f,_"3" }
  \tuplet 5/5 { \tuplet 3/3 { bes,_"4" d_"5" } f_"6" } geseh_"7"
  \tuplet 8/8 { \tuplet 7/7 { \tuplet 5/5 { \tuplet 3/3 { \tuplet 2/2 { bes_"8" c'_"9" } d'_"10" } eeh'_"11" f'_"12" } geh'_"13" gih'_"14" a'_"15" } bes'_"16" }
}

enter image description here

This is almost exactly what I want. I have the straight brackets, and the numbers are great. But the main issue is that I'd also like the octaves marked. To do that, I'd need the bes notes to end the previous tuple before they start the next one. I tried \tuplet 8/8 \=1{ bes \tuplet 8/8 \=2{ bes \=1} ..., but lilypond caught fire. I'd also like the lines to be horizontal, but max-slope-factor isn't available in my version of lilypond (2.24).

But thinking of the \=1( notation my next thought was to use slurs which do support that notation.

  bes,,,4_"1"  ^\=8(                                                
  bes,,_"2"    \=8) ^\=8( ^\=5( 
  f,_"3"       \=5)                                                             
  bes,_"4"     \=8) ^\=8( ^\=5( ^\=3(
  d_"5"        \=3)                                                             
  f_"6"        \=5)   
  bes_"8"      \=8)  ...

enter image description here

Now I have all of the spanners I need (including the octaves), but this clearly looks awful. I'm having trouble setting offsets for only one slur at a time. They all start at the same point so an \override is not going to target only one. I also spent a ton of time offsetting that text above the slurs. Even if I could set the control points for individual slurs that start at the same point, they would be smooth, while I like the jagged look of the other lines.

My next thought was TextSpanner but after an hour of looking up how to make them overlap, I realize that \stopTextSpan cannot point to a specific line, and so it is not possible to make them overlap.

enter image description here

My next thought is markup. I think this is promising. After struggling with define-markup-command for a while, I just brute-forced it and wrote part of it out manually.

  bes,,,4^\markup{\center-column{ "8" \rotate #270 \left-brace #25 } }
  bes,,^\markup{\center-column{ "5" \rotate #270 \left-brace #25 } }^\markup{\center-column{ "8" \rotate #270 \left-brace #50 } }
  f,
  bes,^\markup{\center-column{ "3" \rotate #270 \left-brace #25 } }^\markup{\center-column{ "5" \rotate #270 \left-brace #50 } }^\markup{\center-column{ "8" \rotate #270 \left-brace #100 }}
  ...

enter image description here

This might have potential but the horizontal space between the brace and the number really look bad, and the vertical scaling of the brace is a no-go. I'm not sure if that white-space is from the \rotate #270 taking up a row, or if it is kerning of the bracket.

2 Answers 2

2

The trick to make the tuplets work is to create an empty note and extend the tuplet over it. To ensure the bracket extends to the next note, tweak the TupletBracket.X-positions:

\tweak TupletBracket.X-positions #'(1 . 7)
\tuplet 8/8 {
  bes,,,4
  \once \override NoteHead.stencil = ##f
  \once \override Stem.stencil = ##f
  bes,,,
}

In lilypond >=2.25, you can ensure each bracket is horizontal with the TupletBracket.max-slope-factor

\override TupletBracket.max-slope-factor = #0

In lilypond <= 2.24, to achieve that you need to manually set the Y-coordinates of each bar:

\tweak TupletBracket.positions #'(4.5 . 4.5)
\tuplet 2/2 {
  bes_"8"
  c'_"9"
}

The final solution:

enter image description here

\version "2.24.1"
{
  \clef bass
  \override Staff.TimeSignature.stencil = ##f
  \override Score.BarLine.stencil = ##f
  \time 16/4
  \tupletUp

  \tweak TupletBracket.X-positions #'(1 . 7.)
  \tuplet 8/8 {
    bes,,,4_"1"
    \once \override NoteHead.stencil = ##f
    \once \override Stem.stencil = ##f
    bes,,,
  }
  \tweak TupletBracket.X-positions #'(1.2 . 10.8)
  \tuplet 8/8 {
    \tuplet 5/5 {
      bes,,_"2"
      f,_"3"
    }
    \once \override NoteHead.stencil = ##f
    \once \override Stem.stencil = ##f
    bes,
  }
  \tweak TupletBracket.X-positions #'(1.2 . 19)
  \tuplet 8/8 {
    \tuplet 5/5 {
      \tuplet 3/3 {
        bes,_"4" 
      d_"5"
      }
      f_"6"
    }
    \once \override Voice.NoteHead.color = #(rgb-color 0.8 0.2 0.2)
    \once \override Voice.Stem.color = $(rgb-color 0.8 0.2 0.2)
    \once \override Voice.Accidental.color = $(rgb-color 0.8 0.2 0.2)
    geseh_"7"
  }

  \tweak TupletBracket.positions #'(10.5 . 10.5)
  \tuplet 8/8 {
    \tweak TupletBracket.positions #'(9 . 9)
    \tuplet 7/7 {
      \tweak TupletBracket.positions #'(7.5 . 7.5)
      \tuplet 5/5 {
        \tweak TupletBracket.positions #'(6 . 6)
        \tuplet 3/3 {
          \tweak TupletBracket.positions #'(4.5 . 4.5)
          \tuplet 2/2 {
            bes_"8"
            c'_"9"
          }
          d'_"10"
        }
        \once \override Voice.NoteHead.color = #(rgb-color 0.8 0.2 0.2)
        \once \override Voice.Stem.color = $(rgb-color 0.8 0.2 0.2)
        \once \override Voice.Accidental.color = $(rgb-color 0.8 0.2 0.2)
        eeh'_"11"
        f'_"12"
      }
      \override Voice.NoteHead.color = #(rgb-color 0.8 0.2 0.2)
      \override Voice.Stem.color = $(rgb-color 0.8 0.2 0.2)
      \override Voice.Accidental.color = $(rgb-color 0.8 0.2 0.2)
      geh'_"13"
      gih'_"14"
      \revert Voice.NoteHead.color
      \revert Voice.Stem.color
      \revert Voice.Accidental.color
      a'_"15"
    }
    bes'_"16"
  }
}
\layout {
  \context {
    \Score
    \override SpacingSpanner.common-shortest-duration = #(ly:make-moment 1/16)
  }
}

If you use the same \tweak TupletBracket.positions for all 8, 5, and 3s then you get this:

enter image description here

1

Why not manually offset your Slurs? Instead of doing \override (which changes the defaults for the context) change each single Slur individually doing

\tweak extra-offset #'(0 . 2) (

Generally the issue here are restritions at an engraver level. So the best idea would probably be to create a custom engraver for this.

1
  • Thanks, I'll look up custom engravers.
    – Stewart
    Commented Sep 19, 2023 at 9:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.