# HG changeset patch # User Chris Cannam # Date 1673951978 0 # Tue Jan 17 10:39:38 2023 +0000 # Node ID d49b880c933270e3dc34cd553a5066d5ab3c13ae # Parent 9ccd4c27fa5748aa7717fb16235094e86b1d8acb Add speexdsp support diff --git a/build/run-platform-tests.sh b/build/run-platform-tests.sh --- a/build/run-platform-tests.sh +++ b/build/run-platform-tests.sh @@ -35,7 +35,7 @@ shift echo -n "Running \"$@\"..." if "$@" > "$tmpfile" 2>&1 ; then - if [ -z "$successtext" ] || fgrep -q "$successtext" "$tmpfile" ; then + if [ -z "$successtext" ] || grep -f -q "$successtext" "$tmpfile" ; then echo " OK" return 0 else diff --git a/speex/COPYING b/ext/speex/COPYING rename from speex/COPYING rename to ext/speex/COPYING diff --git a/speex/resample.c b/ext/speex/resample.c rename from speex/resample.c rename to ext/speex/resample.c diff --git a/speex/speex_resampler.h b/ext/speex/speex_resampler.h rename from speex/speex_resampler.h rename to ext/speex/speex_resampler.h diff --git a/src/BQResampler.cpp b/src/BQResampler.cpp --- a/src/BQResampler.cpp +++ b/src/BQResampler.cpp @@ -34,6 +34,7 @@ */ #include "BQResampler.h" +#include "common.h" #include diff --git a/src/Resampler.cpp b/src/Resampler.cpp --- a/src/Resampler.cpp +++ b/src/Resampler.cpp @@ -34,6 +34,7 @@ */ #include "bqresample/Resampler.h" +#include "common.h" #include #include @@ -62,7 +63,11 @@ #endif #ifdef USE_SPEEX -#include "../speex/speex_resampler.h" +#include "../ext/speex/speex_resampler.h" +#else +#ifdef HAVE_LIBSPEEXDSP +#include +#endif #endif #ifdef USE_BQRESAMPLER @@ -71,6 +76,7 @@ #ifndef HAVE_IPP #ifndef HAVE_LIBSAMPLERATE +#ifndef HAVE_LIBSPEEXDSP #ifndef USE_SPEEX #ifndef USE_BQRESAMPLER #error No resampler implementation selected! @@ -78,6 +84,7 @@ #endif #endif #endif +#endif using namespace std; @@ -921,7 +928,7 @@ #endif /* USE_BQRESAMPLER */ -#ifdef USE_SPEEX +#if defined(USE_SPEEX) || defined(HAVE_LIBSPEEXDSP) class D_Speex : public Resampler::Impl { @@ -1029,19 +1036,23 @@ // Speex wants a ratio of two unsigned integers, not a single // float. Let's do that. - unsigned int big = 272408136U; - unsigned int denom = 1, num = 1; + int max_denom = 48000; + if (ratio > 1.0) { + max_denom = int(ceil(48000 / ratio)); + } + + int inum, idenom; + pickNearestRational(ratio, max_denom, inum, idenom); - if (ratio < 1.f) { - denom = big; - double dnum = double(big) * double(ratio); - num = (unsigned int)dnum; - } else if (ratio > 1.f) { - num = big; - double ddenom = double(big) / double(ratio); - denom = (unsigned int)ddenom; + if (inum < 0 || idenom < 0) { + cerr << "Resampler::setRatio: Internal error: " + << "numerator or denominator < 0 (" + << inum << "/" << idenom << ")" << endl; + return; } + unsigned int num = inum, denom = idenom; + if (m_debugLevel > 1) { cerr << "D_Speex: Desired ratio " << ratio << ", requesting ratio " << num << "/" << denom << " = " << float(double(num)/double(denom)) @@ -1055,8 +1066,12 @@ (m_resampler, denom, num, fromRate, toRate); if (err) { - cerr << "Resampler::Resampler: failed to set rate on Speex resampler" - << endl; + cerr << "Resampler::Resampler: failed to set rate on Speex resampler" + << " (with ratio = " << ratio << " [ratio-1 = " << ratio - 1.0 + << "], denom = " << denom + << ", num = " << num << ", fromRate = " << fromRate + << ", toRate = " << toRate << ", err = " << err + << ")" << endl; #ifndef NO_EXCEPTIONS throw Resampler::ImplementationError; #endif @@ -1219,8 +1234,11 @@ #ifdef USE_SPEEX m_method = 2; #endif +#ifdef HAVE_LIBSPEEXDSP + m_method = 2; +#endif #ifdef USE_BQRESAMPLER - m_method = 4; + m_method = 3; #endif #ifdef HAVE_LIBSAMPLERATE m_method = 1; @@ -1235,11 +1253,14 @@ m_method = 2; #endif #ifdef USE_BQRESAMPLER - m_method = 4; + m_method = 3; #endif #ifdef HAVE_LIBSAMPLERATE m_method = 1; #endif +#ifdef HAVE_LIBSPEEXDSP + m_method = 2; +#endif break; case Resampler::Fastest: @@ -1250,11 +1271,14 @@ m_method = 2; #endif #ifdef USE_BQRESAMPLER - m_method = 4; + m_method = 3; #endif #ifdef HAVE_LIBSAMPLERATE m_method = 1; #endif +#ifdef HAVE_LIBSPEEXDSP + m_method = 2; +#endif break; } @@ -1289,7 +1313,7 @@ break; case 2: -#ifdef USE_SPEEX +#if defined(USE_SPEEX) || defined(HAVE_LIBSPEEXDSP) d = new Resamplers::D_Speex (params.quality, params.ratioChange, channels, diff --git a/src/common.cpp b/src/common.cpp new file mode 100644 --- /dev/null +++ b/src/common.cpp @@ -0,0 +1,82 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + bqresample + + A small library wrapping various audio sample rate conversion + implementations in C++. + + Copyright 2007-2023 Particular Programs Ltd. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of Chris Cannam and + Particular Programs Ltd shall not be used in advertising or + otherwise to promote the sale, use or other dealings in this + Software without prior written authorization. +*/ + +#include + +namespace breakfastquay { + +void pickNearestRational(double ratio, int max_denom, int &num, int &denom) +{ + // Farey algorithm, see + // https://www.johndcook.com/blog/2010/10/20/best-rational-approximation/ + double a = 0.0, b = 1.0, c = 1.0, d = 0.0; + double pa = a, pb = b, pc = c, pd = d; + double eps = 1e-9; + while (b <= max_denom && d <= max_denom) { + double mediant = (a + c) / (b + d); + if (fabs(ratio - mediant) < eps) { + if (b + d <= max_denom) { + num = a + c; + denom = b + d; + return; + } else if (d > b) { + num = c; + denom = d; + return; + } else { + num = a; + denom = b; + return; + } + } + if (ratio > mediant) { + pa = a; pb = b; + a += c; b += d; + } else { + pc = c; pd = d; + c += a; d += b; + } + } + if (fabs(ratio - (pc / pd)) < fabs(ratio - (pa / pb))) { + num = pc; + denom = pd; + } else { + num = pa; + denom = pb; + } +} + +} + diff --git a/src/common.h b/src/common.h new file mode 100644 --- /dev/null +++ b/src/common.h @@ -0,0 +1,45 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + bqresample + + A small library wrapping various audio sample rate conversion + implementations in C++. + + Copyright 2007-2023 Particular Programs Ltd. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of Chris Cannam and + Particular Programs Ltd shall not be used in advertising or + otherwise to promote the sale, use or other dealings in this + Software without prior written authorization. +*/ + +#ifndef BQ_BQRESAMPLE_COMMON_H +#define BQ_BQRESAMPLE_COMMON_H + +namespace breakfastquay { + +void pickNearestRational(double ratio, int maxDenom, int &num, int &denom); + +} + +#endif