\version "2.19.10" #(define (ledger-line-no middle-C-pos p) "Returns the number of ledger-lines a pitch @var{p} will have with middle C position @var{middle-C-pos} expressed as staff-steps from the middle staff line." (let* ((ps (ly:pitch-steps p)) (mid-staff-steps (- middle-C-pos)) (top-line (+ mid-staff-steps 4)) (bottom-line (- mid-staff-steps 4)) (above? (> ps top-line)) (below? (< ps bottom-line)) (steps-outside-staff (cond (below? (- ps bottom-line)) (above? (- ps top-line)) (else 0)))) (truncate (/ steps-outside-staff 2)))) #(define (find-clefMiddleCPosition mus) (let ((clef-pos -6)) ; treble is default (for-some-music (lambda (x) (let ((n (ly:music-property x 'symbol))) (and (eq? n 'middleCClefPosition) (set! clef-pos (ly:music-property x 'value))))) mus) clef-pos)) #(define (make-ottava-music arg) (list (make-music 'OttavaMusic 'ottava-number arg))) ottavate = #(define-music-function (parser location upper lower mus) (integer? number? ly:music?) "Create an ottava for notes based on number of ledger lines. Ledger lines above the staff are specified in @var{upper} as positive integers; an 8va will be created for notes with at least this many lines. Ledger lines below the staff are specified in @var{lower} as negative numbers; an 8va bassa will be created for notes with at least the absolute value of this number. Choose an number of ledger lines which does not appear in the music expression to prevent either from appearing. All notes in a chord must pass the threshold to receive an ottava." (let ((up-an-octave (make-ottava-music 1)) (down-an-octave (make-ottava-music -1)) (loco (make-ottava-music 0))) (define (up-or-down-an-octave clef-pos mus-expr) ; select from variables up-an-octave and down-an-octave ; return #f if no displacement (cond ((music-is-of-type? mus-expr 'event-chord) (cond ((every (lambda (p) (>= (ledger-line-no clef-pos (ly:music-property p 'pitch)) upper)) (ly:music-property mus-expr 'elements)) up-an-octave) ((every (lambda (p) (<= (ledger-line-no clef-pos (ly:music-property p 'pitch)) lower)) (ly:music-property mus-expr 'elements)) down-an-octave) (else #f))) ((music-is-of-type? mus-expr 'note-event) (cond ((>= (ledger-line-no clef-pos (ly:music-property mus-expr 'pitch)) upper) up-an-octave) ((<= (ledger-line-no clef-pos (ly:music-property mus-expr 'pitch)) lower) down-an-octave) (else #f))))) (define (no-ottava clef-pos mus-expr) (not (up-or-down-an-octave clef-pos mus-expr))) (define (build-new-elts mus-expr new-expr start-loco? start-ottava? clef-pos) (if (null? mus-expr) ;; ensure that ottava does not extend past a localized ;; use of \ottavate (append new-expr loco) (begin ;; find value for 'clefMiddleCPosition (if (eq? (ly:music-property (car mus-expr) 'name) 'ContextSpeccedMusic) (set! clef-pos (find-clefMiddleCPosition (car mus-expr)))) (cond ((or (music-is-of-type? (car mus-expr) 'event-chord) (music-is-of-type? (car mus-expr) 'note-event)) (cond ((and start-ottava? (up-or-down-an-octave clef-pos (car mus-expr))) (build-new-elts (cdr mus-expr) (append new-expr (up-or-down-an-octave clef-pos (car mus-expr)) (list (car mus-expr))) #t #f clef-pos)) ((and start-loco? (no-ottava clef-pos (car mus-expr))) (build-new-elts (cdr mus-expr) (append new-expr loco (list (car mus-expr))) #f #t clef-pos)) (else (build-new-elts (cdr mus-expr) (append new-expr (list (car mus-expr))) #t #t clef-pos)))) (else (build-new-elts (cdr mus-expr) (append new-expr (list (car mus-expr))) #t #t clef-pos)))))) (define (recurse music) (let ((elts (ly:music-property music 'elements)) (e (ly:music-property music 'element))) (if (ly:music? e) (recurse e)) (if (pair? elts) (if (or (any (lambda (elt) (music-is-of-type? elt 'note-event)) elts) (any (lambda (elt) (music-is-of-type? elt 'event-chord)) elts)) (set! (ly:music-property music 'elements) (build-new-elts elts '() #t #t -6)) (map recurse elts))))) (recurse mus) ;(display-scheme-music mus) mus)) %%%%%%%%%%% EXAMPLE %%%%%%%%%%%% music = \relative c,, { \new Staff { \key g \major \new Voice { \clef "bass_8" 4 8 \clef bass 4 8 \clef tenor 4 8 \clef alto 4 8 \clef treble 4 8 } } } { \ottavate #2 #-2 \music } { \ottavate #1 #-1 \music }