Browse Source

Timeline: Don't fork to generate peak mipmaps, do it in the capture thread. Also, clean up related concurrency issues.

tags/non-daw-v1.2.0
Jonathan Moore Liles 13 years ago
parent
commit
9667f98995
9 changed files with 205 additions and 113 deletions
  1. +11
    -42
      timeline/src/Audio_Region.C
  2. +0
    -3
      timeline/src/Audio_Region.H
  3. +10
    -7
      timeline/src/Engine/Audio_File.C
  4. +4
    -2
      timeline/src/Engine/Audio_File.H
  5. +11
    -3
      timeline/src/Engine/Audio_File_SF.C
  6. +6
    -19
      timeline/src/Engine/Audio_Region.C
  7. +143
    -32
      timeline/src/Engine/Peaks.C
  8. +10
    -2
      timeline/src/Engine/Peaks.H
  9. +10
    -3
      timeline/src/Engine/Track.C

+ 11
- 42
timeline/src/Audio_Region.C View File

@@ -405,44 +405,6 @@ Audio_Region::draw_fade ( const Fade &fade, Fade::fade_dir_e dir, bool line, int
fl_pop_matrix(); fl_pop_matrix();
} }


struct Peaks_Redraw_Request {

Audio_Region *region;

nframes_t start;
nframes_t end;

Peaks_Redraw_Request ( Audio_Region *region, nframes_t start, nframes_t end ) : region( region ), start( start), end( end )
{
}
};

/* static wrapper */
void
Audio_Region::peaks_pending_cb ( void *v )
{
Peaks_Redraw_Request *r = (Peaks_Redraw_Request*)v;

r->region->peaks_pending_cb( r );
}

void
Audio_Region::peaks_pending_cb ( Peaks_Redraw_Request *r )
{
int npeaks = timeline->ts_to_x( r->end - r->start );

if ( _clip->peaks()->ready( r->start, npeaks, timeline->fpp() ) )
{
printf( "damaging from timeout\n" );
/* FIXME: only need to damage the affected area! */
timeline->damage( FL_DAMAGE_ALL, x(), y(), w(), h() );

delete r;
}
else
Fl::repeat_timeout( 0.5f, &Audio_Region::peaks_pending_cb, (void*)r );
}

void void
Audio_Region::draw_box( void ) Audio_Region::draw_box( void )
{ {
@@ -503,6 +465,8 @@ Audio_Region::draw ( void )
X -= 2; X -= 2;
W += 4; W += 4;


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

/* start with region length... */ /* start with region length... */
// int rw = timeline->ts_to_x( min( length(), timeline->x_to_ts( sequence()->w() ) ) ); // int rw = timeline->ts_to_x( min( length(), timeline->x_to_ts( sequence()->w() ) ) );
int rw = W; int rw = W;
@@ -537,6 +501,7 @@ Audio_Region::draw ( void )
if ( X - rx > 0 ) if ( X - rx > 0 )
offset += timeline->x_to_ts( X - rx ); offset += timeline->x_to_ts( X - rx );


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


do { do {


@@ -548,6 +513,12 @@ Audio_Region::draw ( void )


int loop_peaks_needed = _loop ? timeline->ts_to_x( _loop ) : timeline->ts_to_x( _clip->length() ); int loop_peaks_needed = _loop ? timeline->ts_to_x( _loop ) : timeline->ts_to_x( _clip->length() );


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

if ( ! loop_peaks_needed ) if ( ! loop_peaks_needed )
break; break;


@@ -627,15 +598,13 @@ Audio_Region::draw ( void )
loop_peaks_needed, loop_peaks_needed,
ch, ch,
pbuf + i, peaks, channels, pbuf + i, peaks, channels,
selected() ? fl_invert_color( _color ) : _color );
c );
} }
} }


if ( peaks < loop_peaks_needed ) if ( peaks < loop_peaks_needed )
{ {
/* couldn't read peaks--perhaps they're being generated. Try again later. */
Fl::add_timeout( 0.5f, &Audio_Region::peaks_pending_cb,
new Peaks_Redraw_Request( this, start + timeline->x_to_ts( peaks ), end ) );
// DMESSAGE( "Peak read came up %lu peaks short", (unsigned long) loop_peaks_needed - peaks );
} }


xo += loop_peaks_needed; xo += loop_peaks_needed;


+ 0
- 3
timeline/src/Audio_Region.H View File

