react-native-audio-api 0.4.12-beta.5 → 0.4.12

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/android/src/main/cpp/audioapi/CMakeLists.txt +2 -3
  2. package/android/src/main/cpp/audioapi/android/core/AudioDecoder.cpp +3 -3
  3. package/android/src/main/cpp/audioapi/android/core/AudioPlayer.cpp +10 -11
  4. package/android/src/main/cpp/audioapi/android/core/AudioPlayer.h +1 -0
  5. package/android/src/main/java/com/swmansion/audioapi/AudioAPIPackage.kt +0 -1
  6. package/common/cpp/audioapi/AudioAPIModuleInstaller.h +1 -3
  7. package/common/cpp/audioapi/HostObjects/AnalyserNodeHostObject.h +24 -16
  8. package/common/cpp/audioapi/HostObjects/AudioBufferHostObject.h +4 -0
  9. package/common/cpp/audioapi/HostObjects/AudioBufferSourceNodeHostObject.h +20 -4
  10. package/common/cpp/audioapi/HostObjects/AudioContextHostObject.h +3 -2
  11. package/common/cpp/audioapi/HostObjects/AudioScheduledSourceNodeHostObject.h +32 -2
  12. package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.h +14 -21
  13. package/common/cpp/audioapi/HostObjects/OscillatorNodeHostObject.h +4 -2
  14. package/common/cpp/audioapi/core/AudioNode.cpp +2 -2
  15. package/common/cpp/audioapi/core/AudioParam.cpp +1 -1
  16. package/common/cpp/audioapi/core/BaseAudioContext.cpp +4 -12
  17. package/common/cpp/audioapi/core/BaseAudioContext.h +2 -4
  18. package/common/cpp/audioapi/core/Constants.h +8 -33
  19. package/common/cpp/audioapi/core/analysis/AnalyserNode.cpp +42 -45
  20. package/common/cpp/audioapi/core/analysis/AnalyserNode.h +8 -6
  21. package/common/cpp/audioapi/core/destinations/AudioDestinationNode.cpp +1 -1
  22. package/common/cpp/audioapi/core/effects/BiquadFilterNode.cpp +12 -8
  23. package/common/cpp/audioapi/core/effects/GainNode.cpp +4 -3
  24. package/common/cpp/audioapi/core/effects/PeriodicWave.cpp +32 -49
  25. package/common/cpp/audioapi/core/effects/PeriodicWave.h +8 -3
  26. package/common/cpp/audioapi/core/effects/StereoPannerNode.cpp +3 -3
  27. package/common/cpp/audioapi/core/sources/AudioBuffer.cpp +9 -2
  28. package/common/cpp/audioapi/core/sources/AudioBuffer.h +5 -2
  29. package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp +72 -35
  30. package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.h +41 -8
  31. package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp +18 -6
  32. package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h +7 -0
  33. package/common/cpp/audioapi/core/sources/OscillatorNode.cpp +12 -3
  34. package/common/cpp/audioapi/core/sources/OscillatorNode.h +1 -0
  35. package/common/cpp/audioapi/core/types/TimeStretchType.h +7 -0
  36. package/common/cpp/audioapi/dsp/AudioUtils.cpp +2 -2
  37. package/common/cpp/audioapi/dsp/AudioUtils.h +2 -2
  38. package/common/cpp/audioapi/dsp/FFT.cpp +41 -0
  39. package/common/cpp/audioapi/dsp/FFT.h +29 -0
  40. package/common/cpp/audioapi/dsp/VectorMath.cpp +3 -3
  41. package/common/cpp/audioapi/dsp/VectorMath.h +2 -2
  42. package/common/cpp/audioapi/dsp/Windows.cpp +80 -0
  43. package/common/cpp/audioapi/dsp/Windows.h +95 -0
  44. package/{android/src/main/cpp/audioapi/android/libs → common/cpp/audioapi/libs/pffft}/pffft.c +1 -1
  45. package/common/cpp/audioapi/libs/{dsp → signalsmith-stretch}/delay.h +9 -11
  46. package/common/cpp/audioapi/libs/{dsp → signalsmith-stretch}/fft.h +6 -7
  47. package/common/cpp/audioapi/libs/{dsp → signalsmith-stretch}/perf.h +0 -2
  48. package/common/cpp/audioapi/libs/{signalsmith-stretch.h → signalsmith-stretch/signalsmith-stretch.h} +3 -4
  49. package/common/cpp/audioapi/libs/{dsp → signalsmith-stretch}/spectral.h +10 -13
  50. package/common/cpp/audioapi/{core/utils → utils}/AudioArray.cpp +5 -5
  51. package/common/cpp/audioapi/{core/utils → utils}/AudioBus.cpp +29 -29
  52. package/ios/audioapi/ios/core/AudioDecoder.mm +3 -3
  53. package/ios/audioapi/ios/core/AudioPlayer.h +5 -2
  54. package/ios/audioapi/ios/core/AudioPlayer.m +9 -5
  55. package/ios/audioapi/ios/core/IOSAudioPlayer.h +1 -0
  56. package/ios/audioapi/ios/core/IOSAudioPlayer.mm +12 -10
  57. package/lib/module/api.js +1 -2
  58. package/lib/module/api.js.map +1 -1
  59. package/lib/module/api.web.js +1 -1
  60. package/lib/module/api.web.js.map +1 -1
  61. package/lib/module/core/AudioBufferSourceNode.js +6 -0
  62. package/lib/module/core/AudioBufferSourceNode.js.map +1 -1
  63. package/lib/module/core/AudioScheduledSourceNode.js +5 -0
  64. package/lib/module/core/AudioScheduledSourceNode.js.map +1 -1
  65. package/lib/module/core/BaseAudioContext.js +0 -4
  66. package/lib/module/core/BaseAudioContext.js.map +1 -1
  67. package/lib/module/web-core/AudioBufferSourceNode.js +6 -0
  68. package/lib/module/web-core/AudioBufferSourceNode.js.map +1 -1
  69. package/lib/module/web-core/AudioScheduledSourceNode.js +8 -0
  70. package/lib/module/web-core/AudioScheduledSourceNode.js.map +1 -1
  71. package/lib/typescript/api.d.ts +1 -2
  72. package/lib/typescript/api.d.ts.map +1 -1
  73. package/lib/typescript/api.web.d.ts +1 -1
  74. package/lib/typescript/api.web.d.ts.map +1 -1
  75. package/lib/typescript/core/AudioBufferSourceNode.d.ts +3 -0
  76. package/lib/typescript/core/AudioBufferSourceNode.d.ts.map +1 -1
  77. package/lib/typescript/core/AudioScheduledSourceNode.d.ts +1 -0
  78. package/lib/typescript/core/AudioScheduledSourceNode.d.ts.map +1 -1
  79. package/lib/typescript/core/BaseAudioContext.d.ts +0 -2
  80. package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -1
  81. package/lib/typescript/interfaces.d.ts +3 -6
  82. package/lib/typescript/interfaces.d.ts.map +1 -1
  83. package/lib/typescript/types.d.ts +1 -0
  84. package/lib/typescript/types.d.ts.map +1 -1
  85. package/lib/typescript/web-core/AudioBufferSourceNode.d.ts +3 -0
  86. package/lib/typescript/web-core/AudioBufferSourceNode.d.ts.map +1 -1
  87. package/lib/typescript/web-core/AudioScheduledSourceNode.d.ts +1 -0
  88. package/lib/typescript/web-core/AudioScheduledSourceNode.d.ts.map +1 -1
  89. package/package.json +1 -2
  90. package/src/api.ts +1 -1
  91. package/src/api.web.ts +1 -0
  92. package/src/core/AudioBufferSourceNode.ts +9 -0
  93. package/src/core/AudioScheduledSourceNode.ts +5 -0
  94. package/src/core/BaseAudioContext.ts +0 -5
  95. package/src/interfaces.ts +3 -6
  96. package/src/types.ts +2 -0
  97. package/src/web-core/AudioBufferSourceNode.tsx +11 -0
  98. package/src/web-core/AudioScheduledSourceNode.tsx +9 -0
  99. package/common/cpp/audioapi/HostObjects/StretcherNodeHostObject.h +0 -35
  100. package/common/cpp/audioapi/core/effects/StretcherNode.cpp +0 -94
  101. package/common/cpp/audioapi/core/effects/StretcherNode.h +0 -35
  102. package/common/cpp/audioapi/dsp/FFTFrame.cpp +0 -100
  103. package/common/cpp/audioapi/dsp/FFTFrame.h +0 -74
  104. package/common/cpp/audioapi/libs/dsp/common.h +0 -47
  105. package/common/cpp/audioapi/libs/dsp/windows.h +0 -219
  106. package/lib/module/core/StretcherNode.js +0 -12
  107. package/lib/module/core/StretcherNode.js.map +0 -1
  108. package/lib/typescript/core/StretcherNode.d.ts +0 -10
  109. package/lib/typescript/core/StretcherNode.d.ts.map +0 -1
  110. package/src/core/StretcherNode.ts +0 -15
  111. /package/common/cpp/audioapi/libs/{miniaudio.h → miniaudio/miniaudio.h} +0 -0
  112. /package/{android/src/main/cpp/audioapi/android/libs → common/cpp/audioapi/libs/pffft}/pffft.h +0 -0
  113. /package/common/cpp/audioapi/{core/utils → utils}/AudioArray.h +0 -0
  114. /package/common/cpp/audioapi/{core/utils → utils}/AudioBus.h +0 -0
