]> git.donarmstrong.com Git - lilypond.git/blob - lily/completion-rest-engraver.cc
3d8d7211ff97393e5978370bb126c43dd3449a0e
[lilypond.git] / lily / completion-rest-engraver.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1997--2011 Han-Wen Nienhuys <hanwen@xs4all.nl>
5                            Jan Nieuwenhuizen <janneke@gnu.org>
6
7   LilyPond is free software: you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation, either version 3 of the License, or
10   (at your option) any later version.
11
12   LilyPond is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include <cctype>
22 using namespace std;
23
24 #include "dot-column.hh"
25 #include "dots.hh"
26 #include "duration.hh"
27 #include "global-context.hh"
28 #include "item.hh"
29 #include "output-def.hh"
30 #include "pitch.hh"
31 #include "pqueue.hh"
32 #include "rhythmic-head.hh"
33 #include "score-engraver.hh"
34 #include "spanner.hh"
35 #include "staff-symbol-referencer.hh"
36 #include "stream-event.hh"
37 #include "tie.hh"
38 #include "warn.hh"
39
40 #include "translator.icc"
41
42 /*
43   How does this work?
44
45   When we catch the rest, we predict the end of the rest. We keep the
46   events living until we reach the predicted end-time.
47
48   Every time process_music () is called and there are rest events, we
49   figure out how long the rest to typeset should be. It should be no
50   longer than what's specified, than what is left to do and it should
51   not cross barlines.
52
53   We copy the events into scratch rest events, to make sure that we get
54   all durations exactly right.
55 */
56
57 class Completion_rest_engraver : public Engraver
58 {
59   vector<Item*> rests_;
60   vector<Item*> prev_rests_;
61   vector<Stream_event*> rest_events_;
62   Moment rest_end_mom_;
63   bool is_first_;
64   Rational left_to_do_;
65   Rational do_nothing_until_;
66   Rational factor_;
67
68   Moment next_barline_moment ();
69   Item *make_rest (Stream_event*);
70
71 public:
72   TRANSLATOR_DECLARATIONS (Completion_rest_engraver);
73
74 protected:
75   virtual void initialize ();
76   void start_translation_timestep ();
77   void process_music ();
78   void stop_translation_timestep ();
79   DECLARE_TRANSLATOR_LISTENER (rest);
80 };
81
82 void
83 Completion_rest_engraver::initialize ()
84 {
85   is_first_ = false;
86 }
87
88 IMPLEMENT_TRANSLATOR_LISTENER (Completion_rest_engraver, rest);
89 void
90 Completion_rest_engraver::listen_rest (Stream_event *ev)
91 {
92   rest_events_.push_back (ev);
93   
94   is_first_ = true;
95   Moment now = now_mom ();
96   Moment musiclen = get_event_length (ev, now);
97
98   rest_end_mom_ = max (rest_end_mom_, (now + musiclen));
99   do_nothing_until_ = Rational (0, 0);
100 }
101
102 /*
103   The duration _until_ the next barline.
104 */
105 Moment
106 Completion_rest_engraver::next_barline_moment ()
107 {
108   Moment *e = unsmob_moment (get_property ("measurePosition"));
109   Moment *l = unsmob_moment (get_property ("measureLength"));
110   if (!e || !l || !to_boolean (get_property ("timing")))
111     {
112       return Moment (0, 0);
113     }
114
115   return (*l - *e);
116 }
117
118 Item*
119 Completion_rest_engraver::make_rest (Stream_event *ev)
120 {
121   Item *rest = make_item ("Rest", ev->self_scm ());
122   if (Pitch *p = unsmob_pitch (ev->get_property ("pitch")))
123     {
124       int pos = p->steps ();
125       SCM c0 = get_property ("middleCPosition");
126       if (scm_is_number (c0))
127         pos += scm_to_int (c0);
128       rest->set_property ("staff-position", scm_from_int (pos));
129     }
130
131   return rest;
132 }
133
134 void
135 Completion_rest_engraver::process_music ()
136 {
137   if (!is_first_ && !left_to_do_)
138     return;
139
140   is_first_ = false;
141
142   Moment now = now_mom ();
143   if (do_nothing_until_ > now.main_part_)
144     return;
145
146   Duration rest_dur;
147   Duration appearance;
148   Duration *orig = 0;
149   if (left_to_do_)
150     {
151       /*
152         rest that rest_dur may be strictly less than left_to_do_
153         (say, if left_to_do_ == 5/8)
154       */
155       if (factor_.denominator () == 1 && factor_ > Rational (1, 1))
156         rest_dur = Duration (left_to_do_, false);
157       else
158         rest_dur = Duration (left_to_do_ / factor_, false).compressed (factor_);
159       appearance = Duration (left_to_do_, false);
160     }
161   else
162     {
163       orig = unsmob_duration (rest_events_[0]->get_property ("duration"));
164       rest_dur = *orig;
165       factor_ = rest_dur.factor ();
166       left_to_do_ = orig->get_length ();
167     }
168   Moment nb = next_barline_moment ();
169   if (nb.main_part_ && nb < rest_dur.get_length ())
170     {
171       if (factor_.denominator () == 1 && factor_ > Rational (1, 1))
172         rest_dur = Duration (nb.main_part_, false);
173       else
174         rest_dur = Duration (nb.main_part_ / factor_, false).compressed (factor_);
175     }
176
177   do_nothing_until_ = now.main_part_ + rest_dur.get_length ();
178
179   for (vsize i = 0; left_to_do_ && i < rest_events_.size (); i++)
180     {
181       bool need_clone = !orig || *orig != rest_dur;
182       Stream_event *event = rest_events_[i];
183
184       if (need_clone)
185         event = event->clone ();
186
187       SCM pits = rest_events_[i]->get_property ("pitch");
188       event->set_property ("pitch", pits);
189       event->set_property ("duration", rest_dur.smobbed_copy ());
190       event->set_property ("length", Moment (rest_dur.get_length ()).smobbed_copy ());
191       event->set_property ("duration-log", scm_from_int (rest_dur.duration_log ()));
192
193       Item *rest = make_rest (event);
194       if (need_clone)
195         event->unprotect ();
196       rests_.push_back (rest);
197     }
198   
199   left_to_do_ -= rest_dur.get_length ();
200   if (left_to_do_)
201     get_global_context ()->add_moment_to_process (now.main_part_ + rest_dur.get_length());
202   /*
203     don't do complicated arithmetic with grace rests.
204   */
205   if (orig && now_mom ().grace_part_)
206     left_to_do_ = Rational (0, 0);
207 }
208
209 void
210 Completion_rest_engraver::stop_translation_timestep ()
211 {
212   if (rests_.size ())
213     prev_rests_ = rests_;
214   rests_.clear ();
215 }
216
217 void
218 Completion_rest_engraver::start_translation_timestep ()
219 {
220   Moment now = now_mom ();
221   if (rest_end_mom_.main_part_ <= now.main_part_)
222     {
223       rest_events_.clear ();
224       prev_rests_.clear ();
225     }
226   context ()->set_property ("restCompletionBusy",
227                             ly_bool2scm (rest_events_.size ()));
228 }
229
230 Completion_rest_engraver::Completion_rest_engraver ()
231 {
232 }
233
234 ADD_TRANSLATOR (Completion_rest_engraver,
235                 /* doc */
236                 "This engraver replaces @code{Rest_engraver}.  It plays"
237                 " some trickery to break long rests into the next measure."
238                 ,
239                 /* create */
240                 "Rest "
241                 ,
242                 /* read */
243                 "middleCPosition "
244                 "measurePosition "
245                 "measureLength "
246                 ,
247                 /* write */
248                 "restCompletionBusy "
249                 );