@@ -40,6 +40,7 @@ ALL_LIBS += $(MODULEDIR)/rtmempool.a | |||
3RD_LIBS += $(MODULEDIR)/lilv.a | |||
3RD_LIBS += $(MODULEDIR)/sfzero.a | |||
3RD_LIBS += $(MODULEDIR)/water.a | |||
3RD_LIBS += $(MODULEDIR)/zita-resampler.a | |||
ifeq ($(HAVE_DGL),true) | |||
3RD_LIBS += $(MODULEDIR)/dgl.a | |||
@@ -28,6 +28,7 @@ STANDALONE_LIBS += $(MODULEDIR)/native-plugins.a | |||
STANDALONE_LIBS += $(MODULEDIR)/rtmempool.a | |||
STANDALONE_LIBS += $(MODULEDIR)/sfzero.a | |||
STANDALONE_LIBS += $(MODULEDIR)/water.a | |||
STANDALONE_LIBS += $(MODULEDIR)/zita-resampler.a | |||
ifeq ($(HAVE_DGL),true) | |||
STANDALONE_LIBS += $(MODULEDIR)/dgl.a | |||
@@ -157,6 +157,7 @@ NATIVE_LINK_FLAGS += $(MAGIC_LIBS) | |||
LIBS_native += $(MODULEDIR)/audio_decoder.a | |||
LIBS_native += $(MODULEDIR)/native-plugins.a | |||
LIBS_native += $(MODULEDIR)/sfzero.a | |||
LIBS_native += $(MODULEDIR)/zita-resampler.a | |||
ifeq ($(HAVE_DGL),true) | |||
LIBS_native += $(MODULEDIR)/dgl.a | |||
@@ -17,6 +17,7 @@ clean: | |||
$(MAKE) clean -C rtmidi | |||
$(MAKE) clean -C sfzero | |||
$(MAKE) clean -C water | |||
$(MAKE) clean -C zita-resampler | |||
$(MAKE) clean -C juce_audio_basics | |||
$(MAKE) clean -C juce_audio_devices | |||
@@ -0,0 +1,52 @@ | |||
#!/usr/bin/make -f | |||
# Makefile for zita-resampler # | |||
# --------------------------- # | |||
# Created by falkTX | |||
# | |||
CWD=../.. | |||
MODULENAME=zita-resampler | |||
include ../Makefile.mk | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
BUILD_CXX_FLAGS += -I. | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
OBJS = \ | |||
$(OBJDIR)/cresampler.cc.o \ | |||
$(OBJDIR)/resampler-table.cc.o \ | |||
$(OBJDIR)/resampler.cc.o \ | |||
$(OBJDIR)/vresampler.cc.o | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
all: $(MODULEDIR)/$(MODULENAME).a | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
clean: | |||
rm -f $(OBJDIR)/*.o $(MODULEDIR)/$(MODULENAME)*.a | |||
debug: | |||
$(MAKE) DEBUG=true | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
$(MODULEDIR)/$(MODULENAME).a: $(OBJS) | |||
-@mkdir -p $(MODULEDIR) | |||
@echo "Creating $(MODULENAME).a" | |||
@rm -f $@ | |||
@$(AR) crs $@ $^ | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
$(OBJDIR)/%.cc.o: %.cc | |||
-@mkdir -p $(OBJDIR) | |||
@echo "Compiling $<" | |||
@$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | |||
-include $(OBJS:%.o=%.d) | |||
# --------------------------------------------------------------------------------------------------------------------- |
@@ -0,0 +1,192 @@ | |||
// ---------------------------------------------------------------------------- | |||
// | |||
// Copyright (C) 2013 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 <stdlib.h> | |||
#include <stdio.h> | |||
#include <string.h> | |||
#include <math.h> | |||
#include "cresampler.h" | |||
CResampler::CResampler (void) : | |||
_nchan (0), | |||
_buff (0) | |||
{ | |||
reset (); | |||
} | |||
CResampler::~CResampler (void) | |||
{ | |||
clear (); | |||
} | |||
int CResampler::setup (double ratio, | |||
unsigned int nchan) | |||
{ | |||
if (! nchan) return 1; | |||
clear (); | |||
_inmax = 50; | |||
_buff = new float [nchan * (3 + _inmax)]; | |||
_nchan = nchan; | |||
_pstep = 1 / ratio; | |||
return reset (); | |||
} | |||
void CResampler::clear (void) | |||
{ | |||
delete[] _buff; | |||
_buff = 0; | |||
_nchan = 0; | |||
_inmax = 0; | |||
_pstep = 0; | |||
reset (); | |||
} | |||
void CResampler::set_phase (double p) | |||
{ | |||
_phase = p - floor (p); | |||
} | |||
void CResampler::set_ratio (double r) | |||
{ | |||
_pstep = 1.0 / r; | |||
} | |||
double CResampler::inpdist (void) const | |||
{ | |||
return (int)(3 - _nread) - _phase; | |||
} | |||
int CResampler::inpsize (void) const | |||
{ | |||
return 4; | |||
} | |||
int CResampler::reset (void) | |||
{ | |||
inp_count = 0; | |||
out_count = 0; | |||
inp_data = 0; | |||
out_data = 0; | |||
_index = 0; | |||
_phase = 0; | |||
_nread = 4; | |||
_nzero = 0; | |||
return 0; | |||
} | |||
int CResampler::process (void) | |||
{ | |||
unsigned int in, nr, n, c; | |||
int nz; | |||
double ph; | |||
float *pb, a, b, d, m0, m1, m2, m3; | |||
in = _index; | |||
nr = _nread; | |||
nz = _nzero; | |||
ph = _phase; | |||
pb = _buff + in * _nchan; | |||
while (out_count) | |||
{ | |||
if (nr) | |||
{ | |||
if (inp_count == 0) break; | |||
n = (4 - nr) * _nchan; | |||
if (inp_data) | |||
{ | |||
for (c = 0; c < _nchan; c++) pb [n + c] = inp_data [c]; | |||
inp_data += _nchan; | |||
nz = 0; | |||
} | |||
else | |||
{ | |||
for (c = 0; c < _nchan; c++) pb [n + c] = 0; | |||
if (nz < 4) nz++; | |||
} | |||
nr--; | |||
inp_count--; | |||
} | |||
else | |||
{ | |||
n = _nchan; | |||
if (out_data) | |||
{ | |||
if (nz < 4) | |||
{ | |||
a = ph; | |||
b = 1 - a; | |||
d = a * b / 2; | |||
m0 = -d * b; | |||
m1 = b + (3 * b - 1) * d; | |||
m2 = a + (3 * a - 1) * d; | |||
m3 = -d * a; | |||
for (c = 0; c < n; c++) | |||
{ | |||
*out_data++ = m0 * pb [0] | |||
+ m1 * pb [n] | |||
+ m2 * pb [2 * n] | |||
+ m3 * pb [3 * n]; | |||
pb++; | |||
} | |||
pb -= n; | |||
} | |||
else | |||
{ | |||
for (c = 0; c < n; c++) *out_data++ = 0; | |||
} | |||
} | |||
out_count--; | |||
ph += _pstep; | |||
if (ph >= 1.0) | |||
{ | |||
nr = (unsigned int) floor (ph); | |||
ph -= nr; | |||
in += nr; | |||
pb += nr * _nchan; | |||
if (in >= _inmax) | |||
{ | |||
memcpy (_buff, pb, (4 - nr) * _nchan * sizeof (float)); | |||
in = 0; | |||
pb = _buff; | |||
} | |||
} | |||
} | |||
} | |||
_index = in; | |||
_nread = nr; | |||
_nzero = nz; | |||
_phase = ph; | |||
return 0; | |||
} | |||
@@ -0,0 +1,65 @@ | |||
// ---------------------------------------------------------------------------- | |||
// | |||
// Copyright (C) 2013 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 __CRESAMPLER_H | |||
#define __CRESAMPLER_H | |||
class CResampler | |||
{ | |||
public: | |||
CResampler (void); | |||
~CResampler (void); | |||
int setup (double ratio, | |||
unsigned int nchan); | |||
void clear (void); | |||
int reset (void); | |||
int nchan (void) const { return _nchan; } | |||
int inpsize (void) const; | |||
double inpdist (void) const; | |||
int process (void); | |||
void set_ratio (double r); | |||
void set_phase (double p); | |||
unsigned int inp_count; | |||
unsigned int out_count; | |||
float *inp_data; | |||
float *out_data; | |||
void *inp_list; | |||
void *out_list; | |||
private: | |||
unsigned int _nchan; | |||
unsigned int _inmax; | |||
unsigned int _index; | |||
unsigned int _nread; | |||
unsigned int _nzero; | |||
double _phase; | |||
double _pstep; | |||
float *_buff; | |||
}; | |||
#endif |
@@ -0,0 +1,148 @@ | |||
// ---------------------------------------------------------------------------- | |||
// | |||
// Copyright (C) 2006-2012 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 <stdlib.h> | |||
#include <stdio.h> | |||
#include <string.h> | |||
#include <math.h> | |||
#include "resampler-table.h" | |||
static double sinc (double x) | |||
{ | |||
x = fabs (x); | |||
if (x < 1e-6) return 1.0; | |||
x *= M_PI; | |||
return sin (x) / x; | |||
} | |||
static double wind (double x) | |||
{ | |||
x = fabs (x); | |||
if (x >= 1.0) return 0.0f; | |||
x *= M_PI; | |||
return 0.384 + 0.500 * cos (x) + 0.116 * cos (2 * x); | |||
} | |||
Resampler_table *Resampler_table::_list = 0; | |||
Resampler_mutex Resampler_table::_mutex; | |||
Resampler_table::Resampler_table (double fr, unsigned int hl, unsigned int np) : | |||
_next (0), | |||
_refc (0), | |||
_fr (fr), | |||
_hl (hl), | |||
_np (np) | |||
{ | |||
unsigned int i, j; | |||
double t; | |||
float *p; | |||
_ctab = new float [hl * (np + 1)]; | |||
p = _ctab; | |||
for (j = 0; j <= np; j++) | |||
{ | |||
t = (double) j / (double) np; | |||
for (i = 0; i < hl; i++) | |||
{ | |||
p [hl - i - 1] = (float)(fr * sinc (t * fr) * wind (t / hl)); | |||
t += 1; | |||
} | |||
p += hl; | |||
} | |||
} | |||
Resampler_table::~Resampler_table (void) | |||
{ | |||
delete[] _ctab; | |||
} | |||
Resampler_table *Resampler_table::create (double fr, unsigned int hl, unsigned int np) | |||
{ | |||
Resampler_table *P; | |||
_mutex.lock (); | |||
P = _list; | |||
while (P) | |||
{ | |||
if ((fr >= P->_fr * 0.999) && (fr <= P->_fr * 1.001) && (hl == P->_hl) && (np == P->_np)) | |||
{ | |||
P->_refc++; | |||
_mutex.unlock (); | |||
return P; | |||
} | |||
P = P->_next; | |||
} | |||
P = new Resampler_table (fr, hl, np); | |||
P->_refc = 1; | |||
P->_next = _list; | |||
_list = P; | |||
_mutex.unlock (); | |||
return P; | |||
} | |||
void Resampler_table::destroy (Resampler_table *T) | |||
{ | |||
Resampler_table *P, *Q; | |||
_mutex.lock (); | |||
if (T) | |||
{ | |||
T->_refc--; | |||
if (T->_refc == 0) | |||
{ | |||
P = _list; | |||
Q = 0; | |||
while (P) | |||
{ | |||
if (P == T) | |||
{ | |||
if (Q) Q->_next = T->_next; | |||
else _list = T->_next; | |||
break; | |||
} | |||
Q = P; | |||
P = P->_next; | |||
} | |||
delete T; | |||
} | |||
} | |||
_mutex.unlock (); | |||
} | |||
void Resampler_table::print_list (void) | |||
{ | |||
Resampler_table *P; | |||
printf ("Resampler table\n----\n"); | |||
for (P = _list; P; P = P->_next) | |||
{ | |||
printf ("refc = %3d fr = %10.6lf hl = %4d np = %4d\n", P->_refc, P->_fr, P->_hl, P->_np); | |||
} | |||
printf ("----\n\n"); | |||
} | |||
@@ -0,0 +1,72 @@ | |||
// ---------------------------------------------------------------------------- | |||
// | |||
// Copyright (C) 2006-2012 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 __RESAMPLER_TABLE_H | |||
#define __RESAMPLER_TABLE_H | |||
#include <pthread.h> | |||
class Resampler_mutex | |||
{ | |||
private: | |||
friend class Resampler_table; | |||
Resampler_mutex (void) { pthread_mutex_init (&_mutex, 0); } | |||
~Resampler_mutex (void) { pthread_mutex_destroy (&_mutex); } | |||
void lock (void) { pthread_mutex_lock (&_mutex); } | |||
void unlock (void) { pthread_mutex_unlock (&_mutex); } | |||
pthread_mutex_t _mutex; | |||
}; | |||
class Resampler_table | |||
{ | |||
public: | |||
static void print_list (void); | |||
private: | |||
Resampler_table (double fr, unsigned int hl, unsigned int np); | |||
~Resampler_table (void); | |||
friend class Resampler; | |||
friend class VResampler; | |||
Resampler_table *_next; | |||
unsigned int _refc; | |||
float *_ctab; | |||
double _fr; | |||
unsigned int _hl; | |||
unsigned int _np; | |||
static Resampler_table *create (double fr, unsigned int hl, unsigned int np); | |||
static void destroy (Resampler_table *T); | |||
static Resampler_table *_list; | |||
static Resampler_mutex _mutex; | |||
}; | |||
#endif |
@@ -0,0 +1,263 @@ | |||
// ---------------------------------------------------------------------------- | |||
// | |||
// Copyright (C) 2006-2012 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 <stdlib.h> | |||
#include <stdio.h> | |||
#include <string.h> | |||
#include <math.h> | |||
#include "resampler.h" | |||
static unsigned int gcd (unsigned int a, unsigned int b) | |||
{ | |||
if (a == 0) return b; | |||
if (b == 0) return a; | |||
while (1) | |||
{ | |||
if (a > b) | |||
{ | |||
a = a % b; | |||
if (a == 0) return b; | |||
if (a == 1) return 1; | |||
} | |||
else | |||
{ | |||
b = b % a; | |||
if (b == 0) return a; | |||
if (b == 1) return 1; | |||
} | |||
} | |||
return 1; | |||
} | |||
Resampler::Resampler (void) : | |||
_table (0), | |||
_nchan (0), | |||
_buff (0) | |||
{ | |||
reset (); | |||
} | |||
Resampler::~Resampler (void) | |||
{ | |||
clear (); | |||
} | |||
int Resampler::setup (unsigned int fs_inp, | |||
unsigned int fs_out, | |||
unsigned int nchan, | |||
unsigned int hlen) | |||
{ | |||
if ((hlen < 8) || (hlen > 96)) return 1; | |||
return setup (fs_inp, fs_out, nchan, hlen, 1.0 - 2.6 / hlen); | |||
} | |||
int Resampler::setup (unsigned int fs_inp, | |||
unsigned int fs_out, | |||
unsigned int nchan, | |||
unsigned int hlen, | |||
double frel) | |||
{ | |||
unsigned int g, h, k, n, s; | |||
double r; | |||
float *B = 0; | |||
Resampler_table *T = 0; | |||
k = s = 0; | |||
if (fs_inp && fs_out && nchan) | |||
{ | |||
r = (double) fs_out / (double) fs_inp; | |||
g = gcd (fs_out, fs_inp); | |||
n = fs_out / g; | |||
s = fs_inp / g; | |||
if ((16 * r >= 1) && (n <= 1000)) | |||
{ | |||
h = hlen; | |||
k = 250; | |||
if (r < 1) | |||
{ | |||
frel *= r; | |||
h = (unsigned int)(ceil (h / r)); | |||
k = (unsigned int)(ceil (k / r)); | |||
} | |||
T = Resampler_table::create (frel, h, n); | |||
B = new float [nchan * (2 * h - 1 + k)]; | |||
} | |||
} | |||
clear (); | |||
if (T) | |||
{ | |||
_table = T; | |||
_buff = B; | |||
_nchan = nchan; | |||
_inmax = k; | |||
_pstep = s; | |||
return reset (); | |||
} | |||
else return 1; | |||
} | |||
void Resampler::clear (void) | |||
{ | |||
Resampler_table::destroy (_table); | |||
delete[] _buff; | |||
_buff = 0; | |||
_table = 0; | |||
_nchan = 0; | |||
_inmax = 0; | |||
_pstep = 0; | |||
reset (); | |||
} | |||
double Resampler::inpdist (void) const | |||
{ | |||
if (!_table) return 0; | |||
return (int)(_table->_hl + 1 - _nread) - (double)_phase / _table->_np; | |||
} | |||
int Resampler::inpsize (void) const | |||
{ | |||
if (!_table) return 0; | |||
return 2 * _table->_hl; | |||
} | |||
int Resampler::reset (void) | |||
{ | |||
if (!_table) return 1; | |||
inp_count = 0; | |||
out_count = 0; | |||
inp_data = 0; | |||
out_data = 0; | |||
_index = 0; | |||
_nread = 0; | |||
_nzero = 0; | |||
_phase = 0; | |||
if (_table) | |||
{ | |||
_nread = 2 * _table->_hl; | |||
return 0; | |||
} | |||
return 1; | |||
} | |||
int Resampler::process (void) | |||
{ | |||
unsigned int hl, ph, np, dp, in, nr, nz, i, n, c; | |||
float *p1, *p2; | |||
if (!_table) return 1; | |||
hl = _table->_hl; | |||
np = _table->_np; | |||
dp = _pstep; | |||
in = _index; | |||
nr = _nread; | |||
ph = _phase; | |||
nz = _nzero; | |||
n = (2 * hl - nr) * _nchan; | |||
p1 = _buff + in * _nchan; | |||
p2 = p1 + n; | |||
while (out_count) | |||
{ | |||
if (nr) | |||
{ | |||
if (inp_count == 0) break; | |||
if (inp_data) | |||
{ | |||
for (c = 0; c < _nchan; c++) p2 [c] = inp_data [c]; | |||
inp_data += _nchan; | |||
nz = 0; | |||
} | |||
else | |||
{ | |||
for (c = 0; c < _nchan; c++) p2 [c] = 0; | |||
if (nz < 2 * hl) nz++; | |||
} | |||
nr--; | |||
p2 += _nchan; | |||
inp_count--; | |||
} | |||
else | |||
{ | |||
if (out_data) | |||
{ | |||
if (nz < 2 * hl) | |||
{ | |||
float *c1 = _table->_ctab + hl * ph; | |||
float *c2 = _table->_ctab + hl * (np - ph); | |||
for (c = 0; c < _nchan; c++) | |||
{ | |||
float *q1 = p1 + c; | |||
float *q2 = p2 + c; | |||
float s = 1e-20f; | |||
for (i = 0; i < hl; i++) | |||
{ | |||
q2 -= _nchan; | |||
s += *q1 * c1 [i] + *q2 * c2 [i]; | |||
q1 += _nchan; | |||
} | |||
*out_data++ = s - 1e-20f; | |||
} | |||
} | |||
else | |||
{ | |||
for (c = 0; c < _nchan; c++) *out_data++ = 0; | |||
} | |||
} | |||
out_count--; | |||
ph += dp; | |||
if (ph >= np) | |||
{ | |||
nr = ph / np; | |||
ph -= nr * np; | |||
in += nr; | |||
p1 += nr * _nchan;; | |||
if (in >= _inmax) | |||
{ | |||
n = (2 * hl - nr) * _nchan; | |||
memcpy (_buff, p1, n * sizeof (float)); | |||
in = 0; | |||
p1 = _buff; | |||
p2 = p1 + n; | |||
} | |||
} | |||
} | |||
} | |||
_index = in; | |||
_nread = nr; | |||
_phase = ph; | |||
_nzero = nz; | |||
return 0; | |||
} | |||
@@ -0,0 +1,76 @@ | |||
// ---------------------------------------------------------------------------- | |||
// | |||
// Copyright (C) 2006-2012 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 __RESAMPLER_H | |||
#define __RESAMPLER_H | |||
#include "resampler-table.h" | |||
class Resampler | |||
{ | |||
public: | |||
Resampler (void); | |||
~Resampler (void); | |||
int setup (unsigned int fs_inp, | |||
unsigned int fs_out, | |||
unsigned int nchan, | |||
unsigned int hlen); | |||
int setup (unsigned int fs_inp, | |||
unsigned int fs_out, | |||
unsigned int nchan, | |||
unsigned int hlen, | |||
double frel); | |||
void clear (void); | |||
int reset (void); | |||
int nchan (void) const { return _nchan; } | |||
int filtlen (void) const { return inpsize (); } // Deprecated | |||
int inpsize (void) const; | |||
double inpdist (void) const; | |||
int process (void); | |||
unsigned int inp_count; | |||
unsigned int out_count; | |||
float *inp_data; | |||
float *out_data; | |||
void *inp_list; | |||
void *out_list; | |||
private: | |||
Resampler_table *_table; | |||
unsigned int _nchan; | |||
unsigned int _inmax; | |||
unsigned int _index; | |||
unsigned int _nread; | |||
unsigned int _nzero; | |||
unsigned int _phase; | |||
unsigned int _pstep; | |||
float *_buff; | |||
void *_dummy [8]; | |||
}; | |||
#endif |
@@ -0,0 +1,272 @@ | |||
// ---------------------------------------------------------------------------- | |||
// | |||
// Copyright (C) 2006-2013 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 <stdlib.h> | |||
#include <stdio.h> | |||
#include <string.h> | |||
#include <math.h> | |||
#include "vresampler.h" | |||
VResampler::VResampler (void) : | |||
_table (0), | |||
_nchan (0), | |||
_buff (0), | |||
_c1 (0), | |||
_c2 (0) | |||
{ | |||
reset (); | |||
} | |||
VResampler::~VResampler (void) | |||
{ | |||
clear (); | |||
} | |||
int VResampler::setup (double ratio, | |||
unsigned int nchan, | |||
unsigned int hlen) | |||
{ | |||
if ((hlen < 8) || (hlen > 96) || (16 * ratio < 1) || (ratio > 256)) return 1; | |||
return setup (ratio, nchan, hlen, 1.0 - 2.6 / hlen); | |||
} | |||
int VResampler::setup (double ratio, | |||
unsigned int nchan, | |||
unsigned int hlen, | |||
double frel) | |||
{ | |||
unsigned int h, k, n; | |||
double s; | |||
Resampler_table *T = 0; | |||
if (! nchan) return 1; | |||
n = NPHASE; | |||
s = n / ratio; | |||
h = hlen; | |||
k = 250; | |||
if (ratio < 1) | |||
{ | |||
frel *= ratio; | |||
h = (unsigned int)(ceil (h / ratio)); | |||
k = (unsigned int)(ceil (k / ratio)); | |||
} | |||
T = Resampler_table::create (frel, h, n); | |||
clear (); | |||
if (T) | |||
{ | |||
_table = T; | |||
_buff = new float [nchan * (2 * h - 1 + k)]; | |||
_c1 = new float [2 * h]; | |||
_c2 = new float [2 * h]; | |||
_nchan = nchan; | |||
_inmax = k; | |||
_ratio = ratio; | |||
_pstep = s; | |||
_qstep = s; | |||
_wstep = 1; | |||
return reset (); | |||
} | |||
else return 1; | |||
} | |||
void VResampler::clear (void) | |||
{ | |||
Resampler_table::destroy (_table); | |||
delete[] _buff; | |||
delete[] _c1; | |||
delete[] _c2; | |||
_buff = 0; | |||
_c1 = 0; | |||
_c2 = 0; | |||
_table = 0; | |||
_nchan = 0; | |||
_inmax = 0; | |||
_pstep = 0; | |||
_qstep = 0; | |||
_wstep = 1; | |||
reset (); | |||
} | |||
void VResampler::set_phase (double p) | |||
{ | |||
if (!_table) return; | |||
_phase = (p - floor (p)) * _table->_np; | |||
} | |||
void VResampler::set_rrfilt (double t) | |||
{ | |||
if (!_table) return; | |||
_wstep = (t < 1) ? 1 : 1 - exp (-1 / t); | |||
} | |||
void VResampler::set_rratio (double r) | |||
{ | |||
if (!_table) return; | |||
if (r > 16.0) r = 16.0; | |||
if (r < 0.95) r = 0.95; | |||
_qstep = _table->_np / (_ratio * r); | |||
} | |||
double VResampler::inpdist (void) const | |||
{ | |||
if (!_table) return 0; | |||
return (int)(_table->_hl + 1 - _nread) - _phase / _table->_np; | |||
} | |||
int VResampler::inpsize (void) const | |||
{ | |||
if (!_table) return 0; | |||
return 2 * _table->_hl; | |||
} | |||
int VResampler::reset (void) | |||
{ | |||
if (!_table) return 1; | |||
inp_count = 0; | |||
out_count = 0; | |||
inp_data = 0; | |||
out_data = 0; | |||
_index = 0; | |||
_phase = 0; | |||
_nread = 2 * _table->_hl; | |||
_nzero = 0; | |||
return 0; | |||
} | |||
int VResampler::process (void) | |||
{ | |||
unsigned int k, np, in, nr, n, c; | |||
int i, hl, nz; | |||
double ph, dp, dd; | |||
float a, b, *p1, *p2, *q1, *q2; | |||
if (!_table) return 1; | |||
hl = _table->_hl; | |||
np = _table->_np; | |||
in = _index; | |||
nr = _nread; | |||
nz = _nzero; | |||
ph = _phase; | |||
dp = _pstep; | |||
n = (2 * hl - nr) * _nchan; | |||
p1 = _buff + in * _nchan; | |||
p2 = p1 + n; | |||
while (out_count) | |||
{ | |||
if (nr) | |||
{ | |||
if (inp_count == 0) break; | |||
if (inp_data) | |||
{ | |||
for (c = 0; c < _nchan; c++) p2 [c] = inp_data [c]; | |||
inp_data += _nchan; | |||
nz = 0; | |||
} | |||
else | |||
{ | |||
for (c = 0; c < _nchan; c++) p2 [c] = 0; | |||
if (nz < 2 * hl) nz++; | |||
} | |||
nr--; | |||
p2 += _nchan; | |||
inp_count--; | |||
} | |||
else | |||
{ | |||
if (out_data) | |||
{ | |||
if (nz < 2 * hl) | |||
{ | |||
k = (unsigned int) ph; | |||
b = (float)(ph - k); | |||
a = 1.0f - b; | |||
q1 = _table->_ctab + hl * k; | |||
q2 = _table->_ctab + hl * (np - k); | |||
for (i = 0; i < hl; i++) | |||
{ | |||
_c1 [i] = a * q1 [i] + b * q1 [i + hl]; | |||
_c2 [i] = a * q2 [i] + b * q2 [i - hl]; | |||
} | |||
for (c = 0; c < _nchan; c++) | |||
{ | |||
q1 = p1 + c; | |||
q2 = p2 + c; | |||
a = 1e-25f; | |||
for (i = 0; i < hl; i++) | |||
{ | |||
q2 -= _nchan; | |||
a += *q1 * _c1 [i] + *q2 * _c2 [i]; | |||
q1 += _nchan; | |||
} | |||
*out_data++ = a - 1e-25f; | |||
} | |||
} | |||
else | |||
{ | |||
for (c = 0; c < _nchan; c++) *out_data++ = 0; | |||
} | |||
} | |||
out_count--; | |||
dd = _qstep - dp; | |||
if (fabs (dd) < 1e-30) dp = _qstep; | |||
else dp += _wstep * dd; | |||
ph += dp; | |||
if (ph >= np) | |||
{ | |||
nr = (unsigned int) floor( ph / np); | |||
ph -= nr * np;; | |||
in += nr; | |||
p1 += nr * _nchan;; | |||
if (in >= _inmax) | |||
{ | |||
n = (2 * hl - nr) * _nchan; | |||
memcpy (_buff, p1, n * sizeof (float)); | |||
in = 0; | |||
p1 = _buff; | |||
p2 = p1 + n; | |||
} | |||
} | |||
} | |||
} | |||
_index = in; | |||
_nread = nr; | |||
_phase = ph; | |||
_pstep = dp; | |||
_nzero = nz; | |||
return 0; | |||
} | |||
@@ -0,0 +1,84 @@ | |||
// ---------------------------------------------------------------------------- | |||
// | |||
// Copyright (C) 2006-2012 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 __VRESAMPLER_H | |||
#define __VRESAMPLER_H | |||
#include "resampler-table.h" | |||
class VResampler | |||
{ | |||
public: | |||
VResampler (void); | |||
~VResampler (void); | |||
int setup (double ratio, | |||
unsigned int nchan, | |||
unsigned int hlen); | |||
int setup (double ratio, | |||
unsigned int nchan, | |||
unsigned int hlen, | |||
double frel); | |||
void clear (void); | |||
int reset (void); | |||
int nchan (void) const { return _nchan; } | |||
int inpsize (void) const; | |||
double inpdist (void) const; | |||
int process (void); | |||
void set_phase (double p); | |||
void set_rrfilt (double t); | |||
void set_rratio (double r); | |||
unsigned int inp_count; | |||
unsigned int out_count; | |||
float *inp_data; | |||
float *out_data; | |||
void *inp_list; | |||
void *out_list; | |||
private: | |||
enum { NPHASE = 256 }; | |||
Resampler_table *_table; | |||
unsigned int _nchan; | |||
unsigned int _inmax; | |||
unsigned int _index; | |||
unsigned int _nread; | |||
unsigned int _nzero; | |||
double _ratio; | |||
double _phase; | |||
double _pstep; | |||
double _qstep; | |||
double _wstep; | |||
float *_buff; | |||
float *_c1; | |||
float *_c2; | |||
void *_dummy [8]; | |||
}; | |||
#endif |
@@ -25,6 +25,8 @@ extern "C" { | |||
#include "audio_decoder/ad.h" | |||
} | |||
#include "zita-resampler/resampler.h" | |||
typedef struct adinfo ADInfo; | |||
struct AudioFilePool { | |||
@@ -114,7 +116,8 @@ public: | |||
fPollTempSize(0), | |||
fPool(), | |||
fMutex(), | |||
fSignal() | |||
fSignal(), | |||
fResampler() | |||
{ | |||
static bool adInitiated = false; | |||
@@ -590,6 +593,7 @@ private: | |||
AudioFilePool fPool; | |||
CarlaMutex fMutex; | |||
CarlaSignal fSignal; | |||
Resampler fResampler; | |||
CARLA_DECLARE_NON_COPY_STRUCT(AudioFileThread) | |||
}; | |||
@@ -70,6 +70,7 @@ LIBS += $(MODULEDIR)/water.a | |||
LIBS += $(MODULEDIR)/audio_decoder.a | |||
LIBS += $(MODULEDIR)/native-plugins.a | |||
LIBS += $(MODULEDIR)/sfzero.a | |||
LIBS += $(MODULEDIR)/zita-resampler.a | |||
ifeq ($(HAVE_DGL),true) | |||
LIBS += $(MODULEDIR)/dgl.a | |||