react-native-audio-api 0.2.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.
- package/android/src/main/cpp/AudioPlayer/AudioPlayer.cpp +16 -7
- package/android/src/main/cpp/AudioPlayer/AudioPlayer.h +3 -2
- package/common/cpp/AudioAPIInstaller/AudioAPIInstallerHostObject.cpp +5 -3
- package/common/cpp/AudioAPIInstaller/AudioAPIInstallerHostObject.h +5 -1
- package/common/cpp/HostObjects/AudioBufferHostObject.cpp +6 -0
- package/common/cpp/HostObjects/AudioContextHostObject.cpp +2 -2
- package/common/cpp/HostObjects/AudioContextHostObject.h +4 -3
- package/common/cpp/HostObjects/BaseAudioContextHostObject.cpp +28 -2
- package/common/cpp/HostObjects/BaseAudioContextHostObject.h +3 -1
- package/common/cpp/core/AudioArray.cpp +28 -14
- package/common/cpp/core/AudioArray.h +20 -14
- package/common/cpp/core/AudioBuffer.cpp +14 -11
- package/common/cpp/core/AudioBuffer.h +1 -0
- package/common/cpp/core/AudioBufferSourceNode.cpp +29 -19
- package/common/cpp/core/AudioBufferSourceNode.h +1 -1
- package/common/cpp/core/AudioBus.cpp +276 -115
- package/common/cpp/core/AudioBus.h +29 -9
- package/common/cpp/core/AudioContext.cpp +5 -9
- package/common/cpp/core/AudioDestinationNode.cpp +10 -8
- package/common/cpp/core/AudioDestinationNode.h +4 -4
- package/common/cpp/core/AudioNode.cpp +25 -17
- package/common/cpp/core/AudioNode.h +5 -5
- package/common/cpp/core/AudioNodeManager.cpp +10 -7
- package/common/cpp/core/AudioNodeManager.h +11 -4
- package/common/cpp/core/AudioScheduledSourceNode.cpp +2 -2
- package/common/cpp/core/BaseAudioContext.cpp +46 -12
- package/common/cpp/core/BaseAudioContext.h +12 -5
- package/common/cpp/core/BiquadFilterNode.cpp +5 -3
- package/common/cpp/core/GainNode.cpp +1 -1
- package/common/cpp/core/OscillatorNode.cpp +4 -4
- package/common/cpp/core/OscillatorNode.h +2 -2
- package/common/cpp/core/StereoPannerNode.cpp +10 -7
- package/common/cpp/core/StereoPannerNode.h +1 -1
- package/common/cpp/utils/FFTFrame.h +5 -1
- package/common/cpp/utils/JsiPromise.cpp +59 -0
- package/common/cpp/utils/JsiPromise.h +42 -0
- package/common/cpp/utils/Locker.h +8 -6
- package/common/cpp/utils/VectorMath.cpp +71 -55
- package/common/cpp/utils/android/FFTFrame.cpp +12 -11
- package/common/cpp/utils/ios/FFTFrame.cpp +6 -1
- package/common/cpp/wrappers/BaseAudioContextWrapper.cpp +7 -0
- package/common/cpp/wrappers/BaseAudioContextWrapper.h +1 -0
- package/ios/AudioAPIModule.mm +3 -1
- package/ios/AudioDecoder/AudioDecoder.h +17 -0
- package/ios/AudioDecoder/AudioDecoder.m +167 -0
- package/ios/AudioDecoder/IOSAudioDecoder.h +26 -0
- package/ios/AudioDecoder/IOSAudioDecoder.mm +40 -0
- package/ios/AudioPlayer/AudioPlayer.h +1 -1
- package/ios/AudioPlayer/AudioPlayer.m +0 -1
- package/ios/AudioPlayer/IOSAudioPlayer.h +5 -5
- package/ios/AudioPlayer/IOSAudioPlayer.mm +4 -3
- package/lib/module/core/BaseAudioContext.js +5 -0
- package/lib/module/core/BaseAudioContext.js.map +1 -1
- package/lib/module/index.js +235 -17
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.native.js +18 -0
- package/lib/module/index.native.js.map +1 -0
- package/lib/module/utils/resolveAudioSource.js +10 -0
- package/lib/module/utils/resolveAudioSource.js.map +1 -0
- package/lib/typescript/core/BaseAudioContext.d.ts +2 -1
- package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -1
- package/lib/typescript/core/types.d.ts +6 -0
- package/lib/typescript/core/types.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +100 -13
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/index.native.d.ts +14 -0
- package/lib/typescript/index.native.d.ts.map +1 -0
- package/lib/typescript/interfaces.d.ts +1 -0
- package/lib/typescript/interfaces.d.ts.map +1 -1
- package/lib/typescript/utils/resolveAudioSource.d.ts +3 -0
- package/lib/typescript/utils/resolveAudioSource.d.ts.map +1 -0
- package/package.json +4 -2
- package/src/core/BaseAudioContext.ts +12 -1
- package/src/core/types.ts +7 -0
- package/src/index.native.ts +25 -0
- package/src/index.ts +413 -19
- package/src/interfaces.ts +1 -0
- package/src/utils/resolveAudioSource.ts +14 -0
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
|
|
2
|
-
#include "AudioBus.h"
|
|
3
|
-
#include "Constants.h"
|
|
4
|
-
#include "AudioArray.h"
|
|
5
2
|
#include "AudioPlayer.h"
|
|
3
|
+
#include "AudioArray.h"
|
|
4
|
+
#include "AudioBus.h"
|
|
6
5
|
#include "AudioContext.h"
|
|
6
|
+
#include "Constants.h"
|
|
7
7
|
|
|
8
8
|
namespace audioapi {
|
|
9
9
|
|
|
10
|
-
AudioPlayer::AudioPlayer(
|
|
10
|
+
AudioPlayer::AudioPlayer(
|
|
11
|
+
const std::function<void(AudioBus *, int)> &renderAudio)
|
|
11
12
|
: renderAudio_(renderAudio) {
|
|
12
13
|
AudioStreamBuilder builder;
|
|
13
14
|
|
|
@@ -20,7 +21,9 @@ AudioPlayer::AudioPlayer(const std::function<void(AudioBus*, int)> &renderAudio)
|
|
|
20
21
|
->setDataCallback(this)
|
|
21
22
|
->openStream(mStream_);
|
|
22
23
|
|
|
23
|
-
mBus_ = std::make_shared<AudioBus>(
|
|
24
|
+
mBus_ = std::make_shared<AudioBus>(
|
|
25
|
+
getSampleRate(), getBufferSizeInFrames(), CHANNEL_COUNT);
|
|
26
|
+
isInitialized_ = true;
|
|
24
27
|
}
|
|
25
28
|
|
|
26
29
|
int AudioPlayer::getSampleRate() const {
|
|
@@ -38,6 +41,8 @@ void AudioPlayer::start() {
|
|
|
38
41
|
}
|
|
39
42
|
|
|
40
43
|
void AudioPlayer::stop() {
|
|
44
|
+
isInitialized_ = false;
|
|
45
|
+
|
|
41
46
|
if (mStream_) {
|
|
42
47
|
mStream_->requestStop();
|
|
43
48
|
mStream_->close();
|
|
@@ -49,14 +54,18 @@ DataCallbackResult AudioPlayer::onAudioReady(
|
|
|
49
54
|
AudioStream *oboeStream,
|
|
50
55
|
void *audioData,
|
|
51
56
|
int32_t numFrames) {
|
|
52
|
-
|
|
57
|
+
if (!isInitialized_) {
|
|
58
|
+
return DataCallbackResult::Continue;
|
|
59
|
+
}
|
|
53
60
|
|
|
61
|
+
auto buffer = static_cast<float *>(audioData);
|
|
54
62
|
renderAudio_(mBus_.get(), numFrames);
|
|
55
63
|
|
|
56
64
|
// TODO: optimize this with SIMD?
|
|
57
65
|
for (int32_t i = 0; i < numFrames; i += 1) {
|
|
58
66
|
for (int channel = 0; channel < CHANNEL_COUNT; channel += 1) {
|
|
59
|
-
buffer[i * CHANNEL_COUNT + channel] =
|
|
67
|
+
buffer[i * CHANNEL_COUNT + channel] =
|
|
68
|
+
mBus_->getChannel(channel)->getData()[i];
|
|
60
69
|
}
|
|
61
70
|
}
|
|
62
71
|
|
|
@@ -12,7 +12,7 @@ class AudioBus;
|
|
|
12
12
|
|
|
13
13
|
class AudioPlayer : public AudioStreamDataCallback {
|
|
14
14
|
public:
|
|
15
|
-
explicit AudioPlayer(const std::function<void(AudioBus*, int)> &renderAudio);
|
|
15
|
+
explicit AudioPlayer(const std::function<void(AudioBus *, int)> &renderAudio);
|
|
16
16
|
|
|
17
17
|
int getSampleRate() const;
|
|
18
18
|
int getBufferSizeInFrames() const;
|
|
@@ -25,9 +25,10 @@ class AudioPlayer : public AudioStreamDataCallback {
|
|
|
25
25
|
int32_t numFrames) override;
|
|
26
26
|
|
|
27
27
|
private:
|
|
28
|
-
std::function<void(AudioBus*, int)> renderAudio_;
|
|
28
|
+
std::function<void(AudioBus *, int)> renderAudio_;
|
|
29
29
|
std::shared_ptr<AudioStream> mStream_;
|
|
30
30
|
std::shared_ptr<AudioBus> mBus_;
|
|
31
|
+
bool isInitialized_ = false;
|
|
31
32
|
};
|
|
32
33
|
|
|
33
34
|
} // namespace audioapi
|
|
@@ -4,8 +4,10 @@ namespace audioapi {
|
|
|
4
4
|
using namespace facebook;
|
|
5
5
|
|
|
6
6
|
AudioAPIInstallerHostObject::AudioAPIInstallerHostObject(
|
|
7
|
-
const std::shared_ptr<AudioAPIInstallerWrapper> &wrapper)
|
|
8
|
-
: wrapper_(wrapper) {
|
|
7
|
+
const std::shared_ptr<AudioAPIInstallerWrapper> &wrapper, jsi::Runtime* runtime, const std::shared_ptr<facebook::react::CallInvoker> &jsInvoker)
|
|
8
|
+
: wrapper_(wrapper) {
|
|
9
|
+
promiseVendor_ = std::make_shared<JsiPromise::PromiseVendor>(runtime, jsInvoker);
|
|
10
|
+
}
|
|
9
11
|
|
|
10
12
|
std::vector<jsi::PropNameID> AudioAPIInstallerHostObject::getPropertyNames(
|
|
11
13
|
jsi::Runtime &runtime) {
|
|
@@ -32,7 +34,7 @@ jsi::Value AudioAPIInstallerHostObject::get(
|
|
|
32
34
|
size_t count) -> jsi::Value {
|
|
33
35
|
auto audioContext = wrapper_->createAudioContext();
|
|
34
36
|
auto audioContextHostObject =
|
|
35
|
-
AudioContextHostObject::createFromWrapper(audioContext);
|
|
37
|
+
AudioContextHostObject::createFromWrapper(audioContext, promiseVendor_);
|
|
36
38
|
return jsi::Object::createFromHostObject(
|
|
37
39
|
runtime, audioContextHostObject);
|
|
38
40
|
});
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
|
+
#include <ReactCommon/CallInvoker.h>
|
|
3
4
|
#include <jsi/jsi.h>
|
|
4
5
|
#include <memory>
|
|
5
6
|
#include <utility>
|
|
6
7
|
#include <vector>
|
|
7
8
|
|
|
9
|
+
|
|
8
10
|
#include "AudioAPIInstallerWrapper.h"
|
|
9
11
|
#include "AudioContextHostObject.h"
|
|
12
|
+
#include "JsiPromise.h"
|
|
10
13
|
|
|
11
14
|
namespace audioapi {
|
|
12
15
|
using namespace facebook;
|
|
@@ -16,7 +19,7 @@ class AudioAPIInstallerWrapper;
|
|
|
16
19
|
class AudioAPIInstallerHostObject : public jsi::HostObject {
|
|
17
20
|
public:
|
|
18
21
|
explicit AudioAPIInstallerHostObject(
|
|
19
|
-
const std::shared_ptr<AudioAPIInstallerWrapper> &wrapper);
|
|
22
|
+
const std::shared_ptr<AudioAPIInstallerWrapper> &wrapper, jsi::Runtime* runtime, const std::shared_ptr<react::CallInvoker> &jsInvoker);
|
|
20
23
|
|
|
21
24
|
#ifdef ANDROID
|
|
22
25
|
static void createAndInstallFromWrapper(
|
|
@@ -41,5 +44,6 @@ class AudioAPIInstallerHostObject : public jsi::HostObject {
|
|
|
41
44
|
|
|
42
45
|
private:
|
|
43
46
|
std::shared_ptr<AudioAPIInstallerWrapper> wrapper_;
|
|
47
|
+
std::shared_ptr<JsiPromise::PromiseVendor> promiseVendor_;
|
|
44
48
|
};
|
|
45
49
|
} // namespace audioapi
|
|
@@ -128,6 +128,12 @@ jsi::Value AudioBufferHostObject::get(
|
|
|
128
128
|
});
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
// `decodeAudioData` is a method that returns a promise to AudioBufferHostObject
|
|
132
|
+
// It seems that async/await checks for the presence of `then` method on the object
|
|
133
|
+
if (propName == "then") {
|
|
134
|
+
return jsi::Value::undefined();
|
|
135
|
+
}
|
|
136
|
+
|
|
131
137
|
throw std::runtime_error("Not yet implemented!");
|
|
132
138
|
}
|
|
133
139
|
|
|
@@ -4,8 +4,8 @@ namespace audioapi {
|
|
|
4
4
|
using namespace facebook;
|
|
5
5
|
|
|
6
6
|
AudioContextHostObject::AudioContextHostObject(
|
|
7
|
-
const std::shared_ptr<AudioContextWrapper> &wrapper)
|
|
8
|
-
: BaseAudioContextHostObject(wrapper) {}
|
|
7
|
+
const std::shared_ptr<AudioContextWrapper> &wrapper, std::shared_ptr<JsiPromise::PromiseVendor> promiseVendor)
|
|
8
|
+
: BaseAudioContextHostObject(wrapper, promiseVendor) {}
|
|
9
9
|
|
|
10
10
|
std::vector<jsi::PropNameID> AudioContextHostObject::getPropertyNames(
|
|
11
11
|
jsi::Runtime &runtime) {
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
#include <memory>
|
|
5
5
|
#include <vector>
|
|
6
6
|
|
|
7
|
+
#include"JsiPromise.h"
|
|
7
8
|
#include "AudioContextWrapper.h"
|
|
8
9
|
#include "BaseAudioContextHostObject.h"
|
|
9
10
|
|
|
@@ -13,7 +14,7 @@ using namespace facebook;
|
|
|
13
14
|
class AudioContextHostObject : public BaseAudioContextHostObject {
|
|
14
15
|
public:
|
|
15
16
|
explicit AudioContextHostObject(
|
|
16
|
-
const std::shared_ptr<AudioContextWrapper> &wrapper);
|
|
17
|
+
const std::shared_ptr<AudioContextWrapper> &wrapper, std::shared_ptr<JsiPromise::PromiseVendor> promiseVendor);
|
|
17
18
|
|
|
18
19
|
jsi::Value get(jsi::Runtime &runtime, const jsi::PropNameID &name) override;
|
|
19
20
|
|
|
@@ -25,8 +26,8 @@ class AudioContextHostObject : public BaseAudioContextHostObject {
|
|
|
25
26
|
std::vector<jsi::PropNameID> getPropertyNames(jsi::Runtime &rt) override;
|
|
26
27
|
|
|
27
28
|
static std::shared_ptr<AudioContextHostObject> createFromWrapper(
|
|
28
|
-
const std::shared_ptr<AudioContextWrapper> &wrapper) {
|
|
29
|
-
return std::make_shared<AudioContextHostObject>(wrapper);
|
|
29
|
+
const std::shared_ptr<AudioContextWrapper> &wrapper, std::shared_ptr<JsiPromise::PromiseVendor> promiseVendor) {
|
|
30
|
+
return std::make_shared<AudioContextHostObject>(wrapper, promiseVendor);
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
private:
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
+
#include <thread>
|
|
2
|
+
|
|
1
3
|
#include "BaseAudioContextHostObject.h"
|
|
2
4
|
|
|
3
5
|
namespace audioapi {
|
|
4
6
|
using namespace facebook;
|
|
5
7
|
|
|
6
8
|
BaseAudioContextHostObject::BaseAudioContextHostObject(
|
|
7
|
-
const std::shared_ptr<BaseAudioContextWrapper> &wrapper)
|
|
8
|
-
: wrapper_(wrapper) {
|
|
9
|
+
const std::shared_ptr<BaseAudioContextWrapper> &wrapper, std::shared_ptr<JsiPromise::PromiseVendor> promiseVendor)
|
|
10
|
+
: wrapper_(wrapper), promiseVendor_(promiseVendor) {
|
|
9
11
|
auto destinationNodeWrapper = wrapper_->getDestination();
|
|
10
12
|
destination_ =
|
|
11
13
|
AudioDestinationNodeHostObject::createFromWrapper(destinationNodeWrapper);
|
|
@@ -30,6 +32,8 @@ std::vector<jsi::PropNameID> BaseAudioContextHostObject::getPropertyNames(
|
|
|
30
32
|
propertyNames.push_back(jsi::PropNameID::forUtf8(runtime, "createBuffer"));
|
|
31
33
|
propertyNames.push_back(
|
|
32
34
|
jsi::PropNameID::forUtf8(runtime, "createPeriodicWave"));
|
|
35
|
+
propertyNames.push_back(
|
|
36
|
+
jsi::PropNameID::forUtf8(runtime, "decodeAudioDataSource"));
|
|
33
37
|
return propertyNames;
|
|
34
38
|
}
|
|
35
39
|
|
|
@@ -200,6 +204,28 @@ jsi::Value BaseAudioContextHostObject::get(
|
|
|
200
204
|
});
|
|
201
205
|
}
|
|
202
206
|
|
|
207
|
+
if (propName == "decodeAudioDataSource") {
|
|
208
|
+
auto decode = [this](jsi::Runtime& runtime,
|
|
209
|
+
const jsi::Value&,
|
|
210
|
+
const jsi::Value* arguments,
|
|
211
|
+
size_t count) -> jsi::Value {
|
|
212
|
+
auto sourcePath = arguments[0].getString(runtime).utf8(runtime);
|
|
213
|
+
|
|
214
|
+
auto promise = promiseVendor_->createPromise([this, &runtime, sourcePath](std::shared_ptr<JsiPromise::Promise> promise) {
|
|
215
|
+
std::thread([this, &runtime, sourcePath, promise = std::move(promise)]() {
|
|
216
|
+
auto results = wrapper_->decodeAudioDataSource(sourcePath);
|
|
217
|
+
auto audioBufferHostObject = AudioBufferHostObject::createFromWrapper(results);
|
|
218
|
+
|
|
219
|
+
promise->resolve(jsi::Object::createFromHostObject(runtime, audioBufferHostObject));
|
|
220
|
+
}).detach();
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
return promise;
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
return jsi::Function::createFromHostFunction(runtime, propNameId, 1, decode);
|
|
227
|
+
}
|
|
228
|
+
|
|
203
229
|
throw std::runtime_error("Not yet implemented!");
|
|
204
230
|
}
|
|
205
231
|
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
#include <utility>
|
|
6
6
|
#include <vector>
|
|
7
7
|
|
|
8
|
+
#include "JsiPromise.h"
|
|
8
9
|
#include "AudioBufferHostObject.h"
|
|
9
10
|
#include "AudioBufferSourceNodeHostObject.h"
|
|
10
11
|
#include "AudioDestinationNodeHostObject.h"
|
|
@@ -21,7 +22,7 @@ using namespace facebook;
|
|
|
21
22
|
class BaseAudioContextHostObject : public jsi::HostObject {
|
|
22
23
|
public:
|
|
23
24
|
explicit BaseAudioContextHostObject(
|
|
24
|
-
const std::shared_ptr<BaseAudioContextWrapper> &wrapper);
|
|
25
|
+
const std::shared_ptr<BaseAudioContextWrapper> &wrapper, std::shared_ptr<JsiPromise::PromiseVendor> promiseVendor);
|
|
25
26
|
|
|
26
27
|
jsi::Value get(jsi::Runtime &runtime, const jsi::PropNameID &name) override;
|
|
27
28
|
|
|
@@ -35,5 +36,6 @@ class BaseAudioContextHostObject : public jsi::HostObject {
|
|
|
35
36
|
protected:
|
|
36
37
|
std::shared_ptr<BaseAudioContextWrapper> wrapper_;
|
|
37
38
|
std::shared_ptr<AudioDestinationNodeHostObject> destination_;
|
|
39
|
+
std::shared_ptr<JsiPromise::PromiseVendor> promiseVendor_;
|
|
38
40
|
};
|
|
39
41
|
} // namespace audioapi
|
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
|
|
6
6
|
namespace audioapi {
|
|
7
7
|
|
|
8
|
-
AudioArray::AudioArray(int size) :
|
|
8
|
+
AudioArray::AudioArray(int size) : data_(nullptr), size_(size) {
|
|
9
9
|
resize(size);
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
AudioArray::~AudioArray() {
|
|
13
13
|
if (data_) {
|
|
14
14
|
delete[] data_;
|
|
15
|
-
data_ =
|
|
15
|
+
data_ = nullptr;
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
|
|
@@ -20,15 +20,15 @@ int AudioArray::getSize() const {
|
|
|
20
20
|
return size_;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
float*
|
|
23
|
+
float *AudioArray::getData() const {
|
|
24
24
|
return data_;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
float&
|
|
27
|
+
float &AudioArray::operator[](int index) {
|
|
28
28
|
return data_[index];
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
const float&
|
|
31
|
+
const float &AudioArray::operator[](int index) const {
|
|
32
32
|
return data_[index];
|
|
33
33
|
}
|
|
34
34
|
|
|
@@ -75,29 +75,43 @@ void AudioArray::zero(int start, int length) {
|
|
|
75
75
|
memset(data_ + start, 0, length * sizeof(float));
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
void AudioArray::sum(const AudioArray*
|
|
78
|
+
void AudioArray::sum(const AudioArray *source) {
|
|
79
79
|
sum(source, 0, 0, size_);
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
void AudioArray::sum(const AudioArray*
|
|
82
|
+
void AudioArray::sum(const AudioArray *source, int start, int length) {
|
|
83
83
|
sum(source, start, start, length);
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
void AudioArray::sum(
|
|
87
|
-
|
|
86
|
+
void AudioArray::sum(
|
|
87
|
+
const AudioArray *source,
|
|
88
|
+
int sourceStart,
|
|
89
|
+
int destinationStart,
|
|
90
|
+
int length) {
|
|
91
|
+
VectorMath::add(
|
|
92
|
+
data_ + destinationStart,
|
|
93
|
+
source->getData() + sourceStart,
|
|
94
|
+
data_ + destinationStart,
|
|
95
|
+
length);
|
|
88
96
|
}
|
|
89
97
|
|
|
90
|
-
void AudioArray::copy(const AudioArray*
|
|
98
|
+
void AudioArray::copy(const AudioArray *source) {
|
|
91
99
|
copy(source, 0, size_);
|
|
92
100
|
}
|
|
93
101
|
|
|
94
|
-
void AudioArray::copy(const AudioArray*
|
|
102
|
+
void AudioArray::copy(const AudioArray *source, int start, int length) {
|
|
95
103
|
copy(source, start, start, length);
|
|
96
104
|
}
|
|
97
105
|
|
|
98
|
-
void AudioArray::copy(
|
|
99
|
-
|
|
106
|
+
void AudioArray::copy(
|
|
107
|
+
const AudioArray *source,
|
|
108
|
+
int sourceStart,
|
|
109
|
+
int destinationStart,
|
|
110
|
+
int length) {
|
|
111
|
+
memcpy(
|
|
112
|
+
data_ + destinationStart,
|
|
113
|
+
source->getData() + sourceStart,
|
|
114
|
+
length * sizeof(float));
|
|
100
115
|
}
|
|
101
116
|
|
|
102
117
|
} // namespace audioapi
|
|
103
|
-
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
|
-
#include <memory>
|
|
4
3
|
#include <algorithm>
|
|
4
|
+
#include <memory>
|
|
5
5
|
|
|
6
6
|
namespace audioapi {
|
|
7
7
|
|
|
@@ -11,28 +11,34 @@ class AudioArray {
|
|
|
11
11
|
~AudioArray();
|
|
12
12
|
|
|
13
13
|
[[nodiscard]] int getSize() const;
|
|
14
|
-
float*
|
|
15
|
-
|
|
14
|
+
[[nodiscard]] float *getData() const;
|
|
16
15
|
|
|
17
|
-
float&
|
|
18
|
-
const float&
|
|
16
|
+
float &operator[](int index);
|
|
17
|
+
const float &operator[](int index) const;
|
|
19
18
|
|
|
20
19
|
void normalize();
|
|
21
20
|
void resize(int size);
|
|
22
21
|
void scale(float value);
|
|
23
|
-
float getMaxAbsValue() const;
|
|
22
|
+
[[nodiscard]] float getMaxAbsValue() const;
|
|
24
23
|
|
|
25
24
|
void zero();
|
|
26
25
|
void zero(int start, int length);
|
|
27
26
|
|
|
28
|
-
void sum(const AudioArray*
|
|
29
|
-
void sum(const AudioArray*
|
|
30
|
-
void sum(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
27
|
+
void sum(const AudioArray *source);
|
|
28
|
+
void sum(const AudioArray *source, int start, int length);
|
|
29
|
+
void sum(
|
|
30
|
+
const AudioArray *source,
|
|
31
|
+
int sourceStart,
|
|
32
|
+
int destinationStart,
|
|
33
|
+
int length);
|
|
34
|
+
|
|
35
|
+
void copy(const AudioArray *source);
|
|
36
|
+
void copy(const AudioArray *source, int start, int length);
|
|
37
|
+
void copy(
|
|
38
|
+
const AudioArray *source,
|
|
39
|
+
int sourceStart,
|
|
40
|
+
int destinationStart,
|
|
41
|
+
int length);
|
|
36
42
|
|
|
37
43
|
private:
|
|
38
44
|
float *data_;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
#include "AudioBus.h"
|
|
2
|
-
#include "AudioArray.h"
|
|
3
1
|
#include "AudioBuffer.h"
|
|
2
|
+
#include "AudioArray.h"
|
|
3
|
+
#include "AudioBus.h"
|
|
4
4
|
|
|
5
5
|
namespace audioapi {
|
|
6
6
|
|
|
@@ -8,6 +8,10 @@ AudioBuffer::AudioBuffer(int numberOfChannels, int length, int sampleRate) {
|
|
|
8
8
|
bus_ = std::make_shared<AudioBus>(sampleRate, length, numberOfChannels);
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
AudioBuffer::AudioBuffer(AudioBus *bus) {
|
|
12
|
+
bus_ = std::shared_ptr<AudioBus>(bus);
|
|
13
|
+
}
|
|
14
|
+
|
|
11
15
|
int AudioBuffer::getLength() const {
|
|
12
16
|
return bus_->getSize();
|
|
13
17
|
}
|
|
@@ -24,7 +28,7 @@ double AudioBuffer::getDuration() const {
|
|
|
24
28
|
return static_cast<double>(getLength()) / getSampleRate();
|
|
25
29
|
}
|
|
26
30
|
|
|
27
|
-
float*
|
|
31
|
+
float *AudioBuffer::getChannelData(int channel) const {
|
|
28
32
|
return bus_->getChannel(channel)->getData();
|
|
29
33
|
}
|
|
30
34
|
|
|
@@ -34,10 +38,10 @@ void AudioBuffer::copyFromChannel(
|
|
|
34
38
|
int channelNumber,
|
|
35
39
|
int startInChannel) const {
|
|
36
40
|
memcpy(
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
destination,
|
|
42
|
+
bus_->getChannel(channelNumber)->getData() + startInChannel,
|
|
43
|
+
std::min(destinationLength, getLength() - startInChannel) *
|
|
44
|
+
sizeof(float));
|
|
41
45
|
}
|
|
42
46
|
|
|
43
47
|
void AudioBuffer::copyToChannel(
|
|
@@ -46,10 +50,9 @@ void AudioBuffer::copyToChannel(
|
|
|
46
50
|
int channelNumber,
|
|
47
51
|
int startInChannel) {
|
|
48
52
|
memcpy(
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
);
|
|
53
|
+
bus_->getChannel(channelNumber)->getData() + startInChannel,
|
|
54
|
+
source,
|
|
55
|
+
std::min(sourceLength, getLength() - startInChannel) * sizeof(float));
|
|
53
56
|
}
|
|
54
57
|
|
|
55
58
|
} // namespace audioapi
|
|
@@ -12,6 +12,7 @@ class AudioBus;
|
|
|
12
12
|
class AudioBuffer : public std::enable_shared_from_this<AudioBuffer> {
|
|
13
13
|
public:
|
|
14
14
|
explicit AudioBuffer(int numberOfChannels, int length, int sampleRate);
|
|
15
|
+
explicit AudioBuffer(AudioBus *bus);
|
|
15
16
|
|
|
16
17
|
[[nodiscard]] int getLength() const;
|
|
17
18
|
[[nodiscard]] int getSampleRate() const;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#include <algorithm>
|
|
2
2
|
|
|
3
|
-
#include "AudioBus.h"
|
|
4
3
|
#include "AudioArray.h"
|
|
5
|
-
#include "BaseAudioContext.h"
|
|
6
4
|
#include "AudioBufferSourceNode.h"
|
|
5
|
+
#include "AudioBus.h"
|
|
6
|
+
#include "BaseAudioContext.h"
|
|
7
7
|
|
|
8
8
|
namespace audioapi {
|
|
9
9
|
|
|
@@ -28,7 +28,6 @@ void AudioBufferSourceNode::setLoop(bool loop) {
|
|
|
28
28
|
|
|
29
29
|
void AudioBufferSourceNode::setBuffer(
|
|
30
30
|
const std::shared_ptr<AudioBuffer> &buffer) {
|
|
31
|
-
|
|
32
31
|
if (!buffer) {
|
|
33
32
|
buffer_ = std::shared_ptr<AudioBuffer>(nullptr);
|
|
34
33
|
return;
|
|
@@ -37,16 +36,20 @@ void AudioBufferSourceNode::setBuffer(
|
|
|
37
36
|
buffer_ = buffer;
|
|
38
37
|
}
|
|
39
38
|
|
|
40
|
-
// Note: AudioBus copy method will use memcpy if the source buffer and system
|
|
41
|
-
// otherwise it will use the summing
|
|
42
|
-
|
|
39
|
+
// Note: AudioBus copy method will use memcpy if the source buffer and system
|
|
40
|
+
// processing bus have same channel count, otherwise it will use the summing
|
|
41
|
+
// function taking care of up/down mixing.
|
|
42
|
+
void AudioBufferSourceNode::processNode(
|
|
43
|
+
AudioBus *processingBus,
|
|
44
|
+
int framesToProcess) {
|
|
43
45
|
// No audio data to fill, zero the output and return.
|
|
44
46
|
if (!isPlaying() || !buffer_ || buffer_->getLength() == 0) {
|
|
45
47
|
processingBus->zero();
|
|
46
48
|
return;
|
|
47
49
|
}
|
|
48
50
|
|
|
49
|
-
// Easiest case, the buffer is the same length as the number of frames to
|
|
51
|
+
// Easiest case, the buffer is the same length as the number of frames to
|
|
52
|
+
// process, just copy the data.
|
|
50
53
|
if (framesToProcess == buffer_->getLength()) {
|
|
51
54
|
processingBus->copy(buffer_->bus_.get());
|
|
52
55
|
|
|
@@ -65,9 +68,12 @@ void AudioBufferSourceNode::processNode(AudioBus* processingBus, int framesToPro
|
|
|
65
68
|
int framesToCopy = 0;
|
|
66
69
|
|
|
67
70
|
while (framesToProcess - outputBusIndex > 0) {
|
|
68
|
-
framesToCopy = std::min(
|
|
71
|
+
framesToCopy = std::min(
|
|
72
|
+
framesToProcess - outputBusIndex,
|
|
73
|
+
buffer_->getLength() - bufferIndex_);
|
|
69
74
|
|
|
70
|
-
processingBus->copy(
|
|
75
|
+
processingBus->copy(
|
|
76
|
+
buffer_->bus_.get(), bufferIndex_, outputBusIndex, framesToCopy);
|
|
71
77
|
|
|
72
78
|
bufferIndex_ += framesToCopy;
|
|
73
79
|
outputBusIndex += framesToCopy;
|
|
@@ -76,12 +82,11 @@ void AudioBufferSourceNode::processNode(AudioBus* processingBus, int framesToPro
|
|
|
76
82
|
continue;
|
|
77
83
|
}
|
|
78
84
|
|
|
79
|
-
|
|
80
85
|
bufferIndex_ %= buffer_->getLength();
|
|
81
86
|
|
|
82
87
|
if (!loop_) {
|
|
83
|
-
|
|
84
|
-
|
|
88
|
+
playbackState_ = PlaybackState::FINISHED;
|
|
89
|
+
disable();
|
|
85
90
|
|
|
86
91
|
if (framesToProcess - outputBusIndex > 0) {
|
|
87
92
|
processingBus->zero(outputBusIndex, framesToProcess - outputBusIndex);
|
|
@@ -94,9 +99,11 @@ void AudioBufferSourceNode::processNode(AudioBus* processingBus, int framesToPro
|
|
|
94
99
|
|
|
95
100
|
// processing bus is longer than the source buffer
|
|
96
101
|
if (!loop_) {
|
|
97
|
-
// If we don't loop the buffer, copy it once and zero the remaining
|
|
102
|
+
// If we don't loop the buffer, copy it once and zero the remaining
|
|
103
|
+
// processing bus frames.
|
|
98
104
|
processingBus->copy(buffer_->bus_.get());
|
|
99
|
-
processingBus->zero(
|
|
105
|
+
processingBus->zero(
|
|
106
|
+
buffer_->getLength(), framesToProcess - buffer_->getLength());
|
|
100
107
|
|
|
101
108
|
playbackState_ = PlaybackState::FINISHED;
|
|
102
109
|
disable();
|
|
@@ -104,9 +111,10 @@ void AudioBufferSourceNode::processNode(AudioBus* processingBus, int framesToPro
|
|
|
104
111
|
return;
|
|
105
112
|
}
|
|
106
113
|
|
|
107
|
-
// If we loop the buffer, we need to loop the buffer framesToProcess /
|
|
108
|
-
// There might also be a remainder of frames to copy after
|
|
109
|
-
// which will also carry over some buffer frames to the next render
|
|
114
|
+
// If we loop the buffer, we need to loop the buffer framesToProcess /
|
|
115
|
+
// bufferSize times There might also be a remainder of frames to copy after
|
|
116
|
+
// the loop, which will also carry over some buffer frames to the next render
|
|
117
|
+
// quantum.
|
|
110
118
|
int processingBusPosition = 0;
|
|
111
119
|
int bufferSize = buffer_->getLength();
|
|
112
120
|
int remainingFrames = framesToProcess - framesToProcess / bufferSize;
|
|
@@ -125,9 +133,11 @@ void AudioBufferSourceNode::processNode(AudioBus* processingBus, int framesToPro
|
|
|
125
133
|
processingBusPosition += bufferSize;
|
|
126
134
|
}
|
|
127
135
|
|
|
128
|
-
// Fill in the remaining frames from the processing buffer and update buffer
|
|
136
|
+
// Fill in the remaining frames from the processing buffer and update buffer
|
|
137
|
+
// index for next render quantum.
|
|
129
138
|
if (remainingFrames > 0) {
|
|
130
|
-
processingBus->copy(
|
|
139
|
+
processingBus->copy(
|
|
140
|
+
buffer_->bus_.get(), 0, processingBusPosition, remainingFrames);
|
|
131
141
|
bufferIndex_ = remainingFrames;
|
|
132
142
|
}
|
|
133
143
|
}
|
|
@@ -19,7 +19,7 @@ class AudioBufferSourceNode : public AudioScheduledSourceNode {
|
|
|
19
19
|
void setBuffer(const std::shared_ptr<AudioBuffer> &buffer);
|
|
20
20
|
|
|
21
21
|
protected:
|
|
22
|
-
void processNode(AudioBus*
|
|
22
|
+
void processNode(AudioBus *processingBus, int framesToProcess) override;
|
|
23
23
|
|
|
24
24
|
private:
|
|
25
25
|
bool loop_;
|