Automatically adding fingering diagrams for tin whistle

Revision as of 22:43, 26 October 2025 by Jean Abou Samra (talk | contribs) (Import snippet from LSR)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

These functions may be used to automatically add fingering diagrams and reformatted note names to tin whistle music, with the whistle referred to being the common D whistle.

The fingering diagram function makes no attempt to deal with alternate fingerings. It is strictly one diagram per note, doing a fairly simple, straight forward one to one substitution.

The reformatted note names are in line with what I'm told the local tin whistle players expect - the lower octave being printed in upper case, and the upper octave printed in lower case with a plus sign underneath the note name, with the topmost D getting 2 plus signs.

Typically I use this code in combination with the tiedNoteToSkip function from http://lsr.di.unimi.it/LSR/Item?id=760 to avoid having the note name printed again for a tied note. Simply use each function as described in their descriptions, and (so far, at least) they work just fine with each other.

\version "2.24.0"

\language "english"

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Usage example:
%
%  \new NoteNames {
%    %#(define myFingSize 0.75)  % this line would override the size of the diagram produced
%    %#(define myFingThickness  0.25)  % this line would override the thickness of the lines used to draw the diagrams
%    \set noteNameFunction = #myTWFingerings
%    \music
%  }
%
%  \new NoteNames {
%    \set noteNameFunction = #myTWNoteNames
%    \music
%  }
%
% Both can be used to put the note name under (or over, if you prefer) the fingering diagram.
% Just put one after the other in the prefered order. Just make sure to enclose them in
% a set of angle brackets for simultaneous music (i.e. put them in a << >> set).


#(define myFingSize  0.65)  %  Overall size of the fingering diagram
#(define myFingThickness  0.25)  %  How thick the lines used to draw the diagram are


