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.
Files changed (84) hide show
  1. package/android/CMakeLists.txt +2 -2
  2. package/android/build.gradle +1 -3
  3. package/android/libs/include/miniaudio.h +92621 -0
  4. package/android/src/main/cpp/AudioAPIInstaller/AudioAPIInstaller.cpp +8 -4
  5. package/android/src/main/cpp/AudioAPIInstaller/AudioAPIInstaller.h +16 -7
  6. package/android/src/main/cpp/AudioDecoder/AudioDecoder.cpp +64 -0
  7. package/android/src/main/cpp/AudioDecoder/AudioDecoder.h +21 -0
  8. package/android/src/main/cpp/AudioPlayer/AudioPlayer.cpp +16 -7
  9. package/android/src/main/cpp/AudioPlayer/AudioPlayer.h +5 -4
  10. package/android/src/main/java/com/swmansion/audioapi/module/AudioAPIInstaller.kt +14 -4
  11. package/android/src/main/java/com/swmansion/audioapi/nativemodules/AudioAPIModule.kt +2 -3
  12. package/common/cpp/AudioAPIInstaller/AudioAPIInstallerHostObject.cpp +9 -3
  13. package/common/cpp/AudioAPIInstaller/AudioAPIInstallerHostObject.h +13 -7
  14. package/common/cpp/HostObjects/AudioBufferHostObject.cpp +7 -0
  15. package/common/cpp/HostObjects/AudioContextHostObject.cpp +3 -2
  16. package/common/cpp/HostObjects/AudioContextHostObject.h +6 -3
  17. package/common/cpp/HostObjects/BaseAudioContextHostObject.cpp +38 -2
  18. package/common/cpp/HostObjects/BaseAudioContextHostObject.h +4 -1
  19. package/common/cpp/core/AudioArray.cpp +28 -14
  20. package/common/cpp/core/AudioArray.h +20 -14
  21. package/common/cpp/core/AudioBuffer.cpp +14 -11
  22. package/common/cpp/core/AudioBuffer.h +1 -0
  23. package/common/cpp/core/AudioBufferSourceNode.cpp +29 -19
  24. package/common/cpp/core/AudioBufferSourceNode.h +1 -1
  25. package/common/cpp/core/AudioBus.cpp +276 -115
  26. package/common/cpp/core/AudioBus.h +29 -9
  27. package/common/cpp/core/AudioContext.cpp +5 -9
  28. package/common/cpp/core/AudioDestinationNode.cpp +11 -8
  29. package/common/cpp/core/AudioDestinationNode.h +4 -4
  30. package/common/cpp/core/AudioNode.cpp +25 -17
  31. package/common/cpp/core/AudioNode.h +5 -5
  32. package/common/cpp/core/AudioNodeManager.cpp +10 -7
  33. package/common/cpp/core/AudioNodeManager.h +11 -4
  34. package/common/cpp/core/AudioScheduledSourceNode.cpp +2 -2
  35. package/common/cpp/core/BaseAudioContext.cpp +49 -12
  36. package/common/cpp/core/BaseAudioContext.h +16 -7
  37. package/common/cpp/core/BiquadFilterNode.cpp +5 -3
  38. package/common/cpp/core/GainNode.cpp +1 -1
  39. package/common/cpp/core/OscillatorNode.cpp +4 -4
  40. package/common/cpp/core/OscillatorNode.h +2 -2
  41. package/common/cpp/core/StereoPannerNode.cpp +10 -7
  42. package/common/cpp/core/StereoPannerNode.h +1 -1
  43. package/common/cpp/utils/FFTFrame.h +5 -1
  44. package/common/cpp/utils/JsiPromise.cpp +64 -0
  45. package/common/cpp/utils/JsiPromise.h +48 -0
  46. package/common/cpp/utils/Locker.h +8 -6
  47. package/common/cpp/utils/VectorMath.cpp +71 -55
  48. package/common/cpp/utils/android/FFTFrame.cpp +12 -11
  49. package/common/cpp/utils/ios/FFTFrame.cpp +6 -1
  50. package/common/cpp/wrappers/BaseAudioContextWrapper.cpp +7 -0
  51. package/common/cpp/wrappers/BaseAudioContextWrapper.h +2 -0
  52. package/ios/AudioAPIModule.mm +4 -1
  53. package/ios/AudioDecoder/AudioDecoder.h +17 -0
  54. package/ios/AudioDecoder/AudioDecoder.m +80 -0
  55. package/ios/AudioDecoder/IOSAudioDecoder.h +28 -0
  56. package/ios/AudioDecoder/IOSAudioDecoder.mm +46 -0
  57. package/ios/AudioPlayer/AudioPlayer.h +1 -1
  58. package/ios/AudioPlayer/AudioPlayer.m +2 -2
  59. package/ios/AudioPlayer/IOSAudioPlayer.h +5 -5
  60. package/ios/AudioPlayer/IOSAudioPlayer.mm +4 -3
  61. package/lib/module/core/BaseAudioContext.js +4 -0
  62. package/lib/module/core/BaseAudioContext.js.map +1 -1
  63. package/lib/module/index.js +232 -17
  64. package/lib/module/index.js.map +1 -1
  65. package/lib/module/index.native.js +18 -0
  66. package/lib/module/index.native.js.map +1 -0
  67. package/lib/typescript/core/BaseAudioContext.d.ts +1 -0
  68. package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -1
  69. package/lib/typescript/index.d.ts +100 -13
  70. package/lib/typescript/index.d.ts.map +1 -1
  71. package/lib/typescript/index.native.d.ts +14 -0
  72. package/lib/typescript/index.native.d.ts.map +1 -0
  73. package/lib/typescript/interfaces.d.ts +1 -0
  74. package/lib/typescript/interfaces.d.ts.map +1 -1
  75. package/package.json +4 -2
  76. package/src/core/BaseAudioContext.ts +6 -0
  77. package/src/index.native.ts +25 -0
  78. package/src/index.ts +403 -19
  79. package/src/interfaces.ts +1 -0
  80. package/android/libs/fftw3/x86/libfftw3.a +0 -0
  81. package/android/libs/fftw3/x86_64/libfftw3.a +0 -0
  82. /package/android/libs/{fftw3/arm64-v8a → arm64-v8a}/libfftw3.a +0 -0
  83. /package/android/libs/{fftw3/armeabi-v7a → armeabi-v7a}/libfftw3.a +0 -0
  84. /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& lockPtr): lockPtr_(&lockPtr) {
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 { return !!lockPtr_; }
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
- lockPtr_->unlock();
31
+ lockPtr_->unlock();
30
32
  }