@@ -23,7 +23,6 @@
#include "Sequence_Region.H" #include "Sequence_Region.H"


class Audio_File; class Audio_File;
class Peaks_Redraw_Request;


class Fl_Menu_; class Fl_Menu_;
class Fl_Menu_Button; class Fl_Menu_Button;
@@ -105,8 +104,6 @@ private:
friend class Track; /* for _clip */ friend class Track; /* for _clip */


Fl_Menu_Button & menu ( void ); Fl_Menu_Button & menu ( void );
static void peaks_pending_cb ( void *v );
void peaks_pending_cb ( Peaks_Redraw_Request *r );


static void menu_cb ( Fl_Widget *w, void *v ); static void menu_cb ( Fl_Widget *w, void *v );
void menu_cb ( const Fl_Menu_ *m ); void menu_cb ( const Fl_Menu_ *m );


+ 10
- 7
timeline/src/Engine/Audio_File.C View File

@@ -37,6 +37,9 @@ Audio_File::~Audio_File ( )


if ( _filename ) if ( _filename )
free( _filename ); free( _filename );

if ( _path )
free( _path );
} }


const Audio_File::format_desc * const Audio_File::format_desc *
@@ -66,23 +69,23 @@ is_absolute ( const char *name )
return *name == '/'; return *name == '/';
} }


/** return a static pointer to /name/ corrected for relative path. */
const char *Audio_File::realname ( const char *name )
/** return pointer to /name/ corrected for relative path. */
char *Audio_File::path ( const char *name )
{ {
static char rname[512];
char *path = 0;


if ( is_absolute( name ) ) if ( is_absolute( name ) )
strncpy( rname, name, sizeof( rname ) );
path = strdup( name );
else else
snprintf( rname, sizeof( rname ), "sources/%s", name );
asprintf( &path, "sources/%s", name );


return rname;
return path;
} }


const char * const char *
Audio_File::filename ( void ) const Audio_File::filename ( void ) const
{ {
return realname( _filename );
return _path;
} }


/** attempt to open any supported filetype */ /** attempt to open any supported filetype */


+ 4
- 2
timeline/src/Engine/Audio_File.H View File

@@ -52,6 +52,8 @@ protected:
}; };


char *_filename; char *_filename;
char *_path;

volatile nframes_t _length; /* length of file in samples */ volatile nframes_t _length; /* length of file in samples */
nframes_t _samplerate; /* sample rate */ nframes_t _samplerate; /* sample rate */
int _channels; int _channels;
@@ -60,13 +62,13 @@ protected:


static const format_desc * find_format ( const format_desc *fd, const char *name ); static const format_desc * find_format ( const format_desc *fd, const char *name );


static const char *realname ( const char *name );
static char *path ( const char *name );


public: public:


