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.
Files changed (126) hide show
  1. package/android/src/main/cpp/audioapi/CMakeLists.txt +3 -2
  2. package/android/src/main/cpp/audioapi/android/core/AudioDecoder.cpp +3 -3
  3. package/android/src/main/cpp/audioapi/android/core/AudioPlayer.cpp +13 -12
  4. package/android/src/main/cpp/audioapi/android/core/AudioPlayer.h +0 -1
  5. package/{common/cpp/audioapi/libs/pffft → android/src/main/cpp/audioapi/android/libs}/pffft.c +1 -1
  6. package/android/src/main/java/com/swmansion/audioapi/AudioAPIPackage.kt +1 -0
  7. package/common/cpp/audioapi/AudioAPIModuleInstaller.h +3 -1
  8. package/common/cpp/audioapi/HostObjects/AnalyserNodeHostObject.h +16 -24
  9. package/common/cpp/audioapi/HostObjects/AudioBufferHostObject.h +0 -4
  10. package/common/cpp/audioapi/HostObjects/AudioBufferSourceNodeHostObject.h +4 -20
  11. package/common/cpp/audioapi/HostObjects/AudioContextHostObject.h +2 -3
  12. package/common/cpp/audioapi/HostObjects/AudioScheduledSourceNodeHostObject.h +2 -32
  13. package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.h +21 -14
  14. package/common/cpp/audioapi/HostObjects/OscillatorNodeHostObject.h +2 -4
  15. package/common/cpp/audioapi/HostObjects/StretcherNodeHostObject.h +35 -0
  16. package/common/cpp/audioapi/core/AudioNode.cpp +2 -2
  17. package/common/cpp/audioapi/core/AudioParam.cpp +1 -1
  18. package/common/cpp/audioapi/core/BaseAudioContext.cpp +12 -4
  19. package/common/cpp/audioapi/core/BaseAudioContext.h +4 -2
  20. package/common/cpp/audioapi/core/Constants.h +33 -8
  21. package/common/cpp/audioapi/core/analysis/AnalyserNode.cpp +45 -42
  22. package/common/cpp/audioapi/core/analysis/AnalyserNode.h +6 -8
  23. package/common/cpp/audioapi/core/destinations/AudioDestinationNode.cpp +1 -1
  24. package/common/cpp/audioapi/core/effects/BiquadFilterNode.cpp +8 -12
  25. package/common/cpp/audioapi/core/effects/GainNode.cpp +3 -4
  26. package/common/cpp/audioapi/core/effects/PeriodicWave.cpp +49 -32
  27. package/common/cpp/audioapi/core/effects/PeriodicWave.h +3 -8
  28. package/common/cpp/audioapi/core/effects/StereoPannerNode.cpp +3 -3
  29. package/common/cpp/audioapi/core/effects/StretcherNode.cpp +94 -0
  30. package/common/cpp/audioapi/core/effects/StretcherNode.h +35 -0
  31. package/common/cpp/audioapi/core/sources/AudioBuffer.cpp +2 -9
  32. package/common/cpp/audioapi/core/sources/AudioBuffer.h +2 -5
  33. package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp +35 -72
  34. package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.h +8 -41
  35. package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp +6 -18
  36. package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h +0 -7
  37. package/common/cpp/audioapi/core/sources/OscillatorNode.cpp +3 -12
  38. package/common/cpp/audioapi/core/sources/OscillatorNode.h +0 -1
  39. package/common/cpp/audioapi/{utils → core/utils}/AudioArray.cpp +5 -5
  40. package/common/cpp/audioapi/{utils → core/utils}/AudioBus.cpp +29 -29
  41. package/common/cpp/audioapi/dsp/AudioUtils.cpp +2 -2
  42. package/common/cpp/audioapi/dsp/AudioUtils.h +2 -2
  43. package/common/cpp/audioapi/dsp/FFTFrame.cpp +100 -0
  44. package/common/cpp/audioapi/dsp/FFTFrame.h +74 -0
  45. package/common/cpp/audioapi/dsp/VectorMath.cpp +3 -3
  46. package/common/cpp/audioapi/dsp/VectorMath.h +2 -2
  47. package/common/cpp/audioapi/libs/dsp/common.h +47 -0
  48. package/common/cpp/audioapi/libs/{signalsmith-stretch → dsp}/delay.h +11 -9
  49. package/common/cpp/audioapi/libs/{signalsmith-stretch → dsp}/fft.h +7 -6
  50. package/common/cpp/audioapi/libs/{signalsmith-stretch → dsp}/perf.h +2 -0
  51. package/common/cpp/audioapi/libs/{signalsmith-stretch → dsp}/spectral.h +13 -10
  52. package/common/cpp/audioapi/libs/dsp/windows.h +219 -0
  53. package/common/cpp/audioapi/libs/{signalsmith-stretch/signalsmith-stretch.h → signalsmith-stretch.h} +4 -3
  54. package/ios/audioapi/ios/core/AudioDecoder.mm +3 -3
  55. package/ios/audioapi/ios/core/AudioPlayer.h +2 -5
  56. package/ios/audioapi/ios/core/AudioPlayer.m +5 -9
  57. package/ios/audioapi/ios/core/IOSAudioPlayer.h +0 -1
  58. package/ios/audioapi/ios/core/IOSAudioPlayer.mm +10 -12
  59. package/lib/module/api.js +2 -1
  60. package/lib/module/api.js.map +1 -1
  61. package/lib/module/api.web.js +1 -1
  62. package/lib/module/api.web.js.map +1 -1
  63. package/lib/module/core/AudioBufferSourceNode.js +0 -6
  64. package/lib/module/core/AudioBufferSourceNode.js.map +1 -1
  65. package/lib/module/core/AudioScheduledSourceNode.js +0 -5
  66. package/lib/module/core/AudioScheduledSourceNode.js.map +1 -1
  67. package/lib/module/core/BaseAudioContext.js +4 -0
  68. package/lib/module/core/BaseAudioContext.js.map +1 -1
  69. package/lib/module/core/StretcherNode.js +12 -0
  70. package/lib/module/core/StretcherNode.js.map +1 -0
  71. package/lib/module/web-core/AudioBufferSourceNode.js +0 -6
  72. package/lib/module/web-core/AudioBufferSourceNode.js.map +1 -1
  73. package/lib/module/web-core/AudioScheduledSourceNode.js +0 -8
  74. package/lib/module/web-core/AudioScheduledSourceNode.js.map +1 -1
  75. package/lib/module/web-core/StretcherNode.js +7 -24
  76. package/lib/module/web-core/StretcherNode.js.map +1 -1
  77. package/lib/module/web-core/custom/signalsmithStretch/README.md +1 -1
  78. package/lib/module/web-core/custom/signalsmithStretch/SignalsmithStretch.js +0 -1
  79. package/lib/module/web-core/custom/signalsmithStretch/SignalsmithStretch.js.map +1 -1
  80. package/lib/typescript/api.d.ts +2 -1
  81. package/lib/typescript/api.d.ts.map +1 -1
  82. package/lib/typescript/api.web.d.ts +1 -1
  83. package/lib/typescript/api.web.d.ts.map +1 -1
  84. package/lib/typescript/core/AudioBufferSourceNode.d.ts +0 -3
  85. package/lib/typescript/core/AudioBufferSourceNode.d.ts.map +1 -1
  86. package/lib/typescript/core/AudioScheduledSourceNode.d.ts +0 -1
  87. package/lib/typescript/core/AudioScheduledSourceNode.d.ts.map +1 -1
  88. package/lib/typescript/core/BaseAudioContext.d.ts +2 -0
  89. package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -1
  90. package/lib/typescript/core/StretcherNode.d.ts +10 -0
  91. package/lib/typescript/core/StretcherNode.d.ts.map +1 -0
  92. package/lib/typescript/interfaces.d.ts +6 -3
  93. package/lib/typescript/interfaces.d.ts.map +1 -1
  94. package/lib/typescript/types.d.ts +0 -1
  95. package/lib/typescript/types.d.ts.map +1 -1
  96. package/lib/typescript/web-core/AudioBufferSourceNode.d.ts +0 -3
  97. package/lib/typescript/web-core/AudioBufferSourceNode.d.ts.map +1 -1
  98. package/lib/typescript/web-core/AudioScheduledSourceNode.d.ts +0 -1
  99. package/lib/typescript/web-core/AudioScheduledSourceNode.d.ts.map +1 -1
  100. package/lib/typescript/web-core/StretcherNode.d.ts +0 -3
  101. package/lib/typescript/web-core/StretcherNode.d.ts.map +1 -1
  102. package/package.json +4 -3
  103. package/scripts/setup-custom-wasm.js +104 -0
  104. package/src/api.ts +1 -1
  105. package/src/api.web.ts +0 -1
  106. package/src/core/AudioBufferSourceNode.ts +0 -9
  107. package/src/core/AudioScheduledSourceNode.ts +0 -5
  108. package/src/core/BaseAudioContext.ts +5 -0
  109. package/src/core/StretcherNode.ts +15 -0
  110. package/src/interfaces.ts +6 -3
  111. package/src/types.ts +0 -2
  112. package/src/web-core/AudioBufferSourceNode.tsx +0 -11
  113. package/src/web-core/AudioScheduledSourceNode.tsx +0 -9
  114. package/src/web-core/StretcherNode.tsx +8 -28
  115. package/src/web-core/custom/signalsmithStretch/README.md +1 -1
  116. package/src/web-core/custom/signalsmithStretch/SignalsmithStretch.js +0 -1
  117. package/common/cpp/audioapi/core/types/TimeStretchType.h +0 -7
  118. package/common/cpp/audioapi/dsp/FFT.cpp +0 -41
  119. package/common/cpp/audioapi/dsp/FFT.h +0 -29
  120. package/common/cpp/audioapi/dsp/Windows.cpp +0 -80
  121. package/common/cpp/audioapi/dsp/Windows.h +0 -95
  122. package/scripts/setup-rn-audio-api-web.js +0 -58
  123. /package/{common/cpp/audioapi/libs/pffft → android/src/main/cpp/audioapi/android/libs}/pffft.h +0 -0
  124. /package/common/cpp/audioapi/{utils → core/utils}/AudioArray.h +0 -0
  125. /package/common/cpp/audioapi/{utils → core/utils}/AudioBus.h +0 -0
  126. /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::dsp {
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::dsp
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::dsp {
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] = dsp::linearToDecibels(inputVector[i]);
698
+ outputVector[i] = AudioUtils::linearToDecibels(inputVector[i]);
699
699
  }
