]> git.donarmstrong.com Git - lilypond.git/blob - lib/duration.cc
partial: 0.0.39-1.jcn
[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 Duration::Duration( int type_i, int dots_i = 0, Plet* plet_l )
18 {
19         type_i_ = type_i;
20         dots_i_ = dots_i;
21         plet_p_ = 0;
22         set_plet( plet_l );
23 }
24
25 Duration::Duration( Duration const& dur_c_r )
26 {
27         type_i_ = 0;
28         dots_i_ = 0;
29         plet_p_ = 0;
30         *this = dur_c_r;
31 }
32
33 Duration::~Duration()
34 {
35         delete plet_p_;
36 }
37
38 Duration const& 
39 Duration::operator =( Duration const& dur_c_r )
40 {
41         if ( &dur_c_r == this )
42                 return *this;
43
44         type_i_ = dur_c_r.type_i_;
45         dots_i_ = dur_c_r.dots_i_;
46         set_plet( dur_c_r.plet_p_ );
47
48         return *this;
49 }
50
51 void
52 Duration::set_plet( Plet* plet_l )
53 {
54         delete plet_p_;
55         plet_p_ = 0;
56         if ( plet_l )
57                 plet_p_ = new Plet( *plet_l );
58 }
59
60 Plet::Plet( int iso_i, int type_i )
61 {
62         iso_i_ = iso_i;
63         type_i_ = type_i;
64 }
65
66 Plet::Plet( Plet const& plet_c_r )
67 {
68         iso_i_ = plet_c_r.iso_i_;
69         type_i_ = plet_c_r.type_i_;
70 }
71
72 String 
73 Duration_convert::dur2_str( Duration dur )
74 {
75         String str( dur.type_i_ );
76         str += String( '.', dur.dots_i_ );
77         if ( dur.plet_p_ )
78                 str += String( "*" ) + String( dur.plet_p_->iso_i_ )
79                         + String( "/" ) + String( dur.plet_p_->type_i_ );
80         return str;
81 }
82
83 int
84 Duration_convert::dur2_i( Duration dur, int division_1_i )
85 {
86     return dur2_mom( dur ) * Moment( division_1_i );
87 }
88
89 Moment
90 Duration_convert::dur2_mom( Duration dur )
91 {
92         if ( !dur.type_i_ )
93                 return 0;
94
95         Moment mom = Moment( 1 , dur.type_i_ );
96
97         Moment delta = mom;
98         while ( dur.dots_i_-- ) {
99                 delta /= 2.0;
100                 mom += delta;
101         }
102
103         return mom * plet_factor_mom( dur );    
104 }
105
106 Duration
107 Duration_convert::mom2_dur( Moment mom )
108 {
109         /* this is cute, 
110            but filling an array using Duration_iterator
111            might speed things up, a little
112            */
113         Duration_iterator iter_dur;
114         assert( iter_dur );
115         while ( iter_dur ) {
116                 Duration lower_dur = iter_dur++;
117                 Duration upper_dur( 0 );
118                 if ( iter_dur )
119                         upper_dur = iter_dur();
120                 Moment lower_mom = dur2_mom( lower_dur );
121                 Moment upper_mom = dur2_mom( upper_dur );
122                 if ( mom == lower_mom )
123                         return lower_dur;
124                 if ( mom == upper_mom ) // don-t miss last (sic)
125                         return upper_dur;
126                 if ( ( mom >= lower_mom ) && ( mom <= upper_mom ) ) {
127                         warning( String( "duration not exact: " ) + String( (Real)mom ) , 0 );
128                         if ( abs( mom - lower_mom ) < abs( mom - upper_mom ) )
129                                 return lower_dur;
130                         else
131                                 return upper_dur;
132                 }
133                 lower_dur = upper_dur;
134         }
135         return Duration( 0 );
136 }
137
138 Moment
139 Duration_convert::plet_factor_mom( Duration dur )
140 {
141         if ( !dur.plet_p_ )
142                 return 1;
143         return Moment( dur.plet_p_->iso_i_, dur.plet_p_->type_i_ );
144 }
145
146 Real
147 Duration_convert::sync_f( Duration dur, Moment mom )
148 {
149         return mom / dur2_mom( dur );
150 }
151
152 Moment
153 Duration_convert::i2_mom( int time_i, int division_1_i )
154 {
155         if ( !time_i )
156                 return Moment( 0 );
157
158         if ( division_1_i > 0 )
159                 return Moment( time_i, division_1_i );
160         else 
161                 return Moment( -division_1_i, time_i );
162 }
163
164 Duration_iterator::Duration_iterator()
165 {
166         cursor_dur_.type_i_ = 128;
167         cursor_dur_.set_plet( 0 );
168 }
169
170 Duration 
171 Duration_iterator::operator ++(int)
172 {
173         return forward_dur();
174 }
175
176 Duration
177 Duration_iterator::operator ()()
178 {
179         return dur();
180 }
181
182 Duration_iterator::operator bool()
183 {
184         return ok();
185 }
186
187 Duration
188 Duration_iterator::dur()
189 {
190         return cursor_dur_;
191 }
192
193 Duration
194 Duration_iterator::forward_dur()
195 {
196         // should do smart table? guessing: 
197         //      duration wholes
198         //      16      0.0625
199         //      32..    0.0703
200         //      8:2/3   0.0833
201         //      16.     0.0938
202         //      8       0.1250
203         //      16..    0.1406
204         //      4:2/3   0.1667
205         //      8.      0.1875
206
207         assert( ok() );
208
209         Duration dur = cursor_dur_;
210
211         if ( !cursor_dur_.dots_i_ && !cursor_dur_.plet_p_ ) {
212                 cursor_dur_.type_i_ *= 2;
213                 cursor_dur_.dots_i_ = 2;
214         }
215         else if ( cursor_dur_.dots_i_ == 2 ) {
216                 assert( !cursor_dur_.plet_p_ );
217                 cursor_dur_.dots_i_ = 0;
218                 cursor_dur_.type_i_ /= 4;
219                 cursor_dur_.set_plet( &Plet( 2, 3 ) );
220         }
221         else if ( cursor_dur_.plet_p_ 
222                 && ( cursor_dur_.plet_p_->iso_i_ == 2 )
223                 && ( cursor_dur_.plet_p_->type_i_ == 3 ) ) {
224                 assert( !cursor_dur_.dots_i_ );
225                 cursor_dur_.set_plet( 0 );
226                 cursor_dur_.type_i_ *= 2;
227                 cursor_dur_.dots_i_ = 1;
228         }
229         else if ( cursor_dur_.dots_i_ == 1 ) {
230                 assert( !cursor_dur_.plet_p_ );
231                 cursor_dur_.dots_i_ = 0;
232                 cursor_dur_.type_i_ /= 2;
233         }
234                 
235         // ugh
236         if ( no_triplets_bo_g && cursor_dur_.plet_p_ && ok() )
237                 forward_dur();
238
239         return dur;
240 }
241
242 bool
243 Duration_iterator::ok()
244 {
245         return ( cursor_dur_.type_i_ 
246                 && !( ( cursor_dur_.type_i_ == 1 ) && ( cursor_dur_.dots_i_ > 2 ) ) );
247 }