]> git.donarmstrong.com Git - lilypond.git/blob - lily/completion-rest-engraver.cc
Web-ja: update introduction
[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 /*
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   void listen_rest (Stream_event *);
80 };
81
82 void
83 Completion_rest_engraver::initialize ()
84 {
85   is_first_ = false;
86 }
87
88 void
89 Completion_rest_engraver::listen_rest (Stream_event *ev)
90 {
91   rest_events_.push_back (ev);
92
93   is_first_ = true;
94   Moment now = now_mom ();
95   Moment musiclen = get_event_length (ev, now);
96
97   rest_end_mom_ = max (rest_end_mom_, (now + musiclen));
98   do_nothing_until_ = Rational (0, 0);
99 }
100
101 /*
102   The duration _until_ the next barline or completion unit
103 */
104 Moment
105 Completion_rest_engraver::next_moment (Rational const &note_len)
106 {
107   Moment *e = unsmob<Moment> (get_property ("measurePosition"));
108   Moment *l = unsmob<Moment> (get_property ("measureLength"));
109   if (!e || !l || !to_boolean (get_property ("timing")))
110     {
111       return Moment (0, 0);
112     }
113
114   Moment result = *l - *e;
115   Moment const *unit = unsmob<Moment> (get_property ("completionUnit"));
116
117   if (unit)
118     {
119       Rational const now_unit = e->main_part_ / unit->main_part_;
120       if (now_unit.den () > 1)
121         {
122           /*
123             within a unit - go to the end of that
124           */
125           result = unit->main_part_
126             * (Rational (1) - (now_unit - now_unit.trunc_rat ()));
127         }
128       else
129         {
130           /*
131             at the beginning of a unit:
132             take a power-of-two number of units, but not more than required,
133             since then the Duration constructor destroys the unit structure
134           */
135           if (note_len < result.main_part_)
136             result.main_part_ = note_len;
137           Rational const step_unit = result.main_part_ / unit->main_part_;
138           if (step_unit.den () < step_unit.num ())
139             {
140               int const log2
141                 = intlog2 (int (step_unit.num () / step_unit.den ()));
142               result.main_part_ = unit->main_part_ * Rational (1 << log2);
143             }
144         }
145     }
146
147   return result;
148 }
149
150 Item *
151 Completion_rest_engraver::make_rest (Stream_event *ev)
152 {
153   Item *rest = make_item ("Rest", ev->self_scm ());
154   if (Pitch *p = unsmob<Pitch> (ev->get_property ("pitch")))
155     {
156       int pos = p->steps ();
157       SCM c0 = get_property ("middleCPosition");
158       if (scm_is_number (c0))
159         pos += scm_to_int (c0);
160       rest->set_property ("staff-position", scm_from_int (pos));
161     }
162
163   return rest;
164 }
165
166 void
167 Completion_rest_engraver::process_music ()
168 {
169   if (!is_first_ && !left_to_do_)
170     return;
171
172   is_first_ = false;
173
174   Moment now = now_mom ();
175   if (do_nothing_until_ > now.main_part_)
176     return;
177
178   Duration rest_dur;
179   Duration *orig = 0;
180   if (left_to_do_)
181     {
182       /*
183         note that rest_dur may be strictly less than left_to_do_
184         (say, if left_to_do_ == 5/8)
185       */
186       rest_dur = Duration (left_to_do_ / factor_, false).compressed (factor_);
187     }
188   else
189     {
190       orig = unsmob<Duration> (rest_events_[0]->get_property ("duration"));
191       rest_dur = *orig;
192       SCM factor = get_property ("completionFactor");
193       if (ly_is_procedure (factor))
194         factor = scm_call_2 (factor,
195                              context ()->self_scm (),
196                              rest_dur.smobbed_copy ());
197       factor_ = robust_scm2rational (factor, rest_dur.factor());
198       left_to_do_ = orig->get_length ();
199     }
200   Moment nb = next_moment (rest_dur.get_length ());
201   if (nb.main_part_ && nb < rest_dur.get_length ())
202     {
203       rest_dur = Duration (nb.main_part_ / factor_, false).compressed (factor_);
204     }
205
206   do_nothing_until_ = now.main_part_ + rest_dur.get_length ();
207
208   for (vsize i = 0; left_to_do_ && i < rest_events_.size (); i++)
209     {
210       bool need_clone = !orig || *orig != rest_dur;
211       Stream_event *event = rest_events_[i];
212
213       if (need_clone)
214         event = event->clone ();
215
216       SCM pits = rest_events_[i]->get_property ("pitch");
217       event->set_property ("pitch", pits);
218       event->set_property ("duration", rest_dur.smobbed_copy ());
219       event->set_property ("length", Moment (rest_dur.get_length ()).smobbed_copy ());
220       event->set_property ("duration-log", scm_from_int (rest_dur.duration_log ()));
221
222       Item *rest = make_rest (event);
223       if (need_clone)
224         event->unprotect ();
225       rests_.push_back (rest);
226     }
227
228   left_to_do_ -= rest_dur.get_length ();
229   if (left_to_do_)
230     get_global_context ()->add_moment_to_process (now.main_part_ + rest_dur.get_length ());
231   /*
232     don't do complicated arithmetic with grace rests.
233   */
234   if (orig && now_mom ().grace_part_)
235     left_to_do_ = Rational (0, 0);
236 }
237
238 void
239 Completion_rest_engraver::stop_translation_timestep ()
240 {
241   rests_.clear ();
242 }
243
244 void
245 Completion_rest_engraver::start_translation_timestep ()
246 {
247   Moment now = now_mom ();
248   if (rest_end_mom_.main_part_ <= now.main_part_)
249     {
250       rest_events_.clear ();
251     }
252   context ()->set_property ("restCompletionBusy",
253                             ly_bool2scm (rest_events_.size ()));
254 }
255
256 Completion_rest_engraver::Completion_rest_engraver (Context *c)
257   : Engraver (c)
258 {
259 }
260
261 void
262 Completion_rest_engraver::boot ()
263 {
264   ADD_LISTENER (Completion_rest_engraver, rest);
265 }
266
267 ADD_TRANSLATOR (Completion_rest_engraver,
268                 /* doc */
269                 "This engraver replaces @code{Rest_engraver}.  It plays"
270                 " some trickery to break long rests into the next measure.",
271
272                 /* create */
273                 "Rest ",
274
275                 /* read */
276                 "completionFactor "
277                 "completionUnit "
278                 "middleCPosition "
279                 "measurePosition "
280                 "measureLength ",
281
282                 /* write */
283                 "restCompletionBusy "
284                );