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