2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1997--2010 Han-Wen Nienhuys <hanwen@xs4all.nl>
6 LilyPond is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 LilyPond is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
23 #include "dispatcher.hh"
24 #include "duration.hh"
26 #include "international.hh"
27 #include "ly-smobs.icc"
29 #include "music-sequence.hh"
34 Music is anything that has (possibly zero) duration and supports
35 both time compression and transposition.
37 In Lily, everything that can be thought to have a length and a pitch
38 (which has a duration which can be transposed) is considered "music".
41 Music::internal_is_music_type (SCM k
) const
43 SCM ifs
= get_property ("types");
45 return scm_c_memq (k
, ifs
) != SCM_BOOL_F
;
48 Music::Music (SCM init
)
49 : Prob (ly_symbol2scm ("Music"), init
)
51 length_callback_
= SCM_EOL
;
52 start_callback_
= SCM_EOL
;
54 length_callback_
= get_property ("length-callback");
55 if (!ly_is_procedure (length_callback_
))
56 length_callback_
= duration_length_callback_proc
;
58 start_callback_
= get_property ("start-callback");
62 Music::derived_mark () const
64 scm_gc_mark (length_callback_
);
65 scm_gc_mark (start_callback_
);
69 Music::copy_mutable_properties () const
71 return ly_music_deep_copy (mutable_property_alist_
);
75 Music::type_check_assignment (SCM s
, SCM v
) const
77 ::type_check_assignment (s
, v
, ly_symbol2scm ("music-type?"));
80 Music::Music (Music
const &m
)
83 length_callback_
= m
.length_callback_
;
84 start_callback_
= m
.start_callback_
;
87 set_spot (*m
.origin ());
91 Music::get_length () const
93 SCM lst
= get_property ("length");
94 if (unsmob_moment (lst
))
95 return *unsmob_moment (lst
);
97 if (ly_is_procedure (length_callback_
))
99 SCM res
= scm_call_1 (length_callback_
, self_scm ());
100 return *unsmob_moment (res
);
107 Music::start_mom () const
109 SCM lst
= start_callback_
;
110 if (ly_is_procedure (lst
))
112 SCM res
= scm_call_1 (lst
, self_scm ());
113 return *unsmob_moment (res
);
121 print_alist (SCM a
, SCM port
)
123 /* SCM_EOL -> catch malformed lists. */
124 for (SCM s
= a
; scm_is_pair (s
); s
= scm_cdr (s
))
126 scm_display (scm_caar (s
), port
);
127 scm_puts (" = ", port
);
128 scm_write (scm_cdar (s
), port
);
129 scm_puts ("\n", port
);
135 Music::generic_to_relative_octave (Pitch last
)
137 SCM elt
= get_property ("element");
138 Pitch
*old_pit
= unsmob_pitch (get_property ("pitch"));
141 Pitch new_pit
= *old_pit
;
142 new_pit
= new_pit
.to_relative_octave (last
);
144 SCM check
= get_property ("absolute-octave");
145 if (scm_is_number (check
)
146 && new_pit
.get_octave () != scm_to_int (check
))
148 Pitch
expected_pit (scm_to_int (check
),
149 new_pit
.get_notename (),
150 new_pit
.get_alteration ());
151 origin ()->warning (_f ("octave check failed; expected \"%s\", found: \"%s\"",
152 expected_pit
.to_string (),
153 new_pit
.to_string ()));
154 new_pit
= expected_pit
;
157 set_property ("pitch", new_pit
.smobbed_copy ());
162 if (Music
*m
= unsmob_music (elt
))
163 last
= m
->to_relative_octave (last
);
165 last
= music_list_to_relative (get_property ("elements"), last
, false);
170 Music::to_relative_octave (Pitch last
)
172 SCM callback
= get_property ("to-relative-callback");
173 if (ly_is_procedure (callback
))
175 Pitch
*p
= unsmob_pitch (scm_call_2 (callback
, self_scm (),
176 last
.smobbed_copy ()));
180 return generic_to_relative_octave (last
);
184 Music::compress (Moment factor
)
186 SCM elt
= get_property ("element");
188 if (Music
*m
= unsmob_music (elt
))
189 m
->compress (factor
);
191 compress_music_list (get_property ("elements"), factor
);
192 Duration
*d
= unsmob_duration (get_property ("duration"));
194 set_property ("duration",
195 d
->compressed (factor
.main_part_
).smobbed_copy ());
199 This mutates alist. Hence, make sure that it is not shared
202 transpose_mutable (SCM alist
, Pitch delta
)
204 for (SCM s
= alist
; scm_is_pair (s
); s
= scm_cdr (s
))
206 SCM entry
= scm_car (s
);
207 SCM prop
= scm_car (entry
);
208 SCM val
= scm_cdr (entry
);
211 if (Pitch
*p
= unsmob_pitch (val
))
213 Pitch transposed
= p
->transposed (delta
);
214 if (transposed
.get_alteration ().abs () > Rational (1,1))
217 if (delta
.get_alteration ().abs () > Rational (1, 1))
218 delta_str
= (delta
.normalized ().to_string ()
219 + " " + _ ("(normalized pitch)"));
221 delta_str
= delta
.to_string ();
223 warning (_f ("Transposing %s by %s makes alteration larger than double",
226 transposed
= transposed
.normalized ();
229 new_val
= transposed
.smobbed_copy ();
231 else if (prop
== ly_symbol2scm ("element"))
233 if (Music
*m
= unsmob_music (val
))
234 m
->transpose (delta
);
236 else if (prop
== ly_symbol2scm ("elements"))
237 transpose_music_list (val
, delta
);
238 else if (prop
== ly_symbol2scm ("pitch-alist") &&
240 new_val
= ly_transpose_key_alist (val
, delta
.smobbed_copy ());
243 scm_set_cdr_x (entry
, new_val
);
248 Music::transpose (Pitch delta
)
250 if (to_boolean (get_property ("untransposable")))
253 transpose_mutable (mutable_property_alist_
, delta
);
257 Music::set_spot (Input ip
)
259 set_property ("origin", make_input (ip
));
263 Music::origin () const
265 Input
*ip
= unsmob_input (get_property ("origin"));
266 return ip
? ip
: &dummy_input_global
;
270 ES TODO: This method should probably be reworked or junked.
273 Music::to_event () const
275 SCM class_name
= ly_camel_case_2_lisp_identifier (get_property ("name"));
277 // catch programming mistakes.
278 if (!internal_is_music_type (class_name
))
279 programming_error ("Not a music type");
281 Stream_event
*e
= new Stream_event (class_name
, mutable_property_alist_
);
282 Moment length
= get_length ();
283 if (length
.to_bool ())
284 e
->set_property ("length", length
.smobbed_copy ());
286 // articulations as events.
287 SCM art_mus
= e
->get_property ("articulations");
288 if (scm_is_pair (art_mus
))
290 SCM art_ev
= SCM_EOL
;
291 for (; scm_is_pair (art_mus
); art_mus
= scm_cdr (art_mus
))
293 Music
*m
= unsmob_music (scm_car (art_mus
));
294 SCM ev
= m
? m
->to_event ()->unprotect () : scm_car (art_mus
);
295 art_ev
= scm_cons (ev
, art_ev
);
297 e
->set_property ("articulations", scm_reverse_x (art_ev
, SCM_EOL
));
301 ES TODO: This is a temporary fix. Stream_events should not be
304 e
->set_property ("music-cause", self_scm ());
310 Music::send_to_context (Context
*c
)
312 Stream_event
*ev
= to_event ();
313 c
->event_source ()->broadcast (ev
);
318 make_music_by_name (SCM sym
)
320 SCM make_music_proc
= ly_lily_module_constant ("make-music");
321 SCM rv
= scm_call_1 (make_music_proc
, sym
);
324 Music
*m
= unsmob_music (rv
);
329 MAKE_SCHEME_CALLBACK (Music
, duration_length_callback
, 1);
331 Music::duration_length_callback (SCM m
)
333 Music
*me
= unsmob_music (m
);
334 Duration
*d
= unsmob_duration (me
->get_property ("duration"));
338 mom
= d
->get_length ();
339 return mom
.smobbed_copy ();
345 return dynamic_cast<Music
*> (unsmob_prob (m
));