Browse Source

Timeline: Fix waveform drawing during record and cumulative error in looped region drawing. Also, avoid redrawing already displayed parts of waveforms while recording.

tags/non-daw-v1.2.0
Jonathan Moore Liles 13 years ago
parent
commit
e968d8190f
12 changed files with 122 additions and 121 deletions
  1. +55
    -69
      timeline/src/Audio_Region.C
  2. +4
    -12
      timeline/src/Engine/Audio_File.C
  3. +2
    -2
      timeline/src/Engine/Audio_File_Dummy.H
  4. +2
    -2
      timeline/src/Engine/Audio_File_SF.C
  5. +7
    -6
      timeline/src/Engine/Audio_Region.C
  6. +14
    -24
      timeline/src/Engine/Peaks.C
  7. +6
    -0
      timeline/src/Engine/Record_DS.C
  8. +1
    -0
      timeline/src/Engine/Record_DS.H
  9. +12
    -3
      timeline/src/Engine/Track.C
  10. +8
    -1
      timeline/src/Sequence_Widget.H
  11. +9
    -0
      timeline/src/Track.H
  12. +2
    -2
      timeline/src/Waveform.C

+ 55
- 69
timeline/src/Audio_Region.C View File

@@ -492,6 +492,7 @@ Audio_Region::draw ( void )
/* no coverage */ /* no coverage */
return; return;


if ( start() > timeline->xoffset + timeline->x_to_ts( sequence()->w() ) || if ( start() > timeline->xoffset + timeline->x_to_ts( sequence()->w() ) ||
start() + length() < timeline->xoffset ) start() + length() < timeline->xoffset )
/* not in viewport */ /* not in viewport */
@@ -499,31 +500,31 @@ Audio_Region::draw ( void )


fl_push_clip( X, Y, W, H ); fl_push_clip( X, Y, W, H );


/* account for waveform outlines... */
X -= 2;
W += 4;
/* overdraw a little to avoid artifacts when scrolling */
W += 2;


Fl_Color c = selected() ? fl_invert_color( _color ) : _color; Fl_Color c = selected() ? fl_invert_color( _color ) : _color;


/* start with region length... */
// int rw = timeline->ts_to_x( min( length(), timeline->x_to_ts( sequence()->w() ) ) );
int rw = W;

/* calculate waveform offset due to scrolling */
nframes_t offset = 0;
if ( start() < timeline->xoffset )
if ( sequence()->damage() & FL_DAMAGE_USER1 && this == sequence()->track()->capture_region() )
{ {
offset = timeline->xoffset - start();
/* just draw the section with the updated peaks... */


// rw -= timeline->ts_to_x( offset );
nframes_t absolute_frame = _r->start + sequence()->track()->capture()->last_frame_drawn;
int nx = sequence()->x() + timeline->ts_to_x( absolute_frame - scroll_ts() );
W -= nx - X;
X = nx;
} }


/* DMESSAGE( "rw = %d", rw ); */

const int rx = x();
/* calculate waveform offset due to scrolling */
/* offset is the number of frames into the waveform the value of X translates to */
nframes_t x_frame = timeline->xoffset + timeline->x_to_ts( X - _sequence->x() );
nframes_t offset = x_frame - start();


/* fl_color( FL_RED ); */
/* fl_line( rx + rw, y(), rx + rw, y() + h() ); */
nframes_t fo = 0;
nframes_t ostart = 0, oend = 0;
const int total_peaks_needed = W;
nframes_t total_frames_needed = timeline->x_to_ts( total_peaks_needed );


