Attempt to draw measure lines with a more efficient incremental algorithm.

This commit is contained in:
Jonathan Moore Liles 2008-04-30 16:03:58 -05:00
parent 0af8d7e124
commit 34400df589
6 changed files with 126 additions and 25 deletions

View File

@ -712,7 +712,7 @@ Region::draw ( void )
} }
/* FIXME: only draw as many as are necessary! */ /* 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_color( FL_BLACK ); */
/* fl_line( rx, Y, rx, Y + H ); */ /* fl_line( rx, Y, rx, Y + H ); */

View File

@ -49,6 +49,7 @@ protected:
char *_name; char *_name;
friend class Timeline; // for draw_measure
std::list <Sequence_Widget *> _widgets; std::list <Sequence_Widget *> _widgets;
Sequence_Widget *event_widget ( void ); Sequence_Widget *event_widget ( void );

View File

@ -34,25 +34,37 @@ public:
// box( FL_DOWN_BOX ); // box( FL_DOWN_BOX );
} }
/** return a pointer to the closest tempo point *before* /when/ */
Tempo_Point *
at ( nframes_t when )
{
for ( std::list <Sequence_Widget *>::const_reverse_iterator i = _widgets.rbegin();
i != _widgets.rend(); i++ )
if ( (*i)->offset() < when )
return ((Tempo_Point*)(*i));
return NULL;
}
float float
beats_per_minute ( nframes_t when ) beats_per_minute ( nframes_t when )
{ {
// sort(); // sort();
for ( std::list <Sequence_Widget *>::const_reverse_iterator i = _widgets.rbegin(); Tempo_Point *p = at( when );
i != _widgets.rend(); i++ )
{
if ( (*i)->offset() < when )
return ((Tempo_Point*)(*i))->tempo();
}
return 120.0; if ( p )
return p->tempo();
else
return 120.0;
} }
void void
beats_per_minute ( nframes_t when, float bpm ) beats_per_minute ( nframes_t when, float bpm )
{ {
add( new Tempo_Point( when, bpm ) ); add( new Tempo_Point( when, bpm ) );
sort();
} }
}; };

View File

@ -104,18 +104,29 @@ public:
void time ( int bpb, int note ) { _time.beats_per_bar = bpb; _time.beat_type = note; } void time ( int bpb, int note ) { _time.beats_per_bar = bpb; _time.beat_type = note; }
time_sig time ( void ) const { return _time; } time_sig time ( void ) const { return _time; }
int /* Time_Point * */
handle ( int m ) /* at ( nframes_t when ) */
{ /* { */
int r = Sequence_Widget::handle( m ); /* for ( std::list <Sequence_Widget *>::const_reverse_iterator i = _widgets.rbegin(); */
/* i != _widgets.rend(); i++ ) */
/* if ( (*i)->offset() < when ) */
/* return ((Time_Point*)(*i)); */
if ( m == FL_RELEASE ) /* return NULL; */
{ /* } */
_track->sort();
timeline->redraw(); /* int */
} /* handle ( int m ) */
return r; /* { */
} /* int r = Sequence_Widget::handle( m ); */
/* if ( m == FL_RELEASE ) */
/* { */
/* _track->sort(); */
/* timeline->redraw(); */
/* } */
/* return r; */
/* } */
}; };

View File

@ -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 ); o->align( FL_ALIGN_LEFT );
tempo_track = o; 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 ); o->align( FL_ALIGN_LEFT );
time_track = o; time_track = o;
o->time( 0, 4, 4 );
} }
{ {
@ -306,6 +314,12 @@ Timeline::nearest_line ( int ix )
return -1; 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 */ /** draw appropriate measure lines inside the given bounding box */
/* FIXME: this function *really* needs to be optimized. Currently it /* FIXME: this function *really* needs to be optimized. Currently it
searched both the time and tempo lists once for every horiontal 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 ) if ( ! draw_with_measure_lines )
return; 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, 2 );
fl_line_style( FL_DASH, 0 ); fl_line_style( FL_DASH, 0 );
const Fl_Color beat = fl_color_average( FL_BLACK, color, 0.65f ); 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; const nframes_t samples_per_minute = sample_rate() * 60;
/* we need to back up a bit in order to catch all the numbers */ /* 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 <Sequence_Widget*>::const_iterator tpi;
list <Sequence_Widget*>::const_iterator mpi;
/* find the first points before our range */
for ( list <Sequence_Widget *>::const_reverse_iterator i = tempo_track->_widgets.rbegin();
i != tempo_track->_widgets.rend(); i++ )
if ( (*i)->offset() <= when )
{
tpi = i.base();
break;
}
for ( list <Sequence_Widget *>::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; list <Sequence_Widget*>::const_iterator ntpi = tpi;
W += 40; ++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 ) 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 ) ); // 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_line_style( FL_SOLID, 0 );
fl_pop_clip(); // fl_pop_clip();
} }
void void

View File

@ -135,6 +135,7 @@ public:
nframes_t sample_rate ( void ) const { return engine->sample_rate(); } nframes_t sample_rate ( void ) const { return engine->sample_rate(); }
int ts_to_x( nframes_t ts ) const { return ts >> _fpp; } 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_ts ( int x ) const { return x << _fpp; }
nframes_t x_to_offset ( int x ) const;
float beats_per_minute ( nframes_t when ) const; float beats_per_minute ( nframes_t when ) const;
int beats_per_bar ( nframes_t when ) const; int beats_per_bar ( nframes_t when ) const;