2 auto-beam-engraver.cc -- implement Auto_beam_engraver
4 source file of the GNU LilyPond music typesetter
6 (c) 1999--2006 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 start_translation_timestep ();
31 void process_music ();
32 virtual void finalize ();
33 virtual void derived_mark () const;
35 DECLARE_ACKNOWLEDGER (rest);
36 DECLARE_ACKNOWLEDGER (beam);
37 DECLARE_ACKNOWLEDGER (bar_line);
38 DECLARE_ACKNOWLEDGER (stem);
39 DECLARE_TRANSLATOR_LISTENER (beam_forbid);
41 void process_acknowledged ();
44 bool test_moment (Direction, Moment);
45 void consider_begin (Moment);
46 void consider_end (Moment);
47 Spanner *create_beam ();
51 bool is_same_grace_state (Grob *e);
54 Stream_event *forbid_;
56 shortest_mom is the shortest note in the beam.
59 Spanner *finished_beam_;
60 vector<Item*> *stems_;
62 int process_acknowledged_count_;
65 Projected ending of the beam we're working on.
68 Moment beam_start_moment_;
69 Moment beam_start_location_;
71 bool subdivide_beams_;
74 // We act as if beam were created, and start a grouping anyway.
75 Beaming_pattern *grouping_;
78 Beaming_pattern *finished_grouping_;
80 void check_bar_property ();
84 Auto_beam_engraver::derived_mark () const
86 scm_gc_mark (beam_settings_);
90 Auto_beam_engraver::check_bar_property ()
92 /* Duplicated from process_music (), since
93 Repeat_acknowledge_engraver::process_music () may also set whichBar. */
95 Moment now = now_mom ();
96 if (scm_is_string (get_property ("whichBar"))
97 && beam_start_moment_ < now)
99 consider_end (shortest_mom_);
105 Auto_beam_engraver::process_music ()
107 if (scm_is_string (get_property ("whichBar")))
109 consider_end (shortest_mom_);
115 consider_end (shortest_mom_);
120 Auto_beam_engraver::Auto_beam_engraver ()
123 process_acknowledged_count_ = 0;
125 shortest_mom_ = Moment (Rational (1, 8));
127 finished_grouping_ = 0;
129 beam_settings_ = SCM_EOL;
132 IMPLEMENT_TRANSLATOR_LISTENER (Auto_beam_engraver, beam_forbid);
134 Auto_beam_engraver::listen_beam_forbid (Stream_event *ev)
136 ASSIGN_EVENT_ONCE (forbid_, ev);
140 Auto_beam_engraver::test_moment (Direction dir, Moment test)
142 return scm_call_3 (get_property ("autoBeamCheck"),
143 context ()->self_scm (),
145 test.smobbed_copy ())
150 Auto_beam_engraver::consider_begin (Moment test_mom)
152 bool on = to_boolean (get_property ("autoBeaming"));
156 bool b = test_moment (START, test_mom);
163 Auto_beam_engraver::consider_end (Moment test_mom)
167 /* Allow already started autobeam to end:
168 don't check for autoBeaming */
169 bool b = test_moment (STOP, test_mom);
176 Auto_beam_engraver::create_beam ()
178 if (to_boolean (get_property ("skipTypesetting")))
181 for (vsize i = 0; i < stems_->size (); i++)
182 if (Stem::get_beam ((*stems_)[i]))
186 Can't use make_spanner_from_properties() because we have to use
189 Spanner *beam = new Spanner (beam_settings_,
190 context ()->get_grob_key ("Beam"));
192 for (vsize i = 0; i < stems_->size (); i++)
193 Beam::add_stem (beam, (*stems_)[i]);
195 announce_grob (beam, (*stems_)[0]->self_scm ());
201 Auto_beam_engraver::begin_beam ()
203 if (stems_ || grouping_)
205 programming_error ("already have autobeam");
209 stems_ = new vector<Item*>;
210 grouping_ = new Beaming_pattern ();
211 beam_settings_ = updated_grob_properties (context (), ly_symbol2scm ("Beam"));
213 beam_start_moment_ = now_mom ();
215 = robust_scm2moment (get_property ("measurePosition"), Moment (0));
219 Auto_beam_engraver::junk_beam ()
228 beam_settings_ = SCM_EOL;
230 shortest_mom_ = Moment (Rational (1, 8));
234 Auto_beam_engraver::end_beam ()
236 if (stems_->size () < 2)
240 finished_beam_ = create_beam ();
242 finished_grouping_ = grouping_;
246 beam_settings_ = SCM_EOL;
249 shortest_mom_ = Moment (Rational (1, 8));
253 Auto_beam_engraver::typeset_beam ()
257 if (!finished_beam_->get_bound (RIGHT))
258 finished_beam_->set_bound (RIGHT, finished_beam_->get_bound (LEFT));
260 finished_grouping_->beamify (context ());
261 Beam::set_beaming (finished_beam_, finished_grouping_);
264 delete finished_grouping_;
265 finished_grouping_ = 0;
270 Auto_beam_engraver::start_translation_timestep ()
272 process_acknowledged_count_ = 0;
274 don't beam over skips
278 Moment now = now_mom ();
279 if (extend_mom_ < now)
286 Auto_beam_engraver::stop_translation_timestep ()
292 Auto_beam_engraver::finalize ()
294 /* finished beams may be typeset */
296 /* but unfinished may need another announce/acknowledge pass */
303 Auto_beam_engraver::acknowledge_beam (Grob_info info)
306 check_bar_property ();
312 Auto_beam_engraver::acknowledge_bar_line (Grob_info info)
315 check_bar_property ();
321 Auto_beam_engraver::acknowledge_rest (Grob_info info)
324 check_bar_property ();
330 Auto_beam_engraver::acknowledge_stem (Grob_info info)
332 check_bar_property ();
333 Item *stem = dynamic_cast<Item *> (info.grob ());
334 Stream_event *ev = info.ultimate_event_cause ();
335 if (!ev->in_event_class ("rhythmic-event"))
337 programming_error ("stem must have rhythmic structure");
342 Don't (start) auto-beam over empty stems; skips or rests
344 if (!Stem::head_count (stem))
351 if (Stem::get_beam (stem))
358 int durlog = unsmob_duration (ev->get_property ("duration"))->duration_log ();
370 Moment now = now_mom ();
371 if (bool (beam_start_location_.grace_part_) != bool (now.grace_part_))
374 Moment dur = unsmob_duration (ev->get_property ("duration"))->get_length ();
377 consider_begin (dur);
379 if (dur < shortest_mom_)
385 grouping_->add_stem (now - beam_start_moment_ + beam_start_location_,
387 stems_->push_back (stem);
389 extend_mom_ = max (extend_mom_, now) + get_event_length (ev);
393 Auto_beam_engraver::process_acknowledged ()
395 if (extend_mom_ > now_mom ())
398 if (!process_acknowledged_count_)
400 consider_end (shortest_mom_);
401 consider_begin (shortest_mom_);
403 else if (process_acknowledged_count_ > 1)
407 Moment now = now_mom ();
408 if ((extend_mom_ < now)
409 || ((extend_mom_ == now) && (last_add_mom_ != now)))
411 else if (!stems_->size ())
416 process_acknowledged_count_++;
419 ADD_ACKNOWLEDGER (Auto_beam_engraver, stem);
420 ADD_ACKNOWLEDGER (Auto_beam_engraver, bar_line);
421 ADD_ACKNOWLEDGER (Auto_beam_engraver, beam);
422 ADD_ACKNOWLEDGER (Auto_beam_engraver, rest);
423 ADD_TRANSLATOR (Auto_beam_engraver,
424 /* doc */ "Generate beams based on measure characteristics and observed "
425 "Stems. Uses beatLength, measureLength and measurePosition to decide "
426 "when to start and stop a beam. Overriding beaming is done through "
427 "@ref{Stem_engraver} properties @code{stemLeftBeamCount} and "
428 "@code{stemRightBeamCount}. ",
430 /* read */ "autoBeaming autoBeamSettings beatLength subdivideBeams",