react-native-audio-api 0.4.12-beta.1 → 0.4.12-beta.2

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 (114) hide show
  1. package/RNAudioAPI.podspec +11 -1
  2. package/android/CMakeLists.txt +9 -48
  3. package/android/src/main/cpp/audioapi/CMakeLists.txt +44 -0
  4. package/android/src/main/cpp/{AudioAPIModule.cpp → audioapi/android/AudioAPIModule.cpp} +1 -4
  5. package/android/src/main/cpp/{AudioAPIModule.h → audioapi/android/AudioAPIModule.h} +2 -1
  6. package/android/src/main/cpp/{OnLoad.cpp → audioapi/android/OnLoad.cpp} +2 -1
  7. package/android/src/main/cpp/{core → audioapi/android/core}/AudioDecoder.cpp +5 -5
  8. package/android/src/main/cpp/{core → audioapi/android/core}/AudioPlayer.cpp +5 -7
  9. package/android/src/main/cpp/{core → audioapi/android/core}/AudioPlayer.h +1 -0
  10. package/android/src/main/cpp/{libs → audioapi/android/libs}/pffft.c +2 -2
  11. package/android/src/main/java/com/swmansion/audioapi/AudioAPIPackage.kt +1 -0
  12. package/common/cpp/{installer → audioapi}/AudioAPIModuleInstaller.h +5 -3
  13. package/common/cpp/{HostObjects → audioapi/HostObjects}/AnalyserNodeHostObject.h +3 -3
  14. package/common/cpp/{HostObjects → audioapi/HostObjects}/AudioBufferHostObject.h +3 -3
  15. package/common/cpp/{HostObjects → audioapi/HostObjects}/AudioBufferSourceNodeHostObject.h +5 -5
  16. package/common/cpp/{HostObjects → audioapi/HostObjects}/AudioContextHostObject.h +3 -3
  17. package/common/cpp/{HostObjects → audioapi/HostObjects}/AudioDestinationNodeHostObject.h +3 -3
  18. package/common/cpp/{HostObjects → audioapi/HostObjects}/AudioNodeHostObject.h +3 -3
  19. package/common/cpp/{HostObjects → audioapi/HostObjects}/AudioParamHostObject.h +3 -3
  20. package/common/cpp/{HostObjects → audioapi/HostObjects}/AudioScheduledSourceNodeHostObject.h +3 -3
  21. package/common/cpp/{HostObjects → audioapi/HostObjects}/BaseAudioContextHostObject.h +14 -15
  22. package/common/cpp/{HostObjects → audioapi/HostObjects}/BiquadFilterNodeHostObject.h +4 -4
  23. package/common/cpp/{HostObjects → audioapi/HostObjects}/GainNodeHostObject.h +4 -4
  24. package/common/cpp/{HostObjects → audioapi/HostObjects}/OscillatorNodeHostObject.h +5 -5
  25. package/common/cpp/{HostObjects → audioapi/HostObjects}/PeriodicWaveHostObject.h +2 -2
  26. package/common/cpp/{HostObjects → audioapi/HostObjects}/StereoPannerNodeHostObject.h +4 -4
  27. package/common/cpp/audioapi/HostObjects/StretcherNodeHostObject.h +35 -0
  28. package/common/cpp/{core → audioapi/core}/AudioContext.cpp +6 -6
  29. package/common/cpp/{core → audioapi/core}/AudioContext.h +2 -2
  30. package/common/cpp/{core → audioapi/core}/AudioNode.cpp +5 -7
  31. package/common/cpp/{core → audioapi/core}/AudioNode.h +5 -4
  32. package/common/cpp/{core → audioapi/core}/AudioParam.cpp +3 -4
  33. package/common/cpp/{core → audioapi/core}/AudioParam.h +3 -3
  34. package/common/cpp/{core → audioapi/core}/BaseAudioContext.cpp +14 -17
  35. package/common/cpp/{core → audioapi/core}/BaseAudioContext.h +4 -3
  36. package/common/cpp/{core → audioapi/core/analysis}/AnalyserNode.cpp +6 -10
  37. package/common/cpp/{core → audioapi/core/analysis}/AnalyserNode.h +4 -3
  38. package/common/cpp/{core → audioapi/core/destinations}/AudioDestinationNode.cpp +5 -5
  39. package/common/cpp/{core → audioapi/core/destinations}/AudioDestinationNode.h +2 -2
  40. package/common/cpp/{core → audioapi/core/effects}/BiquadFilterNode.cpp +4 -4
  41. package/common/cpp/{core → audioapi/core/effects}/BiquadFilterNode.h +4 -4
  42. package/common/cpp/{core → audioapi/core/effects}/GainNode.cpp +4 -4
  43. package/common/cpp/{core → audioapi/core/effects}/GainNode.h +3 -3
  44. package/common/cpp/{core → audioapi/core/effects}/PeriodicWave.cpp +4 -2
  45. package/common/cpp/{core → audioapi/core/effects}/PeriodicWave.h +2 -4
  46. package/common/cpp/{core → audioapi/core/effects}/StereoPannerNode.cpp +5 -7
  47. package/common/cpp/{core → audioapi/core/effects}/StereoPannerNode.h +4 -3
  48. package/common/cpp/{core → audioapi/core/effects}/StretcherNode.cpp +4 -6
  49. package/common/cpp/audioapi/core/effects/StretcherNode.h +35 -0
  50. package/common/cpp/{core → audioapi/core/sources}/AudioBuffer.cpp +3 -3
  51. package/common/cpp/{core → audioapi/core/sources}/AudioBufferSourceNode.cpp +8 -11
  52. package/common/cpp/{core → audioapi/core/sources}/AudioBufferSourceNode.h +5 -3
  53. package/common/cpp/{core → audioapi/core/sources}/AudioScheduledSourceNode.cpp +6 -8
  54. package/common/cpp/{core → audioapi/core/sources}/AudioScheduledSourceNode.h +3 -2
  55. package/common/cpp/{core → audioapi/core/sources}/OscillatorNode.cpp +4 -4
  56. package/common/cpp/{core → audioapi/core/sources}/OscillatorNode.h +5 -5
  57. package/common/cpp/{core → audioapi/core/utils}/AudioArray.cpp +2 -4
  58. package/common/cpp/{core → audioapi/core/utils}/AudioBus.cpp +4 -7
  59. package/common/cpp/{core → audioapi/core/utils}/AudioBus.h +2 -2
  60. package/common/cpp/{core → audioapi/core/utils}/AudioNodeManager.cpp +3 -4
  61. package/common/cpp/{core → audioapi/core/utils}/ParamChangeEvent.cpp +1 -3
  62. package/common/cpp/{core → audioapi/core/utils}/ParamChangeEvent.h +3 -1
  63. package/common/cpp/{utils → audioapi/dsp}/AudioUtils.cpp +1 -1
  64. package/common/cpp/{utils → audioapi/dsp}/FFTFrame.cpp +1 -10
  65. package/common/cpp/{utils → audioapi/dsp}/FFTFrame.h +4 -3
  66. package/common/cpp/{utils → audioapi/dsp}/VectorMath.cpp +2 -5
  67. package/common/cpp/{utils → audioapi/dsp}/VectorMath.h +2 -0
  68. package/common/cpp/{jsi → audioapi/jsi}/JsiHostObject.cpp +1 -1
  69. package/common/cpp/{jsi → audioapi/jsi}/JsiHostObject.h +2 -2
  70. package/common/cpp/{jsi → audioapi/jsi}/JsiPromise.cpp +2 -6
  71. package/common/cpp/{jsi → audioapi/jsi}/RuntimeAwareCache.h +2 -3
  72. package/common/cpp/{jsi → audioapi/jsi}/RuntimeLifecycleMonitor.cpp +1 -5
  73. package/common/cpp/{jsi → audioapi/jsi}/RuntimeLifecycleMonitor.h +3 -0
  74. package/common/cpp/{libs → audioapi/libs}/dsp/delay.h +35 -35
  75. package/common/cpp/{libs → audioapi/libs}/dsp/fft.h +21 -21
  76. package/common/cpp/{libs → audioapi/libs}/dsp/perf.h +3 -3
  77. package/common/cpp/{libs → audioapi/libs}/dsp/spectral.h +39 -39
  78. package/common/cpp/{libs → audioapi/libs}/dsp/windows.h +11 -11
  79. package/common/cpp/{libs → audioapi/libs}/signalsmith-stretch.h +30 -30
  80. package/ios/{AudioAPIModule.mm → audioapi/ios/AudioAPIModule.mm} +1 -1
  81. package/ios/{core → audioapi/ios/core}/AudioDecoder.mm +4 -4
  82. package/ios/{core → audioapi/ios/core}/AudioPlayer.m +1 -1
  83. package/ios/{core → audioapi/ios/core}/IOSAudioPlayer.mm +4 -4
  84. package/package.json +6 -6
  85. package/common/cpp/HostObjects/StretcherNodeHostObject.h +0 -35
  86. package/common/cpp/core/StretcherNode.h +0 -63
  87. package/common/cpp/libs/dsp/LICENSE.txt +0 -21
  88. package/common/cpp/libs/dsp/README.md +0 -40
  89. package/common/cpp/libs/dsp/curves.h +0 -371
  90. package/common/cpp/libs/dsp/envelopes.h +0 -523
  91. package/common/cpp/libs/dsp/filters.h +0 -436
  92. package/common/cpp/libs/dsp/mix.h +0 -218
  93. package/common/cpp/libs/dsp/rates.h +0 -184
  94. package/common/cpp/types/TimeStretchType.h +0 -6
  95. /package/android/src/main/cpp/{libs → audioapi/android/libs}/pffft.h +0 -0
  96. /package/common/cpp/{core → audioapi/core}/Constants.h +0 -0
  97. /package/common/cpp/{core → audioapi/core/sources}/AudioBuffer.h +0 -0
  98. /package/common/cpp/{types → audioapi/core/types}/BiquadFilterType.h +0 -0
  99. /package/common/cpp/{types → audioapi/core/types}/ChannelCountMode.h +0 -0
  100. /package/common/cpp/{types → audioapi/core/types}/ChannelInterpretation.h +0 -0
  101. /package/common/cpp/{types → audioapi/core/types}/ContextState.h +0 -0
  102. /package/common/cpp/{types → audioapi/core/types}/OscillatorType.h +0 -0
  103. /package/common/cpp/{types → audioapi/core/types}/ParamChangeEventType.h +0 -0
  104. /package/common/cpp/{core → audioapi/core/utils}/AudioArray.h +0 -0
  105. /package/common/cpp/{core → audioapi/core/utils}/AudioDecoder.h +0 -0
  106. /package/common/cpp/{core → audioapi/core/utils}/AudioNodeManager.h +0 -0
  107. /package/common/cpp/{utils → audioapi/core/utils}/Locker.h +0 -0
  108. /package/common/cpp/{utils → audioapi/dsp}/AudioUtils.h +0 -0
  109. /package/common/cpp/{jsi → audioapi/jsi}/JsiPromise.h +0 -0
  110. /package/common/cpp/{libs → audioapi/libs}/dsp/common.h +0 -0
  111. /package/common/cpp/{libs → audioapi/libs}/miniaudio.h +0 -0
  112. /package/ios/{AudioAPIModule.h → audioapi/ios/AudioAPIModule.h} +0 -0
  113. /package/ios/{core → audioapi/ios/core}/AudioPlayer.h +0 -0
  114. /package/ios/{core → audioapi/ios/core}/IOSAudioPlayer.h +0 -0
