]> git.donarmstrong.com Git - lilypond.git/blob - lily/timing-translator.cc
Merge branch 'master' of /home/jcharles/GIT/Lily/. into translation
[lilypond.git] / lily / timing-translator.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1997--2012 Han-Wen Nienhuys <hanwen@xs4all.nl>
5
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.
10
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.
15
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/>.
18 */
19
20 #include "timing-translator.hh"
21
22 #include "warn.hh"
23 #include "translator-group.hh"
24 #include "global-context.hh"
25 #include "moment.hh"
26
27 void
28 Timing_translator::stop_translation_timestep ()
29 {
30   Global_context *global = get_global_context ();
31
32   if (to_boolean (get_property ("timing"))
33       && !to_boolean (get_property ("skipBars")))
34     {
35       Moment barleft = (measure_length () - measure_position (context ()));
36       Moment now = now_mom ();
37
38       if (barleft > Moment (0))
39         {
40           Moment nextmom = now + barleft;
41           nextmom.grace_part_ = Rational (0);
42           global->add_moment_to_process (nextmom);
43         }
44     }
45 }
46
47 void
48 Timing_translator::initialize ()
49 {
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 ())
54     {
55       context ()->add_alias (ly_symbol2scm ("Timing"));
56
57       if (!timing)
58         {
59           programming_error ("Can't find Timing context template");
60           timing = context ();
61         }
62     }
63
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);
69
70   SCM timeSignatureFraction = timing->get_property ("timeSignatureFraction");
71
72   if (!scm_is_pair (timeSignatureFraction))
73     {
74       programming_error ("missing timeSignatureFraction");
75       timeSignatureFraction = scm_cons (scm_from_int (4), scm_from_int (4));
76     }
77   context ()->set_property ("timeSignatureFraction", timeSignatureFraction);
78
79   SCM measureLength = timing->get_property ("measureLength");
80
81   if (!unsmob_moment (measureLength))
82     {
83       measureLength =
84         Moment (ly_scm2rational
85                 (scm_divide (scm_car (timeSignatureFraction),
86                              scm_cdr (timeSignatureFraction)))).smobbed_copy ();
87     }
88   context ()->set_property ("measureLength", measureLength);
89
90   /*
91     Do not init measurePosition; this should be done from global
92     context.
93   */
94
95   SCM timeSignatureSettings = timing->get_property ("timeSignatureSettings");
96   if (!scm_is_pair (timeSignatureSettings))
97     {
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");
104     }
105   context ()->set_property ("timeSignatureSettings", timeSignatureSettings);
106
107   SCM beamExceptions = timing->get_property ("beamExceptions");
108   if (!scm_is_pair (beamExceptions))
109     {
110       beamExceptions =
111         scm_call_2 (ly_lily_module_constant ("beam-exceptions"),
112                     timeSignatureFraction,
113                     timeSignatureSettings);
114     }
115   context ()->set_property ("beamExceptions", beamExceptions);
116
117   SCM baseMoment = timing->get_property ("baseMoment");
118   if (!unsmob_moment (baseMoment))
119     {
120       baseMoment =
121         Moment (ly_scm2rational
122                 (scm_call_2 (ly_lily_module_constant ("base-length"),
123                              timeSignatureFraction,
124                              timeSignatureSettings))).smobbed_copy ();
125     }
126   context ()->set_property ("baseMoment", baseMoment);
127
128   SCM beatStructure = timing->get_property ("beatStructure");
129   if (!scm_is_pair (beatStructure))
130     {
131       beatStructure =
132         scm_call_3 (ly_lily_module_constant ("beat-structure"),
133                     ly_rational2scm (unsmob_moment (baseMoment)->main_part_),
134                     timeSignatureFraction,
135                     timeSignatureSettings);
136     }
137   context ()->set_property ("beatStructure", beatStructure);
138
139   context ()->set_property ("beamHalfMeasure",
140                             timing->get_property ("beamHalfMeasure"));
141
142   context ()->set_property ("autoBeaming",
143                             timing->get_property ("autoBeaming"));
144 }
145
146 Rational
147 Timing_translator::measure_length () const
148 {
149   SCM l = get_property ("measureLength");
150   if (unsmob_moment (l))
151     return unsmob_moment (l)->main_part_;
152   else
153     return Rational (1);
154 }
155
156 Timing_translator::Timing_translator ()
157 {
158 }
159
160 void
161 Timing_translator::start_translation_timestep ()
162 {
163   Global_context *global = get_global_context ();
164
165   Moment now = global->now_mom ();
166   Moment dt = now - global->previous_moment ();
167   if (dt < Moment (0))
168     {
169       programming_error ("moving backwards in time");
170       dt = 0;
171     }
172   else if (dt.main_part_.is_infinity ())
173     {
174       programming_error ("moving infinitely to future");
175       dt = 0;
176     }
177
178   if (!dt.to_bool ())
179     return;
180
181   Moment measposp;
182
183   SCM s = get_property ("measurePosition");
184   if (unsmob_moment (s))
185     measposp = *unsmob_moment (s);
186   else
187     {
188       measposp = now;
189       context ()->set_property ("measurePosition",
190                                 measposp.smobbed_copy ());
191     }
192
193   measposp += dt;
194
195   int current_barnumber = robust_scm2int (get_property ("currentBarNumber"), 0);
196   int internal_barnumber = robust_scm2int (get_property ("internalBarNumber"), 0);
197
198   SCM cad = get_property ("timing");
199   bool c = to_boolean (cad);
200
201   Rational len = measure_length ();
202   while (c && measposp.main_part_ >= len)
203     {
204       measposp.main_part_ -= len;
205       current_barnumber++;
206       internal_barnumber++;
207     }
208
209   context ()->set_property ("currentBarNumber", scm_from_int (current_barnumber));
210   context ()->set_property ("internalBarNumber", scm_from_int (internal_barnumber));
211   context ()->set_property ("measurePosition", measposp.smobbed_copy ());
212 }
213
214 #include "translator.icc"
215
216 ADD_TRANSLATOR (Timing_translator,
217                 /* doc */
218                 "This engraver adds the alias @code{Timing} to its containing"
219                 " context.  Responsible for synchronizing timing information"
220                 " from staves.  Normally in @code{Score}.  In order to create"
221                 " polyrhythmic music, this engraver should be removed from"
222                 " @code{Score} and placed in @code{Staff}.",
223
224                 /* create */
225                 "",
226
227                 /* read */
228                 "baseMoment "
229                 "currentBarNumber "
230                 "internalBarNumber "
231                 "measureLength "
232                 "measurePosition "
233                 "timeSignatureFraction ",
234
235                 /* write */
236                 "baseMoment "
237                 "currentBarNumber "
238                 "internalBarNumber "
239                 "measureLength "
240                 "measurePosition "
241                 "timeSignatureFraction "
242                );