react-native-audio-api 0.3.0-rc1 → 0.3.1
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/CMakeLists.txt +4 -4
- package/android/build.gradle +1 -3
- package/android/libs/include/miniaudio.h +92621 -0
- package/android/src/main/cpp/AudioAPIInstaller/AudioAPIInstaller.cpp +10 -12
- package/android/src/main/cpp/AudioAPIInstaller/AudioAPIInstaller.h +16 -9
- package/android/src/main/cpp/AudioDecoder/AudioDecoder.cpp +64 -0
- package/android/src/main/cpp/AudioDecoder/AudioDecoder.h +21 -0
- package/android/src/main/cpp/AudioPlayer/AudioPlayer.h +2 -2
- package/android/src/main/java/com/swmansion/audioapi/module/AudioAPIInstaller.kt +14 -4
- package/android/src/main/java/com/swmansion/audioapi/nativemodules/AudioAPIModule.kt +2 -3
- package/common/cpp/AudioAPIInstaller/AudioAPIInstallerHostObject.h +26 -27
- package/common/cpp/HostObjects/AudioBufferHostObject.h +79 -13
- package/common/cpp/HostObjects/AudioBufferSourceNodeHostObject.h +93 -14
- package/common/cpp/HostObjects/AudioContextHostObject.h +10 -19
- package/common/cpp/HostObjects/AudioDestinationNodeHostObject.h +3 -16
- package/common/cpp/HostObjects/AudioNodeHostObject.h +48 -11
- package/common/cpp/HostObjects/AudioParamHostObject.h +56 -14
- package/common/cpp/HostObjects/AudioScheduledSourceNodeHostObject.h +23 -16
- package/common/cpp/HostObjects/BaseAudioContextHostObject.h +131 -13
- package/common/cpp/HostObjects/BiquadFilterNodeHostObject.h +76 -18
- package/common/cpp/HostObjects/Constants.h +2 -0
- package/common/cpp/HostObjects/GainNodeHostObject.h +10 -15
- package/common/cpp/HostObjects/OscillatorNodeHostObject.h +40 -17
- package/common/cpp/HostObjects/PeriodicWaveHostObject.h +4 -17
- package/common/cpp/HostObjects/StereoPannerNodeHostObject.h +10 -17
- package/common/cpp/core/AudioBufferSourceNode.cpp +180 -73
- package/common/cpp/core/AudioBufferSourceNode.h +41 -1
- package/common/cpp/core/AudioDestinationNode.cpp +1 -0
- package/common/cpp/core/AudioDestinationNode.h +1 -1
- package/common/cpp/core/AudioScheduledSourceNode.cpp +86 -21
- package/common/cpp/core/AudioScheduledSourceNode.h +12 -4
- package/common/cpp/core/BaseAudioContext.cpp +8 -5
- package/common/cpp/core/BaseAudioContext.h +5 -3
- package/common/cpp/core/OscillatorNode.cpp +7 -2
- package/common/cpp/jsi/JsiHostObject.cpp +85 -0
- package/common/cpp/jsi/JsiHostObject.h +94 -0
- package/common/cpp/jsi/JsiPromise.cpp +65 -0
- package/common/cpp/jsi/JsiPromise.h +48 -0
- package/common/cpp/utils/AudioUtils.cpp +26 -0
- package/common/cpp/utils/AudioUtils.h +16 -0
- package/ios/AudioAPIModule.mm +3 -6
- package/ios/AudioDecoder/AudioDecoder.h +1 -1
- package/ios/AudioDecoder/AudioDecoder.m +14 -102
- package/ios/AudioDecoder/IOSAudioDecoder.h +2 -0
- package/ios/AudioDecoder/IOSAudioDecoder.mm +7 -1
- package/ios/AudioPlayer/AudioPlayer.m +3 -1
- package/lib/module/core/AudioBufferSourceNode.js +15 -0
- package/lib/module/core/AudioBufferSourceNode.js.map +1 -1
- package/lib/module/core/BaseAudioContext.js +2 -3
- package/lib/module/core/BaseAudioContext.js.map +1 -1
- package/lib/module/index.js +18 -3
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/core/AudioBufferSourceNode.d.ts +7 -0
- package/lib/typescript/core/AudioBufferSourceNode.d.ts.map +1 -1
- package/lib/typescript/core/BaseAudioContext.d.ts +2 -2
- package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -1
- package/lib/typescript/core/types.d.ts +0 -6
- package/lib/typescript/core/types.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +8 -4
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/interfaces.d.ts +5 -1
- package/lib/typescript/interfaces.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/core/AudioBufferSourceNode.ts +23 -0
- package/src/core/BaseAudioContext.ts +3 -8
- package/src/core/types.ts +0 -7
- package/src/index.ts +26 -12
- package/src/interfaces.ts +6 -1
- package/android/libs/fftw3/x86/libfftw3.a +0 -0
- package/android/libs/fftw3/x86_64/libfftw3.a +0 -0
- package/common/cpp/AudioAPIInstaller/AudioAPIInstallerHostObject.cpp +0 -54
- package/common/cpp/AudioAPIInstaller/AudioAPIInstallerWrapper.h +0 -38
- package/common/cpp/AudioAPIInstaller/android/AudioAPIInstallerWrapper.cpp +0 -16
- package/common/cpp/AudioAPIInstaller/ios/AudioAPIInstallerWrapper.cpp +0 -12
- package/common/cpp/HostObjects/AudioBufferHostObject.cpp +0 -149
- package/common/cpp/HostObjects/AudioBufferSourceNodeHostObject.cpp +0 -79
- package/common/cpp/HostObjects/AudioContextHostObject.cpp +0 -54
- package/common/cpp/HostObjects/AudioDestinationNodeHostObject.cpp +0 -33
- package/common/cpp/HostObjects/AudioNodeHostObject.cpp +0 -102
- package/common/cpp/HostObjects/AudioParamHostObject.cpp +0 -115
- package/common/cpp/HostObjects/AudioScheduledSourceNodeHostObject.cpp +0 -73
- package/common/cpp/HostObjects/BaseAudioContextHostObject.cpp +0 -240
- package/common/cpp/HostObjects/BiquadFilterNodeHostObject.cpp +0 -125
- package/common/cpp/HostObjects/GainNodeHostObject.cpp +0 -41
- package/common/cpp/HostObjects/OscillatorNodeHostObject.cpp +0 -88
- package/common/cpp/HostObjects/PeriodicWaveHostObject.cpp +0 -33
- package/common/cpp/HostObjects/StereoPannerNodeHostObject.cpp +0 -41
- package/common/cpp/utils/JsiPromise.cpp +0 -59
- package/common/cpp/utils/JsiPromise.h +0 -42
- package/common/cpp/wrappers/AudioBufferSourceNodeWrapper.cpp +0 -45
- package/common/cpp/wrappers/AudioBufferSourceNodeWrapper.h +0 -26
- package/common/cpp/wrappers/AudioBufferWrapper.cpp +0 -46
- package/common/cpp/wrappers/AudioBufferWrapper.h +0 -30
- package/common/cpp/wrappers/AudioContextWrapper.cpp +0 -17
- package/common/cpp/wrappers/AudioContextWrapper.h +0 -19
- package/common/cpp/wrappers/AudioDestinationNodeWrapper.h +0 -16
- package/common/cpp/wrappers/AudioNodeWrapper.cpp +0 -37
- package/common/cpp/wrappers/AudioNodeWrapper.h +0 -25
- package/common/cpp/wrappers/AudioParamWrapper.cpp +0 -42
- package/common/cpp/wrappers/AudioParamWrapper.h +0 -25
- package/common/cpp/wrappers/AudioScheduledSourceNodeWrapper.cpp +0 -23
- package/common/cpp/wrappers/AudioScheduledSourceNodeWrapper.h +0 -23
- package/common/cpp/wrappers/BaseAudioContextWrapper.cpp +0 -83
- package/common/cpp/wrappers/BaseAudioContextWrapper.h +0 -50
- package/common/cpp/wrappers/BiquadFilterNodeWrapper.cpp +0 -60
- package/common/cpp/wrappers/BiquadFilterNodeWrapper.h +0 -37
- package/common/cpp/wrappers/GainNodeWrapper.cpp +0 -14
- package/common/cpp/wrappers/GainNodeWrapper.h +0 -20
- package/common/cpp/wrappers/OscillatorNodeWrapper.cpp +0 -44
- package/common/cpp/wrappers/OscillatorNodeWrapper.h +0 -31
- package/common/cpp/wrappers/PeriodicWaveWrapper.h +0 -17
- package/common/cpp/wrappers/StereoPannerNodeWrapper.cpp +0 -16
- package/common/cpp/wrappers/StereoPannerNodeWrapper.h +0 -21
- package/lib/module/utils/resolveAudioSource.js +0 -10
- package/lib/module/utils/resolveAudioSource.js.map +0 -1
- package/lib/typescript/utils/resolveAudioSource.d.ts +0 -3
- package/lib/typescript/utils/resolveAudioSource.d.ts.map +0 -1
- package/src/utils/resolveAudioSource.ts +0 -14
- /package/android/libs/{fftw3/arm64-v8a → arm64-v8a}/libfftw3.a +0 -0
- /package/android/libs/{fftw3/armeabi-v7a → armeabi-v7a}/libfftw3.a +0 -0
- /package/android/libs/include/{fftw3/fftw3.h → fftw3.h} +0 -0
|
@@ -24,6 +24,7 @@ class AudioBufferSourceNode;
|
|
|
24
24
|
|
|
25
25
|
#ifdef ANDROID
|
|
26
26
|
class AudioPlayer;
|
|
27
|
+
class AudioDecoder;
|
|
27
28
|
#else
|
|
28
29
|
class IOSAudioPlayer;
|
|
29
30
|
class IOSAudioDecoder;
|
|
@@ -33,13 +34,14 @@ class BaseAudioContext {
|
|
|
33
34
|
public:
|
|
34
35
|
BaseAudioContext();
|
|
35
36
|
~BaseAudioContext();
|
|
37
|
+
|
|
36
38
|
std::string getState();
|
|
37
39
|
[[nodiscard]] int getSampleRate() const;
|
|
38
40
|
[[nodiscard]] double getCurrentTime() const;
|
|
39
41
|
[[nodiscard]] int getBufferSizeInFrames() const;
|
|
40
42
|
[[nodiscard]] std::size_t getCurrentSampleFrame() const;
|
|
41
|
-
|
|
42
43
|
std::shared_ptr<AudioDestinationNode> getDestination();
|
|
44
|
+
|
|
43
45
|
std::shared_ptr<OscillatorNode> createOscillator();
|
|
44
46
|
std::shared_ptr<GainNode> createGain();
|
|
45
47
|
std::shared_ptr<StereoPannerNode> createStereoPanner();
|
|
@@ -52,11 +54,10 @@ class BaseAudioContext {
|
|
|
52
54
|
float *imag,
|
|
53
55
|
bool disableNormalization,
|
|
54
56
|
int length);
|
|
55
|
-
std::shared_ptr<AudioBuffer> decodeAudioDataSource(const std::string &source);
|
|
56
57
|
|
|
58
|
+
std::shared_ptr<AudioBuffer> decodeAudioDataSource(const std::string &path);
|
|
57
59
|
std::shared_ptr<PeriodicWave> getBasicWaveForm(OscillatorType type);
|
|
58
60
|
std::function<void(AudioBus *, int)> renderAudio();
|
|
59
|
-
|
|
60
61
|
AudioNodeManager *getNodeManager();
|
|
61
62
|
[[nodiscard]] bool isRunning() const;
|
|
62
63
|
[[nodiscard]] bool isClosed() const;
|
|
@@ -67,6 +68,7 @@ class BaseAudioContext {
|
|
|
67
68
|
|
|
68
69
|
#ifdef ANDROID
|
|
69
70
|
std::shared_ptr<AudioPlayer> audioPlayer_;
|
|
71
|
+
std::shared_ptr<AudioDecoder> audioDecoder_;
|
|
70
72
|
#else
|
|
71
73
|
std::shared_ptr<IOSAudioPlayer> audioPlayer_;
|
|
72
74
|
std::shared_ptr<IOSAudioDecoder> audioDecoder_;
|
|
@@ -40,15 +40,20 @@ void OscillatorNode::setPeriodicWave(
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
void OscillatorNode::processNode(AudioBus *processingBus, int framesToProcess) {
|
|
43
|
+
size_t startOffset = 0;
|
|
44
|
+
size_t offsetLength = 0;
|
|
45
|
+
|
|
46
|
+
updatePlaybackInfo(processingBus, framesToProcess, startOffset, offsetLength);
|
|
47
|
+
|
|
43
48
|
if (!isPlaying()) {
|
|
44
49
|
processingBus->zero();
|
|
45
50
|
return;
|
|
46
51
|
}
|
|
47
52
|
|
|
48
|
-
double time = context_->getCurrentTime();
|
|
49
53
|
double deltaTime = 1.0 / context_->getSampleRate();
|
|
54
|
+
double time = context_->getCurrentTime() + startOffset * deltaTime;
|
|
50
55
|
|
|
51
|
-
for (
|
|
56
|
+
for (size_t i = startOffset; i < offsetLength; i += 1) {
|
|
52
57
|
auto detuneRatio =
|
|
53
58
|
std::pow(2.0f, detuneParam_->getValueAtTime(time) / 1200.0f);
|
|
54
59
|
auto detunedFrequency =
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#include "JsiHostObject.h"
|
|
2
|
+
|
|
3
|
+
namespace audioapi {
|
|
4
|
+
JsiHostObject::JsiHostObject() {
|
|
5
|
+
propertyGetters_ = std::make_unique<std::unordered_map<
|
|
6
|
+
std::string,
|
|
7
|
+
jsi::Value (JsiHostObject::*)(jsi::Runtime &)>>();
|
|
8
|
+
propertyFunctions_ = std::make_unique<std::unordered_map<
|
|
9
|
+
std::string,
|
|
10
|
+
jsi::Value (JsiHostObject::*)(
|
|
11
|
+
jsi::Runtime &, const jsi::Value &, const jsi::Value *, size_t)>>();
|
|
12
|
+
propertySetters_ = std::make_unique<std::unordered_map<
|
|
13
|
+
std::string,
|
|
14
|
+
void (JsiHostObject::*)(jsi::Runtime &, const jsi::Value &)>>();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
std::vector<jsi::PropNameID> JsiHostObject::getPropertyNames(jsi::Runtime &rt) {
|
|
18
|
+
std::vector<jsi::PropNameID> propertyNames;
|
|
19
|
+
propertyNames.reserve(
|
|
20
|
+
propertyGetters_->size() + propertyFunctions_->size() +
|
|
21
|
+
propertySetters_->size());
|
|
22
|
+
|
|
23
|
+
for (const auto &it : *propertyGetters_) {
|
|
24
|
+
propertyNames.push_back(jsi::PropNameID::forUtf8(rt, it.first));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
for (const auto &it : *propertyFunctions_) {
|
|
28
|
+
propertyNames.push_back(jsi::PropNameID::forAscii(rt, it.first));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
for (const auto &it : *propertySetters_) {
|
|
32
|
+
propertyNames.push_back(jsi::PropNameID::forAscii(rt, it.first));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return propertyNames;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
jsi::Value JsiHostObject::get(
|
|
39
|
+
jsi::Runtime &runtime,
|
|
40
|
+
const jsi::PropNameID &name) {
|
|
41
|
+
auto nameAsString = name.utf8(runtime);
|
|
42
|
+
|
|
43
|
+
auto propertyGetter = propertyGetters_->find(nameAsString);
|
|
44
|
+
if (propertyGetter != propertyGetters_->end()) {
|
|
45
|
+
auto dispatcher = [this, &propertyGetter](jsi::Runtime &runtime) {
|
|
46
|
+
return (this->*(propertyGetter->second))(runtime);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
return dispatcher(runtime);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
auto propertyFunction = propertyFunctions_->find(nameAsString);
|
|
53
|
+
if (propertyFunction != propertyFunctions_->end()) {
|
|
54
|
+
auto dispatcher = [this, &propertyFunction](
|
|
55
|
+
jsi::Runtime &runtime,
|
|
56
|
+
const jsi::Value &thisVal,
|
|
57
|
+
const jsi::Value *args,
|
|
58
|
+
size_t count) -> jsi::Value {
|
|
59
|
+
return (this->*(propertyFunction->second))(runtime, thisVal, args, count);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
return jsi::Function::createFromHostFunction(runtime, name, 0, dispatcher);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return jsi::Value::undefined();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
void JsiHostObject::set(
|
|
69
|
+
jsi::Runtime &runtime,
|
|
70
|
+
const jsi::PropNameID &name,
|
|
71
|
+
const jsi::Value &value) {
|
|
72
|
+
auto nameAsString = name.utf8(runtime);
|
|
73
|
+
|
|
74
|
+
auto propertySetter = propertySetters_->find(nameAsString);
|
|
75
|
+
|
|
76
|
+
if (propertySetter != propertySetters_->end()) {
|
|
77
|
+
auto dispatcher = [this, &propertySetter](
|
|
78
|
+
jsi::Runtime &runtime, const jsi::Value &value) {
|
|
79
|
+
return (this->*(propertySetter->second))(runtime, value);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
return dispatcher(runtime, value);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
} // namespace audioapi
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <jsi/jsi.h>
|
|
4
|
+
#include <memory>
|
|
5
|
+
#include <string>
|
|
6
|
+
#include <unordered_map>
|
|
7
|
+
#include <utility>
|
|
8
|
+
#include <vector>
|
|
9
|
+
|
|
10
|
+
#define JSI_HOST_FUNCTION(NAME) \
|
|
11
|
+
jsi::Value NAME( \
|
|
12
|
+
jsi::Runtime &runtime, \
|
|
13
|
+
const jsi::Value &thisVal, \
|
|
14
|
+
const jsi::Value *args, \
|
|
15
|
+
size_t count)
|
|
16
|
+
|
|
17
|
+
#define JSI_EXPORT_FUNCTION(CLASS, FUNCTION) \
|
|
18
|
+
std::make_pair( \
|
|
19
|
+
std::string(#FUNCTION), \
|
|
20
|
+
static_cast<jsi::Value (JsiHostObject::*)( \
|
|
21
|
+
jsi::Runtime &, const jsi::Value &, const jsi::Value *, size_t)>( \
|
|
22
|
+
&CLASS::FUNCTION))
|
|
23
|
+
|
|
24
|
+
#define JSI_PROPERTY_GETTER(name) jsi::Value name(jsi::Runtime &runtime)
|
|
25
|
+
|
|
26
|
+
#define JSI_EXPORT_PROPERTY_GETTER(CLASS, FUNCTION) \
|
|
27
|
+
std::make_pair( \
|
|
28
|
+
std::string(#FUNCTION), \
|
|
29
|
+
static_cast<jsi::Value (JsiHostObject::*)(jsi::Runtime &)>( \
|
|
30
|
+
&CLASS::FUNCTION))
|
|
31
|
+
|
|
32
|
+
#define JSI_PROPERTY_SETTER(name) \
|
|
33
|
+
void name(jsi::Runtime &runtime, const jsi::Value &value)
|
|
34
|
+
|
|
35
|
+
#define JSI_EXPORT_PROPERTY_SETTER(CLASS, FUNCTION) \
|
|
36
|
+
std::make_pair( \
|
|
37
|
+
std::string(#FUNCTION), \
|
|
38
|
+
static_cast<void (JsiHostObject::*)( \
|
|
39
|
+
jsi::Runtime &, const jsi::Value &)>(&CLASS::FUNCTION))
|
|
40
|
+
|
|
41
|
+
namespace audioapi {
|
|
42
|
+
|
|
43
|
+
using namespace facebook;
|
|
44
|
+
|
|
45
|
+
class JsiHostObject : public jsi::HostObject {
|
|
46
|
+
public:
|
|
47
|
+
JsiHostObject();
|
|
48
|
+
|
|
49
|
+
std::vector<jsi::PropNameID> getPropertyNames(jsi::Runtime &rt) override;
|
|
50
|
+
|
|
51
|
+
jsi::Value get(jsi::Runtime &runtime, const jsi::PropNameID &name) override;
|
|
52
|
+
|
|
53
|
+
void set(
|
|
54
|
+
jsi::Runtime &runtime,
|
|
55
|
+
const jsi::PropNameID &name,
|
|
56
|
+
const jsi::Value &value) override;
|
|
57
|
+
|
|
58
|
+
template <typename... Args>
|
|
59
|
+
void addGetters(Args... args) {
|
|
60
|
+
(propertyGetters_->insert(args), ...);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
template <typename... Args>
|
|
64
|
+
void addSetters(Args... args) {
|
|
65
|
+
(propertySetters_->insert(args), ...);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
template <typename... Args>
|
|
69
|
+
void addFunctions(Args... args) {
|
|
70
|
+
(propertyFunctions_->insert(args), ...);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
protected:
|
|
74
|
+
std::unique_ptr<std::unordered_map<
|
|
75
|
+
std::string,
|
|
76
|
+
jsi::Value (JsiHostObject::*)(jsi::Runtime &)>>
|
|
77
|
+
propertyGetters_;
|
|
78
|
+
|
|
79
|
+
std::unique_ptr<std::unordered_map<
|
|
80
|
+
std::string,
|
|
81
|
+
jsi::Value (JsiHostObject::*)(
|
|
82
|
+
jsi::Runtime &,
|
|
83
|
+
const jsi::Value &,
|
|
84
|
+
const jsi::Value *,
|
|
85
|
+
size_t)>>
|
|
86
|
+
propertyFunctions_;
|
|
87
|
+
|
|
88
|
+
std::unique_ptr<std::unordered_map<
|
|
89
|
+
std::string,
|
|
90
|
+
void (JsiHostObject::*)(jsi::Runtime &, const jsi::Value &)>>
|
|
91
|
+
propertySetters_;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
} // namespace audioapi
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#include "JsiPromise.h"
|
|
2
|
+
|
|
3
|
+
#include <ReactCommon/CallInvoker.h>
|
|
4
|
+
#include <jsi/jsi.h>
|
|
5
|
+
#include <functional>
|
|
6
|
+
|
|
7
|
+
namespace audioapi {
|
|
8
|
+
|
|
9
|
+
using namespace facebook;
|
|
10
|
+
|
|
11
|
+
jsi::Value PromiseVendor::createPromise(
|
|
12
|
+
const std::function<void(std::shared_ptr<Promise>)> &function) {
|
|
13
|
+
if (runtime_ == nullptr) {
|
|
14
|
+
throw std::runtime_error("Runtime was null!");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
auto &runtime = *runtime_;
|
|
18
|
+
auto callInvoker = callInvoker_;
|
|
19
|
+
|
|
20
|
+
// get Promise constructor
|
|
21
|
+
auto promiseCtor = runtime.global().getPropertyAsFunction(runtime, "Promise");
|
|
22
|
+
|
|
23
|
+
// create a "run" function (first Promise arg)
|
|
24
|
+
auto runPromise = jsi::Function::createFromHostFunction(
|
|
25
|
+
runtime,
|
|
26
|
+
jsi::PropNameID::forUtf8(runtime, "runPromise"),
|
|
27
|
+
2,
|
|
28
|
+
[callInvoker, function](
|
|
29
|
+
jsi::Runtime &runtime,
|
|
30
|
+
const jsi::Value &thisValue,
|
|
31
|
+
const jsi::Value *arguments,
|
|
32
|
+
size_t count) -> jsi::Value {
|
|
33
|
+
auto resolveLocal = arguments[0].asObject(runtime).asFunction(runtime);
|
|
34
|
+
auto resolve = std::make_shared<jsi::Function>(std::move(resolveLocal));
|
|
35
|
+
auto rejectLocal = arguments[1].asObject(runtime).asFunction(runtime);
|
|
36
|
+
auto reject = std::make_shared<jsi::Function>(std::move(rejectLocal));
|
|
37
|
+
|
|
38
|
+
auto resolveWrapper =
|
|
39
|
+
[resolve, &runtime, callInvoker](jsi::Value value) -> void {
|
|
40
|
+
auto valueShared = std::make_shared<jsi::Value>(std::move(value));
|
|
41
|
+
callInvoker->invokeAsync([resolve, &runtime, valueShared]() -> void {
|
|
42
|
+
resolve->call(runtime, *valueShared);
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
auto rejectWrapper = [reject, &runtime, callInvoker](
|
|
47
|
+
const std::string &errorMessage) -> void {
|
|
48
|
+
auto error = jsi::JSError(runtime, errorMessage);
|
|
49
|
+
auto errorShared = std::make_shared<jsi::JSError>(error);
|
|
50
|
+
callInvoker->invokeAsync([reject, &runtime, errorShared]() -> void {
|
|
51
|
+
reject->call(runtime, errorShared->value());
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
auto promise = std::make_shared<Promise>(resolveWrapper, rejectWrapper);
|
|
56
|
+
function(promise);
|
|
57
|
+
|
|
58
|
+
return jsi::Value::undefined();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// return new Promise((resolve, reject) => ...)
|
|
62
|
+
return promiseCtor.callAsConstructor(runtime, runPromise);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
} // namespace audioapi
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <ReactCommon/CallInvoker.h>
|
|
4
|
+
#include <jsi/jsi.h>
|
|
5
|
+
#include <memory>
|
|
6
|
+
#include <string>
|
|
7
|
+
#include <utility>
|
|
8
|
+
|
|
9
|
+
namespace audioapi {
|
|
10
|
+
|
|
11
|
+
using namespace facebook;
|
|
12
|
+
|
|
13
|
+
class Promise {
|
|
14
|
+
public:
|
|
15
|
+
Promise(
|
|
16
|
+
std::function<void(jsi::Value)> resolve,
|
|
17
|
+
std::function<void(const std::string &)> reject)
|
|
18
|
+
: resolve_(std::move(resolve)), reject_(std::move(reject)) {}
|
|
19
|
+
|
|
20
|
+
void resolve(jsi::Value &&value) {
|
|
21
|
+
resolve_(std::forward<jsi::Value>(value));
|
|
22
|
+
}
|
|
23
|
+
void reject(const std::string &errorMessage) {
|
|
24
|
+
reject_(errorMessage);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
private:
|
|
28
|
+
std::function<void(jsi::Value)> resolve_;
|
|
29
|
+
std::function<void(const std::string &)> reject_;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
class PromiseVendor {
|
|
33
|
+
public:
|
|
34
|
+
PromiseVendor(
|
|
35
|
+
jsi::Runtime *runtime,
|
|
36
|
+
const std::shared_ptr<react::CallInvoker> &callInvoker)
|
|
37
|
+
: runtime_(runtime), callInvoker_(callInvoker) {}
|
|
38
|
+
|
|
39
|
+
public:
|
|
40
|
+
jsi::Value createPromise(
|
|
41
|
+
const std::function<void(std::shared_ptr<Promise>)> &function);
|
|
42
|
+
|
|
43
|
+
private:
|
|
44
|
+
jsi::Runtime *runtime_;
|
|
45
|
+
std::shared_ptr<react::CallInvoker> callInvoker_;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
} // namespace audioapi
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#include "AudioUtils.h"
|
|
2
|
+
|
|
3
|
+
namespace audioapi::AudioUtils {
|
|
4
|
+
size_t timeToSampleFrame(double time, int sampleRate) {
|
|
5
|
+
return static_cast<size_t>(time * sampleRate);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
double sampleFrameToTime(int sampleFrame, int sampleRate) {
|
|
9
|
+
return static_cast<double>(sampleFrame) / sampleRate;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
float linearInterpolate(
|
|
13
|
+
const float *source,
|
|
14
|
+
size_t firstIndex,
|
|
15
|
+
size_t secondIndex,
|
|
16
|
+
float factor) {
|
|
17
|
+
if (firstIndex == secondIndex && firstIndex >= 1) {
|
|
18
|
+
return source[firstIndex] +
|
|
19
|
+
factor * (source[firstIndex] - source[firstIndex - 1]);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return source[firstIndex] +
|
|
23
|
+
factor * (source[secondIndex] - source[firstIndex]);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
} // namespace audioapi::AudioUtils
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <cstddef>
|
|
4
|
+
|
|
5
|
+
namespace audioapi::AudioUtils {
|
|
6
|
+
size_t timeToSampleFrame(double time, int sampleRate);
|
|
7
|
+
|
|
8
|
+
double sampleFrameToTime(int sampleFrame, int sampleRate);
|
|
9
|
+
|
|
10
|
+
float linearInterpolate(
|
|
11
|
+
const float *source,
|
|
12
|
+
size_t firstIndex,
|
|
13
|
+
size_t secondIndex,
|
|
14
|
+
float factor);
|
|
15
|
+
|
|
16
|
+
} // namespace audioapi::AudioUtils
|
package/ios/AudioAPIModule.mm
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
#import "AudioAPIModule.h"
|
|
2
2
|
|
|
3
|
-
#import <ReactCommon/RCTTurboModule.h>
|
|
4
3
|
#import <React/RCTBridge+Private.h>
|
|
5
4
|
#import <React/RCTBridge.h>
|
|
6
5
|
#import <React/RCTUtils.h>
|
|
6
|
+
#import <ReactCommon/RCTTurboModule.h>
|
|
7
7
|
#import <jsi/jsi.h>
|
|
8
8
|
|
|
9
9
|
#import "AudioAPIInstallerHostObject.h"
|
|
10
|
-
#import "AudioAPIInstallerWrapper.h"
|
|
11
10
|
|
|
12
11
|
@implementation AudioAPIModule
|
|
13
12
|
|
|
@@ -34,10 +33,8 @@ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(install)
|
|
|
34
33
|
|
|
35
34
|
auto &runtime = *jsRuntime;
|
|
36
35
|
|
|
37
|
-
auto
|
|
38
|
-
|
|
39
|
-
auto object = jsi::Object::createFromHostObject(runtime, hostObject);
|
|
40
|
-
runtime.global().setProperty(runtime, "__AudioAPIInstaller", std::move(object));
|
|
36
|
+
auto hostObject = std::make_shared<audioapi::AudioAPIInstallerHostObject>(jsRuntime, cxxBridge.jsCallInvoker);
|
|
37
|
+
hostObject->install();
|
|
41
38
|
|
|
42
39
|
NSLog(@"Successfully installed JSI bindings for react-native-audio-api!");
|
|
43
40
|
return @true;
|
|
@@ -10,21 +10,7 @@
|
|
|
10
10
|
return self;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
- (const AudioBufferList *)
|
|
14
|
-
{
|
|
15
|
-
// check if the input is a URL or a local file path
|
|
16
|
-
NSURL *url = [NSURL URLWithString:pathOrURL];
|
|
17
|
-
|
|
18
|
-
if (url && url.scheme) {
|
|
19
|
-
self.buffer = [self decodeWithURL:url];
|
|
20
|
-
} else {
|
|
21
|
-
self.buffer = [self decodeWithFilePath:pathOrURL];
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
return self.buffer.audioBufferList;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
- (AVAudioPCMBuffer *)decodeWithFilePath:(NSString *)path
|
|
13
|
+
- (const AudioBufferList *)decodeWithFile:(NSString *)path
|
|
28
14
|
{
|
|
29
15
|
NSError *error = nil;
|
|
30
16
|
NSURL *fileURL = [NSURL fileURLWithPath:path];
|
|
@@ -49,85 +35,12 @@
|
|
|
49
35
|
}
|
|
50
36
|
|
|
51
37
|
if (self.sampleRate != audioFile.processingFormat.sampleRate) {
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return buffer;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
- (AVAudioPCMBuffer *)decodeWithURL:(NSURL *)url
|
|
59
|
-
{
|
|
60
|
-
__block NSURL *tempFileURL = nil;
|
|
61
|
-
|
|
62
|
-
dispatch_group_t group = dispatch_group_create();
|
|
63
|
-
|
|
64
|
-
dispatch_group_enter(group);
|
|
65
|
-
|
|
66
|
-
[self downloadFileFromURL:url
|
|
67
|
-
completion:^(NSURL *downloadedFileURL, NSError *downloadError) {
|
|
68
|
-
if (downloadError) {
|
|
69
|
-
NSLog(@"Error downloading file: %@", downloadError.localizedDescription);
|
|
70
|
-
tempFileURL = nil;
|
|
71
|
-
} else {
|
|
72
|
-
tempFileURL = downloadedFileURL;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
dispatch_group_leave(group);
|
|
76
|
-
}];
|
|
77
|
-
|
|
78
|
-
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
|
|
79
|
-
|
|
80
|
-
if (!tempFileURL) {
|
|
81
|
-
NSLog(@"Cannot process given url");
|
|
82
|
-
return nil;
|
|
38
|
+
self.buffer = [self convertBuffer:buffer ToFormat:format];
|
|
39
|
+
} else {
|
|
40
|
+
self.buffer = buffer;
|
|
83
41
|
}
|
|
84
42
|
|
|
85
|
-
return
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
- (void)downloadFileFromURL:(NSURL *)url completion:(void (^)(NSURL *tempFileURL, NSError *error))completion
|
|
89
|
-
{
|
|
90
|
-
// get unique file path in temporary dir
|
|
91
|
-
NSString *tempDirectory = NSTemporaryDirectory();
|
|
92
|
-
NSString *timestamp = [NSString stringWithFormat:@"_%@", @((long long)[[NSDate date] timeIntervalSince1970])];
|
|
93
|
-
NSString *fileNameWithTimestamp = [url.lastPathComponent stringByDeletingPathExtension];
|
|
94
|
-
fileNameWithTimestamp = [fileNameWithTimestamp stringByAppendingString:timestamp];
|
|
95
|
-
NSString *fileExtension =
|
|
96
|
-
[url.pathExtension length] > 0 ? [NSString stringWithFormat:@".%@", url.pathExtension] : @"";
|
|
97
|
-
NSString *tempFilePath =
|
|
98
|
-
[tempDirectory stringByAppendingPathComponent:[fileNameWithTimestamp stringByAppendingString:fileExtension]];
|
|
99
|
-
NSURL *tempFileURL = [NSURL fileURLWithPath:tempFilePath];
|
|
100
|
-
|
|
101
|
-
// download file
|
|
102
|
-
NSURLSession *session = [NSURLSession sharedSession];
|
|
103
|
-
NSURLSessionDownloadTask *downloadTask = [session
|
|
104
|
-
downloadTaskWithURL:url
|
|
105
|
-
completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
|
|
106
|
-
if (error) {
|
|
107
|
-
NSLog(@"Error downloading file: %@", error.localizedDescription);
|
|
108
|
-
if (completion) {
|
|
109
|
-
completion(nil, error);
|
|
110
|
-
}
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// move to generated file path in temporary dir
|
|
115
|
-
NSError *fileError = nil;
|
|
116
|
-
BOOL success = [[NSFileManager defaultManager] moveItemAtURL:location toURL:tempFileURL error:&fileError];
|
|
117
|
-
if (success) {
|
|
118
|
-
NSLog(@"File downloaded successfully to %@", tempFileURL.path);
|
|
119
|
-
if (completion) {
|
|
120
|
-
completion(tempFileURL, nil);
|
|
121
|
-
}
|
|
122
|
-
} else {
|
|
123
|
-
NSLog(@"Error moving downloaded file: %@", fileError.localizedDescription);
|
|
124
|
-
if (completion) {
|
|
125
|
-
completion(nil, fileError);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}];
|
|
129
|
-
|
|
130
|
-
[downloadTask resume];
|
|
43
|
+
return self.buffer.audioBufferList;
|
|
131
44
|
}
|
|
132
45
|
|
|
133
46
|
- (AVAudioPCMBuffer *)convertBuffer:(AVAudioPCMBuffer *)buffer ToFormat:(AVAudioFormat *)format
|
|
@@ -138,16 +51,15 @@
|
|
|
138
51
|
[[AVAudioPCMBuffer alloc] initWithPCMFormat:format frameCapacity:(AVAudioFrameCount)buffer.frameCapacity];
|
|
139
52
|
|
|
140
53
|
AVAudioConverterInputBlock inputBlock =
|
|
141
|
-
^AVAudioBuffer *(AVAudioPacketCount inNumberOfPackets, AVAudioConverterInputStatus *outStatus)
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
};
|
|
54
|
+
^AVAudioBuffer *(AVAudioPacketCount inNumberOfPackets, AVAudioConverterInputStatus *outStatus) {
|
|
55
|
+
if (buffer.frameLength > 0) {
|
|
56
|
+
*outStatus = AVAudioConverterInputStatus_HaveData;
|
|
57
|
+
return buffer;
|
|
58
|
+
} else {
|
|
59
|
+
*outStatus = AVAudioConverterInputStatus_NoDataNow;
|
|
60
|
+
return nil;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
151
63
|
|
|
152
64
|
[converter convertToBuffer:convertedBuffer error:&error withInputFromBlock:inputBlock];
|
|
153
65
|
|
|
@@ -19,7 +19,7 @@ IOSAudioDecoder::~IOSAudioDecoder()
|
|
|
19
19
|
|
|
20
20
|
AudioBus *IOSAudioDecoder::decodeWithFilePath(const std::string &path)
|
|
21
21
|
{
|
|
22
|
-
auto bufferList = [audioDecoder_
|
|
22
|
+
auto bufferList = [audioDecoder_ decodeWithFile:[NSString stringWithUTF8String:path.c_str()]];
|
|
23
23
|
AudioBus *audioBus;
|
|
24
24
|
if (bufferList) {
|
|
25
25
|
auto numberOfChannels = bufferList->mNumberBuffers;
|
|
@@ -37,4 +37,10 @@ AudioBus *IOSAudioDecoder::decodeWithFilePath(const std::string &path)
|
|
|
37
37
|
|
|
38
38
|
return audioBus;
|
|
39
39
|
}
|
|
40
|
+
|
|
41
|
+
AudioBus *IOSAudioDecoder::decodeWithArrayBuffer()
|
|
42
|
+
{
|
|
43
|
+
// TODO: implement his
|
|
44
|
+
return new AudioBus(sampleRate_, 1, 1);
|
|
45
|
+
}
|
|
40
46
|
} // namespace audioapi
|
|
@@ -62,7 +62,9 @@
|
|
|
62
62
|
// which is safer to base our internal AudioBus sizes.
|
|
63
63
|
// Buut no documentation => no guarantee :)
|
|
64
64
|
// If something is crackling when it should play silence, start here 📻
|
|
65
|
-
|
|
65
|
+
double maxBufferDuration =
|
|
66
|
+
fmax(0.02, fmax(self.audioSession.IOBufferDuration, self.audioSession.preferredIOBufferDuration));
|
|
67
|
+
return (int)(maxBufferDuration * self.audioSession.sampleRate + 1);
|
|
66
68
|
}
|
|
67
69
|
|
|
68
70
|
- (void)start
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import AudioScheduledSourceNode from './AudioScheduledSourceNode';
|
|
2
2
|
import AudioBuffer from './AudioBuffer';
|
|
3
|
+
import AudioParam from './AudioParam';
|
|
3
4
|
export default class AudioBufferSourceNode extends AudioScheduledSourceNode {
|
|
4
5
|
constructor(context, node) {
|
|
5
6
|
super(context, node);
|
|
7
|
+
this.detune = new AudioParam(node.detune);
|
|
8
|
+
this.playbackRate = new AudioParam(node.playbackRate);
|
|
6
9
|
}
|
|
7
10
|
get buffer() {
|
|
8
11
|
const buffer = this.node.buffer;
|
|
@@ -24,5 +27,17 @@ export default class AudioBufferSourceNode extends AudioScheduledSourceNode {
|
|
|
24
27
|
set loop(value) {
|
|
25
28
|
this.node.loop = value;
|
|
26
29
|
}
|
|
30
|
+
get loopStart() {
|
|
31
|
+
return this.node.loopStart;
|
|
32
|
+
}
|
|
33
|
+
set loopStart(value) {
|
|
34
|
+
this.node.loopStart = value;
|
|
35
|
+
}
|
|
36
|
+
get loopEnd() {
|
|
37
|
+
return this.node.loopEnd;
|
|
38
|
+
}
|
|
39
|
+
set loopEnd(value) {
|
|
40
|
+
this.node.loopEnd = value;
|
|
41
|
+
}
|
|
27
42
|
}
|
|
28
43
|
//# sourceMappingURL=AudioBufferSourceNode.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["AudioScheduledSourceNode","AudioBuffer","AudioBufferSourceNode","constructor","context","node","buffer","loop","value"],"sourceRoot":"../../../src","sources":["core/AudioBufferSourceNode.ts"],"mappings":"AACA,OAAOA,wBAAwB,MAAM,4BAA4B;AAEjE,OAAOC,WAAW,MAAM,eAAe;
|
|
1
|
+
{"version":3,"names":["AudioScheduledSourceNode","AudioBuffer","AudioParam","AudioBufferSourceNode","constructor","context","node","detune","playbackRate","buffer","loop","value","loopStart","loopEnd"],"sourceRoot":"../../../src","sources":["core/AudioBufferSourceNode.ts"],"mappings":"AACA,OAAOA,wBAAwB,MAAM,4BAA4B;AAEjE,OAAOC,WAAW,MAAM,eAAe;AACvC,OAAOC,UAAU,MAAM,cAAc;AAErC,eAAe,MAAMC,qBAAqB,SAASH,wBAAwB,CAAC;EAI1EI,WAAWA,CAACC,OAAyB,EAAEC,IAA4B,EAAE;IACnE,KAAK,CAACD,OAAO,EAAEC,IAAI,CAAC;IAEpB,IAAI,CAACC,MAAM,GAAG,IAAIL,UAAU,CAACI,IAAI,CAACC,MAAM,CAAC;IACzC,IAAI,CAACC,YAAY,GAAG,IAAIN,UAAU,CAACI,IAAI,CAACE,YAAY,CAAC;EACvD;EAEA,IAAWC,MAAMA,CAAA,EAAuB;IACtC,MAAMA,MAAM,GAAI,IAAI,CAACH,IAAI,CAA4BG,MAAM;IAC3D,IAAI,CAACA,MAAM,EAAE;MACX,OAAO,IAAI;IACb;IACA,OAAO,IAAIR,WAAW,CAACQ,MAAM,CAAC;EAChC;EAEA,IAAWA,MAAMA,CAACA,MAA0B,EAAE;IAC5C,IAAI,CAACA,MAAM,EAAE;MACV,IAAI,CAACH,IAAI,CAA4BG,MAAM,GAAG,IAAI;MACnD;IACF;IAEC,IAAI,CAACH,IAAI,CAA4BG,MAAM,GAAGA,MAAM,CAACA,MAAM;EAC9D;EAEA,IAAWC,IAAIA,CAAA,EAAY;IACzB,OAAQ,IAAI,CAACJ,IAAI,CAA4BI,IAAI;EACnD;EAEA,IAAWA,IAAIA,CAACC,KAAc,EAAE;IAC7B,IAAI,CAACL,IAAI,CAA4BI,IAAI,GAAGC,KAAK;EACpD;EAEA,IAAWC,SAASA,CAAA,EAAW;IAC7B,OAAQ,IAAI,CAACN,IAAI,CAA4BM,SAAS;EACxD;EAEA,IAAWA,SAASA,CAACD,KAAa,EAAE;IACjC,IAAI,CAACL,IAAI,CAA4BM,SAAS,GAAGD,KAAK;EACzD;EAEA,IAAWE,OAAOA,CAAA,EAAW;IAC3B,OAAQ,IAAI,CAACP,IAAI,CAA4BO,OAAO;EACtD;EAEA,IAAWA,OAAOA,CAACF,KAAa,EAAE;IAC/B,IAAI,CAACL,IAAI,CAA4BO,OAAO,GAAGF,KAAK;EACvD;AACF","ignoreList":[]}
|
|
@@ -7,7 +7,6 @@ import AudioBufferSourceNode from './AudioBufferSourceNode';
|
|
|
7
7
|
import AudioBuffer from './AudioBuffer';
|
|
8
8
|
import PeriodicWave from './PeriodicWave';
|
|
9
9
|
import { InvalidAccessError } from '../errors';
|
|
10
|
-
import { resolveAudioSource } from '../utils/resolveAudioSource';
|
|
11
10
|
export default class BaseAudioContext {
|
|
12
11
|
constructor(context) {
|
|
13
12
|
this.context = context;
|
|
@@ -54,8 +53,8 @@ export default class BaseAudioContext {
|
|
|
54
53
|
const disableNormalization = constraints?.disableNormalization ?? false;
|
|
55
54
|
return new PeriodicWave(this.context.createPeriodicWave(real, imag, disableNormalization));
|
|
56
55
|
}
|
|
57
|
-
async decodeAudioDataSource(
|
|
58
|
-
const buffer = await this.context.decodeAudioDataSource(
|
|
56
|
+
async decodeAudioDataSource(sourcePath) {
|
|
57
|
+
const buffer = await this.context.decodeAudioDataSource(sourcePath);
|
|
59
58
|
return new AudioBuffer(buffer);
|
|
60
59
|
}
|
|
61
60
|
}
|