From 34400df5897ebe7d33bd0a8e293c4a6cb885e0ca Mon Sep 17 00:00:00 2001 From: Jonathan Moore Liles Date: Wed, 30 Apr 2008 16:03:58 -0500 Subject: [PATCH] Attempt to draw measure lines with a more efficient incremental algorithm. --- Timeline/Region.C | 2 +- Timeline/Sequence.H | 1 + Timeline/Tempo_Sequence.H | 26 ++++++++---- Timeline/Time_Point.H | 33 ++++++++++----- Timeline/Timeline.C | 88 ++++++++++++++++++++++++++++++++++++--- Timeline/Timeline.H | 1 + 6 files changed, 126 insertions(+), 25 deletions(-) diff --git a/Timeline/Region.C b/Timeline/Region.C index b8b66af..e2b908f 100644 --- a/Timeline/Region.C +++ b/Timeline/Region.C @@ -712,7 +712,7 @@ Region::draw ( void ) } /* FIXME: only draw as many as are necessary! */ - timeline->draw_measure_lines( rx, Y, rw, H, _box_color ); + timeline->draw_measure_lines( X, Y, W, H, _box_color ); /* fl_color( FL_BLACK ); */ /* fl_line( rx, Y, rx, Y + H ); */ diff --git a/Timeline/Sequence.H b/Timeline/Sequence.H index 4572cdc..e32f4c1 100644 --- a/Timeline/Sequence.H +++ b/Timeline/Sequence.H @@ -49,6 +49,7 @@ protected: char *_name; + friend class Timeline; // for draw_measure std::list _widgets; Sequence_Widget *event_widget ( void ); diff --git a/Timeline/Tempo_Sequence.H b/Timeline/Tempo_Sequence.H index 1bb909c..cc97587 100644 --- a/Timeline/Tempo_Sequence.H +++ b/Timeline/Tempo_Sequence.H @@ -34,25 +34,37 @@ public: // box( FL_DOWN_BOX ); } + + /** return a pointer to the closest tempo point *before* /when/ */ + Tempo_Point * + at ( nframes_t when ) + { + for ( std::list ::const_reverse_iterator i = _widgets.rbegin(); + i != _widgets.rend(); i++ ) + if ( (*i)->offset() < when ) + return ((Tempo_Point*)(*i)); + + return NULL; + } + float beats_per_minute ( nframes_t when ) { // sort(); - for ( std::list ::const_reverse_iterator i = _widgets.rbegin(); - i != _widgets.rend(); i++ ) - { - if ( (*i)->offset() < when ) - return ((Tempo_Point*)(*i))->tempo(); - } + Tempo_Point *p = at( when ); - return 120.0; + if ( p ) + return p->tempo(); + else + return 120.0; } void beats_per_minute ( nframes_t when, float bpm ) { add( new Tempo_Point( when, bpm ) ); + sort(); } }; diff --git a/Timeline/Time_Point.H b/Timeline/Time_Point.H index 5c5e807..653071a 100644 --- a/Timeline/Time_Point.H +++ b/Timeline/Time_Point.H @@ -104,18 +104,29 @@ public: void time ( int bpb, int note ) { _time.beats_per_bar = bpb; _time.beat_type = note; } time_sig time ( void ) const { return _time; } - int - handle ( int m ) - { - int r = Sequence_Widget::handle( m ); +/* Time_Point * */ +/* at ( nframes_t when ) */ +/* { */ +/* for ( std::list ::const_reverse_iterator i = _widgets.rbegin(); */ +/* i != _widgets.rend(); i++ ) */ +/* if ( (*i)->offset() < when ) */ +/* return ((Time_Point*)(*i)); */ - if ( m == FL_RELEASE ) - { - _track->sort(); - timeline->redraw(); - } - return r; - } +/* return NULL; */ +/* } */ + +/* int */ +/* handle ( int m ) */ +/* { */ +/* int r = Sequence_Widget::handle( m ); */ + +/* if ( m == FL_RELEASE ) */ +/* { */ +/* _track->sort(); */ +/* timeline->redraw(); */ +/* } */ +/* return r; */ +/* } */ }; diff --git a/Timeline/Timeline.C b/Timeline/Timeline.C index dca48d4..1f2f67b 100644 --- a/Timeline/Timeline.C +++ b/Timeline/Timeline.C @@ -151,6 +151,12 @@ Timeline::Timeline ( int X, int Y, int W, int H, const char* L ) : Fl_Overlay_Wi o->align( FL_ALIGN_LEFT ); tempo_track = o; + + o->beats_per_minute( 0, 120 ); + + o->beats_per_minute( 48000 * 50, 250 ); + + o->beats_per_minute( 48000 * 120, 60 ); } { @@ -162,6 +168,8 @@ Timeline::Timeline ( int X, int Y, int W, int H, const char* L ) : Fl_Overlay_Wi o->align( FL_ALIGN_LEFT ); time_track = o; + + o->time( 0, 4, 4 ); } { @@ -306,6 +314,12 @@ Timeline::nearest_line ( int ix ) return -1; } +nframes_t +Timeline::x_to_offset ( int x ) const +{ + return x_to_ts( max( 0, x - Track::width() ) ) + xoffset; +} + /** draw appropriate measure lines inside the given bounding box */ /* FIXME: this function *really* needs to be optimized. Currently it searched both the time and tempo lists once for every horiontal @@ -316,23 +330,83 @@ Timeline::draw_measure ( int X, int Y, int W, int H, Fl_Color color, bool BBT ) if ( ! draw_with_measure_lines ) return; - fl_push_clip( X, Y, W, H ); +// fl_push_clip( X, Y, W, H ); // fl_line_style( FL_DASH, 2 ); fl_line_style( FL_DASH, 0 ); const Fl_Color beat = fl_color_average( FL_BLACK, color, 0.65f ); - const Fl_Color bar = fl_color_average( FL_RED, color, 0.65f ); + const Fl_Color bar = fl_color_average( FL_RED, beat, 0.65f ); const nframes_t samples_per_minute = sample_rate() * 60; /* we need to back up a bit in order to catch all the numbers */ - if ( BBT ) + +/* if ( BBT ) */ +/* { */ +/* X -= 40; */ +/* W += 40; */ +/* } */ + + nframes_t when = x_to_offset( X ); + + list ::const_iterator tpi; + list ::const_iterator mpi; + + /* find the first points before our range */ + + for ( list ::const_reverse_iterator i = tempo_track->_widgets.rbegin(); + i != tempo_track->_widgets.rend(); i++ ) + if ( (*i)->offset() <= when ) + { + tpi = i.base(); + break; + } + + for ( list ::const_reverse_iterator i = time_track->_widgets.rbegin(); + i != time_track->_widgets.rend(); i++ ) + if ( (*i)->offset() <= when ) + { + mpi = i.base(); + break; + } + + --tpi; + + /* start on the next beat */ + const Tempo_Point *tp = (Tempo_Point*)(*tpi); + nframes_t beat_inc = samples_per_minute / tp->tempo(); + + nframes_t f = when - ( ( when - tp->offset() ) % beat_inc ); + + for ( ; tpi != tempo_track->_widgets.end(); ++tpi ) { - X -= 40; - W += 40; + list ::const_iterator ntpi = tpi; + ++ntpi; + + tp = (Tempo_Point*)(*tpi); + const Tempo_Point *ntp = (Tempo_Point*)(*ntpi); + + const nframes_t ntpo = ntp ? ntp->offset() : when + x_to_ts( W + 1 ); + + beat_inc = samples_per_minute / tp->tempo(); + + const int incx = ts_to_x( beat_inc ); + + if ( incx < 8 ) + continue; + + for ( ; f < ntpo; f += beat_inc ) + { + const int x = ts_to_x( f - xoffset ) + Track::width(); + + fl_color( beat ); + + fl_line( x, Y, x, Y + H ); + } } +#if 0 for ( int x = X; x < X + W; ++x ) { // measure = ts_to_x( (double)(sample_rate() * 60) / beats_per_minute( x_to_ts( x - Track::width() ) + xoffset ) ); @@ -404,9 +478,11 @@ Timeline::draw_measure ( int X, int Y, int W, int H, Fl_Color color, bool BBT ) } +#endif + fl_line_style( FL_SOLID, 0 ); - fl_pop_clip(); +// fl_pop_clip(); } void diff --git a/Timeline/Timeline.H b/Timeline/Timeline.H index 4ea4c13..ed2ec94 100644 --- a/Timeline/Timeline.H +++ b/Timeline/Timeline.H @@ -135,6 +135,7 @@ public: nframes_t sample_rate ( void ) const { return engine->sample_rate(); } int ts_to_x( nframes_t ts ) const { return ts >> _fpp; } nframes_t x_to_ts ( int x ) const { return x << _fpp; } + nframes_t x_to_offset ( int x ) const; float beats_per_minute ( nframes_t when ) const; int beats_per_bar ( nframes_t when ) const;