]> git.donarmstrong.com Git - lilypond.git/blob - lily/rest-collision-engraver.cc
Fix 59.
[lilypond.git] / lily / rest-collision-engraver.cc
1 /*
2   rest-collision-engraver.cc -- implement Rest_collision_engraver
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1997--2009 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 */
8
9 #include <list>
10
11 #include "duration.hh"
12 #include "engraver.hh"
13 #include "item.hh"
14 #include "moment.hh"
15 #include "note-column.hh"
16 #include "rest-collision.hh"
17 #include "stream-event.hh"
18 #include "warn.hh"
19
20 class Rest_collision_engraver : public Engraver
21 {
22   Item *rest_collision_;
23   vsize rest_count_;
24   list<pair<Grob*, Moment> > note_columns_;
25 protected:
26   DECLARE_ACKNOWLEDGER (note_column);
27   void process_acknowledged ();
28   void stop_translation_timestep ();
29   void start_translation_timestep ();
30 public:
31   TRANSLATOR_DECLARATIONS (Rest_collision_engraver);
32 };
33
34 Rest_collision_engraver::Rest_collision_engraver ()
35 {
36   rest_collision_ = 0;
37   rest_count_ = 0;
38 }
39
40 void
41 Rest_collision_engraver::process_acknowledged ()
42 {
43   if (rest_collision_
44       || note_columns_.empty ()
45       || !rest_count_
46       || (note_columns_.size () == rest_count_
47           && rest_count_ < 2))
48     return;
49
50   rest_collision_ = make_item ("RestCollision", SCM_EOL);
51
52   list<pair<Grob*, Moment> >::iterator i;
53   for (i = note_columns_.begin (); i != note_columns_.end (); i++)
54     Rest_collision::add_column (rest_collision_, i->first);
55 }
56
57 void
58 Rest_collision_engraver::acknowledge_note_column (Grob_info i)
59 {
60   Moment end = now_mom ();
61   if (Note_column::has_rests (i.grob ()))
62     rest_count_++;
63   else
64     {
65       // We only keep track of ending moments for columns with notes.
66       // It is safe to add a column with notes to multiple RestCollisions, but
67       // it might not be safe to add a column with rests to multiple RestCollisions.
68       Grob *stem = Note_column::get_stem (i.grob ());
69       Stream_event *ev = stem ? stem->event_cause () : 0;
70       Duration *dur_ptr = ev ? unsmob_duration (ev->get_property ("duration")) : 0;
71       if (dur_ptr)
72         {
73           if (end.grace_part_)
74             end.grace_part_ += dur_ptr->get_length ();
75           else
76             end.main_part_ += dur_ptr->get_length ();
77         }
78     }
79   note_columns_.push_back (pair<Grob*, Moment> (i.grob (), end));
80 }
81
82 void
83 Rest_collision_engraver::stop_translation_timestep ()
84 {
85   rest_collision_ = 0;
86   rest_count_ = 0;
87 }
88
89 void
90 Rest_collision_engraver::start_translation_timestep ()
91 {
92   list<pair<Grob*, Moment> >::iterator i = note_columns_.begin ();
93   while (i != note_columns_.end ())
94     {
95       if (i->second <= now_mom ())
96         i = note_columns_.erase (i);
97       else
98         i++;
99     }
100 }
101
102 #include "translator.icc"
103
104 ADD_ACKNOWLEDGER (Rest_collision_engraver, note_column);
105 ADD_TRANSLATOR (Rest_collision_engraver,
106                 /* doc */
107                 "Handle collisions of rests.",
108
109                 /* create */
110                 "RestCollision ",
111
112                 /* read */
113                 "",
114
115                 /* write */
116                 ""
117                 );