{ {
Fl_Color c = fl_color_average( FL_DARK1, Fl_Color c = fl_color_average( FL_DARK1,
@@ -536,38 +537,27 @@ Audio_Region::draw ( void )
draw_fade( _fade_out, Fade::Out, false, X, W ); draw_fade( _fade_out, Fade::Out, false, X, W );
} }


int xo = 0;

nframes_t ostart = 0, oend = 0;

const int total_peaks_needed = rw;
int channels = 0;
int peaks = 0;
Peak *pbuf = NULL;


/* compensate for scrolling */
if ( X - rx > 0 )
offset += timeline->x_to_ts( X - rx );

// DMESSAGE( "Drawing audio region.");

int channels;
int peaks;
Peak *pbuf = NULL;
do { do {

nframes_t start = _r->offset; nframes_t start = _r->offset;


int loop_peaks_needed = _loop ? timeline->ts_to_x( _loop ) : timeline->ts_to_x( _clip->length() );
nframes_t loop_frames_needed = _loop ? _loop : total_frames_needed;
int loop_peaks_needed = timeline->ts_to_x( loop_frames_needed );
Fl_Color c = Fl::get_color( _color );


if ( this == ((Audio_Sequence*)sequence())->capture_region() ) if ( this == ((Audio_Sequence*)sequence())->capture_region() )
{ {
loop_peaks_needed = timeline->ts_to_x( _range.length );
// loop_peaks_needed = timeline->ts_to_x( _range.length );
c = FL_BLACK; c = FL_BLACK;
} }
c = fl_color_add_alpha( c, 220 );


if ( ! loop_peaks_needed )
break;

if ( ! xo ) /* first loop... */
if ( ! fo ) /* first loop... */
{ {
if ( _loop ) if ( _loop )
start += offset % _loop; start += offset % _loop;
@@ -577,38 +567,38 @@ Audio_Region::draw ( void )
/* DMESSAGE( "offset = %lu", (unsigned long) offset ); */ /* DMESSAGE( "offset = %lu", (unsigned long) offset ); */
/* DMESSAGE( "loop peaks needed = %d", loop_peaks_needed ); */ /* DMESSAGE( "loop peaks needed = %d", loop_peaks_needed ); */


loop_peaks_needed -= timeline->ts_to_x( offset % timeline->x_to_ts( loop_peaks_needed ) );

loop_peaks_needed = min( loop_peaks_needed, total_peaks_needed );

if ( _loop )
{
loop_frames_needed -= offset % loop_frames_needed;
loop_peaks_needed = timeline->ts_to_x( loop_frames_needed );
}
/* DMESSAGE( "loop peaks needed = %d", loop_peaks_needed ); */ /* DMESSAGE( "loop peaks needed = %d", loop_peaks_needed ); */


assert( loop_peaks_needed >= 0 ); assert( loop_peaks_needed >= 0 );

} }


if ( xo + loop_peaks_needed > total_peaks_needed )
if ( fo + loop_frames_needed > total_frames_needed )
{ {
loop_peaks_needed -= ( xo + loop_peaks_needed ) - total_peaks_needed;
loop_frames_needed -= ( fo + loop_frames_needed ) - total_frames_needed;
loop_peaks_needed = timeline->ts_to_x( loop_frames_needed );
} }


if ( 0 == loop_peaks_needed )
if ( !loop_peaks_needed )
break; break;


const nframes_t end = start + timeline->x_to_ts( loop_peaks_needed );
const nframes_t end = start + loop_frames_needed;


if ( start != ostart || end != oend ) if ( start != ostart || end != oend )
{ {
if ( _clip->peaks()->peakfile_ready() ) if ( _clip->peaks()->peakfile_ready() )
{ {
if ( _clip->read_peaks( timeline->fpp(), if ( _clip->read_peaks( timeline->fpp(),
start,
end,
start,
end,
&peaks, &pbuf, &channels ) ) &peaks, &pbuf, &channels ) )
{ {
Waveform::scale( pbuf, peaks * channels, _scale ); Waveform::scale( pbuf, peaks * channels, _scale );
ostart = start; ostart = start;
oend = end; oend = end;
} }
@@ -626,14 +616,11 @@ Audio_Region::draw ( void )
{ {
// DMESSAGE( "using cached peaks" ); // DMESSAGE( "using cached peaks" );
} }

Fl_Color c = Fl::get_color( _color );

c = fl_color_add_alpha( c, 220 );

if ( peaks && pbuf ) if ( peaks && pbuf )
{ {
int ch = (h() - Fl::box_dh( box() )) / channels; int ch = (h() - Fl::box_dh( box() )) / channels;
int xo = timeline->ts_to_x( fo );


for ( int i = 0; i < channels; ++i ) for ( int i = 0; i < channels; ++i )
{ {
@@ -645,26 +632,31 @@ Audio_Region::draw ( void )
c ); c );
} }
} }
else
WARNING( "Pbuf == %p, peaks = %lu", pbuf, (unsigned long)peaks );


if ( sequence()->damage() & FL_DAMAGE_USER1 && this == sequence()->track()->capture_region() )
sequence()->track()->capture()->last_frame_drawn = start + peaks;
if ( peaks < loop_peaks_needed ) if ( peaks < loop_peaks_needed )
{ {
// DMESSAGE( "Peak read came up %lu peaks short", (unsigned long) loop_peaks_needed - peaks );
DMESSAGE( "Peak read came up %lu peaks short", (unsigned long)loop_peaks_needed - peaks );
} }


xo += loop_peaks_needed;

fo += loop_frames_needed;
} }
while ( _loop && xo < W );
while ( _loop && fo < total_frames_needed );


if ( _loop && offset < _loop ) if ( _loop && offset < _loop )
{ {
const int lx = timeline->ts_to_x( _loop - offset );
const int lx = get_x( start() + _loop );


if ( lx < X + W ) if ( lx < X + W )
{ {
fl_color( FL_RED ); fl_color( FL_RED );
fl_line_style( FL_DASH, 0 ); fl_line_style( FL_DASH, 0 );
fl_line( X + lx + 2, y(), X + lx + 2, y() + h() );
fl_line( lx, y(), lx, y() + h() );
fl_line_style( FL_SOLID, 0 ); fl_line_style( FL_SOLID, 0 );
} }
} }
@@ -689,12 +681,6 @@ Audio_Region::draw ( void )
fl_line_style( FL_SOLID, 0 ); fl_line_style( FL_SOLID, 0 );
} }


/* fl_color( FL_BLACK ); */
/* fl_line( rx, Y, rx, Y + H ); */
/* fl_line( rx + rw - 1, Y, rx + rw - 1, Y + H ); */


/* if ( current() ) */ /* if ( current() ) */
/* { */ /* { */
/* /\* draw length bubble *\/ */ /* /\* draw length bubble *\/ */


+ 4
- 12
timeline/src/Engine/Audio_File.C View File

@@ -147,22 +147,14 @@ Audio_File::release ( void )
bool bool
Audio_File::read_peaks( float fpp, nframes_t start, nframes_t end, int *peaks, Peak **pbuf, int *channels ) Audio_File::read_peaks( float fpp, nframes_t start, nframes_t end, int *peaks, Peak **pbuf, int *channels )
{ {
// Peaks pk;

*peaks = 0;
*channels = 0;
*pbuf = NULL;
if ( dummy() ) if ( dummy() )
{
*peaks = (end - start) / fpp;
*channels = 0;
*pbuf = NULL;

return false; return false;
}
else else
{ {
*peaks = 0;
*channels = 0;
*pbuf = NULL;

*peaks = _peaks.fill_buffer( fpp, start, end ); *peaks = _peaks.fill_buffer( fpp, start, end );


*channels = this->channels(); *channels = this->channels();


+ 2
- 2
timeline/src/Engine/Audio_File_Dummy.H View File

@@ -40,7 +40,7 @@ public:
bool open ( void ) { return true; } bool open ( void ) { return true; }
void close ( void ) { } void close ( void ) { }
void seek ( nframes_t ) { } void seek ( nframes_t ) { }
nframes_t read ( sample_t *, int, nframes_t len ) { return len; }
nframes_t read ( sample_t *, int, nframes_t start, nframes_t end ) { return end - start; }
nframes_t read ( sample_t *, int, nframes_t len ) { return 0; }
nframes_t read ( sample_t *, int, nframes_t start, nframes_t end ) { return 0; }
nframes_t write ( sample_t *, nframes_t nframes ) { return nframes; } nframes_t write ( sample_t *, nframes_t nframes ) { return nframes; }
}; };

+ 2
- 2
timeline/src/Engine/Audio_File_SF.C View File

@@ -242,13 +242,13 @@ Audio_File_SF::write ( sample_t *buf, nframes_t nframes )
{ {
_peaks.write( buf, nframes ); _peaks.write( buf, nframes );


// lock();
lock();


nframes_t l = sf_writef_float( _in, buf, nframes ); nframes_t l = sf_writef_float( _in, buf, nframes );


_length += l; _length += l;


// unlock();
unlock();


return l; return l;
} }

+ 7
- 6
timeline/src/Engine/Audio_Region.C View File

@@ -83,7 +83,7 @@ Audio_Region::read ( sample_t *buf, nframes_t pos, nframes_t nframes, int channe


nframes_t sofs, /* offset into source */ nframes_t sofs, /* offset into source */
ofs, /* offset into buffer */ ofs, /* offset into buffer */
cnt;
cnt; /* number of frames to read */


cnt = nframes; cnt = nframes;


@@ -105,8 +105,8 @@ Audio_Region::read ( sample_t *buf, nframes_t pos, nframes_t nframes, int channe
return 0; return 0;


// const nframes_t start = ofs + r.start + sofs; // const nframes_t start = ofs + r.start + sofs;
const nframes_t start = r.offset + sofs;
const nframes_t len = min( cnt, nframes - ofs );
const nframes_t start = r.offset + sofs;
const nframes_t len = cnt;


if ( len == 0 ) if ( len == 0 )
return 0; return 0;
@@ -139,6 +139,9 @@ Audio_Region::read ( sample_t *buf, nframes_t pos, nframes_t nframes, int channe
else else
cnt = _clip->read( buf + ofs, channel, start, len ); cnt = _clip->read( buf + ofs, channel, start, len );


if ( ! cnt )
return 0;

/* apply gain */ /* apply gain */


buffer_apply_gain( buf + ofs, cnt, _scale ); buffer_apply_gain( buf + ofs, cnt, _scale );
@@ -194,9 +197,7 @@ Audio_Region::write ( nframes_t nframes )
if ( W ) if ( W )
{ {
Fl::lock(); Fl::lock();
// sequence()->damage( FL_DAMAGE_ALL, ( x() + w() - W ) - 20, y(), W, h() );
sequence()->damage( FL_DAMAGE_ALL, x(), y(), w(), h() );
// Fl::awake();
sequence()->damage(FL_DAMAGE_USER1, x(), y(), w(), h());
Fl::unlock(); Fl::unlock();
} }
} }


+ 14
- 24
timeline/src/Engine/Peaks.C View File

@@ -104,7 +104,7 @@ class Peakfile
FILE *_fp; FILE *_fp;
nframes_t _chunksize; nframes_t _chunksize;
int _channels; /* number of channels this peakfile represents */ int _channels; /* number of channels this peakfile represents */
nframes_t _length; /* length, in frames, of the clip this peakfile represents */
// nframes_t _length; /* length, in frames, of the clip this peakfile represents */
off_t _offset; off_t _offset;
// int _blocks; // int _blocks;


@@ -134,7 +134,7 @@ public:
_offset = 0; _offset = 0;
_chunksize = 0; _chunksize = 0;
_channels = 0; _channels = 0;
_length = 0;
// _length = 0;
} }


~Peakfile ( ) ~Peakfile ( )
@@ -163,7 +163,7 @@ public:
if ( feof( _fp ) ) if ( feof( _fp ) )
break; break;
DMESSAGE( "Peakfile: chunksize=%lu, skip=%lu\n", (uint64_t)bh.chunksize, (uint64_t) bh.skip );
DMESSAGE( "Peakfile: chunksize=%lu, skip=%lu", (uint64_t)bh.chunksize, (uint64_t) bh.skip );
ASSERT( bh.chunksize, "Chucksize of zero. Invalid peak file structure!" ); ASSERT( bh.chunksize, "Chucksize of zero. Invalid peak file structure!" );


@@ -184,11 +184,6 @@ public:
if ( ! blocks.size() ) if ( ! blocks.size() )
FATAL( "Peak file contains no blocks!" ); FATAL( "Peak file contains no blocks!" );


if ( chunksize == _chunksize )
{
return;
/* already on the right block... */
}


// DMESSAGE( "peakfile has %d blocks.", blocks.size() ); // DMESSAGE( "peakfile has %d blocks.", blocks.size() );


@@ -208,7 +203,7 @@ public:
break; break;
} }


// DMESSAGE( "using peakfile block for chunksize %lu", _chunksize );
// DMESSAGE( "using peakfile block for chunksize %lu", _chunksize );
// _blocks = blocks.size(); // _blocks = blocks.size();
_offset = ftello( _fp ); _offset = ftello( _fp );
} }
@@ -310,9 +305,6 @@ public:


/* locate to start position */ /* locate to start position */
/* if ( s > _clip->length() ) */
/* return 0; */

if ( fseeko( _fp, _offset + ( frame_to_peak( s ) * sizeof( Peak ) ), SEEK_SET ) ) if ( fseeko( _fp, _offset + ( frame_to_peak( s ) * sizeof( Peak ) ), SEEK_SET ) )
{ {
DMESSAGE( "failed to seek... peaks not ready?" ); DMESSAGE( "failed to seek... peaks not ready?" );
@@ -359,9 +351,7 @@ public:
} }


if ( feof( _fp) || len < ratio ) if ( feof( _fp) || len < ratio )
{
break; break;
}
} }


delete[] pbuf; delete[] pbuf;
@@ -408,15 +398,14 @@ Peaks::fill_buffer ( float fpp, nframes_t s, nframes_t e ) const
bool bool
Peaks::ready ( nframes_t s, nframes_t npeaks, nframes_t chunksize ) const Peaks::ready ( nframes_t s, nframes_t npeaks, nframes_t chunksize ) const
{ {
/* if ( _pending ) */
/* return false; */
if ( ! _peakfile->open( _clip->filename(), _clip->channels(), chunksize ) )
return false;


Peakfile _peakfile;
int r = _peakfile->ready( s, npeaks );


if ( ! _peakfile.open( _clip->filename(), _clip->channels(), chunksize ) )
return false;
_peakfile->close();


return _peakfile.ready( s, npeaks );
return r;
} }