@@ -1,436 +0,0 @@
1
- #include "./common.h"
2
-
3
- #ifndef SIGNALSMITH_DSP_FILTERS_H
4
- #define SIGNALSMITH_DSP_FILTERS_H
5
-
6
- #include "./perf.h"
7
-
8
- #include <cmath>
9
- #include <complex>
10
-
11
- namespace signalsmith {
12
- namespace filters {
13
- /** @defgroup Filters Basic filters
14
- @brief Classes for some common filter types
15
-
16
- @{
17
- @file
18
- */
19
-
20
- /** Filter design methods.
21
- These differ mostly in how they handle frequency-warping near Nyquist:
22
- \diagram{filters-lowpass.svg}
23
- \diagram{filters-highpass.svg}
24
- \diagram{filters-peak.svg}
25
- \diagram{filters-bandpass.svg}
26
- \diagram{filters-notch.svg}
27
- \diagram{filters-high-shelf.svg}
28
- \diagram{filters-low-shelf.svg}
29
- \diagram{filters-allpass.svg}
30
- */
31
- enum class BiquadDesign {
32
- bilinear, ///< Bilinear transform, adjusting for centre frequency but not bandwidth
33
- cookbook, ///< RBJ's "Audio EQ Cookbook". Based on `bilinear`, adjusting bandwidth (for peak/notch/bandpass) to preserve the ratio between upper/lower boundaries. This performs oddly near Nyquist.
34
- oneSided, ///< Based on `bilinear`, adjusting bandwidth to preserve the lower boundary (leaving the upper one loose).
35
- vicanek ///< From Martin Vicanek's [Matched Second Order Digital Filters](https://vicanek.de/articles/BiquadFits.pdf). Falls back to `oneSided` for shelf and allpass filters. This takes the poles from the impulse-invariant approach, and then picks the zeros to create a better match. This means that Nyquist is not 0dB for peak/notch (or -Inf for lowpass), but it is a decent match to the analogue prototype.
36
- };
37
-
38
- /** A standard biquad.
39
-
40
- This is not guaranteed to be stable if modulated at audio rate.
41
-
42
- The default highpass/lowpass bandwidth (`defaultBandwidth`) produces a Butterworth filter when bandwidth-compensation is disabled.
43
-
44
- Bandwidth compensation defaults to `BiquadDesign::oneSided` (or `BiquadDesign::cookbook` if `cookbookBandwidth` is enabled) for all filter types aside from highpass/lowpass (which use `BiquadDesign::bilinear`).*/
45
- template<typename Sample, bool cookbookBandwidth=false>
46
- class BiquadStatic {
47
- static constexpr BiquadDesign bwDesign = cookbookBandwidth ? BiquadDesign::cookbook : BiquadDesign::oneSided;
48
- Sample a1 = 0, a2 = 0, b0 = 1, b1 = 0, b2 = 0;
49
- Sample x1 = 0, x2 = 0, y1 = 0, y2 = 0;
50
-
51
- enum class Type {highpass, lowpass, highShelf, lowShelf, bandpass, notch, peak, allpass};
52
-
53
- struct FreqSpec {
54
- double scaledFreq;
55
- double w0, sinW0, cosW0;
56
- double inv2Q;
57
-
58
- FreqSpec(double freq, BiquadDesign design) {
59
- scaledFreq = std::max(1e-6, std::min(0.4999, freq));
60
- if (design == BiquadDesign::cookbook) {
61
- scaledFreq = std::min(0.45, scaledFreq);
62
- }
63
- w0 = 2*M_PI*scaledFreq;
64
- cosW0 = std::cos(w0);
65
- sinW0 = std::sin(w0);
66
- }
67
-
68
- void oneSidedCompQ() {
69
- // Ratio between our (digital) lower boundary f1 and centre f0
70
- double f1Factor = std::sqrt(inv2Q*inv2Q + 1) - inv2Q;
71
- // Bilinear means discrete-time freq f = continuous-time freq tan(pi*xf/pi)
72
- double ctF1 = std::tan(M_PI*scaledFreq*f1Factor), invCtF0 = (1 + cosW0)/sinW0;
73
- double ctF1Factor = ctF1*invCtF0;
74
- inv2Q = 0.5/ctF1Factor - 0.5*ctF1Factor;
75
- }
76
- };
77
- SIGNALSMITH_INLINE static FreqSpec octaveSpec(double scaledFreq, double octaves, BiquadDesign design) {
78
- FreqSpec spec(scaledFreq, design);
79
-
80
- if (design == BiquadDesign::cookbook) {
81
- // Approximately preserves bandwidth between halfway points
82
- octaves *= spec.w0/spec.sinW0;
83
- }
84
- spec.inv2Q = std::sinh(std::log(2)*0.5*octaves); // 1/(2Q)
85
- if (design == BiquadDesign::oneSided) spec.oneSidedCompQ();
86
- return spec;
87
- }
88
- SIGNALSMITH_INLINE static FreqSpec qSpec(double scaledFreq, double q, BiquadDesign design) {
89
- FreqSpec spec(scaledFreq, design);
90
-
91
- spec.inv2Q = 0.5/q;
92
- if (design == BiquadDesign::oneSided) spec.oneSidedCompQ();
93
- return spec;
94
- }
95
-
96
- SIGNALSMITH_INLINE double dbToSqrtGain(double db) {
97
- return std::pow(10, db*0.025);
98
- }
99
-
100
- SIGNALSMITH_INLINE BiquadStatic & configure(Type type, FreqSpec calc, double sqrtGain, BiquadDesign design) {
101
- double w0 = calc.w0;
102
-
103
- if (design == BiquadDesign::vicanek) {
104
- if (type == Type::notch) { // Heuristic for notches near Nyquist
105
- calc.inv2Q *= (1 - calc.scaledFreq*0.5);
106
- }
107
- double Q = (type == Type::peak ? 0.5*sqrtGain : 0.5)/calc.inv2Q;
108
- double q = (type == Type::peak ? 1/sqrtGain : 1)*calc.inv2Q;
109
- double expmqw = std::exp(-q*w0);
110
- double da1, da2;
111
- if (q <= 1) {
112
- a1 = da1 = -2*expmqw*std::cos(std::sqrt(1 - q*q)*w0);
113
- } else {
114
- a1 = da1 = -2*expmqw*std::cosh(std::sqrt(q*q - 1)*w0);
115
- }
116
- a2 = da2 = expmqw*expmqw;
117
- double sinpd2 = std::sin(w0/2);
118
- double p0 = 1 - sinpd2*sinpd2, p1 = sinpd2*sinpd2, p2 = 4*p0*p1;
119
- double A0 = 1 + da1 + da2, A1 = 1 - da1 + da2, A2 = -4*da2;
120
- A0 *= A0;
121
- A1 *= A1;
122
- if (type == Type::lowpass) {
123
- double R1 = (A0*p0 + A1*p1 + A2*p2)*Q*Q;
124
- double B0 = A0, B1 = (R1 - B0*p0)/p1;
125
- b0 = 0.5*(std::sqrt(B0) + std::sqrt(std::max(0.0, B1)));
126
- b1 = std::sqrt(B0) - b0;
127
- b2 = 0;
128
- return *this;
129
- } else if (type == Type::highpass) {
130
- b2 = b0 = std::sqrt(A0*p0 + A1*p1 + A2*p2)*Q/(4*p1);
131
- b1 = -2*b0;
132
- return *this;
133
- } else if (type == Type::bandpass) {
134
- double R1 = A0*p0 + A1*p1 + A2*p2;
135
- double R2 = -A0 + A1 + 4*(p0 - p1)*A2;
136
- double B2 = (R1 - R2*p1)/(4*p1*p1);
137
- double B1 = R2 + 4*(p1 - p0)*B2;
138
- b1 = -0.5*std::sqrt(std::max(0.0, B1));
139
- b0 = 0.5*(std::sqrt(std::max(0.0, B2 + 0.25*B1)) - b1);
140
- b2 = -b0 - b1;
141
- return *this;
142
- } else if (type == Type::notch) {
143
- // The Vicanek paper doesn't cover notches (band-stop), but we know where the zeros should be:
144
- b0 = 1;
145
- double db1 = -2*std::cos(w0); // might be higher precision
146
- b1 = db1;
147
- b2 = 1;
148
- // Scale so that B0 == A0 to get 0dB at f=0
149
- double scale = std::sqrt(A0)/(b0 + db1 + b2);
150
- b0 *= scale;
151
- b1 *= scale;
152
- b2 *= scale;
153
- return *this;
154
- } else if (type == Type::peak) {
155
- double G2 = (sqrtGain*sqrtGain)*(sqrtGain*sqrtGain);
156
- double R1 = (A0*p0 + A1*p1 + A2*p2)*G2;
157
- double R2 = (-A0 + A1 + 4*(p0 - p1)*A2)*G2;
158
- double B0 = A0;
159
- double B2 = (R1 - R2*p1 - B0)/(4*p1*p1);
160
- double B1 = R2 + B0 + 4*(p1 - p0)*B2;
161
- double W = 0.5*(std::sqrt(B0) + std::sqrt(std::max(0.0, B1)));
162
- b0 = 0.5*(W + std::sqrt(std::max(0.0, W*W + B2)));
163
- b1 = 0.5*(std::sqrt(B0) - std::sqrt(std::max(0.0, B1)));
164
- b2 = -B2/(4*b0);
165
- return *this;
166
- }
167
- // All others fall back to `oneSided`
168
- design = BiquadDesign::oneSided;
169
- calc.oneSidedCompQ();
170
- }
171
-
172
- double alpha = calc.sinW0*calc.inv2Q;
173
- double A = sqrtGain, sqrtA2alpha = 2*std::sqrt(A)*alpha;
174
-
175
- double a0;
176
- if (type == Type::highpass) {
177
- b1 = -1 - calc.cosW0;
178
- b0 = b2 = (1 + calc.cosW0)*0.5;
179
- a0 = 1 + alpha;
180
- a1 = -2*calc.cosW0;
181
- a2 = 1 - alpha;
182
- } else if (type == Type::lowpass) {
183
- b1 = 1 - calc.cosW0;
184
- b0 = b2 = b1*0.5;
185
- a0 = 1 + alpha;
186
- a1 = -2*calc.cosW0;
187
- a2 = 1 - alpha;
188
- } else if (type == Type::highShelf) {
189
- b0 = A*((A+1)+(A-1)*calc.cosW0+sqrtA2alpha);
190
- b2 = A*((A+1)+(A-1)*calc.cosW0-sqrtA2alpha);
191
- b1 = -2*A*((A-1)+(A+1)*calc.cosW0);
192
- a0 = (A+1)-(A-1)*calc.cosW0+sqrtA2alpha;
193
- a2 = (A+1)-(A-1)*calc.cosW0-sqrtA2alpha;
194
- a1 = 2*((A-1)-(A+1)*calc.cosW0);
195
- } else if (type == Type::lowShelf) {
196
- b0 = A*((A+1)-(A-1)*calc.cosW0+sqrtA2alpha);
197
- b2 = A*((A+1)-(A-1)*calc.cosW0-sqrtA2alpha);
198
- b1 = 2*A*((A-1)-(A+1)*calc.cosW0);
199
- a0 = (A+1)+(A-1)*calc.cosW0+sqrtA2alpha;
200
- a2 = (A+1)+(A-1)*calc.cosW0-sqrtA2alpha;
201
- a1 = -2*((A-1)+(A+1)*calc.cosW0);
202
- } else if (type == Type::bandpass) {
203
- b0 = alpha;
204
- b1 = 0;
205
- b2 = -alpha;
206
- a0 = 1 + alpha;
207
- a1 = -2*calc.cosW0;
208
- a2 = 1 - alpha;
209
- } else if (type == Type::notch) {
210
- b0 = 1;
211
- b1 = -2*calc.cosW0;
212
- b2 = 1;
213
- a0 = 1 + alpha;
214
- a1 = b1;
215
- a2 = 1 - alpha;
216
- } else if (type == Type::peak) {
217
- b0 = 1 + alpha*A;
218
- b1 = -2*calc.cosW0;
219
- b2 = 1 - alpha*A;
220
- a0 = 1 + alpha/A;
221
- a1 = b1;
222
- a2 = 1 - alpha/A;
223
- } else if (type == Type::allpass) {
224
- a0 = b2 = 1 + alpha;
225
- a1 = b1 = -2*calc.cosW0;
226
- a2 = b0 = 1 - alpha;
227
- } else {
228
- // reset to neutral
229
- a1 = a2 = b1 = b2 = 0;
230
- a0 = b0 = 1;
231
- }
232
- double invA0 = 1/a0;
233
- b0 *= invA0;
234
- b1 *= invA0;
235
- b2 *= invA0;
236
- a1 *= invA0;
237
- a2 *= invA0;
238
- return *this;
239
- }
240
- public:
241
- static constexpr double defaultQ = 0.7071067811865476; // sqrt(0.5)
242
- static constexpr double defaultBandwidth = 1.8999686269529916; // equivalent to above Q
243
-
244
- Sample operator ()(Sample x0) {
245
- Sample y0 = x0*b0 + x1*b1 + x2*b2 - y1*a1 - y2*a2;
246
- y2 = y1;
247
- y1 = y0;
248
- x2 = x1;
249
- x1 = x0;
250
- return y0;
251
- }
252
-
253
- void reset() {
254
- x1 = x2 = y1 = y2 = 0;
255
- }
256
-
257
- std::complex<Sample> response(Sample scaledFreq) const {
258
- Sample w = scaledFreq*Sample(2*M_PI);
259
- std::complex<Sample> invZ = {std::cos(w), -std::sin(w)}, invZ2 = invZ*invZ;
260
- return (b0 + invZ*b1 + invZ2*b2)/(Sample(1) + invZ*a1 + invZ2*a2);
261
- }
262
- Sample responseDb(Sample scaledFreq) const {
263
- Sample w = scaledFreq*Sample(2*M_PI);
264
- std::complex<Sample> invZ = {std::cos(w), -std::sin(w)}, invZ2 = invZ*invZ;
265
- Sample energy = std::norm(b0 + invZ*b1 + invZ2*b2)/std::norm(Sample(1) + invZ*a1 + invZ2*a2);
266
- return 10*std::log10(energy);
267
- }
268
-
269
- /// @name Lowpass
270
- /// @{
271
- BiquadStatic & lowpass(double scaledFreq, double octaves=defaultBandwidth, BiquadDesign design=BiquadDesign::bilinear) {
272
- return configure(Type::lowpass, octaveSpec(scaledFreq, octaves, design), 0, design);
273
- }
274
- BiquadStatic & lowpassQ(double scaledFreq, double q, BiquadDesign design=BiquadDesign::bilinear) {
275
- return configure(Type::lowpass, qSpec(scaledFreq, q, design), 0, design);
276
- }
277
- /// @deprecated use `BiquadDesign` instead
278
- void lowpass(double scaledFreq, double octaves, bool correctBandwidth) {
279
- lowpass(scaledFreq, octaves, correctBandwidth ? bwDesign : BiquadDesign::bilinear);
280
- }
281
- /// @deprecated By the time you care about `design`, you should care about the bandwidth
282
- BiquadStatic & lowpass(double scaledFreq, BiquadDesign design) {
283
- return lowpass(scaledFreq, defaultBandwidth, design);
284
- }
285
- /// @}
286
-
287
- /// @name Highpass
288
- /// @{
289
- BiquadStatic & highpass(double scaledFreq, double octaves=defaultBandwidth, BiquadDesign design=BiquadDesign::bilinear) {
290
- return configure(Type::highpass, octaveSpec(scaledFreq, octaves, design), 0, design);
291
- }
292
- BiquadStatic & highpassQ(double scaledFreq, double q, BiquadDesign design=BiquadDesign::bilinear) {
293
- return configure(Type::highpass, qSpec(scaledFreq, q, design), 0, design);
294
- }
295
- /// @deprecated use `BiquadDesign` instead
296
- void highpass(double scaledFreq, double octaves, bool correctBandwidth) {
297
- highpass(scaledFreq, octaves, correctBandwidth ? bwDesign : BiquadDesign::bilinear);
298
- }
299
- /// @deprecated By the time you care about `design`, you should care about the bandwidth
300
- BiquadStatic & highpass(double scaledFreq, BiquadDesign design) {
301
- return highpass(scaledFreq, defaultBandwidth, design);
302
- }
303
- /// @}
304
-
305
- /// @name Bandpass
306
- /// @{
307
- BiquadStatic & bandpass(double scaledFreq, double octaves=defaultBandwidth, BiquadDesign design=bwDesign) {
308
- return configure(Type::bandpass, octaveSpec(scaledFreq, octaves, design), 0, design);
309
- }
310
- BiquadStatic & bandpassQ(double scaledFreq, double q, BiquadDesign design=bwDesign) {
311
- return configure(Type::bandpass, qSpec(scaledFreq, q, design), 0, design);
312
- }
313
- /// @deprecated use `BiquadDesign` instead
314
- void bandpass(double scaledFreq, double octaves, bool correctBandwidth) {
315
- bandpass(scaledFreq, octaves, correctBandwidth ? bwDesign : BiquadDesign::bilinear);
316
- }
317
- /// @deprecated By the time you care about `design`, you should care about the bandwidth
318
- BiquadStatic & bandpass(double scaledFreq, BiquadDesign design) {
319
- return bandpass(scaledFreq, defaultBandwidth, design);
320
- }
321
- /// @}
322
-
323
- /// @name Notch
324
- /// @{
325
- BiquadStatic & notch(double scaledFreq, double octaves=defaultBandwidth, BiquadDesign design=bwDesign) {
326
- return configure(Type::notch, octaveSpec(scaledFreq, octaves, design), 0, design);
327
- }
328
- BiquadStatic & notchQ(double scaledFreq, double q, BiquadDesign design=bwDesign) {
329
- return configure(Type::notch, qSpec(scaledFreq, q, design), 0, design);
330
- }
331
- /// @deprecated use `BiquadDesign` instead
332
- void notch(double scaledFreq, double octaves, bool correctBandwidth) {
333
- notch(scaledFreq, octaves, correctBandwidth ? bwDesign : BiquadDesign::bilinear);
334
- }
335
- /// @deprecated By the time you care about `design`, you should care about the bandwidth
336
- BiquadStatic & notch(double scaledFreq, BiquadDesign design) {
337
- return notch(scaledFreq, defaultBandwidth, design);
338
- }
339
- /// @deprecated alias for `.notch()`
340
- void bandStop(double scaledFreq, double octaves=1, bool correctBandwidth=true) {
341
- notch(scaledFreq, octaves, correctBandwidth ? bwDesign : BiquadDesign::bilinear);
342
- }
343
- /// @}
344
-
345
- /// @name Peak
346
- /// @{
347
- BiquadStatic & peak(double scaledFreq, double gain, double octaves=1, BiquadDesign design=bwDesign) {
348
- return configure(Type::peak, octaveSpec(scaledFreq, octaves, design), std::sqrt(gain), design);
349
- }
350
- BiquadStatic & peakDb(double scaledFreq, double db, double octaves=1, BiquadDesign design=bwDesign) {
351
- return configure(Type::peak, octaveSpec(scaledFreq, octaves, design), dbToSqrtGain(db), design);
352
- }
353
- BiquadStatic & peakQ(double scaledFreq, double gain, double q, BiquadDesign design=bwDesign) {
354
- return configure(Type::peak, qSpec(scaledFreq, q, design), std::sqrt(gain), design);
355
- }
356
- BiquadStatic & peakDbQ(double scaledFreq, double db, double q, BiquadDesign design=bwDesign) {
357
- return configure(Type::peak, qSpec(scaledFreq, q, design), dbToSqrtGain(db), design);
358
- }
359
- /// @deprecated By the time you care about `design`, you should care about the bandwidth
360
- BiquadStatic & peak(double scaledFreq, double gain, BiquadDesign design) {
361
- return peak(scaledFreq, gain, 1, design);
362
- }
363
- /// @}
364
-
365
- /// @name High shelf
366
- /// @{
367
- BiquadStatic & highShelf(double scaledFreq, double gain, double octaves=defaultBandwidth, BiquadDesign design=bwDesign) {
368
- return configure(Type::highShelf, octaveSpec(scaledFreq, octaves, design), std::sqrt(gain), design);
369
- }
370
- BiquadStatic & highShelfDb(double scaledFreq, double db, double octaves=defaultBandwidth, BiquadDesign design=bwDesign) {
371
- return configure(Type::highShelf, octaveSpec(scaledFreq, octaves, design), dbToSqrtGain(db), design);
372
- }
373
- BiquadStatic & highShelfQ(double scaledFreq, double gain, double q, BiquadDesign design=bwDesign) {
374
- return configure(Type::highShelf, qSpec(scaledFreq, q, design), std::sqrt(gain), design);
375
- }
376
- BiquadStatic & highShelfDbQ(double scaledFreq, double db, double q, BiquadDesign design=bwDesign) {
377
- return configure(Type::highShelf, qSpec(scaledFreq, q, design), dbToSqrtGain(db), design);
378
- }
379
- /// @deprecated use `BiquadDesign` instead
380
- BiquadStatic & highShelf(double scaledFreq, double gain, double octaves, bool correctBandwidth) {
381
- return highShelf(scaledFreq, gain, octaves, correctBandwidth ? bwDesign : BiquadDesign::bilinear);
382
- }
383
- /// @deprecated use `BiquadDesign` instead
384
- BiquadStatic & highShelfDb(double scaledFreq, double db, double octaves, bool correctBandwidth) {
385
- return highShelfDb(scaledFreq, db, octaves, correctBandwidth ? bwDesign : BiquadDesign::bilinear);
386
- }
387
- /// @}
388
-
389
- /// @name Low shelf
390
- /// @{
391
- BiquadStatic & lowShelf(double scaledFreq, double gain, double octaves=2, BiquadDesign design=bwDesign) {
392
- return configure(Type::lowShelf, octaveSpec(scaledFreq, octaves, design), std::sqrt(gain), design);
393
- }
394
- BiquadStatic & lowShelfDb(double scaledFreq, double db, double octaves=2, BiquadDesign design=bwDesign) {
395
- return configure(Type::lowShelf, octaveSpec(scaledFreq, octaves, design), dbToSqrtGain(db), design);
396
- }
397
- BiquadStatic & lowShelfQ(double scaledFreq, double gain, double q, BiquadDesign design=bwDesign) {
398
- return configure(Type::lowShelf, qSpec(scaledFreq, q, design), std::sqrt(gain), design);
399
- }
400
- BiquadStatic & lowShelfDbQ(double scaledFreq, double db, double q, BiquadDesign design=bwDesign) {
401
- return configure(Type::lowShelf, qSpec(scaledFreq, q, design), dbToSqrtGain(db), design);
402
- }
403
- /// @deprecated use `BiquadDesign` instead
404
- BiquadStatic & lowShelf(double scaledFreq, double gain, double octaves, bool correctBandwidth) {
405
- return lowShelf(scaledFreq, gain, octaves, correctBandwidth ? bwDesign : BiquadDesign::bilinear);
406
- }
407
- /// @deprecated use `BiquadDesign` instead
408
- BiquadStatic & lowShelfDb(double scaledFreq, double db, double octaves, bool correctBandwidth) {
409
- return lowShelfDb(scaledFreq, db, octaves, correctBandwidth ? bwDesign : BiquadDesign::bilinear);
410
- }
411
- /// @}
412
-
413
- /// @name Allpass
414
- /// @{
415
- BiquadStatic & allpass(double scaledFreq, double octaves=1, BiquadDesign design=bwDesign) {
416
- return configure(Type::allpass, octaveSpec(scaledFreq, octaves, design), 0, design);
417
- }
418
- BiquadStatic & allpassQ(double scaledFreq, double q, BiquadDesign design=bwDesign) {
419
- return configure(Type::allpass, qSpec(scaledFreq, q, design), 0, design);
420
- }
421
- /// @}
422
-
423
- BiquadStatic & addGain(double factor) {
424
- b0 *= factor;
425
- b1 *= factor;
426
- b2 *= factor;
427
- return *this;
428
- }
429
- BiquadStatic & addGainDb(double db) {
430
- return addGain(std::pow(10, db*0.05));
431
- }
432
- };
433
-
434
- /** @} */
435
- }} // signalsmith::filters::
436
- #endif // include guard
@@ -1,218 +0,0 @@
1
- #include "./common.h"
2
-
3
- #ifndef SIGNALSMITH_DSP_MULTI_CHANNEL_H
4
- #define SIGNALSMITH_DSP_MULTI_CHANNEL_H
5
-
6
- #include <array>
7
-
8
- namespace signalsmith {
9
- namespace mix {
10
- /** @defgroup Mix Multichannel mixing
11
- @brief Utilities for stereo/multichannel mixing operations
12
-
13
- @{
14
- @file
15
- */
16
-
17
- /** @defgroup Matrices Orthogonal matrices
18
- @brief Some common matrices used for audio
19
- @ingroup Mix
20
- @{ */
21
-
22
- /// @brief Hadamard: high mixing levels, N log(N) operations
23
- template<typename Sample, int size=-1>
24
- class Hadamard {
25
- public:
26
- static_assert(size >= 0, "Size must be positive (or -1 for dynamic)");
27
- /// Applies the matrix, scaled so it's orthogonal
28
- template<class Data>
29
- static void inPlace(Data &&data) {
30
- unscaledInPlace(data);
31
-
32
- Sample factor = scalingFactor();
33
- for (int c = 0; c < size; ++c) {
34
- data[c] *= factor;
35
- }
36
- }
37
-
38
- /// Scaling factor applied to make it orthogonal
39
- static Sample scalingFactor() {
40
- /// TODO: test for C++20, or whatever makes this constexpr. Maybe a `#define` in `common.h`?
41
- return std::sqrt(Sample(1)/(size ? size : 1));
42
- }
43
-
44
- /// Skips the scaling, so it's a matrix full of `1`s
45
- template<class Data, int startIndex=0>
46
- static void unscaledInPlace(Data &&data) {
47
- if (size <= 1) return;
48
- constexpr int hSize = size/2;
49
-
50
- Hadamard<Sample, hSize>::template unscaledInPlace<Data, startIndex>(data);
51
- Hadamard<Sample, hSize>::template unscaledInPlace<Data, startIndex + hSize>(data);
52
-
53
- for (int i = 0; i < hSize; ++i) {
54
- Sample a = data[i + startIndex], b = data[i + startIndex + hSize];
55
- data[i + startIndex] = (a + b);
56
- data[i + startIndex + hSize] = (a - b);
57
- }
58
- }
59
- };
60
- /// @brief Hadamard with dynamic size
61
- template<typename Sample>
62
- class Hadamard<Sample, -1> {
63
- int size;
64
- public:
65
- Hadamard(int size) : size(size) {}
66
-
67
- /// Applies the matrix, scaled so it's orthogonal
68
- template<class Data>
69
- void inPlace(Data &&data) const {
70
- unscaledInPlace(data);
71
-
72
- Sample factor = scalingFactor();
73
- for (int c = 0; c < size; ++c) {
74
- data[c] *= factor;
75
- }
76
- }
77
-
78
- /// Scaling factor applied to make it orthogonal
79
- Sample scalingFactor() const {
80
- return std::sqrt(Sample(1)/(size ? size : 1));
81
- }
82
-
83
- /// Skips the scaling, so it's a matrix full of `1`s
84
- template<class Data>
85
- void unscaledInPlace(Data &&data) const {
86
- int hSize = size/2;
87
- while (hSize > 0) {
88
- for (int startIndex = 0; startIndex < size; startIndex += hSize*2) {
89
- for (int i = startIndex; i < startIndex + hSize; ++i) {
90
- Sample a = data[i], b = data[i + hSize];
91
- data[i] = (a + b);
92
- data[i + hSize] = (a - b);
93
- }
94
- }
95
- hSize /= 2;
96
- }
97
- }
98
- };
99
- /// @brief Householder: moderate mixing, 2N operations
100
- template<typename Sample, int size=-1>
101
- class Householder {
102
- public:
103
- static_assert(size >= 0, "Size must be positive (or -1 for dynamic)");
104
- template<class Data>
105
- static void inPlace(Data &&data) {
106
- if (size < 1) return;
107
- /// TODO: test for C++20, which makes `std::complex::operator/` constexpr
108
- const Sample factor = Sample(-2)/Sample(size ? size : 1);
109
-
110
- Sample sum = data[0];
111
- for (int i = 1; i < size; ++i) {
112
- sum += data[i];
113
- }
114
- sum *= factor;
115
- for (int i = 0; i < size; ++i) {
116
- data[i] += sum;
117
- }
118
- }
119
- /// @deprecated The matrix is already orthogonal, but this is here for compatibility with Hadamard
120
- constexpr static Sample scalingFactor() {
121
- return 1;
122
- }
123
- };
124
- /// @brief Householder with dynamic size
125
- template<typename Sample>
126
- class Householder<Sample, -1> {
127
- int size;
128
- public:
129
- Householder(int size) : size(size) {}
130
-
131
- template<class Data>
132
- void inPlace(Data &&data) const {
133
- if (size < 1) return;
134
- const Sample factor = Sample(-2)/Sample(size ? size : 1);
135
-
136
- Sample sum = data[0];
137
- for (int i = 1; i < size; ++i) {
138
- sum += data[i];
139
- }
140
- sum *= factor;
141
- for (int i = 0; i < size; ++i) {
142
- data[i] += sum;
143
- }
144
- }
145
- /// @deprecated The matrix is already orthogonal, but this is here for compatibility with Hadamard
146
- constexpr static Sample scalingFactor() {
147
- return 1;
148
- }
149
- };
150
- /// @}
151
-
152
- /** @brief Upmix/downmix a stereo signal to an (even) multi-channel signal
153
-
154
- When spreading out, it rotates the input by various amounts (e.g. a four-channel signal would produce `(left, right, mid side)`), such that energy is preserved for each pair.
155
-
156
- When mixing together, it uses the opposite rotations, such that upmix → downmix produces the same stereo signal (when scaled by `.scalingFactor1()`.
157
- */
158
- template<typename Sample, int channels>
159
- class StereoMultiMixer {
160
- static_assert((channels/2)*2 == channels, "StereoMultiMixer must have an even number of channels");
161
- static_assert(channels > 0, "StereoMultiMixer must have a positive number of channels");
162
- static constexpr int hChannels = channels/2;
163
- std::array<Sample, channels> coeffs;
164
- public:
165
- StereoMultiMixer() {
166
- coeffs[0] = 1;
167
- coeffs[1] = 0;
168
- for (int i = 1; i < hChannels; ++i) {
169
- double phase = M_PI*i/channels;
170
- coeffs[2*i] = std::cos(phase);
171
- coeffs[2*i + 1] = std::sin(phase);
172
- }
173
- }
174
-
175
- template<class In, class Out>
176
- void stereoToMulti(In &input, Out &output) const {
177
- output[0] = input[0];
178
- output[1] = input[1];
179
- for (int i = 2; i < channels; i += 2) {
180
- output[i] = input[0]*coeffs[i] + input[1]*coeffs[i + 1];
181
- output[i + 1] = input[1]*coeffs[i] - input[0]*coeffs[i + 1];
182
- }
183
- }
184
- template<class In, class Out>
185
- void multiToStereo(In &input, Out &output) const {
186
- output[0] = input[0];
187
- output[1] = input[1];
188
- for (int i = 2; i < channels; i += 2) {
189
- output[0] += input[i]*coeffs[i] - input[i + 1]*coeffs[i + 1];
190
- output[1] += input[i + 1]*coeffs[i] + input[i]*coeffs[i + 1];
191
- }
192
- }
193
- /// Scaling factor for the downmix, if channels are phase-aligned
194
- static constexpr Sample scalingFactor1() {
195
- return 2/Sample(channels);
196
- }
197
- /// Scaling factor for the downmix, if channels are independent
198
- static Sample scalingFactor2() {
199
- return std::sqrt(scalingFactor1());
200
- }
201
- };
202
-
203
- /// A cheap (polynomial) almost-energy-preserving crossfade
204
- /// Maximum energy error: 1.06%, average 0.64%, curves overshoot by 0.3%
205
- /// See: http://signalsmith-audio.co.uk/writing/2021/cheap-energy-crossfade/
206
- template<typename Sample, typename Result>
207
- void cheapEnergyCrossfade(Sample x, Result &toCoeff, Result &fromCoeff) {
208
- Sample x2 = 1 - x;
209
- // Other powers p can be approximated by: k = -6.0026608 + p*(6.8773512 - 1.5838104*p)
210
- Sample A = x*x2, B = A*(1 + (Sample)1.4186*A);
211
- Sample C = (B + x), D = (B + x2);
212
- toCoeff = C*C;
213
- fromCoeff = D*D;
214
- }
215
-
216
- /** @} */
217
- }} // signalsmith::delay::
218
- #endif // include guard