Browse Source

Fix mipmapping for streamed peaks.

tags/non-daw-v1.1.0
Jonathan Moore Liles 17 years ago
parent
commit
50fa642321
6 changed files with 82 additions and 36 deletions
  1. +3
    -1
      Timeline/Audio_File.H
  2. +0
    -1
      Timeline/Audio_File_SF.C
  3. +7
    -0
      Timeline/Audio_File_SF.H
  4. +5
    -3
      Timeline/Audio_Region.C
  5. +66
    -29
      Timeline/Peaks.C
  6. +1
    -2
      Timeline/Peaks.H

+ 3
- 1
Timeline/Audio_File.H View File

@@ -35,6 +35,7 @@ class Audio_File
{ {
static std::map <std::string, Audio_File*> _open_files; static std::map <std::string, Audio_File*> _open_files;


/* not permitted */
Audio_File ( const Audio_File &rhs ); Audio_File ( const Audio_File &rhs );
const Audio_File & operator= ( const Audio_File &rhs ); const Audio_File & operator= ( const Audio_File &rhs );


@@ -48,7 +49,7 @@ protected:
}; };


const char *_filename; 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 */ nframes_t _samplerate; /* sample rate */
int _channels; int _channels;


@@ -70,6 +71,7 @@ public:
Audio_File ( ) : _peaks( this ) Audio_File ( ) : _peaks( this )
{ {
_filename = NULL; _filename = NULL;
_samplerate = 0;
_length = _channels = 0; _length = _channels = 0;
} }




+ 0
- 1
Timeline/Audio_File_SF.C View File

