]> git.donarmstrong.com Git - lilypond.git/blob - lib/duration-convert.cc
e64ca663eaa674fe4e8dce9c5309ec9cec318216
[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 }