myTWFingerings =           
#(lambda (pitch ctx)
   (cond
    ((<= (ly:pitch-semitones pitch)
         1)  ; Note too low
     (markup #:sans "U"))
    ((>= (ly:pitch-semitones pitch)
         27)  ;  Note too high
     (markup #:sans "O"))

    ; D4
    ((= (ly:pitch-semitones pitch)
        2)
     (markup
      (#:override `(size . ,myFingSize)
                  (#:override `(thickness . ,myFingThickness)
                              (#:center-column
                               (#:pad-around
                                0.15
                                #:woodwind-diagram
                                'tin-whistle
                                (list (list 'cc 'one 'two 'three 'four 'five 'six)
                                      (list 'lh)
                                      (list 'rh))))))))

    ; D#/Eb4 or 5
    ((or (= (ly:pitch-semitones pitch)
            3)
         (= (ly:pitch-semitones pitch)
            15))
     (markup
      (#:override `(size . ,myFingSize)
                  (#:override `(thickness . ,myFingThickness)
                              (#:center-column
                               (#:pad-around
                                0.15
                                #:woodwind-diagram
                                'tin-whistle
                                (list (list 'cc 'one 'two 'three 'four 'five 'six1h)
                                      (list 'lh)
                                      (list 'rh))))))))

    ; E4 or 5
    ((or (= (ly:pitch-semitones pitch)
            4)
         (= (ly:pitch-semitones pitch)
            16))
     (markup
      (#:override `(size . ,myFingSize)
                  (#:override `(thickness . ,myFingThickness)
                              (#:center-column
                               (#:pad-around
                                0.15
                                #:woodwind-diagram
                                'tin-whistle
                                (list (list 'cc 'one 'two 'three 'four 'five)
                                      (list 'lh)
                                      (list 'rh))))))))

    ; F4 or 5
    ((or (= (ly:pitch-semitones pitch)
            5)
         (= (ly:pitch-semitones pitch)
            17))
     (markup
      (#:override `(size . ,myFingSize)
                  (#:override `(thickness . ,myFingThickness)
                              (#:center-column
                               (#:pad-around
                                0.15
                                #:woodwind-diagram
                                'tin-whistle
                                (list (list 'cc 'one 'two 'three 'four 'five1h)
                                      (list 'lh)
                                      (list 'rh))))))))

    ; F# or Gb4 or 5
    ((or (= (ly:pitch-semitones pitch)
            6)
         (= (ly:pitch-semitones pitch)
            18))
     (markup
      (#:override `(size . ,myFingSize)
                  (#:override `(thickness . ,myFingThickness)
                              (#:center-column
                               (#:pad-around
                                0.15
                                #:woodwind-diagram
                                'tin-whistle
                                (list (list 'cc 'one 'two 'three 'four)
                                      (list 'lh)
                                      (list 'rh))))))))

    ; G4 or 5
    ((or (= (ly:pitch-semitones pitch)
            7)
         (= (ly:pitch-semitones pitch)
            19))
     (markup
      (#:override `(size . ,myFingSize)
                  (#:override `(thickness . ,myFingThickness)
                              (#:center-column
                               (#:pad-around
                                0.15
                                #:woodwind-diagram
                                'tin-whistle
                                (list (list 'cc 'one 'two 'three)
                                      (list 'lh)
                                      (list 'rh))))))))

    ; G# or Ab4
    ((= (ly:pitch-semitones pitch)
        8)
     (markup
      (#:override `(size . ,myFingSize)
                  (#:override `(thickness . ,myFingThickness)
                              (#:center-column
                               (#:pad-around
                                0.15
                                #:woodwind-diagram
                                'tin-whistle
                                (list (list 'cc 'one 'two 'three1h)
                                      (list 'lh)
                                      (list 'rh))))))))

    ; G# or Ab5
    ((= (ly:pitch-semitones pitch)
        20)
     (markup
      (#:override `(size . ,myFingSize)
                  (#:override `(thickness . ,myFingThickness)
                              (#:center-column
                               (#:pad-around
                                0.15
                                #:woodwind-diagram
                                'tin-whistle
                                (list (list 'cc 'one 'two 'four 'five)
                                      (list 'lh)
                                      (list 'rh))))))))

    ; A4 or 5
    ((or (= (ly:pitch-semitones pitch)
            9)
         (= (ly:pitch-semitones pitch)
            21))
     (markup
      (#:override `(size . ,myFingSize)
                  (#:override `(thickness . ,myFingThickness)
                              (#:center-column
                               (#:pad-around
                                0.15
                                #:woodwind-diagram
                                'tin-whistle
                                (list (list 'cc 'one 'two)
                                      (list 'lh)
                                      (list 'rh))))))))

    ; A# or Bb4
    ((= (ly:pitch-semitones pitch)
        10)
     (markup
      (#:override `(size . ,myFingSize)
                  (#:override `(thickness . ,myFingThickness)
                              (#:center-column
                               (#:pad-around
                                0.15
                                #:woodwind-diagram
                                'tin-whistle
                                (list (list 'cc 'one 'two1h)
                                      (list 'lh)
                                      (list 'rh))))))))

    ; A# or Bb5
    ((= (ly:pitch-semitones pitch)
        22)
     (markup
      (#:override `(size . ,myFingSize)
                  (#:override `(thickness . ,myFingThickness)
                              (#:center-column
                               (#:pad-around
                                0.15
                                #:woodwind-diagram
                                'tin-whistle
                                (list (list 'cc 'one 'two1h)
                                      (list 'lh)
                                      (list 'rh))))))))

    ; B4 or 5
    ((or (= (ly:pitch-semitones pitch)
            11)
         (= (ly:pitch-semitones pitch)
            23))
     (markup
      (#:override `(size . ,myFingSize)
                  (#:override `(thickness . ,myFingThickness)
                              (#:center-column
                               (#:pad-around
                                0.15
                                #:woodwind-diagram
                                'tin-whistle
                                (list (list 'cc 'one)
                                      (list 'lh)
                                      (list 'rh))))))))

    ; C5 or D6
    ((or (= (ly:pitch-semitones pitch)
            12)
         (= (ly:pitch-semitones pitch)
            26))
     (markup
      (#:override `(size . ,myFingSize)
                  (#:override `(thickness . ,myFingThickness)
                              (#:center-column
                               (#:pad-around
                                0.15
                                #:woodwind-diagram
                                'tin-whistle
                                (list (list 'cc 'two 'three)
                                      (list 'lh)
                                      (list 'rh))))))))

    ; C# or Db5 or 6
    ((or (= (ly:pitch-semitones pitch)
            13)
         (= (ly:pitch-semitones pitch)
            25))
     (markup
      (#:override `(size . ,myFingSize)
                  (#:override `(thickness . ,myFingThickness)
                              (#:center-column
                               (#:pad-around
                                0.15
                                #:woodwind-diagram
                                'tin-whistle
                                (list (list 'cc )
                                      (list 'lh)
                                      (list 'rh))))))))

    ; C6
    ((= (ly:pitch-semitones pitch)
        24)
     (markup
      (#:override `(size . ,myFingSize)
                  (#:override `(thickness . ,myFingThickness)
                              (#:center-column
                               (#:pad-around
                                0.15
                                #:woodwind-diagram
                                'tin-whistle
                                (list (list 'cc 'one1h)
                                      (list 'lh)
                                      (list 'rh))))))))

    ; D5
    ((= (ly:pitch-semitones pitch)
        14)
     (markup
      (#:override `(size . ,myFingSize)
                  (#:override `(thickness . ,myFingThickness)
                              (#:center-column
                               (#:pad-around
                                0.15
                                #:woodwind-diagram
                                'tin-whistle
                                (list (list 'cc 'two 'three 'four 'five 'six)
                                      (list 'lh)
                                      (list 'rh))))))))

    (else  ;  Failover - should never get here
           (markup #:sans "X"))

    )
   )


myTWNoteNames = 
#(lambda (pitch ctx)
   (cond
    ((<= (ly:pitch-semitones pitch)
         1) ; Note too low
     (markup #:sans "U"))
    ((>= (ly:pitch-semitones pitch)
         27) ; Note too high
     (markup #:sans "O"))
    ((= (ly:pitch-semitones pitch)
        26) ; D6
     (markup #:sans (#:center-column
                     (#:pad-around 0.6
                                   (note-name->markup pitch #t)
                                   "++"))))
    (else
     (if (<= (ly:pitch-semitones pitch)
             13)
         (markup #:sans (note-name->markup pitch #f))
         (markup #:sans (#:center-column
                         (#:pad-around 0.6
                                       (note-name->markup pitch #t)
                                       "+")))
         )
     )
    )
   )

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Example code begins
%

music = {
  \key d \major
  cs'4 d' e' f' fs' g' a' b' c'' cs'' d'' e''
  f'' fs'' g'' a'' b'' c''' cs''' d''' e'''
}

\score {
  <<
    
    \new Staff {
      \new Voice {
        \music
      }
    }
    
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % First NoteNames context used to produce the fingering diagrams
    \new NoteNames {
      %#(define myFingSize 0.75)  % this line would override the size of the diagram produced
      %#(define myFingThickness  0.25)  % this line would override the thickness of the lines used to draw the diagrams
      \set noteNameFunction = #myTWFingerings
      \music
    }

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % Second NoteNames context used to put the note names
    % below the fingering diagrams
    \new NoteNames {
      \set noteNameFunction = #myTWNoteNames
      \music
    }
  
  >>
}