1
0
mirror of https://github.com/cookiengineer/audacity synced 2026-01-11 15:15:57 +01:00

upgrade to libsoxr 0.0.5 from current git

This commit is contained in:
v.audacity
2012-12-18 05:48:55 +00:00
parent a1a5a75804
commit 61f5cdb82b
94 changed files with 13573 additions and 12511 deletions

View File

@@ -0,0 +1,78 @@
/* SoX Resampler Library Copyright (c) 2007-12 robs@users.sourceforge.net
* Licence for this file: LGPL v2.1 See LICENCE for details. */
/* Example 2: resample a raw, single-channel, floating-point data stream from
* stdin to stdout.
*
* The application uses the single function `soxr_process' for both input and
* output to/from the resampler; compared to the `input function' approach
* (illustrated in example 3) this requires that the application implements
* more logic, but one less function.
*
* Arguments are: INPUT-RATE OUTPUT-RATE
*/
#include <soxr.h>
#include "examples-common.h"
int main(int argc, char const * arg[])
{
double const irate = argc > 1? atof(arg[1]) : 96000.;
double const orate = argc > 2? atof(arg[2]) : 44100.;
/* Allocate resampling input and output buffers in proportion to the input
* and output rates: */
#define buf_total_len 15000 /* In samples. */
size_t const olen = (size_t)(orate * buf_total_len / (irate + orate) + .5);
size_t const ilen = buf_total_len - olen;
size_t const osize = sizeof(float), isize = osize;
void * obuf = malloc(osize * olen);
void * ibuf = malloc(isize * ilen);
size_t odone, written, need_input = 1;
soxr_error_t error;
/* Create a stream resampler: */
soxr_t soxr = soxr_create(
irate, orate, 1, /* Input rate, output rate, # of channels. */
&error, /* To report any error during creation. */
NULL, NULL, NULL); /* Use configuration defaults.*/
if (!error) { /* If all is well, run the resampler: */
USE_STD_STDIO;
/* Resample in blocks: */
do {
size_t ilen1 = 0;
if (need_input) {
/* Read one block into the buffer, ready to be resampled: */
ilen1 = fread(ibuf, isize, ilen, stdin);
if (!ilen1) { /* If the is no (more) input data available, */
free(ibuf); /* set ibuf to NULL, to indicate end-of-input */
ibuf = NULL; /* to the resampler. */
}
}
/* Copy data from the input buffer into the resampler, and resample
* to produce as much output as is possible to the given output buffer: */
error = soxr_process(soxr, ibuf, ilen1, NULL, obuf, olen, &odone);
written = fwrite(obuf, osize, odone, stdout); /* Consume output.*/
/* If the actual amount of data output is less than that requested, and
* we have not already reached the end of the input data, then supply some
* more input next time round the loop: */
need_input = odone < olen && ibuf;
} while (!error && (need_input || written));
}
/* Tidy up: */
soxr_delete(soxr);
free(obuf), free(ibuf);
/* Diagnostics: */
fprintf(stderr, "%-26s %s; I/O: %s\n", arg[0],
soxr_strerror(error), errno? strerror(errno) : "no error");
return error || errno;
}

View File

@@ -0,0 +1,97 @@
/* SoX Resampler Library Copyright (c) 2007-12 robs@users.sourceforge.net
* Licence for this file: LGPL v2.1 See LICENCE for details. */
/* Example 3: extends example 2 with multiple channels, multiple datatypes,
* and other options.
*
* The application provides an input function, called on demand by libsoxr, in
* response to calls to soxr_output(); compared to the `process' approach
* (illustrated in example 2) this requires that the application implements
* less logic, but one more function.
*
* The eight arguments (which are optional, from last to first) are:
* INPUT-RATE As example 2
* OUTPUT-RATE Ditto
* NUM-CHANNELS Number of interleaved channels
* IN-DATATYPE# 0:float32 1:float64 2:int32 3:int16
* OUT-DATATYPE# Ditto
* Q-RECIPE Quality recipe (in hex) See soxr.h
* Q-FLAGS Quality flags (in hex) See soxr.h
* USE-THREADS 1 to use multi-threading (where available)
*/
#include <soxr.h>
#include "examples-common.h"
typedef struct {void * ibuf; size_t isize;} input_context_t;
static size_t input_fn(input_context_t * p, soxr_cbuf_t * buf, size_t len)
{
/* Read one block into the buffer, ready to be input to the resampler: */
len = fread(p->ibuf, p->isize, len, stdin); /* Actual len read may be less. */
/* Inform the resampler of the data's whereabouts (which could be anywhere, in
* a freshly malloc'd buffer, for example): */
*buf = (!len && ferror(stdin))? NULL : p->ibuf; /* NULL if error occurred. */
return len; /* # of samples per channel to input. */
}
int main(int n, char const * arg[])
{
char const * const arg0 = n? --n, *arg++ : "";
double const irate = n? --n, atof(*arg++) : 96000.;
double const orate = n? --n, atof(*arg++) : 44100.;
unsigned const chans = n? --n, (unsigned)atoi(*arg++) : 1;
soxr_datatype_t const itype = n? --n, (soxr_datatype_t)atoi(*arg++) : 0;
soxr_datatype_t const otype = n? --n, (soxr_datatype_t)atoi(*arg++) : 0;
unsigned long const q_recipe= n? --n, strtoul(*arg++, 0, 16) : SOXR_HQ;
unsigned long const q_flags = n? --n, strtoul(*arg++, 0, 16) : 0;
int const use_threads = n? --n, atoi(*arg++) : 1;
soxr_quality_spec_t const q_spec = soxr_quality_spec(q_recipe, q_flags);
soxr_io_spec_t const io_spec = soxr_io_spec(itype, otype);
soxr_runtime_spec_t const runtime_spec = soxr_runtime_spec(!use_threads);
/* Allocate resampling input and output buffers in proportion to the input
* and output rates: */
#define buf_total_len 15000 /* In samples per channel. */
size_t const osize = soxr_datatype_size(otype) * chans;
size_t const isize = soxr_datatype_size(itype) * chans;
size_t const olen = (size_t)(orate * buf_total_len / (irate + orate) + .5);
size_t const ilen = buf_total_len - olen;
void * const obuf = malloc(osize * olen);
void * const ibuf = malloc(isize * ilen);
input_context_t icontext;
size_t odone, clips = 0;
soxr_error_t error;
/* Create a stream resampler: */
soxr_t soxr = soxr_create(
irate, orate, chans, /* Input rate, output rate, # of channels. */
&error, /* To report any error during creation. */
&io_spec, &q_spec, &runtime_spec);
if (!error) { /* Register input_fn with the resampler: */
icontext.ibuf = ibuf, icontext.isize = isize;
error = soxr_set_input_fn(soxr, (soxr_input_fn_t)input_fn, &icontext, ilen);
}
if (!error) { /* If all is well, run the resampler: */
USE_STD_STDIO;
/* Resample in blocks: */
do odone = soxr_output(soxr, obuf, olen);
while (fwrite(obuf, osize, odone, stdout)); /* Consume output. */
error = soxr_error(soxr); /* Check if any soxr error occurred. */
clips = *soxr_num_clips(soxr); /* Can occur only with integer output. */
}
/* Tidy up: */
soxr_delete(soxr);
free(obuf), free(ibuf);
/* Diagnostics: */
fprintf(stderr, "%-26s %s; %lu clips; I/O: %s\n", arg0, soxr_strerror(error),
(long unsigned)clips, errno? strerror(errno) : "no error");
return error || errno;
}

View File