700
700
  }
701
- } // namespace audioapi::dsp
701
+ } // namespace audioapi::VectorMath
@@ -32,7 +32,7 @@
32
32
  #include <algorithm>
33
33
  #include <cmath>
34
34
 
35
- namespace audioapi::dsp {
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::dsp
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 <audioapi/libs/signalsmith-stretch/fft.h>
11
- #include <audioapi/dsp/Windows.h>
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
- float kaiserBandwidth = (stopFreq - passFreq)*(n + 1.0/subSampleSteps);
484
- kaiserBandwidth += 1.25f / 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.
485
- double sincScale = audioapi::PI*(passFreq + stopFreq);
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
- audioapi::dsp::Kaiser::withBandwidth(kaiserBandwidth, false).apply(windowedSinc.data(), windowedSinc.size());
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.getSize()*2, 1);
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
- windowedSinc.shrink_to_fit();
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/signalsmith-stretch/perf.h>
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*audioapi::PI*i*f/length;
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*audioapi::PI*f*i/factor;
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*audioapi::PI*(modified ? i + 0.5 : i)/size;
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*audioapi::PI*i/size;
440
+ V rotPhase = -2*M_PI*i/size;
440
441
  modifiedRotations[i] = {std::cos(rotPhase), std::sin(rotPhase)};
