2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1997--2015 Han-Wen Nienhuys <hanwen@xs4all.nl>
6 LilyPond is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 LilyPond is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
20 #include "timing-translator.hh"
23 #include "translator-group.hh"
24 #include "global-context.hh"
26 #include "lily-imports.hh"
29 Timing_translator::stop_translation_timestep ()
31 Global_context *global = get_global_context ();
33 if (to_boolean (get_property ("timing"))
34 && !to_boolean (get_property ("skipBars")))
36 Moment barleft = (measure_length () - measure_position (context ()));
37 Moment now = now_mom ();
39 if (barleft > Moment (0))
41 Moment nextmom = now + barleft;
42 nextmom.grace_part_ = Rational (0);
43 global->add_moment_to_process (nextmom);
49 Timing_translator::initialize ()
51 Context *timing = unsmob<Context>
52 (Lily::ly_context_find (context ()->self_scm (), ly_symbol2scm ("Timing")));
53 if (timing != context ())
55 context ()->add_alias (ly_symbol2scm ("Timing"));
59 programming_error ("Can't find Timing context template");
64 SCM barnumber = timing->get_property ("currentBarNumber");
65 if (!scm_is_integer (barnumber))
66 barnumber = scm_from_int (1);
67 context ()->set_property ("currentBarNumber", barnumber);
68 context ()->set_property ("internalBarNumber", barnumber);
70 SCM timeSignatureFraction = timing->get_property ("timeSignatureFraction");
72 if (!scm_is_pair (timeSignatureFraction))
74 programming_error ("missing timeSignatureFraction");
75 timeSignatureFraction = scm_cons (scm_from_int (4), scm_from_int (4));
77 context ()->set_property ("timeSignatureFraction", timeSignatureFraction);
79 SCM measureLength = timing->get_property ("measureLength");
81 if (!unsmob<Moment> (measureLength))
84 Moment (ly_scm2rational
85 (scm_divide (scm_car (timeSignatureFraction),
86 scm_cdr (timeSignatureFraction)))).smobbed_copy ();
88 context ()->set_property ("measureLength", measureLength);
91 Do not init measurePosition; this should be done from global
95 SCM timeSignatureSettings = timing->get_property ("timeSignatureSettings");
96 if (!scm_is_pair (timeSignatureSettings))
98 programming_error ("missing timeSignatureSettings");
99 timeSignatureSettings = Lily::default_time_signature_settings;
101 context ()->set_property ("timeSignatureSettings", timeSignatureSettings);
103 SCM beamExceptions = timing->get_property ("beamExceptions");
104 if (!scm_is_pair (beamExceptions))
106 beamExceptions = Lily::beam_exceptions (timeSignatureFraction,
107 timeSignatureSettings);
109 context ()->set_property ("beamExceptions", beamExceptions);
111 SCM baseMoment = timing->get_property ("baseMoment");
112 if (!unsmob<Moment> (baseMoment))
115 Moment (ly_scm2rational
116 (Lily::base_length (timeSignatureFraction,
117 timeSignatureSettings))).smobbed_copy ();
119 context ()->set_property ("baseMoment", baseMoment);
121 SCM beatStructure = timing->get_property ("beatStructure");
122 if (!scm_is_pair (beatStructure))
125 Lily::beat_structure (ly_rational2scm (unsmob<Moment> (baseMoment)->main_part_),
126 timeSignatureFraction,
127 timeSignatureSettings);
129 context ()->set_property ("beatStructure", beatStructure);
131 context ()->set_property ("beamHalfMeasure",
132 timing->get_property ("beamHalfMeasure"));
134 context ()->set_property ("autoBeaming",
135 timing->get_property ("autoBeaming"));
139 Timing_translator::measure_length () const
141 SCM l = get_property ("measureLength");
142 if (unsmob<Moment> (l))
143 return unsmob<Moment> (l)->main_part_;
148 Timing_translator::Timing_translator ()
153 Timing_translator::start_translation_timestep ()
155 Global_context *global = get_global_context ();
157 Moment now = global->now_mom ();
158 Moment dt = now - global->previous_moment ();
161 programming_error ("moving backwards in time");
164 else if (dt.main_part_.is_infinity ())
166 programming_error ("moving infinitely to future");
175 SCM s = get_property ("measurePosition");
176 if (unsmob<Moment> (s))
177 measposp = *unsmob<Moment> (s);
183 int current_barnumber = robust_scm2int (get_property ("currentBarNumber"), 0);
184 int internal_barnumber = robust_scm2int (get_property ("internalBarNumber"), 0);
186 SCM cad = get_property ("timing");
187 bool c = to_boolean (cad);
191 Rational len = measure_length ();
195 while (measposp.main_part_ >= len)
197 measposp.main_part_ -= len;
199 internal_barnumber++;
204 // Because "timing" can be switched on and off asynchronously with
205 // graces, measurePosition might get into strange settings of
206 // grace_part_. It does not actually make sense to have it diverge
207 // from the main timing. Updating the grace part outside of the
208 // actual check for "timing" looks strange and will lead to changes
209 // of grace_part_ even when timing is off. However, when timing is
210 // switched back on again, this will generally happen in an override
211 // that does _not_ in itself advance current_moment. So the whole
212 // timing advance logic will only get triggered while "timing" is
213 // still of. Maybe we should keep measurePosition.grace_part_
214 // constantly at zero anyway?
216 measposp.grace_part_ = now.grace_part_;
219 context ()->set_property ("currentBarNumber", scm_from_int (current_barnumber));
220 context ()->set_property ("internalBarNumber", scm_from_int (internal_barnumber));
221 context ()->set_property ("measurePosition", measposp.smobbed_copy ());
224 #include "translator.icc"
226 ADD_TRANSLATOR (Timing_translator,
228 "This engraver adds the alias @code{Timing} to its containing"
229 " context. Responsible for synchronizing timing information"
230 " from staves. Normally in @code{Score}. In order to create"
231 " polyrhythmic music, this engraver should be removed from"
232 " @code{Score} and placed in @code{Staff}.",
243 "timeSignatureFraction ",
251 "timeSignatureFraction "