@@ -1,7 +1,7 @@
/* SoX Resampler Library Copyright (c) 2007-12 robs@users.sourceforge.net
* Licence for this file: LGPL v2.1 See LICENCE for details. */
/* Example 4: variant of example 3a; demonstrates I/O with split channels.
/* Example 4: variant of examples 2 & 3, demonstrating I/O with split channels.
*
* Note that, for convenience of the demonstration, split-channel data is
* made available by deinterleaving data sourced from and sent to
@@ -68,85 +68,79 @@ static void interleave(soxr_datatype_t data_type, void * dest0,
int main(int n, char const * arg[])
{
char const * arg0 = n? --n, *arg++ : "";
double irate = n? --n, atof(*arg++) : 96000.;
double orate = n? --n, atof(*arg++) : 44100.;
unsigned chans = n? --n, (unsigned)atoi(*arg++) : 1;
soxr_datatype_t itype = n? --n, (soxr_datatype_t)atoi(*arg++) :SOXR_FLOAT32_I;
soxr_datatype_t otype = n? --n, (soxr_datatype_t)atoi(*arg++) :SOXR_FLOAT32_I;
unsigned long q_recipe= n? --n, strtoul(*arg++, 0, 16) : SOXR_HQ;
unsigned long q_flags = n? --n, strtoul(*arg++, 0, 16) : 0;
int use_threads = n? --n, atoi(*arg++) : 1;
char const * const arg0 = n? --n, *arg++ : "";
double const irate = n? --n, atof(*arg++) : 96000.;
double const orate = n? --n, atof(*arg++) : 44100.;
unsigned const chans = n? --n, (unsigned)atoi(*arg++) : 1;
soxr_datatype_t const itype = n? --n, (soxr_datatype_t)atoi(*arg++) : 0;
soxr_datatype_t const otype = n? --n, (soxr_datatype_t)atoi(*arg++) : 0;
unsigned long const q_recipe= n? --n, strtoul(*arg++, 0, 16) : SOXR_HQ;
unsigned long const q_flags = n? --n, strtoul(*arg++, 0, 16) : 0;
int const use_threads = n? --n, atoi(*arg++) : 1;
size_t isize = soxr_datatype_size(itype) * chans;
size_t osize = soxr_datatype_size(otype) * chans;
size_t clips = 0;
soxr_quality_spec_t const q_spec = soxr_quality_spec(q_recipe, q_flags);
soxr_io_spec_t const io_spec=soxr_io_spec(itype|SOXR_SPLIT, otype|SOXR_SPLIT);
soxr_runtime_spec_t const runtime_spec = soxr_runtime_spec(!use_threads);
/* Allocate resampling input and output buffers in proportion to the input
* and output rates: */
#define buf_total_len 15000 /* In samples per channel. */
size_t const osize = soxr_datatype_size(otype) * chans;
size_t const isize = soxr_datatype_size(itype) * chans;
size_t const olen = (size_t)(orate * buf_total_len / (irate + orate) + .5);
size_t const ilen = buf_total_len - olen;
/* For split channels: */
void * * const obuf_ptrs = malloc(sizeof(void *) * chans);
void * * ibuf_ptrs = malloc(sizeof(void *) * chans);
char * const obufs = malloc(osize * olen), * optr = obufs;
char * const ibufs = malloc(isize * ilen), * iptr = ibufs;
/* For interleaved channels: */
char * const obuf = malloc(osize * olen);
char * const ibuf = malloc(isize * ilen);
size_t odone, written, need_input = 1, clips = 0;
soxr_error_t error;
soxr_quality_spec_t q_spec = soxr_quality_spec(q_recipe, q_flags);
soxr_io_spec_t io_spec = soxr_io_spec(itype|SOXR_SPLIT, otype|SOXR_SPLIT);
soxr_runtime_spec_t runtime_spec = soxr_runtime_spec(!use_threads);
soxr_t resampler = soxr_create(
soxr_t soxr = soxr_create(
irate, orate, chans, &error, &io_spec, &q_spec, &runtime_spec);
unsigned i;
for (i = 0; i < chans; ++i) {
ibuf_ptrs[i] = iptr;
obuf_ptrs[i] = optr;
iptr += ilen * soxr_datatype_size(itype);
optr += olen * soxr_datatype_size(otype);
}
if (!error) {
#define buf_total_len 14000
/* Allocate resampling input and output buffers in proportion to the input
* and output rates: */
size_t ibuflen = (size_t)(irate * buf_total_len / (irate + orate) + .5);
size_t obuflen = buf_total_len - ibuflen;
/* For split channels: */
void * * ibuf_ptrs = malloc(sizeof(void *) * chans);
void * * obuf_ptrs = malloc(sizeof(void *) * chans);
char * * ibuf_offset_ptrs = malloc(sizeof(void *) * chans);
char * ibufs = malloc(isize * ibuflen), * iptr = ibufs;
char * obufs = malloc(osize * obuflen), * optr = obufs;
/* For interleaved channels: */
char * ibuf = malloc(isize * ibuflen);
char * obuf = malloc(osize * obuflen);
size_t iavailable = 0;
size_t idone, odone, written;
unsigned i;
for (i = 0; i < chans; ++i) {
ibuf_ptrs[i] = iptr;
obuf_ptrs[i] = optr;
iptr += ibuflen * soxr_datatype_size(itype);
optr += obuflen * soxr_datatype_size(otype);
}
USE_STD_STDIO;
do {
if (!iavailable && ibuf_offset_ptrs) { /* If ibuf empty, try to fill it: */
if (!(iavailable = fread(ibuf, isize, ibuflen, stdin)))
free(ibuf_offset_ptrs), ibuf_offset_ptrs = 0; /* If none available, don't retry. */
else {
memcpy(ibuf_offset_ptrs, ibuf_ptrs, sizeof(void *) * chans);
deinterleave(itype, ibuf_ptrs, ibuf, iavailable, chans);
}
size_t ilen1 = 0;
if (need_input) {
if (!(ilen1 = fread(ibuf, isize, ilen, stdin)))
free(ibuf_ptrs), ibuf_ptrs = 0; /* If none available, don't retry. */
else deinterleave(itype, ibuf_ptrs, ibuf, ilen1, chans);
}
error = soxr_process(resampler,
ibuf_offset_ptrs, iavailable, &idone, obuf_ptrs, obuflen, &odone);
if (ibuf_offset_ptrs) for (i = 0; i < chans; ++i) /* Consumed input. */
ibuf_offset_ptrs[i] += idone * isize;
iavailable -= idone;
interleave(otype, obuf, obuf_ptrs, odone, chans); /* Consume output. */
error = soxr_process(soxr, ibuf_ptrs, ilen1, NULL, obuf_ptrs, olen, &odone);
interleave(otype, obuf, obuf_ptrs, odone, chans); /* Consume output... */
written = fwrite(obuf, osize, odone, stdout);
} while (!error && (ibuf_offset_ptrs || written));
free(obuf), free(ibuf), free(obufs), free(ibufs);
free(obuf_ptrs), free(ibuf_ptrs), free(ibuf_offset_ptrs);
clips = *soxr_num_clips(resampler);
soxr_delete(resampler);
need_input = odone < olen && ibuf_ptrs;
} while (!error && (need_input || written));
clips = *soxr_num_clips(soxr); /* Can occur only with integer output. */
}
/* Tidy up: */
soxr_delete(soxr);
free(obuf), free(ibuf), free(obufs), free(ibufs);
free(obuf_ptrs), free(ibuf_ptrs);
/* Diagnostics: */
fprintf(stderr, "%-26s %s; %lu clips; I/O: %s\n", arg0, soxr_strerror(error),
(long unsigned)clips, errno? strerror(errno) : "no error");
return error || errno;

View File

@@ -0,0 +1,94 @@
/* SoX Resampler Library Copyright (c) 2007-12 robs@users.sourceforge.net
* Licence for this file: LGPL v2.1 See LICENCE for details. */
/* Example 5: Variable-rate resampling (N.B. experimental). A test signal
* (held in a buffer) is resampled over a wide range of octaves. Resampled
* data is sent to stdout as raw, float32 samples. Choices of 2 test-signals
* and of 2 ways of varying the sample-rate are combined in a command-line
* option:
*
* Usage: ./5-variable-rate [0|1|2|3]
*/
#include <soxr.h>
#include "examples-common.h"
#define OCTAVES 5 /* Resampling range. ± */
#define OLEN 16 /* Output length in seconds. */
#define FS 44100 /* Output sampling rate in Hz. */
/* For output pos in [0,1], returns an ioratio in the 2^±OCTAVES range: */
static double ioratio(double pos, int fm)
{
if (fm) /* fm: non-0 for a fast-changing ioratio, 0 for a slow sweep. */
pos = .5 - cos(pos * 2 * M_PI) * .4 + sin(pos * OLEN * 20 * M_PI) * .05;
return pow(2, 2 * OCTAVES * pos - OCTAVES);
}
int main(int argc, char *arg[])
{
int opt = argc <= 1? 2 : (atoi(arg[1]) & 3), saw = opt & 1, fm = opt & 2;
float ibuf[10 << OCTAVES], obuf[AL(ibuf)];
int i, wl = 2 << OCTAVES;
size_t ilen = AL(ibuf), need_input = 1;
size_t odone, total_odone, total_olen = OLEN * FS;
size_t olen1 = fm? 10 : AL(obuf); /* Small block-len if fast-changing ratio */
soxr_error_t error;
/* When creating a var-rate resampler, q_spec must be set as follows: */
soxr_quality_spec_t q_spec = soxr_quality_spec(SOXR_HQ, SOXR_VR);
/* The ratio of the given input rate and output rates must equate to the
* maximum I/O ratio that will be used: */
soxr_t soxr = soxr_create(1 << OCTAVES, 1, 1, &error, NULL, &q_spec, NULL);
if (!error) {
USE_STD_STDIO;
/* Generate input signal, sine or saw, with wave-length = wl: */
for (i = 0; i < (int)ilen; ++i)
ibuf[i] = (float)(saw? (i%wl)/(wl-1.)-.5 : .9 * sin(2 * M_PI * i / wl));
/* Set the initial resampling ratio (N.B. 3rd parameter = 0): */
soxr_set_io_ratio(soxr, ioratio(0, fm), 0);
/* Resample in blocks of size olen1: */
for (total_odone = 0; !error && total_odone < total_olen;) {
/* The last block might be shorter: */
size_t block_len = min(olen1, total_olen - total_odone);
/* Determine the position in [0,1] of the end of the current block: */
double pos = (double)(total_odone + block_len) / (double)total_olen;
/* Calculate an ioratio for this position and instruct the resampler to
* move smoothly to the new value, over the course of outputting the next
* 'block_len' samples (or give 0 for an instant change instead): */
soxr_set_io_ratio(soxr, ioratio(pos, fm), block_len);
/* Output the block of samples, supplying input samples as needed: */
do {
size_t len = need_input? ilen : 0;
error = soxr_process(soxr, ibuf, len, NULL, obuf, block_len, &odone);
fwrite(obuf, sizeof(float), odone, stdout);
/* Update counters for the current block and for the total length: */
block_len -= odone;
total_odone += odone;
/* If soxr_process did not provide the complete block, we must call it
* again, supplying more input samples: */
need_input = block_len != 0;
} while (need_input && !error);
/* Now that the block for the current ioratio is complete, go back
* round the main `for' loop in order to process the next block. */
}
soxr_delete(soxr);
}
/* Diagnostics: */
fprintf(stderr, "%-26s %s; I/O: %s\n", arg[0],
soxr_strerror(error), errno? strerror(errno) : "no error");
return error || errno;
}

View File

@@ -8,7 +8,7 @@ if (${BUILD_EXAMPLES})
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_C_FLAGS}")
endif ()
else ()
file (GLOB SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/3b*.c)
file (GLOB SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/3*.c)
endif ()
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${PROJECT_C_FLAGS}")

View File

@@ -72,6 +72,7 @@
<File RelativePath="../src/rate64.c" />
<File RelativePath="../src/simd.c" />
<File RelativePath="../src/soxr.c" />
<File RelativePath="../src/vr32.c" />
</Filter>
</Files>
<Globals>

View File

@@ -10,10 +10,11 @@
#define SOXR_VERSION_MAJOR 0
#define SOXR_VERSION_MINOR 0
#define SOXR_VERSION_PATCH 1
#define SOXR_VERSION "0.0.1"
#define SOXR_VERSION "0.0.5"
#define HAVE_SINGLE_PRECISION 1
#define HAVE_DOUBLE_PRECISION 1
#define HAVE_VR 1
#define HAVE_AVFFT 0
#define HAVE_SIMD 1
#define HAVE_FENV_H 0

View File

