Browse Source

Make normalization code work at all zoom levels.

tags/non-daw-v1.1.0
Jonathan Moore Liles 17 years ago
parent
commit
3b02169d31
9 changed files with 158 additions and 44 deletions
  1. +71
    -7
      Clip.C
  2. +5
    -1
      Clip.H
  3. +47
    -15
      Peaks.C
  4. +4
    -1
      Peaks.H
  5. +4
    -2
      Region.C
  6. +20
    -6
      Track.H
  7. +2
    -10
      Waveform.C
  8. +3
    -0
      Waveform.H
  9. +2
    -2
      main.C

+ 71
- 7
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 )

Clip::Clip ( void ) : _peaks( this )
{ {
_filename = filename;
_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;
}

c = new Clip;


_length = si.frames;
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 )


+ 5
- 1
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; }


+ 47
- 15
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 hi = _peaks->data[ j ].max;
const float lo = peaks[ j ].min;
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();
} }



/* virtual array. Index is a Pixel value, and it returns the
* (resampled) peaks for that pixel based on the current timeline
* zoom. */
/** Return the peak for the range of samples */
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;
int i = start - (peakbuf.offset / peakbuf.buf->chunksize);
start = (start - peakbuf.offset) / peakbuf.buf->chunksize;
end = (end - peakbuf.offset) / peakbuf.buf->chunksize;

if ( end > peakbuf.len )
end = peakbuf.len;


assert( peakbuf.len > i );
// assert( peakbuf.len > start );


p = peakbuf.buf->data[ i ];
downsample( peakbuf.buf->data, start, end, &p.max, &p.min );
} }
else else
{ {
int start = timeline.x_to_ts( X ) / _peaks->chunksize;
int end = timeline.x_to_ts( X + 1 ) / _peaks->chunksize;
start /= _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;
}

+ 4
- 1
Peaks.H 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 );


+ 4
- 2
Region.C 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() ); */
/* fl_line( x() + w() - _end, y(), x() + w() - _end, y() + h() ); */
/* int sx = x() - timeline.ts_to_x( _start ); */
/* 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();




+ 20
- 6
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 ) )
file = text + 7;
else
// error?
file = text;
char *file;

if ( ! sscanf( text, "file://%a[^\r\n]\n", &file ) )
{
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:


+ 2
- 10
Waveform.C 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;

_clip->peaks()->downsample( _start, _end, &mhi, &mlo );

_scale = 1.0f / (float)mhi;

if ( _scale * mlo < -1.0 )
_scale = 1 / fabs( mlo );
printf( "normalize: start=%lu end=%lu\n", _start, _end );


_scale = fabs( _scale );
_scale = _clip->peaks()->normalization_factor( _start, _end );


redraw(); redraw();
} }

+ 3
- 0
Waveform.H 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 );




+ 2
- 2
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 );


Loading…
Cancel
Save