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