]> git.donarmstrong.com Git - lilypond.git/blob - lib/duration-convert.cc
release: 0.1.43
[lilypond.git] / lib / duration-convert.cc
1 /*
2   duration-convert.cc -- implement Duration_convert
3
4   source file of the LilyPond music typesetter
5
6   (c) 1997 Han-Wen Nienhuys <hanwen@stack.nl>
7            Jan Nieuwenhuizen <jan@digicash.com>
8 */
9 #include <assert.h>
10 #include "duration-convert.hh"
11 #include "warn.hh"
12
13 // statics Duration_convert
14 bool const Duration_convert::midi_as_plet_b_s = true;
15 bool Duration_convert::no_quantify_b_s = false;
16 bool Duration_convert::no_double_dots_b_s = false;
17 bool Duration_convert::no_triplets_b_s = false;
18 int Duration_convert::no_smaller_than_i_s = 0;
19 Array<Duration> Duration_convert::dur_array_s;
20         
21 String 
22 Duration_convert::dur2_str (Duration dur)
23 {
24   if (dur.ticks_i_)
25     return String ("[") + String (dur.ticks_i_) + "]";
26   
27   String str;
28   if (dur.durlog_i_ >= 0)
29     str = String ( type2_i (dur.durlog_i_) );
30   else if (dur.durlog_i_ == -1)
31     str = "\\breve";
32   else if (dur.durlog_i_ == -2)
33     str = "\\longa";
34   str += String ('.', dur.dots_i_);
35   if (dur.plet_b ())
36     str += String ("*") + String (dur.plet_.iso_i_)
37       + String ("/") + String (dur.plet_.type_i_);
38   return str;
39 }
40
41 #if 0
42 int
43 Duration_convert::dur2_i (Duration dur, int division_1_i)
44 {
45   return dur2_mom (dur) * Moment (division_1_i);
46 }
47 #endif
48
49 int
50 Duration_convert::dur2ticks_i (Duration dur)
51 {
52   if (dur.ticks_i_)
53     return dur.ticks_i_;
54   return dur2_mom (dur) * Moment (Duration::division_1_i_s);
55 }
56
57
58 int
59 Duration_convert::i2_type (int i)
60 {
61   int t=0;
62   while (!(i & 1)) {
63     i >>= 1;
64     t++;
65   }
66   return t;
67 }
68
69 int
70 Duration_convert::type2_i (int type)
71 {
72   if (type<0)
73     return 0; 
74   else
75     return 1 << type;
76 }
77
78 Moment
79 Duration_convert::dur2_mom (Duration dur)
80 {
81   if (dur.ticks_i_)
82     return Moment (dur.ticks_i_, Duration::division_1_i_s);     
83
84   // or simply assert?
85   if (dur.durlog_i_<-10)
86     return Moment (0);
87   Moment mom;
88   if (dur.durlog_i_<0)
89     mom = Moment (type2_i (-dur.durlog_i_), 1);
90   else
91     mom = Moment (1 , type2_i (dur.durlog_i_));
92
93   Moment delta = mom;
94   while (dur.dots_i_--) 
95     {
96       delta /= 2.0;
97       mom += delta;
98     }
99
100   return mom * plet_factor_mom (dur);    
101 }
102
103 #if 0
104 Moment
105 Duration_convert::i2_mom (int time_i, int division_1_i)
106 {
107   if (!time_i)
108     return Moment (0);
109
110   if (division_1_i > 0)
111     return Moment (time_i, division_1_i);
112   else 
113     return Moment (-division_1_i, time_i);
114 }
115 #endif
116
117 Duration
118 Duration_convert::mom2_dur (Moment mom)
119 {
120   if (!mom) 
121     {
122       Duration dur;
123       dur.set_plet (0,1);
124       return dur;
125     }
126         
127
128   Duration dur = mom2standardised_dur (mom);
129   //    if (!dur.mom () || (dur.mom () == mom))
130   if (!dur.length () || (dur.length () == mom))
131     return dur;
132   assert (midi_as_plet_b_s);
133
134   //    dur.set_plet (type_mom, Duration::division_1_i_s / 4); 
135
136   //    Moment as_plet_mom = mom / dur.mom ();
137   Moment as_plet_mom = mom / dur.length ();
138   as_plet_mom *= dur.plet_.mom ();
139   long num = as_plet_mom.numerator ().as_long ();
140   long den = as_plet_mom.denominator ().as_long ();
141   dur.set_plet (num, den);
142   return dur;
143 }
144
145 Duration
146 Duration_convert::mom2standardised_dur (Moment mom)
147 {
148   //    if (!dur_array_s.length_i ())
149   if (!dur_array_s.size ())
150     set_array ();
151   assert (dur_array_s.size ());
152   for (int i = 0; i < dur_array_s.size () - 1; i++) 
153     {
154       Moment lower_mom = dur2_mom (dur_array_s[ i ]);
155       if (mom <= lower_mom) 
156         {
157           // all arbitrary, but 3/4 will get rid of the noise...
158           // kinda ok
159           if (i || (mom / lower_mom > Moment (3, 4)))
160             return dur_array_s[ i ];
161           else 
162             {
163               Duration d;
164               d.durlog_i_ = -100;
165               return d;
166             }
167         }
168       Moment upper_mom = dur2_mom (dur_array_s[ i + 1 ]);
169       if ((mom < upper_mom)
170           && ((mom - lower_mom) / lower_mom
171               < (upper_mom - mom) / upper_mom))
172         return dur_array_s[ i ];
173     }
174   return dur_array_s[ dur_array_s.size () - 1 ];
175 }
176
177 void
178 Duration_convert::set_array ()
179 {
180   dur_array_s.clear ();
181
182   Duration_iterator iter_dur;
183   assert (iter_dur);
184   while (iter_dur)
185     dur_array_s.push (iter_dur++);
186 }
187
188
189 Moment
190 Duration_convert::plet_factor_mom (Duration dur)
191 {
192   return dur.plet_.mom ();
193 }
194
195 Real
196 Duration_convert::sync_f (Duration dur, Moment mom)
197 {
198   return mom / dur2_mom (dur);
199 }
200
201 Duration
202 Duration_convert::ticks2_dur (int ticks_i)
203 {
204   //            Duration dur (4, 0);
205   //            dur.set_plet (ticks_i, Duration::division_1_i_s / 4); 
206
207   Moment mom (ticks_i, Duration::division_1_i_s);
208   if (midi_as_plet_b_s)
209     return mom2_dur (mom);
210
211   Duration dur = mom2standardised_dur (mom);
212
213   //    if (dur.mom () == mom)
214   if (dur.length () == mom)
215     return dur;
216                 
217 // huh?
218 #if 0
219   dur.durlog_i_ = -100;
220   dur.dots_i_ = 0;
221   dur.set_ticks (ticks_i);
222   return dur;
223 #else
224   return mom2_dur (mom);
225 #endif
226 }
227
228 Duration
229 Duration_convert::ticks2standardised_dur (int ticks_i)
230 {
231   Moment mom (ticks_i, Duration::division_1_i_s);
232   Duration dur = mom2standardised_dur (mom);
233   return dur;
234 }
235
236 Duration_iterator::Duration_iterator ()
237 {
238   cursor_dur_.durlog_i_ = 7;
239   if (Duration_convert::no_smaller_than_i_s)
240     cursor_dur_.durlog_i_ = Duration_convert::no_smaller_than_i_s;
241   //    cursor_dur_.set_plet (1, 1);
242 }
243
244 Duration 
245 Duration_iterator::operator ++(int)
246 {
247   return forward_dur ();
248 }
249
250 Duration
251 Duration_iterator::operator ()()
252 {
253   return dur ();
254 }
255
256 Duration_iterator::operator bool ()
257 {
258   return ok ();
259 }
260
261 Duration
262 Duration_iterator::dur ()
263 {
264   return cursor_dur_;
265 }
266
267 Duration
268 Duration_iterator::forward_dur ()
269 {
270   /* should do smart table? guessing: 
271      duration wholes
272      16         0.0625
273      32..       0.0703
274      8:2/3      0.0833
275      16.        0.0938
276      8  0.1250
277      16..       0.1406
278      4:2/3      0.1667
279      8. 0.1875
280                 
281      */
282   assert (ok ());
283
284   Duration dur = cursor_dur_;
285
286   if (!cursor_dur_.dots_i_ && !cursor_dur_.plet_b ()) 
287     {
288       cursor_dur_.durlog_i_ += 1;
289       cursor_dur_.dots_i_ = 2;
290     }
291   else if (cursor_dur_.dots_i_ == 2) 
292     {
293       assert (!cursor_dur_.plet_b ());
294       cursor_dur_.dots_i_ = 0;
295       cursor_dur_.durlog_i_ -=2;
296       cursor_dur_.set_plet (2, 3);
297     }
298   else if (cursor_dur_.plet_b () 
299            && (cursor_dur_.plet_.iso_i_ == 2)
300            && (cursor_dur_.plet_.type_i_ == 3)) 
301     {
302       assert (!cursor_dur_.dots_i_);
303       cursor_dur_.set_plet (1, 1);
304       cursor_dur_.durlog_i_ += 1;
305       cursor_dur_.dots_i_ = 1;
306     }
307   else if (cursor_dur_.dots_i_ == 1) 
308     {
309       assert (!cursor_dur_.plet_b ());
310       cursor_dur_.dots_i_ = 0;
311       cursor_dur_.durlog_i_ -= 1;
312     }
313                 
314   if (Duration_convert::no_triplets_b_s
315       && cursor_dur_.plet_b () && ok ())
316     forward_dur ();
317   if (Duration_convert::no_double_dots_b_s 
318       && (cursor_dur_.dots_i_ == 2) && ok ())
319     forward_dur ();
320   if (Duration_convert::no_smaller_than_i_s
321       && (cursor_dur_.durlog_i_ > Duration_convert::no_smaller_than_i_s) && ok ())
322     forward_dur ();
323   if (Duration_convert::no_smaller_than_i_s
324       && cursor_dur_.dots_i_
325       && (cursor_dur_.durlog_i_ >= Duration_convert::no_smaller_than_i_s)
326       && ok ())
327     forward_dur ();
328   if (Duration_convert::no_smaller_than_i_s
329       && (cursor_dur_.dots_i_ == 2)
330       && (cursor_dur_.durlog_i_ >= Duration_convert::no_smaller_than_i_s / 2)
331       && ok ())
332     forward_dur ();
333
334   return dur;
335 }
336
337 bool
338 Duration_iterator::ok ()
339 {
340   return (cursor_dur_.durlog_i_ 
341           && !((cursor_dur_.durlog_i_ == 0) && (cursor_dur_.dots_i_ > 2)));
342 }