react-native-audio-api 0.1.0 → 0.3.0-rc1

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 (217) hide show
  1. package/README.md +10 -8
  2. package/RNAudioAPI.podspec +5 -0
  3. package/android/CMakeLists.txt +21 -10
  4. package/android/libs/fftw3/arm64-v8a/libfftw3.a +0 -0
  5. package/android/libs/fftw3/armeabi-v7a/libfftw3.a +0 -0
  6. package/android/libs/fftw3/x86/libfftw3.a +0 -0
  7. package/android/libs/fftw3/x86_64/libfftw3.a +0 -0
  8. package/android/libs/include/fftw3/fftw3.h +413 -0
  9. package/android/src/main/cpp/AudioPlayer/AudioPlayer.cpp +32 -2
  10. package/android/src/main/cpp/AudioPlayer/AudioPlayer.h +6 -2
  11. package/common/cpp/AudioAPIInstaller/AudioAPIInstallerHostObject.cpp +5 -3
  12. package/common/cpp/AudioAPIInstaller/AudioAPIInstallerHostObject.h +5 -1
  13. package/common/cpp/HostObjects/AudioBufferHostObject.cpp +6 -0
  14. package/common/cpp/HostObjects/AudioBufferSourceNodeHostObject.cpp +13 -1
  15. package/common/cpp/HostObjects/AudioContextHostObject.cpp +12 -149
  16. package/common/cpp/HostObjects/AudioContextHostObject.h +8 -14
  17. package/common/cpp/HostObjects/AudioNodeHostObject.cpp +0 -6
  18. package/common/cpp/HostObjects/BaseAudioContextHostObject.cpp +240 -0
  19. package/common/cpp/HostObjects/BaseAudioContextHostObject.h +41 -0
  20. package/common/cpp/HostObjects/BiquadFilterNodeHostObject.cpp +44 -0
  21. package/common/cpp/HostObjects/OscillatorNodeHostObject.cpp +21 -0
  22. package/common/cpp/HostObjects/OscillatorNodeHostObject.h +1 -0
  23. package/common/cpp/HostObjects/PeriodicWaveHostObject.cpp +33 -0
  24. package/common/cpp/HostObjects/PeriodicWaveHostObject.h +33 -0
  25. package/common/cpp/core/AudioArray.cpp +117 -0
  26. package/common/cpp/core/AudioArray.h +48 -0
  27. package/common/cpp/core/AudioBuffer.cpp +23 -80
  28. package/common/cpp/core/AudioBuffer.h +12 -13
  29. package/common/cpp/core/AudioBufferSourceNode.cpp +112 -25
  30. package/common/cpp/core/AudioBufferSourceNode.h +10 -6
  31. package/common/cpp/core/AudioBus.cpp +518 -0
  32. package/common/cpp/core/AudioBus.h +83 -0
  33. package/common/cpp/core/AudioContext.cpp +7 -77
  34. package/common/cpp/core/AudioContext.h +3 -60
  35. package/common/cpp/core/AudioDestinationNode.cpp +27 -15
  36. package/common/cpp/core/AudioDestinationNode.h +13 -5
  37. package/common/cpp/core/AudioNode.cpp +184 -22
  38. package/common/cpp/core/AudioNode.h +37 -37
  39. package/common/cpp/core/AudioNodeManager.cpp +75 -0
  40. package/common/cpp/core/AudioNodeManager.h +42 -0
  41. package/common/cpp/core/AudioParam.cpp +8 -11
  42. package/common/cpp/core/AudioParam.h +8 -8
  43. package/common/cpp/core/AudioScheduledSourceNode.cpp +19 -5
  44. package/common/cpp/core/AudioScheduledSourceNode.h +6 -2
  45. package/common/cpp/core/BaseAudioContext.cpp +191 -0
  46. package/common/cpp/core/BaseAudioContext.h +87 -0
  47. package/common/cpp/core/BiquadFilterNode.cpp +92 -69
  48. package/common/cpp/core/BiquadFilterNode.h +53 -57
  49. package/common/cpp/core/GainNode.cpp +12 -12
  50. package/common/cpp/core/GainNode.h +5 -3
  51. package/common/cpp/core/OscillatorNode.cpp +38 -29
  52. package/common/cpp/core/OscillatorNode.h +29 -69
  53. package/common/cpp/core/ParamChange.h +6 -6
  54. package/common/cpp/core/PeriodicWave.cpp +362 -0
  55. package/common/cpp/core/PeriodicWave.h +119 -0
  56. package/common/cpp/core/StereoPannerNode.cpp +31 -30
  57. package/common/cpp/core/StereoPannerNode.h +6 -6
  58. package/common/cpp/types/BiquadFilterType.h +19 -0
  59. package/common/cpp/types/ChannelCountMode.h +10 -0
  60. package/common/cpp/types/ChannelInterpretation.h +10 -0
  61. package/common/cpp/types/ContextState.h +10 -0
  62. package/common/cpp/types/OscillatorType.h +11 -0
  63. package/common/cpp/utils/FFTFrame.h +67 -0
  64. package/common/cpp/utils/JsiPromise.cpp +59 -0
  65. package/common/cpp/utils/JsiPromise.h +42 -0
  66. package/common/cpp/utils/Locker.h +49 -0
  67. package/common/cpp/utils/VectorMath.cpp +88 -3
  68. package/common/cpp/utils/VectorMath.h +7 -1
  69. package/common/cpp/utils/android/FFTFrame.cpp +23 -0
  70. package/common/cpp/utils/ios/FFTFrame.cpp +29 -0
  71. package/common/cpp/wrappers/AudioBufferSourceNodeWrapper.cpp +10 -0
  72. package/common/cpp/wrappers/AudioBufferSourceNodeWrapper.h +3 -2
  73. package/common/cpp/wrappers/AudioBufferWrapper.h +5 -5
  74. package/common/cpp/wrappers/AudioContextWrapper.cpp +7 -60
  75. package/common/cpp/wrappers/AudioContextWrapper.h +5 -26
  76. package/common/cpp/wrappers/AudioNodeWrapper.h +5 -5
  77. package/common/cpp/wrappers/AudioParamWrapper.h +4 -4
  78. package/common/cpp/wrappers/BaseAudioContextWrapper.cpp +83 -0
  79. package/common/cpp/wrappers/BaseAudioContextWrapper.h +50 -0
  80. package/common/cpp/wrappers/BiquadFilterNodeWrapper.cpp +9 -0
  81. package/common/cpp/wrappers/BiquadFilterNodeWrapper.h +9 -4
  82. package/common/cpp/wrappers/GainNodeWrapper.h +1 -1
  83. package/common/cpp/wrappers/OscillatorNodeWrapper.cpp +6 -0
  84. package/common/cpp/wrappers/OscillatorNodeWrapper.h +5 -2
  85. package/common/cpp/wrappers/PeriodicWaveWrapper.h +17 -0
  86. package/common/cpp/wrappers/StereoPannerNodeWrapper.h +1 -1
  87. package/ios/AudioAPIModule.h +20 -1
  88. package/ios/AudioAPIModule.mm +6 -4
  89. package/ios/AudioDecoder/AudioDecoder.h +17 -0
  90. package/ios/AudioDecoder/AudioDecoder.m +167 -0
  91. package/ios/AudioDecoder/IOSAudioDecoder.h +26 -0
  92. package/ios/AudioDecoder/IOSAudioDecoder.mm +40 -0
  93. package/ios/AudioPlayer/AudioPlayer.h +3 -2
  94. package/ios/AudioPlayer/AudioPlayer.m +14 -17
  95. package/ios/AudioPlayer/IOSAudioPlayer.h +7 -3
  96. package/ios/AudioPlayer/IOSAudioPlayer.mm +31 -7
  97. package/lib/module/core/AudioBuffer.js +37 -0
  98. package/lib/module/core/AudioBuffer.js.map +1 -0
  99. package/lib/module/core/AudioBufferSourceNode.js +28 -0
  100. package/lib/module/core/AudioBufferSourceNode.js.map +1 -0
  101. package/lib/module/core/AudioContext.js +10 -0
  102. package/lib/module/core/AudioContext.js.map +1 -0
  103. package/lib/module/core/AudioDestinationNode.js +7 -0
  104. package/lib/module/core/AudioDestinationNode.js.map +1 -0
  105. package/lib/module/core/AudioNode.js +22 -0
  106. package/lib/module/core/AudioNode.js.map +1 -0
  107. package/lib/module/core/AudioParam.js +35 -0
  108. package/lib/module/core/AudioParam.js.map +1 -0
  109. package/lib/module/core/AudioScheduledSourceNode.js +28 -0
  110. package/lib/module/core/AudioScheduledSourceNode.js.map +1 -0
  111. package/lib/module/core/BaseAudioContext.js +62 -0
  112. package/lib/module/core/BaseAudioContext.js.map +1 -0
  113. package/lib/module/core/BiquadFilterNode.js +25 -0
  114. package/lib/module/core/BiquadFilterNode.js.map +1 -0
  115. package/lib/module/core/GainNode.js +9 -0
  116. package/lib/module/core/GainNode.js.map +1 -0
  117. package/lib/module/core/OscillatorNode.js +24 -0
  118. package/lib/module/core/OscillatorNode.js.map +1 -0
  119. package/lib/module/core/PeriodicWave.js +8 -0
  120. package/lib/module/core/PeriodicWave.js.map +1 -0
  121. package/lib/module/core/StereoPannerNode.js +9 -0
  122. package/lib/module/core/StereoPannerNode.js.map +1 -0
  123. package/lib/module/core/types.js.map +1 -0
  124. package/lib/module/errors/IndexSizeError.js +8 -0
  125. package/lib/module/errors/IndexSizeError.js.map +1 -0
  126. package/lib/module/errors/InvalidAccessError.js +8 -0
  127. package/lib/module/errors/InvalidAccessError.js.map +1 -0
  128. package/lib/module/errors/InvalidStateError.js +8 -0
  129. package/lib/module/errors/InvalidStateError.js.map +1 -0
  130. package/lib/module/errors/RangeError.js +8 -0
  131. package/lib/module/errors/RangeError.js.map +1 -0
  132. package/lib/module/errors/index.js +5 -0
  133. package/lib/module/errors/index.js.map +1 -0
  134. package/lib/module/index.js +212 -15
  135. package/lib/module/index.js.map +1 -1
  136. package/lib/module/index.native.js +18 -0
  137. package/lib/module/index.native.js.map +1 -0
  138. package/lib/module/interfaces.js +2 -0
  139. package/lib/module/interfaces.js.map +1 -0
  140. package/lib/module/utils/resolveAudioSource.js +10 -0
  141. package/lib/module/utils/resolveAudioSource.js.map +1 -0
  142. package/lib/typescript/core/AudioBuffer.d.ts +12 -0
  143. package/lib/typescript/core/AudioBuffer.d.ts.map +1 -0
  144. package/lib/typescript/core/AudioBufferSourceNode.d.ts +12 -0
  145. package/lib/typescript/core/AudioBufferSourceNode.d.ts.map +1 -0
  146. package/lib/typescript/core/AudioContext.d.ts +6 -0
  147. package/lib/typescript/core/AudioContext.d.ts.map +1 -0
  148. package/lib/typescript/core/AudioDestinationNode.d.ts +7 -0
  149. package/lib/typescript/core/AudioDestinationNode.d.ts.map +1 -0
  150. package/lib/typescript/core/AudioNode.d.ts +16 -0
  151. package/lib/typescript/core/AudioNode.d.ts.map +1 -0
  152. package/lib/typescript/core/AudioParam.d.ts +14 -0
  153. package/lib/typescript/core/AudioParam.d.ts.map +1 -0
  154. package/lib/typescript/core/AudioScheduledSourceNode.d.ts +10 -0
  155. package/lib/typescript/core/AudioScheduledSourceNode.d.ts.map +1 -0
  156. package/lib/typescript/core/BaseAudioContext.d.ts +27 -0
  157. package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -0
  158. package/lib/typescript/core/BiquadFilterNode.d.ts +16 -0
  159. package/lib/typescript/core/BiquadFilterNode.d.ts.map +1 -0
  160. package/lib/typescript/core/GainNode.d.ts +9 -0
  161. package/lib/typescript/core/GainNode.d.ts.map +1 -0
  162. package/lib/typescript/core/OscillatorNode.d.ts +15 -0
  163. package/lib/typescript/core/OscillatorNode.d.ts.map +1 -0
  164. package/lib/typescript/core/PeriodicWave.d.ts +5 -0
  165. package/lib/typescript/core/PeriodicWave.d.ts.map +1 -0
  166. package/lib/typescript/core/StereoPannerNode.d.ts +9 -0
  167. package/lib/typescript/core/StereoPannerNode.d.ts.map +1 -0
  168. package/lib/typescript/core/types.d.ts +15 -0
  169. package/lib/typescript/core/types.d.ts.map +1 -0
  170. package/lib/typescript/errors/IndexSizeError.d.ts +5 -0
  171. package/lib/typescript/errors/IndexSizeError.d.ts.map +1 -0
  172. package/lib/typescript/errors/InvalidAccessError.d.ts +5 -0
  173. package/lib/typescript/errors/InvalidAccessError.d.ts.map +1 -0
  174. package/lib/typescript/errors/InvalidStateError.d.ts +5 -0
  175. package/lib/typescript/errors/InvalidStateError.d.ts.map +1 -0
  176. package/lib/typescript/errors/RangeError.d.ts +5 -0
  177. package/lib/typescript/errors/RangeError.d.ts.map +1 -0
  178. package/lib/typescript/errors/index.d.ts +5 -0
  179. package/lib/typescript/errors/index.d.ts.map +1 -0
  180. package/lib/typescript/index.d.ts +88 -5
  181. package/lib/typescript/index.d.ts.map +1 -1
  182. package/lib/typescript/index.native.d.ts +14 -0
  183. package/lib/typescript/index.native.d.ts.map +1 -0
  184. package/lib/typescript/interfaces.d.ts +79 -0
  185. package/lib/typescript/interfaces.d.ts.map +1 -0
  186. package/lib/typescript/utils/resolveAudioSource.d.ts +3 -0
  187. package/lib/typescript/utils/resolveAudioSource.d.ts.map +1 -0
  188. package/package.json +4 -2
  189. package/src/core/AudioBuffer.ts +68 -0
  190. package/src/core/AudioBufferSourceNode.ts +35 -0
  191. package/src/core/AudioContext.ts +12 -0
  192. package/src/core/AudioDestinationNode.ts +9 -0
  193. package/src/core/AudioNode.ts +38 -0
  194. package/src/core/AudioParam.ts +55 -0
  195. package/src/core/AudioScheduledSourceNode.ts +43 -0
  196. package/src/core/BaseAudioContext.ts +108 -0
  197. package/src/core/BiquadFilterNode.ts +49 -0
  198. package/src/core/GainNode.ts +13 -0
  199. package/src/core/OscillatorNode.ts +37 -0
  200. package/src/core/PeriodicWave.ts +10 -0
  201. package/src/core/StereoPannerNode.ts +13 -0
  202. package/src/core/types.ts +33 -0
  203. package/src/errors/IndexSizeError.ts +8 -0
  204. package/src/errors/InvalidAccessError.ts +8 -0
  205. package/src/errors/InvalidStateError.ts +8 -0
  206. package/src/errors/RangeError.ts +8 -0
  207. package/src/errors/index.ts +4 -0
  208. package/src/index.native.ts +25 -0
  209. package/src/index.ts +380 -40
  210. package/src/interfaces.ts +121 -0
  211. package/src/modules/global.d.ts +3 -3
  212. package/src/utils/resolveAudioSource.ts +14 -0
  213. package/lib/module/types.js.map +0 -1
  214. package/lib/typescript/types.d.ts +0 -76
  215. package/lib/typescript/types.d.ts.map +0 -1
  216. package/src/types.ts +0 -108
  217. /package/lib/module/{types.js → core/types.js} +0 -0
