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

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 +14 -4
  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} +15 -8
  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,63 +0,0 @@
1
- #pragma once
2
-
3
- #include <memory>
4
- #include <string>
5
-
6
- #include "signalsmith-stretch.h"
7
- #include "TimeStretchType.h"
8
- #include "AudioNode.h"
9
- #include "AudioParam.h"
10
-
11
- namespace audioapi {
12
- class AudioBus;
13
-
14
- class StretcherNode : public AudioNode {
15
- public:
16
- explicit StretcherNode(BaseAudioContext *context);
17
-
18
- [[nodiscard]] std::shared_ptr<AudioParam> getRateParam() const;
19
- [[nodiscard]] std::shared_ptr<AudioParam> getSemitonesParam() const;
20
-
21
- protected:
22
- void processNode(const std::shared_ptr<AudioBus>& processingBus, int framesToProcess) override;
23
- std::shared_ptr<AudioBus> processAudio(std::shared_ptr<AudioBus> outputBus, int framesToProcess, bool checkIsAlreadyProcessed) override;
24
-
25
- private:
26
- // k-rate params
27
- std::shared_ptr<AudioParam> rate_;
28
- std::shared_ptr<AudioParam> semitones_;
29
-
30
- std::shared_ptr<signalsmith::stretch::SignalsmithStretch<float>> stretch_;
31
- std::shared_ptr<AudioBus> playbackRateBus_;
32
- int framesNeededToStretch_ = RENDER_QUANTUM_SIZE;
33
-
34
- static TimeStretchType fromString(const std::string &type) {
35
- std::string lowerType = type;
36
- std::transform(
37
- lowerType.begin(), lowerType.end(), lowerType.begin(), ::tolower);
38
-
39
- if (lowerType == "linear")
40
- return TimeStretchType::LINEAR;
41
- if (lowerType == "speech")
42
- return TimeStretchType::SPEECH;
43
- if (lowerType == "music")
44
- return TimeStretchType::MUSIC;
45
-
46
- throw std::invalid_argument("Unknown time stretch type: " + type);
47
- }
48
-
49
- static std::string toString(TimeStretchType type) {
50
- switch (type) {
51
- case TimeStretchType::LINEAR:
52
- return "linear";
53
- case TimeStretchType::SPEECH:
54
- return "speech";
55
- case TimeStretchType::MUSIC:
56
- return "music";
57
- default:
58
- throw std::invalid_argument("Unknown time stretch type");
59
- }
60
- }
61
- };
62
-
63
- } // namespace audioapi
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2021 Geraint Luff / Signalsmith Audio Ltd.
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
@@ -1,40 +0,0 @@
1
- # Signalsmith Audio's DSP Library
2
-
3
- A C++11 header-only library, providing classes/templates for (mostly audio) signal-processing tasks.
4
-
5
- More detail is in the [main project page](https://signalsmith-audio.co.uk/code/dsp/), and the [Doxygen docs](https://signalsmith-audio.co.uk/code/dsp/html/modules.html).
6
-
7
- ## Basic use
8
-
9
- ```
10
- git clone https://signalsmith-audio.co.uk/code/dsp.git
11
- ```
12
-
13
- Just include the header file(s) you need, and start using classes:
14
-
15
- ```cpp
16
- #include "dsp/delay.h"
17
-
18
- using Delay = signalsmith::delay::Delay<float>;
19
- Delay delayLine(1024);
20
- ```
21
-
22
- You can add a compile-time version-check to make sure you have a compatible version of the library:
23
- ```cpp
24
- #include "dsp/envelopes.h"
25
- SIGNALSMITH_DSP_VERSION_CHECK(1, 6, 1)
26
- ```
27
-
28
- ### Development / contributing
29
-
30
- Tests (and source-scripts for the above docs) are available in a separate repo:
31
-
32
- ```
33
- git clone https://signalsmith-audio.co.uk/code/dsp-doc.git
34
- ```
35
-
36
- The goal (where possible) is to measure/test the actual audio characteristics of the tools (e.g. frequency responses and aliasing levels).
37
-
38
- ### License
39
-
40
- This code is [MIT licensed](LICENSE.txt). If you'd prefer something else, get in touch.
@@ -1,371 +0,0 @@
1
- #include "./common.h"
2
-
3
- #ifndef SIGNALSMITH_DSP_CURVES_H
4
- #define SIGNALSMITH_DSP_CURVES_H
5
-
6
- #include <vector>
7
- #include <algorithm> // std::stable_sort
8
-
9
- namespace signalsmith {
10
- namespace curves {
11
- /** @defgroup Curves Curves
12
- @brief User-defined mapping functions
13
-
14
- @{
15
- @file
16
- */
17
-
18
- /// Linear map for real values.
19
- template<typename Sample=double>
20
- class Linear {
21
- Sample a1, a0;
22
- public:
23
- Linear() : Linear(0, 1) {}
24
- Linear(Sample a0, Sample a1) : a1(a1), a0(a0) {}
25
- /// Construct by from/to value pairs
26
- Linear(Sample x0, Sample x1, Sample y0, Sample y1) : a1((x0 == x1) ? 0 : (y1 - y0)/(x1 - x0)), a0(y0 - x0*a1) {}
27
-
28
- Sample operator ()(Sample x) const {
29
- return a0 + x*a1;
30
- }
31
-
32
- Sample dx() const {
33
- return a1;
34
- }
35
-
36
- /// Returns the inverse map (with some numerical error)
37
- Linear inverse() const {
38
- Sample invA1 = 1/a1;
39
- return Linear(-a0*invA1, invA1);
40
- }
41
- };
42
-
43
- /// A real-valued cubic curve. It has a "start" point where accuracy is highest.
44
- template<typename Sample=double>
45
- class Cubic {
46
- Sample xStart, a0, a1, a2, a3;
47
-
48
- // Only use with y0 != y1
49
- static inline Sample gradient(Sample x0, Sample x1, Sample y0, Sample y1) {
50
- return (y1 - y0)/(x1 - x0);
51
- }
52
- // Ensure a gradient produces monotonic segments
53
- static inline void ensureMonotonic(Sample &curveGrad, Sample gradA, Sample gradB) {
54
- if ((gradA <= 0 && gradB >= 0) || (gradA >= 0 && gradB <= 0)) {
55
- curveGrad = 0; // point is a local minimum/maximum
56
- } else {
57
- if (std::abs(curveGrad) > std::abs(gradA*3)) {
58
- curveGrad = gradA*3;
59
- }
60
- if (std::abs(curveGrad) > std::abs(gradB*3)) {
61
- curveGrad = gradB*3;
62
- }
63
- }
64
- }
65
- // When we have duplicate x-values (either side) make up a gradient
66
- static inline void chooseGradient(Sample &curveGrad, Sample grad1, Sample curveGradOther, Sample y0, Sample y1, bool monotonic) {
67
- curveGrad = 2*grad1 - curveGradOther;
68
- if (y0 != y1 && (y1 > y0) != (grad1 >= 0)) { // not duplicate y, but a local min/max
69
- curveGrad = 0;
70
- } else if (monotonic) {
71
- if (grad1 >= 0) {
72
- curveGrad = std::max<Sample>(0, curveGrad);
73
- } else {
74
- curveGrad = std::min<Sample>(0, curveGrad);
75
- }
76
- }
77
- }
78
- public:
79
- Cubic() : Cubic(0, 0, 0, 0, 0) {}
80
- Cubic(Sample xStart, Sample a0, Sample a1, Sample a2, Sample a3) : xStart(xStart), a0(a0), a1(a1), a2(a2), a3(a3) {}
81
-
82
- Sample operator ()(Sample x) const {
83
- x -= xStart;
84
- return a0 + x*(a1 + x*(a2 + x*a3));
85
- }
86
- /// The reference x-value, used as the centre of the cubic expansion
87
- Sample start() const {
88
- return xStart;
89
- }
90
- /// Differentiate
91
- Cubic dx() const {
92
- return {xStart, a1, 2*a2, 3*a3, 0};
93
- }
94
- Sample dx(Sample x) const {
95
- x -= xStart;
96
- return a1 + x*(2*a2 + x*(3*a3));
97
- }
98
-
99
- /// Cubic segment based on start/end values and gradients
100
- static Cubic hermite(Sample x0, Sample x1, Sample y0, Sample y1, Sample g0, Sample g1) {
101
- Sample xScale = 1/(x1 - x0);
102
- return {
103
- x0, y0, g0,
104
- (3*(y1 - y0)*xScale - 2*g0 - g1)*xScale,
105
- (2*(y0 - y1)*xScale + g0 + g1)*(xScale*xScale)
106
- };
107
- }
108
-
109
- /** Cubic segment (valid between `x1` and `x2`), which is smooth when applied to an adjacent set of points.
110
- If `x0 == x1` or `x2 == x3` it will choose a gradient which continues in a quadratic curve, or 0 if the point is a local minimum/maximum.
111
- */
112
- static Cubic smooth(Sample x0, Sample x1, Sample x2, Sample x3, Sample y0, Sample y1, Sample y2, Sample y3, bool monotonic=false) {
113
- if (x1 == x2) return {0, y1, 0, 0, 0}; // zero-width segment, just return constant
114
-
115
- Sample grad1 = gradient(x1, x2, y1, y2);
116
- Sample curveGrad1 = grad1;
117
- bool chooseGrad1 = false;
118
- if (x0 != x1) { // we have a defined x0-x1 gradient
119
- Sample grad0 = gradient(x0, x1, y0, y1);
120
- curveGrad1 = (grad0 + grad1)*Sample(0.5);
121
- if (monotonic) ensureMonotonic(curveGrad1, grad0, grad1);
122
- } else if (y0 != y1 && (y1 > y0) != (grad1 >= 0)) {
123
- curveGrad1 = 0; // set to 0 if it's a min/max
124
- } else {
125
- curveGrad1 = 0;
126
- chooseGrad1 = true;
127
- }
128
- Sample curveGrad2;
129
- if (x2 != x3) { // we have a defined x1-x2 gradient
130
- Sample grad2 = gradient(x2, x3, y2, y3);
131
- curveGrad2 = (grad1 + grad2)*Sample(0.5);
132
- if (monotonic) ensureMonotonic(curveGrad2, grad1, grad2);
133
- } else {
134
- chooseGradient(curveGrad2, grad1, curveGrad1, y2, y3, monotonic);
135
- }
136
- if (chooseGrad1) {
137
- chooseGradient(curveGrad1, grad1, curveGrad2, y0, y1, monotonic);
138
- }
139
- return hermite(x1, x2, y1, y2, curveGrad1, curveGrad2);
140
- }
141
- };
142
-
143
- /** Smooth interpolation (optionally monotonic) between points, using cubic segments.
144
- \diagram{cubic-segments-example.svg,Example curve including a repeated point and an instantaneous jump. The curve is flat beyond the first/last points.}
145
- To produce a sharp corner, use a repeated point. The gradient is flat at the edges, unless you use repeated points at the start/end.*/
146
- template<typename Sample=double>
147
- class CubicSegmentCurve {
148
- struct Point {
149
- Sample x, y;
150
- Sample lineGrad = 0, curveGrad = 0;
151
- bool hasCurveGrad = false;
152
-
153
- Point() : Point(0, 0) {}
154
- Point(Sample x, Sample y) : x(x), y(y) {}
155
-
156
- bool operator <(const Point &other) const {
157
- return x < other.x;
158
- }
159
- };
160
- std::vector<Point> points;
161
- Point first{0, 0}, last{0, 0};
162
-
163
- std::vector<Cubic<Sample>> _segments{1};
164
- // Not public because it's only valid inside the bounds
165
- const Cubic<Sample> & findSegment(Sample x) const {
166
- // Binary search
167
- size_t low = 0, high = _segments.size();
168
- while (true) {
169
- size_t mid = (low + high)/2;
170
- if (low == mid) break;
171
- if (_segments[mid].start() <= x) {
172
- low = mid;
173
- } else {
174
- high = mid;
175
- }
176
- }
177
- return _segments[low];
178
- }
179
- public:
180
- Sample lowGrad = 0;
181
- Sample highGrad = 0;
182
-
183
- /// Clear existing points and segments
184
- void clear() {
185
- points.resize(0);
186
- _segments.resize(0);
187
- first = last = {0, 0};
188
- }
189
-
190
- /// Add a new point, but does not recalculate the segments. `corner` just writes the point twice, for convenience.
191
- CubicSegmentCurve & add(Sample x, Sample y, bool corner=false) {
192
- points.push_back({x, y});
193
- if (corner) points.push_back({x, y});
194
- return *this;
195
- }
196
-
197
- /// Recalculates the segments.
198
- void update(bool monotonic=false, bool extendGrad=true, Sample monotonicFactor=3) {
199
- if (points.empty()) add(0, 0);
200
- std::stable_sort(points.begin(), points.end()); // Ensure ascending order
201
- _segments.resize(0);
202
-
203
- // Calculate the point-to-point gradients
204
- for (size_t i = 1; i < points.size(); ++i) {
205
- auto &prev = points[i - 1];
206
- auto &next = points[i];
207
- if (prev.x != next.x) {
208
- prev.lineGrad = (next.y - prev.y)/(next.x - prev.x);
209
- } else {
210
- prev.lineGrad = 0;
211
- }
212
- }
213
-
214
- for (auto &p : points) p.hasCurveGrad = false;
215
- points[0].curveGrad = lowGrad;
216
- points[0].hasCurveGrad = true;
217
- points.back().curveGrad = highGrad;
218
- points.back().hasCurveGrad = true;
219
-
220
- // Calculate curve gradient where we know it
221
- for (size_t i = 1; i + 1 < points.size(); ++i) {
222
- auto &p0 = points[i - 1];
223
- auto &p1 = points[i];
224
- auto &p2 = points[i + 1];
225
- if (p0.x != p1.x && p1.x != p2.x) {
226
- p1.curveGrad = (p0.lineGrad + p1.lineGrad)*Sample(0.5);
227
- p1.hasCurveGrad = true;
228
- }
229
- }
230
-
231
- for (size_t i = 1; i < points.size(); ++i) {
232
- Point &p1 = points[i - 1];
233
- Point &p2 = points[i];
234
- if (p1.x == p2.x) continue;
235
- if (p1.hasCurveGrad) {
236
- if (!p2.hasCurveGrad) {
237
- p2.curveGrad = 2*p1.lineGrad - p1.curveGrad;
238
- }
239
- } else if (p2.hasCurveGrad) {
240
- p1.curveGrad = 2*p1.lineGrad - p2.curveGrad;
241
- } else {
242
- p1.curveGrad = p2.curveGrad = p1.lineGrad;
243
- }
244
- }
245
-
246
- if (monotonic) {
247
- for (size_t i = 1; i < points.size(); ++i) {
248
- Point &p1 = points[i - 1];
249
- Point &p2 = points[i];
250
- if (p1.x != p2.x) {
251
- if (p1.lineGrad >= 0) {
252
- p1.curveGrad = std::max<Sample>(0, std::min(p1.curveGrad, p1.lineGrad*monotonicFactor));
253
- p2.curveGrad = std::max<Sample>(0, std::min(p2.curveGrad, p1.lineGrad*monotonicFactor));
254
- } else {
255
- p1.curveGrad = std::min<Sample>(0, std::max(p1.curveGrad, p1.lineGrad*monotonicFactor));
256
- p2.curveGrad = std::min<Sample>(0, std::max(p2.curveGrad, p1.lineGrad*monotonicFactor));
257
- }
258
- }
259
- }
260
- }
261
-
262
- for (size_t i = 1; i < points.size(); ++i) {
263
- Point &p1 = points[i - 1];
264
- Point &p2 = points[i];
265
- if (p1.x != p2.x) {
266
- _segments.push_back(Segment::hermite(p1.x, p2.x, p1.y, p2.y, p1.curveGrad, p2.curveGrad));
267
- }
268
- }
269
-
270
- first = points[0];
271
- last = points.back();
272
- if (extendGrad && _segments.size()) {
273
- if (points[0].x != points[1].x || points[0].y == points[1].y) {
274
- lowGrad = _segments[0].dx(first.x);
275
- }
276
- auto &last = points.back(), &last2 = points[points.size() - 1];
277
- if (last.x != last2.x || last.y == last2.y) {
278
- highGrad = _segments.back().dx(last.x);
279
- }
280
- }
281
- }
282
-
283
- /// Reads a value out from the curve.
284
- Sample operator()(Sample x) const {
285
- if (x <= first.x) return first.y + (x - first.x)*lowGrad;
286
- if (x >= last.x) return last.y + (x - last.x)*highGrad;
287
- return findSegment(x)(x);
288
- }
289
-
290
- CubicSegmentCurve dx() const {
291
- CubicSegmentCurve result{*this};
292
- result.first.y = lowGrad;
293
- result.last.y = highGrad;
294
- result.lowGrad = result.highGrad = 0;
295
- for (auto &s : result._segments) {
296
- s = s.dx();
297
- }
298
- return result;
299
- }
300
- Sample dx(Sample x) const {
301
- if (x < first.x) return lowGrad;
302
- if (x >= last.x) return highGrad;
303
- return findSegment(x).dx(x);
304
- }
305
-
306
- using Segment = Cubic<Sample>;
307
- std::vector<Segment> & segments() {
308
- return _segments;
309
- }
310
- const std::vector<Segment> & segments() const {
311
- return _segments;
312
- }
313
- };
314
-
315
- /** A warped-range map, based on 1/x
316
- \diagram{curves-reciprocal-example.svg}*/
317
- template<typename Sample=double>
318
- class Reciprocal {
319
- Sample a, b, c, d; // (a + bx)/(c + dx)
320
- Reciprocal(Sample a, Sample b, Sample c, Sample d) : a(a), b(b), c(c), d(d) {}
321
- public:
322
- /** Decent approximation to the Bark scale
323
-
324
- The Bark index goes from 1-24, but this map is valid from approximately 0.25 - 27.5.
325
- You can get the bandwidth by `barkScale.dx(barkIndex)`.
326
- \diagram{curves-reciprocal-approx-bark.svg}*/
327
- static Reciprocal<Sample> barkScale() {
328
- return {1, 10, 24, 60, 1170, 13500};
329
- }
330
- /// Returns a map from 0-1 to the given (non-negative) Hz range.
331
- static Reciprocal<Sample> barkRange(Sample lowHz, Sample highHz) {
332
- Reciprocal bark = barkScale();
333
- Sample lowBark = bark.inverse(lowHz), highBark = bark.inverse(highHz);
334
- return Reciprocal(lowBark, (lowBark + highBark)/2, highBark).then(bark);
335
- }
336
-
337
- Reciprocal() : Reciprocal(0, 0.5, 1) {}
338
- /// If no x-range given, default to the unit range
339
- Reciprocal(Sample y0, Sample y1, Sample y2) : Reciprocal(0, 0.5, 1, y0, y1, y2) {}
340
- Reciprocal(Sample x0, Sample x1, Sample x2, Sample y0, Sample y1, Sample y2) {
341
- Sample kx = (x1 - x0)/(x2 - x1);
342
- Sample ky = (y1 - y0)/(y2 - y1);
343
- a = (kx*x2)*y0 - (ky*x0)*y2;
344
- b = ky*y2 - kx*y0;
345
- c = kx*x2 - ky*x0;
346
- d = ky - kx;
347
- }
348
-
349
- Sample operator ()(double x) const {
350
- return (a + b*x)/(c + d*x);
351
- }
352
- Reciprocal inverse() const {
353
- return Reciprocal(-a, c, b, -d);
354
- }
355
- Sample inverse(Sample y) const {
356
- return (c*y - a)/(b - d*y);
357
- }
358
- Sample dx(Sample x) const {
359
- Sample l = (c + d*x);
360
- return (b*c - a*d)/(l*l);
361
- }
362
-
363
- /// Combine two `Reciprocal`s together in sequence
364
- Reciprocal then(const Reciprocal &other) const {
365
- return Reciprocal(other.a*c + other.b*a, other.a*d + other.b*b, other.c*c + other.d*a, other.c*d + other.d*b);
366
- }
367
- };
368
-
369
- /** @} */
370
- }} // namespace
371
- #endif // include guard