react-native-audio-api 0.2.0 → 0.3.0-rc2
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 +2 -2
- package/android/build.gradle +1 -3
- package/android/libs/include/miniaudio.h +92621 -0
- package/android/src/main/cpp/AudioAPIInstaller/AudioAPIInstaller.cpp +8 -4
- package/android/src/main/cpp/AudioAPIInstaller/AudioAPIInstaller.h +16 -7
- 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.cpp +16 -7
- package/android/src/main/cpp/AudioPlayer/AudioPlayer.h +5 -4
- 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.cpp +9 -3
- package/common/cpp/AudioAPIInstaller/AudioAPIInstallerHostObject.h +13 -7
- package/common/cpp/HostObjects/AudioBufferHostObject.cpp +7 -0
- package/common/cpp/HostObjects/AudioContextHostObject.cpp +3 -2
- package/common/cpp/HostObjects/AudioContextHostObject.h +6 -3
- package/common/cpp/HostObjects/BaseAudioContextHostObject.cpp +38 -2
- package/common/cpp/HostObjects/BaseAudioContextHostObject.h +4 -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 +11 -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 +49 -12
- package/common/cpp/core/BaseAudioContext.h +16 -7
- 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 +64 -0
- package/common/cpp/utils/JsiPromise.h +48 -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 +2 -0
- package/ios/AudioAPIModule.mm +4 -1
- package/ios/AudioDecoder/AudioDecoder.h +17 -0
- package/ios/AudioDecoder/AudioDecoder.m +80 -0
- package/ios/AudioDecoder/IOSAudioDecoder.h +28 -0
- package/ios/AudioDecoder/IOSAudioDecoder.mm +46 -0
- package/ios/AudioPlayer/AudioPlayer.h +1 -1
- package/ios/AudioPlayer/AudioPlayer.m +2 -2
- package/ios/AudioPlayer/IOSAudioPlayer.h +5 -5
- package/ios/AudioPlayer/IOSAudioPlayer.mm +4 -3
- package/lib/module/core/BaseAudioContext.js +4 -0
- package/lib/module/core/BaseAudioContext.js.map +1 -1
- package/lib/module/index.js +232 -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/typescript/core/BaseAudioContext.d.ts +1 -0
- package/lib/typescript/core/BaseAudioContext.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/package.json +4 -2
- package/src/core/BaseAudioContext.ts +6 -0
- package/src/index.native.ts +25 -0
- package/src/index.ts +403 -19
- package/src/interfaces.ts +1 -0
- package/android/libs/fftw3/x86/libfftw3.a +0 -0
- package/android/libs/fftw3/x86_64/libfftw3.a +0 -0
- /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
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#include "JsiPromise.h"
|
|
2
|
+
|
|
3
|
+
#include <ReactCommon/CallInvoker.h>
|
|
4
|
+
#include <jsi/jsi.h>
|
|
5
|
+
#include <functional>
|
|
6
|
+
|
|
7
|
+
namespace JsiPromise {
|
|
8
|
+
|
|
9
|
+
using namespace facebook;
|
|
10
|
+
|
|
11
|
+
jsi::Value PromiseVendor::createPromise(
|
|
12
|
+
std::function<void(std::shared_ptr<Promise>)> func) {
|
|
13
|
+
if (_runtime == nullptr) {
|
|
14
|
+
throw new std::runtime_error("Runtime was null!");
|
|
15
|
+
}
|
|
16
|
+
auto &runtime = *_runtime;
|
|
17
|
+
auto callInvoker = _callInvoker;
|
|
18
|
+
|
|
19
|
+
// get Promise constructor
|
|
20
|
+
auto promiseCtor = runtime.global().getPropertyAsFunction(runtime, "Promise");
|
|
21
|
+
|
|
22
|
+
// create a "run" function (first Promise arg)
|
|
23
|
+
auto runPromise = jsi::Function::createFromHostFunction(
|
|
24
|
+
runtime,
|
|
25
|
+
jsi::PropNameID::forUtf8(runtime, "runPromise"),
|
|
26
|
+
2,
|
|
27
|
+
[callInvoker, func](
|
|
28
|
+
jsi::Runtime &runtime,
|
|
29
|
+
const jsi::Value &thisValue,
|
|
30
|
+
const jsi::Value *arguments,
|
|
31
|
+
size_t count) -> jsi::Value {
|
|
32
|
+
auto resolveLocal = arguments[0].asObject(runtime).asFunction(runtime);
|
|
33
|
+
auto resolve = std::make_shared<jsi::Function>(std::move(resolveLocal));
|
|
34
|
+
auto rejectLocal = arguments[1].asObject(runtime).asFunction(runtime);
|
|
35
|
+
auto reject = std::make_shared<jsi::Function>(std::move(rejectLocal));
|
|
36
|
+
|
|
37
|
+
auto resolveWrapper =
|
|
38
|
+
[resolve, &runtime, callInvoker](jsi::Value value) -> void {
|
|
39
|
+
auto valueShared = std::make_shared<jsi::Value>(std::move(value));
|
|
40
|
+
callInvoker->invokeAsync([resolve, &runtime, valueShared]() -> void {
|
|
41
|
+
resolve->call(runtime, *valueShared);
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
auto rejectWrapper = [reject, &runtime, callInvoker](
|
|
46
|
+
const std::string &errorMessage) -> void {
|
|
47
|
+
auto error = jsi::JSError(runtime, errorMessage);
|
|
48
|
+
auto errorShared = std::make_shared<jsi::JSError>(error);
|
|
49
|
+
callInvoker->invokeAsync([reject, &runtime, errorShared]() -> void {
|
|
50
|
+
reject->call(runtime, errorShared->value());
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
auto promise = std::make_shared<Promise>(resolveWrapper, rejectWrapper);
|
|
55
|
+
func(promise);
|
|
56
|
+
|
|
57
|
+
return jsi::Value::undefined();
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// return new Promise((resolve, reject) => ...)
|
|
61
|
+
return promiseCtor.callAsConstructor(runtime, runPromise);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
} // namespace JsiPromise
|
|
@@ -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 JsiPromise {
|
|
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
|
+
bool isResolved;
|
|
21
|
+
void resolve(jsi::Value &&value) {
|
|
22
|
+
_resolve(std::forward<jsi::Value>(value));
|
|
23
|
+
}
|
|
24
|
+
void reject(const std::string &errorMessage) {
|
|
25
|
+
_reject(errorMessage);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
private:
|
|
29
|
+
std::function<void(jsi::Value)> _resolve;
|
|
30
|
+
std::function<void(const std::string &)> _reject;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
class PromiseVendor {
|
|
34
|
+
public:
|
|
35
|
+
PromiseVendor(
|
|
36
|
+
jsi::Runtime *runtime,
|
|
37
|
+
std::shared_ptr<react::CallInvoker> callInvoker)
|
|
38
|
+
: _runtime(runtime), _callInvoker(callInvoker) {}
|
|
39
|
+
|
|
40
|
+
public:
|
|
41
|
+
jsi::Value createPromise(std::function<void(std::shared_ptr<Promise>)> func);
|
|
42
|
+
|
|
43
|
+
private:
|
|
44
|
+
jsi::Runtime *_runtime;
|
|
45
|
+
std::shared_ptr<react::CallInvoker> _callInvoker;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
} // namespace JsiPromise
|
|
@@ -7,8 +7,8 @@ namespace audioapi {
|
|
|
7
7
|
// Small easy interface to manage locking
|
|
8
8
|
class Locker {
|
|
9
9
|
public:
|
|
10
|
-
Locker(): lockPtr_(0) {}
|
|
11
|
-
explicit Locker(std::mutex&
|
|
10
|
+
Locker() : lockPtr_(0) {}
|
|
11
|
+
explicit Locker(std::mutex &lockPtr) : lockPtr_(&lockPtr) {
|
|
12
12
|
lock();
|
|
13
13
|
}
|
|
14
14
|
|
|
@@ -16,7 +16,9 @@ class Locker {
|
|
|
16
16
|
unlock();
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
explicit operator bool() const {
|
|
19
|
+
explicit operator bool() const {
|
|
20
|
+
return !!lockPtr_;
|
|
21
|
+
}
|
|
20
22
|
|
|
21
23
|
void lock() {
|
|
22
24
|
if (lockPtr_) {
|
|
@@ -26,11 +28,11 @@ class Locker {
|
|
|
26
28
|
|
|
27
29
|
void unlock() {
|
|
28
30
|
if (lockPtr_) {
|
|
29
|
-
|
|
31
|
+
lockPtr_->unlock();
|
|
30
32
|
}
|
|
31
33
|
}
|
|
32
34
|
|
|
33
|
-
static Locker tryLock(std::mutex&
|
|
35
|
+
static Locker tryLock(std::mutex &lock) {
|
|
34
36
|
Locker result = Locker();
|
|
35
37
|
|
|
36
38
|
if (lock.try_lock()) {
|
|
@@ -41,7 +43,7 @@ class Locker {
|
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
private:
|
|
44
|
-
std::mutex*
|
|
46
|
+
std::mutex *lockPtr_;
|
|
45
47
|
};
|
|
46
48
|
|
|
47
49
|
} // namespace audioapi
|
|
@@ -115,8 +115,20 @@ float maximumMagnitude(
|
|
|
115
115
|
return maximumValue;
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
-
void multiplyByScalarThenAddToOutput(
|
|
119
|
-
|
|
118
|
+
void multiplyByScalarThenAddToOutput(
|
|
119
|
+
const float *inputVector,
|
|
120
|
+
float scalar,
|
|
121
|
+
float *outputVector,
|
|
122
|
+
size_t numberOfElementsToProcess) {
|
|
123
|
+
vDSP_vsma(
|
|
124
|
+
inputVector,
|
|
125
|
+
1,
|
|
126
|
+
&scalar,
|
|
127
|
+
outputVector,
|
|
128
|
+
1,
|
|
129
|
+
outputVector,
|
|
130
|
+
1,
|
|
131
|
+
numberOfElementsToProcess);
|
|
120
132
|
}
|
|
121
133
|
|
|
122
134
|
#else
|
|
@@ -609,69 +621,73 @@ float maximumMagnitude(
|
|
|
609
621
|
return max;
|
|
610
622
|
}
|
|
611
623
|
|
|
612
|
-
void multiplyByScalarThenAddToOutput(
|
|
613
|
-
|
|
624
|
+
void multiplyByScalarThenAddToOutput(
|
|
625
|
+
const float *inputVector,
|
|
626
|
+
float scalar,
|
|
627
|
+
float *outputVector,
|
|
628
|
+
size_t numberOfElementsToProcess) {
|
|
629
|
+
size_t n = numberOfElementsToProcess;
|
|
614
630
|
|
|
615
631
|
#if HAVE_X86_SSE2
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
632
|
+
// If the inputVector address is not 16-byte aligned, the first several frames
|
|
633
|
+
// (at most three) should be processed separately.
|
|
634
|
+
while (!is16ByteAligned(inputVector) && n) {
|
|
635
|
+
*outputVector += scalar * *inputVector;
|
|
636
|
+
inputVector++;
|
|
637
|
+
outputVector++;
|
|
638
|
+
n--;
|
|
639
|
+
}
|
|
623
640
|
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
#define SSE2_MULT_ADD(loadInstr, storeInstr)
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
}
|
|
641
|
+
// Now the inputVector is aligned, use SSE.
|
|
642
|
+
size_t tailFrames = n % 4;
|
|
643
|
+
const float *endP = outputVector + n - tailFrames;
|
|
644
|
+
|
|
645
|
+
__m128 pSource;
|
|
646
|
+
__m128 dest;
|
|
647
|
+
__m128 temp;
|
|
648
|
+
__m128 mScale = _mm_set_ps1(scalar);
|
|
649
|
+
|
|
650
|
+
bool destAligned = is16ByteAligned(outputVector);
|
|
651
|
+
|
|
652
|
+
#define SSE2_MULT_ADD(loadInstr, storeInstr) \
|
|
653
|
+
while (outputVector < endP) { \
|
|
654
|
+
pSource = _mm_load_ps(inputVector); \
|
|
655
|
+
temp = _mm_mul_ps(pSource, mScale); \
|
|
656
|
+
dest = _mm_##loadInstr##_ps(outputVector); \
|
|
657
|
+
dest = _mm_add_ps(dest, temp); \
|
|
658
|
+
_mm_##storeInstr##_ps(outputVector, dest); \
|
|
659
|
+
inputVector += 4; \
|
|
660
|
+
outputVector += 4; \
|
|
661
|
+
}
|
|
646
662
|
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
663
|
+
if (destAligned)
|
|
664
|
+
SSE2_MULT_ADD(load, store)
|
|
665
|
+
else
|
|
666
|
+
SSE2_MULT_ADD(loadu, storeu)
|
|
651
667
|
|
|
652
|
-
|
|
668
|
+
n = tailFrames;
|
|
653
669
|
#elif HAVE_ARM_NEON_INTRINSICS
|
|
654
|
-
|
|
655
|
-
|
|
670
|
+
size_t tailFrames = n % 4;
|
|
671
|
+
const float *endP = outputVector + n - tailFrames;
|
|
656
672
|
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
673
|
+
float32x4_t k = vdupq_n_f32(scalar);
|
|
674
|
+
while (outputVector < endP) {
|
|
675
|
+
float32x4_t source = vld1q_f32(inputVector);
|
|
676
|
+
float32x4_t dest = vld1q_f32(outputVector);
|
|
661
677
|
|
|
662
|
-
|
|
663
|
-
|
|
678
|
+
dest = vmlaq_f32(dest, source, k);
|
|
679
|
+
vst1q_f32(outputVector, dest);
|
|
664
680
|
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
681
|
+
inputVector += 4;
|
|
682
|
+
outputVector += 4;
|
|
683
|
+
}
|
|
684
|
+
n = tailFrames;
|
|
669
685
|
#endif
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
686
|
+
while (n--) {
|
|
687
|
+
*outputVector += *inputVector * scalar;
|
|
688
|
+
++inputVector;
|
|
689
|
+
++outputVector;
|
|
690
|
+
}
|
|
675
691
|
}
|
|
676
692
|
|
|
677
693
|
#endif
|
|
@@ -4,19 +4,20 @@
|
|
|
4
4
|
|
|
5
5
|
namespace audioapi {
|
|
6
6
|
void FFTFrame::inverse(float *timeDomainData) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
fftwf_complex *freqDomainData = fftwf_alloc_complex(size_ / 2);
|
|
8
|
+
for (int i = 0; i < size_ / 2; i++) {
|
|
9
|
+
freqDomainData[i][0] = realData_[i];
|
|
10
|
+
freqDomainData[i][1] = imaginaryData_[i];
|
|
11
|
+
}
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
auto plan = fftwf_plan_dft_c2r_1d(
|
|
14
|
+
size_, freqDomainData, timeDomainData, FFTW_ESTIMATE);
|
|
15
|
+
fftwf_execute(plan);
|
|
16
|
+
fftwf_destroy_plan(plan);
|
|
17
|
+
fftwf_free(freqDomainData);
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
VectorMath::multiplyByScalar(
|
|
20
|
+
timeDomainData, 1.0f / static_cast<float>(size_), timeDomainData, size_);
|
|
20
21
|
}
|
|
21
22
|
} // namespace audioapi
|
|
22
23
|
#endif
|
|
@@ -11,7 +11,12 @@ void FFTFrame::inverse(float *timeDomainData) {
|
|
|
11
11
|
freqDomainData.imagp = imaginaryData_;
|
|
12
12
|
|
|
13
13
|
vDSP_fft_zrip(fftSetup_, &freqDomainData, 1, log2Size_, FFT_INVERSE);
|
|
14
|
-
vDSP_ztoc(
|
|
14
|
+
vDSP_ztoc(
|
|
15
|
+
&freqDomainData,
|
|
16
|
+
1,
|
|
17
|
+
reinterpret_cast<DSPComplex *>(timeDomainData),
|
|
18
|
+
2,
|
|
19
|
+
size_ / 2);
|
|
15
20
|
|
|
16
21
|
// Scale the FFT data, beacuse of
|
|
17
22
|
// https://developer.apple.com/library/archive/documentation/Performance/Conceptual/vDSP_Programming_Guide/UsingFourierTransforms/UsingFourierTransforms.html#//apple_ref/doc/uid/TP40005147-CH3-15892
|
|
@@ -73,4 +73,11 @@ BaseAudioContextWrapper::createPeriodicWave(
|
|
|
73
73
|
context_->createPeriodicWave(real, imag, disableNormalization, length);
|
|
74
74
|
return std::make_shared<PeriodicWaveWrapper>(periodicWave);
|
|
75
75
|
}
|
|
76
|
+
|
|
77
|
+
std::shared_ptr<AudioBufferWrapper>
|
|
78
|
+
BaseAudioContextWrapper::decodeAudioDataSource(const std::string &path) {
|
|
79
|
+
return std::make_shared<AudioBufferWrapper>(
|
|
80
|
+
context_->decodeAudioDataSource(path));
|
|
81
|
+
}
|
|
82
|
+
|
|
76
83
|
} // namespace audioapi
|
|
@@ -41,6 +41,8 @@ class BaseAudioContextWrapper {
|
|
|
41
41
|
float *imag,
|
|
42
42
|
bool disableNormalization,
|
|
43
43
|
int length);
|
|
44
|
+
std::shared_ptr<AudioBufferWrapper> decodeAudioDataSource(
|
|
45
|
+
const std::string &path);
|
|
44
46
|
|
|
45
47
|
protected:
|
|
46
48
|
std::shared_ptr<AudioDestinationNodeWrapper> destination_;
|
package/ios/AudioAPIModule.mm
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
#import "AudioAPIModule.h"
|
|
2
2
|
|
|
3
3
|
#import <React/RCTBridge+Private.h>
|
|
4
|
+
#import <React/RCTBridge.h>
|
|
4
5
|
#import <React/RCTUtils.h>
|
|
6
|
+
#import <ReactCommon/RCTTurboModule.h>
|
|
5
7
|
#import <jsi/jsi.h>
|
|
6
8
|
|
|
7
9
|
#import "AudioAPIInstallerHostObject.h"
|
|
@@ -33,7 +35,8 @@ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(install)
|
|
|
33
35
|
auto &runtime = *jsRuntime;
|
|
34
36
|
|
|
35
37
|
auto wrapper = std::make_shared<audioapi::AudioAPIInstallerWrapper>();
|
|
36
|
-
auto hostObject =
|
|
38
|
+
auto hostObject =
|
|
39
|
+
std::make_shared<audioapi::AudioAPIInstallerHostObject>(wrapper, jsRuntime, cxxBridge.jsCallInvoker);
|
|
37
40
|
auto object = jsi::Object::createFromHostObject(runtime, hostObject);
|
|
38
41
|
runtime.global().setProperty(runtime, "__AudioAPIInstaller", std::move(object));
|
|
39
42
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#import <AVFoundation/AVFoundation.h>
|
|
4
|
+
#import <Foundation/Foundation.h>
|
|
5
|
+
|
|
6
|
+
@interface AudioDecoder : NSObject
|
|
7
|
+
|
|
8
|
+
@property (nonatomic, strong) AVAudioPCMBuffer *buffer;
|
|
9
|
+
@property (nonatomic, assign) int sampleRate;
|
|
10
|
+
|
|
11
|
+
- (instancetype)initWithSampleRate:(int)sampleRate;
|
|
12
|
+
|
|
13
|
+
- (const AudioBufferList *)decodeWithFile:(NSString *)path;
|
|
14
|
+
|
|
15
|
+
- (void)cleanup;
|
|
16
|
+
|
|
17
|
+
@end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
#import <AudioDecoder.h>
|
|
2
|
+
|
|
3
|
+
@implementation AudioDecoder
|
|
4
|
+
|
|
5
|
+
- (instancetype)initWithSampleRate:(int)sampleRate
|
|
6
|
+
{
|
|
7
|
+
if (self = [super init]) {
|
|
8
|
+
self.sampleRate = sampleRate;
|
|
9
|
+
}
|
|
10
|
+
return self;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
- (const AudioBufferList *)decodeWithFile:(NSString *)path
|
|
14
|
+
{
|
|
15
|
+
NSError *error = nil;
|
|
16
|
+
NSURL *fileURL = [NSURL fileURLWithPath:path];
|
|
17
|
+
AVAudioFile *audioFile = [[AVAudioFile alloc] initForReading:fileURL error:&error];
|
|
18
|
+
|
|
19
|
+
if (error) {
|
|
20
|
+
NSLog(@"Error occurred while opening the audio file: %@", [error localizedDescription]);
|
|
21
|
+
return nil;
|
|
22
|
+
}
|
|
23
|
+
AVAudioPCMBuffer *buffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:[audioFile processingFormat]
|
|
24
|
+
frameCapacity:[audioFile length]];
|
|
25
|
+
|
|
26
|
+
AVAudioFormat *format = [[AVAudioFormat alloc] initWithCommonFormat:AVAudioPCMFormatFloat32
|
|
27
|
+
sampleRate:self.sampleRate
|
|
28
|
+
channels:buffer.audioBufferList->mNumberBuffers
|
|
29
|
+
interleaved:NO];
|
|
30
|
+
|
|
31
|
+
[audioFile readIntoBuffer:buffer error:&error];
|
|
32
|
+
if (error) {
|
|
33
|
+
NSLog(@"Error occurred while reading the audio file: %@", [error localizedDescription]);
|
|
34
|
+
return nil;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (self.sampleRate != audioFile.processingFormat.sampleRate) {
|
|
38
|
+
self.buffer = [self convertBuffer:buffer ToFormat:format];
|
|
39
|
+
} else {
|
|
40
|
+
self.buffer = buffer;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return self.buffer.audioBufferList;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
- (AVAudioPCMBuffer *)convertBuffer:(AVAudioPCMBuffer *)buffer ToFormat:(AVAudioFormat *)format
|
|
47
|
+
{
|
|
48
|
+
NSError *error = nil;
|
|
49
|
+
AVAudioConverter *converter = [[AVAudioConverter alloc] initFromFormat:buffer.format toFormat:format];
|
|
50
|
+
AVAudioPCMBuffer *convertedBuffer =
|
|
51
|
+
[[AVAudioPCMBuffer alloc] initWithPCMFormat:format frameCapacity:(AVAudioFrameCount)buffer.frameCapacity];
|
|
52
|
+
|
|
53
|
+
AVAudioConverterInputBlock inputBlock =
|
|
54
|
+
^AVAudioBuffer *(AVAudioPacketCount inNumberOfPackets, AVAudioConverterInputStatus *outStatus)
|
|
55
|
+
{
|
|
56
|
+
if (buffer.frameLength > 0) {
|
|
57
|
+
*outStatus = AVAudioConverterInputStatus_HaveData;
|
|
58
|
+
return buffer;
|
|
59
|
+
} else {
|
|
60
|
+
*outStatus = AVAudioConverterInputStatus_NoDataNow;
|
|
61
|
+
return nil;
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
[converter convertToBuffer:convertedBuffer error:&error withInputFromBlock:inputBlock];
|
|
66
|
+
|
|
67
|
+
if (error) {
|
|
68
|
+
NSLog(@"Error occurred while converting the audio file: %@", [error localizedDescription]);
|
|
69
|
+
return nil;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return convertedBuffer;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
- (void)cleanup
|
|
76
|
+
{
|
|
77
|
+
self.buffer = nil;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
@end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <string>
|
|
4
|
+
|
|
5
|
+
#ifdef __OBJC__ // when compiled as Objective-C++
|
|
6
|
+
#import <AudioDecoder.h>
|
|
7
|
+
#else // when compiled as C++
|
|
8
|
+
typedef struct objc_object AudioDecoder;
|
|
9
|
+
#endif // __OBJC__
|
|
10
|
+
|
|
11
|
+
namespace audioapi {
|
|
12
|
+
|
|
13
|
+
class AudioBus;
|
|
14
|
+
|
|
15
|
+
class IOSAudioDecoder {
|
|
16
|
+
protected:
|
|
17
|
+
AudioDecoder *audioDecoder_;
|
|
18
|
+
int sampleRate_;
|
|
19
|
+
|
|
20
|
+
public:
|
|
21
|
+
IOSAudioDecoder(int sampleRate);
|
|
22
|
+
~IOSAudioDecoder();
|
|
23
|
+
|
|
24
|
+
AudioBus *decodeWithFilePath(const std::string &path);
|
|
25
|
+
// TODO: implement this
|
|
26
|
+
AudioBus *decodeWithArrayBuffer();
|
|
27
|
+
};
|
|
28
|
+
} // namespace audioapi
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#import <AVFoundation/AVFoundation.h>
|
|
2
|
+
|
|
3
|
+
#include <AudioArray.h>
|
|
4
|
+
#include <AudioBus.h>
|
|
5
|
+
#include <IOSAudioDecoder.h>
|
|
6
|
+
|
|
7
|
+
namespace audioapi {
|
|
8
|
+
|
|
9
|
+
IOSAudioDecoder::IOSAudioDecoder(int sampleRate) : sampleRate_(sampleRate)
|
|
10
|
+
{
|
|
11
|
+
audioDecoder_ = [[AudioDecoder alloc] initWithSampleRate:sampleRate_];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
IOSAudioDecoder::~IOSAudioDecoder()
|
|
15
|
+
{
|
|
16
|
+
[audioDecoder_ cleanup];
|
|
17
|
+
audioDecoder_ = nullptr;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
AudioBus *IOSAudioDecoder::decodeWithFilePath(const std::string &path)
|
|
21
|
+
{
|
|
22
|
+
auto bufferList = [audioDecoder_ decodeWithFile:[NSString stringWithUTF8String:path.c_str()]];
|
|
23
|
+
AudioBus *audioBus;
|
|
24
|
+
if (bufferList) {
|
|
25
|
+
auto numberOfChannels = bufferList->mNumberBuffers;
|
|
26
|
+
auto size = bufferList->mBuffers[0].mDataByteSize / sizeof(float);
|
|
27
|
+
|
|
28
|
+
audioBus = new AudioBus(sampleRate_, size, numberOfChannels);
|
|
29
|
+
|
|
30
|
+
for (int i = 0; i < numberOfChannels; i++) {
|
|
31
|
+
float *data = (float *)bufferList->mBuffers[i].mData;
|
|
32
|
+
memcpy(audioBus->getChannel(i)->getData(), data, sizeof(float) * size);
|
|
33
|
+
}
|
|
34
|
+
} else {
|
|
35
|
+
audioBus = new AudioBus(sampleRate_, 1, 1);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return audioBus;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
AudioBus *IOSAudioDecoder::decodeWithArrayBuffer()
|
|
42
|
+
{
|
|
43
|
+
// TODO: implement his
|
|
44
|
+
return new AudioBus(sampleRate_, 1, 1);
|
|
45
|
+
}
|
|
46
|
+
} // namespace audioapi
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
#import <AVFoundation/AVFoundation.h>
|
|
4
4
|
#import <Foundation/Foundation.h>
|
|
5
5
|
|
|
6
|
-
typedef void (^RenderAudioBlock)(AudioBufferList*
|
|
6
|
+
typedef void (^RenderAudioBlock)(AudioBufferList *outputBuffer, int numFrames);
|
|
7
7
|
|
|
8
8
|
@interface AudioPlayer : NSObject
|
|
9
9
|
|
|
@@ -62,7 +62,8 @@
|
|
|
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 = fmax(0.02, fmax(self.audioSession.IOBufferDuration, self.audioSession.preferredIOBufferDuration));
|
|
66
|
+
return (int)(maxBufferDuration * self.audioSession.sampleRate + 1);
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
- (void)start
|
|
@@ -70,7 +71,6 @@
|
|
|
70
71
|
[self.audioEngine attachNode:self.sourceNode];
|
|
71
72
|
[self.audioEngine connect:self.sourceNode to:self.audioEngine.mainMixerNode format:self.format];
|
|
72
73
|
|
|
73
|
-
|
|
74
74
|
if (!self.audioEngine.isRunning) {
|
|
75
75
|
NSError *error = nil;
|
|
76
76
|
if (![self.audioEngine startAndReturnError:&error]) {
|
|
@@ -15,12 +15,13 @@ class AudioBus;
|
|
|
15
15
|
|
|
16
16
|
class IOSAudioPlayer {
|
|
17
17
|
protected:
|
|
18
|
-
AudioBus*
|
|
19
|
-
AudioPlayer*
|
|
20
|
-
std::function<void(AudioBus*, int)> renderAudio_;
|
|
18
|
+
AudioBus *audioBus_;
|
|
19
|
+
AudioPlayer *audioPlayer_;
|
|
20
|
+
std::function<void(AudioBus *, int)> renderAudio_;
|
|
21
21
|
|
|
22
22
|
public:
|
|
23
|
-
explicit IOSAudioPlayer(
|
|
23
|
+
explicit IOSAudioPlayer(
|
|
24
|
+
const std::function<void(AudioBus *, int)> &renderAudio);
|
|
24
25
|
~IOSAudioPlayer();
|
|
25
26
|
|
|
26
27
|
int getSampleRate() const;
|
|
@@ -28,6 +29,5 @@ class IOSAudioPlayer {
|
|
|
28
29
|
|
|
29
30
|
void start();
|
|
30
31
|
void stop();
|
|
31
|
-
|
|
32
32
|
};
|
|
33
33
|
} // namespace audioapi
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
#import <AVFoundation/AVFoundation.h>
|
|
2
2
|
|
|
3
|
+
#include <AudioArray.h>
|
|
3
4
|
#include <AudioBus.h>
|
|
4
5
|
#include <Constants.h>
|
|
5
|
-
#include <AudioArray.h>
|
|
6
6
|
#include <IOSAudioPlayer.h>
|
|
7
7
|
|
|
8
8
|
namespace audioapi {
|
|
9
9
|
|
|
10
|
-
IOSAudioPlayer::IOSAudioPlayer(const std::function<void(AudioBus*, int)> &renderAudio)
|
|
10
|
+
IOSAudioPlayer::IOSAudioPlayer(const std::function<void(AudioBus *, int)> &renderAudio)
|
|
11
|
+
: renderAudio_(renderAudio), audioBus_(0)
|
|
11
12
|
{
|
|
12
|
-
RenderAudioBlock renderAudioBlock = ^(AudioBufferList*
|
|
13
|
+
RenderAudioBlock renderAudioBlock = ^(AudioBufferList *outputData, int numFrames) {
|
|
13
14
|
renderAudio_(audioBus_, numFrames);
|
|
14
15
|
|
|
15
16
|
for (int i = 0; i < outputData->mNumberBuffers; i += 1) {
|
|
@@ -53,5 +53,9 @@ export default class BaseAudioContext {
|
|
|
53
53
|
const disableNormalization = constraints?.disableNormalization ?? false;
|
|
54
54
|
return new PeriodicWave(this.context.createPeriodicWave(real, imag, disableNormalization));
|
|
55
55
|
}
|
|
56
|
+
async decodeAudioDataSource(sourcePath) {
|
|
57
|
+
const buffer = await this.context.decodeAudioDataSource(sourcePath);
|
|
58
|
+
return new AudioBuffer(buffer);
|
|
59
|
+
}
|
|
56
60
|
}
|
|
57
61
|
//# sourceMappingURL=BaseAudioContext.js.map
|