Fix mipmapping for streamed peaks.

This commit is contained in:
Jonathan Moore Liles 2008-05-11 17:48:19 -05:00
parent 12d65acf25
commit 50fa642321
6 changed files with 82 additions and 36 deletions

View File

@ -35,6 +35,7 @@ class Audio_File
{
static std::map <std::string, Audio_File*> _open_files;
/* not permitted */
Audio_File ( const Audio_File &rhs );
const Audio_File & operator= ( const Audio_File &rhs );
@ -48,7 +49,7 @@ protected:
};
const char *_filename;
nframes_t _length; /* length of file in samples */
volatile nframes_t _length; /* length of file in samples */
nframes_t _samplerate; /* sample rate */
int _channels;
@ -70,6 +71,7 @@ public:
Audio_File ( ) : _peaks( this )
{
_filename = NULL;
_samplerate = 0;
_length = _channels = 0;
}

View File

@ -109,7 +109,6 @@ Audio_File_SF::create ( const char *filename, nframes_t samplerate, int channels
char *name;
asprintf( &name, "%s.%s", filename, fd->extension );
// if ( ! ( out = sf_open( name, SFM_RDWR, &si ) ) )
if ( ! ( out = sf_open( name, SFM_WRITE, &si ) ) )
{
printf( "couldn't create soundfile.\n" );

View File

@ -31,6 +31,12 @@ class Audio_File_SF : public Audio_File
* enough to do this for us */
nframes_t _current_read;
Audio_File_SF ( )
{
_in = 0;
_current_read = 0;
}
public:
static const Audio_File::format_desc supported_formats[];
@ -38,6 +44,7 @@ public:
static Audio_File_SF *from_file ( const char *filename );
static Audio_File_SF *create ( const char *filename, nframes_t samplerate, int channels, const char *format );
~Audio_File_SF ( )
{
/* stupid C++ */

View File

@ -840,7 +840,8 @@ Audio_Region::write ( nframes_t nframes )
{
nframes_t oldl = _clip->length();
/* FIXME: hack */
/* 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();
@ -858,6 +859,7 @@ Audio_Region::write ( nframes_t nframes )
return nframes;
}
/* THREAD: IO */
/** finalize region capture. Assumes that this *is* a captured region
and that no other regions refer to the same source */
bool
@ -865,11 +867,11 @@ Audio_Region::finalize ( nframes_t frame )
{
log_end();
_clip->finalize();
_clip->close();
_clip->open();
_clip->finalize();
/* FIXME: should we attempt to truncate the file? */
_range.length = frame - _range.start - _range.offset;

View File

@ -140,7 +140,6 @@ class Peakfile
nframes_t _chunksize;
int _channels; /* number of channels this peakfile represents */
nframes_t _length; /* length, in frames, of the clip this peakfile represents */
const char *_name;
size_t _offset;
int _blocks;
@ -169,7 +168,6 @@ public:
_offset = 0;
_chunksize = 0;
_channels = 0;
_name =NULL;
}
~Peakfile ( )
@ -195,11 +193,14 @@ public:
fread( &bh, sizeof( bh ), 1, _fp );
// printf( "chunksize=%lu, skip=%lu\n", (unsigned long)bh.chunksize, (unsigned long) bh.skip );
ASSERT( bh.chunksize, "Invalid peak file structure!" );
blocks.push_back( block_descriptor( bh.chunksize, ftell( _fp ) ) );
if ( ! bh.skip )
/* last block */
break;
if ( fseek( _fp, bh.skip, SEEK_CUR ) )
@ -265,11 +266,10 @@ public:
/** given soundfile name /name/, try to open the best peakfile for /chunksize/ */
bool
open ( const char *name, nframes_t chunksize, int channels )
open ( const char *name, int channels, nframes_t chunksize )
{
_chunksize = 0;
_channels = channels;
_name = name;
if ( ! ( _fp = fopen( peakname( name ), "r" ) ) )
return false;
@ -311,7 +311,7 @@ public:
* channels. Place the result in buffer /peaks/, which must be
* large enough to fit the entire request. Returns the number of
* peaks actually read, which may be fewer than were requested. */
int
nframes_t
read_peaks ( Peak *peaks, nframes_t s, int npeaks, nframes_t chunksize )
{
if ( ! _fp )
@ -320,22 +320,18 @@ public:
const unsigned int ratio = chunksize / _chunksize;
/* 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? */
return 0;
if ( ratio == 1 )
{
int len = fread( peaks, sizeof( Peak ) * _channels, npeaks, _fp );
// close;
return len;
}
return fread( peaks, sizeof( Peak ) * _channels, npeaks, _fp );
Peak *pbuf = new Peak[ ratio * _channels ];
size_t len = 0;
nframes_t len = 0;
int i;
nframes_t i;
for ( i = 0; i < npeaks; ++i )
{
/* read in a buffer */
@ -378,7 +374,7 @@ Peaks::ready ( nframes_t s, int npeaks, nframes_t chunksize ) const
{
Peakfile _peakfile;
if ( ! _peakfile.open( _clip->name(), chunksize, _clip->channels() ) )
if ( ! _peakfile.open( _clip->name(), _clip->channels(), chunksize ) )
return false;
return _peakfile.ready( s, npeaks );
@ -391,7 +387,7 @@ Peaks::read_peakfile_peaks ( Peak *peaks, nframes_t s, int npeaks, nframes_t chu
nframes_t ncc = nearest_cached_chunksize( chunksize );
/* never try to build peaks while recording */
if ( ! ( _peak_writer || transport->recording ) )
if ( ! transport->recording )
{
if ( ! current() )
/* Build peaks asyncronously */
@ -403,7 +399,7 @@ Peaks::read_peakfile_peaks ( Peak *peaks, nframes_t s, int npeaks, nframes_t chu
Peakfile _peakfile;
if ( ! _peakfile.open( _clip->name(), chunksize, _clip->channels() ) )
if ( ! _peakfile.open( _clip->name(), _clip->channels(), chunksize ) )
return 0;
/* else if ( ! _peakfile.contains( s, npeaks ) ) */
@ -556,15 +552,17 @@ Peak::normalization_factor( void ) const
return s;
}
/* THREAD: IO */
/* wrapper for peak writer */
void
Peaks::prepare_for_writing ( void )
{
assert( ! _peak_writer );
_peak_writer = new Peaks::Streamer( _clip->name(), cache_minimum, _clip->channels() );
_peak_writer = new Peaks::Streamer( _clip->name(), _clip->channels(), cache_minimum );
}
/* THREAD: IO */
void
Peaks::finish_writing ( void )
{
@ -575,11 +573,14 @@ Peaks::finish_writing ( void )
}
/* now fill in the rest of the cache */
make_peaks_mipmap();
/* if ( ! fork() ) */
/* exit( make_peaks_mipmap() ); */
if ( ! fork() )
exit( make_peaks_mipmap() );
}
/* THREAD: IO */
void
Peaks::write ( sample_t *buf, nframes_t nframes )
{
@ -596,17 +597,20 @@ Peaks::write ( sample_t *buf, nframes_t nframes )
Streamer has finished.
*/
Peaks::Streamer::Streamer ( const char *filename, nframes_t chunksize, int channels )
Peaks::Streamer::Streamer ( const char *filename, int channels, nframes_t chunksize )
{
_channels = channels;
_chunksize = chunksize;
_index = 0;
_fp = NULL;
_peak = new Peak[ channels ];
memset( _peak, 0, sizeof( Peak ) * channels );
if ( ! ( _fp = fopen( peakname( filename ), "w" ) ) )
/* error! */;
{
WARNING( "could not open peakfile for streaming." );
}
peakfile_block_header bh;
@ -620,6 +624,10 @@ Peaks::Streamer::Streamer ( const char *filename, nframes_t chunksize, int chann
Peaks::Streamer::~Streamer ( )
{
fwrite( _peak, sizeof( Peak ) * _channels, 1, _fp );
fflush( _fp );
touch( fileno( _fp ) );
fclose( _fp );
@ -645,7 +653,11 @@ Peaks::Streamer::write ( sample_t *buf, nframes_t nframes )
if ( _index == _chunksize - 1 )
{
fwrite( _peak, sizeof( Peak ), _channels, _fp );
fwrite( _peak, sizeof( Peak ) * _channels, 1, _fp );
/* FIXME: why the hell is this necessary? */
fflush( _fp );
memset( _peak, 0, sizeof( Peak ) * _channels );
_index = 0;
}
@ -676,11 +688,13 @@ Peaks::Builder::write_block_header ( nframes_t chunksize )
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 );
// 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 );
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 );
fwrite( &bh, sizeof( bh ), 1, fp );
@ -712,13 +726,27 @@ Peaks::Builder::make_peaks_mipmap ( void )
FILE *rfp;
rfp = fopen( peakname( filename ), "r" );
last_block_pos = sizeof( peakfile_block_header );
/* open for reading */
rfp = fopen( peakname( filename ), "r" );
// rfp = fopen( peakname( filename ), "r" );
/* open the file again for appending */
fp = fopen( peakname( filename ), "r+" );
fseek( fp, 0, SEEK_END );
if ( ! ( fp = fopen( peakname( filename ), "r+" ) ) )
{
WARNING( "could not open peakfile for appending." );
return false;
}
if ( fseek( fp, 0, SEEK_END ) )
FATAL( "error performing seek: %s", strerror( errno ) );
if ( ftell( fp ) == sizeof( peakfile_block_header ) )
{
DWARNING( "truncated peakfile. Programming error?" );
return false;
}
Peak buf[ _clip->channels() ];
@ -730,11 +758,22 @@ Peaks::Builder::make_peaks_mipmap ( void )
{
DMESSAGE( "building level %d peak cache", i + 1 );
DMESSAGE( "%lu", _clip->length() / cs );
if ( _clip->length() / cs < 1 )
{
DMESSAGE( "source not long enough for any peaks at chunksize %lu", cs );
break;
}
Peakfile pf;
/* open the peakfile for the previous cache level */
pf.open( rfp, _clip->channels(), cs >> Peaks::cache_step );
// pf.open( _clip->name(), _clip->channels(), cs >> Peaks::cache_step );
write_block_header( cs );
size_t len;
@ -765,8 +804,6 @@ Peaks::Builder::make_peaks ( void )
DMESSAGE( "building peaks for \"%s\"", filename );
FILE *rfp;
if ( ! ( fp = fopen( peakname( filename ), "w+" ) ) )
return false;

View File

@ -64,7 +64,6 @@ class Peaks
Peak *_peak;
int _chunksize;
int _channels;
int _index;
/* not permitted */
@ -73,7 +72,7 @@ class Peaks
public:
Streamer ( const char *filename, nframes_t chunksize, int channels );
Streamer ( const char *filename, int channels, nframes_t chunksize );
~Streamer ( );
void write ( sample_t *buf, nframes_t nframes );