441
442
  }
442
443
  }
@@ -1,3 +1,5 @@
1
+ #include <audioapi/libs/dsp/common.h>
2
+
1
3
  #ifndef SIGNALSMITH_DSP_PERF_H
2
4
  #define SIGNALSMITH_DSP_PERF_H
3
5
 
@@ -1,13 +1,12 @@
1
- #include <audioapi/core/Constants.h>
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/signalsmith-stretch/perf.h>
7
- #include <audioapi/libs/signalsmith-stretch/fft.h>
8
- #include <audioapi/libs/signalsmith-stretch/delay.h>
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 * audioapi::PI * x;
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
- audioapi::dsp::Kaiser::withBandwidth(_windowSize/_interval, true).apply(window.data(), _windowSize);
254
+ auto kaiser_ = Kaiser::withBandwidth(_windowSize/double(_interval), true);
255
+ kaiser_.fill(window, _windowSize);
255
256
  } else {
256
- audioapi::dsp::ApproximateConfinedGaussian::withBandwidth(_windowSize/_interval).apply(window.data(), _windowSize);
257
+ using Confined = ::signalsmith::windows::ApproximateConfinedGaussian;
258
+ auto confined = Confined::withBandwidth(_windowSize/double(_interval));
259
+ confined.fill(window, _windowSize);
257
260
  }
258
- audioapi::dsp::WindowFunction::forcePerfectReconstruction(window.data(), _windowSize, _interval);
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
@@ -1,9 +1,10 @@
1
1
  #ifndef SIGNALSMITH_STRETCH_H
2
2
  #define SIGNALSMITH_STRETCH_H
3
3
 
4
- #include <audioapi/libs/signalsmith-stretch/spectral.h>
5
- #include <audioapi/libs/signalsmith-stretch/delay.h>
6
- #include <audioapi/libs/signalsmith-stretch/perf.h>
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/miniaudio.h>
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