summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Zammit <damien@zamaudio.com>2017-10-29 13:31:34 +1100
committerDamien Zammit <damien@zamaudio.com>2017-10-29 13:31:34 +1100
commit135493d835518e259f6e718ab7c9a3f8fcf8fdc5 (patch)
tree6c2f5ab5226c7d5fc3db135e6e3e4995794ed990
parent45b1d009deb663e6ae27fbb092a1886e77d0653f (diff)
Bundle zita-convolver 3.1.0 and use instead of system lib
-rw-r--r--lib/zita-convolver-3.1.0/zita-convolver.cpp976
-rw-r--r--lib/zita-convolver-3.1.0/zita-convolver.h456
-rw-r--r--plugins/Makefile.mk2
-rw-r--r--plugins/ZamVerb/Makefile3
-rw-r--r--plugins/ZamVerb/convolution.hpp2
5 files changed, 1436 insertions, 3 deletions
diff --git a/lib/zita-convolver-3.1.0/zita-convolver.cpp b/lib/zita-convolver-3.1.0/zita-convolver.cpp
new file mode 100644
index 0000000..a5155de
--- /dev/null
+++ b/lib/zita-convolver-3.1.0/zita-convolver.cpp
@@ -0,0 +1,976 @@
+// ----------------------------------------------------------------------------
+//
+// Copyright (C) 2006-2011 Fons Adriaensen <fons@linuxaudio.org>
+//
+// 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 3 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, see <http://www.gnu.org/licenses/>.
+//
+// ----------------------------------------------------------------------------
+
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "zita-convolver.h"
+
+
+
+int zita_convolver_major_version (void)
+{
+ return ZITA_CONVOLVER_MAJOR_VERSION;
+}
+
+
+int zita_convolver_minor_version (void)
+{
+ return ZITA_CONVOLVER_MINOR_VERSION;
+}
+
+
+float Convproc::_mac_cost = 1.0f;
+float Convproc::_fft_cost = 5.0f;
+
+
+Convproc::Convproc (void) :
+ _state (ST_IDLE),
+ _options (0),
+ _skipcnt (0),
+ _density (0),
+ _ninp (0),
+ _nout (0),
+ _quantum (0),
+ _minpart (0),
+ _maxpart (0),
+ _nlevels (0),
+ _latecnt (0)
+{
+ memset (_inpbuff, 0, MAXINP * sizeof (float *));
+ memset (_outbuff, 0, MAXOUT * sizeof (float *));
+ memset (_convlev, 0, MAXLEV * sizeof (Convlevel *));
+}
+
+
+Convproc::~Convproc (void)
+{
+ cleanup ();
+}
+
+
+void Convproc::set_options (unsigned int options)
+{
+ _options = options;
+}
+
+
+void Convproc::set_density (float density)
+{
+ _density = density;
+}
+
+
+void Convproc::set_skipcnt (unsigned int skipcnt)
+{
+ if ((_quantum == _minpart) && (_quantum == _maxpart)) _skipcnt = skipcnt;
+}
+
+
+int Convproc::configure (unsigned int ninp,
+ unsigned int nout,
+ unsigned int maxsize,
+ unsigned int quantum,
+ unsigned int minpart,
+ unsigned int maxpart)
+{
+ unsigned int offs, npar, size, pind, nmin, nmax, step, i;
+ int prio, d, r, s;
+ float cfft, cmac, t;
+
+ if (_state != ST_IDLE) return Converror::BAD_STATE;
+ if ( (quantum & (quantum - 1))
+ || (quantum < MINQUANT)
+ || (quantum > MAXQUANT)
+ || (minpart & (minpart - 1))
+ || (minpart < MINPART)
+ || (minpart < quantum)
+ || (minpart > MAXDIVIS * quantum)
+ || (maxpart & (maxpart - 1))
+ || (maxpart > MAXPART)
+ || (maxpart < minpart)) return Converror::BAD_PARAM;
+
+ if (ninp < nout) { nmin = ninp; nmax = nout; }
+ else { nmin = nout; nmax = ninp; }
+
+ if (_density <= 0) _density = 1.0 / nmin;
+ else
+ {
+ t = 1.0f / nmax;
+ if (_density < t) _density = t;
+ if (_density > 1) _density = 1;
+ }
+
+ cfft = _fft_cost * (ninp + nout);
+ cmac = _mac_cost * ninp * nout * _density;
+ step = (cfft < 4 * cmac) ? 1 : 2;
+
+ if (step == 2)
+ {
+ r = maxpart / minpart;
+ s = (r & 0xAAAA) ? 1 : 2;
+ }
+ else s = 1;
+ nmin = (s == 1) ? 2 : 6;
+ if (minpart == quantum) nmin++;
+
+ prio = 0;
+ size = quantum;
+ while (size < minpart)
+ {
+ prio -= 1;
+ size <<= 1;
+ }
+
+ try
+ {
+ for (offs = pind = 0; offs < maxsize; pind++)
+ {
+ npar = (maxsize - offs + size - 1) / size;
+ if ((size < maxpart) && (npar > nmin))
+ {
+ r = 1 << s;
+ d = npar - nmin;
+ d = d - (d + r - 1) / r;
+ if (cfft < d * cmac) npar = nmin;
+ }
+ _convlev [pind] = new Convlevel ();
+ _convlev [pind]->configure (prio, offs, npar, size, _options);
+
+ offs += size * npar;
+ if (offs < maxsize)
+ {
+ prio -= s;
+ size <<= s;
+ s = step;
+ nmin = (s == 1) ? 2 : 6;
+ }
+ }
+
+ _ninp = ninp;
+ _nout = nout;
+ _quantum = quantum;
+ _minpart = minpart;
+ _maxpart = size;
+ _nlevels = pind;
+ _latecnt = 0;
+ _inpsize = 2 * size;
+
+ for (i = 0; i < ninp; i++) _inpbuff [i] = new float [_inpsize];
+ for (i = 0; i < nout; i++) _outbuff [i] = new float [_minpart];
+ }
+ catch (...)
+ {
+ cleanup ();
+ return Converror::MEM_ALLOC;
+ }
+
+ _state = ST_STOP;
+ return 0;
+}
+
+
+int Convproc::impdata_create (unsigned int inp,
+ unsigned int out,
+ unsigned int step,
+ float *data,
+ int ind0,
+ int ind1)
+{
+ unsigned int j;
+
+ if (_state != ST_STOP) return Converror::BAD_STATE;
+ try
+ {
+ for (j = 0; j < _nlevels; j++)
+ {
+ _convlev [j]->impdata_create (inp, out, step, data, ind0, ind1);
+ }
+ }
+ catch (...)
+ {
+ cleanup ();
+ return Converror::MEM_ALLOC;
+ }
+ return 0;
+}
+
+
+int Convproc::impdata_update (unsigned int inp,
+ unsigned int out,
+ unsigned int step,
+ float *data,
+ int ind0,
+ int ind1)
+{
+ unsigned int j;
+
+ if (_state < ST_STOP) return Converror::BAD_STATE;
+ for (j = 0; j < _nlevels; j++)
+ {
+ _convlev [j]->impdata_update (inp, out, step, data, ind0, ind1);
+ }
+ return 0;
+}
+
+
+int Convproc::impdata_copy (unsigned int inp1,
+ unsigned int out1,
+ unsigned int inp2,
+ unsigned int out2)
+{
+ unsigned int j;
+
+ if (_state != ST_STOP) return Converror::BAD_STATE;
+ try
+ {
+ for (j = 0; j < _nlevels; j++)
+ {
+ _convlev [j]->impdata_copy (inp1, out1, inp2, out2);
+ }
+ }
+ catch (...)
+ {
+ cleanup ();
+ return Converror::MEM_ALLOC;
+ }
+ return 0;
+}
+
+
+int Convproc::reset (void)
+{
+ unsigned int k;
+
+ if (_state == ST_IDLE) return Converror::BAD_STATE;
+ for (k = 0; k < _ninp; k++) memset (_inpbuff [k], 0, _inpsize * sizeof (float));
+ for (k = 0; k < _nout; k++) memset (_outbuff [k], 0, _minpart * sizeof (float));
+ for (k = 0; k < _nlevels; k++) _convlev [k]->reset (_inpsize, _minpart, _inpbuff, _outbuff);
+ return 0;
+}
+
+
+int Convproc::start_process (int abspri, int policy)
+{
+ unsigned int k;
+
+ if (_state != ST_STOP) return Converror::BAD_STATE;
+
+ _latecnt = 0;
+ _inpoffs = 0;
+ _outoffs = 0;
+ reset ();
+ for (k = (_minpart == _quantum) ? 1 : 0; k < _nlevels; k++)
+ {
+ _convlev [k]->start (abspri, policy);
+ }
+ _state = ST_PROC;
+ return 0;
+}
+
+
+int Convproc::process (bool sync)
+{
+ unsigned int k;
+ int f = 0;
+
+ if (_state != ST_PROC) return 0;
+
+ _inpoffs += _quantum;
+ if (_inpoffs == _inpsize) _inpoffs = 0;
+
+ _outoffs += _quantum;
+ if (_outoffs == _minpart)
+ {
+ _outoffs = 0;
+ for (k = 0; k < _nout; k++) memset (_outbuff [k], 0, _minpart * sizeof (float));
+ for (k = 0; k < _nlevels; k++) f |= _convlev [k]->readout (sync, _skipcnt);
+ if (_skipcnt < _minpart) _skipcnt = 0;
+ else _skipcnt -= _minpart;
+ if (f)
+ {
+ if (++_latecnt >= 5)
+ {
+ stop_process ();
+ f |= FL_LOAD;
+ }
+ }
+ else _latecnt = 0;
+ }
+ return f;
+}
+
+
+int Convproc::stop_process (void)
+{
+ unsigned int k;
+
+ if (_state != ST_PROC) return Converror::BAD_STATE;
+ for (k = 0; k < _nlevels; k++) _convlev [k]->stop ();
+ _state = ST_WAIT;
+ return 0;
+}
+
+
+int Convproc::cleanup (void)
+{
+ unsigned int k;
+
+ while (! check_stop ())
+ {
+ usleep (100000);
+ }
+ if (_state != ST_STOP)
+ {
+ return Converror::BAD_STATE;
+ }
+
+ for (k = 0; k < _ninp; k++)
+ {
+ delete[] _inpbuff [k];
+ _inpbuff [k] = 0;
+ }
+ for (k = 0; k < _nout; k++)
+ {
+ delete[] _outbuff [k];
+ _outbuff [k] = 0;
+ }
+ for (k = 0; k < _nlevels; k++)
+ {
+ delete _convlev [k];
+ _convlev [k] = 0;
+ }
+
+ _state = ST_IDLE;
+ _options = 0;
+ _skipcnt = 0;
+ _density = 0;
+ _ninp = 0;
+ _nout = 0;
+ _quantum = 0;
+ _minpart = 0;
+ _maxpart = 0;
+ _nlevels = 0;
+ _latecnt = 0;
+ return 0;
+}
+
+
+bool Convproc::check_stop (void)
+{
+ unsigned int k;
+
+ for (k = 0; (k < _nlevels) && (_convlev [k]->_stat == Convlevel::ST_IDLE); k++);
+ if (k == _nlevels)
+ {
+ _state = ST_STOP;
+ return true;
+ }
+ return false;
+}
+
+
+void Convproc::print (FILE *F)
+{
+ unsigned int k;
+
+ for (k = 0; k < _nlevels; k++) _convlev [k]->print (F);
+}
+
+
+
+typedef float FV4 __attribute__ ((vector_size(16)));
+
+
+Convlevel::Convlevel (void) :
+ _stat (ST_IDLE),
+ _npar (0),
+ _parsize (0),
+ _options (0),
+ _pthr (0),
+ _inp_list (0),
+ _out_list (0),
+ _plan_r2c (0),
+ _plan_c2r (0),
+ _time_data (0),
+ _prep_data (0),
+ _freq_data (0)
+{
+}
+
+
+
+Convlevel::~Convlevel (void)
+{
+ cleanup ();
+}
+
+
+void *Convlevel::alloc_aligned (size_t size)
+{
+ void *p;
+
+ if (posix_memalign (&p, 16, size)) throw (Converror (Converror::MEM_ALLOC));
+ memset (p, 0, size);
+ return p;
+}
+
+
+void Convlevel::configure (int prio,
+ unsigned int offs,
+ unsigned int npar,
+ unsigned int parsize,
+ unsigned int options)
+{
+ int fftwopt = (options & OPT_FFTW_MEASURE) ? FFTW_MEASURE : FFTW_ESTIMATE;
+
+ _prio = prio;
+ _offs = offs;
+ _npar = npar;
+ _parsize = parsize;
+ _options = options;
+
+ _time_data = (float *)(alloc_aligned (2 * _parsize * sizeof (float)));
+ _prep_data = (float *)(alloc_aligned (2 * _parsize * sizeof (float)));
+ _freq_data = (fftwf_complex *)(alloc_aligned ((_parsize + 1) * sizeof (fftwf_complex)));
+ _plan_r2c = fftwf_plan_dft_r2c_1d (2 * _parsize, _time_data, _freq_data, fftwopt);
+ _plan_c2r = fftwf_plan_dft_c2r_1d (2 * _parsize, _freq_data, _time_data, fftwopt);
+ if (_plan_r2c && _plan_c2r) return;
+ throw (Converror (Converror::MEM_ALLOC));
+}
+
+
+void Convlevel::impdata_create (unsigned int inp,
+ unsigned int out,
+ unsigned int step,
+ float *data,
+ int i0,
+ int i1)
+{
+ unsigned int k;
+ int j, j0, j1, n;
+ float norm;
+ fftwf_complex *fftb;
+ Macnode *M;
+
+ n = i1 - i0;
+ i0 = _offs - i0;
+ i1 = i0 + _npar * _parsize;
+ if ((i0 >= n) || (i1 <= 0)) return;
+
+ M = findmacnode (inp, out, true);
+ if (! (M->_fftb))
+ {
+ M->_fftb = new fftwf_complex * [_npar];
+ memset (M->_fftb, 0, _npar * sizeof (fftwf_complex *));
+ }
+
+ norm = 0.5f / _parsize;
+ for (k = 0; k < _npar; k++)
+ {
+ i1 = i0 + _parsize;
+ if ((i0 < n) && (i1 > 0))
+ {
+ if (! (M->_fftb [k]))
+ {
+ M->_fftb [k] = (fftwf_complex *)(alloc_aligned ((_parsize + 1) * sizeof (fftwf_complex)));
+ }
+ if (data)
+ {
+ memset (_prep_data, 0, 2 * _parsize * sizeof (float));
+ j0 = (i0 < 0) ? 0 : i0;
+ j1 = (i1 > n) ? n : i1;
+ for (j = j0; j < j1; j++) _prep_data [j - i0] = norm * data [j * step];
+ fftwf_execute_dft_r2c (_plan_r2c, _prep_data, _freq_data);
+#ifdef ENABLE_VECTOR_MODE
+ if (_options & OPT_VECTOR_MODE) fftswap (_freq_data);
+#endif
+ fftb = M->_fftb [k];
+ for (j = 0; j <= (int)_parsize; j++)
+ {
+ fftb [j][0] += _freq_data [j][0];
+ fftb [j][1] += _freq_data [j][1];
+ }
+ }
+ }
+ i0 = i1;
+ }
+}
+
+
+void Convlevel::impdata_update (unsigned int inp,
+ unsigned int out,
+ unsigned int step,
+ float *data,
+ int i0,
+ int i1)
+{
+ unsigned int k;
+ int j, j0, j1, n;
+ float norm;
+ fftwf_complex *fftb;
+ Macnode *M;
+
+ M = findmacnode (inp, out, false);
+ if (! M) return;
+
+ n = i1 - i0;
+ i0 = _offs - i0;
+ i1 = i0 + _npar * _parsize;
+ if ((i0 >= n) || (i1 <= 0)) return;
+
+ norm = 0.5f / _parsize;
+ for (k = 0; k < _npar; k++)
+ {
+ i1 = i0 + _parsize;
+ fftb = M->_fftb [k];
+ if (fftb && (i0 < n) && (i1 > 0))
+ {
+ memset (_prep_data, 0, 2 * _parsize * sizeof (float));
+ j0 = (i0 < 0) ? 0 : i0;
+ j1 = (i1 > n) ? n : i1;
+ for (j = j0; j < j1; j++) _prep_data [j - i0] = norm * data [j * step];
+ fftwf_execute_dft_r2c (_plan_r2c, _prep_data, fftb);
+#ifdef ENABLE_VECTOR_MODE
+ if (_options & OPT_VECTOR_MODE) fftswap (fftb);
+#endif
+ }
+ i0 = i1;
+ }
+}
+
+
+void Convlevel::impdata_copy (unsigned int inp1,
+ unsigned int out1,
+ unsigned int inp2,
+ unsigned int out2)
+{
+ Macnode *M1;
+ Macnode *M2;
+
+ M1 = findmacnode (inp1, out1, false);
+ if (! M1) return;
+ M2 = findmacnode (inp2, out2, true);
+ if (M2->_fftb) return;
+ M2->_fftb = M1->_fftb;
+ M2->_copy = true;
+}
+
+
+void Convlevel::reset (unsigned int inpsize,
+ unsigned int outsize,
+ float **inpbuff,
+ float **outbuff)
+{
+ unsigned int i;
+ Inpnode *X;
+ Outnode *Y;
+
+ _inpsize = inpsize;
+ _outsize = outsize;
+ _inpbuff = inpbuff;
+ _outbuff = outbuff;
+ for (X = _inp_list; X; X = X->_next)
+ {
+ for (i = 0; i < _npar; i++)
+ {
+ memset (X->_ffta [i], 0, (_parsize + 1) * sizeof (fftwf_complex));
+ }
+ }
+ for (Y = _out_list; Y; Y = Y->_next)
+ {
+ for (i = 0; i < 3; i++)
+ {
+ memset (Y->_buff [i], 0, _parsize * sizeof (float));
+ }
+ }
+ if (_parsize == _outsize)
+ {
+ _outoffs = 0;
+ _inpoffs = 0;
+ }
+ else
+ {
+ _outoffs = _parsize / 2;
+ _inpoffs = _inpsize - _outoffs;
+ }
+ _bits = _parsize / _outsize;
+ _wait = 0;
+ _ptind = 0;
+ _opind = 0;
+ _trig.init (0, 0);
+ _done.init (0, 0);
+}
+
+
+void Convlevel::start (int abspri, int policy)
+{
+ int min, max;
+ pthread_attr_t attr;
+ struct sched_param parm;
+
+ _pthr = 0;
+ min = sched_get_priority_min (policy);
+ max = sched_get_priority_max (policy);
+ abspri += _prio;
+ if (abspri > max) abspri = max;
+ if (abspri < min) abspri = min;
+ parm.sched_priority = abspri;
+ pthread_attr_init (&attr);
+ pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
+ pthread_attr_setschedpolicy (&attr, policy);
+ pthread_attr_setschedparam (&attr, &parm);
+ pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM);
+ pthread_attr_setinheritsched (&attr, PTHREAD_EXPLICIT_SCHED);
+ pthread_attr_setstacksize (&attr, 0x10000);
+ pthread_create (&_pthr, &attr, static_main, this);
+ pthread_attr_destroy (&attr);
+}
+
+
+void Convlevel::stop (void)
+{
+ if (_stat != ST_IDLE)
+ {
+ _stat = ST_TERM;
+ _trig.post ();
+ }
+}
+
+
+void Convlevel::cleanup (void)
+{
+ unsigned int i;
+ Inpnode *X, *X1;
+ Outnode *Y, *Y1;
+ Macnode *M, *M1;
+
+ X = _inp_list;
+ while (X)
+ {
+ for (i = 0; i < _npar; i++) free (X->_ffta [i]);
+ delete[] X->_ffta;
+ X1 = X->_next;
+ delete X;
+ X = X1;
+ }
+ _inp_list = 0;
+
+ Y = _out_list;
+ while (Y)
+ {
+ M = Y->_list;
+ while (M)
+ {
+ if ((M->_fftb) && !(M->_copy))
+ {
+ for (i = 0; i < _npar; i++)
+ {
+ free (M->_fftb [i]);
+ }
+ delete[] M->_fftb;
+ }
+ M1 = M->_next;
+ delete M;
+ M = M1;
+ }
+ for (i = 0; i < 3; i++) free (Y->_buff [i]);
+ Y1 = Y->_next;
+ delete Y;
+ Y = Y1;
+ }
+ _out_list = 0;
+
+ fftwf_destroy_plan (_plan_r2c);
+ fftwf_destroy_plan (_plan_c2r);
+ free (_time_data);
+ free (_prep_data);
+ free (_freq_data);
+ _plan_r2c = 0;
+ _plan_c2r = 0;
+ _time_data = 0;
+ _prep_data = 0;
+ _freq_data = 0;
+}
+
+
+void *Convlevel::static_main (void *arg)
+{
+ ((Convlevel *) arg)->main ();
+ return 0;
+}
+
+
+void Convlevel::main (void)
+{
+ _stat = ST_PROC;
+ while (true)
+ {
+ _trig.wait ();
+ if (_stat == ST_TERM)
+ {
+ _stat = ST_IDLE;
+ _pthr = 0;
+ return;
+ }
+ process (false);
+ _done.post ();
+ }
+}
+
+
+void Convlevel::process (bool skip)
+{
+ unsigned int i, j, k;
+ unsigned int i1, n1, n2, opi1, opi2;
+
+ Inpnode *X;
+ Macnode *M;
+ Outnode *Y;
+ fftwf_complex *ffta;
+ fftwf_complex *fftb;
+ float *inpd;
+ float *outd;
+
+ i1 = _inpoffs;
+ n1 = _parsize;
+ n2 = 0;
+ _inpoffs = i1 + n1;
+ if (_inpoffs >= _inpsize)
+ {
+ _inpoffs -= _inpsize;
+ n2 = _inpoffs;
+ n1 -= n2;
+ }
+
+ opi1 = (_opind + 1) % 3;
+ opi2 = (_opind + 2) % 3;
+
+ for (X = _inp_list; X; X = X->_next)
+ {
+ inpd = _inpbuff [X->_inp];
+ if (n1) memcpy (_time_data, inpd + i1, n1 * sizeof (float));
+ if (n2) memcpy (_time_data + n1, inpd, n2 * sizeof (float));
+ memset (_time_data + _parsize, 0, _parsize * sizeof (float));
+ fftwf_execute_dft_r2c (_plan_r2c, _time_data, X->_ffta [_ptind]);
+#ifdef ENABLE_VECTOR_MODE
+ if (_options & OPT_VECTOR_MODE) fftswap (X->_ffta [_ptind]);
+#endif
+ }
+
+ if (skip)
+ {
+ for (Y = _out_list; Y; Y = Y->_next)
+ {
+ outd = Y->_buff [opi2];
+ memset (outd, 0, _parsize * sizeof (float));
+ }
+ }
+ else
+ {
+ for (Y = _out_list; Y; Y = Y->_next)
+ {
+ memset (_freq_data, 0, (_parsize + 1) * sizeof (fftwf_complex));
+ for (M = Y->_list; M; M = M->_next)
+ {
+ X = M->_inpn;
+ i = _ptind;
+ for (j = 0; j < _npar; j++)
+ {
+ ffta = X->_ffta [i];
+ fftb = M->_fftb [j];
+ if (fftb)
+ {
+#ifdef ENABLE_VECTOR_MODE
+ if (_options & OPT_VECTOR_MODE)
+ {
+ FV4 *A = (FV4 *) ffta;
+ FV4 *B = (FV4 *) fftb;
+ FV4 *D = (FV4 *) _freq_data;
+ for (k = 0; k < _parsize; k += 4)
+ {
+ D [0] += A [0] * B [0] - A [1] * B [1];
+ D [1] += A [0] * B [1] + A [1] * B [0];
+ A += 2;
+ B += 2;
+ D += 2;
+ }
+ _freq_data [_parsize][0] += ffta [_parsize][0] * fftb [_parsize][0];
+ _freq_data [_parsize][1] = 0;
+ }
+ else
+#endif
+ {
+ for (k = 0; k <= _parsize; k++)
+ {
+ _freq_data [k][0] += ffta [k][0] * fftb [k][0] - ffta [k][1] * fftb [k][1];
+ _freq_data [k][1] += ffta [k][0] * fftb [k][1] + ffta [k][1] * fftb [k][0];
+ }
+ }
+ }
+ if (i == 0) i = _npar;
+ i--;
+ }
+ }
+
+#ifdef ENABLE_VECTOR_MODE
+ if (_options & OPT_VECTOR_MODE) fftswap (_freq_data);
+#endif
+ fftwf_execute_dft_c2r (_plan_c2r, _freq_data, _time_data);
+ outd = Y->_buff [opi1];
+ for (k = 0; k < _parsize; k++) outd [k] += _time_data [k];
+ outd = Y->_buff [opi2];
+ memcpy (outd, _time_data + _parsize, _parsize * sizeof (float));
+ }
+ }
+
+ _ptind++;
+ if (_ptind == _npar) _ptind = 0;
+}
+
+
+int Convlevel::readout (bool sync, unsigned int skipcnt)
+{
+ unsigned int i;
+ float *p, *q;
+ Outnode *Y;
+
+ _outoffs += _outsize;
+ if (_outoffs == _parsize)
+ {
+ _outoffs = 0;
+ if (_stat == ST_PROC)
+ {
+ while (_wait)
+ {
+ if (sync) _done.wait ();
+ else if (_done.trywait ()) break;
+ _wait--;
+ }
+ if (++_opind == 3) _opind = 0;
+ _trig.post ();
+ _wait++;
+ }
+ else
+ {
+ process (skipcnt >= 2 * _parsize);
+ if (++_opind == 3) _opind = 0;
+ }
+ }
+
+ for (Y = _out_list; Y; Y = Y->_next)
+ {
+ p = Y->_buff [_opind] + _outoffs;
+ q = _outbuff [Y->_out];
+ for (i = 0; i < _outsize; i++) q [i] += p [i];
+ }
+
+ return (_wait > 1) ? _bits : 0;
+}
+
+
+void Convlevel::print (FILE *F)
+{
+ fprintf (F, "prio = %4d, offs = %6d, parsize = %5d, npar = %3d\n", _prio, _offs, _parsize, _npar);
+}
+
+
+Macnode *Convlevel::findmacnode (unsigned int inp, unsigned int out, bool create)
+{
+ unsigned int i;
+ Inpnode *X;
+ Outnode *Y;
+ Macnode *M;
+
+ for (X = _inp_list; X && (X->_inp != inp); X = X->_next);
+ if (! X)
+ {
+ if (! create) return 0;
+ X = new Inpnode;
+ X->_next = _inp_list;
+ _inp_list = X;
+ X->_inp = inp;
+ X->_ffta = new fftwf_complex * [_npar];
+ memset (X->_ffta, 0, _npar * sizeof (fftw_complex *));
+ for (i = 0; i < _npar; i++)
+ {
+ X->_ffta [i] = (fftwf_complex *)(alloc_aligned ((_parsize + 1) * sizeof (fftwf_complex)));
+ }
+ }
+
+ for (Y = _out_list; Y && (Y->_out != out); Y = Y->_next);
+ if (! Y)
+ {
+ if (! create) return 0;
+ Y = new Outnode;
+ Y->_next = _out_list;
+ _out_list = Y;
+ Y->_out = out;
+ Y->_list = 0;
+ for (i = 0; i < 3; i++)
+ {
+ Y->_buff [i] = 0;
+ }
+ for (i = 0; i < 3; i++)
+ {
+ Y->_buff [i] = (float *)(alloc_aligned (_parsize * sizeof (float)));
+ }
+ }
+
+ for (M = Y->_list; M && (M->_inpn != X); M = M->_next);
+ if (! M)
+ {
+ if (! create) return 0;
+ M = new Macnode;
+ M->_next = Y->_list;
+ Y->_list = M;
+ M->_inpn = X;
+ M->_fftb = 0;
+ M->_copy = false;
+ }
+
+ return M;
+}
+
+
+#ifdef ENABLE_VECTOR_MODE
+
+void Convlevel::fftswap (fftwf_complex *p)
+{
+ unsigned int n = _parsize;
+ float a, b;
+
+ while (n)
+ {
+ a = p [2][0];
+ b = p [3][0];
+ p [2][0] = p [0][1];
+ p [3][0] = p [1][1];
+ p [0][1] = a;
+ p [1][1] = b;
+ p += 4;
+ n -= 4;
+ }
+}
+
+#endif
+
+
diff --git a/lib/zita-convolver-3.1.0/zita-convolver.h b/lib/zita-convolver-3.1.0/zita-convolver.h
new file mode 100644
index 0000000..0c15710
--- /dev/null
+++ b/lib/zita-convolver-3.1.0/zita-convolver.h
@@ -0,0 +1,456 @@
+// ----------------------------------------------------------------------------
+//
+// Copyright (C) 2006-2011 Fons Adriaensen <fons@linuxaudio.org>
+//
+// 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 3 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, see <http://www.gnu.org/licenses/>.
+//
+// ----------------------------------------------------------------------------
+
+
+#ifndef _ZITA_CONVOLVER_H
+#define _ZITA_CONVOLVER_H
+
+
+#include <pthread.h>
+#include <fftw3.h>
+
+
+#define ZITA_CONVOLVER_MAJOR_VERSION 3
+#define ZITA_CONVOLVER_MINOR_VERSION 1
+
+
+extern int zita_convolver_major_version (void);
+extern int zita_convolver_minor_version (void);
+
+
+// ----------------------------------------------------------------------------
+
+
+#ifdef ZCSEMA_IS_IMPLEMENTED
+#undef ZCSEMA_IS_IMPLEMENTED
+#endif
+
+
+#if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__GNU__)
+
+// NOTE: __FreeBSD_kernel__ and __GNU__ were added by the Debian maintainers
+// (the latter for the HURD version of Debian). Things are reported to work
+// with some applications but probably have not been tested in depth.
+
+#include <semaphore.h>
+
+class ZCsema
+{
+public:
+
+ ZCsema (void) { init (0, 0); }
+ ~ZCsema (void) { sem_destroy (&_sema); }
+
+ ZCsema (const ZCsema&); // disabled
+ ZCsema& operator= (const ZCsema&); // disabled
+
+ int init (int s, int v) { return sem_init (&_sema, s, v); }
+ int post (void) { return sem_post (&_sema); }
+ int wait (void) { return sem_wait (&_sema); }
+ int trywait (void) { return sem_trywait (&_sema); }
+
+private:
+
+ sem_t _sema;
+};
+
+#define ZCSEMA_IS_IMPLEMENTED
+#endif
+
+
+#ifdef __APPLE__
+
+// NOTE: ***** I DO NOT REPEAT NOT PROVIDE SUPPORT FOR OSX *****
+//
+// The following code partially emulates the POSIX sem_t for which
+// OSX has only a crippled implementation. It may or may not compile,
+// and if it compiles it may or may not work correctly. Blame APPLE
+// for not following POSIX standards.
+
+class ZCsema
+{
+public:
+
+ ZCsema (void) : _count (0)
+ {
+ init (0, 0);
+ }
+
+ ~ZCsema (void)
+ {
+ pthread_mutex_destroy (&_mutex);
+ pthread_cond_destroy (&_cond);
+ }
+
+ ZCsema (const ZCsema&); // disabled
+ ZCsema& operator= (const ZCsema&); // disabled
+
+ int init (int s, int v)
+ {
+ _count = v;
+ return pthread_mutex_init (&_mutex, 0) || pthread_cond_init (&_cond, 0);
+ }
+
+ int post (void)
+ {
+ pthread_mutex_lock (&_mutex);
+ _count++;
+ if (_count == 1) pthread_cond_signal (&_cond);
+ pthread_mutex_unlock (&_mutex);
+ return 0;
+ }
+
+ int wait (void)
+ {
+ pthread_mutex_lock (&_mutex);
+ while (_count < 1) pthread_cond_wait (&_cond, &_mutex);
+ _count--;
+ pthread_mutex_unlock (&_mutex);
+ return 0;
+ }
+
+ int trywait (void)
+ {
+ if (pthread_mutex_trylock (&_mutex)) return -1;
+ if (_count < 1)
+ {
+ pthread_mutex_unlock (&_mutex);
+ return -1;
+ }
+ _count--;
+ pthread_mutex_unlock (&_mutex);
+ return 0;
+ }
+
+private:
+
+ int _count;
+ pthread_mutex_t _mutex;
+ pthread_cond_t _cond;
+};
+
+#define ZCSEMA_IS_IMPLEMENTED
+#endif
+
+
+#ifndef ZCSEMA_IS_IMPLEMENTED
+#error "The ZCsema class is not implemented."
+#endif
+
+
+// ----------------------------------------------------------------------------
+
+
+class Inpnode
+{
+private:
+
+ friend class Convlevel;
+
+ Inpnode *_next;
+ fftwf_complex **_ffta;
+ unsigned int _inp;
+};
+
+
+class Macnode
+{
+private:
+
+ friend class Convlevel;
+
+ Macnode *_next;
+ Inpnode *_inpn;
+ fftwf_complex **_fftb;
+ bool _copy;
+};
+
+
+class Outnode
+{
+private:
+
+ friend class Convlevel;
+
+ Outnode *_next;
+ Macnode *_list;
+ float *_buff [3];
+ unsigned int _out;
+};
+
+
+class Converror
+{
+public:
+
+ enum
+ {
+ BAD_STATE = -1,
+ BAD_PARAM = -2,
+ MEM_ALLOC = -3
+ };
+
+private:
+
+ friend class Convlevel;
+ friend class Convproc;
+
+ Converror (int error) : _error (error) {}
+
+ int _error;
+};
+
+
+class Convlevel
+{
+private:
+
+ friend class Convproc;
+
+ enum
+ {
+ OPT_FFTW_MEASURE = 1,
+ OPT_VECTOR_MODE = 2
+ };
+
+ enum
+ {
+ ST_IDLE,
+ ST_TERM,
+ ST_PROC
+ };
+
+ Convlevel (void);
+ ~Convlevel (void);
+
+ void *alloc_aligned (size_t size);
+
+ void configure (int prio,
+ unsigned int offs,
+ unsigned int npar,
+ unsigned int parsize,
+ unsigned int options);
+
+ void impdata_create (unsigned int inp,
+ unsigned int out,
+ unsigned int step,
+ float *data,
+ int ind0,
+ int ind1);
+
+ void impdata_update (unsigned int inp,
+ unsigned int out,
+ unsigned int step,
+ float *data,
+ int ind0,
+ int ind1);
+
+ void impdata_copy (unsigned int inp1,
+ unsigned int out1,
+ unsigned int inp2,
+ unsigned int out2);
+
+ void reset (unsigned int inpsize,
+ unsigned int outsize,
+ float **inpbuff,
+ float **outbuff);
+
+ void start (int absprio, int policy);
+
+ void process (bool sync);
+
+ int readout (bool sync, unsigned int skipcnt);
+
+ void stop (void);
+
+ void cleanup (void);
+
+ void fftswap (fftwf_complex *p);
+
+ void print (FILE *F);
+
+ static void *static_main (void *arg);
+
+ void main (void);
+
+ Macnode *findmacnode (unsigned int inp, unsigned int out, bool create);
+
+ volatile unsigned int _stat; // current processing state
+ int _prio; // relative priority
+ unsigned int _offs; // offset from start of impulse response
+ unsigned int _npar; // number of partitions
+ unsigned int _parsize; // partition and outbut buffer size
+ unsigned int _outsize; // step size for output buffer
+ unsigned int _outoffs; // offset into output buffer
+ unsigned int _inpsize; // size of shared input buffer
+ unsigned int _inpoffs; // offset into input buffer
+ unsigned int _options; // various options
+ unsigned int _ptind; // rotating partition index
+ unsigned int _opind; // rotating output buffer index
+ int _bits; // bit identifiying this level
+ int _wait; // number of unfinished cycles
+ pthread_t _pthr; // posix thread executing this level
+ ZCsema _trig; // sema used to trigger a cycle
+ ZCsema _done; // sema used to wait for a cycle
+ Inpnode *_inp_list; // linked list of active inputs
+ Outnode *_out_list; // linked list of active outputs
+ fftwf_plan _plan_r2c; // FFTW plan, forward FFT
+ fftwf_plan _plan_c2r; // FFTW plan, inverse FFT
+ float *_time_data; // workspace
+ float *_prep_data; // workspace
+ fftwf_complex *_freq_data; // workspace
+ float **_inpbuff; // array of shared input buffers
+ float **_outbuff; // array of shared output buffers
+};
+
+
+// ----------------------------------------------------------------------------
+
+
+class Convproc
+{
+public:
+
+ Convproc (void);
+ ~Convproc (void);
+
+ enum
+ {
+ ST_IDLE,
+ ST_STOP,
+ ST_WAIT,
+ ST_PROC
+ };
+
+ enum
+ {
+ FL_LATE = 0x0000FFFF,
+ FL_LOAD = 0x01000000
+ };
+
+ enum
+ {
+ OPT_FFTW_MEASURE = Convlevel::OPT_FFTW_MEASURE,
+ OPT_VECTOR_MODE = Convlevel::OPT_VECTOR_MODE
+ };
+
+ enum
+ {
+ MAXINP = 64,
+ MAXOUT = 64,
+ MAXLEV = 8,
+ MINPART = 64,
+ MAXPART = 8192,
+ MAXDIVIS = 16,
+ MINQUANT = 16,
+ MAXQUANT = 8192
+ };
+
+ unsigned int state (void) const
+ {
+ return _state;
+ }
+
+ float *inpdata (unsigned int inp) const
+ {
+ return _inpbuff [inp] + _inpoffs;
+ }
+
+ float *outdata (unsigned int out) const
+ {
+ return _outbuff [out] + _outoffs;
+ }
+
+ void set_density (float density);
+
+ void set_options (unsigned int options);
+
+ void set_skipcnt (unsigned int skipcnt);
+
+ int configure (unsigned int ninp,
+ unsigned int nout,
+ unsigned int maxsize,
+ unsigned int quantum,
+ unsigned int minpart,
+ unsigned int maxpart);
+
+ int impdata_create (unsigned int inp,
+ unsigned int out,
+ unsigned int step,
+ float *data,
+ int ind0,
+ int ind1);
+
+ int impdata_update (unsigned int inp,
+ unsigned int out,
+ unsigned int step,
+ float *data,
+ int ind0,
+ int ind1);
+
+ int impdata_copy (unsigned int inp1,
+ unsigned int out1,
+ unsigned int inp2,
+ unsigned int out2);
+
+ int reset (void);
+
+ int start_process (int abspri, int policy);
+
+ int process (bool sync = false);
+
+ int stop_process (void);
+
+ bool check_stop (void);
+
+ int cleanup (void);
+
+ void print (FILE *F = stdout);
+
+ static float _mac_cost;
+ static float _fft_cost;
+
+private:
+
+ unsigned int _state; // current state
+ float *_inpbuff [MAXINP]; // input buffers
+ float *_outbuff [MAXOUT]; // output buffers
+ unsigned int _inpoffs; // current offset in input buffers
+ unsigned int _outoffs; // current offset in output buffers
+ unsigned int _options; // option bits
+ unsigned int _skipcnt; // number of frames to skip
+ float _density; // matrix density hint
+ unsigned int _ninp; // number of inputs
+ unsigned int _nout; // number of outputs
+ unsigned int _quantum; // processing block size
+ unsigned int _minpart; // smallest partition size
+ unsigned int _maxpart; // largest allowed partition size
+ unsigned int _nlevels; // number of partition sizes
+ unsigned int _inpsize; // size of input buffers
+ unsigned int _latecnt; // count of cycles ending too late
+ Convlevel *_convlev [MAXLEV]; // array of processors
+ void *_dummy [64];
+};
+
+
+// ----------------------------------------------------------------------------
+
+
+#endif
+
diff --git a/plugins/Makefile.mk b/plugins/Makefile.mk
index 2319f37..6b9728f 100644
--- a/plugins/Makefile.mk
+++ b/plugins/Makefile.mk
@@ -17,7 +17,7 @@ endif
TARGET_DIR = ../../bin
-BASE_FLAGS += -lzita-convolver -lsamplerate
+BASE_FLAGS += -lfftw3f -lpthread -lsamplerate
BUILD_C_FLAGS += -I.
BUILD_CXX_FLAGS += -I. -I.. -I../../dpf/distrho -I../../dpf/dgl
diff --git a/plugins/ZamVerb/Makefile b/plugins/ZamVerb/Makefile
index f7c5a02..cfa412c 100644
--- a/plugins/ZamVerb/Makefile
+++ b/plugins/ZamVerb/Makefile
@@ -15,7 +15,8 @@ NAME = ZamVerb
OBJS_DSP = \
ZamVerbPlugin.cpp.o \
ZamVerbImpulses.cpp.o \
- convolution.cpp.o
+ convolution.cpp.o \
+ ../../lib/zita-convolver-3.1.0/zita-convolver.cpp.o
OBJS_UI = \
ZamVerbArtwork.cpp.o \
diff --git a/plugins/ZamVerb/convolution.hpp b/plugins/ZamVerb/convolution.hpp
index a730e29..4eeada5 100644
--- a/plugins/ZamVerb/convolution.hpp
+++ b/plugins/ZamVerb/convolution.hpp
@@ -19,7 +19,7 @@
#ifndef CONVOLUTION_H_
#define CONVOLUTION_H_
-#include <zita-convolver.h>
+#include "../../lib/zita-convolver-3.1.0/zita-convolver.h"
#define MAX_CHANNEL_MAPS (4)
#define VERBOSE_printf(x, ...)