lilypond-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: drawing a range reguardless of transposition


From: Aaron Hill
Subject: Re: drawing a range reguardless of transposition
Date: Sun, 24 Nov 2019 14:37:24 -0800
User-agent: Roundcube Webmail/1.3.8

On 2019-11-24 2:40 am, Sandro Santilli wrote:
Like, the following does _not_ work:

  altoDesignedWrittenRange = bes g'''
\override NoteHead.color = \highlightOutOfRange \altoDesignedWrittenRange

The function would need to be modified to support syntax like that.

I took some time to generalize a few things and add some additional usability. Consider the following updated version:

%%%%
\version "2.19.83"

highlightPitches = #(define-music-function
  (color method music)
  ((color? red) symbol? ly:music?)
  "Applies the specified @var{color} to a @code{NoteHead} and its
associated @code{Accidental} when the pitch lies within the range
defined by @var{method} and @var{music}. Supported methods are
@code{below}, @code{above}, @code{outside}, and @code{inside}.
Notes within @var{music} may appear in any order. Pitches are
compared given their respective distance to Middle C."
  (define (pitch-tones<? p1 p2)
    (< (ly:pitch-tones p1) (ly:pitch-tones p2)))
  (define (get-method method range)
    (define (below? pitch) (pitch-tones<? pitch (car range)))
    (define (above? pitch) (pitch-tones<? (cdr range) pitch))
    (define (outside? pitch) (or (below? pitch) (above? pitch)))
    (define (inside? pitch) (not (outside? pitch)))
    (ly:assoc-get method
      `((below . ,below?) (above . ,above?)
        (outside . ,outside?) (inside . ,inside?)) '()))
  (define (pitch-range music)
    (let* ((pitches (map (lambda (x) (ly:music-property x 'pitch))
                         (extract-typed-music music 'note-event)))
           (sorted (sort pitches pitch-tones<?)))
      (cons (first sorted) (last sorted))))
  (let ((pred (get-method method (pitch-range music))))
    (if (null? pred) (ly:parser-error "Unrecognized method."))
    #{ \override NoteHead.after-line-breaking = #(lambda (grob)
      (let* ((cause (ly:grob-property grob 'cause))
             (pitch (and (ly:prob? cause)
                         (ly:prob-property cause 'pitch #f)))
             (acc (ly:grob-object grob 'accidental-grob)))
        (if (and (procedure? pred) (pred pitch)) (begin
          (set! (ly:grob-property grob 'color) color)
          (and (ly:grob? acc)
            (set! (ly:grob-property acc 'color) color)))))) #}))

phrase = \relative c' {
  \set Staff.printKeyCancellation = ##f
  \key c \major
  c8 d e fis g a bes c
}
melody = {
  \transpose c aes, \phrase \bar "||"
  \transpose c e \phrase \bar "|."
}

\new Staff \with { \highlightPitches #cyan below gis' } \melody
\new Staff \with { \highlightPitches #blue above f' } \melody
\new Staff \with { \highlightPitches #magenta outside { fes' bis' } } \melody
\new Staff \with { \highlightPitches inside { bis' fes' } } \melody
%%%%

Note that code above is almost compatible with 2.18.2. You should only need to modify the declaration of the function to explicitly accept the parser and location arguments as required in the older version:

%%%%
% ...
highlightPitches = #(define-music-function
  (parser location color method music)
  ((color? red) symbol? ly:music?)
% ...
%%%%

When using this new function, you can choose to define the note range in a variable or simply wrap up the whole thing:

%%%%
% ...
instrumentRange = { c' c'' }
highlightOutOfRange = \highlightPitches outside \instrumentRange
{ g''4 \once \highlightOutOfRange g'' g'' }
%%%%


-- Aaron Hill

Attachment: out-of-range.cropped.png
Description: PNG image


reply via email to

[Prev in Thread] Current Thread [Next in Thread]