Hi Eef,

Am 16.09.22 um 13:53 schrieb Eef Weenink:
I write mostly arrangements where I bring a melody voice down to the double 
bass (my instrument :-))

Double bass is written an octave higher then sounding, so a lot of times, the 
score lookes OK, but in fact there are voice crossings between lefthand of 
piano and the double bass (what gives unwanted/unpleasant voice crossings.

To check this, I transpose the double bass voice down an octave and manually 
check the boths voices.

Wonder if there is a function in lilypond to do this fastly. Like the coloured 
noteheads when checking a voice against the ambitus of an instrument.

This reminds me of a function I wrote last year to automatically colourise the lowest sounding pitch in a score. (In my case, this was for harmonic analysis of canons.) See attached.

Maybe this could be used or at least adapted?

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-lower-bound? el lst less?)
   ; returns #t if no element of lst is less? than el.
   (if (pair? lst)
       (if (less? (car lst) el)
           #f
           (is-lower-bound? el (cdr lst) less?))
       #t))

Bass_highlighter_engraver =
#(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-lower-bound? pitch current-pitches ly:pitch<?)
              (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
    \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
  }
>>

Reply via email to