Make normalization code work at all zoom levels.

This commit is contained in:
Jonathan Moore Liles 2008-02-17 21:37:26 -06:00
parent a032a95fad
commit 3b02169d31
9 changed files with 159 additions and 45 deletions

80
Clip.C
View File

@ -25,30 +25,94 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
Clip::Clip ( const char *filename ) : _peaks( this )
{
_filename = filename;
Clip::Clip ( void ) : _peaks( this )
{
_filename = NULL;
_length = 0;
}
/* Clip::Clip ( const char *filename ) : _peaks( this ) */
/* { */
/* _filename = filename; */
/* SNDFILE *in; */
/* SF_INFO si; */
/* memset( &si, 0, sizeof( si ) ); */
/* if ( ! ( in = sf_open( filename, SFM_READ, &si ) ) ) */
/* { */
/* printf( "couldn't open file\n" ); */
/* return; */
/* } */
/* if ( si.channels != 1 ) */
/* { */
/* printf( "error: incompatible format\n" ); */
/* return; */
/* } */
/* if ( si.samplerate != timeline.sample_rate ) */
/* { */
/* printf( "error: samplerate mismatch!\n" ); */
/* return; */
/* } */
/* _length = si.frames; */
/* sf_close( in ); */
/* _peaks.open(); */
/* } */
Clip *
Clip::from_file ( const char *filename )
{
SNDFILE *in; SNDFILE *in;
SF_INFO si; SF_INFO si;
Clip *c = NULL;
memset( &si, 0, sizeof( si ) ); memset( &si, 0, sizeof( si ) );
in = sf_open( filename, SFM_READ, &si ); if ( ! ( in = sf_open( filename, SFM_READ, &si ) ) )
{
printf( "couldn't open file\n" );
return NULL;
}
if ( si.channels != 1 ) if ( si.channels != 1 )
printf( "error: incompatible format" ); {
printf( "error: incompatible format\n" );
goto invalid;
}
if ( si.samplerate != timeline.sample_rate ) if ( si.samplerate != timeline.sample_rate )
{
printf( "error: samplerate mismatch!\n" ); printf( "error: samplerate mismatch!\n" );
goto invalid;
}
_length = si.frames; c = new Clip;
c->_filename = filename;
c->_length = si.frames;
sf_close( in ); sf_close( in );
_peaks.open(); c->_peaks.open();
}
return c;
invalid:
sf_close( in );
return NULL;
}
bool bool
Clip::open ( void ) Clip::open ( void )

6
Clip.H
View File

@ -38,7 +38,11 @@ class Clip
public: public:
Clip ( const char *filename ); Clip ( );
// Clip ( const char *filename );
static Clip *from_file ( const char *filename );
Peaks const * peaks ( void ) { return &_peaks; } Peaks const * peaks ( void ) { return &_peaks; }
const char *name ( void ) { return _filename; } const char *name ( void ) { return _filename; }

62
Peaks.C
View File

@ -35,6 +35,8 @@
#include "assert.h" #include "assert.h"
#include <math.h>
Peaks::peakbuffer Peaks::peakbuf; Peaks::peakbuffer Peaks::peakbuf;
@ -58,7 +60,7 @@ Peaks::fill_buffer ( int s, int e ) const
void void
Peaks::downsample ( int s, int e, float *mhi, float *mlo ) const Peaks::downsample ( Peak *peaks, int s, int e, float *mhi, float *mlo ) const
{ {
*mhi = 0; *mhi = 0;
*mlo = 0; *mlo = 0;
@ -68,8 +70,8 @@ Peaks::downsample ( int s, int e, float *mhi, float *mlo ) const
for ( int j = s; j < e; j++ ) for ( int j = s; j < e; j++ )
{ {
const float lo = _peaks->data[ j ].min; const float lo = peaks[ j ].min;
const float hi = _peaks->data[ j ].max; const float hi = peaks[ j ].max;
if ( hi > *mhi ) if ( hi > *mhi )
*mhi = hi; *mhi = hi;
@ -135,12 +137,9 @@ Peaks::read_peaks ( int s, int e, int npeaks, int chunksize ) const
_clip->close(); _clip->close();
} }
/** Return the peak for the range of samples */
/* virtual array. Index is a Pixel value, and it returns the
* (resampled) peaks for that pixel based on the current timeline
* zoom. */
Peak & Peak &
Peaks::operator[] ( int X ) const Peaks::peak ( nframes_t start, nframes_t end ) const
{ {
/* Is there a better way to return this? */ /* Is there a better way to return this? */
static Peak p; static Peak p;
@ -149,24 +148,36 @@ Peaks::operator[] ( int X ) const
{ {
assert( timeline.fpp == peakbuf.buf->chunksize ); assert( timeline.fpp == peakbuf.buf->chunksize );
int start = timeline.x_to_ts( X ) / peakbuf.buf->chunksize; start = (start - peakbuf.offset) / peakbuf.buf->chunksize;
int i = start - (peakbuf.offset / peakbuf.buf->chunksize); end = (end - peakbuf.offset) / peakbuf.buf->chunksize;
assert( peakbuf.len > i ); if ( end > peakbuf.len )
end = peakbuf.len;
p = peakbuf.buf->data[ i ]; // assert( peakbuf.len > start );
downsample( peakbuf.buf->data, start, end, &p.max, &p.min );
} }
else else
{ {
int start = timeline.x_to_ts( X ) / _peaks->chunksize; start /= _peaks->chunksize;
int end = timeline.x_to_ts( X + 1 ) / _peaks->chunksize; end /= _peaks->chunksize;
downsample( start, end, &p.max, &p.min ); downsample( _peaks->data, start, end, &p.max, &p.min );
} }
return p; return p;
} }
/* virtual array. Index is a Pixel value, and it returns the
* (resampled) peaks for that pixel based on the current timeline
* zoom. */
Peak &
Peaks::operator[] ( int X ) const
{
return peak( timeline.x_to_ts( X ), timeline.x_to_ts( X + 1 ) );
}
static static
const char * const char *
peakname ( const char *filename ) peakname ( const char *filename )
@ -271,3 +282,24 @@ Peaks::make_peaks ( int chunksize )
return true; return true;
} }
/** return normalization factor for range of samples from /start/ to
/end/ (uses known peak data if possible */
float
Peaks::normalization_factor( nframes_t start, nframes_t end ) const
{
float s;
fill_buffer( start, end );
Peak p = peak( start, end );
s = fabs( 1.0f / p.max );
if ( s * p.min < -1.0 )
s = 1 / fabs( p.max );
return s;
}

