Clean up Peaks.C
This commit is contained in:
parent
d1a2f52352
commit
f12363340e
438
Timeline/Peaks.C
438
Timeline/Peaks.C
|
@ -25,8 +25,6 @@
|
||||||
|
|
||||||
#include "Peaks.H"
|
#include "Peaks.H"
|
||||||
|
|
||||||
// #include "Timeline.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>
|
||||||
|
@ -40,50 +38,25 @@
|
||||||
|
|
||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
#include <FL/Fl.H> // for Fl::check();
|
|
||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
|
||||||
#include "Transport.H" // for .recording
|
#include "Transport.H" // for .recording
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
Peaks::peakbuffer Peaks::_peakbuf;
|
/* whether to cache peaks at multiple resolutions on disk to
|
||||||
|
* drastically improve performance */
|
||||||
|
|
||||||
bool Peaks::mipmapped_peakfiles = true;
|
bool Peaks::mipmapped_peakfiles = true;
|
||||||
|
|
||||||
/* chunksizes at which to generate peakfiles (on demand). This should
|
|
||||||
pretty much cover the usable range. Better performance can be
|
|
||||||
achieved at high zoom-levels and for compressed sources with a
|
|
||||||
minimum of 64, but those files are up into the megabytes. */
|
|
||||||
const int Peaks::cache_minimum = 256; /* minimum chunksize to build peakfiles for */
|
const int Peaks::cache_minimum = 256; /* minimum chunksize to build peakfiles for */
|
||||||
const int Peaks::cache_levels = 8; /* number of sampling levels in peak cache */
|
const int Peaks::cache_levels = 8; /* number of sampling levels in peak cache */
|
||||||
// const int Peaks::cache_step = 2; /* powers of two between each level. 4 == 256, 2048, 16384, ... */
|
|
||||||
|
|
||||||
const int Peaks::cache_step = 1; /* powers of two between each level. 4 == 256, 2048, 16384, ... */
|
const int Peaks::cache_step = 1; /* powers of two between each level. 4 == 256, 2048, 16384, ... */
|
||||||
|
|
||||||
/* Peaks ( ) */
|
|
||||||
/* { */
|
|
||||||
/* _clip = NULL; */
|
|
||||||
/* } */
|
|
||||||
|
|
||||||
Peaks::Peaks ( Audio_File *c )
|
Peaks::peakbuffer Peaks::_peakbuf;
|
||||||
{
|
|
||||||
_clip = c;
|
|
||||||
_peak_writer = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
Peaks::~Peaks ( )
|
|
||||||
{
|
|
||||||
if ( _peak_writer )
|
|
||||||
delete _peak_writer;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static
|
static
|
||||||
const char *
|
const char *
|
||||||
|
@ -96,16 +69,18 @@ peakname ( const char *filename )
|
||||||
return (const char*)&file;
|
return (const char*)&file;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Prepare a buffer of peaks from /s/ to /e/ for reading. Must be
|
/** update the modification time of file referred to by /fd/ */
|
||||||
* called before any calls to operator[] */
|
static void
|
||||||
int
|
touch ( int fd )
|
||||||
Peaks::fill_buffer ( float fpp, nframes_t s, nframes_t e ) const
|
|
||||||
{
|
{
|
||||||
_fpp = fpp;
|
struct stat st;
|
||||||
|
|
||||||
return read_peaks( s, e, (e - s) / fpp, fpp );
|
fstat( fd, &st );
|
||||||
|
|
||||||
|
fchmod( fd, st.st_mode );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
nearest_power_of_two ( int v )
|
nearest_power_of_two ( int v )
|
||||||
{
|
{
|
||||||
|
@ -128,6 +103,30 @@ nearest_cached_chunksize ( nframes_t chunksize )
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Peaks::Peaks ( Audio_File *c )
|
||||||
|
{
|
||||||
|
_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, (e - s) / fpp, fpp );
|
||||||
|
}
|
||||||
|
|
||||||
struct peakfile_block_header
|
struct peakfile_block_header
|
||||||
{
|
{
|
||||||
unsigned long chunksize;
|
unsigned long chunksize;
|
||||||
|
@ -230,6 +229,7 @@ public:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DMESSAGE( "using peakfile block for chunksize %lu", _chunksize );
|
||||||
|
|
||||||
_offset = ftell( _fp );
|
_offset = ftell( _fp );
|
||||||
}
|
}
|
||||||
|
@ -364,11 +364,8 @@ public:
|
||||||
|
|
||||||
delete[] pbuf;
|
delete[] pbuf;
|
||||||
|
|
||||||
// close();
|
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -456,13 +453,10 @@ Peaks::read_source_peaks ( Peak *peaks, int npeaks, nframes_t chunksize ) const
|
||||||
int
|
int
|
||||||
Peaks::read_source_peaks ( Peak *peaks, nframes_t s, int npeaks, nframes_t chunksize ) const
|
Peaks::read_source_peaks ( Peak *peaks, nframes_t s, int npeaks, nframes_t chunksize ) const
|
||||||
{
|
{
|
||||||
// _clip->open();
|
|
||||||
_clip->seek( s );
|
_clip->seek( s );
|
||||||
|
|
||||||
int i = read_source_peaks( peaks, npeaks, chunksize );
|
int i = read_source_peaks( peaks, npeaks, chunksize );
|
||||||
|
|
||||||
// _clip->close();
|
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -481,8 +475,8 @@ Peaks::read_peaks ( nframes_t s, nframes_t e, int npeaks, nframes_t chunksize )
|
||||||
_peakbuf.offset = s;
|
_peakbuf.offset = s;
|
||||||
_peakbuf.buf->chunksize = chunksize;
|
_peakbuf.buf->chunksize = chunksize;
|
||||||
|
|
||||||
/* FIXME: compart to (minimum) peakfile chunk size */
|
/* FIXME: use actual minimum chunksize from peakfile! */
|
||||||
if ( chunksize < 256 )
|
if ( chunksize < 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 );
|
||||||
|
@ -490,13 +484,6 @@ Peaks::read_peaks ( nframes_t s, nframes_t e, int npeaks, nframes_t chunksize )
|
||||||
return _peakbuf.len;
|
return _peakbuf.len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: what purpose does this serve now? */
|
|
||||||
bool
|
|
||||||
Peaks::open ( void )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** returns false if peak file for /filename/ is out of date */
|
/** returns false if peak file for /filename/ is out of date */
|
||||||
bool
|
bool
|
||||||
Peaks::current ( void ) const
|
Peaks::current ( void ) const
|
||||||
|
@ -521,179 +508,11 @@ Peaks::current ( void ) const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
touch ( int fd )
|
|
||||||
{
|
|
||||||
struct stat st;
|
|
||||||
|
|
||||||
fstat( fd, &st );
|
|
||||||
|
|
||||||
fchmod( fd, st.st_mode );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* The Peak_Builder is for generating peaks from imported or updated sources, or when the
|
|
||||||
peakfile is simply missing */
|
|
||||||
|
|
||||||
class Peak_Builder
|
|
||||||
{
|
|
||||||
FILE *fp;
|
|
||||||
size_t last_block_pos;
|
|
||||||
const Peaks *_peaks;
|
|
||||||
|
|
||||||
void
|
|
||||||
write_block_header ( nframes_t chunksize )
|
|
||||||
{
|
|
||||||
if ( last_block_pos )
|
|
||||||
{
|
|
||||||
/* update previous block */
|
|
||||||
size_t pos = ftell( fp );
|
|
||||||
|
|
||||||
fseek( fp, last_block_pos - sizeof( peakfile_block_header ), SEEK_SET );
|
|
||||||
|
|
||||||
peakfile_block_header bh;
|
|
||||||
|
|
||||||
fread( &bh, sizeof( bh ), 1, fp );
|
|
||||||
|
|
||||||
fseek( fp, last_block_pos - sizeof( peakfile_block_header ), SEEK_SET );
|
|
||||||
// fseek( fp, 0 - sizeof( bh ), SEEK_CUR );
|
|
||||||
|
|
||||||
// DMESSAGE( "old block header: chunksize=%lu, skip=%lu", bh.chunksize, bh.skip );
|
|
||||||
|
|
||||||
bh.skip = pos - last_block_pos;
|
|
||||||
|
|
||||||
// DMESSAGE( "new block header: chunksize=%lu, skip=%lu", bh.chunksize, bh.skip );
|
|
||||||
|
|
||||||
fwrite( &bh, sizeof( bh ), 1, fp );
|
|
||||||
|
|
||||||
fseek( fp, pos, SEEK_SET );
|
|
||||||
}
|
|
||||||
|
|
||||||
peakfile_block_header bh;
|
|
||||||
|
|
||||||
bh.chunksize = chunksize;
|
|
||||||
bh.skip = 0;
|
|
||||||
|
|
||||||
fwrite( &bh, sizeof( bh ), 1, fp );
|
|
||||||
|
|
||||||
last_block_pos = ftell( fp );
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/** generate additional cache levels for a peakfile with only 1 block (ie. that of a new capture) */
|
|
||||||
bool
|
|
||||||
make_peaks_mipmap ( void )
|
|
||||||
{
|
|
||||||
if ( ! Peaks::mipmapped_peakfiles )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
Audio_File *_clip = _peaks->_clip;
|
|
||||||
|
|
||||||
const char *filename = _clip->name();
|
|
||||||
|
|
||||||
FILE *rfp;
|
|
||||||
|
|
||||||
last_block_pos = sizeof( peakfile_block_header );
|
|
||||||
|
|
||||||
/* open for reading */
|
|
||||||
rfp = fopen( peakname( filename ), "r" );
|
|
||||||
/* open the file again for appending */
|
|
||||||
fp = fopen( peakname( filename ), "r+" );
|
|
||||||
fseek( fp, 0, SEEK_END );
|
|
||||||
|
|
||||||
Peak buf[ _clip->channels() ];
|
|
||||||
|
|
||||||
/* now build the remaining peak levels, each based on the
|
|
||||||
* preceding level */
|
|
||||||
|
|
||||||
nframes_t cs = Peaks::cache_minimum << Peaks::cache_step;
|
|
||||||
for ( int i = 1; i < Peaks::cache_levels; ++i, cs <<= Peaks::cache_step )
|
|
||||||
{
|
|
||||||
DMESSAGE( "building level %d peak cache", i + 1 );
|
|
||||||
|
|
||||||
Peakfile pf;
|
|
||||||
|
|
||||||
/* open the peakfile for the previous cache level */
|
|
||||||
pf.open( rfp, _clip->channels(), cs >> Peaks::cache_step );
|
|
||||||
|
|
||||||
write_block_header( cs );
|
|
||||||
|
|
||||||
fflush( fp );
|
|
||||||
|
|
||||||
size_t len;
|
|
||||||
nframes_t s = 0;
|
|
||||||
do {
|
|
||||||
len = pf.read_peaks( buf, s, 1, cs );
|
|
||||||
s += cs;
|
|
||||||
|
|
||||||
fwrite( buf, sizeof( buf ), len, fp );
|
|
||||||
}
|
|
||||||
while ( len );
|
|
||||||
|
|
||||||
pf.leave_open();
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose( rfp );
|
|
||||||
fclose( fp );
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
make_peaks ( void )
|
|
||||||
{
|
|
||||||
Audio_File *_clip = _peaks->_clip;
|
|
||||||
|
|
||||||
const char *filename = _clip->name();
|
|
||||||
|
|
||||||
DMESSAGE( "building peaks for \"%s\"", filename );
|
|
||||||
|
|
||||||
FILE *rfp;
|
|
||||||
|
|
||||||
if ( ! ( fp = fopen( peakname( filename ), "w+" ) ) )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
_clip->seek( 0 );
|
|
||||||
|
|
||||||
Peak buf[ _clip->channels() ];
|
|
||||||
|
|
||||||
DMESSAGE( "building level 1 peak cache" );
|
|
||||||
|
|
||||||
write_block_header( Peaks::cache_minimum );
|
|
||||||
|
|
||||||
/* build first level from source */
|
|
||||||
size_t len;
|
|
||||||
do {
|
|
||||||
len = _peaks->read_source_peaks( buf, 1, Peaks::cache_minimum );
|
|
||||||
|
|
||||||
fwrite( buf, sizeof( buf ), len, fp );
|
|
||||||
}
|
|
||||||
while ( len );
|
|
||||||
|
|
||||||
/* reopen for reading */
|
|
||||||
fclose( fp );
|
|
||||||
|
|
||||||
make_peaks_mipmap();
|
|
||||||
|
|
||||||
DMESSAGE( "done building peaks" );
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Peak_Builder ( const Peaks *peaks ) : _peaks( peaks )
|
|
||||||
{
|
|
||||||
fp = NULL;
|
|
||||||
last_block_pos = 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Peaks::make_peaks ( void ) const
|
Peaks::make_peaks ( void ) const
|
||||||
{
|
{
|
||||||
Peak_Builder pb( this );
|
Peaks::Builder pb( this );
|
||||||
|
|
||||||
return pb.make_peaks();
|
return pb.make_peaks();
|
||||||
}
|
}
|
||||||
|
@ -701,7 +520,7 @@ Peaks::make_peaks ( void ) const
|
||||||
bool
|
bool
|
||||||
Peaks::make_peaks_mipmap ( void ) const
|
Peaks::make_peaks_mipmap ( void ) const
|
||||||
{
|
{
|
||||||
Peak_Builder pb( this );
|
Peaks::Builder pb( this );
|
||||||
|
|
||||||
return pb.make_peaks_mipmap();
|
return pb.make_peaks_mipmap();
|
||||||
}
|
}
|
||||||
|
@ -721,14 +540,13 @@ Peak::normalization_factor( void ) const
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* wrapper for peak writer */
|
/* wrapper for peak writer */
|
||||||
void
|
void
|
||||||
Peaks::prepare_for_writing ( void )
|
Peaks::prepare_for_writing ( void )
|
||||||
{
|
{
|
||||||
assert( ! _peak_writer );
|
assert( ! _peak_writer );
|
||||||
|
|
||||||
_peak_writer = new Peak_Writer( _clip->name(), cache_minimum, _clip->channels() );
|
_peak_writer = new Peaks::Streamer( _clip->name(), cache_minimum, _clip->channels() );
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -752,11 +570,17 @@ Peaks::write ( sample_t *buf, nframes_t nframes )
|
||||||
_peak_writer->write( buf, nframes );
|
_peak_writer->write( buf, nframes );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The Peak_Writer is for streaming peaks from audio buffers to disk
|
|
||||||
* while capturing. It works by accumulating a peak value across
|
|
||||||
* write() calls. */
|
|
||||||
|
|
||||||
Peak_Writer::Peak_Writer ( const char *filename, nframes_t chunksize, int channels )
|
/*
|
||||||
|
The Streamer is for streaming peaks from audio buffers to disk while
|
||||||
|
capturing. It works by accumulating a peak value across write()
|
||||||
|
calls. The Streamer can only generate peaks at a single
|
||||||
|
chunksize--additional cache levels must be appended after the
|
||||||
|
Streamer has finished.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Peaks::Streamer::Streamer ( const char *filename, nframes_t chunksize, int channels )
|
||||||
{
|
{
|
||||||
_channels = channels;
|
_channels = channels;
|
||||||
_chunksize = chunksize;
|
_chunksize = chunksize;
|
||||||
|
@ -778,7 +602,7 @@ Peak_Writer::Peak_Writer ( const char *filename, nframes_t chunksize, int channe
|
||||||
fflush( _fp );
|
fflush( _fp );
|
||||||
}
|
}
|
||||||
|
|
||||||
Peak_Writer::~Peak_Writer ( )
|
Peaks::Streamer::~Streamer ( )
|
||||||
{
|
{
|
||||||
touch( fileno( _fp ) );
|
touch( fileno( _fp ) );
|
||||||
|
|
||||||
|
@ -789,7 +613,7 @@ Peak_Writer::~Peak_Writer ( )
|
||||||
|
|
||||||
/** append peaks for samples in /buf/ to peakfile */
|
/** append peaks for samples in /buf/ to peakfile */
|
||||||
void
|
void
|
||||||
Peak_Writer::write ( sample_t *buf, nframes_t nframes )
|
Peaks::Streamer::write ( sample_t *buf, nframes_t nframes )
|
||||||
{
|
{
|
||||||
for ( ; nframes--; ++_index, buf += _channels )
|
for ( ; nframes--; ++_index, buf += _channels )
|
||||||
{
|
{
|
||||||
|
@ -811,3 +635,157 @@ Peak_Writer::write ( sample_t *buf, nframes_t nframes )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
The Builder is for generating peaks from imported or updated
|
||||||
|
sources, or when the peakfile is simply missing.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
Peaks::Builder::write_block_header ( nframes_t chunksize )
|
||||||
|
{
|
||||||
|
if ( last_block_pos )
|
||||||
|
{
|
||||||
|
/* update previous block */
|
||||||
|
size_t pos = ftell( fp );
|
||||||
|
|
||||||
|
fseek( fp, last_block_pos - sizeof( peakfile_block_header ), SEEK_SET );
|
||||||
|
|
||||||
|
peakfile_block_header bh;
|
||||||
|
|
||||||
|
fread( &bh, sizeof( bh ), 1, fp );
|
||||||
|
|
||||||
|
fseek( fp, last_block_pos - sizeof( peakfile_block_header ), SEEK_SET );
|
||||||
|
// fseek( fp, 0 - sizeof( bh ), SEEK_CUR );
|
||||||
|
|
||||||
|
// DMESSAGE( "old block header: chunksize=%lu, skip=%lu", bh.chunksize, bh.skip );
|
||||||
|
|
||||||
|
bh.skip = pos - last_block_pos;
|
||||||
|
|
||||||
|
// DMESSAGE( "new block header: chunksize=%lu, skip=%lu", bh.chunksize, bh.skip );
|
||||||
|
|
||||||
|
fwrite( &bh, sizeof( bh ), 1, fp );
|
||||||
|
|
||||||
|
fseek( fp, pos, SEEK_SET );
|
||||||
|
}
|
||||||
|
|
||||||
|
peakfile_block_header bh;
|
||||||
|
|
||||||
|
bh.chunksize = chunksize;
|
||||||
|
bh.skip = 0;
|
||||||
|
|
||||||
|
fwrite( &bh, sizeof( bh ), 1, fp );
|
||||||
|
|
||||||
|
last_block_pos = ftell( fp );
|
||||||
|
}
|
||||||
|
|
||||||
|
/** generate additional cache levels for a peakfile with only 1 block (ie. that of a new capture) */
|
||||||
|
bool
|
||||||
|
Peaks::Builder::make_peaks_mipmap ( void )
|
||||||
|
{
|
||||||
|
if ( ! Peaks::mipmapped_peakfiles )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
Audio_File *_clip = _peaks->_clip;
|
||||||
|
|
||||||
|
const char *filename = _clip->name();
|
||||||
|
|
||||||
|
FILE *rfp;
|
||||||
|
|
||||||
|
last_block_pos = sizeof( peakfile_block_header );
|
||||||
|
|
||||||
|
/* open for reading */
|
||||||
|
rfp = fopen( peakname( filename ), "r" );
|
||||||
|
/* open the file again for appending */
|
||||||
|
fp = fopen( peakname( filename ), "r+" );
|
||||||
|
fseek( fp, 0, SEEK_END );
|
||||||
|
|
||||||
|
Peak buf[ _clip->channels() ];
|
||||||
|
|
||||||
|
/* now build the remaining peak levels, each based on the
|
||||||
|
* preceding level */
|
||||||
|
|
||||||
|
nframes_t cs = Peaks::cache_minimum << Peaks::cache_step;
|
||||||
|
for ( int i = 1; i < Peaks::cache_levels; ++i, cs <<= Peaks::cache_step )
|
||||||
|
{
|
||||||
|
DMESSAGE( "building level %d peak cache", i + 1 );
|
||||||
|
|
||||||
|
Peakfile pf;
|
||||||
|
|
||||||
|
/* open the peakfile for the previous cache level */
|
||||||
|
pf.open( rfp, _clip->channels(), cs >> Peaks::cache_step );
|
||||||
|
|
||||||
|
write_block_header( cs );
|
||||||
|
|
||||||
|
fflush( fp );
|
||||||
|
|
||||||
|
size_t len;
|
||||||
|
nframes_t s = 0;
|
||||||
|
do {
|
||||||
|
len = pf.read_peaks( buf, s, 1, cs );
|
||||||
|
s += cs;
|
||||||
|
|
||||||
|
fwrite( buf, sizeof( buf ), len, fp );
|
||||||
|
}
|
||||||
|
while ( len );
|
||||||
|
|
||||||
|
pf.leave_open();
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose( rfp );
|
||||||
|
fclose( fp );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Peaks::Builder::make_peaks ( void )
|
||||||
|
{
|
||||||
|
Audio_File *_clip = _peaks->_clip;
|
||||||
|
|
||||||
|
const char *filename = _clip->name();
|
||||||
|
|
||||||
|
DMESSAGE( "building peaks for \"%s\"", filename );
|
||||||
|
|
||||||
|
FILE *rfp;
|
||||||
|
|
||||||
|
if ( ! ( fp = fopen( peakname( filename ), "w+" ) ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
_clip->seek( 0 );
|
||||||
|
|
||||||
|
Peak buf[ _clip->channels() ];
|
||||||
|
|
||||||
|
DMESSAGE( "building level 1 peak cache" );
|
||||||
|
|
||||||
|
write_block_header( Peaks::cache_minimum );
|
||||||
|
|
||||||
|
/* build first level from source */
|
||||||
|
size_t len;
|
||||||
|
do {
|
||||||
|
len = _peaks->read_source_peaks( buf, 1, Peaks::cache_minimum );
|
||||||
|
|
||||||
|
fwrite( buf, sizeof( buf ), len, fp );
|
||||||
|
}
|
||||||
|
while ( len );
|
||||||
|
|
||||||
|
/* reopen for reading */
|
||||||
|
fclose( fp );
|
||||||
|
|
||||||
|
make_peaks_mipmap();
|
||||||
|
|
||||||
|
DMESSAGE( "done building peaks" );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Peaks::Builder::Builder ( const Peaks *peaks ) : _peaks( peaks )
|
||||||
|
{
|
||||||
|
fp = NULL;
|
||||||
|
last_block_pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -30,8 +30,9 @@ struct Peak {
|
||||||
float normalization_factor ( void ) const;
|
float normalization_factor ( void ) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
class Audio_File;
|
class Audio_File;
|
||||||
class Peak_Writer;
|
|
||||||
|
|
||||||
class Peaks
|
class Peaks
|
||||||
{
|
{
|
||||||
|
@ -57,6 +58,44 @@ class Peaks
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Streamer
|
||||||
|
{
|
||||||
|
FILE *_fp;
|
||||||
|
Peak *_peak;
|
||||||
|
int _chunksize;
|
||||||
|
int _channels;
|
||||||
|
|
||||||
|
int _index;
|
||||||
|
|
||||||
|
/* not permitted */
|
||||||
|
Streamer ( const Streamer &rhs );
|
||||||
|
const Streamer &operator= ( const Streamer &rhs );
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Streamer ( const char *filename, nframes_t chunksize, int channels );
|
||||||
|
~Streamer ( );
|
||||||
|
|
||||||
|
void write ( sample_t *buf, nframes_t nframes );
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class Builder
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
size_t last_block_pos;
|
||||||
|
const Peaks *_peaks;
|
||||||
|
|
||||||
|
void write_block_header ( nframes_t chunksize );
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
bool make_peaks_mipmap ( void );
|
||||||
|
bool make_peaks ( void );
|
||||||
|
|
||||||
|
Builder ( const Peaks *peaks );
|
||||||
|
};
|
||||||
|
|
||||||
static peakbuffer _peakbuf;
|
static peakbuffer _peakbuf;
|
||||||
|
|
||||||
Audio_File *_clip;
|
Audio_File *_clip;
|
||||||
|
@ -68,16 +107,12 @@ class Peaks
|
||||||
int read_source_peaks ( Peak *peaks, int npeaks, nframes_t chunksize ) const;
|
int read_source_peaks ( Peak *peaks, int npeaks, nframes_t chunksize ) const;
|
||||||
int read_peakfile_peaks ( Peak *peaks, nframes_t s, int npeaks, nframes_t chunksize ) const;
|
int read_peakfile_peaks ( Peak *peaks, nframes_t s, int npeaks, nframes_t chunksize ) const;
|
||||||
|
|
||||||
Peak_Writer * volatile _peak_writer; /* exists when streaming peaks to disk */
|
Streamer * volatile _peak_writer; /* exists when streaming peaks to disk */
|
||||||
|
|
||||||
size_t last_block_pos; /* FIXME: only needed in make_peaks! */
|
|
||||||
|
|
||||||
/* not permitted */
|
/* not permitted */
|
||||||
Peaks ( const Peaks &rhs );
|
Peaks ( const Peaks &rhs );
|
||||||
const Peaks &operator= ( const Peaks &rhs );
|
const Peaks &operator= ( const Peaks &rhs );
|
||||||
|
|
||||||
friend class Peak_Builder;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
static bool mipmapped_peakfiles;
|
static bool mipmapped_peakfiles;
|
||||||
|
@ -97,7 +132,6 @@ 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;
|
void read ( int X, float *hi, float *lo ) const;
|
||||||
bool open ( void );
|
|
||||||
|
|
||||||
bool current ( void ) const;
|
bool current ( void ) const;
|
||||||
bool make_peaks ( void ) const;
|
bool make_peaks ( void ) const;
|
||||||
|
@ -107,27 +141,3 @@ public:
|
||||||
void finish_writing ( void );
|
void finish_writing ( void );
|
||||||
void write ( sample_t *buf, nframes_t nframes );
|
void write ( sample_t *buf, nframes_t nframes );
|
||||||
};
|
};
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
class Peak_Writer
|
|
||||||
{
|
|
||||||
FILE *_fp;
|
|
||||||
Peak *_peak;
|
|
||||||
int _chunksize;
|
|
||||||
int _channels;
|
|
||||||
|
|
||||||
int _index;
|
|
||||||
|
|
||||||
/* not permitted */
|
|
||||||
Peak_Writer ( const Peak_Writer &rhs );
|
|
||||||
const Peak_Writer &operator= ( const Peak_Writer &rhs );
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
Peak_Writer ( const char *filename, nframes_t chunksize, int channels );
|
|
||||||
~Peak_Writer ( );
|
|
||||||
|
|
||||||
void write ( sample_t *buf, nframes_t nframes );
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
Loading…
Reference in New Issue