Merge from branch bqresample

This commit is contained in:
Chris Cannam
2021-05-11 17:20:55 +01:00
17 changed files with 2351 additions and 1990 deletions

View File

@@ -10,7 +10,6 @@ platform:
install:
- cinst wget
- cinst meson
- cinst libsndfile
build_script:

View File

@@ -87,8 +87,8 @@ Rubber Band consists of:
* The Rubber Band Library code. This is the code that will normally
be used by your applications. The headers for this are in the
rubberband/ directory, and the source code is in src/.
The Rubber Band Library depends upon resampler and FFT code; see
section 3a below for details.
The Rubber Band Library may also depend upon external resampler
and FFT code; see section 3a below for details.
* The Rubber Band command-line tool. This is in main/main.cpp.
This program uses the Rubber Band Library and also requires libsndfile
@@ -194,9 +194,9 @@ standard. It is unlikely to make any difference (performance or
otherwise) which C++ standard your compiler uses - as long as it's no
older than C++98!
If you are building this software using one of the bundled library
options (Speex or KissFFT), please be sure to review the terms for
those libraries in `src/speex/COPYING` and `src/kissfft/COPYING` as
If you are building this software using either of the Speex or KissFFT
library options, please be sure to review the terms for those
libraries in `src/speex/COPYING` and `src/kissfft/COPYING` as
applicable.
@@ -369,13 +369,26 @@ options (Speex or KissFFT), please be sure to review the terms for
those libraries in `src/speex/COPYING` and `src/kissfft/COPYING` as
applicable.
If you are proposing to package Rubber Band for a Linux distribution
using other packaged libraries, please select FFTW and libsamplerate.
#### FFT libraries supported
```
Library Build option CPP define Notes
---- ------------ ---------- -----
KissFFT -Dfft=kissfft -DUSE_KISSFFT Default except on macOS/iOS.
Built-in -Dfft=builtin -DUSE_BUILTIN_FFT
Default except on macOS/iOS.
Can be distributed with either
the Rubber Band GPL or
commercial licence.
KissFFT -Dfft=kissfft -DHAVE_KISSFFT
Single precision.
Only indicated for use with
single-precision sample type
(see below).
Bundled, can be distributed with
either the Rubber Band GPL or
commercial licence.
@@ -432,8 +445,9 @@ build files will handle these for you.)
-DPROCESS_SAMPLE_TYPE=float
Select single precision for internal calculations. The default is
double precision. Consider using for mobile architectures with
slower double-precision support.
double precision. Consider in conjunction with single-precision
KissFFT for mobile architectures with slower double-precision
support.
-DUSE_POMMIER_MATHFUN
Select the Julien Pommier implementations of trig functions for ARM

View File

@@ -77,7 +77,7 @@
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..;..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>__MSVC__;WIN32;_DEBUG;_LIB;NOMINMAX;_USE_MATH_DEFINES;USE_KISSFFT;USE_SPEEX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>__MSVC__;WIN32;_DEBUG;_LIB;NOMINMAX;_USE_MATH_DEFINES;USE_BUILTIN_FFT;USE_SPEEX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
@@ -91,7 +91,7 @@
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..;..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>__MSVC__;WIN32;_DEBUG;_LIB;NOMINMAX;_USE_MATH_DEFINES;USE_KISSFFT;USE_SPEEX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>__MSVC__;WIN32;_DEBUG;_LIB;NOMINMAX;_USE_MATH_DEFINES;USE_BUILTIN_FFT;USE_SPEEX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<PrecompiledHeader>
@@ -109,7 +109,7 @@
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<AdditionalIncludeDirectories>..;..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>__MSVC__;WIN32;NDEBUG;_LIB;NOMINMAX;_USE_MATH_DEFINES;USE_KISSFFT;NO_TIMING;USE_SPEEX;NO_THREAD_CHECKS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>__MSVC__;WIN32;NDEBUG;_LIB;NOMINMAX;_USE_MATH_DEFINES;USE_BUILTIN_FFT;NO_TIMING;USE_SPEEX;NO_THREAD_CHECKS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet>
@@ -127,7 +127,7 @@
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<AdditionalIncludeDirectories>..;..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>__MSVC__;WIN32;NDEBUG;_LIB;NOMINMAX;_USE_MATH_DEFINES;USE_KISSFFT;NO_TIMING;USE_SPEEX;NO_THREAD_CHECKS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>__MSVC__;WIN32;NDEBUG;_LIB;NOMINMAX;_USE_MATH_DEFINES;USE_BUILTIN_FFT;NO_TIMING;USE_SPEEX;NO_THREAD_CHECKS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet>
@@ -178,8 +178,6 @@
<ClCompile Include="..\src\dsp\AudioCurveCalculator.cpp" />
<ClCompile Include="..\src\dsp\FFT.cpp" />
<ClCompile Include="..\src\dsp\Resampler.cpp" />
<ClCompile Include="..\src\kissfft\kiss_fft.c" />
<ClCompile Include="..\src\kissfft\kiss_fftr.c" />
<ClCompile Include="..\src\rubberband-c.cpp" />
<ClCompile Include="..\src\RubberBandStretcher.cpp" />
<ClCompile Include="..\src\speex\resample.c" />

View File

@@ -2,7 +2,7 @@
project(
'Rubber Band Library',
'c', 'cpp',
version: '1.9.1',
version: '1.9.2-pre',
license: 'GPL-2.0-or-later',
default_options: [
# All Rubber Band code is actually C++98, but some compilers no
@@ -101,6 +101,9 @@ sndfile_dep = dependency('sndfile', version: '>= 1.0.16', required: false)
vamp_dep = dependency('vamp-sdk', version: '>= 2.9', required: false)
thread_dep = dependency('threads')
have_ladspa = cpp.has_header('ladspa.h', args: extra_include_args)
have_sincos = cpp.has_function('sincos',
prefix: '#define _GNU_SOURCE\n#include <math.h>',
args: '-lm')
have_jni = cpp.has_header('jni.h', args: extra_include_args)
javac = find_program('javac', required: false)
@@ -114,6 +117,7 @@ feature_defines = []
feature_libraries = []
feature_sources = []
pkgconfig_requirements = []
pkgconfig_libraries = []
arch_flags = []
config_summary = {}
@@ -128,7 +132,7 @@ if fft == 'auto'
if system == 'darwin'
fft = 'vdsp'
else
fft = 'kissfft'
fft = 'builtin'
endif
endif
@@ -140,14 +144,23 @@ if resampler == 'auto'
endif
endif
if fft == 'kissfft'
if fft == 'builtin'
config_summary += { 'FFT': 'Built-in' }
message('For FFT: using built-in implementation')
if fftw3_dep.found()
message('(to use FFTW instead, reconfigure with -Dfft=fftw)')
endif
feature_defines += ['-DUSE_BUILTIN_FFT']
elif fft == 'kissfft'
config_summary += { 'FFT': 'KissFFT' }
message('For FFT: using KissFFT')
if fftw3_dep.found()
message('(to use FFTW instead, reconfigure with -Dfft=fftw)')
endif
feature_sources += ['src/kissfft/kiss_fft.c', 'src/kissfft/kiss_fftr.c']
feature_defines += ['-DUSE_KISSFFT']
feature_defines += ['-DHAVE_KISSFFT']
general_include_dirs += 'src/kissfft'
elif fft == 'fftw'
if fftw3_dep.found()
@@ -169,6 +182,7 @@ elif fft == 'vdsp'
message('For FFT: using vDSP')
feature_defines += ['-DHAVE_VDSP']
feature_libraries += ['-framework', 'Accelerate']
pkgconfig_libraries += ['-framework', 'Accelerate']
elif fft == 'ipp'
if ipp_path != ''
@@ -185,7 +199,13 @@ else
endif # fft
if resampler == 'libsamplerate'
if resampler == 'builtin'
config_summary += { 'Resampler': 'Built-in' }
message('For resampler: using built-in implementation')
library_sources += 'src/dsp/BQResampler.cpp'
feature_defines += ['-DUSE_BQRESAMPLER']
elif resampler == 'libsamplerate'
if samplerate_dep.found()
config_summary += { 'Resampler': 'libsamplerate' }
message('For resampler: using libsamplerate')
@@ -223,6 +243,10 @@ else
endif # resampler
if not have_sincos
feature_defines += [ '-DLACK_SINCOS' ]
endif
if ipp_needed
feature_defines += [
'-DHAVE_IPP',
@@ -572,7 +596,7 @@ pkg.generate(
url: 'https://breakfastquay.com/rubberband/',
version: meson.project_version(),
requires: pkgconfig_requirements,
libraries: '-L${libdir} -lrubberband',
libraries: ['-L${libdir} -lrubberband'] + pkgconfig_libraries,
extra_cflags: '-I${includedir}',
)

View File

@@ -1,13 +1,13 @@
option('fft',
type: 'combo',
choices: ['auto', 'kissfft', 'fftw', 'vdsp', 'ipp'],
choices: ['auto', 'builtin', 'kissfft', 'fftw', 'vdsp', 'ipp'],
value: 'auto',
description: 'FFT library to use. The default (auto) will use vDSP if available, KissFFT otherwise.')
description: 'FFT library to use. The default (auto) will use vDSP if available, the builtin implementation otherwise.')
option('resampler',
type: 'combo',
choices: ['auto', 'libsamplerate', 'speex', 'ipp'],
choices: ['auto', 'builtin', 'libsamplerate', 'speex', 'ipp'],
value: 'auto',
description: 'Resampler library to use. Recommended is libsamplerate. The default (auto) will use libsamplerate if available, speex otherwise.')

View File

@@ -6,7 +6,7 @@ OPTFLAGS := -DNDEBUG -ffast-math -O3 -ftree-vectorize
ARCHFLAGS :=
CXXFLAGS := -std=c++98 $(ARCHFLAGS) $(OPTFLAGS) -I. -Isrc -Irubberband -DHAVE_LIBSAMPLERATE -DUSE_KISSFFT -DNO_THREAD_CHECKS -DUSE_PTHREADS -DNO_TIMING -DHAVE_POSIX_MEMALIGN -DNDEBUG
CXXFLAGS := -std=c++98 $(ARCHFLAGS) $(OPTFLAGS) -I. -Isrc -Irubberband -DHAVE_LIBSAMPLERATE -DUSE_BUILTIN_FFT -DNO_THREAD_CHECKS -DUSE_PTHREADS -DNO_TIMING -DHAVE_POSIX_MEMALIGN -DNDEBUG
CFLAGS := $(ARCHFLAGS) $(OPTFLAGS)
@@ -69,10 +69,8 @@ LIBRARY_SOURCES := \
src/system/sysutils.cpp \
src/system/Thread.cpp \
src/StretcherChannelData.cpp \
src/StretcherImpl.cpp \
src/kissfft/kiss_fft.c \
src/kissfft/kiss_fftr.c
src/StretcherImpl.cpp
LIBRARY_OBJECTS := $(LIBRARY_SOURCES:.cpp=.o)
LIBRARY_OBJECTS := $(LIBRARY_OBJECTS:.c=.o)

View File

@@ -77,7 +77,7 @@
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..;..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>__MSVC__;WIN32;_DEBUG;_LIB;NOMINMAX;_USE_MATH_DEFINES;USE_KISSFFT;USE_SPEEX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>__MSVC__;WIN32;_DEBUG;_LIB;NOMINMAX;_USE_MATH_DEFINES;USE_BUILTIN_FFT;USE_SPEEX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
@@ -91,7 +91,7 @@
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..;..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>__MSVC__;WIN32;_DEBUG;_LIB;NOMINMAX;_USE_MATH_DEFINES;USE_KISSFFT;USE_SPEEX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>__MSVC__;WIN32;_DEBUG;_LIB;NOMINMAX;_USE_MATH_DEFINES;USE_BUILTIN_FFT;USE_SPEEX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<PrecompiledHeader>
@@ -109,7 +109,7 @@
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<AdditionalIncludeDirectories>..;..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>__MSVC__;WIN32;NDEBUG;_LIB;NOMINMAX;_USE_MATH_DEFINES;USE_KISSFFT;NO_TIMING;USE_SPEEX;NO_THREAD_CHECKS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>__MSVC__;WIN32;NDEBUG;_LIB;NOMINMAX;_USE_MATH_DEFINES;USE_BUILTIN_FFT;NO_TIMING;USE_SPEEX;NO_THREAD_CHECKS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet>
@@ -127,7 +127,7 @@
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<AdditionalIncludeDirectories>..;..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>__MSVC__;WIN32;NDEBUG;_LIB;NOMINMAX;_USE_MATH_DEFINES;USE_KISSFFT;NO_TIMING;USE_SPEEX;NO_THREAD_CHECKS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>__MSVC__;WIN32;NDEBUG;_LIB;NOMINMAX;_USE_MATH_DEFINES;USE_BUILTIN_FFT;NO_TIMING;USE_SPEEX;NO_THREAD_CHECKS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet>
@@ -178,8 +178,6 @@
<ClCompile Include="..\src\dsp\AudioCurveCalculator.cpp" />
<ClCompile Include="..\src\dsp\FFT.cpp" />
<ClCompile Include="..\src\dsp\Resampler.cpp" />
<ClCompile Include="..\src\kissfft\kiss_fft.c" />
<ClCompile Include="..\src\kissfft\kiss_fftr.c" />
<ClCompile Include="..\src\rubberband-c.cpp" />
<ClCompile Include="..\src\RubberBandStretcher.cpp" />
<ClCompile Include="..\src\speex\resample.c" />

View File

@@ -23,7 +23,6 @@
#include "StretcherImpl.h"
using namespace std;
namespace RubberBand {
@@ -122,7 +121,7 @@ RubberBandStretcher::setMaxProcessSize(size_t samples)
}
void
RubberBandStretcher::setKeyFrameMap(const map<size_t, size_t> &mapping)
RubberBandStretcher::setKeyFrameMap(const std::map<size_t, size_t> &mapping)
{
m_d->setKeyFrameMap(mapping);
}
@@ -177,19 +176,19 @@ RubberBandStretcher::getInputIncrement() const
return m_d->getInputIncrement();
}
vector<int>
std::vector<int>
RubberBandStretcher::getOutputIncrements() const
{
return m_d->getOutputIncrements();
}
vector<float>
std::vector<float>
RubberBandStretcher::getPhaseResetCurve() const
{
return m_d->getPhaseResetCurve();
}
vector<int>
std::vector<int>
RubberBandStretcher::getExactTimePoints() const
{
return m_d->getExactTimePoints();

View File

@@ -674,6 +674,8 @@ RubberBandStretcher::Impl::configure()
Resampler::Parameters params;
params.quality = Resampler::FastestTolerable;
params.dynamism = Resampler::RatioOftenChanging;
params.ratioChange = Resampler::SmoothRatioChange;
params.maxBufferSize = 4096 * 16;
params.debugLevel = m_debugLevel;
@@ -818,6 +820,8 @@ RubberBandStretcher::Impl::reconfigure()
Resampler::Parameters params;
params.quality = Resampler::FastestTolerable;
params.dynamism = Resampler::RatioOftenChanging;
params.ratioChange = Resampler::SmoothRatioChange;
params.maxBufferSize = m_sWindowSize;
params.debugLevel = m_debugLevel;

633
src/dsp/BQResampler.cpp Normal file
View File

@@ -0,0 +1,633 @@
//* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Rubber Band Library
An audio time-stretching and pitch-shifting library.
Copyright 2007-2021 Particular Programs Ltd.
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 2 of the
License, or (at your option) any later version. See the file
COPYING included with this distribution for more information.
Alternatively, if you have a valid commercial licence for the
Rubber Band Library obtained by agreement with the copyright
holders, you may redistribute and/or modify it under the terms
described in that licence.
If you wish to distribute code using the Rubber Band Library
under terms other than those of the GNU General Public License,
you must obtain a valid commercial licence before doing so.
*/
#include "BQResampler.h"
#include <cmath>
#include <iostream>
#include "system/Allocators.h"
#include "system/VectorOps.h"
#define BQ_R__ R__
using std::vector;
using std::cerr;
using std::endl;
using std::min;
using std::max;
namespace RubberBand {
BQResampler::BQResampler(Parameters parameters, int channels) :
m_qparams(parameters.quality),
m_dynamism(parameters.dynamism),
m_ratio_change(parameters.ratioChange),
m_debug_level(parameters.debugLevel),
m_initial_rate(parameters.referenceSampleRate),
m_channels(channels),
m_fade_count(0),
m_initialised(false)
{
if (m_debug_level > 0) {
cerr << "BQResampler::BQResampler: "
<< (m_dynamism == RatioOftenChanging ? "often-changing" : "mostly-fixed")
<< ", "
<< (m_ratio_change == SmoothRatioChange ? "smooth" : "sudden")
<< " ratio changes, ref " << m_initial_rate << " Hz" << endl;
}
if (m_dynamism == RatioOftenChanging) {
m_proto_length = m_qparams.proto_p * m_qparams.p_multiple + 1;
if (m_debug_level > 0) {
cerr << "BQResampler: creating prototype filter of length "
<< m_proto_length << endl;
}
m_prototype = make_filter(m_proto_length, m_qparams.proto_p);
m_prototype.push_back(0.0); // interpolate without fear
}
int phase_reserve = 2 * int(round(m_initial_rate));
int buffer_reserve = 1000 * m_channels;
m_state_a.phase_info.reserve(phase_reserve);
m_state_a.buffer.reserve(buffer_reserve);
if (m_dynamism == RatioOftenChanging) {
m_state_b.phase_info.reserve(phase_reserve);
m_state_b.buffer.reserve(buffer_reserve);
}
m_s = &m_state_a;
m_fade = &m_state_b;
}
BQResampler::BQResampler(const BQResampler &other) :
m_qparams(other.m_qparams),
m_dynamism(other.m_dynamism),
m_ratio_change(other.m_ratio_change),
m_debug_level(other.m_debug_level),
m_initial_rate(other.m_initial_rate),
m_channels(other.m_channels),
m_state_a(other.m_state_a),
m_state_b(other.m_state_b),
m_fade_count(other.m_fade_count),
m_prototype(other.m_prototype),
m_proto_length(other.m_proto_length),
m_initialised(other.m_initialised)
{
if (other.m_s == &(other.m_state_a)) {
m_s = &m_state_a;
m_fade = &m_state_b;
} else {
m_s = &m_state_b;
m_fade = &m_state_a;
}
}
void
BQResampler::reset()
{
m_initialised = false;
m_fade_count = 0;
}
BQResampler::QualityParams::QualityParams(Quality q)
{
switch (q) {
case Fastest:
p_multiple = 12;
proto_p = 160;
k_snr = 70.0;
k_transition = 0.2;
cut = 0.9;
break;
case FastestTolerable:
p_multiple = 62;
proto_p = 160;
k_snr = 90.0;
k_transition = 0.05;
cut = 0.975;
break;
case Best:
p_multiple = 122;
proto_p = 800;
k_snr = 100.0;
k_transition = 0.01;
cut = 0.995;
break;
}
}
int
BQResampler::resampleInterleaved(float *const out,
int outspace,
const float *const in,
int incount,
double ratio,
bool final) {
int fade_length = round(m_initial_rate / 1000.0);
if (fade_length < 6) {
fade_length = 6;
}
int max_fade = min(outspace, int(floor(incount * ratio))) / 2;
if (fade_length > max_fade) {
fade_length = max_fade;
}
if (!m_initialised) {
state_for_ratio(*m_s, ratio, *m_fade);
m_initialised = true;
} else if (ratio != m_s->parameters.ratio) {
state *tmp = m_fade;
m_fade = m_s;
m_s = tmp;
state_for_ratio(*m_s, ratio, *m_fade);
if (m_ratio_change == SmoothRatioChange) {
if (m_debug_level > 0) {
cerr << "BQResampler: ratio changed, beginning fade of length "
<< fade_length << endl;
}
m_fade_count = fade_length;
}
}
int i = 0, o = 0;
int bufsize = m_s->buffer.size();
int incount_samples = incount * m_channels;
int outspace_samples = outspace * m_channels;
while (o < outspace_samples) {
while (i < incount_samples && m_s->fill < bufsize) {
m_s->buffer[m_s->fill++] = in[i++];
}
if (m_s->fill == bufsize) {
out[o++] = reconstruct_one(m_s);
} else if (final && m_s->fill > m_s->centre) {
out[o++] = reconstruct_one(m_s);
} else if (final && m_s->fill == m_s->centre &&
m_s->current_phase != m_s->initial_phase) {
out[o++] = reconstruct_one(m_s);
} else {
break;
}
}
int fbufsize = m_fade->buffer.size();
int fi = 0, fo = 0;
while (fo < o && m_fade_count > 0) {
while (fi < incount_samples && m_fade->fill < fbufsize) {
m_fade->buffer[m_fade->fill++] = in[fi++];
}
if (m_fade->fill == fbufsize) {
double r = reconstruct_one(m_fade);
double fadeWith = out[fo];
double extent = double(m_fade_count - 1) / double(fade_length);
double mixture = 0.5 * (1.0 - cos(M_PI * extent));
double mixed = r * mixture + fadeWith * (1.0 - mixture);
out[fo] = mixed;
++fo;
if (m_fade->current_channel == 0) {
--m_fade_count;
}
} else {
break;
}
}
return o / m_channels;
}
int
BQResampler::gcd(int a, int b) const
{
int c = a % b;
if (c == 0) return b;
else return gcd(b, c);
}
double
BQResampler::bessel0(double x) const
{
static double facsquared[] = {
0.0, 1.0, 4.0, 36.0,
576.0, 14400.0, 518400.0, 25401600.0,
1625702400.0, 131681894400.0, 1.316818944E13, 1.59335092224E15,
2.29442532803E17, 3.87757880436E19, 7.60005445655E21,
1.71001225272E24, 4.37763136697E26, 1.26513546506E29,
4.09903890678E31, 1.47975304535E34
};
static int nterms = sizeof(facsquared) / sizeof(facsquared[0]);
double b = 1.0;
for (int n = 1; n < nterms; ++n) {
double ff = facsquared[n];
double term = pow(x / 2.0, n * 2.0) / ff;
b += term;
}
return b;
}
vector<double>
BQResampler::kaiser(double beta, int len) const
{
double denominator = bessel0(beta);
int half = (len % 2 == 0 ? len/2 : (len+1)/2);
vector<double> v(len, 0.0);
for (int n = 0; n < half; ++n) {
double k = (2.0 * n) / (len-1) - 1.0;
v[n] = bessel0 (beta * sqrt(1.0 - k*k)) / denominator;
}
for (int n = half; n < len; ++n) {
v[n] = v[len-1 - n];
}
return v;
}
void
BQResampler::kaiser_params(double attenuation,
double transition,
double &beta,
int &len) const
{
if (attenuation > 21.0) {
len = 1 + ceil((attenuation - 7.95) / (2.285 * transition));
} else {
len = 1 + ceil(5.79 / transition);
}
beta = 0.0;
if (attenuation > 50.0) {
beta = 0.1102 * (attenuation - 8.7);
} else if (attenuation > 21.0) {
beta = 0.5842 * (pow (attenuation - 21.0, 0.4)) +
0.07886 * (attenuation - 21.0);
}
}
vector<double>
BQResampler::kaiser_for(double attenuation,
double transition,
int minlen,
int maxlen) const
{
double beta;
int m;
kaiser_params(attenuation, transition, beta, m);
int mb = m;
if (maxlen > 0 && mb > maxlen - 1) {
mb = maxlen - 1;
} else if (minlen > 0 && mb < minlen) {
mb = minlen;
}
if (mb % 2 == 0) ++mb;
if (m_debug_level > 0) {
cerr << "BQResampler: window attenuation " << attenuation
<< ", transition " << transition
<< " -> length " << m << " adjusted to " << mb
<< ", beta " << beta << endl;
}
return kaiser(beta, mb);
}
void
BQResampler::sinc_multiply(double peak_to_zero, vector<double> &buf) const
{
int len = int(buf.size());
if (len < 2) return;
int left = len / 2;
int right = (len + 1) / 2;
double m = M_PI / peak_to_zero;
for (int i = 1; i <= right; ++i) {
double x = i * m;
double sinc = sin(x) / x;
if (i <= left) {
buf[left - i] *= sinc;
}
if (i < right) {
buf[i + left] *= sinc;
}
}
}
BQResampler::params
BQResampler::fill_params(double ratio, int num, int denom) const
{
params p;
int g = gcd (num, denom);
p.ratio = ratio;
p.numerator = num / g;
p.denominator = denom / g;
p.effective = double(p.numerator) / double(p.denominator);
p.peak_to_zero = max(p.denominator, p.numerator);
p.peak_to_zero /= m_qparams.cut;
p.scale = double(p.numerator) / double(p.peak_to_zero);
if (m_debug_level > 0) {
cerr << "BQResampler: ratio " << p.ratio
<< " -> fraction " << p.numerator << "/" << p.denominator
<< " with error " << p.effective - p.ratio
<< endl;
cerr << "BQResampler: peak-to-zero " << p.peak_to_zero
<< ", scale " << p.scale
<< endl;
}
return p;
}
BQResampler::params
BQResampler::pick_params(double ratio) const
{
// Farey algorithm, see
// https://www.johndcook.com/blog/2010/10/20/best-rational-approximation/
int max_denom = 192000;
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) {
return fill_params(ratio, a + c, b + d);
} else if (d > b) {
return fill_params(ratio, c, d);
} else {
return fill_params(ratio, a, b);
}
}
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))) {
return fill_params(ratio, pc, pd);
} else {
return fill_params(ratio, pa, pb);
}
}
void
BQResampler::phase_data_for(vector<BQResampler::phase_rec> &target_phase_data,
floatbuf &target_phase_sorted_filter,
int filter_length,
const vector<double> *filter,
int initial_phase,
int input_spacing,
int output_spacing) const
{
target_phase_data.clear();
target_phase_data.reserve(input_spacing);
for (int p = 0; p < input_spacing; ++p) {
int next_phase = p - output_spacing;
while (next_phase < 0) next_phase += input_spacing;
next_phase %= input_spacing;
double dspace = double(input_spacing);
int zip_length = ceil(double(filter_length - p) / dspace);
int drop = ceil(double(max(0, output_spacing - p)) / dspace);
phase_rec phase;
phase.next_phase = next_phase;
phase.drop = drop;
phase.length = zip_length;
phase.start_index = 0; // we fill this in below if needed
target_phase_data.push_back(phase);
}
if (m_dynamism == RatioMostlyFixed) {
if (!filter) throw std::logic_error("filter required at phase_data_for in RatioMostlyFixed mode");
target_phase_sorted_filter.clear();
target_phase_sorted_filter.reserve(filter_length);
for (int p = initial_phase; ; ) {
phase_rec &phase = target_phase_data[p];
phase.start_index = target_phase_sorted_filter.size();
for (int i = 0; i < phase.length; ++i) {
target_phase_sorted_filter.push_back
((*filter)[i * input_spacing + p]);
}
p = phase.next_phase;
if (p == initial_phase) {
break;
}
}
}
}
vector<double>
BQResampler::make_filter(int filter_length, double peak_to_zero) const
{
vector<double> filter;
filter.reserve(filter_length);
vector<double> kaiser = kaiser_for(m_qparams.k_snr, m_qparams.k_transition,
1, filter_length);
int k_length = kaiser.size();
if (k_length == filter_length) {
sinc_multiply(peak_to_zero, kaiser);
return kaiser;
} else {
kaiser.push_back(0.0);
double m = double(k_length - 1) / double(filter_length - 1);
for (int i = 0; i < filter_length; ++i) {
double ix = i * m;
int iix = floor(ix);
double remainder = ix - iix;
double value = 0.0;
value += kaiser[iix] * (1.0 - remainder);
value += kaiser[iix+1] * remainder;
filter.push_back(value);
}
sinc_multiply(peak_to_zero, filter);
return filter;
}
}
void
BQResampler::state_for_ratio(BQResampler::state &target_state,
double ratio,
const BQResampler::state &BQ_R__ prev_state) const
{
params parameters = pick_params(ratio);
target_state.parameters = parameters;
target_state.filter_length =
int(parameters.peak_to_zero * m_qparams.p_multiple + 1);
if (target_state.filter_length % 2 == 0) {
++target_state.filter_length;
}
int half_length = target_state.filter_length / 2; // nb length is odd
int input_spacing = parameters.numerator;
int initial_phase = half_length % input_spacing;
target_state.initial_phase = initial_phase;
target_state.current_phase = initial_phase;
if (m_dynamism == RatioMostlyFixed) {
if (m_debug_level > 0) {
cerr << "BQResampler: creating filter of length "
<< target_state.filter_length << endl;
}
vector<double> filter =
make_filter(target_state.filter_length, parameters.peak_to_zero);
phase_data_for(target_state.phase_info,
target_state.phase_sorted_filter,
target_state.filter_length, &filter,
target_state.initial_phase,
input_spacing,
parameters.denominator);
} else {
phase_data_for(target_state.phase_info,
target_state.phase_sorted_filter,
target_state.filter_length, 0,
target_state.initial_phase,
input_spacing,
parameters.denominator);
}
int buffer_left = half_length / input_spacing;
int buffer_right = buffer_left + 1;
int buffer_length = buffer_left + buffer_right;
buffer_length = max(buffer_length,
int(prev_state.buffer.size() / m_channels));
target_state.centre = buffer_length / 2;
target_state.left = target_state.centre - buffer_left;
target_state.fill = target_state.centre;
buffer_length *= m_channels;
target_state.centre *= m_channels;
target_state.left *= m_channels;
target_state.fill *= m_channels;
int n_phases = int(target_state.phase_info.size());
if (m_debug_level > 0) {
cerr << "BQResampler: " << m_channels << " channel(s) interleaved"
<< ", buffer left " << buffer_left
<< ", right " << buffer_right
<< ", total " << buffer_length << endl;
cerr << "BQResampler: input spacing " << input_spacing
<< ", output spacing " << parameters.denominator
<< ", initial phase " << initial_phase
<< " of " << n_phases << endl;
}
if (prev_state.buffer.size() > 0) {
if (int(prev_state.buffer.size()) == buffer_length) {
target_state.buffer = prev_state.buffer;
target_state.fill = prev_state.fill;
} else {
target_state.buffer = floatbuf(buffer_length, 0.0);
for (int i = 0; i < prev_state.fill; ++i) {
int offset = i - prev_state.centre;
int new_ix = offset + target_state.centre;
if (new_ix >= 0 && new_ix < buffer_length) {
target_state.buffer[new_ix] = prev_state.buffer[i];
target_state.fill = new_ix + 1;
}
}
}
int phases_then = int(prev_state.phase_info.size());
double distance_through =
double(prev_state.current_phase) / double(phases_then);
target_state.current_phase = round(n_phases * distance_through);
if (target_state.current_phase >= n_phases) {
target_state.current_phase = n_phases - 1;
}
} else {
target_state.buffer = floatbuf(buffer_length, 0.0);
}
}
double
BQResampler::reconstruct_one(state *s) const
{
const phase_rec &pr = s->phase_info[s->current_phase];
int phase_length = pr.length;
double result = 0.0;
if (m_dynamism == RatioMostlyFixed) {
int phase_start = pr.start_index;
if (m_channels == 1) {
result = v_multiply_and_sum
(s->phase_sorted_filter.data() + phase_start,
s->buffer.data() + s->left,
phase_length);
} else {
for (int i = 0; i < phase_length; ++i) {
result +=
s->phase_sorted_filter[phase_start + i] *
s->buffer[s->left + i * m_channels + s->current_channel];
}
}
} else {
double m = double(m_proto_length - 1) / double(s->filter_length - 1);
for (int i = 0; i < phase_length; ++i) {
double sample =
s->buffer[s->left + i * m_channels + s->current_channel];
int filter_index = i * s->parameters.numerator + s->current_phase;
double proto_index = m * filter_index;
int iix = floor(proto_index);
double remainder = proto_index - iix;
double filter_value = m_prototype[iix] * (1.0 - remainder);
filter_value += m_prototype[iix+1] * remainder;
result += filter_value * sample;
}
}
s->current_channel = (s->current_channel + 1) % m_channels;
if (s->current_channel == 0) {
if (pr.drop > 0) {
int drop = pr.drop * m_channels;
v_move(s->buffer.data(), s->buffer.data() + drop,
int(s->buffer.size()) - drop);
for (int i = 1; i <= drop; ++i) {
s->buffer[s->buffer.size() - i] = 0.0;
}
s->fill -= drop;
}
s->current_phase = pr.next_phase;
}
return result * s->parameters.scale;
}
}

165
src/dsp/BQResampler.h Normal file
View File

@@ -0,0 +1,165 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Rubber Band Library
An audio time-stretching and pitch-shifting library.
Copyright 2007-2021 Particular Programs Ltd.
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 2 of the
License, or (at your option) any later version. See the file
COPYING included with this distribution for more information.
Alternatively, if you have a valid commercial licence for the
Rubber Band Library obtained by agreement with the copyright
holders, you may redistribute and/or modify it under the terms
described in that licence.
If you wish to distribute code using the Rubber Band Library
under terms other than those of the GNU General Public License,
you must obtain a valid commercial licence before doing so.
*/
#ifndef BQ_BQRESAMPLER_H
#define BQ_BQRESAMPLER_H
#include <vector>
#include "system/Allocators.h"
#include "system/VectorOps.h"
namespace RubberBand {
class BQResampler
{
public:
enum Quality { Best, FastestTolerable, Fastest };
enum Dynamism { RatioOftenChanging, RatioMostlyFixed };
enum RatioChange { SmoothRatioChange, SuddenRatioChange };
struct Parameters {
Quality quality;
Dynamism dynamism;
RatioChange ratioChange;
double referenceSampleRate;
int debugLevel;
Parameters() :
quality(FastestTolerable),
dynamism(RatioMostlyFixed),
ratioChange(SmoothRatioChange),
referenceSampleRate(44100),
debugLevel(0) { }
};
BQResampler(Parameters parameters, int channels);
BQResampler(const BQResampler &);
int resampleInterleaved(float *const out, int outspace,
const float *const in, int incount,
double ratio, bool final);
void reset();
private:
struct QualityParams {
int p_multiple;
int proto_p;
double k_snr;
double k_transition;
double cut;
QualityParams(Quality);
};
const QualityParams m_qparams;
const Dynamism m_dynamism;
const RatioChange m_ratio_change;
const int m_debug_level;
const double m_initial_rate;
const int m_channels;
struct params {
double ratio;
int numerator;
int denominator;
double effective;
double peak_to_zero;
double scale;
params() : ratio(1.0), numerator(1), denominator(1),
effective(1.0), peak_to_zero(0), scale(1.0) { }
};
struct phase_rec {
int next_phase;
int length;
int start_index;
int drop;
phase_rec() : next_phase(0), length(0), start_index(0), drop(0) { }
};
typedef std::vector<float, RubberBand::StlAllocator<float> > floatbuf;
struct state {
params parameters;
int initial_phase;
int current_phase;
int current_channel;
int filter_length;
std::vector<phase_rec> phase_info;
floatbuf phase_sorted_filter;
floatbuf buffer;
int left;
int centre;
int fill;
state() : initial_phase(0), current_phase(0), current_channel(0),
filter_length(0), left(0), centre(0), fill(0) { }
};
state m_state_a;
state m_state_b;
state *m_s; // points at either m_state_a or m_state_b
state *m_fade; // whichever one m_s does not point to
int m_fade_count;
std::vector<double> m_prototype;
int m_proto_length;
bool m_initialised;
int gcd(int a, int b) const;
double bessel0(double x) const;
std::vector<double> kaiser(double beta, int len) const;
void kaiser_params(double attenuation, double transition,
double &beta, int &len) const;
std::vector<double> kaiser_for(double attenuation, double transition,
int minlen, int maxlen) const;
void sinc_multiply(double peak_to_zero, std::vector<double> &buf) const;
params fill_params(double ratio, int num, int denom) const;
params pick_params(double ratio) const;
std::vector<double> make_filter(int filter_length,
double peak_to_zero) const;
void phase_data_for(std::vector<phase_rec> &target_phase_data,
floatbuf &target_phase_sorted_filter,
int filter_length,
const std::vector<double> *filter,
int initial_phase,
int input_spacing,
int output_spacing) const;
void state_for_ratio(state &target_state,
double ratio,
const state &R__ prev_state) const;
double reconstruct_one(state *s) const;
BQResampler &operator=(const BQResampler &); // not provided
};
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -64,6 +64,8 @@ public:
FFT(int size, int debugLevel = 0); // may throw InvalidSize
~FFT();
int getSize() const;
void forward(const double *R__ realIn, double *R__ realOut, double *R__ imagOut);
void forwardInterleaved(const double *R__ realIn, double *R__ complexOut);
void forwardPolar(const double *R__ realIn, double *R__ magOut, double *R__ phaseOut);
@@ -121,6 +123,10 @@ protected:
FFTImpl *d;
static std::string m_implementation;
static void pickDefaultImplementation();
private:
FFT(const FFT &); // not provided
FFT &operator=(const FFT &); // not provided
};
}

View File

@@ -1,4 +1,4 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Rubber Band Library
@@ -22,7 +22,9 @@
*/
#include "Resampler.h"
#include "base/Profiler.h"
#include "system/Allocators.h"
#include "system/VectorOps.h"
#include <cstdlib>
#include <cmath>
@@ -30,9 +32,6 @@
#include <iostream>
#include <algorithm>
#include "system/Allocators.h"
#include "system/VectorOps.h"
#ifdef HAVE_IPP
#include <ippversion.h>
#if (IPP_VERSION_MAJOR < 7)
@@ -42,6 +41,10 @@
#endif
#endif
#ifdef HAVE_SAMPLERATE
#define HAVE_LIBSAMPLERATE 1
#endif
#ifdef HAVE_LIBSAMPLERATE
#include <samplerate.h>
#endif
@@ -51,18 +54,26 @@
#endif
#ifdef USE_SPEEX
#include "speex/speex_resampler.h"
#include "../speex/speex_resampler.h"
#endif
#ifdef USE_BQRESAMPLER
#include "BQResampler.h"
#endif
#ifndef HAVE_IPP
#ifndef HAVE_LIBSAMPLERATE
#ifndef HAVE_LIBRESAMPLE
#ifndef USE_SPEEX
#ifndef USE_BQRESAMPLER
#error No resampler implementation selected!
#endif
#endif
#endif
#endif
#endif
#define BQ_R__ R__
using namespace std;
@@ -73,16 +84,16 @@ class Resampler::Impl
public:
virtual ~Impl() { }
virtual int resample(float *const R__ *const R__ out,
virtual int resample(float *const BQ_R__ *const BQ_R__ out,
int outcount,
const float *const R__ *const R__ in,
const float *const BQ_R__ *const BQ_R__ in,
int incount,
double ratio,
bool final) = 0;
virtual int resampleInterleaved(float *const R__ out,
virtual int resampleInterleaved(float *const BQ_R__ out,
int outcount,
const float *const R__ in,
const float *const BQ_R__ in,
int incount,
double ratio,
bool final) = 0;
@@ -99,20 +110,21 @@ namespace Resamplers {
class D_IPP : public Resampler::Impl
{
public:
D_IPP(Resampler::Quality quality, int channels, double initialSampleRate,
D_IPP(Resampler::Quality quality, Resampler::RatioChange,
int channels, double initialSampleRate,
int maxBufferSize, int debugLevel);
~D_IPP();
int resample(float *const R__ *const R__ out,
int resample(float *const BQ_R__ *const BQ_R__ out,
int outcount,
const float *const R__ *const R__ in,
const float *const BQ_R__ *const BQ_R__ in,
int incount,
double ratio,
bool final);
int resampleInterleaved(float *const R__ out,
int resampleInterleaved(float *const BQ_R__ out,
int outcount,
const float *const R__ in,
const float *const BQ_R__ in,
int incount,
double ratio,
bool final = false);
@@ -144,6 +156,7 @@ protected:
};
D_IPP::D_IPP(Resampler::Quality /* quality */,
Resampler::RatioChange /* ratioChange */,
int channels, double initialSampleRate,
int maxBufferSize, int debugLevel) :
m_state(0),
@@ -152,7 +165,7 @@ D_IPP::D_IPP(Resampler::Quality /* quality */,
m_debugLevel(debugLevel)
{
if (m_debugLevel > 0) {
cerr << "Resampler::Resampler: using IPP implementation" << endl;
cerr << "Resampler::Resampler: using implementation: IPP" << endl;
}
m_window = 32;
@@ -190,7 +203,7 @@ D_IPP::D_IPP(Resampler::Quality /* quality */,
setBufSize(maxBufferSize + m_history);
if (m_debugLevel > 1) {
cerr << "D_IPP: bufsize = " << m_bufsize << ", window = " << m_window << ", nStep = " << nStep << ", history = " << m_history << endl;
cerr << "bufsize = " << m_bufsize << ", window = " << m_window << ", nStep = " << nStep << ", history = " << m_history << endl;
}
int specSize = 0;
@@ -214,18 +227,13 @@ D_IPP::D_IPP(Resampler::Quality /* quality */,
9.0f,
m_state[c],
hint);
if (m_debugLevel > 1) {
cerr << "D_IPP: Resampler state size = " << specSize << ", allocated at "
<< m_state[c] << endl;
}
m_lastread[c] = m_history;
m_time[c] = m_history;
}
if (m_debugLevel > 1) {
cerr << "D_IPP: Resampler init done" << endl;
cerr << "Resampler init done" << endl;
}
}
@@ -248,9 +256,9 @@ D_IPP::setBufSize(int sz)
{
if (m_debugLevel > 1) {
if (m_bufsize > 0) {
cerr << "D_IPP: resize bufsize " << m_bufsize << " -> ";
cerr << "resize bufsize " << m_bufsize << " -> ";
} else {
cerr << "D_IPP: initialise bufsize to ";
cerr << "initialise bufsize to ";
}
}
@@ -263,13 +271,13 @@ D_IPP::setBufSize(int sz)
int n1 = m_bufsize + m_history + 2;
if (m_debugLevel > 1) {
cerr << "D_IPP: inbuf allocating " << m_bufsize << " + " << m_history << " + 2 = " << n1 << endl;
cerr << "inbuf allocating " << m_bufsize << " + " << m_history << " + 2 = " << n1 << endl;
}
int n2 = (int)lrintf(ceil((m_bufsize - m_history) * m_factor + 2));
if (m_debugLevel > 1) {
cerr << "D_IPP: outbuf allocating (" << m_bufsize << " - " << m_history << ") * " << m_factor << " + 2 = " << n2 << endl;
cerr << "outbuf allocating (" << m_bufsize << " - " << m_history << ") * " << m_factor << " + 2 = " << n2 << endl;
}
m_inbuf = reallocate_and_zero_extend_channels
@@ -277,30 +285,15 @@ D_IPP::setBufSize(int sz)
m_outbuf = reallocate_and_zero_extend_channels
(m_outbuf, m_channels, m_outbufsz, m_channels, n2);
m_inbufsz = n1;
m_outbufsz = n2;
if (m_debugLevel > 2) {
cerr << "D_IPP: inbuf ptr = " << m_inbuf << ", channel inbufs ";
for (int c = 0; c < m_channels; ++c) {
cerr << m_inbuf[c] << " ";
}
cerr << "at " << m_inbufsz * sizeof(float) << " bytes each" << endl;
cerr << "D_IPP: outbuf ptr = " << m_outbuf << ", channel outbufs ";
for (int c = 0; c < m_channels; ++c) {
cerr << m_outbuf[c] << " ";
}
cerr << "at " << m_outbufsz * sizeof(float) << " bytes each" << endl;
}
}
int
D_IPP::resample(float *const R__ *const R__ out,
D_IPP::resample(float *const BQ_R__ *const BQ_R__ out,
int outspace,
const float *const R__ *const R__ in,
const float *const BQ_R__ *const BQ_R__ in,
int incount,
double ratio,
bool final)
@@ -311,7 +304,7 @@ D_IPP::resample(float *const R__ *const R__ out,
}
if (m_debugLevel > 2) {
cerr << "D_IPP: incount = " << incount << ", ratio = " << ratio << ", est space = " << lrintf(ceil(incount * ratio)) << ", outspace = " << outspace << ", final = " << final << endl;
cerr << "incount = " << incount << ", ratio = " << ratio << ", est space = " << lrintf(ceil(incount * ratio)) << ", outspace = " << outspace << ", final = " << final << endl;
}
for (int c = 0; c < m_channels; ++c) {
@@ -328,7 +321,7 @@ D_IPP::resample(float *const R__ *const R__ out,
}
if (m_debugLevel > 2) {
cerr << "D_IPP: lastread advanced to " << m_lastread[0] << endl;
cerr << "lastread advanced to " << m_lastread[0] << endl;
}
int got = doResample(outspace, ratio, final);
@@ -341,9 +334,9 @@ D_IPP::resample(float *const R__ *const R__ out,
}
int
D_IPP::resampleInterleaved(float *const R__ out,
D_IPP::resampleInterleaved(float *const BQ_R__ out,
int outspace,
const float *const R__ in,
const float *const BQ_R__ in,
int incount,
double ratio,
bool final)
@@ -354,7 +347,7 @@ D_IPP::resampleInterleaved(float *const R__ out,
}
if (m_debugLevel > 2) {
cerr << "D_IPP: incount = " << incount << ", ratio = " << ratio << ", est space = " << lrintf(ceil(incount * ratio)) << ", outspace = " << outspace << ", final = " << final << endl;
cerr << "incount = " << incount << ", ratio = " << ratio << ", est space = " << lrintf(ceil(incount * ratio)) << ", outspace = " << outspace << ", final = " << final << endl;
}
for (int c = 0; c < m_channels; ++c) {
@@ -371,7 +364,7 @@ D_IPP::resampleInterleaved(float *const R__ out,
}
if (m_debugLevel > 2) {
cerr << "D_IPP: lastread advanced to " << m_lastread[0] << " after injection of "
cerr << "lastread advanced to " << m_lastread[0] << " after injection of "
<< incount << " samples" << endl;
}
@@ -392,20 +385,20 @@ D_IPP::doResample(int outspace, double ratio, bool final)
int n = m_lastread[c] - m_history - int(m_time[c]);
if (c == 0 && m_debugLevel > 2) {
cerr << "D_IPP: at start, lastread = " << m_lastread[c] << ", history = "
cerr << "at start, lastread = " << m_lastread[c] << ", history = "
<< m_history << ", time = " << m_time[c] << ", therefore n = "
<< n << endl;
}
if (n <= 0) {
if (c == 0 && m_debugLevel > 1) {
cerr << "D_IPP: not enough input samples to do anything" << endl;
cerr << "not enough input samples to do anything" << endl;
}
continue;
}
if (c == 0 && m_debugLevel > 2) {
cerr << "D_IPP: before resample call, time = " << m_time[c] << endl;
cerr << "before resample call, time = " << m_time[c] << endl;
}
// We're committed to not overrunning outspace, so we need to
@@ -414,7 +407,7 @@ D_IPP::doResample(int outspace, double ratio, bool final)
int limit = int(floor(outspace / ratio));
if (n > limit) {
if (c == 0 && m_debugLevel > 1) {
cerr << "D_IPP: trimming input samples from " << n << " to " << limit
cerr << "trimming input samples from " << n << " to " << limit
<< " to avoid overrunning " << outspace << " at output"
<< endl;
}
@@ -431,26 +424,26 @@ D_IPP::doResample(int outspace, double ratio, bool final)
m_state[c]);
int t = int(floor(m_time[c]));
int moveFrom = t - m_history;
if (c == 0 && m_debugLevel > 2) {
cerr << "D_IPP: converted " << n << " samples to " << outcount
cerr << "converted " << n << " samples to " << outcount
<< " (nb outbufsz = " << m_outbufsz
<< "), time advanced to " << m_time[c] << endl;
cerr << "D_IPP: rounding time to " << t << ", lastread = "
cerr << "rounding time to " << t << ", lastread = "
<< m_lastread[c] << ", history = " << m_history << endl;
cerr << "D_IPP: will move " << m_lastread[c] - moveFrom
cerr << "will move " << m_lastread[c] - moveFrom
<< " unconverted samples back from index " << moveFrom
<< " to 0" << endl;
}
if (moveFrom >= m_lastread[c]) {
moveFrom = m_lastread[c];
if (c == 0 && m_debugLevel > 2) {
cerr << "D_IPP: number of samples to move is <= 0, "
cerr << "number of samples to move is <= 0, "
<< "not actually moving any" << endl;
}
} else {
@@ -464,7 +457,7 @@ D_IPP::doResample(int outspace, double ratio, bool final)
m_time[c] -= moveFrom;
if (c == 0 && m_debugLevel > 2) {
cerr << "D_IPP: lastread reduced to " << m_lastread[c]
cerr << "lastread reduced to " << m_lastread[c]
<< ", time reduced to " << m_time[c]
<< endl;
}
@@ -483,7 +476,7 @@ D_IPP::doResample(int outspace, double ratio, bool final)
int additionalcount = 0;
if (c == 0 && m_debugLevel > 2) {
cerr << "D_IPP: final call, padding input with " << m_history
cerr << "final call, padding input with " << m_history
<< " zeros (symmetrical with m_history)" << endl;
}
@@ -492,14 +485,14 @@ D_IPP::doResample(int outspace, double ratio, bool final)
}
if (c == 0 && m_debugLevel > 2) {
cerr << "D_IPP: before resample call, time = " << m_time[c] << endl;
cerr << "before resample call, time = " << m_time[c] << endl;
}
int nAdditional = m_lastread[c] - int(m_time[c]);
if (n + nAdditional > limit) {
if (c == 0 && m_debugLevel > 1) {
cerr << "D_IPP: trimming final input samples from " << nAdditional
cerr << "trimming final input samples from " << nAdditional
<< " to " << (limit - n)
<< " to avoid overrunning " << outspace << " at output"
<< endl;
@@ -517,9 +510,9 @@ D_IPP::doResample(int outspace, double ratio, bool final)
m_state[c]);
if (c == 0 && m_debugLevel > 2) {
cerr << "D_IPP: converted " << n << " samples to " << additionalcount
cerr << "converted " << n << " samples to " << additionalcount
<< ", time advanced to " << m_time[c] << endl;
cerr << "D_IPP: outcount = " << outcount << ", additionalcount = " << additionalcount << ", sum " << outcount + additionalcount << endl;
cerr << "outcount = " << outcount << ", additionalcount = " << additionalcount << ", sum " << outcount + additionalcount << endl;
}
if (c == 0) {
@@ -529,7 +522,7 @@ D_IPP::doResample(int outspace, double ratio, bool final)
}
if (m_debugLevel > 2) {
cerr << "D_IPP: returning " << outcount << " samples" << endl;
cerr << "returning " << outcount << " samples" << endl;
}
return outcount;
@@ -548,20 +541,21 @@ D_IPP::reset()
class D_SRC : public Resampler::Impl
{
public:
D_SRC(Resampler::Quality quality, int channels, double initialSampleRate,
D_SRC(Resampler::Quality quality, Resampler::RatioChange ratioChange,
int channels, double initialSampleRate,
int maxBufferSize, int m_debugLevel);
~D_SRC();
int resample(float *const R__ *const R__ out,
int resample(float *const BQ_R__ *const BQ_R__ out,
int outcount,
const float *const R__ *const R__ in,
const float *const BQ_R__ *const BQ_R__ in,
int incount,
double ratio,
bool final);
int resampleInterleaved(float *const R__ out,
int resampleInterleaved(float *const BQ_R__ out,
int outcount,
const float *const R__ in,
const float *const BQ_R__ in,
int incount,
double ratio,
bool final = false);
@@ -579,11 +573,12 @@ protected:
int m_ioutsize;
double m_prevRatio;
bool m_ratioUnset;
bool m_smoothRatios;
int m_debugLevel;
};
D_SRC::D_SRC(Resampler::Quality quality, int channels, double,
int maxBufferSize, int debugLevel) :
D_SRC::D_SRC(Resampler::Quality quality, Resampler::RatioChange ratioChange,
int channels, double, int maxBufferSize, int debugLevel) :
m_src(0),
m_iin(0),
m_iout(0),
@@ -592,25 +587,41 @@ D_SRC::D_SRC(Resampler::Quality quality, int channels, double,
m_ioutsize(0),
m_prevRatio(1.0),
m_ratioUnset(true),
m_smoothRatios(ratioChange == Resampler::SmoothRatioChange),
m_debugLevel(debugLevel)
{
if (m_debugLevel > 0) {
cerr << "Resampler::Resampler: using libsamplerate implementation"
<< endl;
cerr << "Resampler::Resampler: using implementation: libsamplerate"
<< endl;
}
if (channels < 1) {
cerr << "Resampler::Resampler: unable to create resampler: invalid channel count " << channels << " supplied" << endl;
#ifdef NO_EXCEPTIONS
throw Resampler::ImplementationError;
#endif
return;
}
int err = 0;
m_src = src_new(quality == Resampler::Best ? SRC_SINC_BEST_QUALITY :
quality == Resampler::Fastest ? SRC_LINEAR :
SRC_SINC_FASTEST,
quality == Resampler::Fastest ? SRC_SINC_FASTEST :
SRC_SINC_MEDIUM_QUALITY,
channels, &err);
if (err) {
cerr << "Resampler::Resampler: failed to create libsamplerate resampler: "
<< src_strerror(err) << endl;
<< src_strerror(err) << endl;
#ifndef NO_EXCEPTIONS
throw Resampler::ImplementationError;
#endif
return;
} else if (!m_src) {
cerr << "Resampler::Resampler: failed to create libsamplerate resampler, but no error reported?" << endl;
#ifndef NO_EXCEPTIONS
throw Resampler::ImplementationError;
#endif
return;
}
if (maxBufferSize > 0 && m_channels > 1) {
@@ -631,9 +642,9 @@ D_SRC::~D_SRC()
}
int
D_SRC::resample(float *const R__ *const R__ out,
D_SRC::resample(float *const BQ_R__ *const BQ_R__ out,
int outcount,
const float *const R__ *const R__ in,
const float *const BQ_R__ *const BQ_R__ in,
int incount,
double ratio,
bool final)
@@ -661,15 +672,15 @@ D_SRC::resample(float *const R__ *const R__ out,
}
int
D_SRC::resampleInterleaved(float *const R__ out,
D_SRC::resampleInterleaved(float *const BQ_R__ out,
int outcount,
const float *const R__ in,
const float *const BQ_R__ in,
int incount,
double ratio,
bool final)
{
SRC_DATA data;
// libsamplerate smooths the filter change over the duration of
// the processing block to avoid artifacts due to sudden changes,
// and it uses outcount to determine how long to smooth the change
@@ -682,7 +693,7 @@ D_SRC::resampleInterleaved(float *const R__ out,
outcount = int(ceil(incount * ratio) + 5);
}
if (m_ratioUnset) {
if (m_ratioUnset || !m_smoothRatios) {
// The first time we set a ratio, we want to do it directly
src_set_ratio(m_src, ratio);
@@ -724,10 +735,9 @@ D_SRC::resampleInterleaved(float *const R__ out,
data.input_frames = incount;
data.output_frames = outcount;
data.src_ratio = ratio;
data.end_of_input = (final ? 1 : 0);
int err = src_process(m_src, &data);
if (err) {
@@ -737,7 +747,7 @@ D_SRC::resampleInterleaved(float *const R__ out,
throw Resampler::ImplementationError;
#endif
}
return (int)data.output_frames_gen;
}
@@ -755,20 +765,21 @@ D_SRC::reset()
class D_Resample : public Resampler::Impl
{
public:
D_Resample(Resampler::Quality quality, int channels, double initialSampleRate,
D_Resample(Resampler::Quality quality, Resampler::RatioChange,
int channels, double initialSampleRate,
int maxBufferSize, int m_debugLevel);
~D_Resample();
int resample(float *const R__ *const R__ out,
int resample(float *const BQ_R__ *const BQ_R__ out,
int outcount,
const float *const R__ *const R__ in,
const float *const BQ_R__ *const BQ_R__ in,
int incount,
double ratio,
bool final);
int resampleInterleaved(float *const R__ out,
int resampleInterleaved(float *const BQ_R__ out,
int outcount,
const float *const R__ in,
const float *const BQ_R__ in,
int incount,
double ratio,
bool final);
@@ -799,7 +810,7 @@ D_Resample::D_Resample(Resampler::Quality quality,
m_debugLevel(debugLevel)
{
if (m_debugLevel > 0) {
cerr << "Resampler::Resampler: using libresample implementation"
cerr << "Resampler::Resampler: using implementation: libresample"
<< endl;
}
@@ -836,9 +847,9 @@ D_Resample::~D_Resample()
}
int
D_Resample::resample(float *const R__ *const R__ out,
D_Resample::resample(float *const BQ_R__ *const BQ_R__ out,
int outcount,
const float *const R__ *const R__ in,
const float *const BQ_R__ *const BQ_R__ in,
int incount,
double ratio,
bool final)
@@ -895,9 +906,9 @@ D_Resample::resample(float *const R__ *const R__ out,
}
int
D_Resample::resampleInterleaved(float *const R__ out,
D_Resample::resampleInterleaved(float *const BQ_R__ out,
int outcount,
const float *const R__ in,
const float *const BQ_R__ in,
int incount,
double ratio,
bool final)
@@ -937,25 +948,174 @@ D_Resample::reset()
#endif /* HAVE_LIBRESAMPLE */
#ifdef USE_BQRESAMPLER
class D_BQResampler : public Resampler::Impl
{
public:
D_BQResampler(Resampler::Parameters params, int channels);
~D_BQResampler();
int resample(float *const BQ_R__ *const BQ_R__ out,
int outcount,
const float *const BQ_R__ *const BQ_R__ in,
int incount,
double ratio,
bool final);
int resampleInterleaved(float *const BQ_R__ out,
int outcount,
const float *const BQ_R__ in,
int incount,
double ratio,
bool final = false);
int getChannelCount() const { return m_channels; }
void reset();
protected:
BQResampler *m_resampler;
float *m_iin;
float *m_iout;
int m_channels;
int m_iinsize;
int m_ioutsize;
int m_debugLevel;
};
D_BQResampler::D_BQResampler(Resampler::Parameters params, int channels) :
m_resampler(0),
m_iin(0),
m_iout(0),
m_channels(channels),
m_iinsize(0),
m_ioutsize(0),
m_debugLevel(params.debugLevel)
{
if (m_debugLevel > 0) {
cerr << "Resampler::Resampler: using implementation: BQResampler" << endl;
}
BQResampler::Parameters rparams;
switch (params.quality) {
case Resampler::Best:
rparams.quality = BQResampler::Best;
break;
case Resampler::FastestTolerable:
rparams.quality = BQResampler::FastestTolerable;
break;
case Resampler::Fastest:
rparams.quality = BQResampler::Fastest;
break;
}
switch (params.dynamism) {
case Resampler::RatioOftenChanging:
rparams.dynamism = BQResampler::RatioOftenChanging;
break;
case Resampler::RatioMostlyFixed:
rparams.dynamism = BQResampler::RatioMostlyFixed;
break;
}
switch (params.ratioChange) {
case Resampler::SmoothRatioChange:
rparams.ratioChange = BQResampler::SmoothRatioChange;
break;
case Resampler::SuddenRatioChange:
rparams.ratioChange = BQResampler::SuddenRatioChange;
break;
}
rparams.referenceSampleRate = params.initialSampleRate;
rparams.debugLevel = params.debugLevel;
m_resampler = new BQResampler(rparams, m_channels);
if (params.maxBufferSize > 0 && m_channels > 1) {
m_iinsize = params.maxBufferSize * m_channels;
m_ioutsize = params.maxBufferSize * m_channels * 2;
m_iin = allocate<float>(m_iinsize);
m_iout = allocate<float>(m_ioutsize);
}
}
D_BQResampler::~D_BQResampler()
{
delete m_resampler;
deallocate(m_iin);
deallocate(m_iout);
}
int
D_BQResampler::resample(float *const BQ_R__ *const BQ_R__ out,
int outcount,
const float *const BQ_R__ *const BQ_R__ in,
int incount,
double ratio,
bool final)
{
if (m_channels == 1) {
return resampleInterleaved(*out, outcount, *in, incount, ratio, final);
}
if (incount * m_channels > m_iinsize) {
m_iin = reallocate<float>(m_iin, m_iinsize, incount * m_channels);
m_iinsize = incount * m_channels;
}
if (outcount * m_channels > m_ioutsize) {
m_iout = reallocate<float>(m_iout, m_ioutsize, outcount * m_channels);
m_ioutsize = outcount * m_channels;
}
v_interleave(m_iin, in, m_channels, incount);
int n = resampleInterleaved(m_iout, outcount, m_iin, incount, ratio, final);
v_deinterleave(out, m_iout, m_channels, n);
return n;
}
int
D_BQResampler::resampleInterleaved(float *const BQ_R__ out,
int outcount,
const float *const BQ_R__ in,
int incount,
double ratio,
bool final)
{
return m_resampler->resampleInterleaved(out, outcount,
in, incount,
ratio, final);
}
void
D_BQResampler::reset()
{
m_resampler->reset();
}
#endif /* USE_BQRESAMPLER */
#ifdef USE_SPEEX
class D_Speex : public Resampler::Impl
{
public:
D_Speex(Resampler::Quality quality, int channels, double initialSampleRate,
D_Speex(Resampler::Quality quality, Resampler::RatioChange,
int channels, double initialSampleRate,
int maxBufferSize, int debugLevel);
~D_Speex();
int resample(float *const R__ *const R__ out,
int resample(float *const BQ_R__ *const BQ_R__ out,
int outcount,
const float *const R__ *const R__ in,
const float *const BQ_R__ *const BQ_R__ in,
int incount,
double ratio,
bool final);
int resampleInterleaved(float *const R__ out,
int resampleInterleaved(float *const BQ_R__ out,
int outcount,
const float *const R__ in,
const float *const BQ_R__ in,
int incount,
double ratio,
bool final = false);
@@ -982,7 +1142,7 @@ protected:
double ratio, bool final);
};
D_Speex::D_Speex(Resampler::Quality quality,
D_Speex::D_Speex(Resampler::Quality quality, Resampler::RatioChange,
int channels, double initialSampleRate,
int maxBufferSize, int debugLevel) :
m_resampler(0),
@@ -1000,7 +1160,7 @@ D_Speex::D_Speex(Resampler::Quality quality,
quality == Resampler::Fastest ? 0 : 4);
if (m_debugLevel > 0) {
cerr << "Resampler::Resampler: using Speex implementation with q = "
cerr << "Resampler::Resampler: using implementation: Speex with q = "
<< q << endl;
}
@@ -1093,9 +1253,9 @@ D_Speex::setRatio(double ratio)
}
int
D_Speex::resample(float *const R__ *const R__ out,
D_Speex::resample(float *const BQ_R__ *const BQ_R__ out,
int outcount,
const float *const R__ *const R__ in,
const float *const BQ_R__ *const BQ_R__ in,
int incount,
double ratio,
bool final)
@@ -1136,9 +1296,9 @@ D_Speex::resample(float *const R__ *const R__ out,
}
int
D_Speex::resampleInterleaved(float *const R__ out,
D_Speex::resampleInterleaved(float *const BQ_R__ out,
int outcount,
const float *const R__ in,
const float *const BQ_R__ in,
int incount,
double ratio,
bool final)
@@ -1236,6 +1396,9 @@ Resampler::Resampler(Resampler::Parameters params, int channels)
#ifdef HAVE_LIBRESAMPLE
m_method = 3;
#endif
#ifdef USE_BQRESAMPLER
m_method = 4;
#endif
#ifdef HAVE_LIBSAMPLERATE
m_method = 1;
#endif
@@ -1251,6 +1414,9 @@ Resampler::Resampler(Resampler::Parameters params, int channels)
#ifdef USE_SPEEX
m_method = 2;
#endif
#ifdef USE_BQRESAMPLER
m_method = 4;
#endif
#ifdef HAVE_LIBSAMPLERATE
m_method = 1;
#endif
@@ -1266,6 +1432,9 @@ Resampler::Resampler(Resampler::Parameters params, int channels)
#ifdef USE_SPEEX
m_method = 2;
#endif
#ifdef USE_BQRESAMPLER
m_method = 4;
#endif
#ifdef HAVE_LIBSAMPLERATE
m_method = 1;
#endif
@@ -1281,7 +1450,7 @@ Resampler::Resampler(Resampler::Parameters params, int channels)
case 0:
#ifdef HAVE_IPP
d = new Resamplers::D_IPP
(params.quality,
(params.quality, params.ratioChange,
channels,
params.initialSampleRate, params.maxBufferSize, params.debugLevel);
#else
@@ -1293,7 +1462,7 @@ Resampler::Resampler(Resampler::Parameters params, int channels)
case 1:
#ifdef HAVE_LIBSAMPLERATE
d = new Resamplers::D_SRC
(params.quality,
(params.quality, params.ratioChange,
channels,
params.initialSampleRate, params.maxBufferSize, params.debugLevel);
#else
@@ -1305,7 +1474,7 @@ Resampler::Resampler(Resampler::Parameters params, int channels)
case 2:
#ifdef USE_SPEEX
d = new Resamplers::D_Speex
(params.quality,
(params.quality, params.ratioChange,
channels,
params.initialSampleRate, params.maxBufferSize, params.debugLevel);
#else
@@ -1317,12 +1486,21 @@ Resampler::Resampler(Resampler::Parameters params, int channels)
case 3:
#ifdef HAVE_LIBRESAMPLE
d = new Resamplers::D_Resample
(params.quality,
(params.quality, params.ratioChange,
channels,
params.initialSampleRate, params.maxBufferSize, params.debugLevel);
#else
cerr << "Resampler::Resampler: No implementation available!" << endl;
abort();
#endif
break;
case 4:
#ifdef USE_BQRESAMPLER
d = new Resamplers::D_BQResampler(params, channels);
#else
cerr << "Resampler::Resampler: No implementation available!" << endl;
abort();
#endif
break;
}
@@ -1340,26 +1518,24 @@ Resampler::~Resampler()
}
int
Resampler::resample(float *const R__ *const R__ out,
Resampler::resample(float *const BQ_R__ *const BQ_R__ out,
int outcount,
const float *const R__ *const R__ in,
const float *const BQ_R__ *const BQ_R__ in,
int incount,
double ratio,
bool final)
{
Profiler profiler("Resampler::resample");
return d->resample(out, outcount, in, incount, ratio, final);
}
int
Resampler::resampleInterleaved(float *const R__ out,
Resampler::resampleInterleaved(float *const BQ_R__ out,
int outcount,
const float *const R__ in,
const float *const BQ_R__ in,
int incount,
double ratio,
bool final)
{
Profiler profiler("Resampler::resampleInterleaved");
return d->resampleInterleaved(out, outcount, in, incount, ratio, final);
}

View File

@@ -1,4 +1,4 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
//* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Rubber Band Library
@@ -32,6 +32,9 @@ class Resampler
{
public:
enum Quality { Best, FastestTolerable, Fastest };
enum Dynamism { RatioOftenChanging, RatioMostlyFixed };
enum RatioChange { SmoothRatioChange, SuddenRatioChange };
enum Exception { ImplementationError };
struct Parameters {
@@ -41,6 +44,22 @@ public:
*/
Quality quality;
/**
* Performance hint indicating whether the ratio is expected
* to change regularly or not. If not, more work may happen on
* ratio changes to reduce work when ratio is unchanged.
*/
Dynamism dynamism;
/**
* Hint indicating whether to smooth transitions, via filter
* interpolation or some such method, at ratio change
* boundaries, or whether to make a precise switch to the new
* ratio without regard to audible artifacts. The actual
* effect of this depends on the implementation in use.
*/
RatioChange ratioChange;
/**
* Rate of expected input prior to resampling: may be used to
* determine the filter bandwidth for the quality setting. If
@@ -67,6 +86,8 @@ public:
Parameters() :
quality(FastestTolerable),
dynamism(RatioMostlyFixed),
ratioChange(SmoothRatioChange),
initialSampleRate(44100),
maxBufferSize(0),
debugLevel(0) { }

View File

@@ -29,6 +29,8 @@
#include <new> // for std::bad_alloc
#include <stdlib.h>
#include <stdexcept>
#ifndef HAVE_POSIX_MEMALIGN
#ifndef _WIN32
#ifndef __APPLE__
@@ -309,6 +311,96 @@ private:
T *m_t;
};
/** Allocator for use with STL classes, e.g. vector, to ensure
* alignment. Based on example code by Stephan T. Lavavej.
*
* e.g. std::vector<float, StlAllocator<float> > v;
*/
template <typename T>
class StlAllocator
{
public:
typedef T *pointer;
typedef const T *const_pointer;
typedef T &reference;
typedef const T &const_reference;
typedef T value_type;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
StlAllocator() { }
StlAllocator(const StlAllocator&) { }
template <typename U> StlAllocator(const StlAllocator<U>&) { }
~StlAllocator() { }
T *
allocate(const size_t n) const {
if (n == 0) return 0;
if (n > max_size()) {
#ifndef NO_EXCEPTIONS
throw std::length_error("Size overflow in StlAllocator::allocate()");
#else
abort();
#endif
}
return ::RubberBand::allocate<T>(n);
}
void
deallocate(T *const p, const size_t) const {
::RubberBand::deallocate(p);
}
template <typename U>
T *
allocate(const size_t n, const U *) const {
return allocate(n);
}
T *
address(T &r) const {
return &r;
}
const T *
address(const T &s) const {
return &s;
}
size_t
max_size() const {
return (static_cast<size_t>(0) - static_cast<size_t>(1)) / sizeof(T);
}
template <typename U> struct rebind {
typedef StlAllocator<U> other;
};
bool
operator==(const StlAllocator &) const {
return true;
}
bool
operator!=(const StlAllocator &) const {
return false;
}
void
construct(T *const p, const T &t) const {
void *const pv = static_cast<void *>(p);
new (pv) T(t);
}
void
destroy(T *const p) const {
p->~T();
}
private:
StlAllocator& operator=(const StlAllocator&);
};
}
#endif

View File

@@ -366,32 +366,32 @@ inline void v_scale(double *const R__ dst,
}
#endif
template<typename T>
inline void v_multiply(T *const R__ dst,
const T *const R__ src,
template<typename T, typename S>
inline void v_multiply(T *const R__ srcdst,
const S *const R__ src,
const int count)
{
for (int i = 0; i < count; ++i) {
dst[i] *= src[i];
srcdst[i] *= src[i];
}
}
#if defined HAVE_IPP
template<>
inline void v_multiply(float *const R__ dst,
inline void v_multiply(float *const R__ srcdst,
const float *const R__ src,
const int count)
{
ippsMul_32f_I(src, dst, count);
ippsMul_32f_I(src, srcdst, count);
}
template<>
inline void v_multiply(double *const R__ dst,
inline void v_multiply(double *const R__ srcdst,
const double *const R__ src,
const int count)
{
ippsMul_64f_I(src, dst, count);
ippsMul_64f_I(src, srcdst, count);
}
#endif
#endif // HAVE_IPP
template<typename T>
inline void v_multiply(T *const R__ dst,
@@ -491,6 +491,58 @@ inline T v_sum(const T *const R__ src,
return result;
}
template<typename T>
inline T v_multiply_and_sum(const T *const R__ src1,
const T *const R__ src2,
const int count)
{
T result = T();
for (int i = 0; i < count; ++i) {
result += src1[i] * src2[i];
}
return result;
}
#if defined HAVE_IPP
template<>
inline float v_multiply_and_sum(const float *const R__ src1,
const float *const R__ src2,
const int count)
{
float dp;
ippsDotProd_32f(src1, src2, count, &dp);
return dp;
}
template<>
inline double v_multiply_and_sum(const double *const R__ src1,
const double *const R__ src2,
const int count)
{
double dp;
ippsDotProd_64f(src1, src2, count, &dp);
return dp;
}
#elif defined HAVE_VDSP
template<>
inline float v_multiply_and_sum(const float *const R__ src1,
const float *const R__ src2,
const int count)
{
float dp;
vDSP_dotpr(src1, 1, src2, 1, &dp, count);
return dp;
}
template<>
inline double v_multiply_and_sum(const double *const R__ src1,
const double *const R__ src2,
const int count)
{
double dp;
vDSP_dotprD(src1, 1, src2, 1, &dp, count);
return dp;
}
#endif
template<typename T>
inline void v_log(T *const R__ dst,
const int count)