/** If this returns false, then the peakfile needs to be built */ /** If this returns false, then the peakfile needs to be built */
@@ -694,6 +683,7 @@ Peaks::Streamer::Streamer ( const char *filename, int channels, nframes_t chunks
fwrite( &bh, sizeof( bh ), 1, _fp ); fwrite( &bh, sizeof( bh ), 1, _fp );


fflush( _fp ); fflush( _fp );
fsync( fileno( _fp ) );
} }


Peaks::Streamer::~Streamer ( ) Peaks::Streamer::~Streamer ( )
@@ -704,7 +694,7 @@ Peaks::Streamer::~Streamer ( )


touch( fileno( _fp ) ); touch( fileno( _fp ) );


// fsync( fileno( _fp ) );
fsync( fileno( _fp ) );


fclose( _fp ); fclose( _fp );


@@ -723,9 +713,6 @@ Peaks::Streamer::write ( const sample_t *buf, nframes_t nframes )
{ {
fwrite( _peak, sizeof( Peak ) * _channels, 1, _fp ); fwrite( _peak, sizeof( Peak ) * _channels, 1, _fp );


/* FIXME: shouldn't we just use write() instead? */
// fflush( _fp );

memset( _peak, 0, sizeof( Peak ) * _channels ); memset( _peak, 0, sizeof( Peak ) * _channels );


_index = 0; _index = 0;
@@ -751,6 +738,9 @@ Peaks::Streamer::write ( const sample_t *buf, nframes_t nframes )
_index += processed; _index += processed;
nframes -= processed; nframes -= processed;
} }

