root/branches/transport_redesign_2/test/t_TransportPosition.cpp @ 1136

Revision 1136, 26.2 KB (checked in by gabriel@…, 4 years ago)

Fix several tests for TransportPosition::operator+= and -=.

TransportPosition? now passes all tests. Woo-hoo!! :-)

Line 
1/*
2 * Hydrogen
3 * Copyright(c) 2002-2008 by Alex >Comix< Cominu [comix@users.sourceforge.net]
4 *
5 * http://www.hydrogen-music.org
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY, without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20 *
21 */
22
23#include <hydrogen/TransportPosition.h>
24#include <boost/test/unit_test.hpp>
25
26#include <cmath>
27
28#define THIS_NAMESPACE t_TransportPosition
29#define THIS(x) t_TransportPosition##_##x
30
31using namespace H2Core;
32
33// "BOOST_CHECK( foo )" is too much typing....
34#define TX BOOST_CHECK
35
36namespace THIS_NAMESPACE
37{
38    struct Fixture
39    {
40        TransportPosition p;  // This is the "normal" one.
41        TransportPosition x;  // This one has an odd setup.
42
43        Fixture() : p() {
44            p.frame_rate = 48000;
45            p.beats_per_bar = 4;
46            p.beat_type = 4;
47            p.ticks_per_beat = 192;
48            p.beats_per_minute = 120.0;
49            // MEMO: p.frames_per_tick() == 125.0
50
51            // x init.
52            x.state = TransportPosition::ROLLING;
53            x.new_position = true;
54            x.frame = 8273901;
55            x.frame_rate = 196123;
56            x.bar = 349;
57            x.beat = 5;
58            x.tick = 18;
59            x.bbt_offset = 115;
60            x.bar_start_tick = 349;
61            x.beats_per_bar = 7;
62            x.beat_type = 8;
63            x.ticks_per_beat = 99;
64            x.beats_per_minute = 543.2;
65            // MEMO: x.frames_per_tick() == 218.81889588075154
66        }
67
68        ~Fixture() {}
69    };
70
71/**********************************************************************
72 * NOTE ON COMPARING FRAMES AND FRAME ADJUSTMENT
73 * =============================================
74 *
75 * Suppose you are summing x(n+1) = x(n) + e where x(i) and e are real
76 * numbers, and x(0) is known.
77 *
78 * If you calculate like this: x(n+1) = round(x(n) + e) you will
79 * consistantly drift away from the actual answer.  However, this is
80 * common to do in frame adjustment calculations where the tempo does
81 * not align with the frame rate.  The maximum error in this situation
82 * is 0.5 * n.
83 *
84 * To mitigate this error (without keeping track of decimal
85 * bbt_offsets), TransportPosition uses dithering.  A random number
86 * between [-.5, .5) is added to the number before rounding.  So:
87 *
88 * x(n+1) = round( x(n) + e + dither() )
89 *
90 * Theoretically, all of the dither()'s should sum up to zero and you
91 * would (usually) have no error over large 'n'.  However, it's not
92 * exactly the case.  In order to have tests that always pass, it
93 * would be nice to know what the tolerance is for error when
94 * comparing expected frame values to calculated frame values.
95 *
96 * To find a boundary for the error introduced by dithering (as
97 * opposed to the error introduced by rounding), I ran about 5000 sets
98 * with e between 0 and 11, and max n = 100000... taking the maximum
99 * errors for various slots.  (E.g. max error for n = [90, 100])
100 *
101 * I hand-fit [1] a couple of equations that always bounded the data.
102 * They are as follows:
103 *
104 *     max_err = 2.1 * Nops^.50   { Nops in [0, 400] }
105 *     max_err = 4.3 * Nops^.435  { Nops in (400, 100000] }
106 *
107 * Tabulated, here's what this function evaluates to:
108 *
109 *     MAXIMUM FRAME DRIFT (+/- frames)
110 *     ================================
111 *      Nops  | dither | no dither
112 *     -------+--------+-----------
113 *          1 |    2.1 |        1
114 *         10 |    6.6 |        5
115 *        100 |   21.0 |       50
116 *       1000 |   86.8 |      500
117 *      10000 |  236.3 |     5000
118 *     100000 | 1751.7 |    50000
119 *
120 * Note that these are WORST CASE.  It is typically much better.
121 * (E.g. over 100 ops I usually get 4.5 frames of drift). [2]
122 *
123 * [1] "Chi-by-eye."
124 *
125 * [2] As it happens, the fractional part of 'e' is the biggest factor
126 *     the determines how much error you will get.  If e is close to a
127 *     whole number, you will get very little error by dithering.
128 *     When e is midway between two numbers, you are more likely to
129 *     get larger errors.
130 *
131 **********************************************************************
132 */
133
134    static inline bool check_frame_drift(double TrueVal,
135                                         uint32_t Frame,
136                                         size_t Nops,
137                                         int Line)
138    {
139        double max_drift = 0.0;
140        bool rv;
141
142        double ActDrift = TrueVal - double(Frame);
143        if( Nops <= 1 ) {
144            max_drift = 1.0;
145        } else if( Nops <= 400 ) {
146            max_drift = 2.1 * sqrt(double(Nops));
147        } else {
148            max_drift = 4.3 * pow(double(Nops), .435);
149        }
150
151        rv = (fabs(ActDrift) <= max_drift);
152
153        if( ! rv ) {
154            BOOST_MESSAGE("In " << __FILE__ << "(" << Line << ") "
155                          << "Too much drift: True(" << TrueVal << ") "
156                          << "- Frame(" << Frame << ") = " << ActDrift
157                          << " [Limit is +/- " << max_drift
158                          << " for " << Nops << " ops]");
159        }
160
161        return rv;
162    }
163
164#define DRIFT(t, f, n) check_frame_drift(t, f, n, __LINE__)
165
166} // namespace THIS_NAMESPACE
167
168using namespace THIS_NAMESPACE;
169
170BOOST_FIXTURE_TEST_SUITE( THIS_NAMESPACE, Fixture );
171
172BOOST_AUTO_TEST_CASE( THIS(000_defaults) )
173{
174    // Test the defaults
175    TX( p.state == TransportPosition::STOPPED );
176    TX( p.new_position == true );
177    TX( p.frame == 0 );
178    TX( p.bar == 1 );
179    TX( p.beat == 1 );
180    TX( p.tick == 0 );
181    TX( p.bbt_offset == 0 );
182    TX( p.bar_start_tick == 0 );
183}
184
185BOOST_AUTO_TEST_CASE( THIS(010_copy_constructor) )
186{
187    TransportPosition y, z;
188
189    TX( y.state == TransportPosition::STOPPED );
190    TX( y.new_position == true );
191    TX( y.frame == 0 );
192    TX( y.bar == 1 );
193    TX( y.beat == 1 );
194    TX( y.tick == 0 );
195    TX( y.bbt_offset == 0 );
196    TX( y.bar_start_tick == 0 );
197
198    TX( z.state == TransportPosition::STOPPED );
199    TX( z.new_position == true );
200    TX( z.frame == 0 );
201    TX( z.bar == 1 );
202    TX( z.beat == 1 );
203    TX( z.tick == 0 );
204    TX( z.bbt_offset == 0 );
205    TX( z.bar_start_tick == 0 );
206
207    p.frame = 12345;
208    p.bar = 21;
209    p.beat = 39;
210    p.tick = -1;
211    y = p;
212    TX( 12345 == y.frame );
213    TX( 21 == y.bar );
214    TX( -1 == y.tick );
215    p.tick = 5;
216    y.tick = 123;
217    TX( 5 == p.tick );
218    TX( 123 == y.tick );
219
220    z = x;
221    TX( TransportPosition::ROLLING == z.state );
222    TX( true == z.new_position );
223    TX( 8273901 == z.frame );
224    TX( 196123 == z.frame_rate );
225    TX( 349 == z.bar );
226    TX( 5 == z.beat );
227    TX( 18 == z.tick );
228    TX( 115 == z.bbt_offset );
229    TX( 349 == z.bar_start_tick );
230    TX( 7 == z.beats_per_bar );
231    TX( 8 == z.beat_type );
232    TX( 99 == z.ticks_per_beat );
233    TX( 543.2 == z.beats_per_minute );
234}
235
236BOOST_AUTO_TEST_CASE( THIS(020_frames_per_tick) )
237{
238    TX( p.frames_per_tick() == 125.0 );
239
240    p.frame_rate = 123456;
241    p.ticks_per_beat = 48;
242    p.beats_per_minute = 33.12;
243    TX( round(p.frames_per_tick()) == 4659.0 );
244
245    TX( round(x.frames_per_tick()*100.0) == 21882.0 );
246}
247
248BOOST_AUTO_TEST_CASE( THIS(030_tick_in_bar) )
249{
250    TX(p.tick_in_bar() == 0);
251    p.tick = 191;
252    TX(p.tick_in_bar() == 191);
253    p.beat = 2;
254    TX(p.tick_in_bar() == 383);
255    p.bar = 9;
256    TX(p.tick_in_bar() == 383);
257
258    TX(x.tick_in_bar() == 414);
259}
260
261BOOST_AUTO_TEST_CASE( THIS(040_normalize) )
262{
263    TransportPosition a;
264    double frame;
265
266    // NOTE: normalize() only changes the frame position if it adjusts
267    // bbt_offset.
268
269    a = p;
270    a.tick += 192 * 6 + 101;
271    a.normalize();
272    TX( 2 == a.bar );
273    TX( 3 == a.beat );
274    TX( 101 == a.tick );
275    TX( 192 * 4 == a.bar_start_tick );
276    TX( DRIFT(0, a.frame, 1) );
277
278    a.beat -= 4;
279    a.normalize();
280    TX( 1 == a.bar );
281    TX( 3 == a.beat );
282    TX( 101 == a.tick );
283    TX( 0 == a.bar_start_tick );
284    TX( DRIFT(0, a.frame, 2) );
285
286    a.bar += 5;
287    a.normalize();
288    TX( 6 == a.bar );
289    TX( 3 == a.beat );
290    TX( 101 == a.tick );
291    TX( 0 == a.bar_start_tick ); // If you manually change bar, you also have
292                                 // to manually adjust bar_start_tick
293    TX( DRIFT(0, a.frame, 3) );
294
295    a = p;
296    frame = a.frame;
297    a.bbt_offset = 6 * 192 * 125 + 50;
298    frame += a.bbt_offset - 50;
299    a.normalize();
300    TX( 2 == a.bar );
301    TX( 3 == a.beat );
302    TX( 0 == a.tick );
303    TX( DRIFT(50.0, a.bbt_offset, 1) );
304    TX( 192 * 4 == a.bar_start_tick );
305    TX( DRIFT(frame, a.frame, 1) );
306
307    a = x;
308    frame = a.frame;
309    a.tick -= 99 * 12 + 65;
310    a.normalize();
311    TX( 347 == a.bar );
312    TX( 6 == a.beat );
313    TX( 52 == a.tick );
314    TX( 115 == a.bbt_offset );
315    TX( 0 == a.bar_start_tick );
316    TX( DRIFT(frame, a.frame, 1) );
317
318    a = x;
319    frame = a.frame;
320    a.beat += 13;
321    a.normalize();
322    TX( 351 == a.bar );
323    TX( 4 == a.beat );
324    TX( 18 == a.tick );
325    TX( 115 == a.bbt_offset );
326    TX( 349 + 2 * 7 * 99 == a.bar_start_tick );
327    TX( DRIFT(frame, a.frame, 1) );
328
329    a = x;
330    a.bar_start_tick = 70000;
331    a.bar -= 11;
332    a.normalize();  // Does not change bar start tick
333    TX( 338 == a.bar );
334    TX( 5 == a.beat );
335    TX( 18 == a.tick );
336    TX( 115 == a.bbt_offset );
337    TX( 70000 == a.bar_start_tick );
338
339    a = x;                // 349:5.18.115 (70000)  349.59816096502567
340    a.bar_start_tick = 70000;
341    frame = a.frame;
342    a.bar += 3;           // 352:5.18.115 (70000)  352.59816096502567
343    a.beat -= 29;         // 348:4.18.115 (67228)  348.45530382216856
344    a.tick += 999;        // 349:7.27.115 (67921)  349.89686226372697
345    a.bbt_offset += 3114; // 349:7.41.165 (67921)  349.91739754005869
346    frame += 3114.0 - 165.0 + 115.0;
347    a.normalize();
348    TX( 349 == a.bar );
349    TX( 7 == a.beat );
350    TX( 41 == a.tick );
351    TX( 165 == a.bbt_offset );
352    TX( 67921 == a.bar_start_tick );
353    TX( DRIFT(frame, a.frame, 1) );   
354}
355
356BOOST_AUTO_TEST_CASE( THIS(050_increment) )
357{
358    double frames_per_tick = double(p.frame_rate) * (60.0/p.beats_per_minute) / p.ticks_per_beat;
359    int k;
360
361    TX( p.frame == 0 );
362    double frame = 0.0;
363    for( k=1 ; (unsigned)k<p.ticks_per_beat ; ++k ) {
364        ++p;
365        frame += frames_per_tick;
366        TX( 1 == p.bar );
367        TX( 1 == p.beat );         
368        TX( k == p.tick );
369        TX( DRIFT(frame, p.frame, 1) );
370    }
371
372    TX( p.tick == 191 );
373    ++p;
374    frame += frames_per_tick;
375    TX( 1 == p.bar );
376    TX( 2 == p.beat );
377    TX( 0 == p.tick );
378    TX( DRIFT(frame, p.frame, 2) );
379    ++p;
380    frame += frames_per_tick;
381    TX( 1 == p.bar );
382    TX( 2 == p.beat );
383    TX( 1 == p.tick );
384    TX( DRIFT(frame, p.frame, 3) );
385    p.bar = 99;
386    p.beat = 3;
387    ++p;
388    frame += frames_per_tick;
389    TX( 99 == p.bar );
390    TX( 3 == p.beat );
391    TX( 2 == p.tick );
392    TX( DRIFT(frame, p.frame, 4) );
393
394    // Tests with 'x'
395    frame = x.frame;
396    frames_per_tick = x.frames_per_tick();
397    for( k=x.tick+1 ; (unsigned)k < x.ticks_per_beat ; ++k ) {
398        ++x;
399        frame += frames_per_tick;
400        TX( 349 == x.bar );
401        TX( 5 == x.beat );
402        TX( k == x.tick );
403        TX( 115 == x.bbt_offset );
404        TX( DRIFT( frame, x.frame, k ) );
405    }
406    TX( x.tick == 98 );
407    ++x;
408    frame += frames_per_tick;
409    TX( 349 == x.bar );
410    TX( 6 == x.beat );
411    TX( 0 == x.tick );
412    TX( 115 == x.bbt_offset );
413    TX( DRIFT( frame, x.frame, k+1 ) );
414
415    x.beat = 7;
416    x.tick = 98;
417    ++x;
418    frame += frames_per_tick;
419    TX( 350 == x.bar );
420    TX( 1 == x.beat );
421    TX( 0 == x.tick );
422    TX( 115 == x.bbt_offset );
423    TX( DRIFT( frame, x.frame, k+2 ) );
424    BOOST_MESSAGE( "++ drift = " << (frame - x.frame) );
425}
426
427BOOST_AUTO_TEST_CASE( THIS(060_decrement) )
428{
429    --p;
430    TX( 0 == p.frame );
431    TX( 1 == p.bar );
432    TX( 1 == p.beat );
433    TX( 0 == p.tick );
434    TX( 0 == p.bbt_offset );
435    TX( 0 == p.bar_start_tick );
436    ++p;
437    --p;
438    TX( 0 == p.frame );
439    TX( 1 == p.bar );
440    TX( 1 == p.beat );
441    TX( 0 == p.tick );
442    TX( 0 == p.bbt_offset );
443    TX( 0 == p.bar_start_tick );
444
445    p.bar = 5;
446    p.beat = 2;
447    p.tick = 1;
448    --p; --p;
449    TX( 0 == p.frame );
450    TX( 5 == p.bar );
451    TX( 1 == p.beat );
452    TX( 191 == p.tick );
453
454    double frame = 0.0;
455    double fpt = p.frames_per_tick();
456    p.frame = 1000.0;
457    p.bar = 5;
458    p.beat = 2;
459    p.tick = 1;
460    frame = p.frame;
461    --p; --p;
462    frame -= 2.0 * fpt;
463    TX( frame >= 0.0 );
464    TX( DRIFT(frame, p.frame, 2) );
465    TX( 5 == p.bar );
466    TX( 1 == p.beat );
467    TX( 191 == p.tick );
468
469    frame = 100000.0;
470    p.frame = frame;
471    p.bar = 100;
472    p.beat = 1;
473    p.tick = 0;
474    int k = p.ticks_per_beat * p.beats_per_bar;
475    frame -= fpt * k;
476    while( k > 0 ) {
477        --k; --p;
478    }
479    double drift = fabs( frame - double(p.frame) );
480    BOOST_MESSAGE( "-- drift @ 768 = " << drift );
481    TX( fabs(drift) < 10.0 );
482    TX( p.bar == 99 );
483    TX( p.beat == 1 );
484    TX( p.tick == 0 );
485
486    // Using the 'x' object
487    fpt = x.frames_per_tick();
488    frame = x.frame;
489    --x;
490    frame -= fpt;
491    TX( fabs(frame - x.frame) <= 1.0 );
492
493    for( k=2374 ; k > 0 ; --k ) --x;
494    frame -= fpt * 2374.0;
495    drift = frame - double(x.frame);
496    BOOST_MESSAGE( "-- drift @ 2375 = " << drift );
497    TX( fabs(drift) < 50.0 );
498    TX( 346 == x.bar );
499    TX( 2 == x.beat );
500    TX( 19 == x.tick );
501       
502}
503
504BOOST_AUTO_TEST_CASE( THIS(070_floor) )
505{
506    p.floor(TransportPosition::TICK);
507    TX( 1 == p.bar );
508    TX( 1 == p.beat );
509    TX( 0 == p.tick );
510    TX( 0 == p.frame );
511    p.floor(TransportPosition::BEAT);
512    TX( 1 == p.bar );
513    TX( 1 == p.beat );
514    TX( 0 == p.tick );
515    TX( 0 == p.frame );
516    p.floor(TransportPosition::BAR);
517    TX( 1 == p.bar );
518    TX( 1 == p.beat );
519    TX( 0 == p.tick );
520    TX( 0 == p.frame );
521
522    double fpt = p.frames_per_tick();
523    p.tick = 1;
524    p.bbt_offset = 921;
525    p.frame = round(fpt);
526    p.floor(TransportPosition::TICK);
527    TX( 1 == p.bar );
528    TX( 1 == p.beat );
529    TX( 8 == p.tick );
530    TX( DRIFT(954.0, p.frame, 1) );
531    TX( 0 == p.bbt_offset );
532    p.tick = 1;
533    p.bbt_offset = 921;
534    p.frame = round(fpt);
535    p.floor(TransportPosition::BEAT);
536    TX( 1 == p.bar );
537    TX( 1 == p.beat );
538    TX( 0 == p.tick );
539    TX( 0 == p.frame );
540    TX( 0 == p.bbt_offset );
541    p.tick = 1;
542    p.bbt_offset = 921;
543    p.frame = round(fpt);
544    p.floor(TransportPosition::BAR);
545    TX( 1 == p.bar );
546    TX( 1 == p.beat );
547    TX( 0 == p.tick );
548    TX( 0 == p.frame );
549    TX( 0 == p.bbt_offset );
550
551    p.tick = 1;
552    p.bbt_offset = 921;
553    p.frame = round(fpt/2.0);
554    p.floor(TransportPosition::BAR);
555    TX( 1 == p.bar );
556    TX( 1 == p.beat );
557    TX( 0 == p.tick );
558    TX( 0 == p.frame );
559    TX( 0 == p.bbt_offset );
560
561    TransportPosition tmp = x;
562    double lastframe = tmp.frame;
563    tmp.floor(TransportPosition::TICK);
564    TX( tmp.bar == 349 );
565    TX( tmp.beat == 5 );
566    TX( tmp.tick == 18 );
567    TX( tmp.bbt_offset == 0 );
568    lastframe -= 115.0;
569    TX( DRIFT(lastframe, tmp.frame, 1) );
570    // Repeating when already floored should
571    // give the same result.
572    tmp.floor(TransportPosition::TICK);
573    TX( tmp.bar == 349 );
574    TX( tmp.beat == 5 );
575    TX( tmp.tick == 18 );
576    TX( tmp.bbt_offset == 0 );
577    TX( DRIFT(lastframe, tmp.frame, 1) );
578
579    tmp = x;
580    tmp.floor(TransportPosition::BEAT);
581    TX( tmp.bar == 349 );
582    TX( tmp.beat == 5 );
583    TX( tmp.tick == 0 );
584    TX( tmp.bbt_offset == 0 );
585    lastframe -= 18.0 * tmp.frames_per_tick();
586    TX( DRIFT(lastframe, tmp.frame, 1) );
587    // Repeating when already floored should
588    // give the same result.
589    tmp.floor(TransportPosition::BEAT);
590    TX( tmp.bar == 349 );
591    TX( tmp.beat == 5 );
592    TX( tmp.tick == 0 );
593    TX( tmp.bbt_offset == 0 );
594    TX( DRIFT(lastframe, tmp.frame, 1) );
595
596    tmp = x;
597    tmp.floor(TransportPosition::BAR);
598    TX( tmp.bar == 349 );
599    TX( tmp.beat == 1 );
600    TX( tmp.tick == 0 );
601    TX( tmp.bbt_offset == 0 );
602    lastframe = x.frame - 4.0 * 99.0 * tmp.frames_per_tick()
603        - x.tick * tmp.frames_per_tick() - x.bbt_offset;
604    TX( DRIFT(lastframe, tmp.frame, 1) );
605    // Repeating when already floored should
606    // give the same result.
607    tmp.floor(TransportPosition::BAR);
608    TX( tmp.bar == 349 );
609    TX( tmp.beat == 1 );
610    TX( tmp.tick == 0 );
611    TX( tmp.bbt_offset == 0 );
612    TX( DRIFT(lastframe, tmp.frame, 1) );
613
614}
615
616BOOST_AUTO_TEST_CASE( THIS(080_ceil) )
617{
618    p.ceil(TransportPosition::TICK);
619    TX( 1 == p.bar );
620    TX( 1 == p.beat );
621    TX( 0 == p.tick );
622    TX( 0 == p.frame );
623    p.ceil(TransportPosition::BEAT);
624    TX( 1 == p.bar );
625    TX( 1 == p.beat );
626    TX( 0 == p.tick );
627    TX( 0 == p.frame );
628    p.ceil(TransportPosition::BAR);
629    TX( 1 == p.bar );
630    TX( 1 == p.beat );
631    TX( 0 == p.tick );
632    TX( 0 == p.frame );
633
634    double fpt = p.frames_per_tick();
635    double frame;
636    p.tick = 1;
637    p.bbt_offset = 75;
638    p.frame = round(fpt);
639    frame = p.frame + fpt - p.bbt_offset;
640    p.ceil(TransportPosition::TICK);
641    TX( 1 == p.bar );
642    TX( 1 == p.beat );
643    TX( 2 == p.tick );
644    TX( DRIFT(frame, p.frame, 1) );
645    TX( 0 == p.bbt_offset );
646    p.tick = 1;
647    p.bbt_offset = 921;
648    p.frame = round(fpt);
649    p.ceil(TransportPosition::BEAT);
650    TX( 1 == p.bar );
651    TX( 2 == p.beat );
652    TX( 0 == p.tick );
653    TX( DRIFT(23953.0, p.frame, 2) ); // 2 internal ops.
654    TX( 0 == p.bbt_offset );
655    p.tick = 1;
656    p.bbt_offset = 921;
657    p.frame = round(fpt);
658    p.ceil(TransportPosition::BAR);
659    TX( 2 == p.bar );
660    TX( 1 == p.beat );
661    TX( 0 == p.tick );
662    TX( DRIFT(71955.0, p.frame, 2) ); // 2 internal ops
663    TX( 0 == p.bbt_offset );
664    TX( 192 * 4 == p.bar_start_tick );
665
666    p.tick = 1;
667    p.bbt_offset = 921;
668    p.frame = round(fpt/2.0);
669    p.ceil(TransportPosition::BAR);
670    TX( 3 == p.bar );
671    TX( 1 == p.beat );
672    TX( 0 == p.tick );
673    TX( DRIFT(95891.0, p.frame, 2) );
674    TX( 0 == p.bbt_offset );
675    TX( 192 * 4 * 2 == p.bar_start_tick );
676
677    // TODO:  ADD MORE TESTS FOR BAR START TICK
678
679    TransportPosition tmp = x;
680    double lastframe = tmp.frame;
681    tmp.ceil(TransportPosition::TICK);
682    TX( tmp.bar == 349 );
683    TX( tmp.beat == 5 );
684    TX( tmp.tick == 19 );
685    TX( tmp.bbt_offset == 0 );
686    lastframe += (x.frames_per_tick() - 115.0);
687    TX( DRIFT(lastframe, tmp.frame, 1) );
688    // Repeating when already ceiled should
689    // give the same result.
690    tmp.ceil(TransportPosition::TICK);
691    TX( tmp.bar == 349 );
692    TX( tmp.beat == 5 );
693    TX( tmp.tick == 19 );
694    TX( tmp.bbt_offset == 0 );
695    TX( DRIFT(lastframe, tmp.frame, 1) );
696
697    tmp = x;
698    lastframe = tmp.frame;
699    tmp.ceil(TransportPosition::BEAT);
700    TX( tmp.bar == 349 );
701    TX( tmp.beat == 6 );
702    TX( tmp.tick == 0 );
703    TX( tmp.bbt_offset == 0 );
704    lastframe += (99.0 - 18.0) * tmp.frames_per_tick() - 115.0;
705    TX( DRIFT(lastframe, tmp.frame, 1) );
706    // Repeating when already ceiled should
707    // give the same result.
708    tmp.ceil(TransportPosition::BEAT);
709    TX( tmp.bar == 349 );
710    TX( tmp.beat == 6 );
711    TX( tmp.tick == 0 );
712    TX( tmp.bbt_offset == 0 );
713    TX( DRIFT(lastframe, tmp.frame, 1) );
714
715    tmp = x;
716    lastframe = tmp.frame;
717    lastframe += ((2.0 * 99.0) + (99.0 - 18.0)) * tmp.frames_per_tick()
718        - tmp.bbt_offset;
719    tmp.ceil(TransportPosition::BAR);
720    TX( tmp.bar == 350 );
721    TX( tmp.beat == 1 );
722    TX( tmp.tick == 0 );
723    TX( tmp.bbt_offset == 0 );
724    TX( DRIFT(lastframe, tmp.frame, 1) );
725    // Repeating when already ceiled should
726    // give the same result.
727    tmp.ceil(TransportPosition::BAR);
728    TX( tmp.bar == 350 );
729    TX( tmp.beat == 1 );
730    TX( tmp.tick == 0 );
731    TX( tmp.bbt_offset == 0 );
732    TX( DRIFT(lastframe, tmp.frame, 1) );
733}
734
735BOOST_AUTO_TEST_CASE( THIS(090_round) )
736{
737    TransportPosition a;
738    double frame;
739
740    a = p;
741    a.round(TransportPosition::TICK);
742    TX( 0 == a.frame );
743    TX( 1 == a.bar );
744    TX( 1 == a.beat );
745    TX( 0 == a.tick );
746    TX( 0 == a.bbt_offset );
747    a.round(TransportPosition::BEAT);
748    TX( 0 == a.frame );
749    TX( 1 == a.bar );
750    TX( 1 == a.beat );
751    TX( 0 == a.tick );
752    TX( 0 == a.bbt_offset );
753    a.round(TransportPosition::BAR);
754    TX( 0 == a.frame );
755    TX( 1 == a.bar );
756    TX( 1 == a.beat );
757    TX( 0 == a.tick );
758    TX( 0 == a.bbt_offset );
759
760    a = p;
761    a.bbt_offset = a.frames_per_tick() / 4.0;
762    a.round(TransportPosition::TICK);
763    TX( 0 == a.frame );
764    TX( 1 == a.bar );
765    TX( 1 == a.beat );
766    TX( 0 == a.tick );
767    TX( 0 == a.bbt_offset );
768    a.bbt_offset = a.frames_per_tick() * 3.0 / 4.0;
769    frame = a.frame + round(a.frames_per_tick() / 4.0);
770    a.round(TransportPosition::TICK);
771    TX( DRIFT( frame, a.frame, 1 ) );
772    TX( 1 == a.bar );
773    TX( 1 == a.beat );
774    TX( 1 == a.tick );
775    TX( 0 == a.bbt_offset );
776    // Re-rounding should not change anything
777    a.round(TransportPosition::TICK);
778    TX( DRIFT( frame, a.frame, 1 ) );
779    TX( 1 == a.bar );
780    TX( 1 == a.beat );
781    TX( 1 == a.tick );
782    TX( 0 == a.bbt_offset );
783
784    // Could use more checks near the zero-point,
785    // but we'll move on.
786
787    a = x;
788    frame = a.frame;
789    frame += a.frames_per_tick() - a.bbt_offset;
790    a.round(TransportPosition::TICK);
791    TX( 349 == a.bar );
792    TX( 5 == a.beat );
793    TX( 19 == a.tick );
794    TX( 0 == a.bbt_offset );
795    TX( DRIFT( frame, a.frame, 1 ) );
796
797    frame -= a.frames_per_tick() * double(a.tick);
798    a.round(TransportPosition::BEAT);
799    TX( 349 == a.bar );
800    TX( 5 == a.beat );
801    TX( 0 == a.tick );
802    TX( 0 == a.bbt_offset );
803    TX( DRIFT( frame, a.frame, 2 ) );
804
805    frame += a.frames_per_tick() * 99.0 * 3.0;
806    a.round(TransportPosition::BAR);
807    TX( 350 == a.bar );
808    TX( 1 == a.beat );
809    TX( 0 == a.tick );
810    TX( 0 == a.bbt_offset );
811    TX( DRIFT( frame, a.frame, 3 ) );
812
813    // Could use more checks... but we'll move on.
814
815}
816
817BOOST_AUTO_TEST_CASE( THIS(100_operator_plus) )
818{
819    unsigned k;
820    TransportPosition a;
821    double fpt;
822    double frame;
823
824    a = p + (-51);
825    TX( 1 == a.bar );
826    TX( 1 == a.beat );
827    TX( 0 == a.tick );
828    TX( 0 == a.bbt_offset );
829    TX( 0 == a.frame );
830
831    a = p;
832    fpt = a.frames_per_tick();
833    for( k=0 ; k<191 ; ++k ) {
834        a = a + 1;
835        TX( 1 == a.bar );
836        TX( 1 == a.beat );
837        TX( (k+1) == unsigned(a.tick) );
838        TX( DRIFT( double(k+1) * fpt, a.frame, k ) );
839    }
840    TX( 191 == a.tick );
841    ++k;
842    a = a + 1;
843    TX( 1 == a.bar );
844    TX( 2 == a.beat );
845    TX( 0 == a.tick );
846    TX( DRIFT( double(k) * fpt, a.frame, k ) );
847
848    k = 192 * 2 + 30;
849    a = p + k;
850    TX( 1 == a.bar );
851    TX( 3 == a.beat );
852    TX( 30 == a.tick );
853    TX( DRIFT( double(k) * fpt, a.frame, 1 ) );
854
855
856    k = 99 * 5 + 64;
857    a = x + k;
858    frame = x.frame + (99*5 + 64) * x.frames_per_tick();
859    TX( 350 == a.bar );
860    TX( 3 == a.beat );
861    TX( 82 == a.tick );
862    TX( 115 == a.bbt_offset );
863    TX( DRIFT( frame, a.frame, 1 ) );
864
865    a = a + (-k);
866    frame = x.frame;
867    TX( 349 == a.bar );
868    TX( 5 == a.beat );
869    TX( 18 == a.tick );
870    TX( 115 == a.bbt_offset );
871    TX( DRIFT( frame, a.frame, 2 ) );
872}
873
874BOOST_AUTO_TEST_CASE( THIS(110_operator_minus) )
875{
876    unsigned k;
877    TransportPosition a;
878    double fpt;
879
880    a = p - 51;
881    TX( 1 == a.bar );
882    TX( 1 == a.beat );
883    TX( 0 == a.tick );
884    TX( 0 == a.bbt_offset );
885    TX( 0 == a.frame );
886
887    a = p;
888    a.bar = 2;
889    a.beat = 1;
890    a.tick = 0;
891    a.frame = 2000000;
892    fpt = a.frames_per_tick();
893    for( k=192 ; k>0 ; --k ) {
894        a = a - 1;
895        TX( 1 == a.bar );
896        TX( 4 == a.beat );
897        TX( (k-1) == unsigned(a.tick) );
898        TX( DRIFT( 2000000.0 - (double(192-k+1) * fpt), a.frame, (193-k) ) );
899    }
900    TX( 0 == a.tick );
901    a = a - 1;
902    k = 193;
903    TX( 1 == a.bar );
904    TX( 3 == a.beat );
905    TX( 191 == a.tick );
906    TX( DRIFT( 2000000.0 - (double(k) * fpt), a.frame, k ) );
907
908    k = 99 * 2 + 30;
909    a = x - k;
910    fpt = x.frames_per_tick();
911    TX( 349 == a.bar );
912    TX( 2 == a.beat );
913    TX( 87 == a.tick );
914    TX( 115 == a.bbt_offset );
915    TX( DRIFT( double(x.frame) - (double(k) * fpt), a.frame, 1 ) );
916
917    k = 99 * 5 + 64;
918    a = x - k;
919    TX( 348 == a.bar );
920    TX( 6 == a.beat );
921    TX( 53 == a.tick );
922    TX( 115 == a.bbt_offset );
923    TX( DRIFT( double(x.frame) - double(k) * fpt, a.frame, 1 ) );
924
925    a = a - (-k);
926    TX( 349 == a.bar );
927    TX( 5 == a.beat );
928    TX( 18 == a.tick );
929    TX( 115 == a.bbt_offset );
930    TX( DRIFT( double(x.frame), a.frame, 2 ) );
931}
932
933BOOST_AUTO_TEST_CASE( THIS(120_operator_plus_equals) )
934{
935    unsigned k;
936    TransportPosition a;
937    double fpt;
938
939    a = p;
940    fpt = a.frames_per_tick();
941    for( k=0 ; k<191 ; ++k ) {
942        a += 1;
943        TX( 1 == a.bar );
944        TX( 1 == a.beat );
945        TX( k+1 == unsigned(a.tick) );
946        TX( DRIFT( double(k+1) * fpt, a.frame, k ) );
947    }
948    TX( 191 == a.tick );
949    ++k;
950    a += 1;
951    TX( 1 == a.bar );
952    TX( 2 == a.beat );
953    TX( 0 == a.tick );
954    TX( DRIFT( double(k) * fpt, a.frame, k ) );
955
956    k = 192 * 2 + 30;
957    a = p;
958    a += k;
959    TX( 1 == a.bar );
960    TX( 3 == a.beat );
961    TX( 30 == a.tick );
962    TX( DRIFT( double(k) * fpt, a.frame, 1 ) );
963
964    k = 99 * 5 + 64;
965    a = x;
966    a += k;
967    fpt = a.frames_per_tick();
968    TX( 350 == a.bar );
969    TX( 3 == a.beat );
970    TX( 82 == a.tick );
971    TX( 115 == a.bbt_offset );
972    TX( DRIFT( double(x.frame) + double(k) * fpt, a.frame, 1 ) );
973
974    a += (-k);
975    TX( 349 == a.bar );
976    TX( 5 == a.beat );
977    TX( 18 == a.tick );
978    TX( 115 == a.bbt_offset );
979    TX( DRIFT( double(x.frame), a.frame, 2 ) );
980}
981
982BOOST_AUTO_TEST_CASE( THIS(130_operator_minus_equals) )
983{
984    unsigned k;
985    TransportPosition a;
986    double fpt;
987
988    a = p;
989    a -= 51;
990    TX( 1 == a.bar );
991    TX( 1 == a.beat );
992    TX( 0 == a.tick );
993    TX( 0 == a.bbt_offset );
994    TX( 0 == a.frame );
995
996    a = p;
997    a.bar = 2;
998    a.beat = 1;
999    a.tick = 0;
1000    a.frame = 2000000;
1001    fpt = a.frames_per_tick();
1002    for( k=192 ; k>0 ; --k ) {
1003        a -= 1;
1004        TX( 1 == a.bar );
1005        TX( 4 == a.beat );
1006        TX( (k-1) == unsigned(a.tick) );
1007        TX( DRIFT( 2000000.0 - (double(192-k+1) * fpt), a.frame, (193-k) ) );
1008    }
1009    TX( 0 == a.tick );
1010    a -= 1;
1011    k = 193;
1012    TX( 1 == a.bar );
1013    TX( 3 == a.beat );
1014    TX( 191 == a.tick );
1015    TX( DRIFT( 2000000.0 - (double(k) * fpt), a.frame, k ) );
1016
1017    k = 99 * 2 + 30;
1018    a = x;
1019    a -= k;
1020    fpt = x.frames_per_tick();
1021    TX( 349 == a.bar );
1022    TX( 2 == a.beat );
1023    TX( 87 == a.tick );
1024    TX( 115 == a.bbt_offset );
1025    TX( DRIFT( double(x.frame) - (double(k) * fpt), a.frame, 1 ) );
1026
1027    k = 99 * 5 + 64;
1028    a = x;
1029    a -= k;
1030    TX( 348 == a.bar );
1031    TX( 6 == a.beat );
1032    TX( 53 == a.tick );
1033    TX( 115 == a.bbt_offset );
1034    TX( DRIFT( double(x.frame) - double(k) * fpt, a.frame, 1 ) );
1035
1036    a -= (-k);
1037    TX( 349 == a.bar );
1038    TX( 5 == a.beat );
1039    TX( 18 == a.tick );
1040    TX( 115 == a.bbt_offset );
1041    TX( DRIFT( double(x.frame), a.frame, 2 ) );
1042}
1043
1044BOOST_AUTO_TEST_SUITE_END()
Note: See TracBrowser for help on using the browser.