Audio_File ( ) : _peaks( this ) Audio_File ( ) : _peaks( this )
{ {
_filename = NULL;
_path =_filename = NULL;
_samplerate = 0; _samplerate = 0;
_length = _channels = 0; _length = _channels = 0;
_refs = 0; _refs = 0;


+ 11
- 3
timeline/src/Engine/Audio_File_SF.C View File

@@ -33,6 +33,7 @@


#include "const.h" #include "const.h"
#include "debug.h" #include "debug.h"
#include <stdio.h>




@@ -62,7 +63,9 @@ Audio_File_SF::from_file ( const char *filename )


memset( &si, 0, sizeof( si ) ); memset( &si, 0, sizeof( si ) );


if ( ! ( in = sf_open( realname( filename ), SFM_READ, &si ) ) )
char *fp = path( filename );

if ( ! ( in = sf_open( fp, SFM_READ, &si ) ) )
return NULL; return NULL;


/* if ( si.samplerate != timeline->sample_rate() ) */ /* if ( si.samplerate != timeline->sample_rate() ) */
@@ -76,6 +79,7 @@ Audio_File_SF::from_file ( const char *filename )
// c->_peak_writer = NULL; // c->_peak_writer = NULL;
c->_current_read = 0; c->_current_read = 0;
c->_filename = strdup( filename ); c->_filename = strdup( filename );
c->_path = fp;
c->_length = si.frames; c->_length = si.frames;
c->_samplerate = si.samplerate; c->_samplerate = si.samplerate;
c->_channels = si.channels; c->_channels = si.channels;
@@ -99,6 +103,7 @@ Audio_File_SF::create ( const char *filename, nframes_t samplerate, int channels


memset( &si, 0, sizeof( si ) ); memset( &si, 0, sizeof( si ) );



const Audio_File::format_desc *fd = Audio_File::find_format( Audio_File_SF::supported_formats, format ); const Audio_File::format_desc *fd = Audio_File::find_format( Audio_File_SF::supported_formats, format );


if ( ! fd ) if ( ! fd )
@@ -111,7 +116,9 @@ Audio_File_SF::create ( const char *filename, nframes_t samplerate, int channels
char *name; char *name;
asprintf( &name, "%s.%s", filename, fd->extension ); asprintf( &name, "%s.%s", filename, fd->extension );


if ( ! ( out = sf_open( realname( name ), SFM_WRITE, &si ) ) )
char *filepath = path( name );

if ( ! ( out = sf_open( filepath, SFM_WRITE, &si ) ) )
{ {
printf( "couldn't create soundfile.\n" ); printf( "couldn't create soundfile.\n" );
free( name ); free( name );
@@ -120,6 +127,7 @@ Audio_File_SF::create ( const char *filename, nframes_t samplerate, int channels


Audio_File_SF *c = new Audio_File_SF; Audio_File_SF *c = new Audio_File_SF;


c->_path = filepath;
c->_filename = name; c->_filename = name;
c->_length = 0; c->_length = 0;
c->_samplerate = samplerate; c->_samplerate = samplerate;
@@ -141,7 +149,7 @@ Audio_File_SF::open ( void )


memset( &si, 0, sizeof( si ) ); memset( &si, 0, sizeof( si ) );


if ( ! ( _in = sf_open( realname( _filename ), SFM_READ, &si ) ) )
if ( ! ( _in = sf_open( _path, SFM_READ, &si ) ) )
return false; return false;


_current_read = 0; _current_read = 0;


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

@@ -208,34 +208,22 @@ Audio_Region::write ( nframes_t nframes )
{ {
THREAD_ASSERT( Capture ); THREAD_ASSERT( Capture );


_range.length += nframes;

/* FIXME: too much? */
// _track->damage( FL_DAMAGE_EXPOSE, x() + w(), y(), 10/* FIXME: guess */, h() );

if ( 0 == ( timeline->ts_to_x( _range.length ) % 20 ) ) if ( 0 == ( timeline->ts_to_x( _range.length ) % 20 ) )
{ {
nframes_t oldl = _clip->length();

/* get the new size. Remember, this is a read-only handle on the source--not the same
one being written to */
_clip->close();
_clip->open();

int W = timeline->ts_to_x( _clip->length() - oldl );

/* why - 1? */
int W = 20;


if ( W ) if ( W )
{ {
++W;
Fl::lock(); Fl::lock();
sequence()->damage( FL_DAMAGE_ALL, x() + w() - W, y(), W, h() );
// Fl::awake();
// sequence()->damage( FL_DAMAGE_ALL, ( x() + w() - W ) - 20, y(), W, h() );
sequence()->damage( FL_DAMAGE_ALL, x(), y(), w(), h() );
// Fl::awake();
Fl::unlock(); Fl::unlock();
} }
} }


_range.length += nframes;

return nframes; return nframes;
} }


@@ -255,7 +243,6 @@ Audio_Region::finalize ( nframes_t frame )
_clip->close(); _clip->close();
_clip->open(); _clip->open();


/* FIXME: should we attempt to truncate the file? */
Fl::lock(); Fl::lock();
redraw(); redraw();
Fl::awake(); Fl::awake();


+ 143
- 32
timeline/src/Engine/Peaks.C View File

@@ -24,6 +24,8 @@


/* Code for peakfile reading, resampling, generation and streaming */ /* Code for peakfile reading, resampling, generation and streaming */


#include <FL/Fl.H>

#include <sys/mman.h> #include <sys/mman.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
@@ -68,20 +70,21 @@ Peaks::peakbuffer Peaks::_peakbuf;


static static
const char *
char *
peakname ( const char *filename ) peakname ( const char *filename )
{ {
static char file[512];
char *file;


snprintf( file, 512, "%s.peak", filename );
asprintf( &file, "%s.peak", filename );


return (const char*)&file;
return file;
} }




Peaks::Peaks ( Audio_File *c ) Peaks::Peaks ( Audio_File *c )
{ {
_pending = false;
_clip = c; _clip = c;
_peak_writer = NULL; _peak_writer = NULL;
} }
@@ -176,7 +179,7 @@ public:


// printf( "chunksize=%lu, skip=%lu\n", (unsigned long)bh.chunksize, (unsigned long) bh.skip ); // printf( "chunksize=%lu, skip=%lu\n", (unsigned long)bh.chunksize, (unsigned long) bh.skip );


ASSERT( bh.chunksize, "Invalid peak file structure!" );
ASSERT( bh.chunksize, "Chucksize of zero. Invalid peak file structure!" );


blocks.push_back( block_descriptor( bh.chunksize, ftell( _fp ) ) ); blocks.push_back( block_descriptor( bh.chunksize, ftell( _fp ) ) );


@@ -192,7 +195,7 @@ public:
} }


if ( ! blocks.size() ) if ( ! blocks.size() )
FATAL( "invalid peak file?" );
FATAL( "Peak file contains no blocks!" );


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


@@ -251,8 +254,16 @@ public:
_chunksize = 0; _chunksize = 0;
_channels = channels; _channels = channels;


if ( ! ( _fp = fopen( peakname( name ), "r" ) ) )
char *pn = peakname( name );

if ( ! ( _fp = fopen( pn, "r" ) ) )
{
WARNING( "Failed to open peakfile for reading: %s", strerror(errno) );
free( pn );
return false; return false;
}

free( pn );


scan( chunksize ); scan( chunksize );


@@ -297,14 +308,19 @@ public:
read_peaks ( Peak *peaks, nframes_t s, int npeaks, nframes_t chunksize ) read_peaks ( Peak *peaks, nframes_t s, int npeaks, nframes_t chunksize )
{ {
if ( ! _fp ) if ( ! _fp )
{
DMESSAGE( "No peakfile open, WTF?" );
return 0; return 0;
}


const unsigned int ratio = chunksize / _chunksize; const unsigned int ratio = chunksize / _chunksize;


/* locate to start position */ /* locate to start position */
if ( fseek( _fp, _offset + ( frame_to_peak( s ) * sizeof( Peak ) ), SEEK_SET ) ) if ( fseek( _fp, _offset + ( frame_to_peak( s ) * sizeof( Peak ) ), SEEK_SET ) )
/* failed to seek... peaks not ready? */
{
DMESSAGE( "failed to seek... peaks not ready?" );
return 0; return 0;
}


if ( ratio == 1 ) if ( ratio == 1 )
return fread( peaks, sizeof( Peak ) * _channels, npeaks, _fp ); return fread( peaks, sizeof( Peak ) * _channels, npeaks, _fp );
@@ -355,6 +371,9 @@ public:
bool bool
Peaks::ready ( nframes_t s, int npeaks, nframes_t chunksize ) const Peaks::ready ( nframes_t s, int npeaks, nframes_t chunksize ) const
{ {
/* if ( _pending ) */
/* return false; */

Peakfile _peakfile; Peakfile _peakfile;


if ( ! _peakfile.open( _clip->filename(), _clip->channels(), chunksize ) ) if ( ! _peakfile.open( _clip->filename(), _clip->channels(), chunksize ) )
@@ -369,20 +388,25 @@ Peaks::read_peakfile_peaks ( Peak *peaks, nframes_t s, int npeaks, nframes_t chu
/* never try to build peaks while recording */ /* never try to build peaks while recording */
if ( ! transport->recording ) if ( ! transport->recording )
{ {
if ( ! current() )
if ( ! current() && ! _pending )
{ {
/* Build peaks asyncronously */ /* Build peaks asyncronously */
if ( ! fork() )
exit( make_peaks() );
else
return 0;
_pending = true;
_make_peaks_thread.clone( &Peaks::make_peaks, const_cast<Peaks*>(this) );
_make_peaks_thread.detach();
} }
} }


/* if ( _pending ) */
/* return 0; */

Peakfile _peakfile; Peakfile _peakfile;


if ( ! _peakfile.open( _clip->filename(), _clip->channels(), chunksize ) ) if ( ! _peakfile.open( _clip->filename(), _clip->channels(), chunksize ) )
{
DMESSAGE( "Failed to open peakfile!" );
return 0; return 0;
}


return _peakfile.read_peaks( peaks, s, npeaks, chunksize ); return _peakfile.read_peaks( peaks, s, npeaks, chunksize );
} }
@@ -458,9 +482,13 @@ Peaks::read_peaks ( nframes_t s, int npeaks, nframes_t chunksize ) const


/* FIXME: use actual minimum chunksize from peakfile! */ /* FIXME: use actual minimum chunksize from peakfile! */
if ( chunksize < (nframes_t)cache_minimum ) if ( chunksize < (nframes_t)cache_minimum )
{
_peakbuf.len = read_source_peaks( _peakbuf.buf->data, s, npeaks, chunksize ); _peakbuf.len = read_source_peaks( _peakbuf.buf->data, s, npeaks, chunksize );
}
else else
{
_peakbuf.len = read_peakfile_peaks( _peakbuf.buf->data, s, npeaks, chunksize ); _peakbuf.len = read_peakfile_peaks( _peakbuf.buf->data, s, npeaks, chunksize );
}


return _peakbuf.len; return _peakbuf.len;
} }
@@ -469,7 +497,22 @@ Peaks::read_peaks ( nframes_t s, int npeaks, nframes_t chunksize ) const
bool bool
Peaks::current ( void ) const Peaks::current ( void ) const
{ {
return ! newer( _clip->filename(), peakname( _clip->filename() ) );
char *pn = peakname( _clip->filename() );

bool b = ! newer( _clip->filename(), pn );

free( pn );

return b;
}

/* thread entry point */
void *
Peaks::make_peaks ( void *v )
{
((Peaks*)v)->make_peaks();

return NULL;
} }


bool bool
@@ -477,7 +520,24 @@ Peaks::make_peaks ( void ) const
{ {
Peaks::Builder pb( this ); Peaks::Builder pb( this );


return pb.make_peaks();
int b = pb.make_peaks();

_pending = false;

Fl::lock();
timeline->redraw();
Fl::unlock();

return b;
}

/* thread entry point */
void *
Peaks::make_peaks_mipmap ( void *v )
{
((Peaks*)v)->make_peaks_mipmap();

return NULL;
} }


bool bool
@@ -485,7 +545,11 @@ Peaks::make_peaks_mipmap ( void ) const
{ {
Peaks::Builder pb( this ); Peaks::Builder pb( this );


return pb.make_peaks_mipmap();
bool b = pb.make_peaks_mipmap();

_pending = false;
return b;
} }


/** return normalization factor for a single peak, assuming the peak /** return normalization factor for a single peak, assuming the peak
@@ -511,7 +575,11 @@ Peaks::prepare_for_writing ( void )


assert( ! _peak_writer ); assert( ! _peak_writer );


_peak_writer = new Peaks::Streamer( _clip->filename(), _clip->channels(), cache_minimum );
char *pn = peakname( _clip->filename() );

_peak_writer = new Peaks::Streamer( pn, _clip->channels(), cache_minimum );

free( pn );
} }


void void
@@ -522,10 +590,7 @@ Peaks::finish_writing ( void )
delete _peak_writer; delete _peak_writer;
_peak_writer = NULL; _peak_writer = NULL;


/* now fill in the rest of the cache */
if ( ! fork() )
exit( make_peaks_mipmap() );

make_peaks_mipmap();
} }


void void
@@ -556,9 +621,9 @@ Peaks::Streamer::Streamer ( const char *filename, int channels, nframes_t chunks
_peak = new Peak[ channels ]; _peak = new Peak[ channels ];
memset( _peak, 0, sizeof( Peak ) * channels ); memset( _peak, 0, sizeof( Peak ) * channels );


if ( ! ( _fp = fopen( peakname( filename ), "w" ) ) )
if ( ! ( _fp = fopen( filename, "w" ) ) )
{ {
WARNING( "could not open peakfile for streaming." );
FATAL( "could not open peakfile for streaming." );
} }


peakfile_block_header bh; peakfile_block_header bh;
@@ -575,8 +640,12 @@ Peaks::Streamer::~Streamer ( )
{ {
/* fwrite( _peak, sizeof( Peak ) * _channels, 1, _fp ); */ /* fwrite( _peak, sizeof( Peak ) * _channels, 1, _fp ); */


fflush( _fp );

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


// fsync( fileno( _fp ) );

fclose( _fp ); fclose( _fp );


delete[] _peak; delete[] _peak;
@@ -595,7 +664,7 @@ 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? */ /* FIXME: shouldn't we just use write() instead? */
fflush( _fp );
// fflush( _fp );


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


@@ -648,13 +717,13 @@ Peaks::Builder::write_block_header ( nframes_t chunksize )
fseek( fp, last_block_pos - sizeof( peakfile_block_header ), SEEK_SET ); fseek( fp, last_block_pos - sizeof( peakfile_block_header ), SEEK_SET );
// fseek( fp, 0 - sizeof( bh ), SEEK_CUR ); // fseek( fp, 0 - sizeof( bh ), SEEK_CUR );


// DMESSAGE( "old block header: chunksize=%lu, skip=%lu", bh.chunksize, bh.skip );
// DMESSAGE( "old block header: chunksize=%lu, skip=%lu", (unsigned long) bh.chunksize, (unsigned long) bh.skip );


bh.skip = pos - last_block_pos; bh.skip = pos - last_block_pos;


ASSERT( bh.skip, "Attempt to create empty block. pos=%lu, last_block_pos=%lu", pos, last_block_pos ); ASSERT( bh.skip, "Attempt to create empty block. pos=%lu, last_block_pos=%lu", pos, last_block_pos );


// DMESSAGE( "new block header: chunksize=%lu, skip=%lu", bh.chunksize, bh.skip );
// DMESSAGE( "new block header: chunksize=%lu, skip=%lu", (unsigned long) bh.chunksize, (unsigned long) bh.skip );


fwrite( &bh, sizeof( bh ), 1, fp ); fwrite( &bh, sizeof( bh ), 1, fp );


@@ -673,6 +742,9 @@ Peaks::Builder::write_block_header ( nframes_t chunksize )
fflush( fp ); fflush( fp );
} }





/** generate additional cache levels for a peakfile with only 1 block (ie. that of a new capture) */ /** generate additional cache levels for a peakfile with only 1 block (ie. that of a new capture) */
bool bool
Peaks::Builder::make_peaks_mipmap ( void ) Peaks::Builder::make_peaks_mipmap ( void )
@@ -683,22 +755,47 @@ Peaks::Builder::make_peaks_mipmap ( void )
Audio_File *_clip = _peaks->_clip; Audio_File *_clip = _peaks->_clip;


const char *filename = _clip->filename(); const char *filename = _clip->filename();
char *pn = peakname( filename );


FILE *rfp; FILE *rfp;
if ( ! ( rfp = fopen( pn, "r" ) ) )
{
WARNING( "could not open peakfile for reading: %s.", strerror( errno ) );
free( pn );
return false;
}

{
peakfile_block_header bh;


rfp = fopen( peakname( filename ), "r" );
fread( &bh, sizeof( peakfile_block_header ), 1, rfp );

if ( bh.skip )
{
WARNING( "Peakfile already has multiple blocks..." );
fclose( rfp );
free( pn );
return false;
}

}


last_block_pos = sizeof( peakfile_block_header ); last_block_pos = sizeof( peakfile_block_header );


/* open for reading */ /* open for reading */
// rfp = fopen( peakname( filename ), "r" ); // rfp = fopen( peakname( filename ), "r" );

/* open the file again for appending */ /* open the file again for appending */
if ( ! ( fp = fopen( peakname( filename ), "r+" ) ) )
if ( ! ( fp = fopen( pn, "r+" ) ) )
{ {
WARNING( "could not open peakfile for appending." );
WARNING( "could not open peakfile for appending: %s.", strerror( errno ) );
free( pn );
return false; return false;
} }


free( pn );

if ( fseek( fp, 0, SEEK_END ) ) if ( fseek( fp, 0, SEEK_END ) )
FATAL( "error performing seek: %s", strerror( errno ) ); FATAL( "error performing seek: %s", strerror( errno ) );


@@ -714,9 +811,10 @@ Peaks::Builder::make_peaks_mipmap ( void )
* preceding level */ * preceding level */


nframes_t cs = Peaks::cache_minimum << Peaks::cache_step; nframes_t cs = Peaks::cache_minimum << Peaks::cache_step;

for ( int i = 1; i < Peaks::cache_levels; ++i, cs <<= Peaks::cache_step ) for ( int i = 1; i < Peaks::cache_levels; ++i, cs <<= Peaks::cache_step )
{ {
DMESSAGE( "building level %d peak cache", i + 1 );
DMESSAGE( "building level %d peak cache cs=%i", i + 1, cs );


/* DMESSAGE( "%lu", _clip->length() / cs ); */ /* DMESSAGE( "%lu", _clip->length() / cs ); */


@@ -726,10 +824,10 @@ Peaks::Builder::make_peaks_mipmap ( void )
break; break;
} }



Peakfile pf; Peakfile pf;


/* open the peakfile for the previous cache level */ /* open the peakfile for the previous cache level */

pf.open( rfp, _clip->channels(), cs >> Peaks::cache_step ); pf.open( rfp, _clip->channels(), cs >> Peaks::cache_step );


// pf.open( _clip->filename(), _clip->channels(), cs >> Peaks::cache_step ); // pf.open( _clip->filename(), _clip->channels(), cs >> Peaks::cache_step );
@@ -740,12 +838,16 @@ Peaks::Builder::make_peaks_mipmap ( void )
nframes_t s = 0; nframes_t s = 0;
do { do {
len = pf.read_peaks( buf, s, 1, cs ); len = pf.read_peaks( buf, s, 1, cs );

s += cs; s += cs;


fwrite( buf, sizeof( buf ), len, fp ); fwrite( buf, sizeof( buf ), len, fp );
} }
while ( len ); while ( len );


/* fflush( fp ); */
/* fsync( fileno( fp ) ); */

pf.leave_open(); pf.leave_open();
} }


@@ -766,8 +868,15 @@ Peaks::Builder::make_peaks ( void )


DMESSAGE( "building peaks for \"%s\"", filename ); DMESSAGE( "building peaks for \"%s\"", filename );


if ( ! ( fp = fopen( peakname( filename ), "w+" ) ) )
char *pn = peakname( filename );

if ( ! ( fp = fopen( pn, "w+" ) ) )
{
free( pn );
return false; return false;
}

free( pn );


_clip->seek( 0 ); _clip->seek( 0 );


@@ -787,6 +896,8 @@ Peaks::Builder::make_peaks ( void )
while ( len ); while ( len );


/* reopen for reading */ /* reopen for reading */
/* fflush( fp ); */
/* fsync( fileno( fp ) ); */
fclose( fp ); fclose( fp );


make_peaks_mipmap(); make_peaks_mipmap();


+ 10
- 2
timeline/src/Engine/Peaks.H View File

@@ -27,10 +27,20 @@


#include <stdio.h> #include <stdio.h>


#include "Thread.H"


class Audio_File; class Audio_File;


class Peaks class Peaks
{ {
mutable volatile bool _pending;

mutable Thread _make_peaks_thread;
mutable Thread _make_peaks_mipmap_thread;

static void * make_peaks_mipmap ( void *v );
static void * make_peaks ( void *v );


struct peakdata { struct peakdata {


@@ -115,8 +125,6 @@ public:
static const int cache_levels; static const int cache_levels;
static const int cache_step; static const int cache_step;




Peaks ( Audio_File *c ); Peaks ( Audio_File *c );
~Peaks ( ); ~Peaks ( );




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

@@ -249,12 +249,14 @@ Track::record ( Capture *c, nframes_t frame )
{ {
THREAD_ASSERT( Capture ); THREAD_ASSERT( Capture );


char pat[256];
char *pat;


snprintf( pat, sizeof( pat ), "%s-%llu", name(), uuid() );
asprintf( &pat, "%s-%llu", name(), uuid() );


c->audio_file = Audio_File_SF::create( pat, engine->sample_rate(), input.size(), Track::capture_format ); c->audio_file = Audio_File_SF::create( pat, engine->sample_rate(), input.size(), Track::capture_format );


free( pat );

if ( ! c->audio_file ) if ( ! c->audio_file )
FATAL( "Could not create file for new capture!" ); FATAL( "Could not create file for new capture!" );


@@ -287,10 +289,15 @@ Track::finalize ( Capture *c, nframes_t frame )
/* adjust region start for latency */ /* adjust region start for latency */
/* FIXME: is just looking at the first channel good enough? */ /* FIXME: is just looking at the first channel good enough? */


c->region->finalize( frame );
DMESSAGE( "finalizing audio file" ); DMESSAGE( "finalizing audio file" );
/* must finalize audio before peaks file, otherwise another thread
* might think the peaks are out of date and attempt to regenerate
* them */
c->audio_file->finalize(); c->audio_file->finalize();


/* peaks get finalized here */
c->region->finalize( frame );

nframes_t capture_offset = 0; nframes_t capture_offset = 0;


/* Add the system latency twice. Once for the input (usually /* Add the system latency twice. Once for the input (usually


Loading…
Cancel
Save