react-native-audio-api 0.4.13 → 0.4.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/src/main/cpp/audioapi/CMakeLists.txt +3 -2
- package/android/src/main/cpp/audioapi/android/core/AudioDecoder.cpp +3 -3
- package/android/src/main/cpp/audioapi/android/core/AudioPlayer.cpp +13 -12
- package/android/src/main/cpp/audioapi/android/core/AudioPlayer.h +0 -1
- package/{common/cpp/audioapi/libs/pffft → android/src/main/cpp/audioapi/android/libs}/pffft.c +1 -1
- package/android/src/main/java/com/swmansion/audioapi/AudioAPIPackage.kt +1 -0
- package/common/cpp/audioapi/AudioAPIModuleInstaller.h +3 -1
- package/common/cpp/audioapi/HostObjects/AnalyserNodeHostObject.h +16 -24
- package/common/cpp/audioapi/HostObjects/AudioBufferHostObject.h +0 -4
- package/common/cpp/audioapi/HostObjects/AudioBufferSourceNodeHostObject.h +4 -20
- package/common/cpp/audioapi/HostObjects/AudioContextHostObject.h +2 -3
- package/common/cpp/audioapi/HostObjects/AudioScheduledSourceNodeHostObject.h +2 -32
- package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.h +21 -14
- package/common/cpp/audioapi/HostObjects/OscillatorNodeHostObject.h +2 -4
- package/common/cpp/audioapi/HostObjects/StretcherNodeHostObject.h +35 -0
- package/common/cpp/audioapi/core/AudioNode.cpp +2 -2
- package/common/cpp/audioapi/core/AudioParam.cpp +1 -1
- package/common/cpp/audioapi/core/BaseAudioContext.cpp +12 -4
- package/common/cpp/audioapi/core/BaseAudioContext.h +4 -2
- package/common/cpp/audioapi/core/Constants.h +33 -8
- package/common/cpp/audioapi/core/analysis/AnalyserNode.cpp +45 -42
- package/common/cpp/audioapi/core/analysis/AnalyserNode.h +6 -8
- package/common/cpp/audioapi/core/destinations/AudioDestinationNode.cpp +1 -1
- package/common/cpp/audioapi/core/effects/BiquadFilterNode.cpp +8 -12
- package/common/cpp/audioapi/core/effects/GainNode.cpp +3 -4
- package/common/cpp/audioapi/core/effects/PeriodicWave.cpp +49 -32
- package/common/cpp/audioapi/core/effects/PeriodicWave.h +3 -8
- package/common/cpp/audioapi/core/effects/StereoPannerNode.cpp +3 -3
- package/common/cpp/audioapi/core/effects/StretcherNode.cpp +94 -0
- package/common/cpp/audioapi/core/effects/StretcherNode.h +35 -0
- package/common/cpp/audioapi/core/sources/AudioBuffer.cpp +2 -9
- package/common/cpp/audioapi/core/sources/AudioBuffer.h +2 -5
- package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp +35 -72
- package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.h +8 -41
- package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp +6 -18
- package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h +0 -7
- package/common/cpp/audioapi/core/sources/OscillatorNode.cpp +3 -12
- package/common/cpp/audioapi/core/sources/OscillatorNode.h +0 -1
- package/common/cpp/audioapi/{utils → core/utils}/AudioArray.cpp +5 -5
- package/common/cpp/audioapi/{utils → core/utils}/AudioBus.cpp +29 -29
- package/common/cpp/audioapi/dsp/AudioUtils.cpp +2 -2
- package/common/cpp/audioapi/dsp/AudioUtils.h +2 -2
- package/common/cpp/audioapi/dsp/FFTFrame.cpp +100 -0
- package/common/cpp/audioapi/dsp/FFTFrame.h +74 -0
- package/common/cpp/audioapi/dsp/VectorMath.cpp +3 -3
- package/common/cpp/audioapi/dsp/VectorMath.h +2 -2
- package/common/cpp/audioapi/libs/dsp/common.h +47 -0
- package/common/cpp/audioapi/libs/{signalsmith-stretch → dsp}/delay.h +11 -9
- package/common/cpp/audioapi/libs/{signalsmith-stretch → dsp}/fft.h +7 -6
- package/common/cpp/audioapi/libs/{signalsmith-stretch → dsp}/perf.h +2 -0
- package/common/cpp/audioapi/libs/{signalsmith-stretch → dsp}/spectral.h +13 -10
- package/common/cpp/audioapi/libs/dsp/windows.h +219 -0
- package/common/cpp/audioapi/libs/{signalsmith-stretch/signalsmith-stretch.h → signalsmith-stretch.h} +4 -3
- package/ios/audioapi/ios/core/AudioDecoder.mm +3 -3
- package/ios/audioapi/ios/core/AudioPlayer.h +2 -5
- package/ios/audioapi/ios/core/AudioPlayer.m +5 -9
- package/ios/audioapi/ios/core/IOSAudioPlayer.h +0 -1
- package/ios/audioapi/ios/core/IOSAudioPlayer.mm +10 -12
- package/lib/module/api.js +2 -1
- package/lib/module/api.js.map +1 -1
- package/lib/module/api.web.js +1 -1
- package/lib/module/api.web.js.map +1 -1
- package/lib/module/core/AudioBufferSourceNode.js +0 -6
- package/lib/module/core/AudioBufferSourceNode.js.map +1 -1
- package/lib/module/core/AudioScheduledSourceNode.js +0 -5
- package/lib/module/core/AudioScheduledSourceNode.js.map +1 -1
- package/lib/module/core/BaseAudioContext.js +4 -0
- package/lib/module/core/BaseAudioContext.js.map +1 -1
- package/lib/module/core/StretcherNode.js +12 -0
- package/lib/module/core/StretcherNode.js.map +1 -0
- package/lib/module/web-core/AudioBufferSourceNode.js +0 -6
- package/lib/module/web-core/AudioBufferSourceNode.js.map +1 -1
- package/lib/module/web-core/AudioScheduledSourceNode.js +0 -8
- package/lib/module/web-core/AudioScheduledSourceNode.js.map +1 -1
- package/lib/module/web-core/StretcherNode.js +7 -24
- package/lib/module/web-core/StretcherNode.js.map +1 -1
- package/lib/module/web-core/custom/signalsmithStretch/README.md +1 -1
- package/lib/module/web-core/custom/signalsmithStretch/SignalsmithStretch.js +0 -1
- package/lib/module/web-core/custom/signalsmithStretch/SignalsmithStretch.js.map +1 -1
- package/lib/typescript/api.d.ts +2 -1
- package/lib/typescript/api.d.ts.map +1 -1
- package/lib/typescript/api.web.d.ts +1 -1
- package/lib/typescript/api.web.d.ts.map +1 -1
- package/lib/typescript/core/AudioBufferSourceNode.d.ts +0 -3
- package/lib/typescript/core/AudioBufferSourceNode.d.ts.map +1 -1
- package/lib/typescript/core/AudioScheduledSourceNode.d.ts +0 -1
- package/lib/typescript/core/AudioScheduledSourceNode.d.ts.map +1 -1
- package/lib/typescript/core/BaseAudioContext.d.ts +2 -0
- package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -1
- package/lib/typescript/core/StretcherNode.d.ts +10 -0
- package/lib/typescript/core/StretcherNode.d.ts.map +1 -0
- package/lib/typescript/interfaces.d.ts +6 -3
- package/lib/typescript/interfaces.d.ts.map +1 -1
- package/lib/typescript/types.d.ts +0 -1
- package/lib/typescript/types.d.ts.map +1 -1
- package/lib/typescript/web-core/AudioBufferSourceNode.d.ts +0 -3
- package/lib/typescript/web-core/AudioBufferSourceNode.d.ts.map +1 -1
- package/lib/typescript/web-core/AudioScheduledSourceNode.d.ts +0 -1
- package/lib/typescript/web-core/AudioScheduledSourceNode.d.ts.map +1 -1
- package/lib/typescript/web-core/StretcherNode.d.ts +0 -3
- package/lib/typescript/web-core/StretcherNode.d.ts.map +1 -1
- package/package.json +4 -3
- package/scripts/setup-custom-wasm.js +104 -0
- package/src/api.ts +1 -1
- package/src/api.web.ts +0 -1
- package/src/core/AudioBufferSourceNode.ts +0 -9
- package/src/core/AudioScheduledSourceNode.ts +0 -5
- package/src/core/BaseAudioContext.ts +5 -0
- package/src/core/StretcherNode.ts +15 -0
- package/src/interfaces.ts +6 -3
- package/src/types.ts +0 -2
- package/src/web-core/AudioBufferSourceNode.tsx +0 -11
- package/src/web-core/AudioScheduledSourceNode.tsx +0 -9
- package/src/web-core/StretcherNode.tsx +8 -28
- package/src/web-core/custom/signalsmithStretch/README.md +1 -1
- package/src/web-core/custom/signalsmithStretch/SignalsmithStretch.js +0 -1
- package/common/cpp/audioapi/core/types/TimeStretchType.h +0 -7
- package/common/cpp/audioapi/dsp/FFT.cpp +0 -41
- package/common/cpp/audioapi/dsp/FFT.h +0 -29
- package/common/cpp/audioapi/dsp/Windows.cpp +0 -80
- package/common/cpp/audioapi/dsp/Windows.h +0 -95
- package/scripts/setup-rn-audio-api-web.js +0 -58
- /package/{common/cpp/audioapi/libs/pffft → android/src/main/cpp/audioapi/android/libs}/pffft.h +0 -0
- /package/common/cpp/audioapi/{utils → core/utils}/AudioArray.h +0 -0
- /package/common/cpp/audioapi/{utils → core/utils}/AudioBus.h +0 -0
- /package/common/cpp/audioapi/libs/{miniaudio/miniaudio.h → miniaudio.h} +0 -0
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
#include <cstdint>
|
|
5
5
|
#include <cmath>
|
|
6
6
|
|
|
7
|
-
namespace audioapi::
|
|
7
|
+
namespace audioapi::AudioUtils {
|
|
8
8
|
|
|
9
9
|
size_t timeToSampleFrame(double time, float sampleRate);
|
|
10
10
|
double sampleFrameToTime(int sampleFrame, float sampleRate);
|
|
@@ -13,4 +13,4 @@ float linearInterpolate(const float *source, size_t firstIndex, size_t secondInd
|
|
|
13
13
|
|
|
14
14
|
float linearToDecibels(float value);
|
|
15
15
|
float decibelsToLinear(float value);
|
|
16
|
-
} // namespace audioapi::
|
|
16
|
+
} // namespace audioapi::AudioUtils
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
#include <audioapi/dsp/FFTFrame.h>
|
|
2
|
+
|
|
3
|
+
namespace audioapi {
|
|
4
|
+
#if defined(HAVE_ACCELERATE)
|
|
5
|
+
static std::unordered_map<size_t, FFTSetup> fftSetups_;
|
|
6
|
+
|
|
7
|
+
FFTFrame::FFTFrame(int size)
|
|
8
|
+
: size_(size), log2Size_(static_cast<int>(log2(size))) {
|
|
9
|
+
fftSetup_ = getFFTSetupForSize(log2Size_);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
FFTFrame::~FFTFrame() {}
|
|
13
|
+
|
|
14
|
+
FFTSetup FFTFrame::getFFTSetupForSize(size_t log2FFTSize) {
|
|
15
|
+
if (!fftSetups_.contains(log2FFTSize)) {
|
|
16
|
+
fftSetups_.emplace(
|
|
17
|
+
log2FFTSize, vDSP_create_fftsetup(log2FFTSize, FFT_RADIX2));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return fftSetups_.at(log2FFTSize);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
void FFTFrame::doFFT(float *data, float *realData, float *imaginaryData) {
|
|
24
|
+
frame_.realp = realData;
|
|
25
|
+
frame_.imagp = imaginaryData;
|
|
26
|
+
vDSP_ctoz(reinterpret_cast<DSPComplex *>(data), 2, &frame_, 1, size_ / 2);
|
|
27
|
+
vDSP_fft_zrip(fftSetup_, &frame_, 1, log2Size_, FFT_FORWARD);
|
|
28
|
+
|
|
29
|
+
VectorMath::multiplyByScalar(realData, 0.5f, realData, size_ / 2);
|
|
30
|
+
VectorMath::multiplyByScalar(imaginaryData, 0.5f, imaginaryData, size_ / 2);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
void FFTFrame::doInverseFFT(
|
|
34
|
+
float *data,
|
|
35
|
+
float *realData,
|
|
36
|
+
float *imaginaryData) {
|
|
37
|
+
frame_.realp = realData;
|
|
38
|
+
frame_.imagp = imaginaryData;
|
|
39
|
+
vDSP_fft_zrip(fftSetup_, &frame_, 1, log2Size_, FFT_INVERSE);
|
|
40
|
+
vDSP_ztoc(&frame_, 1, reinterpret_cast<DSPComplex *>(data), 2, size_ / 2);
|
|
41
|
+
|
|
42
|
+
// Scale the FFT data, beacuse of
|
|
43
|
+
// https://developer.apple.com/library/archive/documentation/Performance/Conceptual/vDSP_Programming_Guide/UsingFourierTransforms/UsingFourierTransforms.html#//apple_ref/doc/uid/TP40005147-CH3-15892
|
|
44
|
+
VectorMath::multiplyByScalar(
|
|
45
|
+
data, 1.0f / static_cast<float>(size_), data, size_);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
#elif defined(ANDROID)
|
|
49
|
+
|
|
50
|
+
FFTFrame::FFTFrame(int size)
|
|
51
|
+
: size_(size), log2Size_(static_cast<int>(log2(size))) {
|
|
52
|
+
pffftSetup_ = pffft_new_setup(size_, PFFFT_REAL);
|
|
53
|
+
work_ = (float *)pffft_aligned_malloc(size_ * sizeof(float));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
FFTFrame::~FFTFrame() {
|
|
57
|
+
pffft_destroy_setup(pffftSetup_);
|
|
58
|
+
pffft_aligned_free(work_);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
void FFTFrame::doFFT(float *data, float *realData, float *imaginaryData) {
|
|
62
|
+
std::vector<std::complex<float>> out(size_);
|
|
63
|
+
pffft_transform_ordered(
|
|
64
|
+
pffftSetup_,
|
|
65
|
+
data,
|
|
66
|
+
reinterpret_cast<float *>(&out[0]),
|
|
67
|
+
work_,
|
|
68
|
+
PFFFT_FORWARD);
|
|
69
|
+
|
|
70
|
+
for (int i = 0; i < size_ / 2; ++i) {
|
|
71
|
+
realData[i] = out[i].real();
|
|
72
|
+
imaginaryData[i] = out[i].imag();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
VectorMath::multiplyByScalar(realData, 0.5f, realData, size_ / 2);
|
|
76
|
+
VectorMath::multiplyByScalar(imaginaryData, 0.5f, imaginaryData, size_ / 2);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
void FFTFrame::doInverseFFT(
|
|
80
|
+
float *data,
|
|
81
|
+
float *realData,
|
|
82
|
+
float *imaginaryData) {
|
|
83
|
+
std::vector<std::complex<float>> out(size_ / 2);
|
|
84
|
+
for (int i = 0; i < size_ / 2; i++) {
|
|
85
|
+
out[i] = {realData[i], imaginaryData[i]};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
pffft_transform_ordered(
|
|
89
|
+
pffftSetup_,
|
|
90
|
+
reinterpret_cast<float *>(&out[0]),
|
|
91
|
+
data,
|
|
92
|
+
work_,
|
|
93
|
+
PFFFT_BACKWARD);
|
|
94
|
+
|
|
95
|
+
VectorMath::multiplyByScalar(
|
|
96
|
+
data, 1.0f / static_cast<float>(size_), data, size_);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
#endif
|
|
100
|
+
} // namespace audioapi
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2010 Google Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* Redistribution and use in source and binary forms, with or without
|
|
5
|
+
* modification, are permitted provided that the following conditions
|
|
6
|
+
* are met:
|
|
7
|
+
*
|
|
8
|
+
* 1. Redistributions of source code must retain the above copyright
|
|
9
|
+
* notice, this list of conditions and the following disclaimer.
|
|
10
|
+
* 2. Redistributions in binary form must reproduce the above copyright
|
|
11
|
+
* notice, this list of conditions and the following disclaimer in the
|
|
12
|
+
* documentation and/or other materials provided with the distribution.
|
|
13
|
+
* 3. Neither the name of Apple Inc. ("Apple") nor the names of
|
|
14
|
+
* its contributors may be used to endorse or promote products derived
|
|
15
|
+
* from this software without specific prior written permission.
|
|
16
|
+
*
|
|
17
|
+
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
|
|
18
|
+
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
19
|
+
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
20
|
+
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
|
|
21
|
+
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
22
|
+
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
23
|
+
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
24
|
+
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
25
|
+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
26
|
+
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
#pragma once
|
|
30
|
+
|
|
31
|
+
#include <audioapi/dsp/VectorMath.h>
|
|
32
|
+
|
|
33
|
+
#include <algorithm>
|
|
34
|
+
#include <cmath>
|
|
35
|
+
#include <utility>
|
|
36
|
+
#include <unordered_map>
|
|
37
|
+
#include <complex>
|
|
38
|
+
|
|
39
|
+
#if defined(HAVE_ACCELERATE)
|
|
40
|
+
#include <Accelerate/Accelerate.h>
|
|
41
|
+
#endif
|
|
42
|
+
|
|
43
|
+
#if defined(ANDROID)
|
|
44
|
+
#include <audioapi/android/libs/pffft.h>
|
|
45
|
+
#endif
|
|
46
|
+
|
|
47
|
+
namespace audioapi {
|
|
48
|
+
|
|
49
|
+
class FFTFrame {
|
|
50
|
+
public:
|
|
51
|
+
explicit FFTFrame(int size);
|
|
52
|
+
~FFTFrame();
|
|
53
|
+
|
|
54
|
+
void doFFT(float *data, float *realData, float *imaginaryData);
|
|
55
|
+
void doInverseFFT(float *data, float *realData, float *imaginaryData);
|
|
56
|
+
|
|
57
|
+
private:
|
|
58
|
+
int size_;
|
|
59
|
+
int log2Size_;
|
|
60
|
+
|
|
61
|
+
#if defined(HAVE_ACCELERATE)
|
|
62
|
+
FFTSetup fftSetup_;
|
|
63
|
+
DSPSplitComplex frame_;
|
|
64
|
+
|
|
65
|
+
static FFTSetup getFFTSetupForSize(size_t log2FFTSize);
|
|
66
|
+
#endif
|
|
67
|
+
|
|
68
|
+
#if defined(ANDROID)
|
|
69
|
+
PFFFT_Setup *pffftSetup_;
|
|
70
|
+
float *work_;
|
|
71
|
+
#endif
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
} // namespace audioapi
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
#include <arm_neon.h>
|
|
39
39
|
#endif
|
|
40
40
|
|
|
41
|
-
namespace audioapi::
|
|
41
|
+
namespace audioapi::VectorMath {
|
|
42
42
|
|
|
43
43
|
#if defined(HAVE_ACCELERATE)
|
|
44
44
|
|
|
@@ -695,7 +695,7 @@ void linearToDecibels(
|
|
|
695
695
|
float *outputVector,
|
|
696
696
|
size_t numberOfElementsToProcess) {
|
|
697
697
|
for (int i = 0; i < numberOfElementsToProcess; i++) {
|
|
698
|
-
outputVector[i] =
|
|
698
|
+
outputVector[i] = AudioUtils::linearToDecibels(inputVector[i]);
|
|
699
699
|
}
|
|
700
700
|
}
|
|
701
|
-
} // namespace audioapi::
|
|
701
|
+
} // namespace audioapi::VectorMath
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
#include <algorithm>
|
|
33
33
|
#include <cmath>
|
|
34
34
|
|
|
35
|
-
namespace audioapi::
|
|
35
|
+
namespace audioapi::VectorMath {
|
|
36
36
|
|
|
37
37
|
void multiplyByScalarThenAddToOutput(const float *inputVector, float scalar, float *outputVector, size_t numberOfElementsToProcess);
|
|
38
38
|
|
|
@@ -46,4 +46,4 @@ void multiply(const float *inputVector1, const float *inputVector2, float *outpu
|
|
|
46
46
|
float maximumMagnitude(const float *inputVector, size_t numberOfElementsToProcess);
|
|
47
47
|
|
|
48
48
|
void linearToDecibels(const float *inputVector, float *outputVector, size_t numberOfElementsToProcess);
|
|
49
|
-
} // namespace audioapi::
|
|
49
|
+
} // namespace audioapi::VectorMath
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#ifndef SIGNALSMITH_DSP_COMMON_H
|
|
2
|
+
#define SIGNALSMITH_DSP_COMMON_H
|
|
3
|
+
|
|
4
|
+
#if defined(__FAST_MATH__) && (__apple_build_version__ >= 16000000) && (__apple_build_version__ <= 16000099)
|
|
5
|
+
# error Apple Clang 16.0.0 generates incorrect SIMD for ARM. If you HAVE to use this version of Clang, turn off -ffast-math.
|
|
6
|
+
#endif
|
|
7
|
+
|
|
8
|
+
#ifndef M_PI
|
|
9
|
+
#define M_PI 3.14159265358979323846264338327950288
|
|
10
|
+
#endif
|
|
11
|
+
|
|
12
|
+
namespace signalsmith {
|
|
13
|
+
/** @defgroup Common Common
|
|
14
|
+
@brief Definitions and helper classes used by the rest of the library
|
|
15
|
+
|
|
16
|
+
@{
|
|
17
|
+
@file
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
#define SIGNALSMITH_DSP_VERSION_MAJOR 1
|
|
21
|
+
#define SIGNALSMITH_DSP_VERSION_MINOR 6
|
|
22
|
+
#define SIGNALSMITH_DSP_VERSION_PATCH 1
|
|
23
|
+
#define SIGNALSMITH_DSP_VERSION_STRING "1.6.1"
|
|
24
|
+
|
|
25
|
+
/** Version compatability check.
|
|
26
|
+
\code{.cpp}
|
|
27
|
+
static_assert(signalsmith::version(1, 4, 1), "version check");
|
|
28
|
+
\endcode
|
|
29
|
+
... or use the equivalent `SIGNALSMITH_DSP_VERSION_CHECK`.
|
|
30
|
+
Major versions are not compatible with each other. Minor and patch versions are backwards-compatible.
|
|
31
|
+
*/
|
|
32
|
+
constexpr bool versionCheck(int major, int minor, int patch=0) {
|
|
33
|
+
return major == SIGNALSMITH_DSP_VERSION_MAJOR
|
|
34
|
+
&& (SIGNALSMITH_DSP_VERSION_MINOR > minor
|
|
35
|
+
|| (SIGNALSMITH_DSP_VERSION_MINOR == minor && SIGNALSMITH_DSP_VERSION_PATCH >= patch));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/// Check the library version is compatible (semver).
|
|
39
|
+
#define SIGNALSMITH_DSP_VERSION_CHECK(major, minor, patch) \
|
|
40
|
+
static_assert(::signalsmith::versionCheck(major, minor, patch), "signalsmith library version is " SIGNALSMITH_DSP_VERSION_STRING);
|
|
41
|
+
|
|
42
|
+
/** @} */
|
|
43
|
+
} // signalsmith::
|
|
44
|
+
#else
|
|
45
|
+
// If we've already included it, check it's the same version
|
|
46
|
+
static_assert(SIGNALSMITH_DSP_VERSION_MAJOR == 1 && SIGNALSMITH_DSP_VERSION_MINOR == 6 && SIGNALSMITH_DSP_VERSION_PATCH == 1, "multiple versions of the Signalsmith DSP library");
|
|
47
|
+
#endif // include guard
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
#include <audioapi/libs/dsp/common.h>
|
|
2
|
+
|
|
1
3
|
#ifndef SIGNALSMITH_DSP_DELAY_H
|
|
2
4
|
#define SIGNALSMITH_DSP_DELAY_H
|
|
3
5
|
|
|
@@ -5,10 +7,10 @@
|
|
|
5
7
|
#include <array>
|
|
6
8
|
#include <cmath> // for std::ceil()
|
|
7
9
|
#include <type_traits>
|
|
8
|
-
#include <complex>
|
|
9
10
|
|
|
10
|
-
#include <
|
|
11
|
-
#include <audioapi/dsp/
|
|
11
|
+
#include <complex>
|
|
12
|
+
#include <audioapi/libs/dsp/fft.h>
|
|
13
|
+
#include <audioapi/libs/dsp/windows.h>
|
|
12
14
|
|
|
13
15
|
namespace signalsmith {
|
|
14
16
|
namespace delay {
|
|
@@ -480,14 +482,14 @@ namespace delay {
|
|
|
480
482
|
InterpolatorKaiserSincN(double passFreq) : InterpolatorKaiserSincN(passFreq, 1 - passFreq) {}
|
|
481
483
|
InterpolatorKaiserSincN(double passFreq, double stopFreq) {
|
|
482
484
|
subSampleSteps = 2*n; // Heuristic again. Really it depends on the bandwidth as well.
|
|
483
|
-
|
|
484
|
-
kaiserBandwidth += 1.
|
|
485
|
-
double sincScale =
|
|
485
|
+
double kaiserBandwidth = (stopFreq - passFreq)*(n + 1.0/subSampleSteps);
|
|
486
|
+
kaiserBandwidth += 1.25/kaiserBandwidth; // We want to place the first zero, but (because using this to window a sinc essentially integrates it in the freq-domain), our ripples (and therefore zeroes) are out of phase. This is a heuristic fix.
|
|
487
|
+
double sincScale = M_PI*(passFreq + stopFreq);
|
|
486
488
|
|
|
487
489
|
double centreIndex = n*subSampleSteps*0.5, scaleFactor = 1.0/subSampleSteps;
|
|
488
490
|
std::vector<Sample> windowedSinc(subSampleSteps*n + 1);
|
|
489
491
|
|
|
490
|
-
|
|
492
|
+
::signalsmith::windows::Kaiser::withBandwidth(kaiserBandwidth, false).fill(windowedSinc, windowedSinc.size());
|
|
491
493
|
|
|
492
494
|
for (size_t i = 0; i < windowedSinc.size(); ++i) {
|
|
493
495
|
double x = (i - centreIndex)*scaleFactor;
|
|
@@ -502,7 +504,7 @@ namespace delay {
|
|
|
502
504
|
}
|
|
503
505
|
|
|
504
506
|
if (minimumPhase) {
|
|
505
|
-
signalsmith::fft::FFT<Sample> fft(windowedSinc.
|
|
507
|
+
signalsmith::fft::FFT<Sample> fft(windowedSinc.size()*2, 1);
|
|
506
508
|
windowedSinc.resize(fft.size(), 0);
|
|
507
509
|
std::vector<std::complex<Sample>> spectrum(fft.size());
|
|
508
510
|
std::vector<std::complex<Sample>> cepstrum(fft.size());
|
|
@@ -527,7 +529,7 @@ namespace delay {
|
|
|
527
529
|
}
|
|
528
530
|
fft.ifft(spectrum, cepstrum);
|
|
529
531
|
windowedSinc.resize(subSampleSteps*n + 1);
|
|
530
|
-
|
|
532
|
+
windowedSinc.shrink_to_fit();
|
|
531
533
|
for (size_t i = 0; i < windowedSinc.size(); ++i) {
|
|
532
534
|
windowedSinc[i] = cepstrum[i].real()*scaling;
|
|
533
535
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
#include <audioapi/libs/dsp/common.h>
|
|
2
|
+
|
|
1
3
|
#ifndef SIGNALSMITH_FFT_V5
|
|
2
4
|
#define SIGNALSMITH_FFT_V5
|
|
3
5
|
|
|
4
|
-
#include <audioapi/libs/
|
|
5
|
-
#include <audioapi/core/Constants.h>
|
|
6
|
+
#include <audioapi/libs/dsp/perf.h>
|
|
6
7
|
|
|
7
8
|
#include <vector>
|
|
8
9
|
#include <complex>
|
|
@@ -128,7 +129,7 @@ namespace signalsmith { namespace fft {
|
|
|
128
129
|
if (!foundStep) {
|
|
129
130
|
for (size_t i = 0; i < subLength; ++i) {
|
|
130
131
|
for (size_t f = 0; f < factor; ++f) {
|
|
131
|
-
double phase = 2*
|
|
132
|
+
double phase = 2*M_PI*i*f/length;
|
|
132
133
|
complex twiddle = {V(std::cos(phase)), V(-std::sin(phase))};
|
|
133
134
|
twiddleVector.push_back(twiddle);
|
|
134
135
|
}
|
|
@@ -211,7 +212,7 @@ namespace signalsmith { namespace fft {
|
|
|
211
212
|
for (size_t f = 0; f < factor; ++f) {
|
|
212
213
|
complex sum = working[0];
|
|
213
214
|
for (size_t i = 1; i < factor; ++i) {
|
|
214
|
-
double phase = 2*
|
|
215
|
+
double phase = 2*M_PI*f*i/factor;
|
|
215
216
|
complex twiddle = {V(std::cos(phase)), V(-std::sin(phase))};
|
|
216
217
|
sum += _fft_impl::complexMul<inverse>(working[i], twiddle);
|
|
217
218
|
}
|
|
@@ -430,13 +431,13 @@ namespace signalsmith { namespace fft {
|
|
|
430
431
|
size_t hhSize = size/4 + 1;
|
|
431
432
|
twiddlesMinusI.resize(hhSize);
|
|
432
433
|
for (size_t i = 0; i < hhSize; ++i) {
|
|
433
|
-
V rotPhase = -2*
|
|
434
|
+
V rotPhase = -2*M_PI*(modified ? i + 0.5 : i)/size;
|
|
434
435
|
twiddlesMinusI[i] = {std::sin(rotPhase), -std::cos(rotPhase)};
|
|
435
436
|
}
|
|
436
437
|
if (modified) {
|
|
437
438
|
modifiedRotations.resize(size/2);
|
|
438
439
|
for (size_t i = 0; i < size/2; ++i) {
|
|
439
|
-
V rotPhase = -2*
|
|
440
|
+
V rotPhase = -2*M_PI*i/size;
|
|
440
441
|
modifiedRotations[i] = {std::cos(rotPhase), std::sin(rotPhase)};
|
|
441
442
|
}
|
|
442
443
|
}
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
#include <audioapi/
|
|
1
|
+
#include <audioapi/libs/dsp/common.h>
|
|
2
2
|
|
|
3
3
|
#ifndef SIGNALSMITH_DSP_SPECTRAL_H
|
|
4
4
|
#define SIGNALSMITH_DSP_SPECTRAL_H
|
|
5
5
|
|
|
6
|
-
#include <audioapi/libs/
|
|
7
|
-
#include <audioapi/libs/
|
|
8
|
-
#include <audioapi/libs/
|
|
9
|
-
|
|
10
|
-
#include <audioapi/dsp/Windows.h>
|
|
6
|
+
#include <audioapi/libs/dsp/perf.h>
|
|
7
|
+
#include <audioapi/libs/dsp/fft.h>
|
|
8
|
+
#include <audioapi/libs/dsp/windows.h>
|
|
9
|
+
#include <audioapi/libs/dsp/delay.h>
|
|
11
10
|
|
|
12
11
|
#include <cmath>
|
|
13
12
|
|
|
@@ -77,7 +76,7 @@ namespace spectral {
|
|
|
77
76
|
/// Sets the size (using the default Blackman-Harris window)
|
|
78
77
|
void setSize(int size, int rotateSamples=0) {
|
|
79
78
|
setSize(size, [](double x) {
|
|
80
|
-
double phase = 2
|
|
79
|
+
double phase = 2*M_PI*x;
|
|
81
80
|
// Blackman-Harris
|
|
82
81
|
return 0.35875 - 0.48829*std::cos(phase) + 0.14128*std::cos(phase*2) - 0.01168*std::cos(phase*3);
|
|
83
82
|
}, Sample(0.5), rotateSamples);
|
|
@@ -250,12 +249,16 @@ namespace spectral {
|
|
|
250
249
|
|
|
251
250
|
auto &window = fft.setSizeWindow(_fftSize, rotateToZero ? _windowSize/2 : 0);
|
|
252
251
|
if (windowShape == Window::kaiser) {
|
|
252
|
+
using Kaiser = ::signalsmith::windows::Kaiser;
|
|
253
253
|
/// Roughly optimal Kaiser for STFT analysis (forced to perfect reconstruction)
|
|
254
|
-
|
|
254
|
+
auto kaiser_ = Kaiser::withBandwidth(_windowSize/double(_interval), true);
|
|
255
|
+
kaiser_.fill(window, _windowSize);
|
|
255
256
|
} else {
|
|
256
|
-
|
|
257
|
+
using Confined = ::signalsmith::windows::ApproximateConfinedGaussian;
|
|
258
|
+
auto confined = Confined::withBandwidth(_windowSize/double(_interval));
|
|
259
|
+
confined.fill(window, _windowSize);
|
|
257
260
|
}
|
|
258
|
-
|
|
261
|
+
::signalsmith::windows::forcePerfectReconstruction(window, _windowSize, _interval);
|
|
259
262
|
|
|
260
263
|
// TODO: fill extra bits of an input buffer with NaN/Infinity, to break this, and then fix by adding zero-padding to WindowedFFT (as opposed to zero-valued window sections)
|
|
261
264
|
for (int i = _windowSize; i < _fftSize; ++i) {
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
#include <audioapi/libs/dsp/common.h>
|
|
2
|
+
|
|
3
|
+
#ifndef SIGNALSMITH_DSP_WINDOWS_H
|
|
4
|
+
#define SIGNALSMITH_DSP_WINDOWS_H
|
|
5
|
+
|
|
6
|
+
#include <cmath>
|
|
7
|
+
#include <algorithm>
|
|
8
|
+
|
|
9
|
+
namespace signalsmith {
|
|
10
|
+
namespace windows {
|
|
11
|
+
/** @defgroup Windows Window functions
|
|
12
|
+
@brief Windows for spectral analysis
|
|
13
|
+
|
|
14
|
+
These are generally double-precision, because they are mostly calculated during setup/reconfiguring, not real-time code.
|
|
15
|
+
|
|
16
|
+
@{
|
|
17
|
+
@file
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/** @brief The Kaiser window (almost) maximises the energy in the main-lobe compared to the side-lobes.
|
|
21
|
+
|
|
22
|
+
Kaiser windows can be constructing using the shape-parameter (beta) or using the static `with???()` methods.*/
|
|
23
|
+
class Kaiser {
|
|
24
|
+
// I_0(x)=\sum_{k=0}^{N}\frac{x^{2k}}{(k!)^2\cdot4^k}
|
|
25
|
+
inline static double bessel0(double x) {
|
|
26
|
+
const double significanceLimit = 1e-4;
|
|
27
|
+
double result = 0;
|
|
28
|
+
double term = 1;
|
|
29
|
+
double m = 0;
|
|
30
|
+
while (term > significanceLimit) {
|
|
31
|
+
result += term;
|
|
32
|
+
++m;
|
|
33
|
+
term *= (x*x)/(4*m*m);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
double beta;
|
|
39
|
+
double invB0;
|
|
40
|
+
|
|
41
|
+
static double heuristicBandwidth(double bandwidth) {
|
|
42
|
+
// Good peaks
|
|
43
|
+
//return bandwidth + 8/((bandwidth + 3)*(bandwidth + 3));
|
|
44
|
+
// Good average
|
|
45
|
+
//return bandwidth + 14/((bandwidth + 2.5)*(bandwidth + 2.5));
|
|
46
|
+
// Compromise
|
|
47
|
+
return bandwidth + 8/((bandwidth + 3)*(bandwidth + 3)) + 0.25*std::max(3 - bandwidth, 0.0);
|
|
48
|
+
}
|
|
49
|
+
public:
|
|
50
|
+
/// Set up a Kaiser window with a given shape. `beta` is `pi*alpha` (since there is ambiguity about shape parameters)
|
|
51
|
+
Kaiser(double beta) : beta(beta), invB0(1/bessel0(beta)) {}
|
|
52
|
+
|
|
53
|
+
/// @name Bandwidth methods
|
|
54
|
+
/// @{
|
|
55
|
+
static Kaiser withBandwidth(double bandwidth, bool heuristicOptimal=false) {
|
|
56
|
+
return Kaiser(bandwidthToBeta(bandwidth, heuristicOptimal));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Returns the Kaiser shape where the main lobe has the specified bandwidth (as a factor of 1/window-length).
|
|
60
|
+
\diagram{kaiser-windows.svg,You can see that the main lobe matches the specified bandwidth.}
|
|
61
|
+
If `heuristicOptimal` is enabled, the main lobe width is _slightly_ wider, improving both the peak and total energy - see `bandwidthToEnergyDb()` and `bandwidthToPeakDb()`.
|
|
62
|
+
\diagram{kaiser-windows-heuristic.svg, The main lobe extends to ±bandwidth/2.} */
|
|
63
|
+
static double bandwidthToBeta(double bandwidth, bool heuristicOptimal=false) {
|
|
64
|
+
if (heuristicOptimal) { // Heuristic based on numerical search
|
|
65
|
+
bandwidth = heuristicBandwidth(bandwidth);
|
|
66
|
+
}
|
|
67
|
+
bandwidth = std::max(bandwidth, 2.0);
|
|
68
|
+
double alpha = std::sqrt(bandwidth*bandwidth*0.25 - 1);
|
|
69
|
+
return alpha*M_PI;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
static double betaToBandwidth(double beta) {
|
|
73
|
+
double alpha = beta*(1.0/M_PI);
|
|
74
|
+
return 2*std::sqrt(alpha*alpha + 1);
|
|
75
|
+
}
|
|
76
|
+
/// @}
|
|
77
|
+
|
|
78
|
+
/// @name Performance methods
|
|
79
|
+
/// @{
|
|
80
|
+
/** @brief Total energy ratio (in dB) between side-lobes and the main lobe.
|
|
81
|
+
\diagram{windows-kaiser-sidelobe-energy.svg,Measured main/side lobe energy ratio. You can see that the heuristic improves performance for all bandwidth values.}
|
|
82
|
+
This function uses an approximation which is accurate to ±0.5dB for 2 ⩽ bandwidth ≤ 10, or 1 ⩽ bandwidth ≤ 10 when `heuristicOptimal`is enabled.
|
|
83
|
+
*/
|
|
84
|
+
static double bandwidthToEnergyDb(double bandwidth, bool heuristicOptimal=false) {
|
|
85
|
+
// Horrible heuristic fits
|
|
86
|
+
if (heuristicOptimal) {
|
|
87
|
+
if (bandwidth < 3) bandwidth += (3 - bandwidth)*0.5;
|
|
88
|
+
return 12.9 + -3/(bandwidth + 0.4) - 13.4*bandwidth + (bandwidth < 3)*-9.6*(bandwidth - 3);
|
|
89
|
+
}
|
|
90
|
+
return 10.5 + 15/(bandwidth + 0.4) - 13.25*bandwidth + (bandwidth < 2)*13*(bandwidth - 2);
|
|
91
|
+
}
|
|
92
|
+
static double energyDbToBandwidth(double energyDb, bool heuristicOptimal=false) {
|
|
93
|
+
double bw = 1;
|
|
94
|
+
while (bw < 20 && bandwidthToEnergyDb(bw, heuristicOptimal) > energyDb) {
|
|
95
|
+
bw *= 2;
|
|
96
|
+
}
|
|
97
|
+
double step = bw/2;
|
|
98
|
+
while (step > 0.0001) {
|
|
99
|
+
if (bandwidthToEnergyDb(bw, heuristicOptimal) > energyDb) {
|
|
100
|
+
bw += step;
|
|
101
|
+
} else {
|
|
102
|
+
bw -= step;
|
|
103
|
+
}
|
|
104
|
+
step *= 0.5;
|
|
105
|
+
}
|
|
106
|
+
return bw;
|
|
107
|
+
}
|
|
108
|
+
/** @brief Peak ratio (in dB) between side-lobes and the main lobe.
|
|
109
|
+
\diagram{windows-kaiser-sidelobe-peaks.svg,Measured main/side lobe peak ratio. You can see that the heuristic improves performance, except in the bandwidth range 1-2 where peak ratio was sacrificed to improve total energy ratio.}
|
|
110
|
+
This function uses an approximation which is accurate to ±0.5dB for 2 ⩽ bandwidth ≤ 9, or 0.5 ⩽ bandwidth ≤ 9 when `heuristicOptimal`is enabled.
|
|
111
|
+
*/
|
|
112
|
+
static double bandwidthToPeakDb(double bandwidth, bool heuristicOptimal=false) {
|
|
113
|
+
// Horrible heuristic fits
|
|
114
|
+
if (heuristicOptimal) {
|
|
115
|
+
return 14.2 - 20/(bandwidth + 1) - 13*bandwidth + (bandwidth < 3)*-6*(bandwidth - 3) + (bandwidth < 2.25)*5.8*(bandwidth - 2.25);
|
|
116
|
+
}
|
|
117
|
+
return 10 + 8/(bandwidth + 2) - 12.75*bandwidth + (bandwidth < 2)*4*(bandwidth - 2);
|
|
118
|
+
}
|
|
119
|
+
static double peakDbToBandwidth(double peakDb, bool heuristicOptimal=false) {
|
|
120
|
+
double bw = 1;
|
|
121
|
+
while (bw < 20 && bandwidthToPeakDb(bw, heuristicOptimal) > peakDb) {
|
|
122
|
+
bw *= 2;
|
|
123
|
+
}
|
|
124
|
+
double step = bw/2;
|
|
125
|
+
while (step > 0.0001) {
|
|
126
|
+
if (bandwidthToPeakDb(bw, heuristicOptimal) > peakDb) {
|
|
127
|
+
bw += step;
|
|
128
|
+
} else {
|
|
129
|
+
bw -= step;
|
|
130
|
+
}
|
|
131
|
+
step *= 0.5;
|
|
132
|
+
}
|
|
133
|
+
return bw;
|
|
134
|
+
}
|
|
135
|
+
/** @} */
|
|
136
|
+
|
|
137
|
+
/** Equivalent noise bandwidth (ENBW), a measure of frequency resolution.
|
|
138
|
+
\diagram{windows-kaiser-enbw.svg,Measured ENBW\, with and without the heuristic bandwidth adjustment.}
|
|
139
|
+
This approximation is accurate to ±0.05 up to a bandwidth of 22.
|
|
140
|
+
*/
|
|
141
|
+
static double bandwidthToEnbw(double bandwidth, bool heuristicOptimal=false) {
|
|
142
|
+
if (heuristicOptimal) bandwidth = heuristicBandwidth(bandwidth);
|
|
143
|
+
double b2 = std::max<double>(bandwidth - 2, 0);
|
|
144
|
+
return 1 + b2*(0.2 + b2*(-0.005 + b2*(-0.000005 + b2*0.0000022)));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/// Return the window's value for position in the range [0, 1]
|
|
148
|
+
double operator ()(double unit) {
|
|
149
|
+
double r = 2*unit - 1;
|
|
150
|
+
double arg = std::sqrt(1 - r*r);
|
|
151
|
+
return bessel0(beta*arg)*invB0;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/// Fills an arbitrary container with a Kaiser window
|
|
155
|
+
template<typename Data>
|
|
156
|
+
void fill(Data &&data, int size) const {
|
|
157
|
+
double invSize = 1.0/size;
|
|
158
|
+
for (int i = 0; i < size; ++i) {
|
|
159
|
+
double r = (2*i + 1)*invSize - 1;
|
|
160
|
+
double arg = std::sqrt(1 - r*r);
|
|
161
|
+
data[i] = bessel0(beta*arg)*invB0;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
/** @brief The Approximate Confined Gaussian window is (almost) optimal
|
|
167
|
+
|
|
168
|
+
ACG windows can be constructing using the shape-parameter (sigma) or using the static `with???()` methods.*/
|
|
169
|
+
class ApproximateConfinedGaussian {
|
|
170
|
+
double gaussianFactor;
|
|
171
|
+
|
|
172
|
+
double gaussian(double x) const {
|
|
173
|
+
return std::exp(-x*x*gaussianFactor);
|
|
174
|
+
}
|
|
175
|
+
public:
|
|
176
|
+
/// Heuristic map from bandwidth to the appropriately-optimal sigma
|
|
177
|
+
static double bandwidthToSigma(double bandwidth) {
|
|
178
|
+
return 0.3/std::sqrt(bandwidth);
|
|
179
|
+
}
|
|
180
|
+
static ApproximateConfinedGaussian withBandwidth(double bandwidth) {
|
|
181
|
+
return ApproximateConfinedGaussian(bandwidthToSigma(bandwidth));
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
ApproximateConfinedGaussian(double sigma) : gaussianFactor(0.0625/(sigma*sigma)) {}
|
|
185
|
+
|
|
186
|
+
/// Fills an arbitrary container
|
|
187
|
+
template<typename Data>
|
|
188
|
+
void fill(Data &&data, int size) const {
|
|
189
|
+
double invSize = 1.0/size;
|
|
190
|
+
double offsetScale = gaussian(1)/(gaussian(3) + gaussian(-1));
|
|
191
|
+
double norm = 1/(gaussian(0) - 2*offsetScale*(gaussian(2)));
|
|
192
|
+
for (int i = 0; i < size; ++i) {
|
|
193
|
+
double r = (2*i + 1)*invSize - 1;
|
|
194
|
+
data[i] = norm*(gaussian(r) - offsetScale*(gaussian(r - 2) + gaussian(r + 2)));
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
/** Forces STFT perfect-reconstruction (WOLA) on an existing window, for a given STFT interval.
|
|
200
|
+
For example, here are perfect-reconstruction versions of the approximately-optimal @ref Kaiser windows:
|
|
201
|
+
\diagram{kaiser-windows-heuristic-pr.svg,Note the lower overall energy\, and the pointy top for 2x bandwidth. Spectral performance is about the same\, though.}
|
|
202
|
+
*/
|
|
203
|
+
template<typename Data>
|
|
204
|
+
void forcePerfectReconstruction(Data &&data, int windowLength, int interval) {
|
|
205
|
+
for (int i = 0; i < interval; ++i) {
|
|
206
|
+
double sum2 = 0;
|
|
207
|
+
for (int index = i; index < windowLength; index += interval) {
|
|
208
|
+
sum2 += data[index]*data[index];
|
|
209
|
+
}
|
|
210
|
+
double factor = 1/std::sqrt(sum2);
|
|
211
|
+
for (int index = i; index < windowLength; index += interval) {
|
|
212
|
+
data[index] *= factor;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/** @} */
|
|
218
|
+
}} // signalsmith::windows
|
|
219
|
+
#endif // include guard
|
package/common/cpp/audioapi/libs/{signalsmith-stretch/signalsmith-stretch.h → signalsmith-stretch.h}
RENAMED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
#ifndef SIGNALSMITH_STRETCH_H
|
|
2
2
|
#define SIGNALSMITH_STRETCH_H
|
|
3
3
|
|
|
4
|
-
#include <audioapi/libs/
|
|
5
|
-
#include <audioapi/libs/
|
|
6
|
-
#include <audioapi/libs/
|
|
4
|
+
#include <audioapi/libs/dsp/spectral.h>
|
|
5
|
+
#include <audioapi/libs/dsp/delay.h>
|
|
6
|
+
#include <audioapi/libs/dsp/perf.h>
|
|
7
|
+
SIGNALSMITH_DSP_VERSION_CHECK(1, 6, 0); // Check version is compatible
|
|
7
8
|
#include <vector>
|
|
8
9
|
#include <algorithm>
|
|
9
10
|
#include <functional>
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#define MINIAUDIO_IMPLEMENTATION
|
|
2
|
-
#import <audioapi/libs/miniaudio
|
|
2
|
+
#import <audioapi/libs/miniaudio.h>
|
|
3
3
|
|
|
4
|
+
#include <audioapi/core/utils/AudioArray.h>
|
|
5
|
+
#include <audioapi/core/utils/AudioBus.h>
|
|
4
6
|
#include <audioapi/core/utils/AudioDecoder.h>
|
|
5
|
-
#include <audioapi/utils/AudioArray.h>
|
|
6
|
-
#include <audioapi/utils/AudioBus.h>
|
|
7
7
|
|
|
8
8
|
namespace audioapi {
|
|
9
9
|
|