X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=scm%2Fmusic-functions.scm;h=490cafe92c40c9cc3f3de7ed20b29541353061ea;hb=de451af43aef0220738bfdd5329f0685bdaba3d2;hp=e33e1629aff9efd16c7e9a1c9d4bfc7fc3ca65bd;hpb=79ee93bd2d973c23f0cea05e85d3b31b3d0766ba;p=lilypond.git diff --git a/scm/music-functions.scm b/scm/music-functions.scm index e33e1629af..490cafe92c 100644 --- a/scm/music-functions.scm +++ b/scm/music-functions.scm @@ -2,8 +2,8 @@ ;;;; ;;;; source file of the GNU LilyPond music typesetter ;;;; -;;;; (c) 1998--2006 Jan Nieuwenhuizen -;;;; Han-Wen Nienhuys +;;;; (c) 1998--2007 Jan Nieuwenhuizen +;;;; Han-Wen Nienhuys ;; (use-modules (ice-9 optargs)) @@ -74,6 +74,7 @@ First it recurses over the children, then the function is applied to MUSIC. (define-public (display-music music) "Display music, not done with music-map for clarity of presentation." + (display music) (display ": { ") (let ((es (ly:music-property music 'elements)) @@ -112,9 +113,11 @@ For instance, (else ;; scheme arg arg))) (define (inner-markup->make-markup mrkup) - (let ((cmd (proc->command-keyword (car mrkup))) - (args (map transform-arg (cdr mrkup)))) - `(,cmd ,@args))) + (if (string? mrkup) + `(#:simple ,mrkup) + (let ((cmd (proc->command-keyword (car mrkup))) + (args (map transform-arg (cdr mrkup)))) + `(,cmd ,@args)))) ;; body: (if (string? markup-expression) markup-expression @@ -183,6 +186,21 @@ Returns `obj'. (newline) obj) +;;; +;;; Scheme music expression --> Lily-syntax-using string translator +;;; +(use-modules (srfi srfi-39) + (scm display-lily)) + +(define*-public (display-lily-music expr parser #:key force-duration) + "Display the music expression using LilyPond syntax" + (memoize-clef-names supported-clefs) + (parameterize ((*indent* 0) + (*previous-duration* (ly:make-duration 2)) + (*force-duration* force-duration)) + (display (music->lily-string expr parser)) + (newline))) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define-public (shift-one-duration-log music shift dot) @@ -207,7 +225,7 @@ Returns `obj'. "create a repeat music expression, with all properties initialized properly" (let ((talts (if (< times (length alts)) (begin - (ly:warning (_ "More alternatives than repeats. Junking excess alternatives")) + (ly:warning (_ "More alternatives than repeats. Junking excess alternatives")) (take alts times)) alts)) (r (make-repeated-music name))) @@ -215,20 +233,23 @@ Returns `obj'. (set! (ly:music-property r 'repeat-count) (max times 1)) (set! (ly:music-property r 'elements) talts) (if (equal? name "tremolo") - (let* ((dot? (zero? (modulo times 3))) - (dots (if dot? 1 0)) - (mult (if dot? - (quotient (* times 2) 3) - times)) - (shift (- (ly:intlog2 mult)))) - + (let* ((dots (1- (logcount times))) + (mult (/ (* times (ash 1 dots)) (1- (ash 2 dots)))) + (shift (- (ly:intlog2 (floor mult))))) + (if (not (integer? mult)) + (ly:warning (_ "invalid tremolo repeat count: ~a") times)) (if (memq 'sequential-music (ly:music-property main 'types)) ;; \repeat "tremolo" { c4 d4 } (let ((children (length (ly:music-property main 'elements)))) - (if (not (= children 2)) + + ;; fixme: should be more generic. + (if (and (not (= children 2)) + (not (= children 1))) (ly:warning (_ "expecting 2 elements for chord tremolo, found ~a") children)) (ly:music-compress r (ly:make-moment 1 children)) - (shift-duration-log r (1- shift) dots)) + (shift-duration-log r + (if (= children 2) (1- shift) shift) + dots)) ;; \repeat "tremolo" c4 (shift-duration-log r shift dots))) r))) @@ -319,7 +340,18 @@ i.e. this is not an override" 'grob-property gprop)) (define direction-polyphonic-grobs - '(Stem Tie Rest Slur PhrasingSlur Script TextScript Dots DotColumn Fingering)) + '(DotColumn + Dots + Fingering + LaissezVibrerTie + PhrasingSlur + RepeatTie + Rest + Script + Slur + Stem + TextScript + Tie)) (define-safe-public (make-voice-props-set n) (make-sequential-music @@ -328,6 +360,17 @@ i.e. this is not an override" (if (odd? n) -1 1))) direction-polyphonic-grobs) (list + (make-property-set 'graceSettings + ;; TODO: take this from voicedGraceSettings or similar. + '((Voice Stem font-size -3) + (Voice NoteHead font-size -3) + (Voice Dots font-size -3) + (Voice Stem length-fraction 0.8) + (Voice Stem no-stem-extend #t) + (Voice Beam thickness 0.384) + (Voice Beam length-fraction 0.8) + (Voice Accidental font-size -4))) + (make-grob-property-set 'NoteColumn 'horizontal-shift (quotient n 2)) (make-grob-property-set 'MultiMeasureRest 'staff-position (if (odd? n) -4 4)))))) @@ -336,8 +379,9 @@ i.e. this is not an override" (append (map (lambda (x) (make-grob-property-revert x 'direction)) direction-polyphonic-grobs) - (list (make-grob-property-revert 'NoteColumn 'horizontal-shift)) - (list (make-grob-property-revert 'MultiMeasureRest 'staff-position))))) + (list (make-property-unset 'graceSettings) + (make-grob-property-revert 'NoteColumn 'horizontal-shift) + (make-grob-property-revert 'MultiMeasureRest 'staff-position))))) (define-safe-public (context-spec-music m context #:optional id) @@ -387,84 +431,39 @@ i.e. this is not an override" ;; mmrest (define-public (make-multi-measure-rest duration location) - (make-music 'MultiMeasureRestMusicGroup + (make-music 'MultiMeasureRestMusic 'origin location - 'elements (list (make-music 'BarCheck - 'origin location) - (make-event-chord (list (make-music 'MultiMeasureRestEvent - 'origin location - 'duration duration))) - (make-music 'BarCheck - 'origin location)))) - -(define-public (glue-mm-rest-texts music) - "Check if we have R1*4-\\markup { .. }, and if applicable convert to -a property set for MultiMeasureRestNumber." - (define (script-to-mmrest-text script-music) - "Extract 'direction and 'text from SCRIPT-MUSIC, and transform MultiMeasureTextEvent" - (let ((dir (ly:music-property script-music 'direction)) - (p (make-music 'MultiMeasureTextEvent - 'text (ly:music-property script-music 'text)))) - (if (ly:dir? dir) - (set! (ly:music-property p 'direction) dir)) - p)) - - (if (eq? (ly:music-property music 'name) 'MultiMeasureRestMusicGroup) - (let* ((text? (lambda (x) (memq 'script-event (ly:music-property x 'types)))) - (event? (lambda (x) (memq 'event (ly:music-property x 'types)))) - (group-elts (ly:music-property music 'elements)) - (texts '()) - (events '()) - (others '())) - - (set! texts - (map script-to-mmrest-text (filter text? group-elts))) - (set! group-elts - (remove text? group-elts)) - - (set! events (filter event? group-elts)) - (set! others (remove event? group-elts)) - - (if (or (pair? texts) (pair? events)) - (set! (ly:music-property music 'elements) - (cons (make-event-chord - (append texts events)) - others))) - - )) - - music) - + 'duration duration)) (define-public (make-property-set sym val) (make-music 'PropertySet 'symbol sym 'value val)) +(define-public (make-property-unset sym) + (make-music 'PropertyUnset + 'symbol sym)) + (define-public (make-ottava-set octavation) (let ((m (make-music 'ApplyContext))) (define (ottava-modify context) "Either reset middleCPosition to the stored original, or remember old middleCPosition, add OCTAVATION to middleCPosition, and set OTTAVATION to `8va', or whatever appropriate." - (if (number? (ly:context-property context 'middleCPosition)) - (if (= octavation 0) - (let ((where (ly:context-property-where-defined context 'middleCPosition)) - (oc0 (ly:context-property context 'originalCentralCPosition))) - (ly:context-set-property! context 'middleCPosition oc0) - (ly:context-unset-property where 'originalCentralCPosition) - (ly:context-unset-property where 'ottavation)) - (let* ((where (ly:context-property-where-defined context 'middleCPosition)) - (c0 (ly:context-property context 'middleCPosition)) - (new-c0 (+ c0 (* -7 octavation))) - (string (cdr (assoc octavation '((2 . "15ma") - (1 . "8va") - (0 . #f) - (-1 . "8va bassa") - (-2 . "15ma bassa")))))) - (ly:context-set-property! context 'middleCPosition new-c0) - (ly:context-set-property! context 'originalCentralCPosition c0) - (ly:context-set-property! context 'ottavation string))))) + (if (number? (ly:context-property context 'middleCOffset)) + (let ((where (ly:context-property-where-defined context 'middleCOffset))) + (ly:context-unset-property where 'middleCOffset) + (ly:context-unset-property where 'ottavation))) + + (let* ((offset (* -7 octavation)) + (string (cdr (assoc octavation '((2 . "15ma") + (1 . "8va") + (0 . #f) + (-1 . "8vb") + (-2 . "15mb")))))) + (ly:context-set-property! context 'middleCOffset offset) + (ly:context-set-property! context 'ottavation string) + (ly:set-middle-C! context))) (set! (ly:music-property m 'procedure) ottava-modify) (context-spec-music m 'Staff))) @@ -529,9 +528,9 @@ of beat groupings " 'duration duration 'text string)) -(define-safe-public (make-span-event type spandir) +(define-safe-public (make-span-event type span-dir) (make-music type - 'span-direction spandir)) + 'span-direction span-dir)) (define-public (set-mus-properties! m alist) "Set all of ALIST as properties of M." @@ -567,7 +566,7 @@ of beat groupings " "Split the parts of a chord into different Voices using separator" (let ((es (ly:music-property ch 'elements))) (set! (ly:music-property ch 'elements) - (voicify-list (split-list es music-separator?) 0)) + (voicify-list (split-list-by-separator es music-separator?) 0)) ch)) (define-public (voicify-music m) @@ -588,9 +587,8 @@ of beat groupings " (define-public (empty-music) (ly:export (make-music 'Music))) -;;; - ; Make a function that checks score element for being of a specific type. +;; Make a function that checks score element for being of a specific type. (define-public (make-type-checker symbol) (lambda (elt) ;;(display symbol) @@ -635,19 +633,29 @@ of beat groupings " "Replace MUS by RestEvent of the same duration if it is a SkipEvent. Useful for extracting parts from crowded scores" - (if (equal? (ly:music-property mus 'name) 'SkipEvent) + (if (memq (ly:music-property mus 'name) '(SkipEvent SkipMusic)) (make-music 'RestEvent 'duration (ly:music-property mus 'duration)) mus)) +(define-public (music-has-type music type) + (memq type (ly:music-property music 'types))) + +(define-public (music-clone music) + (define (alist->args alist acc) + (if (null? alist) + acc + (alist->args (cdr alist) + (cons (caar alist) (cons (cdar alist) acc))))) + + (apply + make-music + (ly:music-property music 'name) + (alist->args (ly:music-mutable-properties music) '()))) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; warn for bare chords at start. -(define (has-request-chord elts) - (reduce (lambda (x y) (or x y)) #f - (map (lambda (x) - (equal? (ly:music-property x 'name) 'RequestChord)) - elts))) (define-public (ly:music-message music msg) (let ((ip (ly:music-property music 'origin))) @@ -655,25 +663,6 @@ SkipEvent. Useful for extracting parts from crowded scores" (ly:input-message ip msg) (ly:warning msg)))) -(define (check-start-chords music) - "Check music expression for a Simultaneous_music containing notes\n(ie. Request_chords), -without context specification. Called from parser." - (let ((es (ly:music-property music 'elements)) - (e (ly:music-property music 'element)) - (name (ly:music-property music 'name))) - (cond ((equal? name "Context_specced_music") #t) - ((equal? name "Simultaneous_music") - (if (has-request-chord es) - (ly:music-message music "Starting score with a chord.\nInsert an explicit \\context before chord") - (map check-start-chords es))) - ((equal? name "SequentialMusic") - (if (pair? es) - (check-start-chords (car es)))) - (else (if (ly:music? e) (check-start-chords e))))) - music) - - - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; setting stuff for grace context. @@ -700,7 +689,6 @@ without context specification. Called from parser." ((< i 0)) (f (vector-ref v i)))) -;; TODO: make a remove-grace-property too. (define-public (add-grace-property context-name grob sym val) "Set SYM=VAL for GROB in CONTEXT-NAME. " (define (set-prop context) @@ -711,6 +699,25 @@ without context specification. Called from parser." (ly:context-set-property! where 'graceSettings new-settings))) (ly:export (context-spec-music (make-apply-context set-prop) 'Voice))) +(define-public (remove-grace-property context-name grob sym) + "Remove all SYM for GROB in CONTEXT-NAME. " + (define (sym-grob-context? property sym grob context-name) + (and (eq? (car property) context-name) + (eq? (cadr property) grob) + (eq? (caddr property) sym))) + (define (delete-prop context) + (let* ((where (ly:context-property-where-defined context 'graceSettings)) + (current (ly:context-property where 'graceSettings)) + (prop-settings (filter + (lambda(x) (sym-grob-context? x sym grob context-name)) + current)) + (new-settings current)) + (for-each (lambda(x) + (set! new-settings (delete x new-settings))) + prop-settings) + (ly:context-set-property! where 'graceSettings new-settings))) + (ly:export (context-spec-music (make-apply-context delete-prop) 'Voice))) + (defmacro-public def-grace-function (start stop) @@ -783,7 +790,7 @@ Syntax: (set! (ly:music-property music 'quoted-events) quoted-vector) (set! (ly:music-property music 'iterator-ctor) ly:quote-iterator::constructor)) - (ly:warning (_ "can't find quoted music `~S'" quoted-name)))) + (ly:warning (_ "cannot find quoted music: `~S'") quoted-name))) music)) @@ -839,12 +846,15 @@ if appropriate. (list (make-sequential-music (list - (context-spec-music (make-property-set 'skipTypesetting #t) 'Score) + (context-spec-music (make-property-set 'skipTypesetting #t) + 'Score) (make-music 'SkipMusic 'duration - (ly:make-duration 0 0 - (ly:moment-main-numerator skip-length) - (ly:moment-main-denominator skip-length))) - (context-spec-music (make-property-set 'skipTypesetting #f) 'Score))) + (ly:make-duration + 0 0 + (ly:moment-main-numerator skip-length) + (ly:moment-main-denominator skip-length))) + (context-spec-music (make-property-set 'skipTypesetting #f) + 'Score))) music))) music))) @@ -852,7 +862,6 @@ if appropriate. (define-public toplevel-music-functions (list (lambda (music parser) (voicify-music music)) - (lambda (x parser) (music-map glue-mm-rest-texts x)) (lambda (x parser) (music-map music-check-error x)) (lambda (x parser) (music-map precompute-music-length x)) (lambda (music parser) @@ -881,26 +890,108 @@ if appropriate. (music-map apply-duration lyric-music)) -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; - -(define-public ((add-balloon-text object-name text off) grob orig-context cur-context) - "Usage: see input/regression/balloon.ly " - (let* ((meta (ly:grob-property grob 'meta)) - (cb (ly:grob-property-data grob 'stencil)) - (nm (if (pair? meta) (cdr (assoc 'name meta)) "nonexistant"))) - (if (and (equal? nm object-name) - (procedure? cb)) - (begin - (ly:grob-set-property! grob 'stencil ly:balloon-interface::print) - (set! (ly:grob-property grob 'original-stencil) cb) - (set! (ly:grob-property grob 'balloon-text) text) - (set! (ly:grob-property grob 'balloon-text-offset) off) - (set! (ly:grob-property grob 'balloon-text-props) '((font-family . roman))))))) - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; accidentals +(define-public ((make-accidental-rule octaveness lazyness) context pitch barnum measurepos) + "Creates an accidental rule that makes its decision based on the octave of the note + and a laziness value. + octaveness is either 'same-octave or 'any-octave and defines whether the rule should + respond to accidental changes in other octaves than the current. 'same-octave is the + normal way to typeset accidentals - an accidental is made if the alteration is different + from the last active pitch in the same octave. 'any-octave looks at the last active pitch + in any octave. + lazyness states over how many bars an accidental should be remembered. + 0 is default - accidental lasts over 0 bar lines, that is, to the end of current measure. + A positive integer means that the accidental lasts over that many bar lines. + -1 is 'forget immediately', that is, only look at key signature. + #t is forever." + (let ((keysig (ly:context-property context 'localKeySignature))) + (ly:find-accidentals-simple keysig pitch barnum lazyness octaveness))) + +(define (key-entry-notename entry) + "Return the pitch of an entry in localKeySignature. The entry is either of the form + '(notename . alter) or '((octave . notename) . (alter barnum . measurepos))." + (if (number? (car entry)) + (car entry) + (cdar entry))) + +(define (key-entry-octave entry) + "Return the octave of an entry in localKeySignature (or #f if the entry does not have + an octave)." + (and (pair? (car entry)) (caar entry))) + +(define (key-entry-bar-number entry) + "Return the bar number of an entry in localKeySignature (or #f if the entry does not + have a bar number)." + (and (pair? (car entry)) (caddr entry))) + +(define (key-entry-measure-position entry) + "Return the measure position of an entry in localKeySignature (or #f if the entry does + not have a measure position)." + (and (pair? (car entry)) (cdddr entry))) + +(define (key-entry-alteration entry) + "Return the alteration of an entry in localKeySignature." + (if (number? (car entry)) + (cdr entry) + (cadr entry))) + +(define-public (find-pitch-entry keysig pitch accept-global accept-local) + "Return the first entry in keysig that matches the pitch. + accept-global states whether key signature entries should be included. + accept-local states whether local accidentals should be included. + if no matching entry is found, #f is returned." + (if (pair? keysig) + (let* ((entry (car keysig)) + (entryoct (key-entry-octave entry)) + (entrynn (key-entry-notename entry)) + (oct (ly:pitch-octave pitch)) + (nn (ly:pitch-notename pitch))) + (if (and (equal? nn entrynn) + (or (and accept-global (equal? #f entryoct)) + (and accept-local (equal? oct entryoct)))) + entry + (find-pitch-entry (cdr keysig) pitch accept-global accept-local))) + #f)) + +(define-public (neo-modern-accidental-rule context pitch barnum measurepos) + "an accidental rule that typesets an accidental if it differs from the key signature + AND does not directly follow a note on the same staff-line. + This rule should not be used alone because it does neither look at bar lines + nor different accidentals at the same notename" + (let* ((keysig (ly:context-property context 'localKeySignature)) + (entry (find-pitch-entry keysig pitch #t #t))) + (if (equal? #f entry) + (cons #f #f) + (let* ((global-entry (find-pitch-entry keysig pitch #t #f)) + (key-acc (if (equal? global-entry #f) + 0 + (key-entry-alteration global-entry))) + (acc (ly:pitch-alteration pitch)) + (entrymp (key-entry-measure-position entry)) + (entrybn (key-entry-bar-number entry))) + (cons #f (not (or (equal? acc key-acc) + (and (equal? entrybn barnum) (equal? entrymp measurepos))))))))) + +(define-public (teaching-accidental-rule context pitch barnum measurepos) + "an accidental rule that typesets a cautionary accidental + if it is included in the key signature AND does not directly follow + a note on the same staff-line." + (let* ((keysig (ly:context-property context 'localKeySignature)) + (entry (find-pitch-entry keysig pitch #t #t))) + (if (equal? #f entry) + (cons #f #f) + (let* ((global-entry (find-pitch-entry keysig pitch #f #f)) + (key-acc (if (equal? global-entry #f) + 0 + (key-entry-alteration global-entry))) + (acc (ly:pitch-alteration pitch)) + (entrymp (key-entry-measure-position entry)) + (entrybn (key-entry-bar-number entry))) + (cons #f (not (or (equal? acc key-acc) + (and (equal? entrybn barnum) (equal? entrymp measurepos))))))))) + (define-public (set-accidentals-properties extra-natural auto-accs auto-cauts context) @@ -915,7 +1006,7 @@ if appropriate. (define-public (set-accidental-style style . rest) "Set accidental style to STYLE. Optionally takes a context argument, -e.g. 'Staff or 'Voice. The context defaults to Voice, except for piano styles, which +e.g. 'Staff or 'Voice. The context defaults to Staff, except for piano styles, which use GrandStaff as a context. " (let ((context (if (pair? rest) (car rest) 'Staff)) @@ -925,74 +1016,133 @@ use GrandStaff as a context. " (cond ;; accidentals as they were common in the 18th century. ((equal? style 'default) - (set-accidentals-properties #t '(Staff (same-octave . 0)) - '() context)) + (set-accidentals-properties #t + `(Staff ,(make-accidental-rule 'same-octave 0)) + '() + context)) ;; accidentals from one voice do NOT get cancelled in other voices ((equal? style 'voice) - (set-accidentals-properties #t '(Voice (same-octave . 0)) - '() context)) + (set-accidentals-properties #t + `(Voice ,(make-accidental-rule 'same-octave 0)) + '() + context)) ;; accidentals as suggested by Kurt Stone, Music Notation in the 20th century. ;; This includes all the default accidentals, but accidentals also needs cancelling ;; in other octaves and in the next measure. ((equal? style 'modern) - (set-accidentals-properties #f '(Staff (same-octave . 0) (any-octave . 0) (same-octave . 1)) - '() context)) + (set-accidentals-properties #f + `(Staff ,(make-accidental-rule 'same-octave 0) + ,(make-accidental-rule 'any-octave 0) + ,(make-accidental-rule 'same-octave 1)) + '() + context)) ;; the accidentals that Stone adds to the old standard as cautionaries ((equal? style 'modern-cautionary) - (set-accidentals-properties #f '(Staff (same-octave . 0)) - '(Staff (any-octave . 0) (same-octave . 1)) + (set-accidentals-properties #f + `(Staff ,(make-accidental-rule 'same-octave 0)) + `(Staff ,(make-accidental-rule 'any-octave 0) + ,(make-accidental-rule 'same-octave 1)) + context)) + ;; same as modern, but accidentals different from the key signature are always + ;; typeset - unless they directly follow a note of the same pitch. + ((equal? style 'neo-modern) + (set-accidentals-properties #f + `(Staff ,(make-accidental-rule 'same-octave 0) + ,(make-accidental-rule 'any-octave 0) + ,(make-accidental-rule 'same-octave 1) + ,neo-modern-accidental-rule) + '() + context)) + ((equal? style 'neo-modern-cautionary) + (set-accidentals-properties #f + `(Staff ,(make-accidental-rule 'same-octave 0)) + `(Staff ,(make-accidental-rule 'any-octave 0) + ,(make-accidental-rule 'same-octave 1) + ,neo-modern-accidental-rule) + context)) + ;; Accidentals as they were common in dodecaphonic music with no tonality. + ;; Each note gets one accidental. + ((equal? style 'dodecaphonic) + (set-accidentals-properties #f + `(Staff ,(lambda (c p bn mp) '(#f . #t))) + '() context)) ;; Multivoice accidentals to be read both by musicians playing one voice ;; and musicians playing all voices. ;; Accidentals are typeset for each voice, but they ARE cancelled across voices. ((equal? style 'modern-voice) (set-accidentals-properties #f - '(Voice (same-octave . 0) (any-octave . 0) (same-octave . 1) - Staff (same-octave . 0) (any-octave . 0) (same-octave . 1)) + `(Voice ,(make-accidental-rule 'same-octave 0) + ,(make-accidental-rule 'any-octave 0) + ,(make-accidental-rule 'same-octave 1) + Staff ,(make-accidental-rule 'same-octave 0) + ,(make-accidental-rule 'any-octave 0) + ,(make-accidental-rule 'same-octave 1)) '() context)) ;; same as modernVoiceAccidental eccept that all special accidentals are typeset ;; as cautionaries ((equal? style 'modern-voice-cautionary) (set-accidentals-properties #f - '(Voice (same-octave . 0)) - '(Voice (any-octave . 0) (same-octave . 1) - Staff (same-octave . 0) (any-octave . 0) (same-octave . 1)) + `(Voice ,(make-accidental-rule 'same-octave 0)) + `(Voice ,(make-accidental-rule 'any-octave 0) + ,(make-accidental-rule 'same-octave 1) + Staff ,(make-accidental-rule 'same-octave 0) + ,(make-accidental-rule 'any-octave 0) + ,(make-accidental-rule 'same-octave 1)) context)) ;; stone's suggestions for accidentals on grand staff. ;; Accidentals are cancelled across the staves in the same grand staff as well ((equal? style 'piano) (set-accidentals-properties #f - '(Staff (same-octave . 0) - (any-octave . 0) (same-octave . 1) - GrandStaff (any-octave . 0) (same-octave . 1)) + `(Staff ,(make-accidental-rule 'same-octave 0) + ,(make-accidental-rule 'any-octave 0) + ,(make-accidental-rule 'same-octave 1) + GrandStaff + ,(make-accidental-rule 'any-octave 0) + ,(make-accidental-rule 'same-octave 1)) '() pcontext)) ((equal? style 'piano-cautionary) (set-accidentals-properties #f - '(Staff (same-octave . 0)) - '(Staff (any-octave . 0) (same-octave . 1) - GrandStaff (any-octave . 0) (same-octave . 1)) + `(Staff ,(make-accidental-rule 'same-octave 0)) + `(Staff ,(make-accidental-rule 'any-octave 0) + ,(make-accidental-rule 'same-octave 1) + GrandStaff + ,(make-accidental-rule 'any-octave 0) + ,(make-accidental-rule 'same-octave 1)) pcontext)) + + ;; same as modern, but cautionary accidentals are printed for all sharp or flat + ;; tones specified by the key signature. + ((equal? style 'teaching) + (set-accidentals-properties #f + `(Staff ,(make-accidental-rule 'same-octave 0)) + `(Staff ,(make-accidental-rule 'same-octave 1) + ,teaching-accidental-rule) + context)) + ;; do not set localKeySignature when a note alterated differently from ;; localKeySignature is found. ;; Causes accidentals to be printed at every note instead of ;; remembered for the duration of a measure. - ;; accidentals not being remembered, causing accidentals always to be typeset relative to the time signature + ;; accidentals not being remembered, causing accidentals always to + ;; be typeset relative to the time signature ((equal? style 'forget) (set-accidentals-properties '() - '(Staff (same-octave . -1)) - '() context)) + `(Staff ,(make-accidental-rule 'same-octave -1)) + '() + context)) ;; Do not reset the key at the start of a measure. Accidentals will be ;; printed only once and are in effect until overridden, possibly many ;; measures later. ((equal? style 'no-reset) (set-accidentals-properties '() - '(Staff (same-octave . #t)) + `(Staff ,(make-accidental-rule 'same-octave #t)) '() context)) (else - (ly:warning (_ "unknown accidental style: ~S" style)) + (ly:warning (_ "unknown accidental style: ~S") style) (make-sequential-music '())))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -1025,3 +1175,34 @@ use GrandStaff as a context. " (ly:music-property (car evs) 'pitch) #f))) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-public (extract-named-music music music-name) +"Return a flat list of all music named @code{music-name} +from @code{music}." + (let ((extracted-list + (if (ly:music? music) + (if (eq? (ly:music-property music 'name) music-name) + (list music) + (let ((elt (ly:music-property music 'element)) + (elts (ly:music-property music 'elements))) + (if (ly:music? elt) + (extract-named-music elt music-name) + (if (null? elts) + '() + (map (lambda(x) + (extract-named-music x music-name )) + elts))))) + '()))) + (flatten-list extracted-list))) + +(define-public (event-chord-notes event-chord) +"Return a list of all notes from @{event-chord}." + (filter + (lambda (m) (eq? 'NoteEvent (ly:music-property m 'name))) + (ly:music-property event-chord 'elements))) + +(define-public (event-chord-pitches event-chord) +"Return a list of all pitches from @{event-chord}." + (map (lambda (x) (ly:music-property x 'pitch)) + (event-chord-notes event-chord)))