2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1997--2012 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"
28 Timing_translator::stop_translation_timestep ()
30 Global_context *global = get_global_context ();
32 if (to_boolean (get_property ("timing"))
33 && !to_boolean (get_property ("skipBars")))
35 Moment barleft = (measure_length () - measure_position (context ()));
36 Moment now = now_mom ();
38 if (barleft > Moment (0))
40 Moment nextmom = now + barleft;
41 nextmom.grace_part_ = Rational (0);
42 global->add_moment_to_process (nextmom);
48 Timing_translator::initialize ()
50 Context *timing = unsmob_context (scm_call_2 (ly_lily_module_constant ("ly:context-find"),
51 context ()->self_scm (),
52 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 // A memoized constant is not the prettiest thing as a fallback
100 // since it does not track changes of the variable. However,
101 // this is still better than nothing, and we already complained
102 // via a programming_error
103 timeSignatureSettings = ly_lily_module_constant ("default-time-signature-settings");
105 context ()->set_property ("timeSignatureSettings", timeSignatureSettings);
107 SCM beamExceptions = timing->get_property ("beamExceptions");
108 if (!scm_is_pair (beamExceptions))
111 scm_call_2 (ly_lily_module_constant ("beam-exceptions"),
112 timeSignatureFraction,
113 timeSignatureSettings);
115 context ()->set_property ("beamExceptions", beamExceptions);
117 SCM baseMoment = timing->get_property ("baseMoment");
118 if (!unsmob_moment (baseMoment))
121 Moment (ly_scm2rational
122 (scm_call_2 (ly_lily_module_constant ("base-length"),
123 timeSignatureFraction,
124 timeSignatureSettings))).smobbed_copy ();
126 context ()->set_property ("baseMoment", baseMoment);
128 SCM beatStructure = timing->get_property ("beatStructure");
129 if (!scm_is_pair (beatStructure))
132 scm_call_3 (ly_lily_module_constant ("beat-structure"),
133 ly_rational2scm (unsmob_moment (baseMoment)->main_part_),
134 timeSignatureFraction,
135 timeSignatureSettings);
137 context ()->set_property ("beatStructure", beatStructure);
139 context ()->set_property ("beamHalfMeasure",
140 timing->get_property ("beamHalfMeasure"));
142 context ()->set_property ("autoBeaming",
143 timing->get_property ("autoBeaming"));
147 Timing_translator::measure_length () const
149 SCM l = get_property ("measureLength");
150 if (unsmob_moment (l))
151 return unsmob_moment (l)->main_part_;
156 Timing_translator::Timing_translator ()
161 Timing_translator::start_translation_timestep ()
163 Global_context *global = get_global_context ();
165 Moment now = global->now_mom ();
166 Moment dt = now - global->previous_moment ();
169 programming_error ("moving backwards in time");
172 else if (dt.main_part_.is_infinity ())
174 programming_error ("moving infinitely to future");
183 SCM s = get_property ("measurePosition");
184 if (unsmob_moment (s))
185 measposp = *unsmob_moment (s);
191 int current_barnumber = robust_scm2int (get_property ("currentBarNumber"), 0);
192 int internal_barnumber = robust_scm2int (get_property ("internalBarNumber"), 0);
194 SCM cad = get_property ("timing");
195 bool c = to_boolean (cad);
199 Rational len = measure_length ();
203 while (measposp.main_part_ >= len)
205 measposp.main_part_ -= len;
207 internal_barnumber++;
212 // Because "timing" can be switched on and off asynchronously with
213 // graces, measurePosition might get into strange settings of
214 // grace_part_. It does not actually make sense to have it diverge
215 // from the main timing. Updating the grace part outside of the
216 // actual check for "timing" looks strange and will lead to changes
217 // of grace_part_ even when timing is off. However, when timing is
218 // switched back on again, this will generally happen in an override
219 // that does _not_ in itself advance current_moment. So the whole
220 // timing advance logic will only get triggered while "timing" is
221 // still of. Maybe we should keep measurePosition.grace_part_
222 // constantly at zero anyway?
224 measposp.grace_part_ = now.grace_part_;
227 context ()->set_property ("currentBarNumber", scm_from_int (current_barnumber));
228 context ()->set_property ("internalBarNumber", scm_from_int (internal_barnumber));
229 context ()->set_property ("measurePosition", measposp.smobbed_copy ());
232 #include "translator.icc"
234 ADD_TRANSLATOR (Timing_translator,
236 "This engraver adds the alias @code{Timing} to its containing"
237 " context. Responsible for synchronizing timing information"
238 " from staves. Normally in @code{Score}. In order to create"
239 " polyrhythmic music, this engraver should be removed from"
240 " @code{Score} and placed in @code{Staff}.",
251 "timeSignatureFraction ",
259 "timeSignatureFraction "