That's amazing Lukas! :chefkiss:
Thanks so much.
Drew

On Wed, 29 Jan 2025 at 15:47, Lukas-Fabian Moser <l...@gmx.de> wrote:
> 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