@@ -184,13 +184,14 @@ void _soxr_deinterleave_f(float * * dest, /* Round/clipping not needed here */
#define INTERLEAVE_TO(T) do { \
#define INTERLEAVE_TO(T,flag) do { \
unsigned i; \
size_t j; \
T * dest = *dest0; \
if (ch == 1) \
for (j = 0; j < n; *dest++ = (T)src[0][j++]); \
else for (j = 0; j < n; ++j) for (i = 0; i < ch; ++i) *dest++ = (T)src[i][j]; \
if (ch > 1) \
for (j = 0; j < n; ++j) for (i = 0; i < ch; ++i) *dest++ = (T)src[i][j]; \
else if (flag) memcpy(dest, src[0], n * sizeof(T)), dest = &dest[n]; \
else for (j = 0; j < n; *dest++ = (T)src[0][j++]); \
*dest0 = dest; \
return 0; \
} while (0)
@@ -200,8 +201,8 @@ size_t /* clips */ _soxr_interleave(soxr_datatype_t data_type, void * * dest0,
double const * const * src, size_t n, unsigned ch, unsigned long * seed)
{
switch (data_type & 3) {
case SOXR_FLOAT32: INTERLEAVE_TO(float);
case SOXR_FLOAT64: INTERLEAVE_TO(double);
case SOXR_FLOAT32: INTERLEAVE_TO(float, 0);
case SOXR_FLOAT64: INTERLEAVE_TO(double, 1);
case SOXR_INT32: if (ch == 1)
return lsx_rint32_clip(dest0, src[0], n);
@@ -226,8 +227,8 @@ size_t /* clips */ _soxr_interleave_f(soxr_datatype_t data_type, void * * dest0,
float const * const * src, size_t n, unsigned ch, unsigned long * seed)
{
switch (data_type & 3) {
case SOXR_FLOAT32: INTERLEAVE_TO(float);
case SOXR_FLOAT64: INTERLEAVE_TO(double);
case SOXR_FLOAT32: INTERLEAVE_TO(float, 1);
case SOXR_FLOAT64: INTERLEAVE_TO(double, 0);
case SOXR_INT32: if (ch == 1)
return lsx_rint32_clip_f(dest0, src[0], n);

View File

@@ -4,14 +4,11 @@
#ifndef fifo_included
#define fifo_included
#include <string.h>
#if !defined FIFO_SIZE_T
#define FIFO_SIZE_T size_t
#endif
#if !defined FIFO_REALLOC
#include <stdlib.h>
#define FIFO_REALLOC(a,b,c) realloc(a,b)
#undef FIFO_FREE
#define FIFO_FREE free
@@ -27,7 +24,9 @@ typedef struct {
size_t end; /* 1 + Offset of the last byte byte to read. */
} fifo_t;
#define FIFO_MIN 0x4000
#if !defined FIFO_MIN
#define FIFO_MIN 0x4000
#endif
#if !defined UNUSED
#define UNUSED

View File

@@ -14,8 +14,16 @@
#define range_limit(x, lower, upper) (min(max(x, lower), upper))
#define linear_to_dB(x) (log10(x) * 20)
#define array_length(a) (sizeof(a)/sizeof(a[0]))
#define AL(a) array_length(a)
#define iAL(a) (int)AL(a)
#define sqr(a) ((a) * (a))
#ifdef __GNUC__
#define UNUSED __attribute__ ((unused))
#else
#define UNUSED
#endif
#if defined NDEBUG
#ifdef __GNUC__
void lsx_dummy(char const *, ...);
@@ -26,10 +34,7 @@
#else
#include <stdarg.h>
#include <stdio.h>
#ifdef __GNUC__
__attribute__ ((unused))
#endif
static void lsx_debug(char const * fmt, ...)
UNUSED static void lsx_debug(char const * fmt, ...)
{
va_list args;
va_start(args, fmt);

View File

@@ -51,7 +51,7 @@ soxr_t src_callback_new(soxr_input_fn_t fn, unsigned id, int channels, SRC_ERROR
*/
soxr = soxr_create(0, 0, (unsigned)channels, &error, 0, &q_spec, &r_spec);
if (soxr)
error = soxr_set_input_fn(soxr, fn, p);
error = soxr_set_input_fn(soxr, fn, p, 0);
*(int *)error0 = (int)(long)error;
return soxr;
}
@@ -59,7 +59,7 @@ soxr_t src_callback_new(soxr_input_fn_t fn, unsigned id, int channels, SRC_ERROR
soxr_error_t src_process(soxr_t p, io_t * io)
{
if (!p || !io) return "null pointer";
soxr_set_error(p, soxr_set_oi_ratio(p, io->oi_ratio));
soxr_set_error(p, soxr_set_io_ratio(p, 1/io->oi_ratio, (size_t)io->olen));
{ size_t idone , odone;
soxr_process(p, io->in, (size_t)(io->eoi? ~io->ilen : io->ilen), /* hack */
@@ -71,7 +71,7 @@ soxr_error_t src_process(soxr_t p, io_t * io)
long src_callback_read(soxr_t p, double oi_ratio, long olen, float * obuf)
{
if (!p || olen < 0) return -1;
soxr_set_error(p, soxr_set_oi_ratio(p, oi_ratio));
soxr_set_error(p, soxr_set_io_ratio(p, 1/oi_ratio, (size_t)olen));
return (long)soxr_output(p, obuf, (size_t)olen);
}
@@ -110,5 +110,5 @@ int src_is_valid_ratio(double oi_ratio) {return getenv("SOXR_LSR_STRICT")?
soxr_error_t src_error(soxr_t p) {return soxr_error(p);}
soxr_error_t src_reset(soxr_t p) {return soxr_clear(p);}
soxr_t src_delete(soxr_t p) {soxr_delete(p); return 0;}
soxr_error_t src_set_ratio(soxr_t p, double oi_ratio) {return soxr_set_oi_ratio(p, oi_ratio);}
soxr_error_t src_set_ratio(soxr_t p, double oi_ratio) {return soxr_set_io_ratio(p, 1/oi_ratio, 0);}
soxr_t src_new(unsigned id, int channels, SRC_ERROR * error) {return src_callback_new(0, id, channels, error, 0);}

View File

@@ -4,18 +4,17 @@
/* Resample using a non-interpolated poly-phase FIR with length LEN.*/
/* Input must be followed by LEN-1 samples. */
#define _ sum += (coef(p->shared->poly_fir_coefs, 0, FIR_LENGTH, divided.rem, 0, j)) *at[j], ++j;
#define _ sum += (coef(p->shared->poly_fir_coefs, 0, FIR_LENGTH, rem, 0, j)) *at[j], ++j;
static void FUNCTION(stage_t * p, fifo_t * output_fifo)
{
sample_t const * input = stage_read_p(p);
int i, num_in = stage_occupancy(p), max_num_out = 1 + (int)(num_in*p->out_in_ratio);
sample_t * output = fifo_reserve(output_fifo, max_num_out);
div_t divided2;
for (i = 0; p->at.integer < num_in * p->L; ++i, p->at.integer += p->step.integer) {
div_t divided = div(p->at.integer, p->L);
sample_t const * at = input + divided.quot;
int div = p->at.integer / p->L, rem = p->at.integer % p->L;
sample_t const * at = input + div;
sample_t sum = 0;
int j = 0;
CONVOLVE
@@ -23,9 +22,8 @@ static void FUNCTION(stage_t * p, fifo_t * output_fifo)
}
assert(max_num_out - i >= 0);
fifo_trim_by(output_fifo, max_num_out - i);
divided2 = div(p->at.integer, p->L);
fifo_read(&p->fifo, divided2.quot, NULL);
p->at.integer = divided2.rem;
fifo_read(&p->fifo, p->at.integer / p->L, NULL);
p->at.integer = p->at.integer % p->L;
}
#undef _

View File

@@ -431,9 +431,9 @@ static char const * rate_init(
double d, epsilon = 0, frac;
upsample = arbM < 1;
for (i = (int)(arbM * .5), shift = 0; i >>= 1; arbM *= .5, ++shift);
preM = 1 - (arbM > 2);
postM = 1 + (arbM > 1 && arbM < 2), arbM /= postM;
preL = 1 + (upsample && mode), arbM *= preL;
preM = upsample || (arbM > 1.5 && arbM < 2);
postM = 1 + (arbM > 1 && preM), arbM /= postM;
preL = 1 + (!preM && arbM < 2) + (upsample && mode), arbM *= preL;
if ((frac = arbM - (int)arbM))
epsilon = fabs((uint32_t)(frac * MULT32 + .5) / (frac * MULT32) - 1);
for (i = 1, rational = !frac; i <= maxL && !rational; ++i) {
@@ -632,7 +632,7 @@ static void rate_flush(rate_t * p)
size_t remaining = (size_t)(samples_out - p->samples_out);
sample_t * buff = calloc(1024, sizeof(*buff));
if ((int)remaining > 0) {
if (samples_out > p->samples_out) {
while ((size_t)fifo_occupancy(fifo) < remaining) {
rate_input(p, buff, 1024);
rate_process(p);
@@ -690,14 +690,14 @@ static void rate_sizes(size_t * shared, size_t * channel)
static char const * rate_create(
void * channel,
void * shared,
double oi_ratio,
double io_ratio,
soxr_quality_spec_t * q_spec,
soxr_runtime_spec_t * r_spec,
double scale)
{
return rate_init(
channel, shared,
1 / oi_ratio,
io_ratio,
q_spec->bits,
q_spec->phase,
q_spec->bw_pc,
@@ -728,7 +728,7 @@ fn_t RATE_CB[] = {
(fn_t)rate_delay,
(fn_t)rate_sizes,
(fn_t)rate_create,
0,
(fn_t)0,
(fn_t)id,
};
#endif

View File

@@ -29,9 +29,9 @@ typedef struct {
void (* close)(void *);
double (* delay)(void *);
void (* sizes)(size_t * shared, size_t * channel);
char const * (* create)(void * channel, void * shared, double oi_ratio,
char const * (* create)(void * channel, void * shared, double io_ratio,
soxr_quality_spec_t * q_spec, soxr_runtime_spec_t * r_spec, double scale);
void (* set_oi_ratio)(void *, double oi_ratio);
void (* set_io_ratio)(void *, double io_ratio, size_t len);
char const * (* id)(void);
} control_block_t;
@@ -43,7 +43,7 @@ typedef struct {
#define resampler_delay (*p->control_block.delay)
#define resampler_sizes (*p->control_block.sizes)
#define resampler_create (*p->control_block.create)
#define resampler_set_oi_ratio (*p->control_block.set_oi_ratio)
#define resampler_set_io_ratio (*p->control_block.set_io_ratio)
#define resampler_id (*p->control_block.id)
@@ -57,7 +57,7 @@ typedef size_t (* interleave_t)(soxr_datatype_t data_type, void * * dest,
struct soxr {
unsigned num_channels;
double oi_ratio;
double io_ratio;
soxr_error_t error;
soxr_quality_spec_t q_spec;
soxr_io_spec_t io_spec;
@@ -65,6 +65,7 @@ struct soxr {
void * input_fn_state;
soxr_input_fn_t input_fn;
size_t max_ilen;
resampler_shared_t shared;
resampler_t * resamplers;
@@ -217,7 +218,7 @@ soxr_t soxr_create(
soxr_quality_spec_t const * q_spec,
soxr_runtime_spec_t const * runtime_spec)
{
double oi_ratio = input_rate? output_rate? output_rate / input_rate : -1 : output_rate? -1 : 0;
double io_ratio = output_rate? input_rate? input_rate / output_rate : -1 : input_rate? -1 : 0;
static const float datatype_full_scale[] = {1, 1, 65536.*32768, 32768};
soxr_t p = 0;
soxr_error_t error = 0;
@@ -230,7 +231,7 @@ soxr_t soxr_create(
if (p) {
p->q_spec = q_spec? *q_spec : soxr_quality_spec(SOXR_HQ, 0);
p->oi_ratio = oi_ratio;
p->io_ratio = io_ratio;
p->num_channels = num_channels;
if (io_spec)
p->io_spec = *io_spec;
@@ -271,8 +272,8 @@ soxr_t soxr_create(
}
#endif
if (p->num_channels && oi_ratio)
error = soxr_set_oi_ratio(p, oi_ratio);
if (p->num_channels && io_ratio)
error = soxr_set_io_ratio(p, io_ratio, 0);
}
if (error)
soxr_delete(p), p = 0;
@@ -284,10 +285,11 @@ soxr_t soxr_create(
soxr_error_t soxr_set_input_fn(soxr_t p,
soxr_input_fn_t input_fn, void * input_fn_state)
soxr_input_fn_t input_fn, void * input_fn_state, size_t max_ilen)
{
p->input_fn_state = input_fn_state;
p->input_fn = input_fn;
p->max_ilen = max_ilen? max_ilen : (size_t)-1;
return 0;
}
@@ -345,7 +347,7 @@ static soxr_error_t initialise(soxr_t p)
error = resampler_create(
p->resamplers[i],
p->shared,
p->oi_ratio,
p->io_ratio,
&p->q_spec,
&p->runtime_spec,
p->io_spec.scale);
@@ -364,29 +366,29 @@ soxr_error_t soxr_set_num_channels(soxr_t p, unsigned num_channels)
if (!num_channels) return "invalid # of channels";
if (p->resamplers) return "# of channels can't be changed";
p->num_channels = num_channels;
return soxr_set_oi_ratio(p, p->oi_ratio);
return soxr_set_io_ratio(p, p->io_ratio, 0);
}
soxr_error_t soxr_set_oi_ratio(soxr_t p, double oi_ratio)
soxr_error_t soxr_set_io_ratio(soxr_t p, double io_ratio, size_t slew_len)
{
unsigned i;
soxr_error_t error;
if (!p) return "invalid soxr_t pointer";
if ((error = p->error)) return error;
if (!p->num_channels) return "must set # channels before O/I ratio";
if (oi_ratio <= 0) return "O/I ratio out-of-range";
if (io_ratio <= 0) return "I/O ratio out-of-range";
if (!p->channel_ptrs) {
p->oi_ratio = oi_ratio;
p->io_ratio = io_ratio;
return initialise(p);
}
if (p->control_block.set_oi_ratio) {
if (p->control_block.set_io_ratio) {
for (i = 0; !error && i < p->num_channels; ++i)
resampler_set_oi_ratio(p->resamplers[i], oi_ratio);
resampler_set_io_ratio(p->resamplers[i], io_ratio, slew_len);
return error;
}
return fabs(p->oi_ratio - oi_ratio) < 1e-15? 0 :
return fabs(p->io_ratio - io_ratio) < 1e-15? 0 :
"Varying O/I ratio is not supported with this quality level";
}
@@ -430,8 +432,7 @@ static void soxr_input_1ch(soxr_t p, unsigned i, soxr_cbuf_t src, size_t len)
size_t soxr_input(soxr_t p, void const * in, size_t len);
size_t soxr_input(soxr_t p, void const * in, size_t len)
static size_t soxr_input(soxr_t p, void const * in, size_t len)
{
bool separated = !!(p->io_spec.itype & SOXR_SPLIT);
unsigned i;
@@ -500,6 +501,7 @@ static size_t soxr_output_no_callback(soxr_t p, soxr_buf_t out, size_t len)
size_t soxr_output(soxr_t p, void * out, size_t len0)
{
size_t odone, odone0 = 0, olen = len0, osize, idone;
size_t ilen = min(p->max_ilen, (size_t)ceil((double)olen *p->io_ratio));
void const * in = out; /* Set to !=0, so that caller may leave unset. */
bool was_flushing;
@@ -509,13 +511,13 @@ size_t soxr_output(soxr_t p, void * out, size_t len0)
do {
odone = soxr_output_no_callback(p, out, olen);
odone0 += odone;
if (odone0 == len0 || !p->input_fn)
if (odone0 == len0 || !p->input_fn || p->flushing)
break;
osize = soxr_datatype_size(p->io_spec.otype) * p->num_channels;
out = (char *)out + osize * odone;
olen -= odone;
idone = p->input_fn(p->input_fn_state, &in, (size_t)ceil((double)olen /p->oi_ratio));
idone = p->input_fn(p->input_fn_state, &in, ilen);
was_flushing = p->flushing;
if (!in)
p->error = "input function reported failure";
@@ -534,17 +536,19 @@ static size_t soxr_i_for_o(soxr_t p, size_t olen, size_t ilen)
result = rate_i_for_o(p->resamplers[0], olen);
else
#endif
result = (size_t)ceil((double)olen / p->oi_ratio);
result = (size_t)ceil((double)olen * p->io_ratio);
return min(result, ilen);
}
#if 0
static size_t soxr_o_for_i(soxr_t p, size_t ilen, size_t olen)
{
size_t result = (size_t)ceil((double)ilen * p->oi_ratio);
size_t result = (size_t)ceil((double)ilen / p->io_ratio);
return min(result, olen);
}
#endif
@@ -563,10 +567,10 @@ soxr_error_t soxr_process(soxr_t p,
else {
if ((ptrdiff_t)ilen0 < 0)
flush_requested = true, ilen0 = ~ilen0;
if (1 || flush_requested)
if (idone0 && (1 || flush_requested))
ilen = soxr_i_for_o(p, olen, ilen0);
else
ilen = ilen0, olen = soxr_o_for_i(p, ilen, olen);
ilen = ilen0/*, olen = soxr_o_for_i(p, ilen, olen)*/;
}
p->flushing |= ilen == ilen0 && flush_requested;

View File

@@ -114,7 +114,7 @@ SOXR soxr_error_t soxr_process(
Note that no special meaning is associated with ilen or olen equal to
zero. End-of-input (i.e. no data is available nor shall be available)
may be indicated by seting in to zero. */
may be indicated by seting `in' to NULL. */
@@ -140,7 +140,8 @@ typedef size_t /* data_len */
SOXR soxr_error_t soxr_set_input_fn(/* Set (or reset) an input function.*/
soxr_t resampler, /* As returned by soxr_create. */
soxr_input_fn_t, /* Function to supply data to be resampled.*/
void * input_fn_state); /* If needed by the input function. */
void * input_fn_state, /* If needed by the input function. */
size_t max_ilen); /* Maximum value for input fn. requested_len.*/
/* then repeatedly call: */
@@ -178,6 +179,13 @@ SOXR soxr_error_t soxr_oneshot(
/* For variable-rate resampling (experimental). See example # 5 for how to
* create a variable-rate resampler and how to use this function. */
SOXR soxr_error_t soxr_set_io_ratio(soxr_t, double io_ratio, size_t slew_len);
/* -------------------------- API type definitions -------------------------- */
typedef enum { /* Datatypes supported for I/O to/from the resampler: */
@@ -226,7 +234,7 @@ struct soxr_quality_spec { /* Typically */
#define SOXR_MAINTAIN_3DB_PT 4u /* Reserved for internal use. */
#define SOXR_HI_PREC_CLOCK 8u /* Increase `irrational' ratio accuracy. */
#define SOXR_DOUBLE_PRECISION 16u /* Use double prec. even @ bitdepths <= 20.*/
#define SOXR_VR 32u /* Reserved for future use. */
#define SOXR_VR 32u /* Experimental, variable-rate resampling. */
@@ -244,7 +252,7 @@ struct soxr_runtime_spec { /* Typically */
#define SOXR_COEF_INTERP_HIGH 2u /* Man. select: more CPU, less memory. */
#define SOXR_STRICT_BUFFERING 4u /* Reserved for future use. */
#define SOXR_NOSMALLINTOPT 8u /* More CPU, less latency for 3/2, 3/4 etc.*/
#define SOXR_NOSMALLINTOPT 8u /* For test purposes only. */
@@ -298,7 +306,6 @@ SOXR soxr_io_spec_t soxr_io_spec(
SOXR soxr_error_t soxr_set_error(soxr_t, soxr_error_t);
SOXR soxr_error_t soxr_set_num_channels(soxr_t, unsigned);
SOXR soxr_error_t soxr_set_oi_ratio(soxr_t, double);

771
lib-src/libsoxr/src/vr32.c Normal file
View File

@@ -0,0 +1,771 @@
/* SoX Resampler Library Copyright (c) 2007-12 robs@users.sourceforge.net
* Licence for this file: LGPL v2.1 See LICENCE for details. */
/* Experimental variable-rate resampling. */
#include <assert.h>
#include <math.h>
#if !defined M_PI
#define M_PI 3.14159265358979323846
#endif
#if !defined M_LN2
#define M_LN2 0.69314718055994530942
#endif
#include <string.h>
#include <stdlib.h>
#include "internal.h"
#define FIFO_SIZE_T int
#define FIFO_MIN 0x8000
#include "fifo.h"
#define FADE_LEN_BITS 9
#define PHASE_BITS_D (8 + PHASE_MORE)
#define PHASE_BITS_U (7 + PHASE_MORE)
#define PHASE_MORE 0 /* 2 improves small int, and large u, ratios. */
#define PHASES0_D 12
#define POLY_FIR_LEN_D 20
#define PHASES0_U 6
#define POLY_FIR_LEN_U 12
#define MULT32 (65536. * 65536.)
#define PHASES_D (1 << PHASE_BITS_D)
#define PHASES_U (1 << PHASE_BITS_U)
static float const half_fir_coefs[] = {
4.7111692735253413e-1f, 3.1690797657656167e-1f, 2.8691667164678896e-2f,
-1.0192825848403946e-1f, -2.8122856237424654e-2f, 5.6804928137780292e-2f,
2.7192768359197508e-2f, -3.6082309197154230e-2f, -2.5927789156038026e-2f,
2.3644444384060669e-2f, 2.4363075319345607e-2f, -1.5127630198606428e-2f,
-2.2541790286342567e-2f, 8.8733836742880233e-3f, 2.0513077413933017e-2f,
-4.1186431656279818e-3f, -1.8330444480421631e-2f, 4.6288071358217028e-4f,
1.6049769308921290e-2f, 2.3282106680446069e-3f, -1.3727327353082214e-2f,
-4.4066375505196096e-3f, 1.1417847550661287e-2f, 5.8817724081355978e-3f,
-9.1727580349157123e-3f, -6.8404638339394346e-3f, 7.0385357033205332e-3f,
7.3574525331962567e-3f, -5.0554197628506353e-3f, -7.5008330890673153e-3f,
3.2563575907277676e-3f, 7.3346538206330259e-3f, -1.6663208501478607e-3f,
-6.9199171108861694e-3f, 3.0196567996023190e-4f, 6.3146436955438768e-3f,
8.2835711466756098e-4f, -5.5734271982033918e-3f, -1.7242765658561860e-3f,
4.7467223803576682e-3f, 2.3927523666941205e-3f, -3.8801054688632139e-3f,
-2.8472115748114728e-3f, 3.0135659731132642e-3f, 3.1064651802365259e-3f,
-2.1809660142807748e-3f, -3.1935061143485862e-3f, 1.4096923923208671e-3f,
3.1342382222281609e-3f, -7.2053095076414931e-4f, -2.9561940489039682e-3f,
1.2777585046118889e-4f, 2.6873033434313882e-3f, 3.6043554054680685e-4f,
-2.3547716396561816e-3f, -7.4160208709749312e-4f, 1.9840894915230177e-3f,
1.0181606831615856e-3f, -1.5982325266851590e-3f, -1.1966774804490967e-3f,
1.2170528733224913e-3f, 1.2869618709883193e-3f, -8.5687504489877664e-4f,
-1.3011452950496001e-3f, 5.3030588389885972e-4f, 1.2527854026453923e-3f,
-2.4622758430821288e-4f, -1.1560181289625195e-3f, 9.9661643910782316e-6f,
1.0247989665318426e-3f, 1.7639297561664703e-4f, -8.7226452073196350e-4f,
-3.1358436147401782e-4f, 7.1022054657665971e-4f, 4.0466151692224986e-4f,
-5.4877022848030636e-4f, -4.5444807961399138e-4f, 3.9609542800868769e-4f,
4.6899779918507020e-4f, -2.5835154936239735e-4f, -4.5505391611721792e-4f,
1.3970512544147175e-4f, 4.1957352577882777e-4f, -4.2458993694471047e-5f,
-3.6930861782460262e-4f, -3.2738549063278822e-5f, 3.1046609224355927e-4f,
8.6624679037202785e-5f, -2.4845427128026068e-4f, -1.2101300074995281e-4f,
1.8773208187021294e-4f, 1.3849844077872591e-4f, -1.3170611080827864e-4f,
-1.4212373327156217e-4f, 8.2758595879431528e-5f, 1.3513059684140468e-4f,
-4.2284127775471251e-5f, -1.2070298779675768e-4f, 1.0811692847491609e-5f,
1.0178008299781669e-4f, 1.1852545451857104e-5f, -8.0914539313342186e-5f,
-2.6454558961220653e-5f, 6.0208388858339534e-5f, 3.4169979203255580e-5f,
-4.1203296686185329e-5f, -3.6353143441156863e-5f, 2.4999186627094098e-5f,
3.4542829080466582e-5f, -1.2148053427488782e-5f, -3.0260855999161159e-5f,
2.7687092952335852e-6f, 2.5095689880235108e-5f, 3.6223160417538916e-6f,
-2.0960977068565079e-5f, -9.3312292092513232e-6f, 2.0711288605113663e-5f,
3.1992093654438569e-5f, 1.9772538588596925e-5f, 4.8667740603532560e-6f,
-5.3495033191567977e-7f,
};
#define CONVOLVE \
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
#define HALF_FIR_LEN_2 (iAL(half_fir_coefs) - 1)
#define HALF_FIR_LEN_4 (HALF_FIR_LEN_2 / 2)
#define _ sum += (input[-i] + input[i]) * half_fir_coefs[i], ++i;
static float half_fir(float const * input)
{
long i = 1;
float sum = input[0] * half_fir_coefs[0];
CONVOLVE CONVOLVE
assert(i == HALF_FIR_LEN_2 + 1);
return (float)sum;
}
#undef _
#define _ sum += (input[-i] + input[i]) * half_fir_coefs[2*i], ++i;
static float double_fir0(float const * input)
{
int i = 1;
float sum = input[0] * half_fir_coefs[0];
CONVOLVE
assert(i == HALF_FIR_LEN_4 + 1);
return (float)(sum * 2);
}
#undef _
#define _ sum += (input[-i] + input[1+i]) * half_fir_coefs[2*i+1], ++i;
static float double_fir1(float const * input)
{
int i = 0;
float sum = 0;
CONVOLVE
assert(i == HALF_FIR_LEN_4 + 0);
return (float)(sum * 2);
}
#undef _
static float fast_half_fir(float const * input)
{
static const float coefs[] = {
.3094188462713818f, -.08198144615199748f, .03055232105456833f,
-.01015890277986387f, .002513237297525149f, -.0003469672050347395f,
};
int i = 0;
float sum = input[0] * .5f;
#define _ sum += (input[-(2*i+1)] + input[2*i+1]) * coefs[i], ++i;
_ _ _ _ _ _
#undef _
return (float)sum;
}
static const float iir_coefs[] = {
.0262852045255816f, .0998310478296204f, .2068650611060755f,
.3302241336172489f, .4544203620946318f, .5685783569471244f,
.6669444657994612f, .7478697711807407f, .8123244036799226f,
.8626000999654434f, .9014277444199280f, .9314860567781748f,
.9551915287878752f, .9746617828910630f, .9917763050166036f,
};
#define IIR_FILTER _ _ _ _ _ _ _
#define _ in1=(in1-p->y[i])*iir_coefs[i]+tmp1;tmp1=p->y[i],p->y[i]=in1;++i;\
in0=(in0-p->y[i])*iir_coefs[i]+tmp0;tmp0=p->y[i],p->y[i]=in0;++i;
typedef struct {float x[2], y[AL(iir_coefs)];} half_iir_t;
static float half_iir1(half_iir_t * p, float in0, float in1)
{
int i = 0;
float tmp0, tmp1;
tmp0 = p->x[0], p->x[0] = in0;
tmp1 = p->x[1], p->x[1] = in1;
IIR_FILTER
p->y[i] = in1 = (in1 - p->y[i]) * iir_coefs[i] + tmp1;
return in1 + in0;
}
#undef _
static void half_iir(half_iir_t * p, float * obuf, float const * ibuf, int olen)
{
int i;
for (i=0; i < olen; obuf[i] = (float)half_iir1(p, ibuf[i*2], ibuf[i*2+1]),++i);
}
static void half_phase(half_iir_t * p, float * buf, int len)
{
float const small_normal = 1/MULT32/MULT32; /* To quash denormals on path 0.*/
int i;
for (i = 0; i < len; buf[i] = (float)half_iir1(p, buf[i], 0), ++i);
#define _ p->y[i] += small_normal, i += 2;
i = 0, _ IIR_FILTER
#undef _
#define _ p->y[i] -= small_normal, i += 2;
i = 0, _ IIR_FILTER
#undef _
}
#define raw_coef_t float
static const raw_coef_t coefs0_d[POLY_FIR_LEN_D / 2 * PHASES0_D + 1] = {
0.f, 1.4057457935754080e-5f, 2.3302768424632188e-5f, 4.0084897378442095e-5f,
6.1916773126231636e-5f, 8.7973434034929016e-5f, 1.1634847507082481e-4f,
1.4391931654629385e-4f, 1.6635470822160746e-4f, 1.7830838562749493e-4f,
1.7382737311735053e-4f, 1.4698011689178234e-4f, 9.2677933545427018e-5f,
7.6288745483685147e-6f, -1.0867156553965507e-4f, -2.5303924530322309e-4f,
-4.1793463959360433e-4f, -5.9118012513731508e-4f, -7.5619603440508576e-4f,
-8.9285245696990080e-4f, -9.7897684238178358e-4f, -9.9248131798952959e-4f,
-9.1398576537725926e-4f, -7.2972364732199553e-4f, -4.3443557115962946e-4f,
-3.3895523979487613e-5f, 4.5331297364457429e-4f, 9.9513966802111057e-4f,
1.5468348913161652e-3f, 2.0533350794358640e-3f, 2.4533031436958950e-3f,
2.6846707315385087e-3f, 2.6913237051575155e-3f, 2.4303724507982708e-3f,
1.8792817173578587e-3f, 1.0420231121204950e-3f, -4.6617252898486750e-5f,
-1.3193786988492551e-3f, -2.6781478874181100e-3f, -3.9992272197487003e-3f,
-5.1422613336274056e-3f, -5.9624224517967755e-3f, -6.3250283969908542e-3f,
-6.1213677360236101e-3f, -5.2841872043022185e-3f, -3.8011036067186429e-3f,
-1.7241752288145494e-3f, 8.2596463599396213e-4f, 3.6626436307478369e-3f,
6.5430316636724021e-3f, 9.1853404499045010e-3f, 1.1292516396583619e-2f,
1.2580791345879052e-2f, 1.2810714562937180e-2f, 1.1817712330677889e-2f,
9.5388893881204976e-3f, 6.0327678128662696e-3f, 1.4889921444742027e-3f,
-3.7742770128030593e-3f, -9.3265389310393538e-3f, -1.4654680466977541e-2f,
-1.9204813565928323e-2f, -2.2433342812570076e-2f, -2.3863084249865732e-2f,
-2.3139248817097825e-2f, -2.0079526147977360e-2f, -1.4712465100990968e-2f,
-7.2989072959128900e-3f, 1.6676055337427264e-3f, 1.1483818597217116e-2f,
2.1283378291010333e-2f, 3.0104924254589629e-2f, 3.6977102234817580e-2f,
4.1013752396638667e-2f, 4.1510805491867378e-2f, 3.8035383354576423e-2f,
3.0497421566956902e-2f, 1.9194910514469185e-2f, 4.8255960959712636e-3f,
-1.1539393212932630e-2f, -2.8521204184392364e-2f, -4.4535662544571142e-2f,
-5.7926040870466614e-2f, -6.7116245375785713e-2f, -7.0771566186484461e-2f,
-6.7952220045636696e-2f, -5.8244261062898019e-2f, -4.1853211028450271e-2f,
-1.9648003905967236e-2f, 6.8535507014343263e-3f, 3.5561844452076982e-2f,
6.3953651316164553e-2f, 8.9264185854578418e-2f, 1.0872025112127688e-1f,
1.1979689474056175e-1f, 1.2047646491371326e-1f, 1.0948710929592399e-1f,
8.6497869185231543e-2f, 5.2249701648862154e-2f, 8.6059406690018377e-3f,
-4.1488376792262582e-2f, -9.4141677945723271e-2f, -1.4474093381170536e-1f,
-1.8825408052888104e-1f, -2.1958987927558168e-1f, -2.3398931875783419e-1f,
-2.2741860176576378e-1f, -1.9693206642095332e-1f, -1.4097432039328661e-1f,
-5.9594435654526039e-2f, 4.5448949025739843e-2f, 1.7070477403312445e-1f,
3.1117273816011837e-1f, 4.6056631075658744e-1f, 6.1167961235662682e-1f,
7.5683349228721264e-1f, 8.8836924234920911e-1f, 9.9915393319190682e-1f,
1.0830597619389459e+0f, 1.1353812335460003e+0f, 1.1531583819295732e+0f,
};
static const raw_coef_t coefs0_u[POLY_FIR_LEN_U / 2 * PHASES0_U + 1] = {
0.f, 2.4376543962047211e-5f, 9.7074354091545404e-5f, 2.5656573977863553e-4f,
5.2734092391248152e-4f, 8.9078135146855391e-4f, 1.2494786883827907e-3f,
1.4060353542261659e-3f, 1.0794576035695273e-3f, -2.1547711862939183e-5f,
-2.0658693124381805e-3f, -4.9333908355966233e-3f, -8.0713165910440213e-3f,
-1.0451560117817383e-2f, -1.0703998868319438e-2f, -7.4626412699536097e-3f,
1.0898921033926621e-4f, 1.1734475997741493e-2f, 2.5579413661660957e-2f,
3.8168952738129619e-2f, 4.4846162998312754e-2f, 4.0821915377309274e-2f,
2.2679961923658700e-2f, -9.9957152600624218e-3f, -5.3343924460223908e-2f,
-9.8792607573741240e-2f, -1.3382736970823086e-1f, -1.4404307655147228e-1f,
-1.1619851747063137e-1f, -4.1649695271274462e-2f, 8.0680482815468343e-2f,
2.4264355486537642e-1f, 4.2712782955601925e-1f, 6.1041328492424185e-1f,
7.6625948559498691e-1f, 8.7088876549652772e-1f, 9.0774244518772884e-1f,
};
#define coef(coef_p, interp_order, fir_len, phase_num, coef_interp_num, \
fir_coef_num) coef_p[(fir_len) * ((interp_order) + 1) * (phase_num) + \
((interp_order) + 1) * (fir_coef_num) + (interp_order - coef_interp_num)]
#define COEF(h,l,i) ((i)<0||(i)>=(l)?0:(h)[(i)>(l)/2?(l)-(i):(i)])
static void prepare_coefs(float * coefs, int n, int phases0, int phases,
raw_coef_t const * coefs0, double multiplier)
{
double k[6];
int length0 = n * phases0, length = n * phases, K0 = iAL(k)/2 - 1, i, j, pos;
raw_coef_t * coefs1 = malloc(((size_t)length / 2 + 1) * sizeof(*coefs1));
raw_coef_t * p = coefs1, f0, f1 = 0;
for (j = 0; j < iAL(k); k[j] = COEF(coefs0, length0, j - K0), ++j);
for (pos = i = 0; i < length0 / 2; ++i) {
double b=(1/24.)*(k[0]+k[4]+6*k[2]-4*(k[1]+k[3])),d=.5*(k[1]+k[3])-k[2]-b;
double a=(1/120.)*(k[5]-k[2]-9*(9*b+d)+2.5*(k[3]-k[1])-2*(k[4]-k[0]));
double c=(1/12.)*(k[4]-k[0]-2*(k[3]-k[1])-60*a),e=.5*(k[3]-k[1])-a-c;
for (; pos / phases == i; pos += phases0) {
double x = (double)(pos % phases) / phases;
*p++ = (raw_coef_t)(k[K0] + ((((a*x + b)*x + c)*x + d)*x + e)*x);
}
for (j = 0; j < iAL(k) - 1; k[j] = k[j + 1], ++j);
k[j] = COEF(coefs0, length0, i + iAL(k) / 2 + 1);
}
if (!(length & 1))
*p++ = (raw_coef_t)k[K0];
assert(p - coefs1 == length / 2 + 1);
for (i = 0; i < n; ++i) for (j = phases - 1; j >= 0; --j, f1 = f0) {
pos = (n - 1 - i) * phases + j;
f0 = COEF(coefs1, length, pos) * (raw_coef_t)multiplier;
coef(coefs, 1, n, j, 0, i) = (float)f0;
coef(coefs, 1, n, j, 1, i) = (float)(f1 - f0);
}
free(coefs1);
}
#define _ sum += (b *x + a)*input[i], ++i;
#define a (coef(poly_fir_coefs_d, 1, POLY_FIR_LEN_D, phase, 0,i))
#define b (coef(poly_fir_coefs_d, 1, POLY_FIR_LEN_D, phase, 1,i))
static float poly_fir_coefs_d[POLY_FIR_LEN_D * PHASES_D * 2];
static float poly_fir1_d(float const * input, uint32_t frac)
{
int i = 0, phase = (int)(frac >> (32 - PHASE_BITS_D));
float sum = 0, x = (float)(frac << PHASE_BITS_D) * (float)(1 / MULT32);
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
assert(i == POLY_FIR_LEN_D);
return (float)sum;
}
#undef a
#undef b
#define a (coef(poly_fir_coefs_u, 1, POLY_FIR_LEN_U, phase, 0,i))
#define b (coef(poly_fir_coefs_u, 1, POLY_FIR_LEN_U, phase, 1,i))
static float poly_fir_coefs_u[POLY_FIR_LEN_U * PHASES_U * 2];
static float poly_fir1_u(float const * input, uint32_t frac)
{
int i = 0, phase = (int)(frac >> (32 - PHASE_BITS_U));
float sum = 0, x = (float)(frac << PHASE_BITS_U) * (float)(1 / MULT32);
_ _ _ _ _ _ _ _ _ _ _ _
assert(i == POLY_FIR_LEN_U);
return (float)sum;
}
#undef a
#undef b
#undef _
#define ADD_TO(x,y) x.all += y.all
#define SUBTRACT_FROM(x,y) x.all -= y.all
#define FRAC(x) x.part.frac
#define INT(x) x.part.integer
typedef struct {
union {
int64_t all;
#if WORDS_BIGENDIAN
struct {int32_t integer; uint32_t frac;} part;
#else
struct {uint32_t frac; int32_t integer;} part;
#endif
} at, step, step_step;
float const * input;
int len, stage_num;
bool is_d; /* true: downsampling at x2 rate; false: upsampling at 1x rate. */
double step_mult;
} stream_t;
static int poly_fir_d(stream_t * s, float * output, int olen)
{
int i;
float const * input = s->input - POLY_FIR_LEN_D / 2 + 1;
for (i = 0; i < olen && INT(s->at) < s->len; ++i) {
output[i] = poly_fir1_d(input + INT(s->at), FRAC(s->at));
ADD_TO(s->at, s->step);
if (!(INT(s->at) < s->len)) {
SUBTRACT_FROM(s->at, s->step);
break;
}
output[++i] = poly_fir1_d(input + INT(s->at), FRAC(s->at));
ADD_TO(s->at, s->step);
ADD_TO(s->step, s->step_step);
}
return i;
}
static int poly_fir_fade_d(
stream_t * s, float const * vol, int step, float * output, int olen)
{
int i;
float const * input = s->input - POLY_FIR_LEN_D / 2 + 1;
for (i = 0; i < olen && INT(s->at) < s->len; ++i, vol += step) {
output[i] += *vol * poly_fir1_d(input + INT(s->at), FRAC(s->at));
ADD_TO(s->at, s->step);
if (!(INT(s->at) < s->len)) {
SUBTRACT_FROM(s->at, s->step);
break;
}
output[++i] += *(vol += step) * poly_fir1_d(input + INT(s->at),FRAC(s->at));
ADD_TO(s->at, s->step);
ADD_TO(s->step, s->step_step);
}
return i;
}
static int poly_fir_u(stream_t * s, float * output, int olen)
{
int i;
float const * input = s->input - POLY_FIR_LEN_U / 2 + 1;
for (i = 0; i < olen && INT(s->at) < s->len; ++i) {
output[i] = poly_fir1_u(input + INT(s->at), FRAC(s->at));
ADD_TO(s->at, s->step);
ADD_TO(s->step, s->step_step);
}
return i;
}
static int poly_fir_fade_u(
stream_t * s, float const * vol, int step, float * output, int olen)
{
int i;
float const * input = s->input - POLY_FIR_LEN_U / 2 + 1;
for (i = 0; i < olen && INT(s->at) < s->len; i += 2, vol += step) {
output[i] += *vol * poly_fir1_u(input + INT(s->at), FRAC(s->at));
ADD_TO(s->at, s->step);
ADD_TO(s->step, s->step_step);
}
return i;
}
#define shiftr(x,by) ((by) < 0? (x) << (-(by)) : (x) >> (by))
#define shiftl(x,by) shiftr(x,-(by))
#define stage_occupancy(s) (fifo_occupancy(&(s)->fifo) - 4*HALF_FIR_LEN_2)
#define stage_read_p(s) ((float *)fifo_read_ptr(&(s)->fifo) + 2*HALF_FIR_LEN_2)
#define stage_preload(s) memset(fifo_reserve(&(s)->fifo, (s)->preload), \
0, sizeof(float) * (size_t)(s)->preload);
typedef struct {
fifo_t fifo;
double step_mult;
int is_fast, x_fade_len, preload;
} stage_t;
typedef struct {
int num_stages0, num_stages, flushing;
int fade_len, slew_len, xfade, stage_inc, switch_stage_num;
double new_io_ratio, default_io_ratio;
stage_t * stages;
fifo_t output_fifo;
half_iir_t halfer;
stream_t current, fadeout; /* Current/fade-in, fadeout streams. */
} rate_t;
static float fade_coefs[(2 << FADE_LEN_BITS) + 1];
static void vr_init(rate_t * p, double default_io_ratio, int num_stages, double mult)
{
int i;
assert(num_stages >= 0);
memset(p, 0, sizeof(*p));
p->num_stages0 = num_stages;
p->num_stages = num_stages = max(num_stages, 1);
p->stages = (stage_t *)calloc((unsigned)num_stages + 1, sizeof(*p->stages)) + 1;
for (i = -1; i < p->num_stages; ++i) {
stage_t * s = &p->stages[i];
fifo_create(&s->fifo, sizeof(float));
s->step_mult = 2 * MULT32 / shiftl(2, i);
s->preload = i < 0? 0 : i == 0? 2 * HALF_FIR_LEN_2 : 3 * HALF_FIR_LEN_2 / 2;
stage_preload(s);
s->is_fast = true;
lsx_debug("%-3i preload=%i", i, s->preload);
}
fifo_create(&p->output_fifo, sizeof(float));
p->default_io_ratio = default_io_ratio;
if (!fade_coefs[0]) {
for (i = 0; i < iAL(fade_coefs); ++i)
fade_coefs[i] = (float)(.5 * (1 + cos(M_PI * i / (AL(fade_coefs) - 1))));
prepare_coefs(poly_fir_coefs_u, POLY_FIR_LEN_U, PHASES0_U, PHASES_U, coefs0_u, mult);
prepare_coefs(poly_fir_coefs_d, POLY_FIR_LEN_D, PHASES0_D, PHASES_D, coefs0_d, mult *.5);
}
assert(fade_coefs[0]);
}
static void enter_new_stage(rate_t * p, int occupancy0)
{
p->current.len = shiftr(occupancy0, p->current.stage_num);
p->current.input = stage_read_p(&p->stages[p->current.stage_num]);
p->current.step_mult = p->stages[p->current.stage_num].step_mult;
p->current.is_d = p->current.stage_num >= 0;
if (p->current.is_d)
p->current.step_mult *= .5;
}
static void set_step(stream_t * p, double io_ratio)
{
p->step.all = (int64_t)(io_ratio * p->step_mult + .5);
}
static bool set_step_step(stream_t * p, double io_ratio, int slew_len)
{
int64_t dif;
int difi;
stream_t tmp = *p;
set_step(&tmp, io_ratio);
dif = tmp.step.all - p->step.all;
dif = dif < 0? dif - (slew_len >> 1) : dif + (slew_len >> 1);
difi = (int)dif; /* Try to avoid int64_t div. */
p->step_step.all = difi == dif? difi / slew_len : dif / slew_len;
return p->step_step.all != 0;
}
static void vr_set_io_ratio(rate_t * p, double io_ratio, size_t slew_len)
{
assert(io_ratio > 0);
if (slew_len) {
if (!set_step_step(&p->current, io_ratio, p->slew_len = (int)slew_len))
p->slew_len = 0, p->new_io_ratio = 0, p->fadeout.step_step.all = 0;
else {
p->new_io_ratio = io_ratio;
if (p->fade_len)
set_step_step(&p->fadeout, io_ratio, p->slew_len);
}
}
else {
if (p->default_io_ratio) { /* Then this is the first call to this fn. */
int octave = (int)floor(log(io_ratio) / M_LN2);
p->current.stage_num = octave < 0? -1 : min(octave, p->num_stages0-1);
enter_new_stage(p, 0);
}
else if (p->fade_len)
set_step(&p->fadeout, io_ratio);
set_step(&p->current, io_ratio);
if (p->default_io_ratio) FRAC(p->current.at) = FRAC(p->current.step) >> 1;
p->default_io_ratio = 0;
}
}
static bool do_input_stage(rate_t * p, int stage_num, int sign, int min_stage_num)
{
int i = 0;
float * dest;
stage_t * s = &p->stages[stage_num];
stage_t * s1 = &p->stages[stage_num - sign];
float const * src = (float *)fifo_read_ptr(&s1->fifo) + HALF_FIR_LEN_2;
int len = shiftr(fifo_occupancy(&s1->fifo) - HALF_FIR_LEN_2 * 2, sign);
int already_done = fifo_occupancy(&s->fifo) - s->preload;
if ((len -= already_done) <= 0)
return false;
src += shiftl(already_done, sign);
dest = fifo_reserve(&s->fifo, len);
if (stage_num < 0) for (; i < len; ++src)
dest[i++] = double_fir0(src), dest[i++] = double_fir1(src);
else {
bool should_be_fast = p->stage_inc;
if (!s->x_fade_len && stage_num == p->switch_stage_num) {
p->switch_stage_num = 0;
if (s->is_fast != should_be_fast) {
s->x_fade_len = 1 << FADE_LEN_BITS, s->is_fast = should_be_fast, ++p->xfade;
lsx_debug("xfade level %i, inc?=%i", stage_num, p->stage_inc);
}
}
if (s->x_fade_len) {
float const * vol1 = fade_coefs + (s->x_fade_len << 1);
float const * vol2 = fade_coefs + (((1 << FADE_LEN_BITS) - s->x_fade_len) << 1);
int n = min(len, s->x_fade_len);
/*lsx_debug("xfade level %i, inc?=%i len=%i n=%i", stage_num, p->stage_inc, s->x_fade_len, n);*/
if (should_be_fast)
for (; i < n; vol2 += 2, vol1 -= 2, src += 2)
dest[i++] = *vol1 * fast_half_fir(src) + *vol2 * half_fir(src);
else for (; i < n; vol2 += 2, vol1 -= 2, src += 2)
dest[i++] = *vol2 * fast_half_fir(src) + *vol1 * half_fir(src);
s->x_fade_len -= n;
p->xfade -= !s->x_fade_len;
}
if (stage_num < min_stage_num)
for (; i < len; dest[i++] = fast_half_fir(src), src += 2);
else for (; i < len; dest[i++] = half_fir(src), src += 2);
}
if (p->flushing > 0)
stage_preload(s);
return true;
}
static int vr_process(rate_t * p, int olen0)
{
assert(p->num_stages > 0);
if (p->default_io_ratio)
vr_set_io_ratio(p, p->default_io_ratio, 0);
{
float * output = fifo_reserve(&p->output_fifo, olen0);
int j, odone0 = 0, min_stage_num = p->current.stage_num;
int occupancy0, max_stage_num = min_stage_num;
if (p->fade_len) {
min_stage_num = min(min_stage_num, p->fadeout.stage_num);
max_stage_num = max(max_stage_num, p->fadeout.stage_num);
}
for (j = min(min_stage_num, 0); j <= max_stage_num; ++j)
if (j && !do_input_stage(p, j, j < 0? -1 : 1, min_stage_num))
break;
if (p->flushing > 0)
p->flushing = -1;
occupancy0 = shiftl(max(0,stage_occupancy(&p->stages[max_stage_num])), max_stage_num);
p->current.len = shiftr(occupancy0, p->current.stage_num);
p->current.input = stage_read_p(&p->stages[p->current.stage_num]);
if (p->fade_len) {
p->fadeout.len = shiftr(occupancy0, p->fadeout.stage_num);
p->fadeout.input = stage_read_p(&p->stages[p->fadeout.stage_num]);
}
while (odone0 < olen0) {
int odone, odone2, olen = olen0 - odone0, stage_dif = 0, shift;
float buf[64 << 1];
olen = min(olen, (int)(AL(buf) >> 1));
if (p->slew_len)
olen = min(olen, p->slew_len);
else if (p->new_io_ratio) {
set_step(&p->current, p->new_io_ratio);
set_step(&p->fadeout, p->new_io_ratio);
p->fadeout.step_step.all = p->current.step_step.all = 0;
p->new_io_ratio = 0;
}
if (!p->flushing && !p->fade_len && !p->xfade) {
if (p->current.is_d) {
if (INT(p->current.step) && FRAC(p->current.step))
stage_dif = 1, ++max_stage_num;
else if (!INT(p->current.step) && FRAC(p->current.step) < (1u << 31))
stage_dif = -1, --min_stage_num;
} else if (INT(p->current.step) > 1 && FRAC(p->current.step))
stage_dif = 1, ++max_stage_num;
}
if (stage_dif) {
int n = p->current.stage_num + stage_dif;
if (n >= p->num_stages)
--max_stage_num;
else {
p->stage_inc = stage_dif > 0;
p->fadeout = p->current;
p->current.stage_num += stage_dif;
if (!p->stage_inc)
p->switch_stage_num = p->current.stage_num;
if ((p->current.stage_num < 0 && stage_dif < 0) ||
(p->current.stage_num > 0 && stage_dif > 0)) {
stage_t * s = &p->stages[p->current.stage_num];
fifo_clear(&s->fifo);
stage_preload(s);
s->is_fast = false;
do_input_stage(p, p->current.stage_num, stage_dif, p->current.stage_num);
}
if (p->current.stage_num > 0 && stage_dif < 0) {
int idone = INT(p->current.at);
stage_t * s = &p->stages[p->current.stage_num];
fifo_trim_to(&s->fifo, 2 * HALF_FIR_LEN_2 + idone + (POLY_FIR_LEN_D >> 1));
do_input_stage(p, p->current.stage_num, 1, p->current.stage_num);
}
enter_new_stage(p, occupancy0);
shift = -stage_dif;
#define lshift(x,by) (x)=(by)>0?(x)<<(by):(x)>>-(by)
lshift(p->current.at.all, shift);
shift += p->fadeout.is_d - p->current.is_d;
lshift(p->current.step.all, shift);
lshift(p->current.step_step.all, shift);
p->fade_len = AL(fade_coefs) - 1;
lsx_debug("switch from stage %i to %i, x2 from %i to %i", p->fadeout.stage_num, p->current.stage_num, p->fadeout.is_d, p->current.is_d);
}
}
if (p->fade_len) {
float const * vol1 = fade_coefs + p->fade_len;
float const * vol2 = fade_coefs + (iAL(fade_coefs) - 1 - p->fade_len);
int olen2 = (olen = min(olen, p->fade_len >> 1)) << 1;
/* x2 is more fine-grained so may fail to produce a pair of samples
* where x1 would not (the x1 second sample is a zero so is always
* available). So do x2 first, then feed odone to the second one. */
memset(buf, 0, sizeof(*buf) * (size_t)olen2);
if (p->current.is_d && p->fadeout.is_d) {
odone = poly_fir_fade_d(&p->current, vol1,-1, buf, olen2);
odone2 = poly_fir_fade_d(&p->fadeout, vol2, 1, buf, odone);
} else if (p->current.is_d) {
odone = poly_fir_fade_d(&p->current, vol1,-1, buf, olen2);
odone2 = poly_fir_fade_u(&p->fadeout, vol2, 2, buf, odone);
} else {
assert(p->fadeout.is_d);
odone = poly_fir_fade_d(&p->fadeout, vol2, 1, buf, olen2);
odone2 = poly_fir_fade_u(&p->current, vol1,-2, buf, odone);
}
assert(odone == odone2);
(void)odone2;
p->fade_len -= odone;
if (!p->fade_len) {
if (p->stage_inc)
p->switch_stage_num = min_stage_num++;
else
--max_stage_num;
}
half_iir(&p->halfer, &output[odone0], buf, odone >>= 1);
}
else if (p->current.is_d) {
odone = poly_fir_d(&p->current, buf, olen << 1) >> 1;
half_iir(&p->halfer, &output[odone0], buf, odone);
}
else {
odone = poly_fir_u(&p->current, &output[odone0], olen);
if (p->num_stages0)
half_phase(&p->halfer, &output[odone0], odone);
}
odone0 += odone;
if (p->slew_len)
p->slew_len -= odone;
if (odone != olen)
break; /* Need more input. */
} {
int from = max(0, max_stage_num), to = min(0, min_stage_num);
int i, idone = shiftr(INT(p->current.at), from - p->current.stage_num);
INT(p->current.at) -= shiftl(idone, from - p->current.stage_num);
if (p->fade_len)
INT(p->fadeout.at) -= shiftl(idone, from - p->fadeout.stage_num);
for (i = from; i >= to; --i, idone <<= 1)
fifo_read(&p->stages[i].fifo, idone, NULL);
}
fifo_trim_by(&p->output_fifo, olen0 - odone0);
return odone0;
}
}
static float * vr_input(rate_t * p, float const * input, size_t n)
{
return fifo_write(&p->stages[0].fifo, (int)n, input);
}
static float const * vr_output(rate_t * p, float * output, size_t * n)
{
fifo_t * fifo = &p->output_fifo;
if (1 || !p->num_stages0)
return fifo_read(fifo, (int)(*n = min(*n, (size_t)fifo_occupancy(fifo))), output);
else { /* Ignore this complication for now. */
int const IIR_DELAY = 2;
float * ptr = fifo_read_ptr(fifo);
int olen = min((int)*n, max(0, fifo_occupancy(fifo) - IIR_DELAY));
*n = (size_t)olen;
if (output)
memcpy(output, ptr + IIR_DELAY, *n * sizeof(*output));
fifo_read(fifo, olen, NULL);
return ptr + IIR_DELAY;
}
}
static void vr_flush(rate_t * p)
{
if (!p->flushing) {
stage_preload(&p->stages[0]);
++p->flushing;
}
}
static void vr_close(rate_t * p)
{
int i;
fifo_delete(&p->output_fifo);
for (i = -1; i < p->num_stages; ++i) {
stage_t * s = &p->stages[i];
fifo_delete(&s->fifo);
}
free(p->stages - 1);
}
static double vr_delay(rate_t * p)
{
return 100; /* TODO */
(void)p;
}
static void vr_sizes(size_t * shared, size_t * channel)
{
*shared = 0;
*channel = sizeof(rate_t);
}
static char const * vr_create(void * channel, void * shared,double max_io_ratio,
void * q_spec, void * r_spec, double scale)
{
double x = max_io_ratio;
int n;
for (n = 0; x > 1; x *= .5, ++n);
vr_init(channel, max_io_ratio, n, scale);
return 0;
(void)shared, (void)q_spec, (void)r_spec;
}
static char const * vr_id(void)
{
return "single-precision variable-rate";
}
typedef void (* fn_t)(void);
fn_t _soxr_vr32_cb[] = {
(fn_t)vr_input,
(fn_t)vr_process,
(fn_t)vr_output,
(fn_t)vr_flush,
(fn_t)vr_close,
(fn_t)vr_delay,
(fn_t)vr_sizes,
(fn_t)vr_create,
(fn_t)vr_set_io_ratio,
(fn_t)vr_id,
};

View File

@@ -7,7 +7,7 @@ else ()
set (quality 44)
endif ()
execute_process(COMMAND ${EXAMPLES_BIN}3b-options-with-input-fn ${from} ${to} 1 2 2 ${quality} a
execute_process(COMMAND ${EXAMPLES_BIN}3-options-input-fn ${from} ${to} 1 2 2 ${quality} a
INPUT_FILE ref-${from}.s32
OUTPUT_FILE ${from}-${to}.s32
ERROR_VARIABLE test_error
@@ -15,8 +15,6 @@ execute_process(COMMAND ${EXAMPLES_BIN}3b-options-with-input-fn ${from} ${to} 1
if (test_result)
message (FATAL_ERROR "Resampling failure: ${test_error}")
#else ()
#message (STATUS ${test_error})
endif ()
execute_process(COMMAND ${BIN}vector-cmp ref-${to}.s32 ${from}-${to}.s32 ${to} ${leader} ${len} ${bits} 98

View File

@@ -5,17 +5,25 @@
len=8
#vg="valgrind --leak-check=full --show-reachable=yes"
$vg ./1-single-block
ir=96000
or=44100
for i in 1 2; do
prev=""
sox -r $ir -n 0.f32 synth $len sin 0+`expr $ir / 2`
for f in `find ../examples -type f -executable -name "[2-4]*"`; do
$vg $f $ir $or < 0.f32 > $f.f32
test x$prev != x && cmp $f.f32 $prev
prev=$f.f32
done
or=96000
ir=44100
prev=""
sox -r $ir -n 0.f32 synth $len sin 0+`expr $ir / 2`
for f in `find . -type f -executable -name "[2-4]*"`; do
$vg $f $ir $or < 0.f32 > $f.f32
test x$prev != x && cmp $f.f32 $prev
prev=$f.f32
done
or=96000
ir=44100
done
rm *.f32
rm ?.png
for n in 0 1 2 3; do
$vg ./5-variable-rate $n | sox -tf32 -r44100 -c1 - -n spectrogram -hwk -o $n.png -X 50
vg=""
done

View File

@@ -4,23 +4,22 @@
ir=96000
or=44100
len=8
f=3k
len=16
f=0+48k
g=48k+0
ex=../examples/3b-options-with-input-fn
ex=./3-options-input-fn
types=(f32 f64 s32 s16)
do_one() {
$ex $ir $or $c $1 $2 $3 < $c.${types[$1]} |
sox -t ${types[$2]} -r $or -c $c - -n spectrogram -X85 -hwk -z180 -o $n$c.png
sox -t ${types[$2]} -r $or -c $c - -n spectrogram -X50 -hwk -z180 -o io$n$c.png
n=`expr $n + 1`
}
rm *.png
rm io??.png
j=1; test z$1 != z && j=$1
j=2; test z$1 != z && j=$1
for c in `seq 1 $j`; do
for n in `seq 0 3`; do
@@ -39,5 +38,3 @@ for c in `seq 1 $j`; do
done
rm ?.[sf][0-9][0-9]
#kv . 2> /dev/null

View File

@@ -5,9 +5,17 @@
# Warning: the intermediate signal (piped) is 3.2 Gbytes so may slug the
# system somewhat.
ex=../examples/3b-options-with-input-fn
ex=./3-options-input-fn
q=6
rm lr.png
./vector-gen 1000 0 8 500 .9375 1.s32
$ex 1 1e5 1 2 1 $q < 1.s32 | $ex 1e5 1 1 1 2 $q > 2.s32
/usr/bin/sox -M -r 1k 1.s32 -r 1k 2.s32 -n spectrogram -hwk -z180 -o 2.png
display 2.png &
/usr/bin/sox -M -r 1k 1.s32 -r 1k 2.s32 -n spectrogram -hwk -z180 -o lr.png
display lr.png &
rm [12].s32

View File

@@ -1,9 +1,10 @@
/* SoX Resampler Library Copyright (c) 2012 robs@users.sourceforge.net
/* SoX Resampler Library Copyright (c) 2007-12 robs@users.sourceforge.net
* Licence for this file: LGPL v2.1 See LICENCE for details. */
/* Utility used to help test the library; not for general consumption.
*
* Utility used to help test the library; not for general consumption.
*
* Compare two swept-sine files.
*/
* Compare two swept-sine files. */
#include <stdlib.h>
#include <stdio.h>
#include <math.h>