@@ -2,10 +2,10 @@
2
2
  #include <audioapi/core/BaseAudioContext.h>
3
3
  #include <audioapi/core/Constants.h>
4
4
  #include <audioapi/core/sources/AudioBufferSourceNode.h>
5
- #include <audioapi/core/utils/AudioArray.h>
6
- #include <audioapi/core/utils/AudioBus.h>
7
5
  #include <audioapi/core/utils/Locker.h>
8
6
  #include <audioapi/dsp/AudioUtils.h>
7
+ #include <audioapi/utils/AudioArray.h>
8
+ #include <audioapi/utils/AudioBus.h>
9
9
 
10
10
  namespace audioapi {
11
11
 
@@ -14,15 +14,18 @@ AudioBufferSourceNode::AudioBufferSourceNode(BaseAudioContext *context)
14
14
  loop_(false),
15
15
  loopStart_(0),
16
16
  loopEnd_(0),
17
+ timeStretchType_(TimeStretchType::LINEAR),
17
18
  vReadIndex_(0.0) {
18
19
  buffer_ = std::shared_ptr<AudioBuffer>(nullptr);
19
- alignedBus_ = std::make_shared<AudioBus>(
20
- RENDER_QUANTUM_SIZE, 1, context_->getSampleRate());
21
20
 
22
- detuneParam_ = std::make_shared<AudioParam>(0.0, MIN_DETUNE, MAX_DETUNE);
21
+ detuneParam_ = std::make_shared<AudioParam>(
22
+ 0.0, MOST_NEGATIVE_SINGLE_FLOAT, MOST_POSITIVE_SINGLE_FLOAT);
23
23
  playbackRateParam_ = std::make_shared<AudioParam>(
24
24
  1.0, MOST_NEGATIVE_SINGLE_FLOAT, MOST_POSITIVE_SINGLE_FLOAT);
25
25
 
26
+ playbackRateBus_ = std::make_shared<AudioBus>(
27
+ RENDER_QUANTUM_SIZE * 3, channelCount_, context_->getSampleRate());
28
+
26
29
  isInitialized_ = true;
27
30
  }
28
31
 
@@ -51,6 +54,10 @@ std::shared_ptr<AudioBuffer> AudioBufferSourceNode::getBuffer() const {
51
54
  return buffer_;
52
55
  }
53
56
 
57
+ std::string AudioBufferSourceNode::getTimeStretchType() const {
58
+ return toString(timeStretchType_);
59
+ }
60
+
54
61
  void AudioBufferSourceNode::setLoop(bool loop) {
55
62
  loop_ = loop;
56
63
  }
@@ -69,8 +76,6 @@ void AudioBufferSourceNode::setBuffer(
69
76
 
70
77
  if (!buffer) {
71
78
  buffer_ = std::shared_ptr<AudioBuffer>(nullptr);
72
- alignedBus_ = std::make_shared<AudioBus>(
73
- RENDER_QUANTUM_SIZE, 1, context_->getSampleRate());
74
79
  loopEnd_ = 0;
75
80
  return;
76
81
  }
@@ -78,17 +83,18 @@ void AudioBufferSourceNode::setBuffer(
78
83
  buffer_ = buffer;
79
84
  channelCount_ = buffer_->getNumberOfChannels();
80
85
 
81
- alignedBus_ = std::make_shared<AudioBus>(
82
- buffer_->getLength(), channelCount_, context_->getSampleRate());
83
- alignedBus_->zero();
84
- alignedBus_->sum(buffer_->bus_.get());
85
-
86
86
  audioBus_ = std::make_shared<AudioBus>(
87
87
  RENDER_QUANTUM_SIZE, channelCount_, context_->getSampleRate());
88
+ playbackRateBus_ = std::make_shared<AudioBus>(
89
+ RENDER_QUANTUM_SIZE * 3, channelCount_, context_->getSampleRate());
88
90
 
89
91
  loopEnd_ = buffer_->getDuration();
90
92
  }
91
93
 
94
+ void AudioBufferSourceNode::setTimeStretchType(const std::string &type) {
95
+ timeStretchType_ = fromString(type);
96
+ }
97
+
92
98
  void AudioBufferSourceNode::start(double when, double offset, double duration) {
93
99
  AudioScheduledSourceNode::start(when);
94
100
 
@@ -117,7 +123,7 @@ void AudioBufferSourceNode::processNode(
117
123
  const std::shared_ptr<AudioBus> &processingBus,
118
124
  int framesToProcess) {
119
125
  // No audio data to fill, zero the output and return.
120
- if (!buffer_) {
126
+ if (!buffer_ || !buffer_->bus_) {
121
127
  processingBus->zero();
122
128
  return;
123
129
  }
@@ -130,26 +136,58 @@ void AudioBufferSourceNode::processNode(
130
136
  size_t startOffset = 0;
131
137
  size_t offsetLength = 0;
132
138
 
133
- updatePlaybackInfo(processingBus, framesToProcess, startOffset, offsetLength);
134
- float playbackRate = getPlaybackRateValue(startOffset);
139
+ if (timeStretchType_ == TimeStretchType::LINEAR) {
140
+ auto computedPlaybackRate = getComputedPlaybackRateValue();
141
+ updatePlaybackInfo(
142
+ processingBus, framesToProcess, startOffset, offsetLength);
143
+
144
+ if (computedPlaybackRate == 0.0f || !isPlaying()) {
145
+ processingBus->zero();
146
+ return;
147
+ } else if (std::fabs(computedPlaybackRate) == 1.0) {
148
+ processWithoutInterpolation(
149
+ processingBus, startOffset, offsetLength, computedPlaybackRate);
150
+ } else {
151
+ processWithInterpolation(
152
+ processingBus, startOffset, offsetLength, computedPlaybackRate);
153
+ }
154
+ } else {
155
+ auto time = context_->getCurrentTime();
156
+ auto playbackRate =
157
+ std::clamp(playbackRateParam_->getValueAtTime(time), 0.0f, 3.0f);
158
+ auto detune =
159
+ std::clamp(detuneParam_->getValueAtTime(time) / 100.0f, -12.0f, 12.0f);
135
160
 
136
- assert(alignedBus_ != nullptr);
137
- assert(alignedBus_->getSize() > 0);
161
+ playbackRateBus_->zero();
162
+
163
+ auto framesNeededToStretch =
164
+ static_cast<int>(playbackRate * static_cast<float>(framesToProcess));
165
+
166
+ updatePlaybackInfo(
167
+ playbackRateBus_, framesNeededToStretch, startOffset, offsetLength);
138
168
 
139
- if (playbackRate == 0.0f || !isPlaying()) {
140
- processingBus->zero();
141
- return;
142
- } else if (std::fabs(playbackRate) == 1.0) {
143
169
  processWithoutInterpolation(
144
- processingBus, startOffset, offsetLength, playbackRate);
145
- } else {
146
- processWithInterpolation(
147
- processingBus, startOffset, offsetLength, playbackRate);
170
+ playbackRateBus_, startOffset, offsetLength, playbackRate);
171
+
172
+ auto stretch = buffer_->stretch_;
173
+
174
+ stretch->process(
175
+ playbackRateBus_.get()[0],
176
+ framesNeededToStretch,
177
+ processingBus.get()[0],
178
+ framesToProcess);
179
+
180
+ stretch->setTransposeSemitones(detune);
148
181
  }
149
182
 
150
183
  handleStopScheduled();
151
184
  }
152
185
 
186
+ double AudioBufferSourceNode::getStopTime() const {
187
+ return dsp::sampleFrameToTime(
188
+ static_cast<int>(vReadIndex_), buffer_->getSampleRate());
189
+ }
190
+
153
191
  /**
154
192
  * Helper functions
155
193
  */
@@ -182,12 +220,12 @@ void AudioBufferSourceNode::processWithoutInterpolation(
182
220
  // Direction is forward, we can normally copy the data
183
221
  if (direction == 1) {
184
222
  processingBus->copy(
185
- alignedBus_.get(), readIndex, writeIndex, framesToCopy);
223
+ buffer_->bus_.get(), readIndex, writeIndex, framesToCopy);
186
224
  } else {
187
225
  for (int i = 0; i < framesToCopy; i += 1) {
188
226
  for (int j = 0; j < processingBus->getNumberOfChannels(); j += 1) {
189
227
  (*processingBus->getChannel(j))[writeIndex + i] =
190
- (*alignedBus_->getChannel(j))[readIndex - i];
228
+ (*buffer_->bus_->getChannel(j))[readIndex - i];
191
229
  }
192
230
  }
193
231
  }
@@ -248,10 +286,10 @@ void AudioBufferSourceNode::processWithInterpolation(
248
286
 
249
287
  for (int i = 0; i < processingBus->getNumberOfChannels(); i += 1) {
250
288
  float *destination = processingBus->getChannel(i)->getData();
251
- const float *source = alignedBus_->getChannel(i)->getData();
289
+ const float *source = buffer_->bus_->getChannel(i)->getData();
252
290
 
253
- destination[writeIndex] = AudioUtils::linearInterpolate(
254
- source, readIndex, nextReadIndex, factor);
291
+ destination[writeIndex] =
292
+ dsp::linearInterpolate(source, readIndex, nextReadIndex, factor);
255
293
  }
256
294
 
257
295
  writeIndex += 1;
@@ -271,13 +309,12 @@ void AudioBufferSourceNode::processWithInterpolation(
271
309
  }
272
310
  }
273
311
 
274
- float AudioBufferSourceNode::getPlaybackRateValue(size_t &startOffset) {
275
- auto time = context_->getCurrentTime() +
276
- static_cast<double>(startOffset) / context_->getSampleRate();
312
+ float AudioBufferSourceNode::getComputedPlaybackRateValue() {
313
+ auto time = context_->getCurrentTime();
277
314
 
278
315
  auto sampleRateFactor = buffer_->getSampleRate() / context_->getSampleRate();
279
- auto detune = std::pow(2.0f, detuneParam_->getValueAtTime(time) / 1200.0f);
280
316
  auto playbackRate = playbackRateParam_->getValueAtTime(time);
317
+ auto detune = std::pow(2.0f, detuneParam_->getValueAtTime(time) / 1200.0f);
281
318
 
282
319
  return playbackRate * sampleRateFactor * detune;
283
320
  }
@@ -290,7 +327,7 @@ double AudioBufferSourceNode::getVirtualStartFrame() {
290
327
  }
291
328
 
292
329
  double AudioBufferSourceNode::getVirtualEndFrame() {
293
- auto inputBufferLength = static_cast<double>(alignedBus_->getSize());
330
+ auto inputBufferLength = static_cast<double>(buffer_->bus_->getSize());
294
331
  auto loopEndFrame = loopEnd_ * context_->getSampleRate();
295
332
 
296
333
  return loop_ && loopEndFrame > 0 && loopStart_ < loopEnd_
@@ -2,11 +2,12 @@
2
2
 
3
3
  #include <audioapi/core/sources/AudioBuffer.h>
4
4
  #include <audioapi/core/sources/AudioScheduledSourceNode.h>
5
+ #include <audioapi/core/types/TimeStretchType.h>
5
6
 
6
7
  #include <memory>
7
8
  #include <cstddef>
8
9
  #include <algorithm>
9
- #include <cassert>
10
+ #include <string>
10
11
 
11
12
  namespace audioapi {
12
13
 
@@ -22,41 +23,68 @@ class AudioBufferSourceNode : public AudioScheduledSourceNode {
22
23
  [[nodiscard]] double getLoopEnd() const;
23
24
  [[nodiscard]] std::shared_ptr<AudioParam> getDetuneParam() const;
24
25
  [[nodiscard]] std::shared_ptr<AudioParam> getPlaybackRateParam() const;
26
+ [[nodiscard]] std::shared_ptr<AudioParam> getSemitonesParam() const;
25
27
  [[nodiscard]] std::shared_ptr<AudioBuffer> getBuffer() const;
28
+ [[nodiscard]] std::string getTimeStretchType() const;
26
29
 
27
30
  void setLoop(bool loop);
28
31
  void setLoopStart(double loopStart);
29
32
  void setLoopEnd(double loopEnd);
30
33
  void setBuffer(const std::shared_ptr<AudioBuffer> &buffer);
34
+ void setTimeStretchType(const std::string &type);
31
35
 
32
36
  void start(double when, double offset, double duration = -1);
33
37
 
34
38
  protected:
35
39
  std::mutex &getBufferLock();
36
40
  void processNode(const std::shared_ptr<AudioBus>& processingBus, int framesToProcess) override;
41
+ double getStopTime() const override;
37
42
 
38
43
  private:
44
+ static TimeStretchType fromString(const std::string &type) {
45
+ std::string lowerType = type;
46
+ std::transform(
47
+ lowerType.begin(), lowerType.end(), lowerType.begin(), ::tolower);
48
+
49
+ if (lowerType == "linear")
50
+ return TimeStretchType::LINEAR;
51
+ if (lowerType == "speech-music")
52
+ return TimeStretchType::SPEECH_MUSIC;
53
+
54
+ throw std::invalid_argument("Unknown time stretch type: " + type);
55
+ }
56
+
57
+ static std::string toString(TimeStretchType type) {
58
+ switch (type) {
59
+ case TimeStretchType::LINEAR:
60
+ return "linear";
61
+ case TimeStretchType::SPEECH_MUSIC:
62
+ return "speech-music";
63
+ }
64
+
65
+ throw std::invalid_argument("Unknown time stretch type");
66
+ }
67
+
39
68
  // Looping related properties
40
69
  bool loop_;
41
70
  double loopStart_;
42
71
  double loopEnd_;
43
72
  std::mutex bufferLock_;
44
73
 
45
- // playback rate aka pitch change params
74
+ // time-stretching and pitch-shifting
75
+ TimeStretchType timeStretchType_;
76
+
77
+ // k-rate params
46
78
  std::shared_ptr<AudioParam> detuneParam_;
47
79
  std::shared_ptr<AudioParam> playbackRateParam_;
48
80
 
81
+ std::shared_ptr<AudioBus> playbackRateBus_;
82
+
49
83
  // internal helper
50
84
  double vReadIndex_;
51
85
 
52
86
  // User provided buffer
53
87
  std::shared_ptr<AudioBuffer> buffer_;
54
- std::shared_ptr<AudioBus> alignedBus_;
55
-
56
- float getPlaybackRateValue(size_t &startOffset);
57
-
58
- double getVirtualStartFrame();
59
- double getVirtualEndFrame();
60
88
 
61
89
  void processWithoutInterpolation(
62
90
  const std::shared_ptr<AudioBus>& processingBus,
@@ -69,6 +97,11 @@ class AudioBufferSourceNode : public AudioScheduledSourceNode {
69
97
  size_t startOffset,
70
98
  size_t offsetLength,
71
99
  float playbackRate);
100
+
101
+ float getComputedPlaybackRateValue();
102
+
103
+ double getVirtualStartFrame();
104
+ double getVirtualEndFrame();
72
105
  };
73
106
 
74
107
  } // namespace audioapi
@@ -1,9 +1,9 @@
1
1
  #include <audioapi/core/BaseAudioContext.h>
2
2
  #include <audioapi/core/sources/AudioScheduledSourceNode.h>
3
- #include <audioapi/core/utils/AudioArray.h>
4
- #include <audioapi/core/utils/AudioBus.h>
5
3
  #include <audioapi/core/utils/AudioNodeManager.h>
6
4
  #include <audioapi/dsp/AudioUtils.h>
5
+ #include <audioapi/utils/AudioArray.h>
6
+ #include <audioapi/utils/AudioBus.h>
7
7
 
8
8
  namespace audioapi {
9
9
 
@@ -40,6 +40,11 @@ bool AudioScheduledSourceNode::isFinished() {
40
40
  return playbackState_ == PlaybackState::FINISHED;
41
41
  }
42
42
 
43
+ void AudioScheduledSourceNode::setOnendedCallback(
44
+ const std::function<void(double)> &onendedCallback) {
45
+ onendedCallback_ = onendedCallback;
46
+ }
47
+
43
48
  void AudioScheduledSourceNode::updatePlaybackInfo(
44
49
  const std::shared_ptr<AudioBus> &processingBus,
45
50
  int framesToProcess,
@@ -58,12 +63,11 @@ void AudioScheduledSourceNode::updatePlaybackInfo(
58
63
  size_t firstFrame = context_->getCurrentSampleFrame();
59
64
  size_t lastFrame = firstFrame + framesToProcess;
60
65
 
61
- size_t startFrame = std::max(
62
- AudioUtils::timeToSampleFrame(startTime_, sampleRate), firstFrame);
66
+ size_t startFrame =
67
+ std::max(dsp::timeToSampleFrame(startTime_, sampleRate), firstFrame);
63
68
  size_t stopFrame = stopTime_ == -1.0
64
69
  ? std::numeric_limits<size_t>::max()
65
- : std::max(
66
- AudioUtils::timeToSampleFrame(stopTime_, sampleRate), firstFrame);
70
+ : std::max(dsp::timeToSampleFrame(stopTime_, sampleRate), firstFrame);
67
71
 
68
72
  if (isUnscheduled() || isFinished()) {
69
73
  startOffset = 0;
@@ -105,6 +109,11 @@ void AudioScheduledSourceNode::updatePlaybackInfo(
105
109
  if (stopFrame < firstFrame) {
106
110
  startOffset = 0;
107
111
  nonSilentFramesToProcess = 0;
112
+
113
+ if (onendedCallback_) {
114
+ onendedCallback_(getStopTime());
115
+ }
116
+
108
117
  playbackState_ = PlaybackState::FINISHED;
109
118
  disable();
110
119
  return;
@@ -117,6 +126,9 @@ void AudioScheduledSourceNode::updatePlaybackInfo(
117
126
 
118
127
  void AudioScheduledSourceNode::handleStopScheduled() {
119
128
  if (isPlaying() && stopTime_ > 0 && context_->getCurrentTime() >= stopTime_) {
129
+ if (onendedCallback_) {
130
+ onendedCallback_(getStopTime());
131
+ }
120
132
  playbackState_ = PlaybackState::FINISHED;
121
133
  disable();
122
134
  }
@@ -12,6 +12,7 @@
12
12
  #include <thread>
13
13
  #include <cstddef>
14
14
  #include <cassert>
15
+ #include <utility>
15
16
 
16
17
  namespace audioapi {
17
18
 
@@ -28,6 +29,10 @@ class AudioScheduledSourceNode : public AudioNode {
28
29
  bool isPlaying();
29
30
  bool isFinished();
30
31
 
32
+ void setOnendedCallback(const std::function<void(double)> &onendedCallback);
33
+
34
+ virtual double getStopTime() const = 0;
35
+
31
36
  protected:
32
37
  PlaybackState playbackState_;
33
38
 
@@ -42,6 +47,8 @@ class AudioScheduledSourceNode : public AudioNode {
42
47
  private:
43
48
  double startTime_;
44
49
  double stopTime_;
50
+
51
+ std::function<void(double)> onendedCallback_;
45
52
  };
46
53
 
47
54
  } // namespace audioapi
@@ -1,7 +1,8 @@
1
1
  #include <audioapi/core/BaseAudioContext.h>
2
2
  #include <audioapi/core/sources/OscillatorNode.h>
3
- #include <audioapi/core/utils/AudioArray.h>
4
- #include <audioapi/core/utils/AudioBus.h>
3
+ #include <audioapi/dsp/AudioUtils.h>
4
+ #include <audioapi/utils/AudioArray.h>
5
+ #include <audioapi/utils/AudioBus.h>
5
6
 
6
7
  namespace audioapi {
7
8
 
@@ -9,7 +10,10 @@ OscillatorNode::OscillatorNode(BaseAudioContext *context)
9
10
  : AudioScheduledSourceNode(context) {
10
11
  frequencyParam_ = std::make_shared<AudioParam>(
11
12
  444.0, -context_->getNyquistFrequency(), context_->getNyquistFrequency());
12
- detuneParam_ = std::make_shared<AudioParam>(0.0, -MAX_DETUNE, MAX_DETUNE);
13
+ detuneParam_ = std::make_shared<AudioParam>(
14
+ 0.0,
15
+ -1200 * LOG2_MOST_POSITIVE_SINGLE_FLOAT,
16
+ 1200 * LOG2_MOST_POSITIVE_SINGLE_FLOAT);
13
17
  type_ = OscillatorType::SINE;
14
18
  periodicWave_ = context_->getBasicWaveForm(type_);
15
19
  isInitialized_ = true;
@@ -81,4 +85,9 @@ void OscillatorNode::processNode(
81
85
  handleStopScheduled();
82
86
  }
83
87
 
88
+ double OscillatorNode::getStopTime() const {
89
+ return dsp::sampleFrameToTime(
90
+ static_cast<int>(phase_), context_->getSampleRate());
91
+ }
92
+
84
93
  } // namespace audioapi
@@ -25,6 +25,7 @@ class OscillatorNode : public AudioScheduledSourceNode {
25
25
 
26
26
  protected:
27
27
  void processNode(const std::shared_ptr<AudioBus>& processingBus, int framesToProcess) override;
28
+ double getStopTime() const override;
28
29
 
29
30
  private:
30
31
  std::shared_ptr<AudioParam> frequencyParam_;
@@ -0,0 +1,7 @@
1
+ #pragma once
2
+
3
+ namespace audioapi {
4
+
5
+ enum class TimeStretchType { LINEAR, SPEECH_MUSIC };
6
+
7
+ }
@@ -1,6 +1,6 @@
1
1
  #include <audioapi/dsp/AudioUtils.h>
2
2
 
3
- namespace audioapi::AudioUtils {
3
+ namespace audioapi::dsp {
4
4
  size_t timeToSampleFrame(double time, float sampleRate) {
5
5
  return static_cast<size_t>(time * sampleRate);
6
6
  }
@@ -30,4 +30,4 @@ float linearToDecibels(float value) {
30
30
  float decibelsToLinear(float value) {
31
31
  return powf(10, value / 20);
32
32
  }
33
- } // namespace audioapi::AudioUtils
33
+ } // namespace audioapi::dsp
@@ -4,7 +4,7 @@
4
4
  #include <cstdint>
5
5
  #include <cmath>
6
6
 
7
- namespace audioapi::AudioUtils {
7
+ namespace audioapi::dsp {
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::AudioUtils
16
+ } // namespace audioapi::dsp
@@ -0,0 +1,41 @@
1
+ #include <audioapi/dsp/FFT.h>
2
+
3
+ namespace audioapi::dsp {
4
+
5
+ FFT::FFT(int size) : size_(size) {
6
+ pffftSetup_ = pffft_new_setup(size_, PFFFT_REAL);
7
+ work_ = (float *)pffft_aligned_malloc(size_ * sizeof(float));
8
+ }
9
+
10
+ FFT::~FFT() {
11
+ pffft_destroy_setup(pffftSetup_);
12
+ pffft_aligned_free(work_);
13
+ }
14
+
15
+ void FFT::doFFT(float *in, std::vector<std::complex<float>> &out) {
16
+ pffft_transform_ordered(
17
+ pffftSetup_,
18
+ in,
19
+ reinterpret_cast<float *>(&out[0]),
20
+ work_,
21
+ PFFFT_FORWARD);
22
+
23
+ dsp::multiplyByScalar(
24
+ reinterpret_cast<float *>(&out[0]),
25
+ 0.5f,
26
+ reinterpret_cast<float *>(&out[0]),
27
+ size_ * 2);
28
+ }
29
+
30
+ void FFT::doInverseFFT(std::vector<std::complex<float>> &in, float *out) {
31
+ pffft_transform_ordered(
32
+ pffftSetup_,
33
+ reinterpret_cast<float *>(&in[0]),
34
+ out,
35
+ work_,
36
+ PFFFT_BACKWARD);
37
+
38
+ dsp::multiplyByScalar(out, 1.0f / static_cast<float>(size_), out, size_);
39
+ }
40
+
41
+ } // namespace audioapi::dsp
@@ -0,0 +1,29 @@
1
+ #pragma once
2
+
3
+ #include <audioapi/dsp/VectorMath.h>
4
+ #include <audioapi/libs/pffft/pffft.h>
5
+
6
+ #include <algorithm>
7
+ #include <cmath>
8
+ #include <utility>
9
+ #include <complex>
10
+ #include <vector>
11
+
12
+ namespace audioapi::dsp {
13
+
14
+ class FFT {
15
+ public:
16
+ explicit FFT(int size);
17
+ ~FFT();
18
+
19
+ void doFFT(float *in, std::vector<std::complex<float>> &out);
20
+ void doInverseFFT(std::vector<std::complex<float>> &in, float *out);
21
+
22
+ private:
23
+ int size_;
24
+
25
+ PFFFT_Setup *pffftSetup_;
26
+ float *work_;
27
+ };
28
+
29
+ } // namespace audioapi::dsp
@@ -38,7 +38,7 @@
38
38
  #include <arm_neon.h>
39
39
  #endif
40
40
 
41
- namespace audioapi::VectorMath {
41
+ namespace audioapi::dsp {
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] = AudioUtils::linearToDecibels(inputVector[i]);
698
+ outputVector[i] = dsp::linearToDecibels(inputVector[i]);
699
699
  }
700
700
  }
701
- } // namespace audioapi::VectorMath
701
+ } // namespace audioapi::dsp
@@ -32,7 +32,7 @@
32
32
  #include <algorithm>
33
33
  #include <cmath>
34
34
 
35
- namespace audioapi::VectorMath {
35
+ namespace audioapi::dsp {
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::VectorMath
49
+ } // namespace audioapi::dsp
@@ -0,0 +1,80 @@
1
+ #include <audioapi/core/Constants.h>
2
+ #include <audioapi/dsp/Windows.h>
3
+
4
+ namespace audioapi::dsp {
5
+
6
+ void WindowFunction::forcePerfectReconstruction(
7
+ float *data,
8
+ int windowLength,
9
+ int interval) {
10
+ for (int i = 0; i < interval; ++i) {
11
+ float sum2 = 0;
12
+
13
+ for (int index = i; index < windowLength; index += interval) {
14
+ sum2 += data[index] * data[index];
15
+ }
16
+
17
+ float factor = 1 / std::sqrt(sum2);
18
+
19
+ for (int index = i; index < windowLength; index += interval) {
20
+ data[index] *= factor;
21
+ }
22
+ }
23
+ }
24
+
25
+ void Hann::apply(float *data, int size) const {
26
+ for (int i = 0; i < size; ++i) {
27
+ auto x = static_cast<float>(i) / static_cast<float>(size - 1);
28
+ auto window = 0.5f - 0.5f * cos(2 * PI * x);
29
+ data[i] = window * amplitude_;
30
+ }
31
+ }
32
+
33
+ void Blackman::apply(float *data, int size) const {
34
+ for (int i = 0; i < size; ++i) {
35
+ auto x = static_cast<float>(i) / static_cast<float>(size - 1);
36
+ auto window = 0.42f - 0.5f * cos(2 * PI * x) + 0.08f * cos(4 * PI * x);
37
+ data[i] = window * amplitude_;
38
+ }
39
+ }
40
+
41
+ void Kaiser::apply(float *data, int size) const {
42
+ for (int i = 0; i < size; ++i) {
43
+ auto r = static_cast<float>(2 * i + 1) / static_cast<float>(size) - 1.0f;
44
+ auto arg = std::sqrt(1 - r * r);
45
+ data[i] = bessel0(beta_ * arg) * invB0_ * amplitude_;
46
+ }
47
+ }
48
+
49
+ float Kaiser::bandwidthToBeta(float bandwidth, bool heuristicOptimal) {
50
+ if (heuristicOptimal) { // Heuristic based on numerical search
51
+ return bandwidth + 8.0f / (bandwidth + 3.0f) * (bandwidth + 3.0f) +
52
+ 0.25f * std::max(3.0f - bandwidth, 0.0f);
53
+ }
54
+
55
+ bandwidth = std::max(bandwidth, 2.0f);
56
+ auto alpha = std::sqrt(bandwidth * bandwidth * 0.25f - 1.0f);
57
+ return alpha * PI;
58
+ }
59
+
60
+ void ApproximateConfinedGaussian::apply(float *data, int size) const {
61
+ auto offsetScale =
62
+ getGaussian(1.0f) / (getGaussian(3.0f) + getGaussian(-1.0f));
63
+ auto norm = 1 / (getGaussian(1.0f) - 2 * offsetScale * getGaussian(2.0f));
64
+ for (int i = 0; i < size; ++i) {
65
+ auto r = static_cast<float>(2 * i + 1) / static_cast<float>(size) - 1.0f;
66
+ data[i] = norm *
67
+ (getGaussian(r) -
68
+ offsetScale * (getGaussian(r - 2) + getGaussian(r + 2)));
69
+ }
70
+ }
71
+
72
+ float ApproximateConfinedGaussian::bandwidthToSigma(float bandwidth) {
73
+ return 0.3f / std::sqrt(bandwidth);
74
+ }
75
+
76
+ float ApproximateConfinedGaussian::getGaussian(float x) const {
77
+ return std::exp(-x * x * gaussianFactor_);
78
+ }
79
+
80
+ } // namespace audioapi::dsp