]> git.donarmstrong.com Git - lilypond.git/blob - scm/music-functions.scm
* VERSION (MY_PATCH_LEVEL): make 1.7.0
[lilypond.git] / scm / music-functions.scm
1
2 (define (denominator-tuplet-formatter mus)
3   (number->string (ly-get-mus-property mus 'denominator)))
4
5 (define (fraction-tuplet-formatter mus)
6   (string-append (number->string (ly-get-mus-property mus 'numerator))
7                  ":"
8                  (number->string (ly-get-mus-property mus 'denominator))
9                  ))
10 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
11
12
13 (define (shift-duration-log music shift dot)
14   "Recurse through music, adding SHIFT to duration-log and optionally 
15   a dot to any note encountered. This scales the music up by a factor 
16   2^shift * (2 - (1/2)^dot)"
17   (let* ((es (ly-get-mus-property music 'elements))
18          (e (ly-get-mus-property music 'element))
19          (n  (ly-music-name music))
20          (f  (lambda (x)  (shift-duration-log x shift dot)))
21          )
22     (if (or (equal? n "Note_req")
23             (equal? n "Rest_req"))
24         (let* (
25                (d (ly-get-mus-property music 'duration))
26                (cp (duration-factor d))
27                (nd (make-duration (+ shift (duration-log d))
28                                   (+ dot (duration-dot-count d))
29                                   (car cp)
30                                   (cdr cp)))
31                
32                )
33           (ly-set-mus-property! music 'duration nd)
34           ))
35     
36     (if (pair? es)
37         (ly-set-mus-property!
38          music 'elements
39          (map f es)))
40     
41     (if (music? e)
42         (ly-set-mus-property!
43          music 'element
44          (f e)))
45     
46     music))
47
48
49 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
50 (define (unfold-repeats music)
51 "
52 This function replaces all repeats  with unfold repeats. It was 
53 written by Rune Zedeler. "
54   (let* ((es (ly-get-mus-property music 'elements))
55          (e (ly-get-mus-property music 'element))
56          (n  (ly-music-name music)))
57  
58     (if (equal? n "Repeated_music")
59         (begin
60           (if (equal?
61                (ly-get-mus-property music 'iterator-ctor)
62                Chord_tremolo_iterator::constructor)
63               (shift-duration-log music  (intlog2 (ly-get-mus-property music 'repeat-count)) 0)
64               )
65           (ly-set-mus-property!
66            music 'length Repeated_music::unfolded_music_length)
67           (ly-set-mus-property!
68            music 'start-moment-function Repeated_music::first_start)
69           (ly-set-mus-property!
70            music 'iterator-ctor Unfolded_repeat_iterator::constructor)))
71
72     (if (pair? es)
73         (ly-set-mus-property!
74          music 'elements
75          (map unfold-repeats es)))
76
77     (if (music? e)
78         (ly-set-mus-property!
79          music 'element
80          (unfold-repeats e)))
81
82     music))
83
84
85 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
86 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
87
88 (define  (pitchify-scripts music)
89   "Copy the pitch fields of the Note_requests into  Text_script_requests, to aid
90 Fingering_engraver."
91   (define (find-note musics)
92     (filter-list (lambda (m) (equal? (ly-music-name m) "Note_req")) musics)
93     )
94   (define (find-scripts musics)
95     (filter-list (lambda (m) (equal? (ly-music-name m) "Text_script_req")) musics))
96
97   (let* (
98          (e (ly-get-mus-property music 'element))
99          (es (ly-get-mus-property music 'elements))
100          (notes (find-note es))
101          (pitch (if (pair? notes) (ly-get-mus-property (car  notes) 'pitch) #f))
102          )
103
104     (if pitch
105         (map (lambda (x) (ly-set-mus-property! x 'pitch pitch)) (find-scripts es))
106         )
107         
108     (if (pair? es)
109         (ly-set-mus-property!
110          music 'elements
111          (map pitchify-scripts es)))
112
113     (if (music? e)
114         (ly-set-mus-property!
115          music 'element
116          (pitchify-scripts e)))
117
118     music))
119
120
121 ;;;;;;;;;;;;;;;;;
122 ;;;;;;;;;;;;;;;;
123 ;;;;;;;;;;;;;;;;
124
125
126 (define (make-grob-property-set grob gprop val)
127   "Make a M-exp that sets GPROP to VAL in GROBS. Does a pop first, i.e.
128 this is not an override 
129 "
130   
131    (let* ((m (ly-make-music  "Music")))
132      (ly-set-mus-property! m 'iterator-ctor Push_property_iterator::constructor)
133      (ly-set-mus-property! m 'symbol grob)
134      (ly-set-mus-property! m 'grob-property gprop)
135      (ly-set-mus-property! m 'grob-value val)
136      (ly-set-mus-property! m 'pop-first #t)
137                 
138      m
139    
140    ))
141    
142 (define (make-grob-property-revert grob gprop)
143   "Revert the grob property GPROP for GROB."
144    (let* ((m (ly-make-music  "Music")))
145      (ly-set-mus-property! m 'iterator-ctor Pop_property_iterator::constructor)
146      (ly-set-mus-property! m 'symbol grob)
147      (ly-set-mus-property! m 'grob-property gprop)
148                 
149      m
150    
151    ))
152    
153 (define (make-voice-props-set n)
154   (make-sequential-music
155    (append
156       (map (lambda (x) (make-grob-property-set x 'direction
157                                                (if (odd? n) -1 1)))
158            '(Tie Slur Stem Dots))
159       (list (make-grob-property-set 'NoteColumn 'horizontal-shift (quotient n 2)))
160    )
161   ))
162
163 (define (make-voice-props-revert)
164   (make-sequential-music
165    (list
166       (make-grob-property-revert 'Tie 'direction)
167       (make-grob-property-revert 'Dots 'direction)
168       (make-grob-property-revert 'Stem 'direction)
169       (make-grob-property-revert 'Slur 'direction)          
170       (make-grob-property-revert 'NoteColumn 'horizontal-shift)
171    ))
172   )
173
174 (define (context-spec-music m context . rest)
175   "Add \context CONTEXT = foo to M. "
176   
177   (let* ((cm (ly-make-music "Context_specced_music")))
178     (ly-set-mus-property! cm 'element m)
179     (ly-set-mus-property! cm 'context-type context)
180     (if (and  (pair? rest) (string? (car rest)))
181         (ly-set-mus-property! cm 'context-id (car rest))
182     )
183     cm
184   ))
185
186 (define (make-sequential-music elts)
187   (let*  ((m (ly-make-music "Sequential_music")))
188     (ly-set-mus-property! m 'elements elts)
189     m
190   ))
191 (define (make-simultaneous-music elts)
192   (let*  ((m (ly-make-music "Simultaneous_music")))
193     (ly-set-mus-property! m 'elements elts)
194     m
195     ))
196 (define (music-separator? m)
197   "Is M a separator."
198   (let* ((n (ly-get-mus-property m 'name )))
199     (and (symbol? n) (equal? 'separator n))
200   ))
201
202 (define (split-one sep?  l acc)
203   "Split off the first parts before separator and return both parts.
204
205 "
206   (if (null? l)
207       (cons acc '())
208       (if (sep? (car l))
209           (cons acc (cdr l))
210           (split-one sep? (cdr l) (cons (car l) acc))
211           )
212       ))
213
214 (define (split-list l sep?)
215   (if (null? l)
216       '()
217       (let* ((c (split-one sep? l '())))
218         (cons (reverse! (car c) '()) (split-list (cdr c) sep?))
219         )
220       )
221   )
222
223 ;; test code
224 ; (display (split-list '(a b c / d e f / g) (lambda (x) (equal? x '/))) )
225
226
227 ;;; splitting chords into voices.
228
229 (define (voicify-list lst number)
230    "Make a list of Musics.
231
232    voicify-list :: [ [Music ] ] -> number -> [Music]
233    LST is a list music-lists.
234 "
235
236    (if (null? lst) '()
237        (cons (context-spec-music
238               (make-sequential-music
239                (list
240                 (make-voice-props-set number)
241                 (make-simultaneous-music (car lst))))
242
243               "Voice"  (number->string number))
244               (voicify-list (cdr lst) (+ number 1))
245        ))
246    )
247
248 (define (voicify-chord ch)
249   "Split the parts of a chord into different Voices using separator"
250    (let* ((es (ly-get-mus-property ch 'elements)))
251
252
253      (ly-set-mus-property!  ch 'elements
254        (voicify-list (split-list es music-separator?) 0))
255      ch
256    ))
257
258 (define (voicify-music m)
259    "Recursively split chords that are separated with \\ "
260    
261    (if (not (music? m))
262        (begin (display m)
263        (error "not music!"))
264        )
265    (let*
266        ((es (ly-get-mus-property m 'elements))
267         (e (ly-get-mus-property m 'element))
268         )
269      (if (pair? es)
270          (ly-set-mus-property! m 'elements (map voicify-music es)))
271      (if (music? e)
272          (ly-set-mus-property! m 'element  (voicify-music e)))
273      (if
274       (and (equal? (ly-music-name m) "Simultaneous_music")
275            (reduce (lambda (x y ) (or x y))     (map music-separator? es)))
276       (voicify-chord m)
277       )
278
279      m
280      ))
281
282 ;;;
283
284 ;;;;;;;;;;;;;;;;
285 ;;;;;;;;;;;;;;;;
286
287 (define (has-request-chord elts)
288   (reduce (lambda (x y) (or x y)) (map (lambda (x) (equal? (ly-music-name x)
289                                                            "Request_chord")) elts)
290   ))
291
292 (define (ly-music-message music msg)
293   (let* (
294       (ip (ly-get-mus-property music 'origin))
295       )
296
297     (if (ly-input-location? ip)
298         (ly-input-message ip msg)
299         (ly-warn msg))
300   ))
301   
302 (define (check-start-chords music)
303   "Check music expression for a Simultaneous_music containing notes\n(ie. Request_chords), without context specification. Called  from parser."
304   
305      (let*
306        ((es (ly-get-mus-property music 'elements))
307         (e (ly-get-mus-property music 'element))
308         (name (ly-music-name music)) 
309         )
310
311        (cond 
312          ((equal? name "Context_specced_music") #t)
313          ((equal? name "Simultaneous_music")
314
315           (if (has-request-chord es)
316               (ly-music-message music "Starting score with a chord.\nPlease insert an explicit \\context before chord")
317               (map check-start-chords es)))
318          
319          ((equal? name "Sequential_music")
320            (if (pair? es)
321                (check-start-chords (car es))))
322           (else (if (music? e) (check-start-chords e )))
323        
324        ))
325      music
326      )
327
328
329 ;; switch it on here, so parsing and init isn't checked (too slow!)
330
331 (define (switch-on-debugging m)
332   (set-debug-cell-accesses! 15000)
333   m
334   )
335
336 (define toplevel-music-functions
337   (list check-start-chords
338         voicify-music
339
340 ; switch-on-debugging
341         ))