2 % Copyright (C) 2008, 2009, 2010, 2011 NICTA
3 % Author: Peter Chubb <peter.chubb AT nicta.com.au>
4 % $Id: articulate.ly,v 1.7 2011-03-24 00:40:00 peterc Exp $
7 % This program is free software; you can redistribute it and/or modify
8 % it under the terms of the GNU General Public License, version 3,
9 % as published by the Free Software Foundation.
11 % WARNING: this file under GPLv3 only, not GPLv3+
13 % This program is distributed in the hope that it will be useful,
14 % but WITHOUT ANY WARRANTY; without even the implied warranty of
15 % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 % See the GNU General Public License for more details. It is
17 % available in the Lilypond source tree, or at
18 % http://www.gnu.org/licenses/gpl-3.0.html
20 % This script tries to make MIDI output from LilyPond a little more realistic.
21 % It tries to take articulations (slurs, staccato, etc) into account, by
22 % replacing notes with sequential music of suitably time-scaled note plus
25 % It also tries to unfold trills turns etc., and take rallentendo
26 % and accelerando into account.
28 % As my scheme knowledge is poor (I was teaching myself as I went), there
29 % is much scope for improvement.
33 % In the \score section do:
35 % all the rest of the score
37 % or use the lilywrap script.
39 % TO DO (prioritised, the ones that'll make the most difference first)
42 % * Fix quantisation for dynamics on single note (replace note
43 % with tied 128th notes?) -- started, needs work.
44 % * Make \fp do the right thing (loud start, then quiet).
46 % * Inegalite. Notes on-beat steal time from notes off-beat.
47 % Degree of stealing is a parameter: from 1.0 (straight)
48 % to 1.5 (extreme swing). Also fix tenuto to use this.
50 % * add accel (to match rall), and molto rall. I've never seen
51 % molto accel but some composer somewhere has probably used it.
53 % * Fermata, and Fermata Lunga
54 % * Add more synonyms for accel and rall: rit ritard stringendo
57 % * Rall at end of piece
58 % * Very slight accel into a phrase, rall out of it.
59 % * Dynamics during a phrase???? unclear how these should be in
62 % * Trill algorithm needs work.
64 % * Cope with more ornaments/articulations.
65 % inverted-turns, etc.
66 % -- accent needs better control of dynamics.
67 % -- Articulations: mezzo-staccato, portato.
68 % -- Handling of generic ornaments (in lily, `\stopped'; in
69 % most early music: ornament this note (trill, turn
70 % or mordent as the player wishes))
71 % * Automatic gruppetto at end of trill; better handling of
72 % initial/final grace notes on trill
73 % * Automatic ornaments.
74 % * Spot cadences and ornament
75 % * Look for quaver-dotted note for trills, for example.
76 % * Fill in steps. (Needs lookahead/lookbehind.)
77 % * `afterturn' -- a turn after the start of a note.
78 % * accidentals for trills and turns
81 % * David Kastrup: basic 2.15.28 compatibility by using event-chord-wrap!
82 % This should really be done by rewriting the code more thoroughly.
83 % * From Iain Nicol: appoggiatura timings were out; add staccatissimo; fix
84 % trillSpanner endpoints.
85 % * Also handle Breathing events (by throwing them away). This isn't ideal;
86 % one should really shorten the note before a little. But I don't know
87 % how to do lookahead in scheme.
88 % * Also ignore explicit line breaks.
89 % * Add Mordents (reported by Patrick Karl)
94 #(use-modules (srfi srfi-1))
95 #(use-modules (srfi srfi-11))
96 #(use-modules (ice-9 debug))
97 #(use-modules (scm display-lily))
100 % How much to compress notes marked Staccato. CPE Bach says `as short as
101 % may conveniently be played, as if the keys were too hot to touch'.
102 % Most modern sources say 1/2 the notated length of a note.
103 #(define ac:staccatoFactor '(1 . 2))
105 % How much to compress notes marked staccatissimo.
106 #(define ac:staccatissimoFactor '(1 . 4))
108 % And tenuto (if we ever implement time stealing, this should be >1.0)
109 #(define ac:tenutoFactor '(1 . 1))
111 % How much to articulate normal notes. CPE Bach says 1/2 (and
112 % staccato should be `as short as may conveniently be played') but this
113 % sounds too short for modern music. 7/8 sounds about right.
114 #(define ac:normalFactor '(7 . 8))
116 % How much to slow down for a rall. or a poco rall.
117 % (or speed up for accel or poco accel)
118 #(define ac:rallFactor (ly:make-moment 60/100)) % 40% slowdown
119 #(define ac:pocoRallFactor (ly:make-moment 90/100)) % 10% slowdown
121 % The absolute time for a twiddle in a trill, in minutes.
122 % Start with 1/4 seconds == 1/240 minutes
123 #(define ac:maxTwiddleTime (ly:make-moment 1/240))
125 % How long ordinary grace notes should be relative to their notated
126 % duration. 9/40 is LilyPond's built-in behaviour for MIDI output
127 % (though the notation reference says 1/4).
128 #(define ac:defaultGraceFactor 9/40)
130 % What proportion of an ordinary grace note's time should be stolen
131 % from preceding notes (as opposed to stealing from the principal note).
132 % Composers' intentions for this vary. Taking all from the preceding
133 % notes is LilyPond's built-in behaviour for MIDI output.
134 #(define ac:defaultGraceBackwardness 1)
137 % Internal variables, don't touch.
138 % (should probably be part of a context somehow)
140 % Whether to slur, or not
141 #(define ac:inSlur #f)
142 #(define ac:inPhrasingSlur #f)
144 % Whether the current noteevent is in a trill spanner
145 #(define ac:inTrill #f)
147 % assume start in C major. Key change events override this.
148 % Could get from context, but don't know how.
149 #(define ac:current-key (make-music
152 (ly:make-pitch -1 0 0)
163 #(define ac:currentTempo (ly:make-moment 15/1)) % 4 = 60, measured wholes per minute
164 #(define ac:lastTempo ac:currentTempo) % for 'a tempo' or 'tempo I'
166 % The duration of the current note. Start at a crotchet
167 % for no good reason.
168 #(define ac:currentDuration (ly:make-duration 2 0 1/1))
170 % Amount of musical time (in whole notes) that we need to steal from the
172 #(define ac:stealForward 0)
174 % List of events in the output so far, in reverse order, from which we can
176 #(define ac:eventsBackward '())
178 % Log events for the backward chain.
179 #(define (ac:logEventsBackward music)
182 (case (ly:music-property m 'name)
184 (set! ac:eventsBackward (cons m ac:eventsBackward))
186 ((BarCheck SkipMusic)
187 (let ((wm (make-sequential-music (list m))))
188 (set! ac:eventsBackward (cons wm ac:eventsBackward))
194 % Steal time from the backward chain. Adds to ac:stealForward (with a
195 % warning) if it couldn't backward-steal all that was desired.
196 #(define (ac:stealTimeBackward tosteal)
199 (if (null? ac:eventsBackward)
201 (ly:warning (_ "articulation failed to steal ~a note backward at beginning of music; stealing forward instead") tosteal)
202 (set! ac:stealForward (+ ac:stealForward tosteal)))
204 ((lastev (car ac:eventsBackward))
205 (levlen (ly:moment-main (ly:music-length lastev))))
206 (if (< tosteal levlen)
208 (ly:music-compress lastev (ly:make-moment (/ (- levlen tosteal) levlen)))
211 (if (any (lambda (z) (eq? 'NoteEvent (ly:music-property z 'name)))
212 (ly:music-property lastev 'elements))
213 (ly:warning (_ "stealing the entirety of a note's time")))
214 (set! (ly:music-property lastev 'elements) '())
215 (set! ac:eventsBackward (cdr ac:eventsBackward))
216 (ac:stealTimeBackward (- tosteal levlen))))))))
218 % Debugging: display a moment plus some text.
219 % Returns its moment argument so can be used in-line.
220 #(define (display-moment text m)
222 (display (list (ly:moment-main-numerator m) "/" (ly:moment-main-denominator m)))
226 % Track tempo (and maybe later, other context properties)
227 % as they change. Needs to better cope with saving only Tempo I,
228 % otherwise "a tempo" goes back to the tempo before the last change.
229 #(define (ac:adjust-props sym music)
231 ((tempoWholesPerMinute)
232 (set! ac:currentTempo (ly:music-property music 'value))
233 (set! ac:lastTempo ac:currentTempo)
236 % Raise note one step in the current diatonic scale.
237 #(define (ac:up note)
238 (let* ((pitch (ly:music-property note 'pitch))
239 (notename (ly:pitch-notename pitch))
240 (new-notename (if (eq? notename 6) 0 (+ 1 notename)))
241 (alterations (ly:music-property ac:current-key 'pitch-alist))
242 (new-alteration (cdr (assq new-notename alterations)))
243 (new-octave (if (eq? new-notename 0) (+ 1 (ly:pitch-octave pitch))
244 (ly:pitch-octave pitch)))
246 (set! (ly:music-property note 'pitch)(ly:make-pitch new-octave new-notename new-alteration))))
249 % Lower note one step in the current diatonic scale.
250 #(define (ac:down note)
251 (begin (let* ((pitch (ly:music-property note 'pitch))
252 (notename (ly:pitch-notename pitch))
253 (new-notename (if (eq? notename 0) 6 (- notename 1)))
254 (alterations (ly:music-property ac:current-key 'pitch-alist))
255 (new-alteration (cdr (assq new-notename alterations)))
256 (new-octave (if (eq? new-notename 6) (- (ly:pitch-octave pitch) 1)
257 (ly:pitch-octave pitch)))
259 (set! (ly:music-property note 'pitch)(ly:make-pitch new-octave new-notename new-alteration))))
262 % Shorten a note, and save the note's original duration in ac:currentDuration
263 #(define (ac:articulate-one-note m fraction)
264 "Replace m with m*fraction"
265 (if (eq? 'NoteEvent (ly:music-property m 'name))
267 ((dur (ly:music-property m 'duration))
268 (l (ly:duration-log dur))
269 (d (ly:duration-dot-count dur))
270 (factor (ly:duration-factor dur))
272 (denom (cdr fraction)))
274 (set! ac:currentDuration dur)
275 (set! (ly:music-property m 'duration)
276 (ly:make-duration l d
278 (* denom (cdr factor))))))
281 % helper routine to set duration.
282 #(define (ac:setduration music duration)
283 "Set a note's duration."
284 (let ((eventtype (ly:music-property music 'name)))
287 (eq? eventtype 'NoteEvent)
288 (eq? eventtype 'RestEvent)
289 (eq? eventtype 'SkipEvent))
290 (set! (ly:music-property music 'duration) duration))))
292 % Add an articulation event to a note.
293 % Used in afterGrace to mark all notes as tenuto, so they're not shortened
294 #(define (ac:add-articulation type music)
295 (music-map (lambda (m)
296 (if (eq? 'EventChord (ly:music-property m 'name))
297 (set! (ly:music-property m 'elements)
298 (append (ly:music-property m 'elements)
299 (list (make-music 'ArticulationEvent 'articulation-type type)))))
303 % Convert a long note to an equivalent set of short notes, tied together.
304 % This is needed to get smooth dynamics changes.
305 % Need to deal properly with stuff other than the notes (dynamics, markup etc)
306 % Still experimental, so disabled for now.
307 #(define (ac:to128 music) music)
309 #(define (ac:to128_disabled music)
310 (if (or (eq? 'SkipEvent (ly:music-property music 'name))
311 (eq? 'NoteEvent (ly:music-property music 'name)))
312 (let* ((dur (ly:music-property music 'duration))
313 (log2 (ly:duration-log dur))
314 (shiftcount (- 6 log2))
315 (lastm (ly:music-deep-copy (shift-duration-log music shiftcount 0))))
316 (set! (ly:music-property music 'elements)
317 (cons (make-music 'TieEvent) (ly:music-property music 'elements)))
318 (make-sequential-music (list
319 (make-repeat "unfold" (1- (expt 2 shiftcount))
320 (make-sequential-music (list music)) '())
325 % absolute time in minutes of a length of music, as a rational number (moment)
326 #(define (ac:abstime music)
327 (ly:moment-div (ly:music-length music) ac:currentTempo))
329 % convert absolute time (in minutes) to a moment in the current tempo
330 #(define (ac:abs->mom m)
331 (ly:moment-mul m ac:currentTempo))
334 % a moment that is ac:maxTwiddletime seconds at the current tempo.
335 #(define (ac:targetTwiddleTime)
336 (ac:abs->mom ac:maxTwiddleTime))
339 % Nearest twiddletime (in minutes) achievable with power-of-2 divisions of
340 % the original music. (twiddletime is the time for one pair of notes
342 % If the music has a precomputed twiddletime (e.g., from \afterGrace) use that.
343 #(define (ac:twiddletime music)
344 (let* ((tr (filter (lambda (x)
345 (and (eq? 'ArticulationEvent (ly:music-property x 'name))
346 (string= "trill" (ly:music-property x 'articulation-type))))
347 (ly:music-property music 'elements)))
348 (pre-t (if (pair? tr) (ly:music-property (car tr) 'twiddle)
350 (hemisemidur (ly:make-duration 5 0 1/1))
351 (t (ac:targetTwiddleTime)))
352 (if (ly:moment? pre-t)
358 % Note: I'm assuming early music practice of starting on the auxiliary note.
359 % Needs to add gruppetto if it's a long trill (TODO)
360 #(define (ac:trill music)
361 " Replace music with time-compressed repeats of the music,
362 maybe accelerating if the length is longer than a crotchet "
363 (let* ((hemisemidur (ly:make-duration 5 0 1/1))
364 (orig-len (ly:music-length music))
365 (t (ac:twiddletime music))
367 (note_moment (ly:moment-mul t (ly:make-moment 1/2)))
368 (c1 (ly:moment-div orig-len t))
370 (round (/ (ly:moment-main-numerator c1)
371 (* 2 (ly:moment-main-denominator c1))))))
372 (count (if (< c2 2) 2 c2)))
374 (set! (ly:music-property music 'elements)
375 (filter (lambda (y) (eq? 'NoteEvent (ly:music-property y 'name)))
376 (ly:music-property music 'elements)))
377 (map (lambda (y) (ac:setduration y hemisemidur))
378 (ly:music-property music 'elements))
379 (set! uppernote (ly:music-deep-copy music))
380 (map (lambda (y) (ac:up y))
382 (lambda (z) (eq? 'NoteEvent (ly:music-property z 'name)))
383 (ly:music-property uppernote 'elements)))
385 (let* ((trillMusicElements
386 (let loop ((so_far (list uppernote music))
389 (loop (append (list (ly:music-deep-copy uppernote) (ly:music-deep-copy music)) so_far) (1- c))
391 (trillMusic (make-sequential-music trillMusicElements))
392 (newlen (ly:music-length trillMusic))
393 (factor (ly:moment-div orig-len newlen)))
394 (ly:music-compress trillMusic factor)
395 ; accelerating the music seems to put lily into an infinite loop in
396 ; its layout and midi engines.
397 ; (let* ((realfactor (exp (* (/ 1.0 count) (log 0.75))))
398 ; (factor (ly:make-moment (inexact->exact (round (* 1024 realfactor)))
400 ; (ac:accel trillMusic factor))
404 % Generate a tempoChangeEvent and its associated property setting.
406 #(define (ac:tempoChange tempo)
407 (make-sequential-music
408 (list (make-music 'TempoChangeEvent
412 (ly:make-duration 0 0 1/1))
414 (make-property-set 'tempoWholesPerMinute tempo) 'Score))))
417 % Totally unfold repeats, so that the non-obvious sequencing doesn't
418 % confuse us. This is necessary for time stealing to work, because
419 % that relies on the sequence in which we see events matching their
420 % audible sequence. Also unfold multi-measure rests to equivalent
421 % skips, with preceding and following bar checks, so that time stealing
422 % can change the length of the pause without falling foul of the
423 % implicit bar checks.
425 #(define (ac:unfoldMusic music)
428 (case (ly:music-property m 'name)
429 ((UnfoldedRepeatedMusic)
431 ((body (ly:music-property m 'element))
432 (altl (ly:music-property m 'elements))
433 (rc (ly:music-property m 'repeat-count)))
435 (make-sequential-music
436 (list-tabulate rc (lambda (i) (ly:music-deep-copy body))))
437 (let ((ealtl (if (> (length altl) rc) (take altl rc) altl)))
438 (make-sequential-music
442 (- rc (length ealtl))
443 (lambda (i) (list (ly:music-deep-copy body) (ly:music-deep-copy (car ealtl)))))
444 (map (lambda (alt) (list (ly:music-deep-copy body) alt)) ealtl))))))))
448 (partition (lambda (v) (eq? (ly:music-property v 'name) 'TremoloEvent))
449 (ly:music-property m 'elements))))
453 ((tremtype (ly:music-property (car trem) 'tremolo-type))
454 (tremtype-log (1- (integer-length tremtype)))
455 (durev (find (lambda (v) (not (null? (ly:music-property v 'duration)))) evl))
456 (totaldur (if durev (ly:music-property durev 'duration) (ly:make-duration tremtype-log 0 1)))
457 (tgt-nrep (/ (duration-visual-length totaldur) (duration-log-factor tremtype-log)))
458 (eff-nrep (max (truncate tgt-nrep) 1))
459 (tremdur (ly:make-duration tremtype-log 0
460 (* (/ tgt-nrep eff-nrep) (ly:duration-scale totaldur)))))
461 (or (and (= eff-nrep tgt-nrep) (= (ash 1 tremtype-log) tremtype))
462 (ly:warning (_ "non-integer tremolo ~a:~a")
463 (duration->lily-string (duration-visual totaldur) #:force-duration #t #:time-scale 1)
467 (or (null? (ly:music-property v 'duration))
468 (set! (ly:music-property v 'duration) tremdur)))
470 (set! (ly:music-property m 'elements) evl)
471 (make-sequential-music
472 (list-tabulate eff-nrep (lambda (i) (ly:music-deep-copy m))))))))
473 ((MultiMeasureRestMusic)
474 (make-sequential-music
476 (make-music 'BarCheck)
477 (make-music 'SkipMusic 'duration (ly:music-property m 'duration))
478 (make-music 'BarCheck))))
481 (unfold-repeats music)))
483 % If there's an articulation, use it.
484 % If in a slur, use (1 . 1) instead.
485 % Treat phrasing slurs as slurs, but allow explicit articulation.
486 % (Maybe should treat staccato under a phrasing slur as mezzo-staccato?)
488 % Expect an EventChord.
490 % trills, turns, ornaments etc. are also treated as Articulations.
491 % Split into two functions:
492 % ac:getactions traverses the elements in the EventChord
493 % and calculates the parameters.
494 % ac:articulate-chord applies the actions to each NoteEvent in
496 #(define (ac:getactions music)
497 (let loop ((factor ac:normalFactor)
499 (es (ly:music-property music 'elements))
503 (set! (ly:music-property music 'elements) (reverse newelements))
505 (not (any (lambda (m) (music-is-of-type? m 'rhythmic-event))
509 (let ((st ac:stealForward))
513 (set! ac:stealForward 0)
517 (ac:inTrill '(trill))
518 ((and (eq? factor ac:normalFactor) (or ac:inSlur ac:inPhrasingSlur))
519 (list 'articulation '(1 . 1)))
520 (else (list 'articulation factor))))))
524 (case (ly:music-property e 'name)
526 ((BeamEvent) ; throw away beam events, or they'll be duplicated by turn or trill
527 (loop factor newelements tail actions))
529 ((LineBreakEvent FingeringEvent MarkEvent BreathingEvent TieEvent SkipEvent RestEvent) ; pass through some events.
530 (loop (cons 1 1) (cons e newelements) tail actions))
533 (let ((articname (ly:music-property e 'articulation-type)))
534 ; TODO: add more here
536 ((string= articname "staccato")
537 (loop ac:staccatoFactor newelements tail actions))
538 ((string= articname "staccatissimo")
539 (loop ac:staccatissimoFactor newelements tail actions))
540 ((string= articname "tenuto")
541 (loop ac:tenutoFactor newelements tail actions))
542 ((string= articname "mordent")
543 (loop (cons 1 1) newelements tail (cons 'mordent actions)))
544 ((string= articname "prall")
545 (loop (cons 1 1) newelements tail (cons 'prall actions)))
546 ((string= articname "trill")
547 (loop (cons 1 1) newelements tail (cons 'trill actions)))
548 ((string= articname "turn")
549 (loop (cons 1 1) newelements tail (cons 'turn actions)))
550 (else (loop factor (cons e newelements) tail actions)))))
553 (let ((t (ly:music-property e 'text)))
554 (if (not (string? t))
555 (loop factor (cons e newelements) tail actions)
563 (loop factor (cons e newelements) tail (cons 'rall actions)))
565 (string= t "accelerando")
567 (string= t "accel."))
568 (loop factor (cons e newelements) tail (cons 'accel actions)))
570 (string= t "poco accel."))
571 (loop factor (cons e newelements) tail (cons 'pocoAccel actions)))
573 (string= t "poco rall.")
574 (string= t "poco rit."))
575 (loop factor (cons e newelements) tail (cons 'pocoRall actions)))
576 ((or (string= t "a tempo")
577 (string= t "tempo I"))
578 (loop factor (cons e newelements) tail (cons 'aTempo actions)))
579 (else (loop factor (cons e newelements) tail actions)))))))
582 (let ((direction (ly:music-property e 'span-direction)))
583 (set! ac:inSlur (eq? direction -1))
584 (loop factor newelements tail actions)))
587 (let ((direction (ly:music-property e 'span-direction)))
588 (set! ac:inTrill (eq? direction -1))
590 (loop factor newelements tail (cons 'trill actions))
591 (loop factor (cons e newelements) tail actions))))
594 (let ((direction (ly:music-property e 'span-direction)))
595 (set! ac:inPhrasingSlur (eq? direction -1))
596 (loop factor newelements tail actions)))
598 (else (loop factor (cons e newelements) tail actions)))))))
602 #(define (ac:articulate-chord music)
604 ((eq? 'EventChord (ly:music-property music 'name))
605 (ac:logEventsBackward
606 (let loop ((actions (ac:getactions music)))
608 (if (ly:moment<? (ly:make-moment 1/4) (ly:music-length music))
616 (lambda (x) (ac:articulate-one-note x (cadr actions)))
617 (ly:music-property music 'elements))
619 ((num (caadr actions))
620 (denom (cdadr actions))
621 (mult (ly:duration-factor ac:currentDuration))
622 (newnum (* (- denom num) (car mult)))
623 (newdenom (* (cdr mult) denom))
624 (len (ly:duration-log ac:currentDuration))
625 (dots (ly:duration-dot-count ac:currentDuration)))
627 (if (not (eq? num denom))
628 (make-sequential-music
629 (list (ac:to128 music)
630 (make-music 'EventChord 'elements
632 (make-music 'RestEvent 'duration (ly:make-duration len dots newnum newdenom))))))
636 (set! ac:lastTempo ac:currentTempo)
637 (set! ac:currentTempo (ly:moment-div ac:currentTempo ac:rallFactor))
638 (let ((pset (ac:tempoChange ac:currentTempo)))
639 (if (null? (cdr actions))
640 (make-sequential-music (list pset music))
641 (make-sequential-music
642 (list pset (loop (cdr actions)))))))
645 (set! ac:lastTempo ac:currentTempo)
646 (set! ac:currentTempo (ly:moment-div ac:currentTempo ac:pocoRallFactor))
647 (let ((pset (ac:tempoChange ac:currentTempo)))
648 (if (null? (cdr actions))
649 (make-sequential-music (list pset music))
650 (make-sequential-music
651 (list pset (loop (cdr actions)))))))
654 (set! ac:lastTempo ac:currentTempo)
655 (set! ac:currentTempo (ly:moment-mul ac:currentTempo ac:rallFactor))
656 (let ((pset (ac:tempoChange ac:currentTempo)))
657 (if (null? (cdr actions))
658 (make-sequential-music (list pset music))
659 (make-sequential-music
660 (list pset (loop (cdr actions)))))))
663 (set! ac:lastTempo ac:currentTempo)
664 (set! ac:currentTempo (ly:moment-mul ac:currentTempo ac:pocoRallFactor))
665 (let ((pset (ac:tempoChange ac:currentTempo)))
666 (if (null? (cdr actions))
667 (make-sequential-music (list pset music))
668 (make-sequential-music
669 (list pset (loop (cdr actions)))))))
672 (set! ac:currentTempo ac:lastTempo)
674 (let ((pset (ac:tempoChange ac:currentTempo)))
675 (if (null? (cdr actions))
676 (make-sequential-music (list pset music))
677 (make-sequential-music
678 (list pset (loop (cdr actions)))))))
684 ; A pralltriller symbol can either mean an inverted mordent
685 ; or a half-shake -- a short, two twiddle trill.
686 ; We implement as a half-shake.
688 ((totallength (ly:music-length music))
689 (newlen (ly:moment-sub totallength (ly:make-moment 3/32)))
690 (newdur (ly:make-duration
692 (ly:moment-main-numerator newlen)
693 (ly:moment-main-denominator newlen)))
694 (gracedur (ly:make-duration 5 0 1/1))
695 (gracenote (ly:music-deep-copy music))
696 (abovenote (ly:music-deep-copy music))
697 (mainnote (ly:music-deep-copy music))
698 (prall (make-sequential-music (list gracenote abovenote)))
700 (music-map (lambda (n)
701 (if (eq? 'NoteEvent (ly:music-property n 'name))
702 (set! (ly:music-property n 'duration) gracedur))
705 (music-map (lambda (n)
706 (if (eq? 'NoteEvent (ly:music-property n 'name))
707 (set! (ly:music-property n 'duration) gracedur))
710 (music-map (lambda (n)
711 (if (eq? 'NoteEvent (ly:music-property n 'name))
712 (set! (ly:music-property n 'duration) newdur))
716 (map (lambda (y) (ac:up y))
718 (lambda (z) (eq? 'NoteEvent (ly:music-property z 'name)))
719 (ly:music-property abovenote 'elements)))
720 (make-sequential-music (list abovenote gracenote abovenote mainnote))))
724 ((totaldur (ly:music-property
725 (car (ly:music-property music 'elements)) 'duration))
726 (dur (ly:duration-length totaldur))
727 (newlen (ly:moment-sub dur (ly:make-moment 2/32)))
728 (newdur (ly:make-duration
730 (ly:moment-main-numerator newlen)
731 (ly:moment-main-denominator newlen)))
732 (gracenote (ly:music-deep-copy music))
733 (belownote (ly:music-deep-copy music))
734 (mainnote (ly:music-deep-copy music))
735 (mordent (make-sequential-music (list gracenote belownote)))
738 (music-map (lambda (n)
739 (if (eq? 'NoteEvent (ly:music-property n 'name))
740 (set! (ly:music-property n 'duration)
741 (ly:make-duration 5 0 1/1)))
744 (music-map (lambda (n)
745 (if (eq? 'NoteEvent (ly:music-property n 'name))
746 (set! (ly:music-property n 'duration) newdur))
749 (map (lambda (y) (ac:down y))
751 (lambda (z) (eq? 'NoteEvent (ly:music-property z 'name)))
752 (ly:music-property belownote 'elements)))
753 (make-sequential-music (list mordent mainnote)))))
756 ((dur (ly:music-property
757 (car (ly:music-property music 'elements)) 'duration))
758 (factor (ly:duration-factor dur))
759 (newdur (ly:make-duration (+ (ly:duration-log dur) 2)
760 (ly:duration-dot-count dur) (car factor)(cdr factor))))
762 (map (lambda (y) (ac:setduration y newdur))
763 (ly:music-property music 'elements))
764 (let* ((above (ly:music-deep-copy music))
765 (below (ly:music-deep-copy music))
766 (newmusic (make-sequential-music (list above music below music))))
768 (map (lambda (y) (ac:down y))
770 (lambda (z) (eq? 'NoteEvent (ly:music-property z 'name)))
771 (ly:music-property below 'elements)))
772 (map (lambda (y) (ac:up y))
774 (lambda (z) (eq? 'NoteEvent (ly:music-property z 'name)))
775 (ly:music-property above 'elements)))
779 ((totallen (ly:moment-main (ly:music-length music)))
780 (steallen (cadr actions)))
781 (if (>= steallen totallen)
783 (if (any (lambda (z) (eq? 'NoteEvent (ly:music-property z 'name)))
784 (ly:music-property music 'elements))
785 (ly:warning (_ "stealing the entirety of a note's time")))
786 (set! ac:stealForward (- steallen totallen))
787 (make-sequential-music '()))
789 (ly:music-compress music (ly:make-moment (/ (- totallen steallen) totallen)))
790 (loop (cddr actions))))))
793 ((eq? 'GraceMusic (ly:music-property music 'name))
796 (call-with-current-continuation
800 (if (eq? 'EventChord (ly:music-property m 'name))
806 (let ((fev-pos (find-tail (lambda (m) (eq? m first-ev)) ac:eventsBackward)))
808 (set! ac:eventsBackward (cdr fev-pos))
809 (ly:warning (_ "articulation of grace notes has gone awry"))))))
811 ((gmus (ly:music-compress (ly:music-property music 'element)
812 (ly:make-moment ac:defaultGraceFactor)))
813 (glen (ly:moment-main (ly:music-length gmus))))
814 (ac:stealTimeBackward (* glen ac:defaultGraceBackwardness))
815 (set! ac:stealForward (+ ac:stealForward (* glen (- 1 ac:defaultGraceBackwardness))))
818 ((memq (ly:music-property music 'name) '(BarCheck SkipMusic))
819 (let ((totallen (ly:moment-main (ly:music-length music)))
820 (steallen ac:stealForward))
823 (ac:logEventsBackward music))
824 ((< steallen totallen)
825 (set! ac:stealForward 0)
826 (ac:logEventsBackward
827 (ly:music-compress music (ly:make-moment (/ (- totallen steallen) totallen)))))
829 (set! ac:stealForward (- steallen totallen))
830 (make-sequential-music '())))))
832 ((eq? 'KeyChangeEvent (ly:music-property music 'name))
833 (set! ac:current-key music)
836 ((eq? 'PropertySet (ly:music-property music 'name))
837 (ac:adjust-props (ly:music-property music 'symbol) music)
844 % At last ... here's the music function that applies all the above to a
846 articulate = #(define-music-function (parser location music)
848 "Adjust times of note to add tenuto, staccato and
849 normal articulations.
853 (set! ac:stealForward 0)
854 (set! ac:eventsBackward '()))
858 (ac:unfoldMusic (event-chord-wrap! music parser))))
860 (or (= ac:stealForward 0)
862 (ly:warning (_ "articulation failed to steal ~a note at end of music") ac:stealForward)
863 (set! ac:stealForward 0)))
864 (set! ac:eventsBackward '()))))
867 % Override \afterGrace to be in terms of audio, not spacing.
868 % Special handling for a gruppetto after a trill.
870 #(define-music-function
871 (parser location main grace)
872 (ly:music? ly:music?)
874 (set! main (event-chord-wrap! main parser))
875 (set! grace (event-chord-wrap! grace parser))
877 ((main-length (ly:music-length main))
878 (grace-orig-length (ly:music-length grace))
879 (gracelen (ac:twiddletime main))
880 (grace-factor (ly:moment-div gracelen grace-orig-length))
881 (new-main-length (ly:moment-sub main-length gracelen))
882 (factor (ly:moment-div new-main-length main-length))
884 (map (lambda (y) (set! (ly:music-property y 'twiddle) gracelen))
887 (eq? 'ArticulationEvent (ly:music-property z 'name))
888 (string= "trill" (ly:music-property z 'articulation-type))))
889 (ly:music-property main 'elements)))
890 (ac:add-articulation "tenuto" grace)
891 (make-sequential-music (list (ly:music-compress main factor) (ly:music-compress grace grace-factor)))))
893 % An appoggiatura takes half the duration of the main note,
894 % or 1/3 if the note is dotted (i.e., half the undotted equivalent time)
895 % Somewhere around the end of the 19th, start of 20th century the rules
896 % changed, but my main interest is early music.
898 #(define-music-function (parser location grace main)
899 (ly:music? ly:music?)
900 (set! grace (event-chord-wrap! grace parser))
901 (set! main (event-chord-wrap! main parser))
902 (let* ((maindur (ly:music-length main))
903 (grace-orig-len (ly:music-length grace))
904 (main-orig-len (ly:music-length main))
905 (numerator (ly:moment-main-numerator maindur))
906 (factor (if (eq? (remainder numerator 3) 0)
907 (ly:make-moment 1/3) (ly:make-moment 1/2))))
908 (ly:music-compress grace
909 (ly:moment-mul factor (ly:moment-div main-orig-len grace-orig-len)))
910 (ly:music-compress main (ly:moment-sub (ly:make-moment 1/1) factor))
912 (set! (ly:music-property grace 'elements)
913 (append (ly:music-property grace 'elements)
914 (list (make-music 'SlurEvent 'span-direction -1))))
915 (set! (ly:music-property main 'elements)
916 (append (ly:music-property main 'elements)
917 (list (make-music 'SlurEvent 'span-direction 1))))
918 (make-sequential-music (list grace main))))