Skip to content

Commit

Permalink
Add --precise to compensate for audio start being truncated to sample
Browse files Browse the repository at this point in the history
The starting time for  audio read for a pixel column is truncated to an
integer (a sample number) which introduces a semi-random time jitter of
up to one sample period and making the actual start time up to one sample
period earlier than requested. This patch tries to compensate for that by
linear interpolation between each sample and the following one.
  • Loading branch information
martinwguy committed Dec 12, 2015
1 parent 9ca5867 commit 2f57eb7
Showing 1 changed file with 38 additions and 2 deletions.
40 changes: 38 additions & 2 deletions src/spectrogram.c
Expand Up @@ -34,6 +34,7 @@
#include <stdbool.h>
#include <math.h>
#include <limits.h>
#include <assert.h>

#include <cairo.h>
#include <fftw3.h>
Expand Down Expand Up @@ -65,6 +66,11 @@ typedef struct
double spec_floor_db ;
} RENDER ;

/* Interpolate between samples to eliminate the
* 1-sample-period jitter due to time quantization?
*/
static bool precise_timing = 0;

typedef struct
{ int left, top, width, height ;
} RECT ;
Expand Down Expand Up @@ -157,11 +163,17 @@ static void
read_mono_audio (SNDFILE * file, sf_count_t filelen, double * data, int datalen, int indx, int total)
{
sf_count_t start ;
double error ; /* How much "start" is wrong by
* (start == exact_value_of_start + error) */
sf_count_t k;

memset (data, 0, datalen * sizeof (data [0])) ;

start = (indx * filelen) / total - datalen / 2 ;

error = start - (((double)indx * filelen) / total - datalen / 2.0) ;
assert (-1.0 < error && error <= 0.0) ;

if (start >= 0)
sf_seek (file, start, SEEK_SET) ;
else
Expand All @@ -171,7 +183,23 @@ read_mono_audio (SNDFILE * file, sf_count_t filelen, double * data, int datalen,
datalen -= start ;
} ;

sfx_mix_mono_read_double (file, data, datalen) ;
sfx_mix_mono_read_double (file, data, datalen+(precise_timing?1:0)) ;

/* The starting time is truncated to a sample boundary and is slighty
* earlier that the exact starting time.
* We compensate by reading in one more sample than this and
* interpolating between each sample and the following one.
*/
if ( precise_timing && error != 0.0 )
{
/* Proportion to take of this sample and of the following one.
* this + next == 1.0
*/
double this = 1.0 + error, next = -error ;

for (k=0; k < datalen; k++)
data[k] = data[k]*this + data[k+1]*next;
}

return ;
} /* read_mono_audio */
Expand Down Expand Up @@ -589,7 +617,9 @@ render_to_surface (const RENDER * render, SNDFILE *infile, int samplerate, sf_co
}
}

time_domain = calloc (2 * speclen, sizeof (double)) ;
/* + 1 because with --precise, read_mono_audio reads the following
* sample and interpolates to get the starting moment exact. */
time_domain = calloc ((2 * speclen + 1), sizeof (double)) ;
freq_domain = calloc (2 * speclen, sizeof (double)) ;
single_mag_spec = calloc (speclen, sizeof (double)) ;
mag_spec = calloc (width, sizeof (float *)) ;
Expand Down Expand Up @@ -738,6 +768,7 @@ usage_exit (const char * argv0, int error)
" --kaiser : Use a Kaiser window function (the default)\n"
" --nuttall : Use a Nuttall window function\n"
" --hann : Use a Hann window function\n"
" --precise : Interpolate between samples for precise timing\n"
) ;

exit (error) ;
Expand Down Expand Up @@ -795,6 +826,11 @@ main (int argc, char * argv [])
continue ;
} ;

if (strcmp (argv [k], "--precise") == 0)
{ precise_timing = 1;
continue ;
} ;

printf ("\nError : Bad command line argument '%s'\n", argv [k]) ;
usage_exit (argv [0], 1) ;
} ;
Expand Down

0 comments on commit 2f57eb7

Please sign in to comment.