@@ -1,73 +1,16 @@
1
1
  #pragma once
2
2
 
3
- #include <functional>
4
3
  #include <memory>
5
- #include <string>
6
- #include <utility>
7
- #include <vector>
8
4
 
9
- #include "AudioBuffer.h"
10
- #include "AudioBufferSourceNode.h"
11
- #include "AudioDestinationNode.h"
12
- #include "AudioScheduledSourceNode.h"
13
- #include "BiquadFilterNode.h"
14
- #include "Constants.h"
15
- #include "GainNode.h"
16
- #include "OscillatorNode.h"
17
- #include "StereoPannerNode.h"
18
-
19
- #ifdef ANDROID
20
- #include "AudioPlayer.h"
21
- #else
22
- #include "IOSAudioPlayer.h"
23
- #endif
5
+ #include "BaseAudioContext.h"
24
6
 
25
7
  namespace audioapi {
26
8
 
27
- class AudioContext {
9
+ class AudioContext : public BaseAudioContext {
28
10
  public:
29
11
  AudioContext();
30
- std::string getState();
31
- int getSampleRate() const;
32
- double getCurrentTime() const;
33
- void close();
34
-
35
- std::shared_ptr<AudioDestinationNode> getDestination();
36
- std::shared_ptr<OscillatorNode> createOscillator();
37
- std::shared_ptr<GainNode> createGain();
38
- std::shared_ptr<StereoPannerNode> createStereoPanner();
39
- std::shared_ptr<BiquadFilterNode> createBiquadFilter();
40
- std::shared_ptr<AudioBufferSourceNode> createBufferSource();
41
- static std::shared_ptr<AudioBuffer>
42
- createBuffer(int numberOfChannels, int length, int sampleRate);
43
- std::function<void(float *, int)> renderAudio();
44
12
 
45
- private:
46
- enum class State { SUSPENDED, RUNNING, CLOSED };
47
-
48
- static std::string toString(State state) {
49
- switch (state) {
50
- case State::SUSPENDED:
51
- return "suspended";
52
- case State::RUNNING:
53
- return "running";
54
- case State::CLOSED:
55
- return "closed";
56
- default:
57
- throw std::invalid_argument("Unknown context state");
58
- }
59
- }
60
-
61
- private:
62
- std::shared_ptr<AudioDestinationNode> destination_;
63
- #ifdef ANDROID
64
- std::shared_ptr<AudioPlayer> audioPlayer_;
65
- #else
66
- std::shared_ptr<IOSAudioPlayer> audioPlayer_;
67
- #endif
68
- State state_ = State::RUNNING;
69
- int sampleRate_;
70
- double contextStartTime_;
13
+ void close();
71
14
  };
72
15
 
73
16
  } // namespace audioapi
@@ -1,35 +1,47 @@
1
1
  #include "AudioDestinationNode.h"
2
- #include "AudioContext.h"
2
+ #include "AudioBus.h"
3
+ #include "AudioNode.h"
4
+ #include "AudioNodeManager.h"
5
+ #include "BaseAudioContext.h"
6
+ #include "VectorMath.h"
3
7
 
4
8
  namespace audioapi {
5
9
 
6
- AudioDestinationNode::AudioDestinationNode(AudioContext *context)
7
- : AudioNode(context) {
10
+ AudioDestinationNode::AudioDestinationNode(BaseAudioContext *context)
11
+ : AudioNode(context), currentSampleFrame_(0) {
8
12
  numberOfOutputs_ = 0;
9
13
  numberOfInputs_ = INT_MAX;
10
14
  channelCountMode_ = ChannelCountMode::EXPLICIT;
15
+ isInitialized_ = true;
11
16
  }
12
17
 
13
- void AudioDestinationNode::renderAudio(float *audioData, int32_t numFrames) {
14
- processAudio(audioData, numFrames);
18
+ std::size_t AudioDestinationNode::getCurrentSampleFrame() const {
19
+ return currentSampleFrame_;
15
20
  }
16
21
 
17
- bool AudioDestinationNode::processAudio(float *audioData, int32_t numFrames) {
18
- int numSamples = numFrames * CHANNEL_COUNT;
22
+ double AudioDestinationNode::getCurrentTime() const {
23
+ return static_cast<double>(currentSampleFrame_) / context_->getSampleRate();
24
+ }
19
25
 
20
- if (mixingBuffer == nullptr) {
21
- mixingBuffer = std::make_unique<float[]>(numSamples);
26
+ void AudioDestinationNode::renderAudio(
27
+ AudioBus *destinationBus,
28
+ int32_t numFrames) {
29
+ if (!numFrames || !destinationBus || !isInitialized_) {
30
+ return;
22
31
  }
23
32
 
24
- memset(audioData, 0.0f, sizeof(float) * numSamples);
33
+ context_->getNodeManager()->preProcessGraph();
34
+ destinationBus->zero();
35
+
36
+ AudioBus *processedBus = processAudio(destinationBus, numFrames);
25
37
 
26
- for (auto &node : inputNodes_) {
27
- if (node && node->processAudio(mixingBuffer.get(), numFrames)) {
28
- VectorMath::add(audioData, mixingBuffer.get(), audioData, numSamples);
29
- }
38
+ if (processedBus && processedBus != destinationBus) {
39
+ destinationBus->copy(processedBus);
30
40
  }
31
41
 
32
- return true;
42
+ destinationBus->normalize();
43
+
44
+ currentSampleFrame_ += numFrames;
33
45
  }
34
46
 
35
47
  } // namespace audioapi
@@ -5,20 +5,28 @@
5
5
  #include <vector>
6
6
 
7
7
  #include "AudioNode.h"
8
- #include "VectorMath.h"
9
8
 
10
9
  namespace audioapi {
11
10
 
11
+ class AudioBus;
12
+ class BaseAudioContext;
13
+
12
14
  class AudioDestinationNode : public AudioNode {
13
15
  public:
14
- explicit AudioDestinationNode(AudioContext *context);
16
+ explicit AudioDestinationNode(BaseAudioContext *context);
17
+
18
+ void renderAudio(AudioBus *audioData, int32_t numFrames);
15
19
 
16
- void renderAudio(float *audioData, int32_t numFrames);
20
+ std::size_t getCurrentSampleFrame() const;
21
+ double getCurrentTime() const;
17
22
 
18
23
  protected:
19
- bool processAudio(float *audioData, int32_t numFrames) override;
24
+ // DestinationNode is triggered by AudioContext using renderAudio
25
+ // processNode function is not necessary and is never called.
26
+ void processNode(AudioBus *, int) final{};
20
27
 
21
28
  private:
22
- std::unique_ptr<float[]> mixingBuffer;
29
+ std::size_t currentSampleFrame_;
23
30
  };
31
+
24
32
  } // namespace audioapi
@@ -1,11 +1,21 @@
1
+ #include <memory>
2
+
3
+ #include "AudioBus.h"
1
4
  #include "AudioNode.h"
2
- #include "AudioContext.h"
5
+ #include "AudioNodeManager.h"
6
+ #include "BaseAudioContext.h"
3
7
 
4
8
  namespace audioapi {
5
9
 
6
- AudioNode::AudioNode(AudioContext *context) : context_(context) {}
10
+ AudioNode::AudioNode(BaseAudioContext *context) : context_(context) {
11
+ audioBus_ = std::make_shared<AudioBus>(
12
+ context->getSampleRate(),
13
+ context->getBufferSizeInFrames(),
14
+ channelCount_);
15
+ }
7
16
 
8
17
  AudioNode::~AudioNode() {
18
+ isInitialized_ = false;
9
19
  cleanup();
10
20
  }
11
21
 
@@ -30,23 +40,142 @@ std::string AudioNode::getChannelInterpretation() const {
30
40
  }
31
41
 
32
42
  void AudioNode::connect(const std::shared_ptr<AudioNode> &node) {
33
- if (numberOfOutputs_ > outputNodes_.size() &&
34
- node->getNumberOfInputs() > node->inputNodes_.size()) {
35
- outputNodes_.push_back(node);
36
- node->inputNodes_.push_back(shared_from_this());
37
- }
43
+ context_->getNodeManager()->addPendingConnection(
44
+ shared_from_this(), node, AudioNodeManager::ConnectionType::CONNECT);
45
+ }
46
+
47
+ void AudioNode::connectNode(const std::shared_ptr<AudioNode> &node) {
48
+ outputNodes_.push_back(node);
49
+ node->onInputConnected(this);
38
50
  }
39
51
 
40
52
  void AudioNode::disconnect(const std::shared_ptr<AudioNode> &node) {
41
- outputNodes_.erase(
42
- std::remove(outputNodes_.begin(), outputNodes_.end(), node),
43
- outputNodes_.end());
44
- if (auto sharedThis = shared_from_this()) {
45
- node->inputNodes_.erase(
46
- std::remove(
47
- node->inputNodes_.begin(), node->inputNodes_.end(), sharedThis),
48
- node->inputNodes_.end());
53
+ context_->getNodeManager()->addPendingConnection(
54
+ shared_from_this(), node, AudioNodeManager::ConnectionType::DISCONNECT);
55
+ }
56
+
57
+ void AudioNode::disconnectNode(const std::shared_ptr<AudioNode> &node) {
58
+ node->onInputDisconnected(this);
59
+
60
+ auto position = std::find(outputNodes_.begin(), outputNodes_.end(), node);
61
+
62
+ if (position != outputNodes_.end()) {
63
+ outputNodes_.erase(position);
64
+ }
65
+ }
66
+
67
+ bool AudioNode::isEnabled() const {
68
+ return isEnabled_;
69
+ }
70
+
71
+ void AudioNode::enable() {
72
+ isEnabled_ = true;
73
+
74
+ for (auto it = outputNodes_.begin(); it != outputNodes_.end(); ++it) {
75
+ it->get()->onInputEnabled();
76
+ }
77
+ }
78
+
79
+ void AudioNode::disable() {
80
+ isEnabled_ = false;
81
+
82
+ for (auto it = outputNodes_.begin(); it != outputNodes_.end(); ++it) {
83
+ it->get()->onInputDisabled();
84
+ }
85
+ }
86
+
87
+ std::string AudioNode::toString(ChannelCountMode mode) {
88
+ switch (mode) {
89
+ case ChannelCountMode::MAX:
90
+ return "max";
91
+ case ChannelCountMode::CLAMPED_MAX:
92
+ return "clamped-max";
93
+ case ChannelCountMode::EXPLICIT:
94
+ return "explicit";
95
+ default:
96
+ throw std::invalid_argument("Unknown channel count mode");
97
+ }
98
+ }
99
+
100
+ std::string AudioNode::toString(ChannelInterpretation interpretation) {
101
+ switch (interpretation) {
102
+ case ChannelInterpretation::SPEAKERS:
103
+ return "speakers";
104
+ case ChannelInterpretation::DISCRETE:
105
+ return "discrete";
106
+ default:
107
+ throw std::invalid_argument("Unknown channel interpretation");
108
+ }
109
+ }
110
+
111
+ AudioBus *AudioNode::processAudio(AudioBus *outputBus, int framesToProcess) {
112
+ if (!isInitialized_) {
113
+ return outputBus;
114
+ }
115
+
116
+ std::size_t currentSampleFrame = context_->getCurrentSampleFrame();
117
+
118
+ // check if the node has already been processed for this rendering quantum
119
+ bool isAlreadyProcessed = currentSampleFrame == lastRenderedFrame_;
120
+
121
+ // Node can't use output bus if:
122
+ // - outputBus is not provided, which means that next node is doing a
123
+ // multi-node summing.
124
+ // - it has more than one input, which means that it has to sum all inputs
125
+ // using internal bus.
126
+ // - it has more than one output, so each output node can get the processed
127
+ // data without re-calculating the node.
128
+ bool canUseOutputBus =
129
+ outputBus != 0 && inputNodes_.size() < 2 && outputNodes_.size() < 2;
130
+
131
+ if (isAlreadyProcessed) {
132
+ // If it was already processed in the rendering quantum, return it.
133
+ return audioBus_.get();
49
134
  }
135
+
136
+ // Update the last rendered frame before processing node and its inputs.
137
+ lastRenderedFrame_ = currentSampleFrame;
138
+
139
+ AudioBus *processingBus = canUseOutputBus ? outputBus : audioBus_.get();
140
+
141
+ if (!canUseOutputBus) {
142
+ // Clear the bus before summing all connected nodes.
143
+ processingBus->zero();
144
+ }
145
+
146
+ if (inputNodes_.empty()) {
147
+ // If there are no connected inputs, process the node just to advance the
148
+ // audio params. The node will output silence anyway.
149
+ processNode(processingBus, framesToProcess);
150
+ return processingBus;
151
+ }
152
+
153
+ for (auto it = inputNodes_.begin(); it != inputNodes_.end(); ++it) {
154
+ if (!(*it)->isEnabled()) {
155
+ continue;
156
+ }
157
+
158
+ // Process first connected node, it can be directly connected to the
159
+ // processingBus, resulting in one less summing operation.
160
+ if (it == inputNodes_.begin()) {
161
+ AudioBus *inputBus = (*it)->processAudio(processingBus, framesToProcess);
162
+
163
+ if (inputBus != processingBus) {
164
+ processingBus->sum(inputBus);
165
+ }
166
+ } else {
167
+ // Enforce the summing to be done using the internal bus.
168
+ AudioBus *inputBus = (*it)->processAudio(0, framesToProcess);
169
+ if (inputBus) {
170
+ processingBus->sum(inputBus);
171
+ }
172
+ }
173
+ }
174
+
175
+ // Finally, process the node itself.
176
+ processNode(processingBus, framesToProcess);
177
+
178
+ return processingBus;
50
179
  }
51
180
 
52
181
  void AudioNode::cleanup() {
@@ -54,15 +183,48 @@ void AudioNode::cleanup() {
54
183
  inputNodes_.clear();
55
184
  }
56
185
 
57
- bool AudioNode::processAudio(float *audioData, int32_t numFrames) {
58
- bool isPlaying = false;
59
- for (auto &node : inputNodes_) {
60
- if (node->processAudio(audioData, numFrames)) {
61
- isPlaying = true;
62
- }
186
+ void AudioNode::onInputEnabled() {
187
+ numberOfEnabledInputNodes_ += 1;
188
+
189
+ if (!isEnabled()) {
190
+ enable();
63
191
  }
192
+ }
64
193
 
65
- return isPlaying;
194
+ void AudioNode::onInputDisabled() {
195
+ numberOfEnabledInputNodes_ -= 1;
196
+
197
+ if (isEnabled() && numberOfEnabledInputNodes_ == 0) {
198
+ disable();
199
+ }
200
+ }
201
+
202
+ void AudioNode::onInputConnected(AudioNode *node) {
203
+ inputNodes_.push_back(node);
204
+
205
+ if (node->isEnabled()) {
206
+ onInputEnabled();
207
+ }
208
+ }
209
+
210
+ void AudioNode::onInputDisconnected(AudioNode *node) {
211
+ auto position = std::find(inputNodes_.begin(), inputNodes_.end(), node);
212
+
213
+ if (position != inputNodes_.end()) {
214
+ inputNodes_.erase(position);
215
+ }
216
+
217
+ if (inputNodes_.size() > 0) {
218
+ return;
219
+ }
220
+
221
+ if (isEnabled()) {
222
+ node->onInputDisabled();
223
+ }
224
+
225
+ for (auto outputNode : outputNodes_) {
226
+ disconnectNode(outputNode);
227
+ }
66
228
  }
67
229
 
68
230
  } // namespace audioapi
@@ -3,17 +3,19 @@
3
3
  #include <memory>
4
4
  #include <string>
5
5
  #include <vector>
6
- #include "Constants.h"
7
6
 
8
- // channelCount always equal to 2
7
+ #include "ChannelCountMode.h"
8
+ #include "ChannelInterpretation.h"
9
+ #include "Constants.h"
9
10
 
10
11
  namespace audioapi {
11
12
 
12
- class AudioContext;
13
+ class AudioBus;
14
+ class BaseAudioContext;
13
15
 
14
16
  class AudioNode : public std::enable_shared_from_this<AudioNode> {
15
17
  public:
16
- explicit AudioNode(AudioContext *context);
18
+ explicit AudioNode(BaseAudioContext *context);
17
19
  virtual ~AudioNode();
18
20
  int getNumberOfInputs() const;
19
21
  int getNumberOfOutputs() const;
@@ -23,52 +25,50 @@ class AudioNode : public std::enable_shared_from_this<AudioNode> {
23
25
  void connect(const std::shared_ptr<AudioNode> &node);
24
26
  void disconnect(const std::shared_ptr<AudioNode> &node);
25
27
 
26
- // Change public to protected
27
- virtual bool processAudio(float *audioData, int32_t numFrames);
28
+ bool isEnabled() const;
29
+ void enable();
30
+ void disable();
28
31
 
29
32
  protected:
30
- enum class ChannelCountMode { MAX, CLAMPED_MAX, EXPLICIT };
31
-
32
- static std::string toString(ChannelCountMode mode) {
33
- switch (mode) {
34
- case ChannelCountMode::MAX:
35
- return "max";
36
- case ChannelCountMode::CLAMPED_MAX:
37
- return "clamped-max";
38
- case ChannelCountMode::EXPLICIT:
39
- return "explicit";
40
- default:
41
- throw std::invalid_argument("Unknown channel count mode");
42
- }
43
- }
44
-
45
- enum class ChannelInterpretation { SPEAKERS, DISCRETE };
46
-
47
- static std::string toString(ChannelInterpretation interpretation) {
48
- switch (interpretation) {
49
- case ChannelInterpretation::SPEAKERS:
50
- return "speakers";
51
- case ChannelInterpretation::DISCRETE:
52
- return "discrete";
53
- default:
54
- throw std::invalid_argument("Unknown channel interpretation");
55
- }
56
- }
33
+ friend class AudioNodeManager;
34
+ friend class AudioDestinationNode;
35
+
36
+ BaseAudioContext *context_;
37
+ std::shared_ptr<AudioBus> audioBus_;
38
+
39
+ int channelCount_ = CHANNEL_COUNT;
57
40
 
58
- protected:
59
- AudioContext *context_;
60
41
  int numberOfInputs_ = 1;
61
42
  int numberOfOutputs_ = 1;
62
- int channelCount_ = CHANNEL_COUNT;
43
+ int numberOfEnabledInputNodes_ = 0;
44
+
45
+ bool isInitialized_ = false;
46
+ bool isEnabled_ = true;
47
+
48
+ std::size_t lastRenderedFrame_{SIZE_MAX};
49
+
63
50
  ChannelCountMode channelCountMode_ = ChannelCountMode::MAX;
64
51
  ChannelInterpretation channelInterpretation_ =
65
52
  ChannelInterpretation::SPEAKERS;
66
53
 
67
- std::vector<std::shared_ptr<AudioNode>> inputNodes_ = {};
54
+ std::vector<AudioNode *> inputNodes_ = {};
68
55
  std::vector<std::shared_ptr<AudioNode>> outputNodes_ = {};
69
56
 
70
57
  private:
58
+ static std::string toString(ChannelCountMode mode);
59
+ static std::string toString(ChannelInterpretation interpretation);
60
+
71
61
  void cleanup();
62
+ AudioBus *processAudio(AudioBus *outputBus, int framesToProcess);
63
+ virtual void processNode(AudioBus *processingBus, int framesToProcess) = 0;
64
+
65
+ void connectNode(const std::shared_ptr<AudioNode> &node);
66
+ void disconnectNode(const std::shared_ptr<AudioNode> &node);
67
+
68
+ void onInputEnabled();
69
+ void onInputDisabled();
70
+ void onInputConnected(AudioNode *node);
71
+ void onInputDisconnected(AudioNode *node);
72
72
  };
73
73
 
74
74
  } // namespace audioapi
@@ -0,0 +1,75 @@
1
+
2
+ #include "AudioNodeManager.h"
3
+ #include "AudioNode.h"
4
+ #include "Locker.h"
5
+
6
+ namespace audioapi {
7
+
8
+ AudioNodeManager::AudioNodeManager() {}
9
+
10
+ AudioNodeManager::~AudioNodeManager() {
11
+ audioNodesToConnect_.clear();
12
+ sourceNodes_.clear();
13
+ }
14
+
15
+ void AudioNodeManager::addPendingConnection(
16
+ const std::shared_ptr<AudioNode> &from,
17
+ const std::shared_ptr<AudioNode> &to,
18
+ ConnectionType type) {
19
+ Locker lock(getGraphLock());
20
+
21
+ audioNodesToConnect_.push_back(std::make_tuple(from, to, type));
22
+ }
23
+
24
+ void AudioNodeManager::addSourceNode(const std::shared_ptr<AudioNode> &node) {
25
+ Locker lock(getGraphLock());
26
+
27
+ sourceNodes_.push_back(node);
28
+ }
29
+
30
+ void AudioNodeManager::preProcessGraph() {
31
+ if (!Locker::tryLock(getGraphLock())) {
32
+ return;
33
+ }
34
+
35
+ settlePendingConnections();
36
+ removeFinishedSourceNodes();
37
+ }
38
+
39
+ std::mutex &AudioNodeManager::getGraphLock() {
40
+ return graphLock_;
41
+ }
42
+
43
+ void AudioNodeManager::settlePendingConnections() {
44
+ for (auto &connection : audioNodesToConnect_) {
45
+ std::shared_ptr<AudioNode> from = std::get<0>(connection);
46
+ std::shared_ptr<AudioNode> to = std::get<1>(connection);
47
+ ConnectionType type = std::get<2>(connection);
48
+
49
+ if (type == ConnectionType::CONNECT) {
50
+ from->connectNode(to);
51
+ } else {
52
+ from->disconnectNode(to);
53
+ }
54
+ }
55
+
56
+ audioNodesToConnect_.clear();
57
+ }
58
+
59
+ void AudioNodeManager::removeFinishedSourceNodes() {
60
+ for (auto it = sourceNodes_.begin(); it != sourceNodes_.end();) {
61
+ auto currentNode = it->get();
62
+ // Release the source node if use count is equal to 1 (this vector)
63
+ if (!currentNode->isEnabled() && it->use_count() == 1) {
64
+ for (auto &outputNode : currentNode->outputNodes_) {
65
+ currentNode->disconnectNode(outputNode);
66
+ }
67
+
68
+ it = sourceNodes_.erase(it);
69
+ } else {
70
+ ++it;
71
+ }
72
+ }
73
+ }
74
+
75
+ } // namespace audioapi
@@ -0,0 +1,42 @@
1
+ #pragma once
2
+
3
+ #include <memory>
4
+ #include <mutex>
5
+ #include <tuple>
6
+ #include <vector>
7
+
8
+ namespace audioapi {
9
+
10
+ class AudioNode;
11
+
12
+ class AudioNodeManager {
13
+ public:
14
+ enum class ConnectionType { CONNECT, DISCONNECT };
15
+ AudioNodeManager();
16
+ ~AudioNodeManager();
17
+
18
+ void preProcessGraph();
19
+ void addPendingConnection(
20
+ const std::shared_ptr<AudioNode> &from,
21
+ const std::shared_ptr<AudioNode> &to,
22
+ ConnectionType type);
23
+
24
+ void addSourceNode(const std::shared_ptr<AudioNode> &node);
25
+
26
+ std::mutex &getGraphLock();
27
+
28
+ private:
29
+ std::mutex graphLock_;
30
+
31
+ std::vector<std::shared_ptr<AudioNode>> sourceNodes_;
32
+ std::vector<std::tuple<
33
+ std::shared_ptr<AudioNode>,
34
+ std::shared_ptr<AudioNode>,
35
+ ConnectionType>>
36
+ audioNodesToConnect_;
37
+
38
+ void settlePendingConnections();
39
+ void removeFinishedSourceNodes();
40
+ };
41
+
42
+ } // namespace audioapi
@@ -1,10 +1,10 @@
1
1
  #include "AudioParam.h"
2
- #include "AudioContext.h"
2
+ #include "BaseAudioContext.h"
3
3
 
4
4
  namespace audioapi {
5
5
 
6
6
  AudioParam::AudioParam(
7
- AudioContext *context,
7
+ BaseAudioContext *context,
8
8
  float defaultValue,
9
9
  float minValue,
10
10
  float maxValue)
@@ -40,8 +40,7 @@ float AudioParam::getMaxValue() const {
40
40
  }
41
41
 
42
42
  void AudioParam::setValue(float value) {
43
- checkValue(value);
44
- value_ = value;
43
+ value_ = checkValue(value);
45
44
  }
46
45
 
47
46
  float AudioParam::getValueAtTime(double time) {
@@ -66,7 +65,7 @@ float AudioParam::getValueAtTime(double time) {
66
65
  }
67
66
 
68
67
  void AudioParam::setValueAtTime(float value, double time) {
69
- checkValue(value);
68
+ value = checkValue(value);
70
69
  auto calculateValue = [](double, double, float, float endValue, double) {
71
70
  return endValue;
72
71
  };
@@ -76,7 +75,7 @@ void AudioParam::setValueAtTime(float value, double time) {
76
75
  }
77
76
 
78
77
  void AudioParam::linearRampToValueAtTime(float value, double time) {
79
- checkValue(value);
78
+ value = checkValue(value);
80
79
  auto calculateValue = [](double startTime,
81
80
  double endTime,
82
81
  float startValue,
@@ -94,7 +93,7 @@ void AudioParam::linearRampToValueAtTime(float value, double time) {
94
93
  }
95
94
 
96
95
  void AudioParam::exponentialRampToValueAtTime(float value, double time) {
97
- checkValue(value);
96
+ value = checkValue(value);
98
97
  auto calculateValue = [](double startTime,
99
98
  double endTime,
100
99
  float startValue,
@@ -111,10 +110,8 @@ void AudioParam::exponentialRampToValueAtTime(float value, double time) {
111
110
  changesQueue_.emplace(paramChange);
112
111
  }
113
112
 
114
- void AudioParam::checkValue(float value) const {
115
- if (value < minValue_ || value > maxValue_) {
116
- throw std::invalid_argument("Value out of range");
117
- }
113
+ float AudioParam::checkValue(float value) const {
114
+ return std::clamp(value, minValue_, maxValue_);
118
115
  }
119
116
 
120
117
  double AudioParam::getStartTime() {