]> git.donarmstrong.com Git - lilypond.git/blob - lib/duration.cc
release: 0.0.43
[lilypond.git] / lib / duration.cc
1 //
2 // duration.cc -- implement Duration, Plet, Duration_convert, Duration_iterator
3 //
4 // copyright 1997 Jan Nieuwenhuizen <jan@digicash.com>
5
6 // split into 4?
7
8 #include "proto.hh"
9 #include "plist.hh"
10 #include "string.hh"
11 #include "source-file.hh"
12 #include "source.hh"
13 #include "moment.hh"
14 #include "duration.hh"
15 #include "debug.hh"  //ugh
16
17 // statics Duration
18 int Duration::division_1_i_s = 384 * 4;
19
20 Duration::Duration( int type_i, int dots_i = 0, Plet* plet_l )
21 {
22         type_i_ = type_i;
23         dots_i_ = dots_i;
24         plet_p_ = 0;
25         ticks_i_ = 0;
26         set_plet( plet_l );
27 }
28
29 Duration::Duration( Duration const& dur_c_r )
30 {
31         type_i_ = 0;
32         dots_i_ = 0;
33         plet_p_ = 0;
34         ticks_i_ = 0;
35         *this = dur_c_r;
36 }
37
38 Duration::~Duration()
39 {
40         delete plet_p_;
41 }
42
43 Duration const& 
44 Duration::operator =( Duration const& dur_c_r )
45 {
46         if ( &dur_c_r == this )
47                 return *this;
48
49         type_i_ = dur_c_r.type_i_;
50         dots_i_ = dur_c_r.dots_i_;
51         ticks_i_ = dur_c_r.ticks_i_;
52         set_plet( dur_c_r.plet_p_ );
53
54         return *this;
55 }
56
57 void
58 Duration::set_plet( Plet* plet_l )
59 {
60         delete plet_p_;
61         plet_p_ = 0;
62         if ( plet_l )
63                 plet_p_ = new Plet( *plet_l );
64 }
65
66 void
67 Duration::set_ticks( int ticks_i )
68 {
69         assert( !type_i_ );
70         assert( !dots_i_ );
71         assert( !plet_p_ );
72         ticks_i_ = ticks_i;
73 }
74
75 Plet::Plet( int iso_i, int type_i )
76 {
77         iso_i_ = iso_i;
78         type_i_ = type_i;
79 }
80
81
82 // statics Duration_convert
83 bool Duration_convert::be_blonde_b_s = false;
84 bool Duration_convert::no_double_dots_b_s = false;
85 bool Duration_convert::no_triplets_b_s = false;
86 int Duration_convert::no_smaller_than_i_s = 0;
87         
88 String 
89 Duration_convert::dur2_str( Duration dur )
90 {
91         if ( dur.ticks_i_ )
92                 return String( "["  ) + String( dur.ticks_i_ ) + "]";
93
94         String str( dur.type_i_ );
95         str += String( '.', dur.dots_i_ );
96         if ( dur.plet_p_ )
97                 str += String( "*" ) + String( dur.plet_p_->iso_i_ )
98                         + String( "/" ) + String( dur.plet_p_->type_i_ );
99         return str;
100 }
101
102 #if 0
103 int
104 Duration_convert::dur2_i( Duration dur, int division_1_i )
105 {
106         return dur2_mom( dur ) * Moment( division_1_i );
107 }
108 #endif
109
110 int
111 Duration_convert::dur2ticks_i( Duration dur )
112 {
113         if ( dur.ticks_i_ )
114                 return dur.ticks_i_;
115         return dur2_mom( dur ) * Moment( Duration::division_1_i_s );
116 }
117
118 Moment
119 Duration_convert::dur2_mom( Duration dur )
120 {
121         if ( dur.ticks_i_ )
122                 return Moment( dur.ticks_i_, Duration::division_1_i_s );        
123
124         // or simply assert?
125         if ( !dur.type_i_ )
126                 return Moment( 0 );
127
128         Moment mom = Moment( 1 , dur.type_i_ );
129
130         Moment delta = mom;
131         while ( dur.dots_i_-- ) {
132                 delta /= 2.0;
133                 mom += delta;
134         }
135
136         return mom * plet_factor_mom( dur );    
137 }
138
139 #if 0
140 Moment
141 Duration_convert::i2_mom( int time_i, int division_1_i )
142 {
143         if ( !time_i )
144                 return Moment( 0 );
145
146         if ( division_1_i > 0 )
147                 return Moment( time_i, division_1_i );
148         else 
149                 return Moment( -division_1_i, time_i );
150 }
151 #endif
152
153 #if 0
154 Duration
155 Duration_convert::mom2_dur( Moment mom )
156 {
157         /* this is cute, 
158            but filling an array using Duration_iterator
159            might speed things up, a little
160            */
161         Duration_iterator iter_dur;
162         assert( iter_dur );
163         while ( iter_dur ) {
164                 Duration lower_dur = iter_dur++;
165                 Duration upper_dur( 0 );
166                 if ( iter_dur )
167                         upper_dur = iter_dur();
168                 Moment lower_mom = dur2_mom( lower_dur );
169                 Moment upper_mom = dur2_mom( upper_dur );
170                 if ( mom == lower_mom )
171                         return lower_dur;
172                 if ( mom == upper_mom ) // don-t miss last (sic)
173                         return upper_dur;
174                 if ( ( mom >= lower_mom ) && ( mom <= upper_mom ) ) {
175                         warning( String( "duration not exact: " ) + String( (Real)mom ) , 0 );
176                         if ( abs( mom - lower_mom ) < abs( mom - upper_mom ) )
177                                 return lower_dur;
178                         else
179                                 return upper_dur;
180                 }
181                 lower_dur = upper_dur;
182         }
183         return Duration( 0 );
184 }
185 #endif
186
187 Moment
188 Duration_convert::plet_factor_mom( Duration dur )
189 {
190         if ( !dur.plet_p_ )
191                 return 1;
192         return Moment( dur.plet_p_->iso_i_, dur.plet_p_->type_i_ );
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         /* this is cute, 
205            but filling an array using Duration_iterator
206            might speed things up, a little
207            */
208         Moment mom( ticks_i, Duration::division_1_i_s );
209         Duration_iterator iter_dur;
210         assert( iter_dur );
211         while ( iter_dur ) {
212                 Duration dur = iter_dur++;
213                 if ( mom == dur2_mom( dur ) )
214                         return dur;
215         }
216         Duration dur( 0 );
217         dur.set_ticks( ticks_i );
218         return dur;
219 }
220
221 Duration
222 Duration_convert::ticks2standardised_dur( int ticks_i )
223 {
224         /* this is cute, 
225            but filling an array using Duration_iterator
226            might speed things up, a little
227            */
228         Moment mom( ticks_i, Duration::division_1_i_s );
229         Duration_iterator iter_dur;
230         assert( iter_dur );
231         while ( iter_dur ) {
232                 Duration lower_dur = iter_dur++;
233 //              Duration upper_dur( 0 );
234                 Duration upper_dur( 1, 1 );
235                 if ( iter_dur )
236                         upper_dur = iter_dur();
237                 Moment lower_mom = dur2_mom( lower_dur );
238                 Moment upper_mom = dur2_mom( upper_dur );
239                 if ( mom < lower_mom )
240                         return lower_dur;
241                 if ( mom == lower_mom )
242                         return lower_dur;
243                 if ( mom == upper_mom ) // don-t miss last (sic)
244                         return upper_dur;
245                 if ( ( mom >= lower_mom ) && ( mom <= upper_mom ) ) {
246                         warning( String( "duration not exact: " ) + String( (Real)mom ) , 0 );
247                         if ( abs( mom - lower_mom ) < abs( mom - upper_mom ) )
248                                 return lower_dur;
249                         else
250                                 return upper_dur;
251                 }
252                 lower_dur = upper_dur;
253         }
254         return iter_dur();
255 }
256
257 Duration_iterator::Duration_iterator()
258 {
259         cursor_dur_.type_i_ = 128;
260         if ( Duration_convert::no_smaller_than_i_s )
261                 cursor_dur_.type_i_ = Duration_convert::no_smaller_than_i_s;
262         cursor_dur_.set_plet( 0 );
263 }
264
265 Duration 
266 Duration_iterator::operator ++(int)
267 {
268         return forward_dur();
269 }
270
271 Duration
272 Duration_iterator::operator ()()
273 {
274         return dur();
275 }
276
277 Duration_iterator::operator bool()
278 {
279         return ok();
280 }
281
282 Duration
283 Duration_iterator::dur()
284 {
285         return cursor_dur_;
286 }
287
288 Duration
289 Duration_iterator::forward_dur()
290 {
291         // should do smart table? guessing: 
292         //      duration wholes
293         //      16      0.0625
294         //      32..    0.0703
295         //      8:2/3   0.0833
296         //      16.     0.0938
297         //      8       0.1250
298         //      16..    0.1406
299         //      4:2/3   0.1667
300         //      8.      0.1875
301
302         assert( ok() );
303
304         Duration dur = cursor_dur_;
305
306         if ( !cursor_dur_.dots_i_ && !cursor_dur_.plet_p_ ) {
307                 cursor_dur_.type_i_ *= 2;
308                 cursor_dur_.dots_i_ = 2;
309         }
310         else if ( cursor_dur_.dots_i_ == 2 ) {
311                 assert( !cursor_dur_.plet_p_ );
312                 cursor_dur_.dots_i_ = 0;
313                 cursor_dur_.type_i_ /= 4;
314                 cursor_dur_.set_plet( &Plet( 2, 3 ) );
315         }
316         else if ( cursor_dur_.plet_p_ 
317                 && ( cursor_dur_.plet_p_->iso_i_ == 2 )
318                 && ( cursor_dur_.plet_p_->type_i_ == 3 ) ) {
319                 assert( !cursor_dur_.dots_i_ );
320                 cursor_dur_.set_plet( 0 );
321                 cursor_dur_.type_i_ *= 2;
322                 cursor_dur_.dots_i_ = 1;
323         }
324         else if ( cursor_dur_.dots_i_ == 1 ) {
325                 assert( !cursor_dur_.plet_p_ );
326                 cursor_dur_.dots_i_ = 0;
327                 cursor_dur_.type_i_ /= 2;
328         }
329                 
330         if ( Duration_convert::no_triplets_b_s && cursor_dur_.plet_p_ && ok() )
331                 forward_dur();
332         if ( Duration_convert::no_double_dots_b_s && ( cursor_dur_.dots_i_ == 2 ) && ok() )
333                 forward_dur();
334         if ( Duration_convert::no_smaller_than_i_s && ( cursor_dur_.type_i_ > Duration_convert::no_smaller_than_i_s ) && ok() )
335                 forward_dur();
336         if ( Duration_convert::no_smaller_than_i_s && cursor_dur_.dots_i_ && ( cursor_dur_.type_i_ >= Duration_convert::no_smaller_than_i_s ) && ok() )
337                 forward_dur();
338         if ( Duration_convert::no_smaller_than_i_s && ( cursor_dur_.dots_i_ == 2 ) && ( cursor_dur_.type_i_ >= Duration_convert::no_smaller_than_i_s / 2 ) && ok() )
339                 forward_dur();
340
341         return dur;
342 }
343
344 bool
345 Duration_iterator::ok()
346 {
347         return ( cursor_dur_.type_i_ 
348                 && !( ( cursor_dur_.type_i_ == 1 ) && ( cursor_dur_.dots_i_ > 2 ) ) );
349 }