@@ -40,6 +40,7 @@ ALL_LIBS += $(MODULEDIR)/rtmempool.a | |||||
3RD_LIBS += $(MODULEDIR)/lilv.a | 3RD_LIBS += $(MODULEDIR)/lilv.a | ||||
3RD_LIBS += $(MODULEDIR)/sfzero.a | 3RD_LIBS += $(MODULEDIR)/sfzero.a | ||||
3RD_LIBS += $(MODULEDIR)/water.a | 3RD_LIBS += $(MODULEDIR)/water.a | ||||
3RD_LIBS += $(MODULEDIR)/zita-resampler.a | |||||
ifeq ($(HAVE_DGL),true) | ifeq ($(HAVE_DGL),true) | ||||
3RD_LIBS += $(MODULEDIR)/dgl.a | 3RD_LIBS += $(MODULEDIR)/dgl.a | ||||
@@ -28,6 +28,7 @@ STANDALONE_LIBS += $(MODULEDIR)/native-plugins.a | |||||
STANDALONE_LIBS += $(MODULEDIR)/rtmempool.a | STANDALONE_LIBS += $(MODULEDIR)/rtmempool.a | ||||
STANDALONE_LIBS += $(MODULEDIR)/sfzero.a | STANDALONE_LIBS += $(MODULEDIR)/sfzero.a | ||||
STANDALONE_LIBS += $(MODULEDIR)/water.a | STANDALONE_LIBS += $(MODULEDIR)/water.a | ||||
STANDALONE_LIBS += $(MODULEDIR)/zita-resampler.a | |||||
ifeq ($(HAVE_DGL),true) | ifeq ($(HAVE_DGL),true) | ||||
STANDALONE_LIBS += $(MODULEDIR)/dgl.a | STANDALONE_LIBS += $(MODULEDIR)/dgl.a | ||||
@@ -157,6 +157,7 @@ NATIVE_LINK_FLAGS += $(MAGIC_LIBS) | |||||
LIBS_native += $(MODULEDIR)/audio_decoder.a | LIBS_native += $(MODULEDIR)/audio_decoder.a | ||||
LIBS_native += $(MODULEDIR)/native-plugins.a | LIBS_native += $(MODULEDIR)/native-plugins.a | ||||
LIBS_native += $(MODULEDIR)/sfzero.a | LIBS_native += $(MODULEDIR)/sfzero.a | ||||
LIBS_native += $(MODULEDIR)/zita-resampler.a | |||||
ifeq ($(HAVE_DGL),true) | ifeq ($(HAVE_DGL),true) | ||||
LIBS_native += $(MODULEDIR)/dgl.a | LIBS_native += $(MODULEDIR)/dgl.a | ||||
@@ -17,6 +17,7 @@ clean: | |||||
$(MAKE) clean -C rtmidi | $(MAKE) clean -C rtmidi | ||||
$(MAKE) clean -C sfzero | $(MAKE) clean -C sfzero | ||||
$(MAKE) clean -C water | $(MAKE) clean -C water | ||||
$(MAKE) clean -C zita-resampler | |||||
$(MAKE) clean -C juce_audio_basics | $(MAKE) clean -C juce_audio_basics | ||||
$(MAKE) clean -C juce_audio_devices | $(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 "audio_decoder/ad.h" | ||||
} | } | ||||
#include "zita-resampler/resampler.h" | |||||
typedef struct adinfo ADInfo; | typedef struct adinfo ADInfo; | ||||
struct AudioFilePool { | struct AudioFilePool { | ||||
@@ -114,7 +116,8 @@ public: | |||||
fPollTempSize(0), | fPollTempSize(0), | ||||
fPool(), | fPool(), | ||||
fMutex(), | fMutex(), | ||||
fSignal() | |||||
fSignal(), | |||||
fResampler() | |||||
{ | { | ||||
static bool adInitiated = false; | static bool adInitiated = false; | ||||
@@ -590,6 +593,7 @@ private: | |||||
AudioFilePool fPool; | AudioFilePool fPool; | ||||
CarlaMutex fMutex; | CarlaMutex fMutex; | ||||
CarlaSignal fSignal; | CarlaSignal fSignal; | ||||
Resampler fResampler; | |||||
CARLA_DECLARE_NON_COPY_STRUCT(AudioFileThread) | CARLA_DECLARE_NON_COPY_STRUCT(AudioFileThread) | ||||
}; | }; | ||||
@@ -70,6 +70,7 @@ LIBS += $(MODULEDIR)/water.a | |||||
LIBS += $(MODULEDIR)/audio_decoder.a | LIBS += $(MODULEDIR)/audio_decoder.a | ||||
LIBS += $(MODULEDIR)/native-plugins.a | LIBS += $(MODULEDIR)/native-plugins.a | ||||
LIBS += $(MODULEDIR)/sfzero.a | LIBS += $(MODULEDIR)/sfzero.a | ||||
LIBS += $(MODULEDIR)/zita-resampler.a | |||||
ifeq ($(HAVE_DGL),true) | ifeq ($(HAVE_DGL),true) | ||||
LIBS += $(MODULEDIR)/dgl.a | LIBS += $(MODULEDIR)/dgl.a | ||||