2 spacing-engraver.cc -- implement Spacing_engraver
4 source file of the GNU LilyPond music typesetter
6 (c) 1999--2009 Han-Wen Nienhuys <hanwen@xs4all.nl>
11 #include "note-spacing.hh"
12 #include "paper-column.hh"
13 #include "pointer-group-interface.hh"
16 #include "staff-spacing.hh"
17 #include "stream-event.hh"
19 #include "translator.icc"
29 Rhythmic_tuple (Grob_info i
, Moment m
)
34 static int time_compare (Rhythmic_tuple
const &, Rhythmic_tuple
const &);
38 compare (Rhythmic_tuple
const &a
, Rhythmic_tuple
const &b
)
40 return Rhythmic_tuple::time_compare (a
, b
);
44 Rhythmic_tuple::time_compare (Rhythmic_tuple
const &h1
,
45 Rhythmic_tuple
const &h2
)
47 return (h1
.end_
- h2
.end_
).main_part_
.sign ();
50 /****************************************************************/
53 Acknowledge rhythmic elements, for initializing spacing fields in
56 class Spacing_engraver
: public Engraver
58 PQueue
<Rhythmic_tuple
> playing_durations_
;
59 vector
<Rhythmic_tuple
> now_durations_
;
60 vector
<Rhythmic_tuple
> stopped_durations_
;
63 Stream_event
*start_section_
;
65 TRANSLATOR_DECLARATIONS (Spacing_engraver
);
68 DECLARE_ACKNOWLEDGER (staff_spacing
);
69 DECLARE_ACKNOWLEDGER (note_spacing
);
70 DECLARE_ACKNOWLEDGER (rhythmic_head
);
71 DECLARE_ACKNOWLEDGER (rhythmic_grob
);
72 DECLARE_TRANSLATOR_LISTENER (spacing_section
);
74 void start_translation_timestep ();
75 void stop_translation_timestep ();
76 void process_music ();
77 void add_starter_duration (Grob_info i
);
79 virtual void finalize ();
81 void start_spanner ();
85 Spacing_engraver::Spacing_engraver ()
91 IMPLEMENT_TRANSLATOR_LISTENER (Spacing_engraver
, spacing_section
);
93 Spacing_engraver::listen_spacing_section (Stream_event
*ev
)
95 ASSIGN_EVENT_ONCE (start_section_
, ev
);
99 Spacing_engraver::process_music ()
101 if (start_section_
&& spacing_
)
109 Spacing_engraver::start_spanner ()
114 spacing_
= make_spanner ("SpacingSpanner", SCM_EOL
);
115 spacing_
->set_bound (LEFT
,
116 unsmob_grob (get_property ("currentCommandColumn")));
120 Spacing_engraver::finalize ()
126 Spacing_engraver::stop_spanner ()
130 Grob
*p
= unsmob_grob (get_property ("currentCommandColumn"));
132 spacing_
->set_bound (RIGHT
, p
);
138 Spacing_engraver::acknowledge_note_spacing (Grob_info i
)
140 Pointer_group_interface::add_grob (spacing_
, ly_symbol2scm ("wishes"), i
.grob ());
144 Spacing_engraver::acknowledge_staff_spacing (Grob_info i
)
146 Pointer_group_interface::add_grob (spacing_
, ly_symbol2scm ("wishes"), i
.grob ());
150 Spacing_engraver::acknowledge_rhythmic_grob (Grob_info i
)
152 add_starter_duration (i
);
156 Spacing_engraver::acknowledge_rhythmic_head (Grob_info i
)
158 add_starter_duration (i
);
163 Spacing_engraver::add_starter_duration (Grob_info i
)
165 if (i
.grob ()->internal_has_interface (ly_symbol2scm ("lyric-syllable-interface"))
166 || i
.grob ()->internal_has_interface (ly_symbol2scm ("multi-measure-interface")))
170 only pay attention to durations that are not grace notes.
172 if (!now_
.grace_part_
)
174 Stream_event
*r
= i
.event_cause ();
175 if (r
&& r
->in_event_class ("rhythmic-event"))
177 Moment len
= get_event_length (r
, now_
);
178 Rhythmic_tuple
t (i
, now_mom () + len
);
179 now_durations_
.push_back (t
);
185 Spacing_engraver::stop_translation_timestep ()
187 Paper_column
*musical_column
188 = dynamic_cast<Paper_column
*> (unsmob_grob (get_property ("currentMusicalColumn")));
194 musical_column
->set_object ("spacing", spacing_
->self_scm ());
195 unsmob_grob (get_property ("currentCommandColumn"))
196 ->set_object ("spacing", spacing_
->self_scm ());
198 SCM proportional
= get_property ("proportionalNotationDuration");
199 if (unsmob_moment (proportional
))
201 musical_column
->set_property ("shortest-playing-duration", proportional
);
202 musical_column
->set_property ("shortest-starter-duration", proportional
);
203 musical_column
->set_property ("used", SCM_BOOL_T
);
207 Moment shortest_playing
;
208 shortest_playing
.set_infinite (1);
209 for (vsize i
= 0; i
< playing_durations_
.size (); i
++)
211 Stream_event
*ev
= playing_durations_
[i
].info_
.event_cause ();
214 Moment now
= now_mom ();
215 Moment m
= get_event_length (ev
);
216 shortest_playing
= min (shortest_playing
, m
);
220 starter
.set_infinite (1);
222 for (vsize i
= 0; i
< now_durations_
.size (); i
++)
224 Moment m
= get_event_length (now_durations_
[i
].info_
.event_cause ());
227 starter
= min (starter
, m
);
228 playing_durations_
.insert (now_durations_
[i
]);
231 now_durations_
.clear ();
233 shortest_playing
= min (shortest_playing
, starter
);
235 assert (starter
.to_bool ());
236 SCM sh
= shortest_playing
.smobbed_copy ();
237 SCM st
= starter
.smobbed_copy ();
239 musical_column
->set_property ("shortest-playing-duration", sh
);
240 musical_column
->set_property ("shortest-starter-duration", st
);
246 Spacing_engraver::start_translation_timestep ()
251 stopped_durations_
.clear ();
253 while (playing_durations_
.size () && playing_durations_
.front ().end_
< now_
)
254 playing_durations_
.delmin ();
255 while (playing_durations_
.size () && playing_durations_
.front ().end_
== now_
)
256 stopped_durations_
.push_back (playing_durations_
.get ());
259 ADD_ACKNOWLEDGER (Spacing_engraver
, staff_spacing
);
260 ADD_ACKNOWLEDGER (Spacing_engraver
, note_spacing
);
261 ADD_ACKNOWLEDGER (Spacing_engraver
, rhythmic_head
);
262 ADD_ACKNOWLEDGER (Spacing_engraver
, rhythmic_grob
);
264 ADD_TRANSLATOR (Spacing_engraver
,
266 "Make a @code{SpacingSpanner} and do bookkeeping of shortest"
267 " starting and playing notes.",
273 "currentMusicalColumn "
274 "currentCommandColumn "
275 "proportionalNotationDuration ",