|
Packit |
c32a2d |
/*
|
|
Packit |
c32a2d |
waves: some oscillators, for fun
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
copyright 2017 by the mpg123 project, license: LGPL 2.1
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
This code does not care about efficiency constructing the period buffer,
|
|
Packit |
c32a2d |
as that is done only once at the beginning. Double precision
|
|
Packit |
c32a2d |
computations should be fine with software emulation.
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
There might be some slight pulsing from aliasing inside the buffer, where
|
|
Packit |
c32a2d |
there is a fractional number of samples per period and so some shidting
|
|
Packit |
c32a2d |
of sample point locations.
|
|
Packit |
c32a2d |
*/
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
#include "waves.h"
|
|
Packit |
c32a2d |
#include "debug.h"
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Not depending on C99 math for these simple things, */
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static const double freq_error = 1e-4;
|
|
Packit |
c32a2d |
static const double twopi = 2.0*3.14159265358979323846;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* absolute value */
|
|
Packit |
c32a2d |
static double myabs(double a)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
return a < 0 ? -a : a;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* round floating point to size_t */
|
|
Packit |
c32a2d |
static size_t round2size(double a)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
return a < 0 ? 0 : (size_t)(a+0.5);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* fractional part, relating to frequencies (so long matches) */
|
|
Packit |
c32a2d |
static double myfrac(double a)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
return a-(long)a;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/*
|
|
Packit |
c32a2d |
Given a set of wave frequencies, compute an approximate common
|
|
Packit |
c32a2d |
period for the combined signal. Invalid frequencies are set to
|
|
Packit |
c32a2d |
the error bound for some sanity.
|
|
Packit |
c32a2d |
*/
|
|
Packit |
c32a2d |
static double common_samples_per_period( long rate, size_t count
|
|
Packit |
c32a2d |
, double *freq, size_t size_limit )
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
double spp = 0;
|
|
Packit |
c32a2d |
size_t i;
|
|
Packit |
c32a2d |
for(i=0; i
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
double sppi;
|
|
Packit |
c32a2d |
size_t periods = 1;
|
|
Packit |
c32a2d |
/* Limiting sensible frequency range. */
|
|
Packit |
c32a2d |
if(freq[i] < freq_error)
|
|
Packit |
c32a2d |
freq[i] = freq_error;
|
|
Packit |
c32a2d |
if(freq[i] > rate/2)
|
|
Packit |
c32a2d |
freq[i] = rate/2;
|
|
Packit |
c32a2d |
sppi = myabs((double)rate/freq[i]);
|
|
Packit |
c32a2d |
debug2("freq=%g sppi=%g", freq[i], sppi);
|
|
Packit |
c32a2d |
if(spp == 0)
|
|
Packit |
c32a2d |
spp = sppi;
|
|
Packit |
c32a2d |
while
|
|
Packit |
c32a2d |
(
|
|
Packit |
c32a2d |
periods*spp < size_limit &&
|
|
Packit |
c32a2d |
myabs( myfrac(periods*spp / sppi) ) > freq_error
|
|
Packit |
c32a2d |
)
|
|
Packit |
c32a2d |
periods++;
|
|
Packit |
c32a2d |
spp*=periods;
|
|
Packit |
c32a2d |
debug3( "samples_per_period + %f Hz = %g (%" SIZE_P " periods)"
|
|
Packit |
c32a2d |
, freq[i], spp, periods );
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
return spp;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Compute a good size of a table covering the common period for all waves. */
|
|
Packit |
c32a2d |
static size_t tablesize( long rate, size_t count
|
|
Packit |
c32a2d |
, double *freq, size_t size_limit )
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
size_t ts;
|
|
Packit |
c32a2d |
double samples_per_period;
|
|
Packit |
c32a2d |
size_t periods;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
samples_per_period = common_samples_per_period( rate, count
|
|
Packit |
c32a2d |
, freq, size_limit );
|
|
Packit |
c32a2d |
periods = 1;
|
|
Packit |
c32a2d |
while
|
|
Packit |
c32a2d |
(
|
|
Packit |
c32a2d |
myabs( (double)(ts =
|
|
Packit |
c32a2d |
round2size(periods*samples_per_period))
|
|
Packit |
c32a2d |
- periods*samples_per_period
|
|
Packit |
c32a2d |
) / periods > freq_error*samples_per_period
|
|
Packit |
c32a2d |
&& periods*samples_per_period < size_limit
|
|
Packit |
c32a2d |
)
|
|
Packit |
c32a2d |
periods++;
|
|
Packit |
c32a2d |
/* Ensure that we got an even number of samples to accomodate the minimal */
|
|
Packit |
c32a2d |
/* sampling of a period. */
|
|
Packit |
c32a2d |
ts += ts % 2;
|
|
Packit |
c32a2d |
debug1("table size: %" SIZE_P, ts);
|
|
Packit |
c32a2d |
return ts;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* The wave functions. Argument is the phase normalised to the period. */
|
|
Packit |
c32a2d |
/* The argument is guaranteed to be 0 <= p < 1. */
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
const char *wave_pattern_default = "sine";
|
|
Packit |
c32a2d |
const char *wave_pattern_list = "sine, square, triangle, sawtooth, gauss, pulse, shot";
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* _________ */
|
|
Packit |
c32a2d |
/* */
|
|
Packit |
c32a2d |
static double wave_none(double p)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
return 0;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* __ */
|
|
Packit |
c32a2d |
/* / \ */
|
|
Packit |
c32a2d |
/* \__/ */
|
|
Packit |
c32a2d |
static double wave_sine(double p)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
return sin(twopi*p);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* ___ */
|
|
Packit |
c32a2d |
/* ___| */
|
|
Packit |
c32a2d |
static double wave_square(double p)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
return (myfrac(p) < 0.5 ? -1 : 1);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* 1234 Avoid jump from zero at beginning. */
|
|
Packit |
c32a2d |
/* /\ */
|
|
Packit |
c32a2d |
/* \/ */
|
|
Packit |
c32a2d |
static double wave_triangle(double p)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
return 4*p < 1
|
|
Packit |
c32a2d |
? 4*p /* 1 */
|
|
Packit |
c32a2d |
: ( 4*p < 3
|
|
Packit |
c32a2d |
? 2.-4*p /* 2 and 3 */
|
|
Packit |
c32a2d |
: -4+4*p /* 4 */
|
|
Packit |
c32a2d |
);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* /| Avoid jump from zero ... */
|
|
Packit |
c32a2d |
/* |/ */
|
|
Packit |
c32a2d |
static double wave_sawtooth(double p)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
return 2*p < 1 ? 2*p : -2+2*p;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* _ */
|
|
Packit |
c32a2d |
/* __/ \__ */
|
|
Packit |
c32a2d |
/* */
|
|
Packit |
c32a2d |
static double wave_gauss(double p)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
double v = p-0.5;
|
|
Packit |
c32a2d |
return exp(-30*v*v);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* _ */
|
|
Packit |
c32a2d |
/* _/ -___ */
|
|
Packit |
c32a2d |
/* */
|
|
Packit |
c32a2d |
/* p**2*exp(-a*p**2) */
|
|
Packit |
c32a2d |
/* Scaling: maximum at sqrt(1/a), value 1/a*exp(-1). */
|
|
Packit |
c32a2d |
static double wave_pulse(double p)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
return p*p*exp(-50*p*p)/0.00735758882342885;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* _ */
|
|
Packit |
c32a2d |
/* / -___ */
|
|
Packit |
c32a2d |
/* */
|
|
Packit |
c32a2d |
/* p**2*exp(-a*p) */
|
|
Packit |
c32a2d |
/* Scaling: maximum at 4/a, value 4/a**2*exp(-2). */
|
|
Packit |
c32a2d |
static double wave_shot(double p)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
return p*p*exp(-100*p)/5.41341132946451e-05;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Fill table with given periodic wave function. */
|
|
Packit |
c32a2d |
static void add_table( double *table, size_t samples
|
|
Packit |
c32a2d |
, long rate, double *freq, const char *wavetype, double phase)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
size_t i, periods;
|
|
Packit |
c32a2d |
double spp, phaseoff;
|
|
Packit |
c32a2d |
double (*wave)(double);
|
|
Packit |
c32a2d |
debug3("add_table %" SIZE_P " %ld %g", samples, rate, *freq);
|
|
Packit |
c32a2d |
periods = round2size((double)samples*(*freq)/rate);
|
|
Packit |
c32a2d |
if(!periods)
|
|
Packit |
c32a2d |
periods = 1;
|
|
Packit |
c32a2d |
spp = (double)samples/periods;
|
|
Packit |
c32a2d |
/* 2 samples is absolute minimum. */
|
|
Packit |
c32a2d |
if(spp < 2)
|
|
Packit |
c32a2d |
spp = 2;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* The actual frequency after the rounding of samples per period. */
|
|
Packit |
c32a2d |
*freq = (double)rate/spp;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Center samples in period, somewhat, to ensure getting extrema with very */
|
|
Packit |
c32a2d |
/* small sample counts (instead of zero at beginning and center). */
|
|
Packit |
c32a2d |
phaseoff = 1./(2*spp);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if(!wavetype)
|
|
Packit |
c32a2d |
wave = wave_none;
|
|
Packit |
c32a2d |
else if(!strcasecmp(wavetype, "sine"))
|
|
Packit |
c32a2d |
wave = wave_sine;
|
|
Packit |
c32a2d |
else if(!strcasecmp(wavetype, "square"))
|
|
Packit |
c32a2d |
wave = wave_square;
|
|
Packit |
c32a2d |
else if(!strcasecmp(wavetype, "triangle"))
|
|
Packit |
c32a2d |
wave = wave_triangle;
|
|
Packit |
c32a2d |
else if(!strcasecmp(wavetype, "sawtooth"))
|
|
Packit |
c32a2d |
wave = wave_sawtooth;
|
|
Packit |
c32a2d |
else if(!strcasecmp(wavetype, "gauss"))
|
|
Packit |
c32a2d |
wave = wave_gauss;
|
|
Packit |
c32a2d |
else if(!strcasecmp(wavetype, "pulse"))
|
|
Packit |
c32a2d |
wave = wave_pulse;
|
|
Packit |
c32a2d |
else if(!strcasecmp(wavetype, "shot"))
|
|
Packit |
c32a2d |
wave = wave_shot;
|
|
Packit |
c32a2d |
else
|
|
Packit |
c32a2d |
wave = wave_none;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
debug3( "adding wave: %s @ %g Hz + %g"
|
|
Packit |
c32a2d |
, wavetype ? wavetype : "none", *freq, phase );
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/*
|
|
Packit |
c32a2d |
compromise: smooth onset for low frequencies, but also good sampling
|
|
Packit |
c32a2d |
of high freqs extreme case: 2 samples per period should trigger
|
|
Packit |
c32a2d |
max/min amplitude, not both zero so, center the samples within one
|
|
Packit |
c32a2d |
period. That's achieved by adding 0.25 to the counter.
|
|
Packit |
c32a2d |
*/
|
|
Packit |
c32a2d |
if(phase >= 0)
|
|
Packit |
c32a2d |
for(i=0; i
|
|
Packit |
c32a2d |
table[i] *= wave(myfrac( ((double)i+phaseoff)/spp + phase));
|
|
Packit |
c32a2d |
else
|
|
Packit |
c32a2d |
for(i=0; i
|
|
Packit |
c32a2d |
table[i] *= wave(1.-myfrac( ((double)i+phaseoff)/spp - phase));
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Construct the prototype table in double precision. */
|
|
Packit |
c32a2d |
static double* mytable( long rate, size_t count, double *freq
|
|
Packit |
c32a2d |
, const char** wavetype, double *phase
|
|
Packit |
c32a2d |
, size_t size_limit, size_t *samples)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
size_t i;
|
|
Packit |
c32a2d |
double *table = NULL;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
*samples = tablesize(rate, count, freq, size_limit);
|
|
Packit |
c32a2d |
debug1("computed table size: %" SIZE_P, *samples);
|
|
Packit |
c32a2d |
table = malloc(*samples*sizeof(double));
|
|
Packit |
c32a2d |
if(!table)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
error("OOM!");
|
|
Packit |
c32a2d |
return NULL;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
/* Initialise to zero. */
|
|
Packit |
c32a2d |
for(i=0; i<*samples; ++i)
|
|
Packit |
c32a2d |
table[i] = 1;
|
|
Packit |
c32a2d |
/* Add individual waves, with default parameters. */
|
|
Packit |
c32a2d |
for(i=0; i
|
|
Packit |
c32a2d |
add_table(
|
|
Packit |
c32a2d |
table, *samples, rate, freq+i
|
|
Packit |
c32a2d |
, wavetype ? wavetype[i] : wave_pattern_default
|
|
Packit |
c32a2d |
, phase ? phase[i] : 0
|
|
Packit |
c32a2d |
);
|
|
Packit |
c32a2d |
/* Amplification could have caused clipping. */
|
|
Packit |
c32a2d |
for(i=0; i<*samples; ++i)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(table[i] > 1.0)
|
|
Packit |
c32a2d |
table[i] = 1.0;
|
|
Packit |
c32a2d |
if(table[i] < -1.0)
|
|
Packit |
c32a2d |
table[i] = -1.0;
|
|
Packit |
c32a2d |
debug2("table[%" SIZE_P "]=%f", i, table[i]);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
return table;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Some trivial conversion functions. No need for a library. */
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* All symmetric, +/- 2^n-1. */
|
|
Packit |
c32a2d |
#define CONV(name, type, maxval) \
|
|
Packit |
c32a2d |
static type name(double d) \
|
|
Packit |
c32a2d |
{ \
|
|
Packit |
c32a2d |
type imax = maxval; \
|
|
Packit |
c32a2d |
d *= imax; \
|
|
Packit |
c32a2d |
if(d>=0) \
|
|
Packit |
c32a2d |
{ \
|
|
Packit |
c32a2d |
d += 0.5; \
|
|
Packit |
c32a2d |
return d > imax \
|
|
Packit |
c32a2d |
? imax \
|
|
Packit |
c32a2d |
: (type)d; \
|
|
Packit |
c32a2d |
} \
|
|
Packit |
c32a2d |
else \
|
|
Packit |
c32a2d |
{ \
|
|
Packit |
c32a2d |
d -= 0.5; \
|
|
Packit |
c32a2d |
return d < -imax \
|
|
Packit |
c32a2d |
? -imax \
|
|
Packit |
c32a2d |
: (type)d; \
|
|
Packit |
c32a2d |
} \
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
CONV(d2s32, int32_t, 2147483647L)
|
|
Packit |
c32a2d |
CONV(d2s16, int16_t, 32767)
|
|
Packit |
c32a2d |
CONV(d2s8, char, 127)
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
#define HANDLE_OOM(p, h, p2) \
|
|
Packit |
c32a2d |
if(!(p)) \
|
|
Packit |
c32a2d |
{ \
|
|
Packit |
c32a2d |
error("OOM!"); \
|
|
Packit |
c32a2d |
if((p2)) free((p2)); \
|
|
Packit |
c32a2d |
return wave_table_del((h)); \
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Build internal table, allocate external table, convert to that one, */
|
|
Packit |
c32a2d |
/* adjusting sample storage format and channel count. */
|
|
Packit |
c32a2d |
struct wave_table* wave_table_new(
|
|
Packit |
c32a2d |
long rate, int channels, int encoding
|
|
Packit |
c32a2d |
, size_t count, double *freq
|
|
Packit |
c32a2d |
, const char** wavetype, double *phase
|
|
Packit |
c32a2d |
, size_t size_limit
|
|
Packit |
c32a2d |
){
|
|
Packit |
c32a2d |
struct wave_table *handle;
|
|
Packit |
c32a2d |
double *dtable;
|
|
Packit |
c32a2d |
int c,i;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
handle = malloc(sizeof(struct wave_table));
|
|
Packit |
c32a2d |
HANDLE_OOM(handle, handle, NULL)
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
handle->buf = NULL;
|
|
Packit |
c32a2d |
handle->fmt.rate = rate;
|
|
Packit |
c32a2d |
handle->fmt.channels = channels;
|
|
Packit |
c32a2d |
handle->fmt.encoding = encoding;
|
|
Packit |
c32a2d |
handle->samples = 0;
|
|
Packit |
c32a2d |
handle->offset = 0;
|
|
Packit |
c32a2d |
handle->count = count;
|
|
Packit |
c32a2d |
handle->freq = NULL;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
handle->freq = malloc(sizeof(double)*count);
|
|
Packit |
c32a2d |
HANDLE_OOM(handle->freq, handle, NULL)
|
|
Packit |
c32a2d |
for(i=0; i
|
|
Packit |
c32a2d |
handle->freq[i] = freq[i];
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
dtable = mytable( rate, count, handle->freq, wavetype, phase
|
|
Packit |
c32a2d |
, size_limit, &handle->samples );
|
|
Packit |
c32a2d |
HANDLE_OOM(dtable, handle, NULL)
|
|
Packit |
c32a2d |
handle->buf = malloc( handle->samples
|
|
Packit |
c32a2d |
* MPG123_SAMPLESIZE(encoding) * channels );
|
|
Packit |
c32a2d |
HANDLE_OOM(handle->buf, handle, dtable)
|
|
Packit |
c32a2d |
/* Now convert. */
|
|
Packit |
c32a2d |
for(c=0; c
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
switch(encoding)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
/* Samples are clipped. Rounding a double below 1.0 to float cannot */
|
|
Packit |
c32a2d |
/* get larger than 1.0 since that is exact in single precision. */
|
|
Packit |
c32a2d |
case MPG123_ENC_FLOAT_64:
|
|
Packit |
c32a2d |
for(i=0; i<handle->samples; ++i)
|
|
Packit |
c32a2d |
((double*)handle->buf)[i*channels+c] = dtable[i];
|
|
Packit |
c32a2d |
break;
|
|
Packit |
c32a2d |
case MPG123_ENC_FLOAT_32:
|
|
Packit |
c32a2d |
for(i=0; i<handle->samples; ++i)
|
|
Packit |
c32a2d |
((float*)handle->buf)[i*channels+c] = dtable[i];
|
|
Packit |
c32a2d |
break;
|
|
Packit |
c32a2d |
case MPG123_ENC_SIGNED_32:
|
|
Packit |
c32a2d |
for(i=0; i<handle->samples; ++i)
|
|
Packit |
c32a2d |
((int32_t*)handle->buf)[i*channels+c] = d2s32(dtable[i]);
|
|
Packit |
c32a2d |
break;
|
|
Packit |
c32a2d |
case MPG123_ENC_SIGNED_16:
|
|
Packit |
c32a2d |
for(i=0; i<handle->samples; ++i)
|
|
Packit |
c32a2d |
((int16_t*)handle->buf)[i*channels+c] = d2s16(dtable[i]);
|
|
Packit |
c32a2d |
break;
|
|
Packit |
c32a2d |
case MPG123_ENC_SIGNED_8:
|
|
Packit |
c32a2d |
for(i=0; i<handle->samples; ++i)
|
|
Packit |
c32a2d |
((char*)handle->buf)[i*channels+c] = d2s8(dtable[i]);
|
|
Packit |
c32a2d |
break;
|
|
Packit |
c32a2d |
default:
|
|
Packit |
c32a2d |
error("unsupported encoding, choose f64, f32, s32, s16 or s8");
|
|
Packit |
c32a2d |
free(dtable);
|
|
Packit |
c32a2d |
return wave_table_del(handle);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
free(dtable);
|
|
Packit |
c32a2d |
return handle;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
void* wave_table_del(struct wave_table* handle)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(handle)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(handle->freq)
|
|
Packit |
c32a2d |
free(handle->freq);
|
|
Packit |
c32a2d |
if(handle->buf)
|
|
Packit |
c32a2d |
free(handle->buf);
|
|
Packit |
c32a2d |
free(handle);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
return NULL;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Copy blocks from offset to end until desired amount is extracted. */
|
|
Packit |
c32a2d |
size_t wave_table_extract( struct wave_table *handle
|
|
Packit |
c32a2d |
, void *dest, size_t dest_samples )
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
char *cdest = (char*)dest; /* Want to do arithmetic. */
|
|
Packit |
c32a2d |
size_t framesize;
|
|
Packit |
c32a2d |
size_t extracted = 0;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if(!handle)
|
|
Packit |
c32a2d |
return 0;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
framesize = MPG123_SAMPLESIZE(handle->fmt.encoding)
|
|
Packit |
c32a2d |
* handle->fmt.channels;
|
|
Packit |
c32a2d |
while(dest_samples)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
size_t block = dest_samples > handle->samples - handle->offset
|
|
Packit |
c32a2d |
? handle->samples - handle->offset
|
|
Packit |
c32a2d |
: dest_samples;
|
|
Packit |
c32a2d |
debug1("block: %" SIZE_P, block);
|
|
Packit |
c32a2d |
memcpy( cdest, (char*)handle->buf+handle->offset*framesize
|
|
Packit |
c32a2d |
, framesize*block );
|
|
Packit |
c32a2d |
cdest += framesize*block;
|
|
Packit |
c32a2d |
handle->offset += block;
|
|
Packit |
c32a2d |
handle->offset %= handle->samples;
|
|
Packit |
c32a2d |
dest_samples -= block;
|
|
Packit |
c32a2d |
extracted += block;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
debug1("extracted: %" SIZE_P, extracted);
|
|
Packit |
c32a2d |
return extracted;
|
|
Packit |
c32a2d |
}
|