@@ -109,7 +109,6 @@ 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( name, SFM_RDWR, &si ) ) )
if ( ! ( out = sf_open( name, SFM_WRITE, &si ) ) ) if ( ! ( out = sf_open( name, SFM_WRITE, &si ) ) )
{ {
printf( "couldn't create soundfile.\n" ); printf( "couldn't create soundfile.\n" );


+ 7
- 0
Timeline/Audio_File_SF.H View File

@@ -31,6 +31,12 @@ class Audio_File_SF : public Audio_File
* enough to do this for us */ * enough to do this for us */
nframes_t _current_read; nframes_t _current_read;


Audio_File_SF ( )
{
_in = 0;
_current_read = 0;
}

public: public:


static const Audio_File::format_desc supported_formats[]; 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 *from_file ( const char *filename );
static Audio_File_SF *create ( const char *filename, nframes_t samplerate, int channels, const char *format ); static Audio_File_SF *create ( const char *filename, nframes_t samplerate, int channels, const char *format );



~Audio_File_SF ( ) ~Audio_File_SF ( )
{ {
/* stupid C++ */ /* stupid C++ */


+ 5
- 3
Timeline/Audio_Region.C View File

@@ -840,7 +840,8 @@ Audio_Region::write ( nframes_t nframes )
{ {
nframes_t oldl = _clip->length(); 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->close();
_clip->open(); _clip->open();


@@ -858,6 +859,7 @@ Audio_Region::write ( nframes_t nframes )
return nframes; return nframes;
} }


/* THREAD: IO */
/** finalize region capture. Assumes that this *is* a captured region /** finalize region capture. Assumes that this *is* a captured region
and that no other regions refer to the same source */ and that no other regions refer to the same source */
bool bool
@@ -865,11 +867,11 @@ Audio_Region::finalize ( nframes_t frame )
{ {
log_end(); log_end();


_clip->finalize();

_clip->close(); _clip->close();
_clip->open(); _clip->open();


_clip->finalize();

/* FIXME: should we attempt to truncate the file? */ /* FIXME: should we attempt to truncate the file? */


_range.length = frame - _range.start - _range.offset; _range.length = frame - _range.start - _range.offset;


+ 66
- 29
Timeline/Peaks.C View File

@@ -140,7 +140,6 @@ 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 */
const char *_name;
size_t _offset; size_t _offset;
int _blocks; int _blocks;


@@ -169,7 +168,6 @@ public:
_offset = 0; _offset = 0;
_chunksize = 0; _chunksize = 0;
_channels = 0; _channels = 0;
_name =NULL;
} }


~Peakfile ( ) ~Peakfile ( )
@@ -195,11 +193,14 @@ public:


fread( &bh, sizeof( bh ), 1, _fp ); 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!" ); ASSERT( bh.chunksize, "Invalid peak file structure!" );


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


if ( ! bh.skip ) if ( ! bh.skip )
/* last block */
break; break;


if ( fseek( _fp, bh.skip, SEEK_CUR ) ) if ( fseek( _fp, bh.skip, SEEK_CUR ) )
@@ -265,11 +266,10 @@ public:


/** given soundfile name /name/, try to open the best peakfile for /chunksize/ */ /** given soundfile name /name/, try to open the best peakfile for /chunksize/ */
bool bool
open ( const char *name, nframes_t chunksize, int channels )
open ( const char *name, int channels, nframes_t chunksize )
{ {
_chunksize = 0; _chunksize = 0;
_channels = channels; _channels = channels;
_name = name;


if ( ! ( _fp = fopen( peakname( name ), "r" ) ) ) if ( ! ( _fp = fopen( peakname( name ), "r" ) ) )
return false; return false;
@@ -311,7 +311,7 @@ public:
* channels. Place the result in buffer /peaks/, which must be * channels. Place the result in buffer /peaks/, which must be
* 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. */
int
nframes_t
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 )
@@ -320,22 +320,18 @@ 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 ( fseek( _fp, _offset + ( frame_to_peak( s ) * sizeof( Peak ) ), SEEK_SET ) )
/* failed to seek... peaks not ready? */ /* failed to seek... peaks not ready? */
return 0; return 0;


if ( ratio == 1 ) 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 ]; 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 ) for ( i = 0; i < npeaks; ++i )
{ {
/* read in a buffer */ /* read in a buffer */
@@ -378,7 +374,7 @@ Peaks::ready ( nframes_t s, int npeaks, nframes_t chunksize ) const
{ {
Peakfile _peakfile; Peakfile _peakfile;


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


return _peakfile.ready( s, npeaks ); 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 ); nframes_t ncc = nearest_cached_chunksize( chunksize );


/* never try to build peaks while recording */ /* never try to build peaks while recording */
if ( ! ( _peak_writer || transport->recording ) )
if ( ! transport->recording )
{ {
if ( ! current() ) if ( ! current() )
/* Build peaks asyncronously */ /* Build peaks asyncronously */
@@ -403,7 +399,7 @@ Peaks::read_peakfile_peaks ( Peak *peaks, nframes_t s, int npeaks, nframes_t chu


Peakfile _peakfile; Peakfile _peakfile;


if ( ! _peakfile.open( _clip->name(), chunksize, _clip->channels() ) )
if ( ! _peakfile.open( _clip->name(), _clip->channels(), chunksize ) )
return 0; return 0;


/* else if ( ! _peakfile.contains( s, npeaks ) ) */ /* else if ( ! _peakfile.contains( s, npeaks ) ) */
@@ -556,15 +552,17 @@ Peak::normalization_factor( void ) const
return s; return s;
} }


/* THREAD: IO */
/* 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 Peaks::Streamer( _clip->name(), cache_minimum, _clip->channels() );
_peak_writer = new Peaks::Streamer( _clip->name(), _clip->channels(), cache_minimum );
} }


/* THREAD: IO */
void void
Peaks::finish_writing ( void ) Peaks::finish_writing ( void )
{ {
@@ -575,11 +573,14 @@ Peaks::finish_writing ( void )
} }


/* now fill in the rest of the cache */ /* 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 void
Peaks::write ( sample_t *buf, nframes_t nframes ) Peaks::write ( sample_t *buf, nframes_t nframes )
{ {
@@ -596,17 +597,20 @@ Peaks::write ( sample_t *buf, nframes_t nframes )
Streamer has finished. 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; _channels = channels;
_chunksize = chunksize; _chunksize = chunksize;
_index = 0; _index = 0;
_fp = NULL;


_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( peakname( filename ), "w" ) ) )
/* error! */;
{
WARNING( "could not open peakfile for streaming." );
}


peakfile_block_header bh; peakfile_block_header bh;


@@ -620,6 +624,10 @@ Peaks::Streamer::Streamer ( const char *filename, nframes_t chunksize, int chann


Peaks::Streamer::~Streamer ( ) Peaks::Streamer::~Streamer ( )
{ {
fwrite( _peak, sizeof( Peak ) * _channels, 1, _fp );

fflush( _fp );

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


fclose( _fp ); fclose( _fp );
@@ -645,7 +653,11 @@ Peaks::Streamer::write ( sample_t *buf, nframes_t nframes )


if ( _index == _chunksize - 1 ) 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 ); memset( _peak, 0, sizeof( Peak ) * _channels );
_index = 0; _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, 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", bh.chunksize, bh.skip );


bh.skip = pos - last_block_pos; 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 ); fwrite( &bh, sizeof( bh ), 1, fp );


@@ -712,13 +726,27 @@ Peaks::Builder::make_peaks_mipmap ( void )


FILE *rfp; FILE *rfp;


rfp = fopen( peakname( filename ), "r" );

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 */
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() ]; Peak buf[ _clip->channels() ];


@@ -730,11 +758,22 @@ Peaks::Builder::make_peaks_mipmap ( void )
{ {
DMESSAGE( "building level %d peak cache", i + 1 ); 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; 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->name(), _clip->channels(), cs >> Peaks::cache_step );

write_block_header( cs ); write_block_header( cs );


size_t len; size_t len;
@@ -765,8 +804,6 @@ Peaks::Builder::make_peaks ( void )


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


FILE *rfp;

if ( ! ( fp = fopen( peakname( filename ), "w+" ) ) ) if ( ! ( fp = fopen( peakname( filename ), "w+" ) ) )
return false; return false;




+ 1
- 2
Timeline/Peaks.H View File

@@ -64,7 +64,6 @@ class Peaks
Peak *_peak; Peak *_peak;
int _chunksize; int _chunksize;
int _channels; int _channels;

int _index; int _index;


/* not permitted */ /* not permitted */
@@ -73,7 +72,7 @@ class Peaks


public: public:


Streamer ( const char *filename, nframes_t chunksize, int channels );
Streamer ( const char *filename, int channels, nframes_t chunksize );
~Streamer ( ); ~Streamer ( );


void write ( sample_t *buf, nframes_t nframes ); void write ( sample_t *buf, nframes_t nframes );


Loading…
Cancel
Save