Hi Eef,
Am 17.09.22 um 10:52 schrieb Eef Weenink:
PS; I you might change the engraver, consider to NOT colour equal
notes. (or make it an option). Equal notes do not harm the harmonic
line. (for seeing where the lowest notes are, it might be set to #t).
Yes, I suspected that this might not be fitting for your need.
In my case, I wanted to mark the notes in a canon where the current line
takes over the bass function: This is an interesting question in the
construction of a canon, where the composer might add the bass notes
"all at the same time" (usually at the end, creating additional
voice-leading constraints for the voices entering before that) like in
Mozart's /Bona Nox/:
or the bass might be constituted in different parts of the pieces by
different bits in the melody like in Mozart's /Gehn wir im Prater, gehn
wir in'd Hetz/:
Anyway: See attached. The engraver (now called in LilyPond syntax with
\) now takes a mandatory argument indicating if only strict lowest notes
should be coloured (#t) or not (#f). (I think the meaning of #t and #f
is switched with respect to what you proposed.)
Lukas
\version "2.23"
% ==== Bass_highlighter_engraver =====================================
#(set-object-property! 'bass-notehead-callback 'backend-type? procedure?)
#(set-object-property! 'bass-notehead-callback 'backend-doc "Function to be called on grob if it is a bass notehead")
#(define (is-lowest? el lst less? strict)
(every
(lambda (x)
(or ((if strict eq? equal?) el x)
(less? el x))) lst))
Bass_highlighter_engraver =
#(define-scheme-function (strict) (boolean?)
(lambda (context)
(define (is-over? note moment)
(not (ly:moment<? moment (assq-ref note 'off-time))))
(let ((notes '()))
(make-engraver
(listeners
((note-event engraver event)
(let*
((on-time (ly:context-current-moment context))
(pitch (ly:event-property event 'pitch))
(duration (ly:event-property event 'duration))
(note-length (ly:duration-length duration))
(off-time (ly:moment-add on-time note-length)))
(set! notes (cons `((on-time . ,on-time)
(off-time . ,off-time)
(pitch . ,pitch))
notes)))))
(acknowledgers
((note-head-interface engraver grob source-engraver)
(let* ((event (ly:grob-property grob 'cause))
(pitch (ly:event-property event 'pitch))
(current-pitches
(map (lambda (note) (assq-ref note 'pitch)) notes)))
(if (is-lowest? pitch current-pitches ly:pitch<? strict)
(let
((callback (ly:grob-property grob 'bass-notehead-callback)))
(if (procedure? callback) (callback grob)))))))
((start-translation-timestep translator)
; remove all notes that are over by now
(let* ((now (ly:context-current-moment context)))
(set! notes
(filter (lambda (note) (not (is-over? note now)))
notes))))))))
% =======================================================
\layout {
\context {
\Score
\consists \Bass_highlighter_engraver ##t
\override NoteHead.bass-notehead-callback =
#(lambda (grob) (ly:grob-set-property! grob 'color red))
% interesting alternative:
% #(lambda (grob) (ly:grob-set-property! grob 'duration-log 1))
}
}
% Example:
<<
\new Staff \relative {
c'4 d e f
g a b c
c, d c g
}
\new Staff \relative {
d''4 c b a
g f e d
<c e g> q q q
}
>>