View File

@ -65,6 +65,8 @@ class Peaks
void read_peaks ( int s, int e, int npeaks, int chunksize ) const; void read_peaks ( int s, int e, int npeaks, int chunksize ) const;
int clip_read_peaks ( Peak *peaks, int npeaks, int chunksize ) const; int clip_read_peaks ( Peak *peaks, int npeaks, int chunksize ) const;
Peak & peak ( nframes_t start, nframes_t end ) const;
public: public:
Peaks ( Clip *c ) Peaks ( Clip *c )
@ -78,9 +80,10 @@ public:
void fill_buffer ( int s, int e ) const; void fill_buffer ( int s, int e ) const;
void downsample ( int s, int e, float *mhi, float *mlo ) const; void downsample ( Peak *peaks, int s, int e, float *mhi, float *mlo ) const;
void read ( int X, float *hi, float *lo ) const; void read ( int X, float *hi, float *lo ) const;
bool open ( void ); bool open ( void );
float normalization_factor( nframes_t start, nframes_t end ) const;
bool current ( void ) const; bool current ( void ) const;
bool make_peaks ( int chunksize ); bool make_peaks ( int chunksize );

View File

@ -250,8 +250,10 @@ Region::draw ( void )
/* fl_color( FL_RED ); */ /* fl_color( FL_RED ); */
/* fl_line( x() - timeline.ts_to_x( _start ), y(), x() - timeline.ts_to_x( _start ), y() + h() ); */ /* int sx = x() - timeline.ts_to_x( _start ); */
/* fl_line( x() + w() - _end, y(), x() + w() - _end, y() + h() ); */ /* fl_line( sx, y(), sx, y() + h() ); */
/* int ex = x() + timeline.ts_to_x( _end - _start ); */
/* fl_line( ex, y(), ex, y() + h() ); */
draw_label(); draw_label();

26
Track.H
View File

@ -92,16 +92,30 @@ public:
return 1; return 1;
case FL_PASTE: case FL_PASTE:
{ {
const char *file, *text = Fl::event_text(); const char *text = Fl::event_text();
if ( ! strncmp( text, "file://", 7 ) ) char *file;
file = text + 7;
else if ( ! sscanf( text, "file://%a[^\r\n]\n", &file ) )
// error? {
file = text; printf( "invalid drop \"%s\"\n", text );
return 0;
}
printf( "pasted file \"%s\"\n", file ); printf( "pasted file \"%s\"\n", file );
Clip *c = Clip::from_file( file );
// free( file );
if ( ! c )
{
free( file );
return 0;
}
this->add( new Region( c ) );
return 1; return 1;
} }
default: default:

View File

@ -141,20 +141,12 @@ Waveform::draw ( int X, int Y, int W, int H )
fl_pop_clip(); fl_pop_clip();
} }
void void
Waveform::normalize ( void ) Waveform::normalize ( void )
{ {
float mhi, mlo; printf( "normalize: start=%lu end=%lu\n", _start, _end );
_clip->peaks()->downsample( _start, _end, &mhi, &mlo ); _scale = _clip->peaks()->normalization_factor( _start, _end );
_scale = 1.0f / (float)mhi;
if ( _scale * mlo < -1.0 )
_scale = 1 / fabs( mlo );
_scale = fabs( _scale );
redraw(); redraw();
} }

View File

@ -69,6 +69,9 @@ public:
void start ( nframes_t s ) { _start = s; } void start ( nframes_t s ) { _start = s; }
void end ( nframes_t e ) { _end = e; } void end ( nframes_t e ) { _end = e; }
void scale ( float s ) { _scale = s; }
float scale ( void ) { return _scale; }
// void peaks ( float *p ) { _peaks = p; } // void peaks ( float *p ) { _peaks = p; }
void normalize ( void ); void normalize ( void );

4
main.C
View File

@ -103,7 +103,7 @@ main ( int argc, char **argv )
// Region *wave = new Region( 0, 0, 5000, 100, "foo" ); // Region *wave = new Region( 0, 0, 5000, 100, "foo" );
Region *wave = new Region( new Clip( "streambass8.wav" ) ); Region *wave = new Region( Clip::from_file( "streambass8.wav" ) );
// wave->resize( 0, 0, 500, 100 ); // wave->resize( 0, 0, 500, 100 );
@ -141,7 +141,7 @@ main ( int argc, char **argv )
timeline.scroll->end(); timeline.scroll->end();
Fl_Slider *zoom_slider = new Fl_Slider( 0, 0, 800, 24 ); Fl_Slider *zoom_slider = new Fl_Slider( 0, 0, 800, 24 );
zoom_slider->type( 1 ); zoom_slider->type( FL_HOR_SLIDER );
zoom_slider->callback( cb_zoom, 0 ); zoom_slider->callback( cb_zoom, 0 );
zoom_slider->range( 2, 4096 ); zoom_slider->range( 2, 4096 );
zoom_slider->step( 1 ); zoom_slider->step( 1 );