]> git.donarmstrong.com Git - lilypond.git/blob - lily/completion-rest-engraver.cc
56e11a5d1df0e2185b12e49329f917a74f56fa88
[lilypond.git] / lily / completion-rest-engraver.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1997--2014 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 #include "misc.hh"
40
41 #include "translator.icc"
42
43 /*
44   How does this work?
45
46   When we catch the rest, we predict the end of the rest. We keep the
47   events living until we reach the predicted end-time.
48
49   Every time process_music () is called and there are rest events, we
50   figure out how long the rest to typeset should be. It should be no
51   longer than what's specified, than what is left to do and it should
52   not cross barlines or sub-bar units.
53
54   We copy the events into scratch rest events, to make sure that we get
55   all durations exactly right.
56 */
57
58 class Completion_rest_engraver : public Engraver
59 {
60   vector<Item *> 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_moment (Rational const &);
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 or completion unit
104 */
105 Moment
106 Completion_rest_engraver::next_moment (Rational const &note_len)
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   Moment result = *l - *e;
116   Moment const *unit = unsmob_moment (get_property ("completionUnit"));
117
118   if (unit)
119     {
120       Rational const now_unit = e->main_part_ / unit->main_part_;
121       if (now_unit.den () > 1)
122         {
123           /*
124             within a unit - go to the end of that
125           */
126           result = unit->main_part_
127             * (Rational (1) - (now_unit - now_unit.trunc_rat ()));
128         }
129       else
130         {
131           /*
132             at the beginning of a unit:
133             take a power-of-two number of units, but not more than required,
134             since then the Duration constructor destroys the unit structure
135           */
136           if (note_len < result.main_part_)
137             result.main_part_ = note_len;
138           Rational const step_unit = result.main_part_ / unit->main_part_;
139           if (step_unit.den () < step_unit.num ())
140             {
141               int const log2
142                 = intlog2 (int (step_unit.num () / step_unit.den ()));
143               result.main_part_ = unit->main_part_ * Rational (1 << log2);
144             }
145         }
146     }
147
148   return result;
149 }
150
151 Item *
152 Completion_rest_engraver::make_rest (Stream_event *ev)
153 {
154   Item *rest = make_item ("Rest", ev->self_scm ());
155   if (Pitch *p = unsmob_pitch (ev->get_property ("pitch")))
156     {
157       int pos = p->steps ();
158       SCM c0 = get_property ("middleCPosition");
159       if (scm_is_number (c0))
160         pos += scm_to_int (c0);
161       rest->set_property ("staff-position", scm_from_int (pos));
162     }
163
164   return rest;
165 }
166
167 void
168 Completion_rest_engraver::process_music ()
169 {
170   if (!is_first_ && !left_to_do_)
171     return;
172
173   is_first_ = false;
174
175   Moment now = now_mom ();
176   if (do_nothing_until_ > now.main_part_)
177     return;
178
179   Duration rest_dur;
180   Duration *orig = 0;
181   if (left_to_do_)
182     {
183       /*
184         note that rest_dur may be strictly less than left_to_do_
185         (say, if left_to_do_ == 5/8)
186       */
187       rest_dur = Duration (left_to_do_ / factor_, false).compressed (factor_);
188     }
189   else
190     {
191       orig = unsmob_duration (rest_events_[0]->get_property ("duration"));
192       rest_dur = *orig;
193       SCM factor = get_property ("completionFactor");
194       if (ly_is_procedure (factor))
195         factor = scm_call_2 (factor,
196                              context ()->self_scm (),
197                              rest_dur.smobbed_copy ());
198       factor_ = robust_scm2rational (factor, rest_dur.factor());
199       left_to_do_ = orig->get_length ();
200     }
201   Moment nb = next_moment (rest_dur.get_length ());
202   if (nb.main_part_ && nb < rest_dur.get_length ())
203     {
204       rest_dur = Duration (nb.main_part_ / factor_, false).compressed (factor_);
205     }
206
207   do_nothing_until_ = now.main_part_ + rest_dur.get_length ();
208
209   for (vsize i = 0; left_to_do_ && i < rest_events_.size (); i++)
210     {
211       bool need_clone = !orig || *orig != rest_dur;
212       Stream_event *event = rest_events_[i];
213
214       if (need_clone)
215         event = event->clone ();
216
217       SCM pits = rest_events_[i]->get_property ("pitch");
218       event->set_property ("pitch", pits);
219       event->set_property ("duration", rest_dur.smobbed_copy ());
220       event->set_property ("length", Moment (rest_dur.get_length ()).smobbed_copy ());
221       event->set_property ("duration-log", scm_from_int (rest_dur.duration_log ()));
222
223       Item *rest = make_rest (event);
224       if (need_clone)
225         event->unprotect ();
226       rests_.push_back (rest);
227     }
228
229   left_to_do_ -= rest_dur.get_length ();
230   if (left_to_do_)
231     get_global_context ()->add_moment_to_process (now.main_part_ + rest_dur.get_length ());
232   /*
233     don't do complicated arithmetic with grace rests.
234   */
235   if (orig && now_mom ().grace_part_)
236     left_to_do_ = Rational (0, 0);
237 }
238
239 void
240 Completion_rest_engraver::stop_translation_timestep ()
241 {
242   rests_.clear ();
243 }
244
245 void
246 Completion_rest_engraver::start_translation_timestep ()
247 {
248   Moment now = now_mom ();
249   if (rest_end_mom_.main_part_ <= now.main_part_)
250     {
251       rest_events_.clear ();
252     }
253   context ()->set_property ("restCompletionBusy",
254                             ly_bool2scm (rest_events_.size ()));
255 }
256
257 Completion_rest_engraver::Completion_rest_engraver ()
258 {
259 }
260
261 ADD_TRANSLATOR (Completion_rest_engraver,
262                 /* doc */
263                 "This engraver replaces @code{Rest_engraver}.  It plays"
264                 " some trickery to break long rests into the next measure.",
265
266                 /* create */
267                 "Rest ",
268
269                 /* read */
270                 "completionFactor "
271                 "completionUnit "
272                 "middleCPosition "
273                 "measurePosition "
274                 "measureLength ",
275
276                 /* write */
277                 "restCompletionBusy "
278                );