31
33
  }
32
34
 
33
- static Locker tryLock(std::mutex& lock) {
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* lockPtr_;
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(const float* inputVector, float scalar, float* outputVector, size_t numberOfElementsToProcess) {
119
- vDSP_vsma(inputVector, 1, &scalar, outputVector, 1, outputVector, 1, numberOfElementsToProcess);
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(const float* inputVector, float scalar, float* outputVector, size_t numberOfElementsToProcess) {
613
- size_t n = numberOfElementsToProcess;
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
- // If the inputVector address is not 16-byte aligned, the first several frames (at most three) should be processed separately.
617
- while (!is16ByteAligned(inputVector) && n) {
618
- *outputVector += scalar * *inputVector;
619
- inputVector++;
620
- outputVector++;
621
- n--;
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
- // Now the inputVector is aligned, use SSE.
625
- size_t tailFrames = n % 4;
626
- const float* endP = outputVector + n - tailFrames;
627
-
628
- __m128 pSource;
629
- __m128 dest;
630
- __m128 temp;
631
- __m128 mScale = _mm_set_ps1(scalar);
632
-
633
- bool destAligned = is16ByteAligned(outputVector);
634
-
635
- #define SSE2_MULT_ADD(loadInstr, storeInstr) \
636
- while (outputVector < endP) \
637
- { \
638
- pSource = _mm_load_ps(inputVector); \
639
- temp = _mm_mul_ps(pSource, mScale); \
640
- dest = _mm_##loadInstr##_ps(outputVector); \
641
- dest = _mm_add_ps(dest, temp); \
642
- _mm_##storeInstr##_ps(outputVector, dest); \
643
- inputVector += 4; \
644
- outputVector += 4; \
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
- if (destAligned)
648
- SSE2_MULT_ADD(load, store)
649
- else
650
- SSE2_MULT_ADD(loadu, storeu)
663
+ if (destAligned)
664
+ SSE2_MULT_ADD(load, store)
665
+ else
666
+ SSE2_MULT_ADD(loadu, storeu)
651
667
 
652
- n = tailFrames;
668
+ n = tailFrames;
653
669
  #elif HAVE_ARM_NEON_INTRINSICS
654
- size_t tailFrames = n % 4;
655
- const float* endP = outputVector + n - tailFrames;
670
+ size_t tailFrames = n % 4;
671
+ const float *endP = outputVector + n - tailFrames;
656
672
 
657
- float32x4_t k = vdupq_n_f32(scalar);
658
- while (outputVector < endP) {
659
- float32x4_t source = vld1q_f32(inputVector);
660
- float32x4_t dest = vld1q_f32(outputVector);
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
- dest = vmlaq_f32(dest, source, k);
663
- vst1q_f32(outputVector, dest);
678
+ dest = vmlaq_f32(dest, source, k);
679
+ vst1q_f32(outputVector, dest);
664
680
 
665
- inputVector += 4;
666
- outputVector += 4;
667
- }
668
- n = tailFrames;
681
+ inputVector += 4;
682
+ outputVector += 4;
683
+ }
684
+ n = tailFrames;
669
685
  #endif
670
- while (n--) {
671
- *outputVector += *inputVector * scalar;
672
- ++inputVector;
673
- ++outputVector;
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
- 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
- }
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
- auto plan = fftwf_plan_dft_c2r_1d(size_, freqDomainData, timeDomainData, FFTW_ESTIMATE);
14
- fftwf_execute(plan);
15
- fftwf_destroy_plan(plan);
16
- fftwf_free(freqDomainData);
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
- VectorMath::multiplyByScalar(
19
- timeDomainData, 1.0f / static_cast<float>(size_), timeDomainData, size_);
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(&freqDomainData, 1, reinterpret_cast<DSPComplex *>(timeDomainData), 2, size_ / 2);
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_;
@@ -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 = std::make_shared<audioapi::AudioAPIInstallerHostObject>(wrapper);
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* outputBuffer, int numFrames);
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
- return (int)(self.audioSession.preferredIOBufferDuration * self.audioSession.sampleRate);
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* audioBus_;
19
- AudioPlayer* 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(const std::function<void(AudioBus*, int)> &renderAudio);
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) : renderAudio_(renderAudio), audioBus_(0)
10
+ IOSAudioPlayer::IOSAudioPlayer(const std::function<void(AudioBus *, int)> &renderAudio)
11
+ : renderAudio_(renderAudio), audioBus_(0)
11
12
  {
12
- RenderAudioBlock renderAudioBlock = ^(AudioBufferList* outputData, int numFrames) {
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