2 music.cc -- implement Music
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2007 Han-Wen Nienhuys <hanwen@xs4all.nl>
12 #include "dispatcher.hh"
13 #include "duration.hh"
15 #include "international.hh"
16 #include "ly-smobs.icc"
18 #include "music-sequence.hh"
23 Music is anything that has (possibly zero) duration and supports
24 both time compression and transposition.
26 In Lily, everything that can be thought to have a length and a pitch
27 (which has a duration which can be transposed) is considered "music".
30 Music::internal_is_music_type (SCM k
) const
32 SCM ifs
= get_property ("types");
34 return scm_c_memq (k
, ifs
) != SCM_BOOL_F
;
37 Music::Music (SCM init
)
38 : Prob (ly_symbol2scm ("Music"), init
)
40 length_callback_
= SCM_EOL
;
41 start_callback_
= SCM_EOL
;
43 length_callback_
= get_property ("length-callback");
44 if (!ly_is_procedure (length_callback_
))
45 length_callback_
= duration_length_callback_proc
;
47 start_callback_
= get_property ("start-callback");
51 Music::derived_mark () const
53 scm_gc_mark (length_callback_
);
54 scm_gc_mark (start_callback_
);
58 Music::copy_mutable_properties () const
60 return ly_music_deep_copy (mutable_property_alist_
);
64 Music::type_check_assignment (SCM s
, SCM v
) const
66 ::type_check_assignment (s
, v
, ly_symbol2scm ("music-type?"));
69 Music::Music (Music
const &m
)
72 length_callback_
= m
.length_callback_
;
73 start_callback_
= m
.start_callback_
;
76 set_spot (*m
.origin ());
80 Music::get_length () const
82 SCM lst
= get_property ("length");
83 if (unsmob_moment (lst
))
84 return *unsmob_moment (lst
);
86 if (ly_is_procedure (length_callback_
))
88 SCM res
= scm_call_1 (length_callback_
, self_scm ());
89 return *unsmob_moment (res
);
96 Music::start_mom () const
98 SCM lst
= start_callback_
;
99 if (ly_is_procedure (lst
))
101 SCM res
= scm_call_1 (lst
, self_scm ());
102 return *unsmob_moment (res
);
110 print_alist (SCM a
, SCM port
)
112 /* SCM_EOL -> catch malformed lists. */
113 for (SCM s
= a
; scm_is_pair (s
); s
= scm_cdr (s
))
115 scm_display (scm_caar (s
), port
);
116 scm_puts (" = ", port
);
117 scm_write (scm_cdar (s
), port
);
118 scm_puts ("\n", port
);
124 Music::generic_to_relative_octave (Pitch last
)
126 SCM elt
= get_property ("element");
127 Pitch
*old_pit
= unsmob_pitch (get_property ("pitch"));
130 Pitch new_pit
= *old_pit
;
131 new_pit
= new_pit
.to_relative_octave (last
);
133 SCM check
= get_property ("absolute-octave");
134 if (scm_is_number (check
)
135 && new_pit
.get_octave () != scm_to_int (check
))
137 Pitch
expected_pit (scm_to_int (check
),
138 new_pit
.get_notename (),
139 new_pit
.get_alteration ());
140 origin ()->warning (_f ("octave check failed; expected \"%s\", found: \"%s\"",
141 expected_pit
.to_string (),
142 new_pit
.to_string ()));
143 new_pit
= expected_pit
;
146 set_property ("pitch", new_pit
.smobbed_copy ());
151 if (Music
*m
= unsmob_music (elt
))
152 last
= m
->to_relative_octave (last
);
154 last
= music_list_to_relative (get_property ("elements"), last
, false);
159 Music::to_relative_octave (Pitch last
)
161 SCM callback
= get_property ("to-relative-callback");
162 if (ly_is_procedure (callback
))
164 Pitch
*p
= unsmob_pitch (scm_call_2 (callback
, self_scm (), last
.smobbed_copy ()));
168 return generic_to_relative_octave (last
);
172 Music::compress (Moment factor
)
174 SCM elt
= get_property ("element");
176 if (Music
*m
= unsmob_music (elt
))
177 m
->compress (factor
);
179 compress_music_list (get_property ("elements"), factor
);
180 Duration
*d
= unsmob_duration (get_property ("duration"));
182 set_property ("duration", d
->compressed (factor
.main_part_
).smobbed_copy ());
186 This mutates alist. Hence, make sure that it is not shared
189 transpose_mutable (SCM alist
, Pitch delta
)
191 for (SCM s
= alist
; scm_is_pair (s
); s
= scm_cdr (s
))
193 SCM entry
= scm_car (s
);
194 SCM prop
= scm_car (entry
);
195 SCM val
= scm_cdr (entry
);
198 if (Pitch
*p
= unsmob_pitch (val
))
200 Pitch transposed
= p
->transposed (delta
);
201 if (transposed
.get_alteration ().abs () > Rational (1,1))
203 warning (_f ("transposition by %s makes alteration larger than double",
204 delta
.to_string ()));
207 new_val
= transposed
.smobbed_copy ();
209 else if (prop
== ly_symbol2scm ("element"))
211 if (Music
*m
= unsmob_music (val
))
212 m
->transpose (delta
);
214 else if (prop
== ly_symbol2scm ("elements"))
215 transpose_music_list (val
, delta
);
216 else if (prop
== ly_symbol2scm ("pitch-alist") &&
218 new_val
= ly_transpose_key_alist (val
, delta
.smobbed_copy ());
221 scm_set_cdr_x (entry
, new_val
);
226 Music::transpose (Pitch delta
)
228 if (to_boolean (get_property ("untransposable")))
231 transpose_mutable (mutable_property_alist_
, delta
);
235 Music::set_spot (Input ip
)
237 set_property ("origin", make_input (ip
));
241 Music::origin () const
243 Input
*ip
= unsmob_input (get_property ("origin"));
244 return ip
? ip
: &dummy_input_global
;
248 ES TODO: This method should probably be reworked or junked.
251 Music::to_event () const
253 SCM class_name
= ly_camel_case_2_lisp_identifier (get_property ("name"));
255 // catch programming mistakes.
256 if (!internal_is_music_type (class_name
))
258 programming_error ("Not a music type");
261 Stream_event
*e
= new Stream_event (class_name
, mutable_property_alist_
);
262 Moment length
= get_length ();
263 if (length
.to_bool ())
264 e
->set_property ("length", length
.smobbed_copy ());
266 // articulations as events.
267 SCM art_mus
= e
->get_property ("articulations");
268 if (scm_is_pair (art_mus
))
270 SCM art_ev
= SCM_EOL
;
271 for (; scm_is_pair (art_mus
); art_mus
= scm_cdr (art_mus
))
273 Music
*m
= unsmob_music (scm_car (art_mus
));
274 SCM ev
= m
? m
->to_event ()->unprotect () : scm_car (art_mus
);
275 art_ev
= scm_cons (ev
, art_ev
);
277 e
->set_property ("articulations", scm_reverse_x (art_ev
, SCM_EOL
));
281 ES TODO: This is a temporary fix. Stream_events should not be
284 e
->set_property ("music-cause", self_scm ());
290 Music::send_to_context (Context
*c
)
292 Stream_event
*ev
= to_event ();
293 c
->event_source ()->broadcast (ev
);
298 make_music_by_name (SCM sym
)
300 SCM make_music_proc
= ly_lily_module_constant ("make-music");
301 SCM rv
= scm_call_1 (make_music_proc
, sym
);
304 Music
*m
= unsmob_music (rv
);
309 MAKE_SCHEME_CALLBACK (Music
, duration_length_callback
, 1);
311 Music::duration_length_callback (SCM m
)
313 Music
*me
= unsmob_music (m
);
314 Duration
*d
= unsmob_duration (me
->get_property ("duration"));
318 mom
= d
->get_length ();
319 return mom
.smobbed_copy ();
325 return dynamic_cast<Music
*> (unsmob_prob (m
));