// ---------------------------------------------------------------------------- // // Copyright (C) 2006-2013 Fons Adriaensen // // 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 . // // ---------------------------------------------------------------------------- #include #include #include #include #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; }