/* FIXME: shouldn't we just use write() instead? */
fflush( _fp );
} }




+ 6
- 0
timeline/src/Engine/Record_DS.C View File

@@ -42,6 +42,12 @@ Record_DS::capture_region ( void ) const
return NULL; return NULL;
} }


Track::Capture *
Record_DS::capture ( void )
{
return _capture;
}

/** write /nframes/ from buf to the capture file of the attached track */ /** write /nframes/ from buf to the capture file of the attached track */
void void
Record_DS::write_block ( sample_t *buf, nframes_t nframes ) Record_DS::write_block ( sample_t *buf, nframes_t nframes )


+ 1
- 0
timeline/src/Engine/Record_DS.H View File

@@ -63,6 +63,7 @@ public:
/* bool seek_pending ( void ); */ /* bool seek_pending ( void ); */
/* void seek ( nframes_t frame ); */ /* void seek ( nframes_t frame ); */
const Audio_Region * capture_region ( void ) const; const Audio_Region * capture_region ( void ) const;
Track::Capture * capture ( void );


void start ( nframes_t frame ); void start ( nframes_t frame );
void stop ( nframes_t frame ); void stop ( nframes_t frame );


+ 12
- 3
timeline/src/Engine/Track.C View File

@@ -40,6 +40,15 @@ Track::capture_region ( void ) const
return NULL; return NULL;
} }


