]> git.donarmstrong.com Git - lilypond.git/blob - scm/music-functions.scm
* input/regression/markup-note.ly: new file
[lilypond.git] / scm / music-functions.scm
1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2 ;; tuplets.
3
4 (define-public (denominator-tuplet-formatter mus)
5   (number->string (ly:get-mus-property mus 'denominator)))
6
7 (define-public (fraction-tuplet-formatter mus)
8   (string-append (number->string (ly:get-mus-property mus 'numerator))
9                  ":"
10                  (number->string (ly:get-mus-property mus 'denominator))
11                  ))
12
13 ;; metronome marks
14 (define-public (make-metronome-markup event context)
15   (let*
16       ((dur  (ly:get-mus-property event 'tempo-unit))
17        (count (ly:get-mus-property event 'metronome-count))
18        (note-mark     (make-note-markup (ly:duration-log dur)
19                                         (ly:duration-dot-count dur)
20                                         1)
21                       )
22        )
23
24     (make-line-markup
25      (list
26       note-mark
27       (make-simple-markup  "=")
28       (make-simple-markup (number->string count))
29       
30   ))))
31
32 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
33
34 (define-public (music-map function music)
35   "Apply @var{function} to @var{music} and all of the music it contains. "
36   (let* ((es (ly:get-mus-property music 'elements))
37          (e (ly:get-mus-property music 'element))
38          )
39
40     (ly:set-mus-property! music 'elements 
41         (map (lambda (y) (music-map  function y)) es))
42         (if (ly:music? e)
43             (ly:set-mus-property! music 'element (music-map function  e)))
44         (function music)
45         ))
46
47 (define-public (display-music music)
48   "Display music, not done with music-map for clarity of presentation."
49   (display music)
50   (display ": { ")
51   
52   (let* ((es (ly:get-mus-property music 'elements))
53          (e (ly:get-mus-property music 'element))
54          )
55
56     (display (ly:get-mutable-properties music))
57
58     (if (pair?  es)
59         (begin (display "\nElements: {\n")
60                (map display-music es)
61                (display "}\n")
62         ))
63     
64     
65     (if (ly:music? e)
66         (begin
67           (display "\nChild:")
68           (display-music e)
69           )
70         )
71     )
72   (display " }\n")
73   music
74   )
75
76
77
78
79   
80 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
81
82 (define (shift-one-duration-log music shift dot)
83   "  add SHIFT to ly:duration-log and optionally 
84   a dot to any note encountered. This scales the music up by a factor 
85   2^shift * (2 - (1/2)^dot)"
86
87   (let*
88       (
89        (d (ly:get-mus-property music 'duration))
90        )
91     (if (ly:duration? d)
92         (let* (
93                (cp (ly:duration-factor d))
94                (nd (ly:make-duration (+ shift (ly:duration-log d))
95                                      (+ dot (ly:duration-dot-count d))
96                                      (car cp)
97                                      (cdr cp)))
98                
99                )
100           (ly:set-mus-property! music 'duration nd)
101           ))
102     music))
103
104
105
106 (define-public (shift-duration-log music shift dot)
107   (music-map (lambda (x) (shift-one-duration-log x shift dot))
108              music))
109   
110
111 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
112 ;; repeats.
113
114 (define-public (unfold-repeats music)
115 "
116 This function replaces all repeats  with unfold repeats. It was 
117 written by Rune Zedeler. "
118   (let* ((es (ly:get-mus-property music 'elements))
119          (e (ly:get-mus-property music 'element))
120          (n  (ly:music-name music)))
121  
122     (if (equal? n "Repeated_music")
123         (begin
124           (if (equal?
125                (ly:get-mus-property music 'iterator-ctor)
126                Chord_tremolo_iterator::constructor)
127               (shift-duration-log music  (ly:intlog2 (ly:get-mus-property music 'repeat-count)) 0)
128               )
129           (ly:set-mus-property!
130            music 'length Repeated_music::unfolded_music_length)
131           (ly:set-mus-property!
132            music 'start-moment-function Repeated_music::first_start)
133           (ly:set-mus-property!
134            music 'iterator-ctor Unfolded_repeat_iterator::constructor)))
135
136     (if (pair? es)
137         (ly:set-mus-property!
138          music 'elements
139          (map unfold-repeats es)))
140
141     (if (ly:music? e)
142         (ly:set-mus-property!
143          music 'element
144          (unfold-repeats e)))
145
146     music))
147
148
149 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
150 ;; property setting music objs.
151
152 (define-public (make-grob-property-set grob gprop val)
153
154   "Make a Music expression that sets GPROP to VAL in GROB. Does a pop first,
155 i.e.  this is not an override"
156   
157    (let* ((m (make-music-by-name  'OverrideProperty)))
158      (ly:set-mus-property! m 'symbol grob)
159      (ly:set-mus-property! m 'grob-property gprop)
160      (ly:set-mus-property! m 'grob-value val)
161      (ly:set-mus-property! m 'pop-first #t)
162                 
163      m
164    
165    ))
166
167
168 (define-public (make-grob-property-revert grob gprop)
169   "Revert the grob property GPROP for GROB."
170    (let* ((m (make-music-by-name  'OverrideProperty)))
171      (ly:set-mus-property! m 'symbol grob)
172      (ly:set-mus-property! m 'grob-property gprop)
173                 
174      m
175    
176    ))
177
178
179 (define-public (make-voice-props-set n)
180   (make-sequential-music
181    (append
182       (map (lambda (x) (make-grob-property-set x 'direction
183                                                (if (odd? n) -1 1)))
184            '(Tie Slur Stem Dots))
185       (list
186        (make-grob-property-set 'NoteColumn 'horizontal-shift (quotient n 2))
187        (make-grob-property-set 'MultiMeasureRest 'staff-position
188                                (if (odd? n) -4 4)
189                                )
190        
191        )
192    )
193   ))
194
195
196 (define-public (make-voice-props-revert)
197   (make-sequential-music
198    (list
199       (make-grob-property-revert 'Tie 'direction)
200       (make-grob-property-revert 'Dots 'direction)
201       (make-grob-property-revert 'Stem 'direction)
202       (make-grob-property-revert 'Slur 'direction)          
203       (make-grob-property-revert 'NoteColumn 'horizontal-shift)
204    ))
205   )
206
207
208 (define-public (context-spec-music m context . rest)
209   "Add \context CONTEXT = foo to M. "
210   
211   (let* ((cm (make-music-by-name 'ContextSpeccedMusic)))
212     (ly:set-mus-property! cm 'element m)
213     (ly:set-mus-property! cm 'context-type context)
214     (if (and  (pair? rest) (string? (car rest)))
215         (ly:set-mus-property! cm 'context-id (car rest))
216     )
217     cm
218   ))
219
220 (define-public (make-apply-context func)
221   (let*
222       (
223        (m (make-music-by-name 'ApplyContext))
224        )
225
226     (ly:set-mus-property! m 'procedure func)
227     m
228   ))
229
230 (define-public (make-sequential-music elts)
231   (let*  ((m (make-music-by-name 'SequentialMusic)))
232     (ly:set-mus-property! m 'elements elts)
233     m
234   ))
235
236 (define-public (make-simultaneous-music elts)
237   (let*  ((m (make-music-by-name 'SimultaneousMusic)))
238     (ly:set-mus-property! m 'elements elts)
239     m
240     ))
241
242 (define-public (make-event-chord elts)
243   (let*  ((m (make-music-by-name 'EventChord)))
244     (ly:set-mus-property! m 'elements elts)
245     m
246     ))
247
248
249 (define-public (make-multi-measure-rest duration location)
250   (let*
251       (
252        (start (make-music-by-name 'MultiMeasureRestEvent))
253        (stop  (make-music-by-name 'MultiMeasureRestEvent))
254        (skip ( make-music-by-name 'SkipEvent))
255        (ch (make-music-by-name 'BarCheck))
256        (ch2  (make-music-by-name 'BarCheck))
257        (seq  (make-music-by-name 'MultiMeasureRestMusicGroup))
258        )
259
260     (map (lambda (x) (ly:set-mus-property! x 'origin location))
261          (list start stop skip ch ch2 seq))
262     (ly:set-mus-property! start 'span-direction START)
263     (ly:set-mus-property! stop 'span-direction STOP)    
264     (ly:set-mus-property! skip 'duration duration)
265     (ly:set-mus-property! seq 'elements
266      (list
267       ch
268       (make-event-chord (list start))
269       (make-event-chord (list skip))
270       (make-event-chord (list stop))
271       ch2
272       ))
273
274     seq
275     ))
276
277 (define-public (glue-mm-rest-texts music)
278   "Check if we have R1*4-\markup { .. }, and if applicable convert to
279 a property set for MultiMeasureRestNumber."
280   
281   (define (script-to-mmrest-text script-music)
282     "Extract 'direction and 'text   from SCRIPT-MUSIC, and transform into property sets."
283     
284     (let*
285         (
286          (text (ly:get-mus-property script-music 'text))
287          (dir (ly:get-mus-property script-music 'direction))
288          (p (make-music-by-name 'MultiMeasureTextEvent))
289          )
290
291       (if (ly:dir? dir)
292           (ly:set-mus-property! p  'direction dir))
293       (ly:set-mus-property! p 'text text)
294       p
295     ))
296   
297   (if (eq? (ly:get-mus-property music 'name)  'MultiMeasureRestMusicGroup)
298       (let*
299           (
300            (text? (lambda (x) (memq 'script-event (ly:get-mus-property x 'types))))
301            (es (ly:get-mus-property  music 'elements))
302            (texts (map script-to-mmrest-text  (filter-list text? es)))
303            (others (filter-out-list text? es))
304            )
305         (if (pair? texts)
306             (ly:set-mus-property!
307              music 'elements
308              (cons (make-event-chord texts) others)
309             ))
310       ))
311   music
312   )
313
314
315 (define-public (make-property-set sym val)
316   (let*
317       (
318        (m (make-music-by-name 'PropertySet))
319        )
320     (ly:set-mus-property! m 'symbol sym)
321     (ly:set-mus-property! m 'value val)
322     m
323   ))
324
325 (define-public (make-time-signature-set num den . rest)
326   " Set properties for time signature NUM/DEN.
327 Rest can contain a list of beat groupings 
328
329 "
330   
331   (let*
332       (
333        (set1 (make-property-set 'timeSignatureFraction (cons num den) ))
334        (beat (ly:make-moment 1 den))
335        (len  (ly:make-moment num den))
336        (set2 (make-property-set 'beatLength beat))
337        (set3 (make-property-set 'measureLength len))
338        (set4 (make-property-set 'beatGrouping (if (pair? rest)
339                                                   (car rest)
340                                                   '())))
341        (basic  (list set1 set2 set3 set4))
342        
343        )
344
345     (context-spec-music
346      (make-sequential-music basic) "Timing")))
347
348 (define-public (set-time-signature num den . rest)
349   (ly:export (apply make-time-signature-set `(,num ,den . ,rest)))
350   )
351
352 (define-public (make-penalty-music pen)
353  (let
354      ((m (make-music-by-name 'BreakEvent)))
355    (ly:set-mus-property! m 'penalty pen)
356    m))
357
358 (define-public (make-articulation name)
359   (let* (
360          (m (make-music-by-name 'ArticulationEvent))
361       )
362       (ly:set-mus-property! m 'articulation-type name)
363       m
364   ))
365
366 (define-public (make-span-event type spandir)
367   (let* (
368          (m (make-music-by-name  type))
369          )
370     (ly:set-mus-property! m 'span-direction spandir)
371     m
372     ))
373
374 (define-public (set-mus-properties! m alist)
375   "Set all of ALIST as properties of M." 
376   (if (pair? alist)
377       (begin
378         (ly:set-mus-property! m (caar alist) (cdar alist))
379         (set-mus-properties! m (cdr alist)))
380   ))
381
382 (define-public (music-separator? m)
383   "Is M a separator?"
384   (let* ((ts (ly:get-mus-property m 'types )))
385     (memq 'separator ts)
386   ))
387
388
389 ;;; splitting chords into voices.
390
391 (define (voicify-list lst number)
392    "Make a list of Musics.
393
394    voicify-list :: [ [Music ] ] -> number -> [Music]
395    LST is a list music-lists.
396 "
397
398    (if (null? lst) '()
399        (cons (context-spec-music
400               (make-sequential-music
401                (list
402                 (make-voice-props-set number)
403                 (make-simultaneous-music (car lst))))
404
405               "Voice"  (number->string number))
406               (voicify-list (cdr lst) (+ number 1))
407        ))
408    )
409
410 (define (voicify-chord ch)
411   "Split the parts of a chord into different Voices using separator"
412    (let* ((es (ly:get-mus-property ch 'elements)))
413
414
415      (ly:set-mus-property!  ch 'elements
416        (voicify-list (split-list es music-separator?) 0))
417      ch
418    ))
419
420 (define (voicify-music m)
421    "Recursively split chords that are separated with \\ "
422    
423    (if (not (ly:music? m))
424        (begin (display m)
425        (error "not music!"))
426        )
427    (let*
428        ((es (ly:get-mus-property m 'elements))
429         (e (ly:get-mus-property m 'element))
430         )
431      (if (pair? es)
432          (ly:set-mus-property! m 'elements (map voicify-music es)))
433      (if (ly:music? e)
434          (ly:set-mus-property! m 'element  (voicify-music e)))
435      (if
436       (and (equal? (ly:music-name m) "Simultaneous_music")
437            (reduce (lambda (x y ) (or x y))     (map music-separator? es)))
438       (voicify-chord m)
439       )
440
441      m
442      ))
443
444 (define-public (empty-music)
445   (ly:export (make-music-by-name 'Music))
446   )
447 ;;;
448
449 ; Make a function that checks score element for being of a specific type. 
450 (define-public (make-type-checker symbol)
451   (lambda (elt)
452     ;;(display  symbol)
453     ;;(eq? #t (ly:get-grob-property elt symbol))
454     (not (eq? #f (memq symbol (ly:get-grob-property elt 'interfaces))))))
455
456
457 ;;
458 (define-public (smart-bar-check n)
459   "Make  a bar check that checks for a specific bar number. 
460 "
461   (let*
462       (
463        (m (make-music-by-name 'ApplyContext))
464        )
465     
466     (define (checker tr)
467       (let* ((bn (ly:get-context-property tr 'currentBarNumber)))
468         (if (= bn  n)
469             #t
470             (error
471              (format "Bar check failed, we should have reached ~a, instead at ~a\n"
472                      n bn ))
473             )))
474
475     (ly:set-mus-property! m 'procedure checker)
476     m
477     ))
478
479 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
480 ;; warn for bare chords at start.
481
482 (define (has-request-chord elts)
483   (reduce (lambda (x y) (or x y)) (map (lambda (x) (equal? (ly:music-name x)
484                                                            "Request_chord")) elts)
485   ))
486
487 (define (ly:music-message music msg)
488   (let*
489       (
490       (ip (ly:get-mus-property music 'origin))
491       )
492
493     (if (ly:input-location? ip)
494         (ly:input-message ip msg)
495         (ly:warn msg))
496   ))
497   
498 (define (check-start-chords music)
499   "Check music expression for a Simultaneous_music containing notes\n(ie. Request_chords), without context specification. Called  from parser."
500   
501      (let*
502        ((es (ly:get-mus-property music 'elements))
503         (e (ly:get-mus-property music 'element))
504         (name (ly:music-name music)) 
505         )
506
507        (cond 
508          ((equal? name "Context_specced_music") #t)
509          ((equal? name "Simultaneous_music")
510
511           (if (has-request-chord es)
512               (ly:music-message music "Starting score with a chord.\nPlease insert an explicit \\context before chord")
513               (map check-start-chords es)))
514          
515          ((equal? name "Sequential_music")
516            (if (pair? es)
517                (check-start-chords (car es))))
518           (else (if (ly:music? e) (check-start-chords e )))
519        
520        ))
521      music
522      )
523
524 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
525 ;; switch it on here, so parsing and init isn't checked (too slow!)
526
527 ;; automatic music transformations.
528
529 (define (switch-on-debugging m)
530   (set-debug-cell-accesses! 15000)
531   m
532   )
533
534 (define-public toplevel-music-functions
535   (list check-start-chords
536         voicify-music
537         (lambda (x) (music-map glue-mm-rest-texts x))
538 ; switch-on-debugging
539         ))
540
541