Fix runaway processing in peakfile generation.
This commit is contained in:
parent
3e73817155
commit
e5875fa072
|
@ -14,7 +14,7 @@ OBJS:=$(SRCS:.C=.o)
|
||||||
|
|
||||||
LIBS += $(FLTK_LDFLAGS) $(JACK_LIBS) $(SNDFILE_LIBS) $(LIBLO_LIBS) $(SIGCPP_LIBS) $(XPM_LIBS)
|
LIBS += $(FLTK_LDFLAGS) $(JACK_LIBS) $(SNDFILE_LIBS) $(LIBLO_LIBS) $(SIGCPP_LIBS) $(XPM_LIBS)
|
||||||
|
|
||||||
CFLAGS += $(SNDFILE_CFLAGS) $(FLTK_CFLAGS) $(JACK_CFLAGS) $(SIGCPP_CFLAGS) $(XPM_CFLAGS)
|
CFLAGS += $(SNDFILE_CFLAGS) $(FLTK_CFLAGS) $(JACK_CFLAGS) $(SIGCPP_CFLAGS) $(XPM_CFLAGS) -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
|
||||||
|
|
||||||
ifeq ($(USE_UNOPTIMIZED_DRAWING),yes)
|
ifeq ($(USE_UNOPTIMIZED_DRAWING),yes)
|
||||||
CFLAGS+=-DUSE_UNOPTIMIZED_DRAWING
|
CFLAGS+=-DUSE_UNOPTIMIZED_DRAWING
|
||||||
|
|
|
@ -470,6 +470,15 @@ Audio_Region::draw_box( void )
|
||||||
fl_pop_clip();
|
fl_pop_clip();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Audio_Region::peaks_ready_callback ( void *v )
|
||||||
|
{
|
||||||
|
Fl::lock();
|
||||||
|
((Audio_Region*)v)->redraw();
|
||||||
|
Fl::unlock();
|
||||||
|
Fl::awake();
|
||||||
|
}
|
||||||
|
|
||||||
/** Draw (part of) region. X, Y, W and H are the rectangle we're clipped to. */
|
/** Draw (part of) region. X, Y, W and H are the rectangle we're clipped to. */
|
||||||
void
|
void
|
||||||
Audio_Region::draw ( void )
|
Audio_Region::draw ( void )
|
||||||
|
@ -540,11 +549,11 @@ Audio_Region::draw ( void )
|
||||||
|
|
||||||
// DMESSAGE( "Drawing audio region.");
|
// DMESSAGE( "Drawing audio region.");
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
int channels;
|
int channels;
|
||||||
int peaks;
|
int peaks;
|
||||||
Peak *pbuf;
|
Peak *pbuf = NULL;
|
||||||
|
|
||||||
|
do {
|
||||||
|
|
||||||
nframes_t start = _r->offset;
|
nframes_t start = _r->offset;
|
||||||
|
|
||||||
|
@ -577,22 +586,7 @@ Audio_Region::draw ( void )
|
||||||
|
|
||||||
assert( loop_peaks_needed >= 0 );
|
assert( loop_peaks_needed >= 0 );
|
||||||
|
|
||||||
if ( _loop && offset < _loop )
|
|
||||||
{
|
|
||||||
const int x = timeline->ts_to_x( _loop - offset );
|
|
||||||
|
|
||||||
/* FIXME: is there no way to draw these symbols direclty? */
|
|
||||||
fl_color( FL_WHITE );
|
|
||||||
|
|
||||||
fl_push_matrix();
|
|
||||||
|
|
||||||
fl_translate( X + x + 2, y() + h() - 14 );
|
|
||||||
fl_scale( - 16, 8 );
|
|
||||||
|
|
||||||
draw_full_arrow_symbol( FL_BLACK );
|
|
||||||
|
|
||||||
fl_pop_matrix();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( xo + loop_peaks_needed > total_peaks_needed )
|
if ( xo + loop_peaks_needed > total_peaks_needed )
|
||||||
|
@ -606,6 +600,8 @@ Audio_Region::draw ( void )
|
||||||
const nframes_t end = start + timeline->x_to_ts( loop_peaks_needed );
|
const nframes_t end = start + timeline->x_to_ts( loop_peaks_needed );
|
||||||
|
|
||||||
if ( start != ostart || end != oend )
|
if ( start != ostart || end != oend )
|
||||||
|
{
|
||||||
|
if ( _clip->peaks()->peakfile_ready() )
|
||||||
{
|
{
|
||||||
if ( _clip->read_peaks( timeline->fpp(),
|
if ( _clip->read_peaks( timeline->fpp(),
|
||||||
start,
|
start,
|
||||||
|
@ -620,6 +616,15 @@ Audio_Region::draw ( void )
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if ( ! transport->rolling )
|
||||||
|
{
|
||||||
|
/* create a thread to make the peaks */
|
||||||
|
_clip->peaks()->make_peaks_asynchronously( Audio_Region::peaks_ready_callback, this );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// DMESSAGE( "using cached peaks" );
|
// DMESSAGE( "using cached peaks" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -656,6 +661,21 @@ Audio_Region::draw ( void )
|
||||||
|
|
||||||
timeline->draw_measure_lines( X, Y, W, H );
|
timeline->draw_measure_lines( X, Y, W, H );
|
||||||
|
|
||||||
|
if ( _loop && offset < _loop )
|
||||||
|
{
|
||||||
|
const int x = timeline->ts_to_x( _loop - offset );
|
||||||
|
|
||||||
|
/* FIXME: is there no way to draw these symbols direclty? */
|
||||||
|
|
||||||
|
fl_push_matrix();
|
||||||
|
|
||||||
|
fl_translate( X + x + 2, y() + h() - 7 );
|
||||||
|
fl_scale( - 8, 8 );
|
||||||
|
|
||||||
|
draw_full_arrow_symbol( FL_WHITE );
|
||||||
|
|
||||||
|
fl_pop_matrix();
|
||||||
|
}
|
||||||
/* fl_color( FL_BLACK ); */
|
/* fl_color( FL_BLACK ); */
|
||||||
/* fl_line( rx, Y, rx, Y + H ); */
|
/* fl_line( rx, Y, rx, Y + H ); */
|
||||||
/* fl_line( rx + rw - 1, Y, rx + rw - 1, Y + H ); */
|
/* fl_line( rx + rw - 1, Y, rx + rw - 1, Y + H ); */
|
||||||
|
|
|
@ -33,6 +33,8 @@ class Audio_Region : public Sequence_Region
|
||||||
/* not permitted */
|
/* not permitted */
|
||||||
Audio_Region & operator = ( const Audio_Region &rhs );
|
Audio_Region & operator = ( const Audio_Region &rhs );
|
||||||
|
|
||||||
|
static void peaks_ready_callback ( void *v );
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
static bool inherit_track_color;
|
static bool inherit_track_color;
|
||||||
|
|
|
@ -35,8 +35,6 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "../Transport.H" // for .recording
|
|
||||||
|
|
||||||
#include "Audio_File.H"
|
#include "Audio_File.H"
|
||||||
#include "Peaks.H"
|
#include "Peaks.H"
|
||||||
|
|
||||||
|
@ -53,8 +51,19 @@
|
||||||
using std::min;
|
using std::min;
|
||||||
using std::max;
|
using std::max;
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
|
struct peak_thread_data
|
||||||
|
{
|
||||||
|
void(*callback)(void*);
|
||||||
|
void *userdata;
|
||||||
|
Peaks *peaks;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* whether to cache peaks at multiple resolutions on disk to
|
/* whether to cache peaks at multiple resolutions on disk to
|
||||||
|
@ -82,31 +91,6 @@ peakname ( const char *filename )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Peaks::Peaks ( Audio_File *c )
|
|
||||||
{
|
|
||||||
_pending = false;
|
|
||||||
_clip = c;
|
|
||||||
_peak_writer = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
Peaks::~Peaks ( )
|
|
||||||
{
|
|
||||||
if ( _peak_writer )
|
|
||||||
delete _peak_writer;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Prepare a buffer of peaks from /s/ to /e/ for reading. Must be
|
|
||||||
* called before any calls to operator[] */
|
|
||||||
int
|
|
||||||
Peaks::fill_buffer ( float fpp, nframes_t s, nframes_t e ) const
|
|
||||||
{
|
|
||||||
_fpp = fpp;
|
|
||||||
|
|
||||||
return read_peaks( s, (e - s) / fpp, fpp );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct peakfile_block_header
|
struct peakfile_block_header
|
||||||
{
|
{
|
||||||
|
@ -121,15 +105,15 @@ class Peakfile
|
||||||
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 */
|
||||||
size_t _offset;
|
off_t _offset;
|
||||||
int _blocks;
|
// int _blocks;
|
||||||
|
|
||||||
struct block_descriptor
|
struct block_descriptor
|
||||||
{
|
{
|
||||||
nframes_t chunksize;
|
nframes_t chunksize;
|
||||||
size_t pos;
|
off_t pos;
|
||||||
|
|
||||||
block_descriptor ( nframes_t chunksize, size_t pos ) : chunksize( chunksize ), pos( pos )
|
block_descriptor ( nframes_t chunksize, off_t pos ) : chunksize( chunksize ), pos( pos )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,16 +123,18 @@ class Peakfile
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::list <block_descriptor> blocks;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Peakfile ( )
|
Peakfile ( )
|
||||||
{
|
{
|
||||||
_blocks = 0;
|
// _blocks = 0;
|
||||||
_fp = NULL;
|
_fp = NULL;
|
||||||
_offset = 0;
|
_offset = 0;
|
||||||
_chunksize = 0;
|
_chunksize = 0;
|
||||||
_channels = 0;
|
_channels = 0;
|
||||||
|
_length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
~Peakfile ( )
|
~Peakfile ( )
|
||||||
|
@ -157,16 +143,16 @@ public:
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
int blocks ( void ) const { return _blocks; }
|
/* int blocks ( void ) const { return blocks.size(); } */
|
||||||
/** find the best block for /chunksize/ */
|
/** find the best block for /chunksize/ */
|
||||||
void
|
void
|
||||||
scan ( nframes_t chunksize )
|
scan ( nframes_t chunksize )
|
||||||
|
{
|
||||||
|
if ( ! blocks.size() )
|
||||||
{
|
{
|
||||||
rewind( _fp );
|
rewind( _fp );
|
||||||
clearerr( _fp );
|
clearerr( _fp );
|
||||||
|
|
||||||
std::list <block_descriptor> blocks;
|
|
||||||
|
|
||||||
/* scan all blocks */
|
/* scan all blocks */
|
||||||
for ( ;; )
|
for ( ;; )
|
||||||
{
|
{
|
||||||
|
@ -177,32 +163,39 @@ public:
|
||||||
if ( feof( _fp ) )
|
if ( feof( _fp ) )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// printf( "chunksize=%lu, skip=%lu\n", (unsigned long)bh.chunksize, (unsigned long) bh.skip );
|
DMESSAGE( "Peakfile: chunksize=%lu, skip=%lu\n", (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!" );
|
||||||
|
|
||||||
blocks.push_back( block_descriptor( bh.chunksize, ftell( _fp ) ) );
|
blocks.push_back( block_descriptor( bh.chunksize, ftello( _fp ) ) );
|
||||||
|
|
||||||
if ( ! bh.skip )
|
if ( ! bh.skip )
|
||||||
/* last block */
|
/* last block */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if ( fseek( _fp, bh.skip, SEEK_CUR ) )
|
if ( fseeko( _fp, bh.skip, SEEK_CUR ) )
|
||||||
{
|
{
|
||||||
WARNING( "seek failed: %s (%lu)", strerror( errno ), bh.skip );
|
WARNING( "seek failed: %s (%lu)", strerror( errno ), bh.skip );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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() );
|
||||||
|
|
||||||
blocks.sort();
|
blocks.sort();
|
||||||
|
|
||||||
/* fall back on the smallest chunksize */
|
/* fall back on the smallest chunksize */
|
||||||
fseek( _fp, blocks.front().pos, SEEK_SET );
|
fseeko( _fp, blocks.front().pos, SEEK_SET );
|
||||||
_chunksize = blocks.front().chunksize;
|
_chunksize = blocks.front().chunksize;
|
||||||
|
|
||||||
/* search for the best-fit chunksize */
|
/* search for the best-fit chunksize */
|
||||||
|
@ -211,19 +204,19 @@ public:
|
||||||
if ( chunksize >= i->chunksize )
|
if ( chunksize >= i->chunksize )
|
||||||
{
|
{
|
||||||
_chunksize = i->chunksize;
|
_chunksize = i->chunksize;
|
||||||
fseek( _fp, i->pos, SEEK_SET );
|
fseeko( _fp, i->pos, SEEK_SET );
|
||||||
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 = ftell( _fp );
|
_offset = ftello( _fp );
|
||||||
}
|
}
|
||||||
|
|
||||||
/** convert frame number of peak number */
|
/** convert frame number of peak number */
|
||||||
nframes_t frame_to_peak ( nframes_t frame )
|
nframes_t frame_to_peak ( nframes_t frame )
|
||||||
{
|
{
|
||||||
return frame * _channels / _chunksize;
|
return ( frame / _chunksize ) * (nframes_t)_channels;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** return the number of peaks in already open peakfile /fp/ */
|
/** return the number of peaks in already open peakfile /fp/ */
|
||||||
|
@ -241,7 +234,7 @@ public:
|
||||||
bool
|
bool
|
||||||
ready ( nframes_t start, nframes_t npeaks )
|
ready ( nframes_t start, nframes_t npeaks )
|
||||||
{
|
{
|
||||||
if ( _blocks > 1 )
|
if ( blocks.size() > 1 )
|
||||||
return true;
|
return true;
|
||||||
else
|
else
|
||||||
return this->npeaks() > frame_to_peak( start ) + npeaks;
|
return this->npeaks() > frame_to_peak( start ) + npeaks;
|
||||||
|
@ -251,7 +244,7 @@ public:
|
||||||
bool
|
bool
|
||||||
open ( const char *name, int channels, nframes_t chunksize )
|
open ( const char *name, int channels, nframes_t chunksize )
|
||||||
{
|
{
|
||||||
_chunksize = 0;
|
// _chunksize = 0;
|
||||||
_channels = channels;
|
_channels = channels;
|
||||||
|
|
||||||
char *pn = peakname( name );
|
char *pn = peakname( name );
|
||||||
|
@ -305,7 +298,7 @@ public:
|
||||||
* large enough to fit the entire request. Returns the number of
|
* large enough to fit the entire request. Returns the number of
|
||||||
* peaks actually read, which may be fewer than were requested. */
|
* peaks actually read, which may be fewer than were requested. */
|
||||||
nframes_t
|
nframes_t
|
||||||
read_peaks ( Peak *peaks, nframes_t s, int npeaks, nframes_t chunksize )
|
read_peaks ( Peak *peaks, nframes_t s, nframes_t npeaks, nframes_t chunksize )
|
||||||
{
|
{
|
||||||
if ( ! _fp )
|
if ( ! _fp )
|
||||||
{
|
{
|
||||||
|
@ -316,12 +309,19 @@ public:
|
||||||
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 ( s > _clip->length() ) */
|
||||||
|
/* return 0; */
|
||||||
|
|
||||||
|
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?" );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( feof( _fp ) )
|
||||||
|
return 0;
|
||||||
|
|
||||||
if ( ratio == 1 )
|
if ( ratio == 1 )
|
||||||
return fread( peaks, sizeof( Peak ) * _channels, npeaks, _fp );
|
return fread( peaks, sizeof( Peak ) * _channels, npeaks, _fp );
|
||||||
|
|
||||||
|
@ -329,7 +329,7 @@ public:
|
||||||
|
|
||||||
nframes_t len = 0;
|
nframes_t len = 0;
|
||||||
|
|
||||||
int i;
|
nframes_t i;
|
||||||
|
|
||||||
for ( i = 0; i < npeaks; ++i )
|
for ( i = 0; i < npeaks; ++i )
|
||||||
{
|
{
|
||||||
|
@ -358,9 +358,11 @@ public:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( len < ratio )
|
if ( feof( _fp) || len < ratio )
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
delete[] pbuf;
|
delete[] pbuf;
|
||||||
|
|
||||||
|
@ -368,8 +370,43 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Peaks::Peaks ( Audio_File *c )
|
||||||
|
{
|
||||||
|
_pending = false;
|
||||||
|
_clip = c;
|
||||||
|
_peak_writer = NULL;
|
||||||
|
_peakfile = new Peakfile();
|
||||||
|
}
|
||||||
|
|
||||||
|
Peaks::~Peaks ( )
|
||||||
|
{
|
||||||
|
if ( _peak_writer )
|
||||||
|
{
|
||||||
|
delete _peak_writer;
|
||||||
|
_peak_writer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete _peakfile;
|
||||||
|
_peakfile = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Prepare a buffer of peaks from /s/ to /e/ for reading. Must be
|
||||||
|
* called before any calls to operator[] */
|
||||||
|
int
|
||||||
|
Peaks::fill_buffer ( float fpp, nframes_t s, nframes_t e ) const
|
||||||
|
{
|
||||||
|
_fpp = fpp;
|
||||||
|
|
||||||
|
return read_peaks( s, (e - s) / fpp, fpp );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Peaks::ready ( nframes_t s, int npeaks, nframes_t chunksize ) const
|
Peaks::ready ( nframes_t s, nframes_t npeaks, nframes_t chunksize ) const
|
||||||
{
|
{
|
||||||
/* if ( _pending ) */
|
/* if ( _pending ) */
|
||||||
/* return false; */
|
/* return false; */
|
||||||
|
@ -382,45 +419,65 @@ Peaks::ready ( nframes_t s, int npeaks, nframes_t chunksize ) const
|
||||||
return _peakfile.ready( s, npeaks );
|
return _peakfile.ready( s, npeaks );
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
/** If this returns false, then the peakfile needs to be built */
|
||||||
Peaks::read_peakfile_peaks ( Peak *peaks, nframes_t s, int npeaks, nframes_t chunksize ) const
|
bool
|
||||||
|
Peaks::peakfile_ready ( void ) const
|
||||||
{
|
{
|
||||||
/* never try to build peaks while recording */
|
return current() && ! _pending;
|
||||||
if ( ! transport->recording )
|
}
|
||||||
{
|
|
||||||
if ( ! current() && ! _pending )
|
|
||||||
{
|
|
||||||
/* Build peaks asyncronously */
|
|
||||||
_pending = true;
|
|
||||||
_make_peaks_thread.clone( &Peaks::make_peaks, const_cast<Peaks*>(this) );
|
|
||||||
_make_peaks_thread.detach();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Peaks::make_peaks_asynchronously ( void(*callback)(void*), void *userdata ) const
|
||||||
|
{
|
||||||
|
/* already working on it... */
|
||||||
|
if( _pending )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// make_peaks();
|
||||||
|
|
||||||
|
_pending = true;
|
||||||
|
|
||||||
|
peak_thread_data *pd = new peak_thread_data();
|
||||||
|
|
||||||
|
pd->callback = callback;
|
||||||
|
pd->userdata = userdata;
|
||||||
|
pd->peaks = const_cast<Peaks*>(this);
|
||||||
|
|
||||||
|
_make_peaks_thread.clone( &Peaks::make_peaks, pd );
|
||||||
|
_make_peaks_thread.detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
nframes_t
|
||||||
|
Peaks::read_peakfile_peaks ( Peak *peaks, nframes_t s, nframes_t npeaks, nframes_t chunksize ) const
|
||||||
|
{
|
||||||
/* if ( _pending ) */
|
/* if ( _pending ) */
|
||||||
/* return 0; */
|
/* 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!" );
|
DMESSAGE( "Failed to open peakfile!" );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _peakfile.read_peaks( peaks, s, npeaks, chunksize );
|
nframes_t l = _peakfile->read_peaks( peaks, s, npeaks, chunksize );
|
||||||
|
|
||||||
|
_peakfile->close();
|
||||||
|
|
||||||
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
nframes_t
|
||||||
Peaks::read_source_peaks ( Peak *peaks, int npeaks, nframes_t chunksize ) const
|
Peaks::read_source_peaks ( Peak *peaks, nframes_t npeaks, nframes_t chunksize ) const
|
||||||
{
|
{
|
||||||
int channels = _clip->channels();
|
int channels = _clip->channels();
|
||||||
|
|
||||||
sample_t *fbuf = new sample_t[ chunksize * channels ];
|
sample_t *fbuf = new sample_t[ chunksize * channels ];
|
||||||
|
|
||||||
size_t len;
|
off_t len;
|
||||||
|
|
||||||
int i;
|
nframes_t i;
|
||||||
for ( i = 0; i < npeaks; ++i )
|
for ( i = 0; i < npeaks; ++i )
|
||||||
{
|
{
|
||||||
/* read in a buffer */
|
/* read in a buffer */
|
||||||
|
@ -455,19 +512,19 @@ Peaks::read_source_peaks ( Peak *peaks, int npeaks, nframes_t chunksize ) const
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
nframes_t
|
||||||
Peaks::read_source_peaks ( Peak *peaks, nframes_t s, int npeaks, nframes_t chunksize ) const
|
Peaks::read_source_peaks ( Peak *peaks, nframes_t s, nframes_t npeaks, nframes_t chunksize ) const
|
||||||
{
|
{
|
||||||
_clip->seek( s );
|
_clip->seek( s );
|
||||||
|
|
||||||
int i = read_source_peaks( peaks, npeaks, chunksize );
|
return read_source_peaks( peaks, npeaks, chunksize );
|
||||||
|
|
||||||
return i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
nframes_t
|
||||||
Peaks::read_peaks ( nframes_t s, int npeaks, nframes_t chunksize ) const
|
Peaks::read_peaks ( nframes_t s, nframes_t npeaks, nframes_t chunksize ) const
|
||||||
{
|
{
|
||||||
|
THREAD_ASSERT( UI ); /* because _peakbuf cache is static */
|
||||||
|
|
||||||
// printf( "reading peaks %d @ %d\n", npeaks, chunksize );
|
// printf( "reading peaks %d @ %d\n", npeaks, chunksize );
|
||||||
|
|
||||||
if ( _peakbuf.size < (nframes_t)( npeaks * _clip->channels() ) )
|
if ( _peakbuf.size < (nframes_t)( npeaks * _clip->channels() ) )
|
||||||
|
@ -510,7 +567,14 @@ Peaks::current ( void ) const
|
||||||
void *
|
void *
|
||||||
Peaks::make_peaks ( void *v )
|
Peaks::make_peaks ( void *v )
|
||||||
{
|
{
|
||||||
((Peaks*)v)->make_peaks();
|
peak_thread_data *pd = (peak_thread_data*)v;
|
||||||
|
|
||||||
|
pd->peaks->make_peaks();
|
||||||
|
|
||||||
|
if ( pd->callback )
|
||||||
|
pd->callback( pd->userdata );
|
||||||
|
|
||||||
|
delete pd;
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -524,10 +588,6 @@ Peaks::make_peaks ( void ) const
|
||||||
|
|
||||||
_pending = false;
|
_pending = false;
|
||||||
|
|
||||||
Fl::lock();
|
|
||||||
timeline->redraw();
|
|
||||||
Fl::unlock();
|
|
||||||
|
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -706,16 +766,16 @@ Peaks::Builder::write_block_header ( nframes_t chunksize )
|
||||||
if ( last_block_pos )
|
if ( last_block_pos )
|
||||||
{
|
{
|
||||||
/* update previous block */
|
/* update previous block */
|
||||||
size_t pos = ftell( fp );
|
off_t pos = ftello( fp );
|
||||||
|
|
||||||
fseek( fp, last_block_pos - sizeof( peakfile_block_header ), SEEK_SET );
|
fseeko( fp, last_block_pos - sizeof( peakfile_block_header ), SEEK_SET );
|
||||||
|
|
||||||
peakfile_block_header bh;
|
peakfile_block_header bh;
|
||||||
|
|
||||||
fread( &bh, sizeof( bh ), 1, fp );
|
fread( &bh, sizeof( bh ), 1, fp );
|
||||||
|
|
||||||
fseek( fp, last_block_pos - sizeof( peakfile_block_header ), SEEK_SET );
|
fseeko( fp, last_block_pos - sizeof( peakfile_block_header ), SEEK_SET );
|
||||||
// fseek( fp, 0 - sizeof( bh ), SEEK_CUR );
|
// fseeko( fp, 0 - sizeof( bh ), SEEK_CUR );
|
||||||
|
|
||||||
// DMESSAGE( "old block header: chunksize=%lu, skip=%lu", (unsigned long) bh.chunksize, (unsigned long) bh.skip );
|
// DMESSAGE( "old block header: chunksize=%lu, skip=%lu", (unsigned long) bh.chunksize, (unsigned long) bh.skip );
|
||||||
|
|
||||||
|
@ -727,7 +787,7 @@ Peaks::Builder::write_block_header ( nframes_t chunksize )
|
||||||
|
|
||||||
fwrite( &bh, sizeof( bh ), 1, fp );
|
fwrite( &bh, sizeof( bh ), 1, fp );
|
||||||
|
|
||||||
fseek( fp, pos, SEEK_SET );
|
fseeko( fp, pos, SEEK_SET );
|
||||||
}
|
}
|
||||||
|
|
||||||
peakfile_block_header bh;
|
peakfile_block_header bh;
|
||||||
|
@ -737,7 +797,7 @@ Peaks::Builder::write_block_header ( nframes_t chunksize )
|
||||||
|
|
||||||
fwrite( &bh, sizeof( bh ), 1, fp );
|
fwrite( &bh, sizeof( bh ), 1, fp );
|
||||||
|
|
||||||
last_block_pos = ftell( fp );
|
last_block_pos = ftello( fp );
|
||||||
|
|
||||||
fflush( fp );
|
fflush( fp );
|
||||||
}
|
}
|
||||||
|
@ -796,10 +856,10 @@ Peaks::Builder::make_peaks_mipmap ( void )
|
||||||
|
|
||||||
free( pn );
|
free( pn );
|
||||||
|
|
||||||
if ( fseek( fp, 0, SEEK_END ) )
|
if ( fseeko( fp, 0, SEEK_END ) )
|
||||||
FATAL( "error performing seek: %s", strerror( errno ) );
|
FATAL( "error performing seek: %s", strerror( errno ) );
|
||||||
|
|
||||||
if ( ftell( fp ) == sizeof( peakfile_block_header ) )
|
if ( ftello( fp ) == sizeof( peakfile_block_header ) )
|
||||||
{
|
{
|
||||||
DWARNING( "truncated peakfile. Programming error?" );
|
DWARNING( "truncated peakfile. Programming error?" );
|
||||||
return false;
|
return false;
|
||||||
|
@ -834,7 +894,7 @@ Peaks::Builder::make_peaks_mipmap ( void )
|
||||||
|
|
||||||
write_block_header( cs );
|
write_block_header( cs );
|
||||||
|
|
||||||
size_t len;
|
off_t len;
|
||||||
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 );
|
||||||
|
@ -843,7 +903,9 @@ Peaks::Builder::make_peaks_mipmap ( void )
|
||||||
|
|
||||||
fwrite( buf, sizeof( buf ), len, fp );
|
fwrite( buf, sizeof( buf ), len, fp );
|
||||||
}
|
}
|
||||||
while ( len );
|
while ( len > 0 && s < _clip->length() );
|
||||||
|
|
||||||
|
DMESSAGE( "Last sample was %lu", s );
|
||||||
|
|
||||||
/* fflush( fp ); */
|
/* fflush( fp ); */
|
||||||
/* fsync( fileno( fp ) ); */
|
/* fsync( fileno( fp ) ); */
|
||||||
|
@ -887,7 +949,7 @@ Peaks::Builder::make_peaks ( void )
|
||||||
write_block_header( Peaks::cache_minimum );
|
write_block_header( Peaks::cache_minimum );
|
||||||
|
|
||||||
/* build first level from source */
|
/* build first level from source */
|
||||||
size_t len;
|
off_t len;
|
||||||
do {
|
do {
|
||||||
len = _peaks->read_source_peaks( buf, 1, Peaks::cache_minimum );
|
len = _peaks->read_source_peaks( buf, 1, Peaks::cache_minimum );
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
|
|
||||||
|
|
||||||
class Audio_File;
|
class Audio_File;
|
||||||
|
class Peakfile;
|
||||||
|
|
||||||
class Peaks
|
class Peaks
|
||||||
{
|
{
|
||||||
|
@ -63,6 +64,8 @@ class Peaks
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Peakfile *_peakfile;
|
||||||
|
|
||||||
class Streamer
|
class Streamer
|
||||||
{
|
{
|
||||||
FILE *_fp;
|
FILE *_fp;
|
||||||
|
@ -87,7 +90,7 @@ class Peaks
|
||||||
class Builder
|
class Builder
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
size_t last_block_pos;
|
off_t last_block_pos;
|
||||||
const Peaks *_peaks;
|
const Peaks *_peaks;
|
||||||
|
|
||||||
void write_block_header ( nframes_t chunksize );
|
void write_block_header ( nframes_t chunksize );
|
||||||
|
@ -100,16 +103,17 @@ class Peaks
|
||||||
Builder ( const Peaks *peaks );
|
Builder ( const Peaks *peaks );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* FIXME: Is this ever accessed by multiple threads? */
|
||||||
static peakbuffer _peakbuf;
|
static peakbuffer _peakbuf;
|
||||||
|
|
||||||
Audio_File *_clip;
|
Audio_File *_clip;
|
||||||
|
|
||||||
mutable float _fpp;
|
mutable float _fpp;
|
||||||
|
|
||||||
int read_peaks ( nframes_t s, int npeaks, nframes_t chunksize ) const;
|
nframes_t read_peaks ( nframes_t s, nframes_t npeaks, nframes_t chunksize ) const;
|
||||||
int read_source_peaks ( Peak *peaks, nframes_t s, int npeaks, nframes_t chunksize ) const;
|
nframes_t read_source_peaks ( Peak *peaks, nframes_t s, nframes_t npeaks, nframes_t chunksize ) const;
|
||||||
int read_source_peaks ( Peak *peaks, int npeaks, nframes_t chunksize ) const;
|
nframes_t read_source_peaks ( Peak *peaks, nframes_t npeaks, nframes_t chunksize ) const;
|
||||||
int read_peakfile_peaks ( Peak *peaks, nframes_t s, int npeaks, nframes_t chunksize ) const;
|
nframes_t read_peakfile_peaks ( Peak *peaks, nframes_t s, nframes_t npeaks, nframes_t chunksize ) const;
|
||||||
|
|
||||||
Streamer * volatile _peak_writer; /* exists when streaming peaks to disk */
|
Streamer * volatile _peak_writer; /* exists when streaming peaks to disk */
|
||||||
|
|
||||||
|
@ -117,6 +121,8 @@ class Peaks
|
||||||
Peaks ( const Peaks &rhs );
|
Peaks ( const Peaks &rhs );
|
||||||
const Peaks &operator= ( const Peaks &rhs );
|
const Peaks &operator= ( const Peaks &rhs );
|
||||||
|
|
||||||
|
bool current ( void ) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
static bool mipmapped_peakfiles;
|
static bool mipmapped_peakfiles;
|
||||||
|
@ -133,14 +139,17 @@ public:
|
||||||
|
|
||||||
int fill_buffer ( float fpp, nframes_t s, nframes_t e ) const;
|
int fill_buffer ( float fpp, nframes_t s, nframes_t e ) const;
|
||||||
|
|
||||||
void read ( int X, float *hi, float *lo ) const;
|
bool peakfile_ready ( void ) const;
|
||||||
bool ready ( nframes_t s, int npeaks, nframes_t chunksize ) const;
|
|
||||||
|
void read ( int X, float *hi, float *lo ) const;
|
||||||
|
bool ready ( nframes_t s, nframes_t npeaks, nframes_t chunksize ) const;
|
||||||
|
|
||||||
bool current ( void ) const;
|
|
||||||
bool make_peaks ( void ) const;
|
bool make_peaks ( void ) const;
|
||||||
bool make_peaks_mipmap ( void ) const;
|
bool make_peaks_mipmap ( void ) const;
|
||||||
|
void make_peaks_asynchronously ( void(*callback)(void*), void *userdata ) const;
|
||||||
|
|
||||||
void prepare_for_writing ( void );
|
void prepare_for_writing ( void );
|
||||||
void finish_writing ( void );
|
void finish_writing ( void );
|
||||||
void write ( sample_t *buf, nframes_t nframes );
|
void write ( sample_t *buf, nframes_t nframes );
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
/* Controls the audio transport */
|
/* Controls the audio transport */
|
||||||
|
|
||||||
#include "Transport.H"
|
#include "Transport.H"
|
||||||
|
#include "Timeline.H"
|
||||||
|
|
||||||
#include "Engine/Engine.H"
|
#include "Engine/Engine.H"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue