M build/run-platform-tests.sh +1 -1
@@ 35,7 35,7 @@ run() {
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
M speex/COPYING => ext/speex/COPYING +0 -0
M speex/resample.c => ext/speex/resample.c +0 -0
M speex/speex_resampler.h => ext/speex/speex_resampler.h +0 -0
M src/BQResampler.cpp +1 -0
@@ 34,6 34,7 @@
*/
#include "BQResampler.h"
+#include "common.h"
#include <cmath>
M src/Resampler.cpp +42 -18
@@ 34,6 34,7 @@
*/
#include "bqresample/Resampler.h"
+#include "common.h"
#include <cstdlib>
#include <cmath>
@@ 62,7 63,11 @@
#endif
#ifdef USE_SPEEX
-#include "../speex/speex_resampler.h"
+#include "../ext/speex/speex_resampler.h"
+#else
+#ifdef HAVE_LIBSPEEXDSP
+#include <speex/speex_resampler.h>
+#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 @@ D_BQResampler::reset()
#endif /* USE_BQRESAMPLER */
-#ifdef USE_SPEEX
+#if defined(USE_SPEEX) || defined(HAVE_LIBSPEEXDSP)
class D_Speex : public Resampler::Impl
{
@@ 1029,19 1036,23 @@ D_Speex::setRatio(double ratio)
// 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 @@ D_Speex::setRatio(double ratio)
(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 @@ Resampler::Resampler(Resampler::Paramete
#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 @@ Resampler::Resampler(Resampler::Paramete
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 @@ Resampler::Resampler(Resampler::Paramete
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 @@ Resampler::Resampler(Resampler::Paramete
break;
case 2:
-#ifdef USE_SPEEX
+#if defined(USE_SPEEX) || defined(HAVE_LIBSPEEXDSP)
d = new Resamplers::D_Speex
(params.quality, params.ratioChange,
channels,
A => src/common.cpp +82 -0
@@ 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 <cmath>
+
+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;
+ }
+}
+
+}
+
A => src/common.h +45 -0
@@ 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