Track::Capture *
Track::capture ( void )
{
if ( record_ds )
return record_ds->capture();
else
return NULL;
}

void void
Track::update_port_names ( void ) Track::update_port_names ( void )
{ {
@@ -261,9 +270,9 @@ Track::record ( Capture *c, nframes_t frame )
FATAL( "Could not create file for new capture!" ); FATAL( "Could not create file for new capture!" );


/* open it again for reading in the GUI thread */ /* open it again for reading in the GUI thread */
Audio_File *af = Audio_File::from_file( c->audio_file->name() );
// Audio_File *af = Audio_File::from_file( c->audio_file->name() );


c->region = new Audio_Region( af, sequence(), frame );
c->region = new Audio_Region( c->audio_file, sequence(), frame );


c->region->prepare(); c->region->prepare();
} }
@@ -315,5 +324,5 @@ Track::finalize ( Capture *c, nframes_t frame )


c->region->offset( capture_offset ); c->region->offset( capture_offset );


delete c->audio_file;
// delete c->audio_file;
} }

+ 8
- 1
timeline/src/Sequence_Widget.H View File

@@ -193,9 +193,16 @@ public:
virtual int h ( void ) const { return _sequence->h(); } virtual int h ( void ) const { return _sequence->h(); }


/* used by regions */ /* used by regions */
int get_x( nframes_t frame ) const
{
return frame < timeline->xoffset ? _sequence->x() : min( _sequence->x() + _sequence->w(), _sequence->x() + timeline->ts_to_x( frame - timeline->xoffset ) );

}

virtual int x ( void ) const virtual int x ( void ) const
{ {
return _r->start < timeline->xoffset ? _sequence->x() : min( _sequence->x() + _sequence->w(), _sequence->x() + timeline->ts_to_x( _r->start - timeline->xoffset ) );
return get_x( _r->start );
} }


/* use this as x() when you need to draw lines between widgets */ /* use this as x() when you need to draw lines between widgets */


+ 9
- 0
timeline/src/Track.H View File

@@ -70,8 +70,16 @@ public:


struct Capture struct Capture
{ {
nframes_t last_frame_drawn;
Audio_File *audio_file; Audio_File *audio_file;
Audio_Region *region; Audio_Region *region;

Capture ( )
{
last_frame_drawn = 0;
region = 0;
audio_file = 0;
}
}; };


Fl_Color color ( void ) const { return child(0)->color(); } Fl_Color color ( void ) const { return child(0)->color(); }
@@ -213,6 +221,7 @@ public:


/* Engine */ /* Engine */
const Audio_Region *capture_region ( void ) const; const Audio_Region *capture_region ( void ) const;
Capture *capture ( void );


void resize_buffers ( nframes_t nframes ); void resize_buffers ( nframes_t nframes );
nframes_t process_input ( nframes_t nframes ); nframes_t process_input ( nframes_t nframes );


+ 2
- 2
timeline/src/Waveform.C View File

@@ -99,7 +99,7 @@ Waveform::draw ( int X, int Y, int W, int H,
fl_color( color ); fl_color( color );
fl_begin_complex_polygon(); fl_begin_complex_polygon();
j = start; j = start;


for ( int x = X; x <= X + W; x++, j += skip ) for ( int x = X; x <= X + W; x++, j += skip )
@@ -109,7 +109,7 @@ Waveform::draw ( int X, int Y, int W, int H,


for ( int x = X + W; x >= X; x--, j -= skip ) for ( int x = X + W; x >= X; x--, j -= skip )
fl_vertex( x, ty - ( halfheight * pbuf[ j ].max ) ); fl_vertex( x, ty - ( halfheight * pbuf[ j ].max ) );
fl_end_complex_polygon(); fl_end_complex_polygon();
} }
} }


Loading…
Cancel
Save