Hi Drew,

    ... which is great, since it means that the noteNameFunction gets
    called with the current context (as opposed to only a pitch),
    which means we can read the tonic from the context and do not need
    to write our own engraver (whose job it would be to read the
    context's tonic and pass it to our note NoteName grobs). The only
    caveat is that, by default, a NoteNames context doesn't \consist
    the Key_engraver, so it knows nothing about tonics. So we add this
    engraver, but then have to \omit the actual printed key signatures.

Here a new version (now only the NoteNames version) that allows specifying the syllable to use for the tonic (as defined by \key):

\version "2.25.21"

#(set-object-property! 'tonicSyllable 'translation-type? string?)

#(define (normalize-pitch p)
   (ly:make-pitch 0 (ly:pitch-notename p) (ly:pitch-alteration p)))

#(define (inv-assoc key alist default)
   (let ((resulting-pair
          (find (lambda (entry)
                  (equal? (cdr entry)
                          key))
                alist)))
     (if resulting-pair
         (car resulting-pair)
         default)))

#(define-markup-command (highlight-tonic layout props arg) (markup?)
   (interpret-markup layout props
                     (markup #:bold #:with-color red arg)))

extract-syllables =
#(define-scheme-function (unknown def) ((string? "?") ly:music?)
   (map
    (lambda (note-ev)
      (cons
       (normalize-pitch (ly:music-property note-ev 'pitch))
       (let ((text-script (extract-typed-music note-ev 'text-script-event)))
         (if (pair? text-script)
             (ly:music-property (car text-script) 'text unknown)
             unknown))))
    (extract-typed-music def 'note-event)))

noteSyllable =
#(define-scheme-function
  (unknown-syllable syllable-definition)
  ((string? "?") ly:music?)
  (let ((pitch-syllable-dictionary
         (extract-syllables unknown-syllable syllable-definition)))
    (pretty-print pitch-syllable-dictionary)
    (lambda (pitch context)
      (let* ((tonic-pitch (ly:context-property context 'tonic #{ c #}))
             (tonic-syllable (ly:context-property context 'tonicSyllable "do"))              (do-offset (inv-assoc tonic-syllable pitch-syllable-dictionary #{ c #}))
             (syllable (assoc-get (normalize-pitch (- pitch
                                                      (- tonic-pitch do-offset)))
                                  pitch-syllable-dictionary
                                  unknown-syllable)))
        (if (equal? syllable tonic-syllable)
            (make-highlight-tonic-markup syllable)
            syllable)))))

#(set-global-staff-size 30)

doSyllables = {
  % to be entered for c major
  c -do d -re e -mi f -fa g -so a -la b -ti
  cis -di dis -ri fis -fi gis -si ais -li
  des -ru es -mu ges -su as -lu bes -tu
}

\layout {
  ragged-right = ##t
  \context {
    \NoteNames
    \consists Key_engraver % we need this in order to manage the 'tonic' context property ...     \omit KeySignature % ... but we don't want to see the key signature printed
    \omit KeyCancellation
  }
}

mus = \relative c' {
  c4 d e f8 fis
  g4 a b c \break

  \key a \major
  a,4 b cis d
  e4 f8 fis g gis a4 \break

  \key d \dorian
  \set tonicSyllable = re
  d,4 e f g
  a4 b c d \break

  \key d \minor
  \set tonicSyllable = la
  d,4 e f g
  a4 b cis d
  d c bes a
}

<<
  \new Staff \mus
  \new NoteNames \with {
    noteNameFunction = \noteSyllable \doSyllables
  } \mus
>>

Lukas

Reply via email to