[vlc-devel] [PATCH 3/3] audio_filter: SOFAlizer new module (libs)
Wolfgang Hrauda
wolfgang.hrauda at gmx.at
Tue May 12 12:33:03 CEST 2015
The code in this patch provides audio resampling and FFT functionality to SOFAlizer. Some large source files (e.g. resampling filter coefficients) are ommited in this post due to size constraints.
See PATCH 1 for more information on this audio filter module.
---
modules/audio_filter/sofalizer/fft/COPYING | 11 +
modules/audio_filter/sofalizer/fft/kiss_fft.c | 408 +++++++++++++++
modules/audio_filter/sofalizer/fft/kiss_fft.h | 124 +++++
modules/audio_filter/sofalizer/resampling/common.h | 169 +++++++
.../audio_filter/sofalizer/resampling/samplerate.c | 545 +++++++++++++++++++++
.../audio_filter/sofalizer/resampling/samplerate.h | 197 ++++++++
6 files changed, 1454 insertions(+)
create mode 100644 modules/audio_filter/sofalizer/fft/COPYING
create mode 100644 modules/audio_filter/sofalizer/fft/kiss_fft.c
create mode 100644 modules/audio_filter/sofalizer/fft/kiss_fft.h
create mode 100644 modules/audio_filter/sofalizer/resampling/common.h
create mode 100644 modules/audio_filter/sofalizer/resampling/samplerate.c
create mode 100644 modules/audio_filter/sofalizer/resampling/samplerate.h
diff --git a/modules/audio_filter/sofalizer/fft/COPYING b/modules/audio_filter/sofalizer/fft/COPYING
new file mode 100644
index 0000000..2fc6685
--- /dev/null
+++ b/modules/audio_filter/sofalizer/fft/COPYING
@@ -0,0 +1,11 @@
+Copyright (c) 2003-2010 Mark Borgerding
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+ * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/modules/audio_filter/sofalizer/fft/kiss_fft.c b/modules/audio_filter/sofalizer/fft/kiss_fft.c
new file mode 100644
index 0000000..465d6c9
--- /dev/null
+++ b/modules/audio_filter/sofalizer/fft/kiss_fft.c
@@ -0,0 +1,408 @@
+/*
+Copyright (c) 2003-2010, Mark Borgerding
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+ * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include "_kiss_fft_guts.h"
+/* The guts header contains all the multiplication and addition macros that are defined for
+ fixed or floating point complex numbers. It also delares the kf_ internal functions.
+ */
+
+static void kf_bfly2(
+ kiss_fft_cpx * Fout,
+ const size_t fstride,
+ const kiss_fft_cfg st,
+ int m
+ )
+{
+ kiss_fft_cpx * Fout2;
+ kiss_fft_cpx * tw1 = st->twiddles;
+ kiss_fft_cpx t;
+ Fout2 = Fout + m;
+ do{
+ C_FIXDIV(*Fout,2); C_FIXDIV(*Fout2,2);
+
+ C_MUL (t, *Fout2 , *tw1);
+ tw1 += fstride;
+ C_SUB( *Fout2 , *Fout , t );
+ C_ADDTO( *Fout , t );
+ ++Fout2;
+ ++Fout;
+ }while (--m);
+}
+
+static void kf_bfly4(
+ kiss_fft_cpx * Fout,
+ const size_t fstride,
+ const kiss_fft_cfg st,
+ const size_t m
+ )
+{
+ kiss_fft_cpx *tw1,*tw2,*tw3;
+ kiss_fft_cpx scratch[6];
+ size_t k=m;
+ const size_t m2=2*m;
+ const size_t m3=3*m;
+
+
+ tw3 = tw2 = tw1 = st->twiddles;
+
+ do {
+ C_FIXDIV(*Fout,4); C_FIXDIV(Fout[m],4); C_FIXDIV(Fout[m2],4); C_FIXDIV(Fout[m3],4);
+
+ C_MUL(scratch[0],Fout[m] , *tw1 );
+ C_MUL(scratch[1],Fout[m2] , *tw2 );
+ C_MUL(scratch[2],Fout[m3] , *tw3 );
+
+ C_SUB( scratch[5] , *Fout, scratch[1] );
+ C_ADDTO(*Fout, scratch[1]);
+ C_ADD( scratch[3] , scratch[0] , scratch[2] );
+ C_SUB( scratch[4] , scratch[0] , scratch[2] );
+ C_SUB( Fout[m2], *Fout, scratch[3] );
+ tw1 += fstride;
+ tw2 += fstride*2;
+ tw3 += fstride*3;
+ C_ADDTO( *Fout , scratch[3] );
+
+ if(st->inverse) {
+ Fout[m].r = scratch[5].r - scratch[4].i;
+ Fout[m].i = scratch[5].i + scratch[4].r;
+ Fout[m3].r = scratch[5].r + scratch[4].i;
+ Fout[m3].i = scratch[5].i - scratch[4].r;
+ }else{
+ Fout[m].r = scratch[5].r + scratch[4].i;
+ Fout[m].i = scratch[5].i - scratch[4].r;
+ Fout[m3].r = scratch[5].r - scratch[4].i;
+ Fout[m3].i = scratch[5].i + scratch[4].r;
+ }
+ ++Fout;
+ }while(--k);
+}
+
+static void kf_bfly3(
+ kiss_fft_cpx * Fout,
+ const size_t fstride,
+ const kiss_fft_cfg st,
+ size_t m
+ )
+{
+ size_t k=m;
+ const size_t m2 = 2*m;
+ kiss_fft_cpx *tw1,*tw2;
+ kiss_fft_cpx scratch[5];
+ kiss_fft_cpx epi3;
+ epi3 = st->twiddles[fstride*m];
+
+ tw1=tw2=st->twiddles;
+
+ do{
+ C_FIXDIV(*Fout,3); C_FIXDIV(Fout[m],3); C_FIXDIV(Fout[m2],3);
+
+ C_MUL(scratch[1],Fout[m] , *tw1);
+ C_MUL(scratch[2],Fout[m2] , *tw2);
+
+ C_ADD(scratch[3],scratch[1],scratch[2]);
+ C_SUB(scratch[0],scratch[1],scratch[2]);
+ tw1 += fstride;
+ tw2 += fstride*2;
+
+ Fout[m].r = Fout->r - HALF_OF(scratch[3].r);
+ Fout[m].i = Fout->i - HALF_OF(scratch[3].i);
+
+ C_MULBYSCALAR( scratch[0] , epi3.i );
+
+ C_ADDTO(*Fout,scratch[3]);
+
+ Fout[m2].r = Fout[m].r + scratch[0].i;
+ Fout[m2].i = Fout[m].i - scratch[0].r;
+
+ Fout[m].r -= scratch[0].i;
+ Fout[m].i += scratch[0].r;
+
+ ++Fout;
+ }while(--k);
+}
+
+static void kf_bfly5(
+ kiss_fft_cpx * Fout,
+ const size_t fstride,
+ const kiss_fft_cfg st,
+ int m
+ )
+{
+ kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4;
+ int u;
+ kiss_fft_cpx scratch[13];
+ kiss_fft_cpx * twiddles = st->twiddles;
+ kiss_fft_cpx *tw;
+ kiss_fft_cpx ya,yb;
+ ya = twiddles[fstride*m];
+ yb = twiddles[fstride*2*m];
+
+ Fout0=Fout;
+ Fout1=Fout0+m;
+ Fout2=Fout0+2*m;
+ Fout3=Fout0+3*m;
+ Fout4=Fout0+4*m;
+
+ tw=st->twiddles;
+ for ( u=0; u<m; ++u ) {
+ C_FIXDIV( *Fout0,5); C_FIXDIV( *Fout1,5); C_FIXDIV( *Fout2,5); C_FIXDIV( *Fout3,5); C_FIXDIV( *Fout4,5);
+ scratch[0] = *Fout0;
+
+ C_MUL(scratch[1] ,*Fout1, tw[u*fstride]);
+ C_MUL(scratch[2] ,*Fout2, tw[2*u*fstride]);
+ C_MUL(scratch[3] ,*Fout3, tw[3*u*fstride]);
+ C_MUL(scratch[4] ,*Fout4, tw[4*u*fstride]);
+
+ C_ADD( scratch[7],scratch[1],scratch[4]);
+ C_SUB( scratch[10],scratch[1],scratch[4]);
+ C_ADD( scratch[8],scratch[2],scratch[3]);
+ C_SUB( scratch[9],scratch[2],scratch[3]);
+
+ Fout0->r += scratch[7].r + scratch[8].r;
+ Fout0->i += scratch[7].i + scratch[8].i;
+
+ scratch[5].r = scratch[0].r + S_MUL(scratch[7].r,ya.r) + S_MUL(scratch[8].r,yb.r);
+ scratch[5].i = scratch[0].i + S_MUL(scratch[7].i,ya.r) + S_MUL(scratch[8].i,yb.r);
+
+ scratch[6].r = S_MUL(scratch[10].i,ya.i) + S_MUL(scratch[9].i,yb.i);
+ scratch[6].i = -S_MUL(scratch[10].r,ya.i) - S_MUL(scratch[9].r,yb.i);
+
+ C_SUB(*Fout1,scratch[5],scratch[6]);
+ C_ADD(*Fout4,scratch[5],scratch[6]);
+
+ scratch[11].r = scratch[0].r + S_MUL(scratch[7].r,yb.r) + S_MUL(scratch[8].r,ya.r);
+ scratch[11].i = scratch[0].i + S_MUL(scratch[7].i,yb.r) + S_MUL(scratch[8].i,ya.r);
+ scratch[12].r = - S_MUL(scratch[10].i,yb.i) + S_MUL(scratch[9].i,ya.i);
+ scratch[12].i = S_MUL(scratch[10].r,yb.i) - S_MUL(scratch[9].r,ya.i);
+
+ C_ADD(*Fout2,scratch[11],scratch[12]);
+ C_SUB(*Fout3,scratch[11],scratch[12]);
+
+ ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4;
+ }
+}
+
+/* perform the butterfly for one stage of a mixed radix FFT */
+static void kf_bfly_generic(
+ kiss_fft_cpx * Fout,
+ const size_t fstride,
+ const kiss_fft_cfg st,
+ int m,
+ int p
+ )
+{
+ int u,k,q1,q;
+ kiss_fft_cpx * twiddles = st->twiddles;
+ kiss_fft_cpx t;
+ int Norig = st->nfft;
+
+ kiss_fft_cpx * scratch = (kiss_fft_cpx*)KISS_FFT_TMP_ALLOC(sizeof(kiss_fft_cpx)*p);
+
+ for ( u=0; u<m; ++u ) {
+ k=u;
+ for ( q1=0 ; q1<p ; ++q1 ) {
+ scratch[q1] = Fout[ k ];
+ C_FIXDIV(scratch[q1],p);
+ k += m;
+ }
+
+ k=u;
+ for ( q1=0 ; q1<p ; ++q1 ) {
+ int twidx=0;
+ Fout[ k ] = scratch[0];
+ for (q=1;q<p;++q ) {
+ twidx += fstride * k;
+ if (twidx>=Norig) twidx-=Norig;
+ C_MUL(t,scratch[q] , twiddles[twidx] );
+ C_ADDTO( Fout[ k ] ,t);
+ }
+ k += m;
+ }
+ }
+ KISS_FFT_TMP_FREE(scratch);
+}
+
+static
+void kf_work(
+ kiss_fft_cpx * Fout,
+ const kiss_fft_cpx * f,
+ const size_t fstride,
+ int in_stride,
+ int * factors,
+ const kiss_fft_cfg st
+ )
+{
+ kiss_fft_cpx * Fout_beg=Fout;
+ const int p=*factors++; /* the radix */
+ const int m=*factors++; /* stage's fft length/p */
+ const kiss_fft_cpx * Fout_end = Fout + p*m;
+
+#ifdef _OPENMP
+ // use openmp extensions at the
+ // top-level (not recursive)
+ if (fstride==1 && p<=5)
+ {
+ int k;
+
+ // execute the p different work units in different threads
+# pragma omp parallel for
+ for (k=0;k<p;++k)
+ kf_work( Fout +k*m, f+ fstride*in_stride*k,fstride*p,in_stride,factors,st);
+ // all threads have joined by this point
+
+ switch (p) {
+ case 2: kf_bfly2(Fout,fstride,st,m); break;
+ case 3: kf_bfly3(Fout,fstride,st,m); break;
+ case 4: kf_bfly4(Fout,fstride,st,m); break;
+ case 5: kf_bfly5(Fout,fstride,st,m); break;
+ default: kf_bfly_generic(Fout,fstride,st,m,p); break;
+ }
+ return;
+ }
+#endif
+
+ if (m==1) {
+ do{
+ *Fout = *f;
+ f += fstride*in_stride;
+ }while(++Fout != Fout_end );
+ }else{
+ do{
+ // recursive call:
+ // DFT of size m*p performed by doing
+ // p instances of smaller DFTs of size m,
+ // each one takes a decimated version of the input
+ kf_work( Fout , f, fstride*p, in_stride, factors,st);
+ f += fstride*in_stride;
+ }while( (Fout += m) != Fout_end );
+ }
+
+ Fout=Fout_beg;
+
+ // recombine the p smaller DFTs
+ switch (p) {
+ case 2: kf_bfly2(Fout,fstride,st,m); break;
+ case 3: kf_bfly3(Fout,fstride,st,m); break;
+ case 4: kf_bfly4(Fout,fstride,st,m); break;
+ case 5: kf_bfly5(Fout,fstride,st,m); break;
+ default: kf_bfly_generic(Fout,fstride,st,m,p); break;
+ }
+}
+
+/* facbuf is populated by p1,m1,p2,m2, ...
+ where
+ p[i] * m[i] = m[i-1]
+ m0 = n */
+static
+void kf_factor(int n,int * facbuf)
+{
+ int p=4;
+ double floor_sqrt;
+ floor_sqrt = floor( sqrt((double)n) );
+
+ /*factor out powers of 4, powers of 2, then any remaining primes */
+ do {
+ while (n % p) {
+ switch (p) {
+ case 4: p = 2; break;
+ case 2: p = 3; break;
+ default: p += 2; break;
+ }
+ if (p > floor_sqrt)
+ p = n; /* no more factors, skip to end */
+ }
+ n /= p;
+ *facbuf++ = p;
+ *facbuf++ = n;
+ } while (n > 1);
+}
+
+/*
+ *
+ * User-callable function to allocate all necessary storage space for the fft.
+ *
+ * The return value is a contiguous block of memory, allocated with malloc. As such,
+ * It can be freed with free(), rather than a kiss_fft-specific function.
+ * */
+kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem )
+{
+ kiss_fft_cfg st=NULL;
+ size_t memneeded = sizeof(struct kiss_fft_state)
+ + sizeof(kiss_fft_cpx)*(nfft-1); /* twiddle factors*/
+
+ if ( lenmem==NULL ) {
+ st = ( kiss_fft_cfg)KISS_FFT_MALLOC( memneeded );
+ }else{
+ if (mem != NULL && *lenmem >= memneeded)
+ st = (kiss_fft_cfg)mem;
+ *lenmem = memneeded;
+ }
+ if (st) {
+ int i;
+ st->nfft=nfft;
+ st->inverse = inverse_fft;
+
+ for (i=0;i<nfft;++i) {
+ const double pi=3.141592653589793238462643383279502884197169399375105820974944;
+ double phase = -2*pi*i / nfft;
+ if (st->inverse)
+ phase *= -1;
+ kf_cexp(st->twiddles+i, phase );
+ }
+
+ kf_factor(nfft,st->factors);
+ }
+ return st;
+}
+
+
+void kiss_fft_stride(kiss_fft_cfg st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int in_stride)
+{
+ if (fin == fout) {
+ //NOTE: this is not really an in-place FFT algorithm.
+ //It just performs an out-of-place FFT into a temp buffer
+ kiss_fft_cpx * tmpbuf = (kiss_fft_cpx*)KISS_FFT_TMP_ALLOC( sizeof(kiss_fft_cpx)*st->nfft);
+ kf_work(tmpbuf,fin,1,in_stride, st->factors,st);
+ memcpy(fout,tmpbuf,sizeof(kiss_fft_cpx)*st->nfft);
+ KISS_FFT_TMP_FREE(tmpbuf);
+ }else{
+ kf_work( fout, fin, 1,in_stride, st->factors,st );
+ }
+}
+
+void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout)
+{
+ kiss_fft_stride(cfg,fin,fout,1);
+}
+
+
+void kiss_fft_cleanup(void)
+{
+ // nothing needed any more
+}
+
+int kiss_fft_next_fast_size(int n)
+{
+ while(1) {
+ int m=n;
+ while ( (m%2) == 0 ) m/=2;
+ while ( (m%3) == 0 ) m/=3;
+ while ( (m%5) == 0 ) m/=5;
+ if (m<=1)
+ break; /* n is completely factorable by twos, threes, and fives */
+ n++;
+ }
+ return n;
+}
diff --git a/modules/audio_filter/sofalizer/fft/kiss_fft.h b/modules/audio_filter/sofalizer/fft/kiss_fft.h
new file mode 100644
index 0000000..64c50f4
--- /dev/null
+++ b/modules/audio_filter/sofalizer/fft/kiss_fft.h
@@ -0,0 +1,124 @@
+#ifndef KISS_FFT_H
+#define KISS_FFT_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ ATTENTION!
+ If you would like a :
+ -- a utility that will handle the caching of fft objects
+ -- real-only (no imaginary time component ) FFT
+ -- a multi-dimensional FFT
+ -- a command-line utility to perform ffts
+ -- a command-line utility to perform fast-convolution filtering
+
+ Then see kfc.h kiss_fftr.h kiss_fftnd.h fftutil.c kiss_fastfir.c
+ in the tools/ directory.
+*/
+
+#ifdef USE_SIMD
+# include <xmmintrin.h>
+# define kiss_fft_scalar __m128
+#define KISS_FFT_MALLOC(nbytes) _mm_malloc(nbytes,16)
+#define KISS_FFT_FREE _mm_free
+#else
+#define KISS_FFT_MALLOC malloc
+#define KISS_FFT_FREE free
+#endif
+
+
+#ifdef FIXED_POINT
+#include <sys/types.h>
+# if (FIXED_POINT == 32)
+# define kiss_fft_scalar int32_t
+# else
+# define kiss_fft_scalar int16_t
+# endif
+#else
+# ifndef kiss_fft_scalar
+/* default is float */
+# define kiss_fft_scalar float
+# endif
+#endif
+
+typedef struct {
+ kiss_fft_scalar r;
+ kiss_fft_scalar i;
+}kiss_fft_cpx;
+
+typedef struct kiss_fft_state* kiss_fft_cfg;
+
+/*
+ * kiss_fft_alloc
+ *
+ * Initialize a FFT (or IFFT) algorithm's cfg/state buffer.
+ *
+ * typical usage: kiss_fft_cfg mycfg=kiss_fft_alloc(1024,0,NULL,NULL);
+ *
+ * The return value from fft_alloc is a cfg buffer used internally
+ * by the fft routine or NULL.
+ *
+ * If lenmem is NULL, then kiss_fft_alloc will allocate a cfg buffer using malloc.
+ * The returned value should be free()d when done to avoid memory leaks.
+ *
+ * The state can be placed in a user supplied buffer 'mem':
+ * If lenmem is not NULL and mem is not NULL and *lenmem is large enough,
+ * then the function places the cfg in mem and the size used in *lenmem
+ * and returns mem.
+ *
+ * If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough),
+ * then the function returns NULL and places the minimum cfg
+ * buffer size in *lenmem.
+ * */
+
+kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem);
+
+/*
+ * kiss_fft(cfg,in_out_buf)
+ *
+ * Perform an FFT on a complex input buffer.
+ * for a forward FFT,
+ * fin should be f[0] , f[1] , ... ,f[nfft-1]
+ * fout will be F[0] , F[1] , ... ,F[nfft-1]
+ * Note that each element is complex and can be accessed like
+ f[k].r and f[k].i
+ * */
+void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout);
+
+/*
+ A more generic version of the above function. It reads its input from every Nth sample.
+ * */
+void kiss_fft_stride(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int fin_stride);
+
+/* If kiss_fft_alloc allocated a buffer, it is one contiguous
+ buffer and can be simply free()d when no longer needed*/
+#define kiss_fft_free free
+
+/*
+ Cleans up some memory that gets managed internally. Not necessary to call, but it might clean up
+ your compiler output to call this before you exit.
+*/
+void kiss_fft_cleanup(void);
+
+
+/*
+ * Returns the smallest integer k, such that k>=n and k has only "fast" factors (2,3,5)
+ */
+int kiss_fft_next_fast_size(int n);
+
+/* for real ffts, we need an even size */
+#define kiss_fftr_next_fast_size_real(n) \
+ (kiss_fft_next_fast_size( ((n)+1)>>1)<<1)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/modules/audio_filter/sofalizer/resampling/common.h b/modules/audio_filter/sofalizer/resampling/common.h
new file mode 100644
index 0000000..a8d4e98
--- /dev/null
+++ b/modules/audio_filter/sofalizer/resampling/common.h
@@ -0,0 +1,169 @@
+/*
+** Copyright (C) 2002-2011 Erik de Castro Lopo <erikd at mega-nerd.com>
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+/*
+** This code is part of Secret Rabbit Code aka libsamplerate. A commercial
+** use license for this code is available, please see:
+** http://www.mega-nerd.com/SRC/procedure.html
+*/
+
+#ifndef COMMON_H_INCLUDED
+#define COMMON_H_INCLUDED
+
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#elif (SIZEOF_INT == 4)
+typedef int int32_t ;
+#elif (SIZEOF_LONG == 4)
+typedef long int32_t ;
+#endif
+
+#define SRC_MAX_RATIO 256
+#define SRC_MAX_RATIO_STR "256"
+
+#define SRC_MIN_RATIO_DIFF (1e-20)
+
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+
+#define ARRAY_LEN(x) ((int) (sizeof (x) / sizeof ((x) [0])))
+#define OFFSETOF(type,member) ((int) (&((type*) 0)->member))
+
+#define MAKE_MAGIC(a,b,c,d,e,f) ((a) + ((b) << 4) + ((c) << 8) + ((d) << 12) + ((e) << 16) + ((f) << 20))
+
+/*
+** Inspiration : http://sourcefrog.net/weblog/software/languages/C/unused.html
+*/
+#ifdef UNUSED
+#elif defined (__GNUC__)
+# define UNUSED(x) UNUSED_ ## x __attribute__ ((unused))
+#elif defined (__LCLINT__)
+# define UNUSED(x) /*@unused@*/ x
+#else
+# define UNUSED(x) x
+#endif
+
+#ifdef __GNUC__
+# define WARN_UNUSED __attribute__ ((warn_unused_result))
+#else
+# define WARN_UNUSED
+#endif
+
+
+#include "samplerate.h"
+
+enum
+{ SRC_FALSE = 0,
+ SRC_TRUE = 1,
+
+ SRC_MODE_PROCESS = 555,
+ SRC_MODE_CALLBACK = 556
+} ;
+
+enum
+{ SRC_ERR_NO_ERROR = 0,
+
+ SRC_ERR_MALLOC_FAILED,
+ SRC_ERR_BAD_STATE,
+ SRC_ERR_BAD_DATA,
+ SRC_ERR_BAD_DATA_PTR,
+ SRC_ERR_NO_PRIVATE,
+ SRC_ERR_BAD_SRC_RATIO,
+ SRC_ERR_BAD_PROC_PTR,
+ SRC_ERR_SHIFT_BITS,
+ SRC_ERR_FILTER_LEN,
+ SRC_ERR_BAD_CONVERTER,
+ SRC_ERR_BAD_CHANNEL_COUNT,
+ SRC_ERR_SINC_BAD_BUFFER_LEN,
+ SRC_ERR_SIZE_INCOMPATIBILITY,
+ SRC_ERR_BAD_PRIV_PTR,
+ SRC_ERR_BAD_SINC_STATE,
+ SRC_ERR_DATA_OVERLAP,
+ SRC_ERR_BAD_CALLBACK,
+ SRC_ERR_BAD_MODE,
+ SRC_ERR_NULL_CALLBACK,
+ SRC_ERR_NO_VARIABLE_RATIO,
+ SRC_ERR_SINC_PREPARE_DATA_BAD_LEN,
+
+ /* This must be the last error number. */
+ SRC_ERR_MAX_ERROR
+} ;
+
+typedef struct SRC_PRIVATE_tag
+{ double last_ratio, last_position ;
+
+ int error ;
+ int channels ;
+
+ /* SRC_MODE_PROCESS or SRC_MODE_CALLBACK */
+ int mode ;
+
+ /* Pointer to data to converter specific data. */
+ void *private_data ;
+
+ /* Varispeed process function. */
+ int (*vari_process) (struct SRC_PRIVATE_tag *psrc, SRC_DATA *data) ;
+
+ /* Constant speed process function. */
+ int (*const_process) (struct SRC_PRIVATE_tag *psrc, SRC_DATA *data) ;
+
+ /* State reset. */
+ void (*reset) (struct SRC_PRIVATE_tag *psrc) ;
+
+ /* Data specific to SRC_MODE_CALLBACK. */
+ src_callback_t callback_func ;
+ void *user_callback_data ;
+ long saved_frames ;
+ float *saved_data ;
+} SRC_PRIVATE ;
+
+/* In src_sinc.c */
+const char* sinc_get_name (int src_enum) ;
+const char* sinc_get_description (int src_enum) ;
+
+int sinc_set_converter (SRC_PRIVATE *psrc, int src_enum) ;
+
+/* In src_linear.c */
+const char* linear_get_name (int src_enum) ;
+const char* linear_get_description (int src_enum) ;
+
+int linear_set_converter (SRC_PRIVATE *psrc, int src_enum) ;
+
+/* In src_zoh.c */
+const char* zoh_get_name (int src_enum) ;
+const char* zoh_get_description (int src_enum) ;
+
+int zoh_set_converter (SRC_PRIVATE *psrc, int src_enum) ;
+
+/*----------------------------------------------------------
+** Common static inline functions.
+*/
+
+static inline double
+fmod_one (double x)
+{ double res ;
+
+ res = x - lrint (x) ;
+ if (res < 0.0)
+ return res + 1.0 ;
+
+ return res ;
+} /* fmod_one */
+
+#endif /* COMMON_H_INCLUDED */
+
diff --git a/modules/audio_filter/sofalizer/resampling/samplerate.c b/modules/audio_filter/sofalizer/resampling/samplerate.c
new file mode 100644
index 0000000..9e54fb7
--- /dev/null
+++ b/modules/audio_filter/sofalizer/resampling/samplerate.c
@@ -0,0 +1,545 @@
+/*
+** Copyright (C) 2002-2011 Erik de Castro Lopo <erikd at mega-nerd.com>
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+/*
+** This code is part of Secret Rabbit Code aka libsamplerate. A commercial
+** use license for this code is available, please see:
+** http://www.mega-nerd.com/SRC/procedure.html
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+
+#include "samplerate.h"
+#include "float_cast.h"
+#include "common.h"
+
+static int psrc_set_converter (SRC_PRIVATE *psrc, int converter_type) ;
+
+
+static inline int
+is_bad_src_ratio (double ratio)
+{ return (ratio < (1.0 / SRC_MAX_RATIO) || ratio > (1.0 * SRC_MAX_RATIO)) ;
+} /* is_bad_src_ratio */
+
+SRC_STATE *
+src_new (int converter_type, int channels, int *error)
+{ SRC_PRIVATE *psrc ;
+
+ if (error)
+ *error = SRC_ERR_NO_ERROR ;
+
+ if (channels < 1)
+ { if (error)
+ *error = SRC_ERR_BAD_CHANNEL_COUNT ;
+ return NULL ;
+ } ;
+
+ if ((psrc = calloc (1, sizeof (*psrc))) == NULL)
+ { if (error)
+ *error = SRC_ERR_MALLOC_FAILED ;
+ return NULL ;
+ } ;
+
+ psrc->channels = channels ;
+ psrc->mode = SRC_MODE_PROCESS ;
+
+ if (psrc_set_converter (psrc, converter_type) != SRC_ERR_NO_ERROR)
+ { if (error)
+ *error = SRC_ERR_BAD_CONVERTER ;
+ free (psrc) ;
+ psrc = NULL ;
+ } ;
+
+ src_reset ((SRC_STATE*) psrc) ;
+
+ return (SRC_STATE*) psrc ;
+} /* src_new */
+
+SRC_STATE*
+src_callback_new (src_callback_t func, int converter_type, int channels, int *error, void* cb_data)
+{ SRC_STATE *src_state ;
+
+ if (func == NULL)
+ { if (error)
+ *error = SRC_ERR_BAD_CALLBACK ;
+ return NULL ;
+ } ;
+
+ if (error != NULL)
+ *error = 0 ;
+
+ if ((src_state = src_new (converter_type, channels, error)) == NULL)
+ return NULL ;
+
+ src_reset (src_state) ;
+
+ ((SRC_PRIVATE*) src_state)->mode = SRC_MODE_CALLBACK ;
+ ((SRC_PRIVATE*) src_state)->callback_func = func ;
+ ((SRC_PRIVATE*) src_state)->user_callback_data = cb_data ;
+
+ return src_state ;
+} /* src_callback_new */
+
+SRC_STATE *
+src_delete (SRC_STATE *state)
+{ SRC_PRIVATE *psrc ;
+
+ psrc = (SRC_PRIVATE*) state ;
+ if (psrc)
+ { if (psrc->private_data)
+ free (psrc->private_data) ;
+ memset (psrc, 0, sizeof (SRC_PRIVATE)) ;
+ free (psrc) ;
+ } ;
+
+ return NULL ;
+} /* src_state */
+
+int
+src_process (SRC_STATE *state, SRC_DATA *data)
+{ SRC_PRIVATE *psrc ;
+ int error ;
+
+ psrc = (SRC_PRIVATE*) state ;
+
+ if (psrc == NULL)
+ return SRC_ERR_BAD_STATE ;
+ if (psrc->vari_process == NULL || psrc->const_process == NULL)
+ return SRC_ERR_BAD_PROC_PTR ;
+
+ if (psrc->mode != SRC_MODE_PROCESS)
+ return SRC_ERR_BAD_MODE ;
+
+ /* Check for valid SRC_DATA first. */
+ if (data == NULL)
+ return SRC_ERR_BAD_DATA ;
+
+ /* And that data_in and data_out are valid. */
+ if (data->data_in == NULL || data->data_out == NULL)
+ return SRC_ERR_BAD_DATA_PTR ;
+
+ /* Check src_ratio is in range. */
+ if (is_bad_src_ratio (data->src_ratio))
+ return SRC_ERR_BAD_SRC_RATIO ;
+
+ if (data->input_frames < 0)
+ data->input_frames = 0 ;
+ if (data->output_frames < 0)
+ data->output_frames = 0 ;
+
+ if (data->data_in < data->data_out)
+ { if (data->data_in + data->input_frames * psrc->channels > data->data_out)
+ { /*-printf ("\n\ndata_in: %p data_out: %p\n",
+ (void*) (data->data_in + data->input_frames * psrc->channels), (void*) data->data_out) ;-*/
+ return SRC_ERR_DATA_OVERLAP ;
+ } ;
+ }
+ else if (data->data_out + data->output_frames * psrc->channels > data->data_in)
+ { /*-printf ("\n\ndata_in : %p ouput frames: %ld data_out: %p\n", (void*) data->data_in, data->output_frames, (void*) data->data_out) ;
+
+ printf ("data_out: %p (%p) data_in: %p\n", (void*) data->data_out,
+ (void*) (data->data_out + data->input_frames * psrc->channels), (void*) data->data_in) ;-*/
+ return SRC_ERR_DATA_OVERLAP ;
+ } ;
+
+ /* Set the input and output counts to zero. */
+ data->input_frames_used = 0 ;
+ data->output_frames_gen = 0 ;
+
+ /* Special case for when last_ratio has not been set. */
+ if (psrc->last_ratio < (1.0 / SRC_MAX_RATIO))
+ psrc->last_ratio = data->src_ratio ;
+
+ /* Now process. */
+ if (fabs (psrc->last_ratio - data->src_ratio) < 1e-15)
+ error = psrc->const_process (psrc, data) ;
+ else
+ error = psrc->vari_process (psrc, data) ;
+
+ return error ;
+} /* src_process */
+
+long
+src_callback_read (SRC_STATE *state, double src_ratio, long frames, float *data)
+{ SRC_PRIVATE *psrc ;
+ SRC_DATA src_data ;
+
+ long output_frames_gen ;
+ int error = 0 ;
+
+ if (state == NULL)
+ return 0 ;
+
+ if (frames <= 0)
+ return 0 ;
+
+ psrc = (SRC_PRIVATE*) state ;
+
+ if (psrc->mode != SRC_MODE_CALLBACK)
+ { psrc->error = SRC_ERR_BAD_MODE ;
+ return 0 ;
+ } ;
+
+ if (psrc->callback_func == NULL)
+ { psrc->error = SRC_ERR_NULL_CALLBACK ;
+ return 0 ;
+ } ;
+
+ memset (&src_data, 0, sizeof (src_data)) ;
+
+ /* Check src_ratio is in range. */
+ if (is_bad_src_ratio (src_ratio))
+ { psrc->error = SRC_ERR_BAD_SRC_RATIO ;
+ return 0 ;
+ } ;
+
+ /* Switch modes temporarily. */
+ src_data.src_ratio = src_ratio ;
+ src_data.data_out = data ;
+ src_data.output_frames = frames ;
+
+ src_data.data_in = psrc->saved_data ;
+ src_data.input_frames = psrc->saved_frames ;
+
+ output_frames_gen = 0 ;
+ while (output_frames_gen < frames)
+ { /* Use a dummy array for the case where the callback function
+ ** returns without setting the ptr.
+ */
+ float dummy [1] ;
+
+ if (src_data.input_frames == 0)
+ { float *ptr = dummy ;
+
+ src_data.input_frames = psrc->callback_func (psrc->user_callback_data, &ptr) ;
+ src_data.data_in = ptr ;
+
+ if (src_data.input_frames == 0)
+ src_data.end_of_input = 1 ;
+ } ;
+
+ /*
+ ** Now call process function. However, we need to set the mode
+ ** to SRC_MODE_PROCESS first and when we return set it back to
+ ** SRC_MODE_CALLBACK.
+ */
+ psrc->mode = SRC_MODE_PROCESS ;
+ error = src_process (state, &src_data) ;
+ psrc->mode = SRC_MODE_CALLBACK ;
+
+ if (error != 0)
+ break ;
+
+ src_data.data_in += src_data.input_frames_used * psrc->channels ;
+ src_data.input_frames -= src_data.input_frames_used ;
+
+ src_data.data_out += src_data.output_frames_gen * psrc->channels ;
+ src_data.output_frames -= src_data.output_frames_gen ;
+
+ output_frames_gen += src_data.output_frames_gen ;
+
+ if (src_data.end_of_input == SRC_TRUE && src_data.output_frames_gen == 0)
+ break ;
+ } ;
+
+ psrc->saved_data = src_data.data_in ;
+ psrc->saved_frames = src_data.input_frames ;
+
+ if (error != 0)
+ { psrc->error = error ;
+ return 0 ;
+ } ;
+
+ return output_frames_gen ;
+} /* src_callback_read */
+
+/*==========================================================================
+*/
+
+int
+src_set_ratio (SRC_STATE *state, double new_ratio)
+{ SRC_PRIVATE *psrc ;
+
+ psrc = (SRC_PRIVATE*) state ;
+
+ if (psrc == NULL)
+ return SRC_ERR_BAD_STATE ;
+ if (psrc->vari_process == NULL || psrc->const_process == NULL)
+ return SRC_ERR_BAD_PROC_PTR ;
+
+ if (is_bad_src_ratio (new_ratio))
+ return SRC_ERR_BAD_SRC_RATIO ;
+
+ psrc->last_ratio = new_ratio ;
+
+ return SRC_ERR_NO_ERROR ;
+} /* src_set_ratio */
+
+int
+src_reset (SRC_STATE *state)
+{ SRC_PRIVATE *psrc ;
+
+ if ((psrc = (SRC_PRIVATE*) state) == NULL)
+ return SRC_ERR_BAD_STATE ;
+
+ if (psrc->reset != NULL)
+ psrc->reset (psrc) ;
+
+ psrc->last_position = 0.0 ;
+ psrc->last_ratio = 0.0 ;
+
+ psrc->saved_data = NULL ;
+ psrc->saved_frames = 0 ;
+
+ psrc->error = SRC_ERR_NO_ERROR ;
+
+ return SRC_ERR_NO_ERROR ;
+} /* src_reset */
+
+/*==============================================================================
+** Control functions.
+*/
+
+const char *
+src_get_name (int converter_type)
+{ const char *desc ;
+
+ if ((desc = sinc_get_name (converter_type)) != NULL)
+ return desc ;
+
+ if ((desc = zoh_get_name (converter_type)) != NULL)
+ return desc ;
+
+ if ((desc = linear_get_name (converter_type)) != NULL)
+ return desc ;
+
+ return NULL ;
+} /* src_get_name */
+
+const char *
+src_get_description (int converter_type)
+{ const char *desc ;
+
+ if ((desc = sinc_get_description (converter_type)) != NULL)
+ return desc ;
+
+ if ((desc = zoh_get_description (converter_type)) != NULL)
+ return desc ;
+
+ if ((desc = linear_get_description (converter_type)) != NULL)
+ return desc ;
+
+ return NULL ;
+} /* src_get_description */
+
+const char *
+src_get_version (void)
+{ return PACKAGE "-" VERSION " (c) 2002-2008 Erik de Castro Lopo" ;
+} /* src_get_version */
+
+int
+src_is_valid_ratio (double ratio)
+{
+ if (is_bad_src_ratio (ratio))
+ return SRC_FALSE ;
+
+ return SRC_TRUE ;
+} /* src_is_valid_ratio */
+
+/*==============================================================================
+** Error reporting functions.
+*/
+
+int
+src_error (SRC_STATE *state)
+{ if (state)
+ return ((SRC_PRIVATE*) state)->error ;
+ return SRC_ERR_NO_ERROR ;
+} /* src_error */
+
+const char*
+src_strerror (int error)
+{
+ switch (error)
+ { case SRC_ERR_NO_ERROR :
+ return "No error." ;
+ case SRC_ERR_MALLOC_FAILED :
+ return "Malloc failed." ;
+ case SRC_ERR_BAD_STATE :
+ return "SRC_STATE pointer is NULL." ;
+ case SRC_ERR_BAD_DATA :
+ return "SRC_DATA pointer is NULL." ;
+ case SRC_ERR_BAD_DATA_PTR :
+ return "SRC_DATA->data_out is NULL." ;
+ case SRC_ERR_NO_PRIVATE :
+ return "Internal error. No private data." ;
+
+ case SRC_ERR_BAD_SRC_RATIO :
+ return "SRC ratio outside [1/" SRC_MAX_RATIO_STR ", " SRC_MAX_RATIO_STR "] range." ;
+
+ case SRC_ERR_BAD_SINC_STATE :
+ return "src_process() called without reset after end_of_input." ;
+ case SRC_ERR_BAD_PROC_PTR :
+ return "Internal error. No process pointer." ;
+ case SRC_ERR_SHIFT_BITS :
+ return "Internal error. SHIFT_BITS too large." ;
+ case SRC_ERR_FILTER_LEN :
+ return "Internal error. Filter length too large." ;
+ case SRC_ERR_BAD_CONVERTER :
+ return "Bad converter number." ;
+ case SRC_ERR_BAD_CHANNEL_COUNT :
+ return "Channel count must be >= 1." ;
+ case SRC_ERR_SINC_BAD_BUFFER_LEN :
+ return "Internal error. Bad buffer length. Please report this." ;
+ case SRC_ERR_SIZE_INCOMPATIBILITY :
+ return "Internal error. Input data / internal buffer size difference. Please report this." ;
+ case SRC_ERR_BAD_PRIV_PTR :
+ return "Internal error. Private pointer is NULL. Please report this." ;
+ case SRC_ERR_DATA_OVERLAP :
+ return "Input and output data arrays overlap." ;
+ case SRC_ERR_BAD_CALLBACK :
+ return "Supplied callback function pointer is NULL." ;
+ case SRC_ERR_BAD_MODE :
+ return "Calling mode differs from initialisation mode (ie process v callback)." ;
+ case SRC_ERR_NULL_CALLBACK :
+ return "Callback function pointer is NULL in src_callback_read ()." ;
+ case SRC_ERR_NO_VARIABLE_RATIO :
+ return "This converter only allows constant conversion ratios." ;
+ case SRC_ERR_SINC_PREPARE_DATA_BAD_LEN :
+ return "Internal error : Bad length in prepare_data ()." ;
+
+ case SRC_ERR_MAX_ERROR :
+ return "Placeholder. No error defined for this error number." ;
+
+ default : break ;
+ }
+
+ return NULL ;
+} /* src_strerror */
+
+/*==============================================================================
+** Simple interface for performing a single conversion from input buffer to
+** output buffer at a fixed conversion ratio.
+*/
+
+int
+src_simple (SRC_DATA *src_data, int converter, int channels)
+{ SRC_STATE *src_state ;
+ int error ;
+
+ if ((src_state = src_new (converter, channels, &error)) == NULL)
+ return error ;
+
+ src_data->end_of_input = 1 ; /* Only one buffer worth of input. */
+
+ error = src_process (src_state, src_data) ;
+
+ src_state = src_delete (src_state) ;
+
+ return error ;
+} /* src_simple */
+
+void
+src_short_to_float_array (const short *in, float *out, int len)
+{
+ while (len)
+ { len -- ;
+ out [len] = (float) (in [len] / (1.0 * 0x8000)) ;
+ } ;
+
+ return ;
+} /* src_short_to_float_array */
+
+void
+src_float_to_short_array (const float *in, short *out, int len)
+{ double scaled_value ;
+
+ /*while (len)
+ { len -- ;
+
+ scaled_value = in [len] * (8.0 * 0x10000000) ;
+ if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF))
+ { out [len] = 32767 ;
+ continue ;
+ } ;
+ if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000))
+ { out [len] = -32768 ;
+ continue ;
+ } ;
+
+ out [len] = (short) (lrint (scaled_value) >> 16) ;
+ } ;*/
+
+} /* src_float_to_short_array */
+
+void
+src_int_to_float_array (const int *in, float *out, int len)
+{
+ while (len)
+ { len -- ;
+ out [len] = (float) (in [len] / (8.0 * 0x10000000)) ;
+ } ;
+
+ return ;
+} /* src_int_to_float_array */
+
+void
+src_float_to_int_array (const float *in, int *out, int len)
+{ double scaled_value ;
+
+ /*while (len)
+ { len -- ;
+
+ scaled_value = in [len] * (8.0 * 0x10000000) ;
+ if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF))
+ { out [len] = 0x7fffffff ;
+ continue ;
+ } ;
+ if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000))
+ { out [len] = -1 - 0x7fffffff ;
+ continue ;
+ } ;
+
+ out [len] = lrint (scaled_value) ;
+ } ;*/
+
+} /* src_float_to_int_array */
+
+/*==============================================================================
+** Private functions.
+*/
+
+static int
+psrc_set_converter (SRC_PRIVATE *psrc, int converter_type)
+{
+ if (sinc_set_converter (psrc, converter_type) == SRC_ERR_NO_ERROR)
+ return SRC_ERR_NO_ERROR ;
+
+ if (zoh_set_converter (psrc, converter_type) == SRC_ERR_NO_ERROR)
+ return SRC_ERR_NO_ERROR ;
+
+ if (linear_set_converter (psrc, converter_type) == SRC_ERR_NO_ERROR)
+ return SRC_ERR_NO_ERROR ;
+
+ return SRC_ERR_BAD_CONVERTER ;
+} /* psrc_set_converter */
+
diff --git a/modules/audio_filter/sofalizer/resampling/samplerate.h b/modules/audio_filter/sofalizer/resampling/samplerate.h
new file mode 100644
index 0000000..044f8d7
--- /dev/null
+++ b/modules/audio_filter/sofalizer/resampling/samplerate.h
@@ -0,0 +1,197 @@
+/*
+** Copyright (C) 2002-2011 Erik de Castro Lopo <erikd at mega-nerd.com>
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+/*
+** This code is part of Secret Rabbit Code aka libsamplerate. A commercial
+** use license for this code is available, please see:
+** http://www.mega-nerd.com/SRC/procedure.html
+*/
+
+/*
+** API documentation is available here:
+** http://www.mega-nerd.com/SRC/api.html
+*/
+
+#ifndef SAMPLERATE_H
+#define SAMPLERATE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/* Opaque data type SRC_STATE. */
+typedef struct SRC_STATE_tag SRC_STATE ;
+
+/* SRC_DATA is used to pass data to src_simple() and src_process(). */
+typedef struct
+{ float *data_in, *data_out ;
+
+ long input_frames, output_frames ;
+ long input_frames_used, output_frames_gen ;
+
+ int end_of_input ;
+
+ double src_ratio ;
+} SRC_DATA ;
+
+/* SRC_CB_DATA is used with callback based API. */
+typedef struct
+{ long frames ;
+ float *data_in ;
+} SRC_CB_DATA ;
+
+/*
+** User supplied callback function type for use with src_callback_new()
+** and src_callback_read(). First parameter is the same pointer that was
+** passed into src_callback_new(). Second parameter is pointer to a
+** pointer. The user supplied callback function must modify *data to
+** point to the start of the user supplied float array. The user supplied
+** function must return the number of frames that **data points to.
+*/
+
+typedef long (*src_callback_t) (void *cb_data, float **data) ;
+
+/*
+** Standard initialisation function : return an anonymous pointer to the
+** internal state of the converter. Choose a converter from the enums below.
+** Error returned in *error.
+*/
+
+SRC_STATE* src_new (int converter_type, int channels, int *error) ;
+
+/*
+** Initilisation for callback based API : return an anonymous pointer to the
+** internal state of the converter. Choose a converter from the enums below.
+** The cb_data pointer can point to any data or be set to NULL. Whatever the
+** value, when processing, user supplied function "func" gets called with
+** cb_data as first parameter.
+*/
+
+SRC_STATE* src_callback_new (src_callback_t func, int converter_type, int channels,
+ int *error, void* cb_data) ;
+
+/*
+** Cleanup all internal allocations.
+** Always returns NULL.
+*/
+
+SRC_STATE* src_delete (SRC_STATE *state) ;
+
+/*
+** Standard processing function.
+** Returns non zero on error.
+*/
+
+int src_process (SRC_STATE *state, SRC_DATA *data) ;
+
+/*
+** Callback based processing function. Read up to frames worth of data from
+** the converter int *data and return frames read or -1 on error.
+*/
+long src_callback_read (SRC_STATE *state, double src_ratio, long frames, float *data) ;
+
+/*
+** Simple interface for performing a single conversion from input buffer to
+** output buffer at a fixed conversion ratio.
+** Simple interface does not require initialisation as it can only operate on
+** a single buffer worth of audio.
+*/
+
+int src_simple (SRC_DATA *data, int converter_type, int channels) ;
+
+/*
+** This library contains a number of different sample rate converters,
+** numbered 0 through N.
+**
+** Return a string giving either a name or a more full description of each
+** sample rate converter or NULL if no sample rate converter exists for
+** the given value. The converters are sequentially numbered from 0 to N.
+*/
+
+const char *src_get_name (int converter_type) ;
+const char *src_get_description (int converter_type) ;
+const char *src_get_version (void) ;
+
+/*
+** Set a new SRC ratio. This allows step responses
+** in the conversion ratio.
+** Returns non zero on error.
+*/
+
+int src_set_ratio (SRC_STATE *state, double new_ratio) ;
+
+/*
+** Reset the internal SRC state.
+** Does not modify the quality settings.
+** Does not free any memory allocations.
+** Returns non zero on error.
+*/
+
+int src_reset (SRC_STATE *state) ;
+
+/*
+** Return TRUE if ratio is a valid conversion ratio, FALSE
+** otherwise.
+*/
+
+int src_is_valid_ratio (double ratio) ;
+
+/*
+** Return an error number.
+*/
+
+int src_error (SRC_STATE *state) ;
+
+/*
+** Convert the error number into a string.
+*/
+const char* src_strerror (int error) ;
+
+/*
+** The following enums can be used to set the interpolator type
+** using the function src_set_converter().
+*/
+
+enum
+{
+ SRC_SINC_BEST_QUALITY = 0,
+ SRC_SINC_MEDIUM_QUALITY = 1,
+ SRC_SINC_FASTEST = 2,
+ SRC_ZERO_ORDER_HOLD = 3,
+ SRC_LINEAR = 4,
+} ;
+
+/*
+** Extra helper functions for converting from short to float and
+** back again.
+*/
+
+void src_short_to_float_array (const short *in, float *out, int len) ;
+void src_float_to_short_array (const float *in, short *out, int len) ;
+
+void src_int_to_float_array (const int *in, float *out, int len) ;
+void src_float_to_int_array (const float *in, int *out, int len) ;
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif /* SAMPLERATE_H */
+
--
1.9.1
More information about the vlc-devel
mailing list