2 auto-beam-engraver.cc -- implement Auto_beam_engraver
4 source file of the GNU LilyPond music typesetter
6 (c) 1999--2007 Jan Nieuwenhuizen <janneke@gnu.org>
10 #include "beaming-pattern.hh"
13 #include "duration.hh"
14 #include "engraver.hh"
18 #include "stream-event.hh"
22 #include "translator.icc"
24 class Auto_beam_engraver
: public Engraver
26 TRANSLATOR_DECLARATIONS (Auto_beam_engraver
);
29 void stop_translation_timestep ();
30 void process_music ();
31 virtual void finalize ();
32 virtual void derived_mark () const;
34 DECLARE_ACKNOWLEDGER (rest
);
35 DECLARE_ACKNOWLEDGER (beam
);
36 DECLARE_ACKNOWLEDGER (bar_line
);
37 DECLARE_ACKNOWLEDGER (stem
);
38 DECLARE_TRANSLATOR_LISTENER (beam_forbid
);
40 void process_acknowledged ();
43 bool test_moment (Direction
, Moment
);
44 void consider_begin (Moment
);
45 void consider_end (Moment
);
46 Spanner
*create_beam ();
50 bool is_same_grace_state (Grob
*e
);
53 Stream_event
*forbid_
;
55 shortest_mom is the shortest note in the beam.
58 Spanner
*finished_beam_
;
59 vector
<Item
*> *stems_
;
61 int process_acknowledged_count_
;
64 Projected ending of the beam we're working on.
67 Moment beam_start_moment_
;
68 Moment beam_start_location_
;
70 // We act as if beam were created, and start a grouping anyway.
71 Beaming_pattern
*grouping_
;
74 Beaming_pattern
*finished_grouping_
;
77 Beaming_options beaming_options_
;
78 Beaming_options finished_beaming_options_
;
81 void check_bar_property ();
85 Auto_beam_engraver::derived_mark () const
87 scm_gc_mark (beam_settings_
);
91 Auto_beam_engraver::check_bar_property ()
93 /* Duplicated from process_music (), since
94 Repeat_acknowledge_engraver::process_music () may also set whichBar. */
96 Moment now
= now_mom ();
97 if (scm_is_string (get_property ("whichBar"))
98 && beam_start_moment_
< now
)
100 consider_end (shortest_mom_
);
106 Auto_beam_engraver::process_music ()
109 don't beam over skips
113 Moment now
= now_mom ();
114 if (extend_mom_
< now
)
118 if (scm_is_string (get_property ("whichBar")))
120 consider_end (shortest_mom_
);
126 consider_end (shortest_mom_
);
131 Auto_beam_engraver::Auto_beam_engraver ()
134 process_acknowledged_count_
= 0;
136 shortest_mom_
= Moment (Rational (1, 8));
138 finished_grouping_
= 0;
140 beam_settings_
= SCM_EOL
;
143 IMPLEMENT_TRANSLATOR_LISTENER (Auto_beam_engraver
, beam_forbid
);
145 Auto_beam_engraver::listen_beam_forbid (Stream_event
*ev
)
147 ASSIGN_EVENT_ONCE (forbid_
, ev
);
151 Auto_beam_engraver::test_moment (Direction dir
, Moment test
)
153 return scm_call_3 (get_property ("autoBeamCheck"),
154 context ()->self_scm (),
156 test
.smobbed_copy ())
161 Auto_beam_engraver::consider_begin (Moment test_mom
)
163 bool on
= to_boolean (get_property ("autoBeaming"));
167 bool b
= test_moment (START
, test_mom
);
174 Auto_beam_engraver::consider_end (Moment test_mom
)
178 /* Allow already started autobeam to end:
179 don't check for autoBeaming */
180 bool b
= test_moment (STOP
, test_mom
);
187 Auto_beam_engraver::create_beam ()
189 if (to_boolean (get_property ("skipTypesetting")))
192 for (vsize i
= 0; i
< stems_
->size (); i
++)
193 if (Stem::get_beam ((*stems_
)[i
]))
197 Can't use make_spanner_from_properties () because we have to use
200 Spanner
*beam
= new Spanner (beam_settings_
);
202 for (vsize i
= 0; i
< stems_
->size (); i
++)
203 Beam::add_stem (beam
, (*stems_
)[i
]);
205 announce_grob (beam
, (*stems_
)[0]->self_scm ());
211 Auto_beam_engraver::begin_beam ()
213 if (stems_
|| grouping_
)
215 programming_error ("already have autobeam");
219 stems_
= new vector
<Item
*>;
220 grouping_
= new Beaming_pattern ();
221 beaming_options_
.from_context (context ());
222 beam_settings_
= updated_grob_properties (context (), ly_symbol2scm ("Beam"));
224 beam_start_moment_
= now_mom ();
226 = robust_scm2moment (get_property ("measurePosition"), Moment (0));
230 Auto_beam_engraver::junk_beam ()
239 beam_settings_
= SCM_EOL
;
241 shortest_mom_
= Moment (Rational (1, 8));
245 Auto_beam_engraver::end_beam ()
247 if (stems_
->size () < 2)
251 finished_beam_
= create_beam ();
255 announce_end_grob (finished_beam_
, SCM_EOL
);
256 finished_grouping_
= grouping_
;
257 finished_beaming_options_
= beaming_options_
;
262 beam_settings_
= SCM_EOL
;
265 shortest_mom_
= Moment (Rational (1, 8));
269 Auto_beam_engraver::typeset_beam ()
273 if (!finished_beam_
->get_bound (RIGHT
))
274 finished_beam_
->set_bound (RIGHT
, finished_beam_
->get_bound (LEFT
));
276 finished_grouping_
->beamify (finished_beaming_options_
);
277 Beam::set_beaming (finished_beam_
, finished_grouping_
);
280 delete finished_grouping_
;
281 finished_grouping_
= 0;
286 Auto_beam_engraver::stop_translation_timestep ()
289 process_acknowledged_count_
= 0;
294 Auto_beam_engraver::finalize ()
296 /* finished beams may be typeset */
298 /* but unfinished may need another announce/acknowledge pass */
305 Auto_beam_engraver::acknowledge_beam (Grob_info info
)
308 check_bar_property ();
314 Auto_beam_engraver::acknowledge_bar_line (Grob_info info
)
317 check_bar_property ();
323 Auto_beam_engraver::acknowledge_rest (Grob_info info
)
326 check_bar_property ();
332 Auto_beam_engraver::acknowledge_stem (Grob_info info
)
334 check_bar_property ();
335 Item
*stem
= dynamic_cast<Item
*> (info
.grob ());
336 Stream_event
*ev
= info
.ultimate_event_cause ();
337 if (!ev
->in_event_class ("rhythmic-event"))
339 programming_error ("stem must have rhythmic structure");
344 Don't (start) auto-beam over empty stems; skips or rests
346 if (!Stem::head_count (stem
))
353 if (Stem::get_beam (stem
))
360 int durlog
= unsmob_duration (ev
->get_property ("duration"))->duration_log ();
372 Moment now
= now_mom ();
373 if (bool (beam_start_location_
.grace_part_
) != bool (now
.grace_part_
))
376 Moment dur
= unsmob_duration (ev
->get_property ("duration"))->get_length ();
379 consider_begin (dur
);
381 if (dur
< shortest_mom_
)
387 grouping_
->add_stem (now
- beam_start_moment_
+ beam_start_location_
,
389 Stem::is_invisible (stem
));
390 stems_
->push_back (stem
);
392 extend_mom_
= max (extend_mom_
, now
) + get_event_length (ev
, now
);
396 Auto_beam_engraver::process_acknowledged ()
398 if (extend_mom_
> now_mom ())
401 if (!process_acknowledged_count_
)
403 consider_end (shortest_mom_
);
404 consider_begin (shortest_mom_
);
406 else if (process_acknowledged_count_
> 1)
410 Moment now
= now_mom ();
411 if ((extend_mom_
< now
)
412 || ((extend_mom_
== now
) && (last_add_mom_
!= now
)))
414 else if (!stems_
->size ())
419 process_acknowledged_count_
++;
422 ADD_ACKNOWLEDGER (Auto_beam_engraver
, stem
);
423 ADD_ACKNOWLEDGER (Auto_beam_engraver
, bar_line
);
424 ADD_ACKNOWLEDGER (Auto_beam_engraver
, beam
);
425 ADD_ACKNOWLEDGER (Auto_beam_engraver
, rest
);
426 ADD_TRANSLATOR (Auto_beam_engraver
,
428 "Generate beams based on measure characteristics and observed"
429 " Stems. Uses @code{beatLength}, @code{measureLength}, and"
430 " @code{measurePosition} to decide when to start and stop a"
431 " beam. Overriding beaming is done through"
432 " @ref{Stem_engraver} properties @code{stemLeftBeamCount} and"
433 " @code{stemRightBeamCount}.",