diff --git a/packages/audiodocs/docs/sources/audio-buffer.mdx b/packages/audiodocs/docs/sources/audio-buffer.mdx index 26efefb1f..b935da889 100644 --- a/packages/audiodocs/docs/sources/audio-buffer.mdx +++ b/packages/audiodocs/docs/sources/audio-buffer.mdx @@ -18,15 +18,15 @@ Once you have data in `AudioBuffer`, audio can be played by passing it to [`Audi ## Constructor ```tsx -constructor(context: BaseAudioContext, options: AudioBufferOptions) +constructor(options: AudioBufferOptions) ``` ### `AudioBufferOptions` | Parameter | Type | Default | Description | | :---: | :---: | :----: | :---- | -| `numberOfChannels` | `number` | 1.0 | Number of [`channels`](/docs/sources/audio-buffer#properties) in buffer | | `length` | `number` | - | [`Length`](/docs/sources/audio-buffer#properties) of the buffer | +| `numberOfChannels` | `number` | 1.0 | Number of [`channels`](/docs/sources/audio-buffer#properties) in buffer | | `sampleRate` | `number` | - | [`Sample rate`](/docs/sources/audio-buffer#properties) of the buffer in Hz | Or by using `BaseAudioContext` factory method: diff --git a/packages/custom-node-generator/templates/basic/shared/MyProcessorNode.cpp b/packages/custom-node-generator/templates/basic/shared/MyProcessorNode.cpp index 3aa07f407..b69d3986c 100644 --- a/packages/custom-node-generator/templates/basic/shared/MyProcessorNode.cpp +++ b/packages/custom-node-generator/templates/basic/shared/MyProcessorNode.cpp @@ -2,7 +2,7 @@ #include namespace audioapi { -MyProcessorNode::MyProcessorNode(BaseAudioContext *context) +MyProcessorNode::MyProcessorNode(std::shared_ptr context) : AudioNode(context) { isInitialized_ = true; } diff --git a/packages/custom-node-generator/templates/basic/shared/MyProcessorNode.h b/packages/custom-node-generator/templates/basic/shared/MyProcessorNode.h index e065ff359..1f339aaa0 100644 --- a/packages/custom-node-generator/templates/basic/shared/MyProcessorNode.h +++ b/packages/custom-node-generator/templates/basic/shared/MyProcessorNode.h @@ -6,7 +6,7 @@ class AudioBus; class MyProcessorNode : public AudioNode { public: - explicit MyProcessorNode(BaseAudioContext *context); + explicit MyProcessorNode(std::shared_ptr context); protected: std::shared_ptr processNode(const std::shared_ptr &bus, diff --git a/packages/react-native-audio-api/common/cpp/audioapi/AudioAPIModuleInstaller.h b/packages/react-native-audio-api/common/cpp/audioapi/AudioAPIModuleInstaller.h index 116673979..fb2543d4d 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/AudioAPIModuleInstaller.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/AudioAPIModuleInstaller.h @@ -3,11 +3,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include @@ -36,6 +38,7 @@ class AudioAPIModuleInstaller { getCreateAudioRecorderFunction(jsiRuntime, audioEventHandlerRegistry); auto createOfflineAudioContext = getCreateOfflineAudioContextFunction( jsiRuntime, jsCallInvoker, audioEventHandlerRegistry, uiRuntime); + auto createAudioBuffer = getCrateAudioBufferFunction(jsiRuntime); auto createAudioDecoder = getCreateAudioDecoderFunction(jsiRuntime, jsCallInvoker); auto createAudioStretcher = getCreateAudioStretcherFunction(jsiRuntime, jsCallInvoker); @@ -43,6 +46,7 @@ class AudioAPIModuleInstaller { jsiRuntime->global().setProperty(*jsiRuntime, "createAudioRecorder", createAudioRecorder); jsiRuntime->global().setProperty( *jsiRuntime, "createOfflineAudioContext", createOfflineAudioContext); + jsiRuntime->global().setProperty(*jsiRuntime, "createAudioBuffer", createAudioBuffer); jsiRuntime->global().setProperty(*jsiRuntime, "createAudioDecoder", createAudioDecoder); jsiRuntime->global().setProperty(*jsiRuntime, "createAudioStretcher", createAudioStretcher); @@ -63,7 +67,7 @@ class AudioAPIModuleInstaller { return jsi::Function::createFromHostFunction( *jsiRuntime, jsi::PropNameID::forAscii(*jsiRuntime, "createAudioContext"), - 0, + 1, [jsCallInvoker, audioEventHandlerRegistry, uiRuntime]( jsi::Runtime &runtime, const jsi::Value &thisValue, @@ -94,7 +98,7 @@ class AudioAPIModuleInstaller { return jsi::Function::createFromHostFunction( *jsiRuntime, jsi::PropNameID::forAscii(*jsiRuntime, "createOfflineAudioContext"), - 0, + 3, [jsCallInvoker, audioEventHandlerRegistry, uiRuntime]( jsi::Runtime &runtime, const jsi::Value &thisValue, @@ -181,6 +185,23 @@ class AudioAPIModuleInstaller { return jsi::Object::createFromHostObject(runtime, audioStretcherHostObject); }); } + + static jsi::Function getCrateAudioBufferFunction(jsi::Runtime *jsiRuntime) { + return jsi::Function::createFromHostFunction( + *jsiRuntime, + jsi::PropNameID::forAscii(*jsiRuntime, "createAudioStretcher"), + 3, + [](jsi::Runtime &runtime, const jsi::Value &thisValue, const jsi::Value *args, size_t count) + -> jsi::Value { + auto numberOfChannels = static_cast(args[0].getNumber()); + auto length = static_cast(args[1].getNumber()); + auto sampleRate = static_cast(args[2].getNumber()); + + auto audioBuffer = std::make_shared(numberOfChannels, length, sampleRate); + auto audioBufferHostObject = std::make_shared(audioBuffer); + return jsi::Object::createFromHostObject(runtime, audioBufferHostObject); + }); + } }; } // namespace audioapi diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/AudioNodeHostObject.cpp b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/AudioNodeHostObject.cpp index 7fea3115e..8976e9398 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/AudioNodeHostObject.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/AudioNodeHostObject.cpp @@ -7,7 +7,8 @@ namespace audioapi { -AudioNodeHostObject::AudioNodeHostObject(const std::shared_ptr &node) : node_(node) { +AudioNodeHostObject::AudioNodeHostObject(const std::shared_ptr &node, + const AudioNodeOptions &options) : node_(node) { addGetters( JSI_EXPORT_PROPERTY_GETTER(AudioNodeHostObject, numberOfInputs), JSI_EXPORT_PROPERTY_GETTER(AudioNodeHostObject, numberOfOutputs), diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/AudioNodeHostObject.h b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/AudioNodeHostObject.h index dfea4ab46..423f84b6d 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/AudioNodeHostObject.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/AudioNodeHostObject.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -13,7 +14,9 @@ class AudioNode; class AudioNodeHostObject : public JsiHostObject { public: - explicit AudioNodeHostObject(const std::shared_ptr &node); + explicit AudioNodeHostObject( + const std::shared_ptr &node, + const AudioNodeOptions &options = AudioNodeOptions()); ~AudioNodeHostObject() override; JSI_PROPERTY_GETTER_DECL(numberOfInputs); diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.cpp b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.cpp index aa9978d2a..9cb1d072f 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.cpp @@ -60,7 +60,6 @@ BaseAudioContextHostObject::BaseAudioContextHostObject( JSI_EXPORT_FUNCTION(BaseAudioContextHostObject, createIIRFilter), JSI_EXPORT_FUNCTION(BaseAudioContextHostObject, createBufferSource), JSI_EXPORT_FUNCTION(BaseAudioContextHostObject, createBufferQueueSource), - JSI_EXPORT_FUNCTION(BaseAudioContextHostObject, createBuffer), JSI_EXPORT_FUNCTION(BaseAudioContextHostObject, createPeriodicWave), JSI_EXPORT_FUNCTION(BaseAudioContextHostObject, createConvolver), JSI_EXPORT_FUNCTION(BaseAudioContextHostObject, createAnalyser), @@ -260,19 +259,6 @@ JSI_HOST_FUNCTION_IMPL(BaseAudioContextHostObject, createBufferQueueSource) { return jsi::Object::createFromHostObject(runtime, bufferStreamSourceHostObject); } -JSI_HOST_FUNCTION_IMPL(BaseAudioContextHostObject, createBuffer) { - const auto options = args[0].asObject(runtime); - const auto audioBufferOptions = - audioapi::option_parser::parseAudioBufferOptions(runtime, options); - auto buffer = BaseAudioContext::createBuffer(audioBufferOptions); - auto bufferHostObject = std::make_shared(buffer); - - auto jsiObject = jsi::Object::createFromHostObject(runtime, bufferHostObject); - jsiObject.setExternalMemoryPressure(runtime, bufferHostObject->getSizeInBytes()); - - return jsiObject; -} - JSI_HOST_FUNCTION_IMPL(BaseAudioContextHostObject, createPeriodicWave) { auto arrayBufferReal = args[0].getObject(runtime).getPropertyAsObject(runtime, "buffer").getArrayBuffer(runtime); diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.h b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.h index dc0ec18a5..6ccd1dc3d 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.h @@ -42,7 +42,6 @@ class BaseAudioContextHostObject : public JsiHostObject { JSI_HOST_FUNCTION_DECL(createIIRFilter); JSI_HOST_FUNCTION_DECL(createBufferSource); JSI_HOST_FUNCTION_DECL(createBufferQueueSource); - JSI_HOST_FUNCTION_DECL(createBuffer); JSI_HOST_FUNCTION_DECL(createPeriodicWave); JSI_HOST_FUNCTION_DECL(createAnalyser); JSI_HOST_FUNCTION_DECL(createConvolver); diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/analysis/AnalyserNodeHostObject.cpp b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/analysis/AnalyserNodeHostObject.cpp index 45b9be3e2..3edfd86ce 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/analysis/AnalyserNodeHostObject.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/analysis/AnalyserNodeHostObject.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include @@ -9,7 +9,7 @@ namespace audioapi { AnalyserNodeHostObject::AnalyserNodeHostObject(const std::shared_ptr& context, const AnalyserOptions &options) - : AudioNodeHostObject(context->createAnalyser(options)) { + : AudioNodeHostObject(context->createAnalyser(options), options) { addGetters( JSI_EXPORT_PROPERTY_GETTER(AnalyserNodeHostObject, fftSize), JSI_EXPORT_PROPERTY_GETTER(AnalyserNodeHostObject, frequencyBinCount), diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/destinations/AudioDestinationNodeHostObject.h b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/destinations/AudioDestinationNodeHostObject.h index b3e4211cc..03c985261 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/destinations/AudioDestinationNodeHostObject.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/destinations/AudioDestinationNodeHostObject.h @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -12,6 +13,6 @@ using namespace facebook; class AudioDestinationNodeHostObject : public AudioNodeHostObject { public: explicit AudioDestinationNodeHostObject(const std::shared_ptr &node) - : AudioNodeHostObject(node) {} + : AudioNodeHostObject(node, AudioDestinationOptions()) {} }; } // namespace audioapi diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/effects/BiquadFilterNodeHostObject.cpp b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/effects/BiquadFilterNodeHostObject.cpp index ced78f8c0..b2e785530 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/effects/BiquadFilterNodeHostObject.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/effects/BiquadFilterNodeHostObject.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include #include #include @@ -12,7 +12,7 @@ namespace audioapi { BiquadFilterNodeHostObject::BiquadFilterNodeHostObject(const std::shared_ptr& context, const BiquadFilterOptions &options) - : AudioNodeHostObject(context->createBiquadFilter(options)) { + : AudioNodeHostObject(context->createBiquadFilter(options), options) { addGetters( JSI_EXPORT_PROPERTY_GETTER(BiquadFilterNodeHostObject, frequency), JSI_EXPORT_PROPERTY_GETTER(BiquadFilterNodeHostObject, detune), diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/effects/ConvolverNodeHostObject.cpp b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/effects/ConvolverNodeHostObject.cpp index 42d9fbf8d..d6f72a4c2 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/effects/ConvolverNodeHostObject.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/effects/ConvolverNodeHostObject.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include @@ -9,7 +9,7 @@ namespace audioapi { ConvolverNodeHostObject::ConvolverNodeHostObject(const std::shared_ptr& context, const ConvolverOptions &options) - : AudioNodeHostObject(context->createConvolver(options)) { + : AudioNodeHostObject(context->createConvolver(options), options) { addGetters( JSI_EXPORT_PROPERTY_GETTER(ConvolverNodeHostObject, normalize), JSI_EXPORT_PROPERTY_GETTER(ConvolverNodeHostObject, buffer)); diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/effects/DelayNodeHostObject.cpp b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/effects/DelayNodeHostObject.cpp index 9035caca3..17929e069 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/effects/DelayNodeHostObject.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/effects/DelayNodeHostObject.cpp @@ -2,14 +2,14 @@ #include #include #include -#include +#include #include namespace audioapi { DelayNodeHostObject::DelayNodeHostObject(const std::shared_ptr& context, const DelayOptions &options) - : AudioNodeHostObject(context->createDelay(options)) { + : AudioNodeHostObject(context->createDelay(options), options) { addGetters(JSI_EXPORT_PROPERTY_GETTER(DelayNodeHostObject, delayTime)); } diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/effects/GainNodeHostObject.cpp b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/effects/GainNodeHostObject.cpp index 98c89de37..4f9c040ed 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/effects/GainNodeHostObject.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/effects/GainNodeHostObject.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include #include #include #include @@ -11,7 +11,7 @@ namespace audioapi { GainNodeHostObject::GainNodeHostObject( const std::shared_ptr &context, const GainOptions &options) - : AudioNodeHostObject(context->createGain(options)) { + : AudioNodeHostObject(context->createGain(options), options) { addGetters(JSI_EXPORT_PROPERTY_GETTER(GainNodeHostObject, gain)); } diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/effects/IIRFilterNodeHostObject.cpp b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/effects/IIRFilterNodeHostObject.cpp index 592457c70..e77cdfebc 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/effects/IIRFilterNodeHostObject.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/effects/IIRFilterNodeHostObject.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include @@ -9,7 +9,7 @@ namespace audioapi { IIRFilterNodeHostObject::IIRFilterNodeHostObject( const std::shared_ptr &context, const IIRFilterOptions &options) - : AudioNodeHostObject(context->createIIRFilter(options)) { + : AudioNodeHostObject(context->createIIRFilter(options), options) { addFunctions(JSI_EXPORT_FUNCTION(IIRFilterNodeHostObject, getFrequencyResponse)); } diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/effects/StereoPannerNodeHostObject.cpp b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/effects/StereoPannerNodeHostObject.cpp index 1fbd45f72..5170659ef 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/effects/StereoPannerNodeHostObject.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/effects/StereoPannerNodeHostObject.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include #include #include #include @@ -11,7 +11,7 @@ namespace audioapi { StereoPannerNodeHostObject::StereoPannerNodeHostObject( const std::shared_ptr &context, const StereoPannerOptions &options) - : AudioNodeHostObject(context->createStereoPanner(options)) { + : AudioNodeHostObject(context->createStereoPanner(options), options) { addGetters(JSI_EXPORT_PROPERTY_GETTER(StereoPannerNodeHostObject, pan)); } diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/effects/WaveShaperNodeHostObject.cpp b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/effects/WaveShaperNodeHostObject.cpp index 1550e9b72..f1351cdcf 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/effects/WaveShaperNodeHostObject.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/effects/WaveShaperNodeHostObject.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include #include @@ -13,7 +13,7 @@ namespace audioapi { WaveShaperNodeHostObject::WaveShaperNodeHostObject( const std::shared_ptr &context, const WaveShaperOptions &options) - : AudioNodeHostObject(context->createWaveShaper(options)) { + : AudioNodeHostObject(context->createWaveShaper(options), options) { addGetters( JSI_EXPORT_PROPERTY_GETTER(WaveShaperNodeHostObject, oversample), JSI_EXPORT_PROPERTY_GETTER(WaveShaperNodeHostObject, curve)); diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioBufferBaseSourceNodeHostObject.cpp b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioBufferBaseSourceNodeHostObject.cpp index d7152ffa8..9f503d682 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioBufferBaseSourceNodeHostObject.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioBufferBaseSourceNodeHostObject.cpp @@ -2,13 +2,15 @@ #include #include +#include #include namespace audioapi { AudioBufferBaseSourceNodeHostObject::AudioBufferBaseSourceNodeHostObject( - const std::shared_ptr &node) - : AudioScheduledSourceNodeHostObject(node) { + const std::shared_ptr &node, + const BaseAudioBufferSourceOptions &options) + : AudioScheduledSourceNodeHostObject(node, options) { addGetters( JSI_EXPORT_PROPERTY_GETTER(AudioBufferBaseSourceNodeHostObject, detune), JSI_EXPORT_PROPERTY_GETTER(AudioBufferBaseSourceNodeHostObject, playbackRate), diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioBufferBaseSourceNodeHostObject.h b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioBufferBaseSourceNodeHostObject.h index 60ee74d90..f65c39a14 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioBufferBaseSourceNodeHostObject.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioBufferBaseSourceNodeHostObject.h @@ -9,11 +9,13 @@ namespace audioapi { using namespace facebook; class AudioBufferBaseSourceNode; +struct BaseAudioBufferSourceOptions; class AudioBufferBaseSourceNodeHostObject : public AudioScheduledSourceNodeHostObject { public: explicit AudioBufferBaseSourceNodeHostObject( - const std::shared_ptr &node); + const std::shared_ptr &node, + const BaseAudioBufferSourceOptions &options); ~AudioBufferBaseSourceNodeHostObject() override; diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioBufferQueueSourceNodeHostObject.cpp b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioBufferQueueSourceNodeHostObject.cpp index 3705cb43b..f5996753c 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioBufferQueueSourceNodeHostObject.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioBufferQueueSourceNodeHostObject.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include #include #include #include @@ -11,7 +11,7 @@ namespace audioapi { AudioBufferQueueSourceNodeHostObject::AudioBufferQueueSourceNodeHostObject( const std::shared_ptr &context, const BaseAudioBufferSourceOptions &options) - : AudioBufferBaseSourceNodeHostObject(context->createBufferQueueSource(options)) { + : AudioBufferBaseSourceNodeHostObject(context->createBufferQueueSource(options), options) { functions_->erase("start"); addSetters(JSI_EXPORT_PROPERTY_SETTER(AudioBufferQueueSourceNodeHostObject, onBufferEnded)); diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioBufferSourceNodeHostObject.cpp b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioBufferSourceNodeHostObject.cpp index faadb9da8..ac23adb1d 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioBufferSourceNodeHostObject.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioBufferSourceNodeHostObject.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include #include #include #include @@ -11,7 +11,7 @@ namespace audioapi { AudioBufferSourceNodeHostObject::AudioBufferSourceNodeHostObject( const std::shared_ptr &context, const AudioBufferSourceOptions &options) - : AudioBufferBaseSourceNodeHostObject(context->createBufferSource(options)) { + : AudioBufferBaseSourceNodeHostObject(context->createBufferSource(options), options) { addGetters( JSI_EXPORT_PROPERTY_GETTER(AudioBufferSourceNodeHostObject, loop), JSI_EXPORT_PROPERTY_GETTER(AudioBufferSourceNodeHostObject, loopSkip), diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioScheduledSourceNodeHostObject.cpp b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioScheduledSourceNodeHostObject.cpp index dc3542710..0f6c06c38 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioScheduledSourceNodeHostObject.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioScheduledSourceNodeHostObject.cpp @@ -1,12 +1,14 @@ #include - #include +#include + #include namespace audioapi { AudioScheduledSourceNodeHostObject::AudioScheduledSourceNodeHostObject( - const std::shared_ptr &node) + const std::shared_ptr &node, + const AudioScheduledSourceNodeOptions &options) : AudioNodeHostObject(node) { addSetters(JSI_EXPORT_PROPERTY_SETTER(AudioScheduledSourceNodeHostObject, onEnded)); diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioScheduledSourceNodeHostObject.h b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioScheduledSourceNodeHostObject.h index 8b9c3c101..f80caf5b6 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioScheduledSourceNodeHostObject.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioScheduledSourceNodeHostObject.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -13,7 +14,8 @@ class AudioScheduledSourceNode; class AudioScheduledSourceNodeHostObject : public AudioNodeHostObject { public: explicit AudioScheduledSourceNodeHostObject( - const std::shared_ptr &node); + const std::shared_ptr &node, + const AudioScheduledSourceNodeOptions &options = AudioScheduledSourceNodeOptions()); ~AudioScheduledSourceNodeHostObject() override; diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/ConstantSourceNodeHostObject.cpp b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/ConstantSourceNodeHostObject.cpp index d8d13cd4a..57ec5e828 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/ConstantSourceNodeHostObject.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/ConstantSourceNodeHostObject.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include #include @@ -10,7 +10,7 @@ namespace audioapi { ConstantSourceNodeHostObject::ConstantSourceNodeHostObject( const std::shared_ptr &context, const ConstantSourceOptions &options) - : AudioScheduledSourceNodeHostObject(context->createConstantSource(options)) { + : AudioScheduledSourceNodeHostObject(context->createConstantSource(options), options) { addGetters(JSI_EXPORT_PROPERTY_GETTER(ConstantSourceNodeHostObject, offset)); } diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/OscillatorNodeHostObject.cpp b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/OscillatorNodeHostObject.cpp index 85641fb33..0dfd11326 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/OscillatorNodeHostObject.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/OscillatorNodeHostObject.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include #include @@ -13,7 +13,7 @@ namespace audioapi { OscillatorNodeHostObject::OscillatorNodeHostObject( const std::shared_ptr &context, const OscillatorOptions &options) - : AudioScheduledSourceNodeHostObject(context->createOscillator(options)) { + : AudioScheduledSourceNodeHostObject(context->createOscillator(options), options) { addGetters( JSI_EXPORT_PROPERTY_GETTER(OscillatorNodeHostObject, frequency), JSI_EXPORT_PROPERTY_GETTER(OscillatorNodeHostObject, detune), diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/StreamerNodeHostObject.cpp b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/StreamerNodeHostObject.cpp index f9dbef6f5..90ca56353 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/StreamerNodeHostObject.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/StreamerNodeHostObject.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include #include @@ -12,7 +12,7 @@ namespace audioapi { StreamerNodeHostObject::StreamerNodeHostObject( const std::shared_ptr &context, const StreamerOptions &options) - : AudioScheduledSourceNodeHostObject(context->createStreamer(options)) { + : AudioScheduledSourceNodeHostObject(context->createStreamer(options), options) { addFunctions(JSI_EXPORT_FUNCTION(StreamerNodeHostObject, initialize)); addGetters(JSI_EXPORT_PROPERTY_GETTER(StreamerNodeHostObject, streamPath)); } diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/utils/NodeOptions.h b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/utils/NodeOptions.h deleted file mode 100644 index b3fcd250c..000000000 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/utils/NodeOptions.h +++ /dev/null @@ -1,111 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace audioapi { -struct AudioNodeOptions { - int channelCount = 2; - ChannelCountMode channelCountMode; - ChannelInterpretation channelInterpretation; -}; - -struct GainOptions : AudioNodeOptions { - float gain; -}; - -struct StereoPannerOptions : AudioNodeOptions { - float pan; -}; - -struct ConvolverOptions : AudioNodeOptions { - std::shared_ptr bus; - bool disableNormalization; -}; - -struct ConstantSourceOptions { - float offset; -}; - -struct AnalyserOptions : AudioNodeOptions { - int fftSize; - float minDecibels; - float maxDecibels; - float smoothingTimeConstant; -}; - -struct BiquadFilterOptions : AudioNodeOptions { - BiquadFilterType type; - float frequency; - float detune; - float Q; - float gain; -}; - -struct OscillatorOptions { - std::shared_ptr periodicWave; - float frequency; - float detune; - OscillatorType type; -}; - -struct BaseAudioBufferSourceOptions { - float detune; - bool pitchCorrection; - float playbackRate; -}; - -struct AudioBufferSourceOptions : BaseAudioBufferSourceOptions { - std::shared_ptr buffer; - bool loop; - float loopStart; - float loopEnd; -}; - -struct StreamerOptions { - std::string streamPath; -}; - -struct AudioBufferOptions { - int numberOfChannels; - size_t length; - float sampleRate; -}; - -struct DelayOptions : AudioNodeOptions { - float maxDelayTime; - float delayTime; -}; - -struct IIRFilterOptions : AudioNodeOptions { - std::vector feedforward; - std::vector feedback; - - IIRFilterOptions() = default; - - explicit IIRFilterOptions(const AudioNodeOptions options) : AudioNodeOptions(options) {} - - IIRFilterOptions(const std::vector &ff, const std::vector &fb) - : feedforward(ff), feedback(fb) {} - - IIRFilterOptions(std::vector &&ff, std::vector &&fb) - : feedforward(std::move(ff)), feedback(std::move(fb)) {} -}; - -struct WaveShaperOptions : AudioNodeOptions { - std::shared_ptr curve; - OverSampleType oversample; -}; - -} // namespace audioapi diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/utils/NodeOptionsParser.h b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/utils/NodeOptionsParser.h index ede0e4a94..d98b386fe 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/utils/NodeOptionsParser.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/utils/NodeOptionsParser.h @@ -9,33 +9,37 @@ #include #include -#include +#include namespace audioapi::option_parser { AudioNodeOptions parseAudioNodeOptions(jsi::Runtime &runtime, const jsi::Object &optionsObject) { AudioNodeOptions options; - options.channelCount = - static_cast(optionsObject.getProperty(runtime, "channelCount").getNumber()); - - auto channelCountModeStr = - optionsObject.getProperty(runtime, "channelCountMode").asString(runtime).utf8(runtime); - - if (channelCountModeStr == "max") { - options.channelCountMode = ChannelCountMode::MAX; - } else if (channelCountModeStr == "clamped-max") { - options.channelCountMode = ChannelCountMode::CLAMPED_MAX; - } else if (channelCountModeStr == "explicit") { - options.channelCountMode = ChannelCountMode::EXPLICIT; + auto channelCountValue = optionsObject.getProperty(runtime, "channelCount"); + if (channelCountValue.isNumber()) { + options.channelCount = static_cast(channelCountValue.getNumber()); } - auto channelInterpretationStr = - optionsObject.getProperty(runtime, "channelInterpretation").asString(runtime).utf8(runtime); + auto channelCountModeValue = optionsObject.getProperty(runtime, "channelCountMode"); + if (channelCountModeValue.isString()) { + auto channelCountModeStr = channelCountModeValue.asString(runtime).utf8(runtime); + if (channelCountModeStr == "max") { + options.channelCountMode = ChannelCountMode::MAX; + } else if (channelCountModeStr == "clamped-max") { + options.channelCountMode = ChannelCountMode::CLAMPED_MAX; + } else if (channelCountModeStr == "explicit") { + options.channelCountMode = ChannelCountMode::EXPLICIT; + } + } - if (channelInterpretationStr == "speakers") { - options.channelInterpretation = ChannelInterpretation::SPEAKERS; - } else if (channelInterpretationStr == "discrete") { - options.channelInterpretation = ChannelInterpretation::DISCRETE; + auto channelInterpretationValue = optionsObject.getProperty(runtime, "channelInterpretation"); + if (channelInterpretationValue.isString()) { + auto channelInterpretationStr = channelInterpretationValue.asString(runtime).utf8(runtime); + if (channelInterpretationStr == "speakers") { + options.channelInterpretation = ChannelInterpretation::SPEAKERS; + } else if (channelInterpretationStr == "discrete") { + options.channelInterpretation = ChannelInterpretation::DISCRETE; + } } return options; @@ -43,7 +47,12 @@ AudioNodeOptions parseAudioNodeOptions(jsi::Runtime &runtime, const jsi::Object GainOptions parseGainOptions(jsi::Runtime &runtime, const jsi::Object &optionsObject) { GainOptions options(parseAudioNodeOptions(runtime, optionsObject)); - options.gain = static_cast(optionsObject.getProperty(runtime, "gain").getNumber()); + + auto gainValue = optionsObject.getProperty(runtime, "gain"); + if (gainValue.isNumber()) { + options.gain = static_cast(gainValue.getNumber()); + } + return options; } @@ -51,14 +60,23 @@ StereoPannerOptions parseStereoPannerOptions( jsi::Runtime &runtime, const jsi::Object &optionsObject) { StereoPannerOptions options(parseAudioNodeOptions(runtime, optionsObject)); - options.pan = static_cast(optionsObject.getProperty(runtime, "pan").getNumber()); + + auto panValue = optionsObject.getProperty(runtime, "pan"); + if (panValue.isNumber()) { + options.pan = static_cast(panValue.getNumber()); + } + return options; } ConvolverOptions parseConvolverOptions(jsi::Runtime &runtime, const jsi::Object &optionsObject) { ConvolverOptions options(parseAudioNodeOptions(runtime, optionsObject)); - options.disableNormalization = - optionsObject.getProperty(runtime, "disableNormalization").getBool(); + + auto disableNormalizationValue = optionsObject.getProperty(runtime, "disableNormalization"); + if (disableNormalizationValue.isBool()) { + options.disableNormalization = disableNormalizationValue.getBool(); + } + if (optionsObject.hasProperty(runtime, "buffer")) { auto bufferHostObject = optionsObject.getProperty(runtime, "buffer") .getObject(runtime) @@ -72,19 +90,38 @@ ConstantSourceOptions parseConstantSourceOptions( jsi::Runtime &runtime, const jsi::Object &optionsObject) { ConstantSourceOptions options; - options.offset = static_cast(optionsObject.getProperty(runtime, "offset").getNumber()); + + auto offsetValue = optionsObject.getProperty(runtime, "offset"); + if (offsetValue.isNumber()) { + options.offset = static_cast(offsetValue.getNumber()); + } + return options; } AnalyserOptions parseAnalyserOptions(jsi::Runtime &runtime, const jsi::Object &optionsObject) { AnalyserOptions options(parseAudioNodeOptions(runtime, optionsObject)); - options.fftSize = static_cast(optionsObject.getProperty(runtime, "fftSize").getNumber()); - options.minDecibels = - static_cast(optionsObject.getProperty(runtime, "minDecibels").getNumber()); - options.maxDecibels = - static_cast(optionsObject.getProperty(runtime, "maxDecibels").getNumber()); - options.smoothingTimeConstant = - static_cast(optionsObject.getProperty(runtime, "smoothingTimeConstant").getNumber()); + + auto fftSizeValue = optionsObject.getProperty(runtime, "fftSize"); + if (fftSizeValue.isNumber()) { + options.fftSize = static_cast(fftSizeValue.getNumber()); + } + + auto minDecibelsValue = optionsObject.getProperty(runtime, "minDecibels"); + if (minDecibelsValue.isNumber()) { + options.minDecibels = static_cast(minDecibelsValue.getNumber()); + } + + auto maxDecibelsValue = optionsObject.getProperty(runtime, "maxDecibels"); + if (maxDecibelsValue.isNumber()) { + options.maxDecibels = static_cast(maxDecibelsValue.getNumber()); + } + + auto smoothingTimeConstantValue = optionsObject.getProperty(runtime, "smoothingTimeConstant"); + if (smoothingTimeConstantValue.isNumber()) { + options.smoothingTimeConstant = static_cast(smoothingTimeConstantValue.getNumber()); + } + return options; } @@ -93,31 +130,47 @@ BiquadFilterOptions parseBiquadFilterOptions( const jsi::Object &optionsObject) { BiquadFilterOptions options(parseAudioNodeOptions(runtime, optionsObject)); - auto typeStr = optionsObject.getProperty(runtime, "type").asString(runtime).utf8(runtime); - - if (typeStr == "lowpass") { - options.type = BiquadFilterType::LOWPASS; - } else if (typeStr == "highpass") { - options.type = BiquadFilterType::HIGHPASS; - } else if (typeStr == "bandpass") { - options.type = BiquadFilterType::BANDPASS; - } else if (typeStr == "lowshelf") { - options.type = BiquadFilterType::LOWSHELF; - } else if (typeStr == "highshelf") { - options.type = BiquadFilterType::HIGHSHELF; - } else if (typeStr == "peaking") { - options.type = BiquadFilterType::PEAKING; - } else if (typeStr == "notch") { - options.type = BiquadFilterType::NOTCH; - } else if (typeStr == "allpass") { - options.type = BiquadFilterType::ALLPASS; - } - - options.frequency = - static_cast(optionsObject.getProperty(runtime, "frequency").getNumber()); - options.detune = static_cast(optionsObject.getProperty(runtime, "detune").getNumber()); - options.Q = static_cast(optionsObject.getProperty(runtime, "Q").getNumber()); - options.gain = static_cast(optionsObject.getProperty(runtime, "gain").getNumber()); + auto typeValue = optionsObject.getProperty(runtime, "type"); + if (typeValue.isString()) { + auto typeStr = typeValue.asString(runtime).utf8(runtime); + if (typeStr == "lowpass") { + options.type = BiquadFilterType::LOWPASS; + } else if (typeStr == "highpass") { + options.type = BiquadFilterType::HIGHPASS; + } else if (typeStr == "bandpass") { + options.type = BiquadFilterType::BANDPASS; + } else if (typeStr == "lowshelf") { + options.type = BiquadFilterType::LOWSHELF; + } else if (typeStr == "highshelf") { + options.type = BiquadFilterType::HIGHSHELF; + } else if (typeStr == "peaking") { + options.type = BiquadFilterType::PEAKING; + } else if (typeStr == "notch") { + options.type = BiquadFilterType::NOTCH; + } else if (typeStr == "allpass") { + options.type = BiquadFilterType::ALLPASS; + } + } + + auto frequencyValue = optionsObject.getProperty(runtime, "frequency"); + if (frequencyValue.isNumber()) { + options.frequency = static_cast(frequencyValue.getNumber()); + } + + auto detuneValue = optionsObject.getProperty(runtime, "detune"); + if (detuneValue.isNumber()) { + options.detune = static_cast(detuneValue.getNumber()); + } + + auto QValue = optionsObject.getProperty(runtime, "Q"); + if (QValue.isNumber()) { + options.Q = static_cast(QValue.getNumber()); + } + + auto gainValue = optionsObject.getProperty(runtime, "gain"); + if (gainValue.isNumber()) { + options.gain = static_cast(gainValue.getNumber()); + } return options; } @@ -125,28 +178,36 @@ BiquadFilterOptions parseBiquadFilterOptions( OscillatorOptions parseOscillatorOptions(jsi::Runtime &runtime, const jsi::Object &optionsObject) { OscillatorOptions options; - auto typeStr = optionsObject.getProperty(runtime, "type").asString(runtime).utf8(runtime); + auto typeValue = optionsObject.getProperty(runtime, "type"); + if (typeValue.isString()) { + auto typeStr = typeValue.asString(runtime).utf8(runtime); + if (typeStr == "sine") { + options.type = OscillatorType::SINE; + } else if (typeStr == "square") { + options.type = OscillatorType::SQUARE; + } else if (typeStr == "sawtooth") { + options.type = OscillatorType::SAWTOOTH; + } else if (typeStr == "triangle") { + options.type = OscillatorType::TRIANGLE; + } else if (typeStr == "custom") { + options.type = OscillatorType::CUSTOM; + } + } - if (typeStr == "sine") { - options.type = OscillatorType::SINE; - } else if (typeStr == "square") { - options.type = OscillatorType::SQUARE; - } else if (typeStr == "sawtooth") { - options.type = OscillatorType::SAWTOOTH; - } else if (typeStr == "triangle") { - options.type = OscillatorType::TRIANGLE; - } else if (typeStr == "custom") { - options.type = OscillatorType::CUSTOM; + auto frequencyValue = optionsObject.getProperty(runtime, "frequency"); + if (frequencyValue.isNumber()) { + options.frequency = static_cast(frequencyValue.getNumber()); } - options.frequency = - static_cast(optionsObject.getProperty(runtime, "frequency").getNumber()); - options.detune = static_cast(optionsObject.getProperty(runtime, "detune").getNumber()); + auto detuneValue = optionsObject.getProperty(runtime, "detune"); + if (detuneValue.isNumber()) { + options.detune = static_cast(detuneValue.getNumber()); + } - if (optionsObject.hasProperty(runtime, "periodicWave")) { - auto periodicWaveHostObject = optionsObject.getProperty(runtime, "periodicWave") - .getObject(runtime) - .asHostObject(runtime); + auto periodicWaveValue = optionsObject.getProperty(runtime, "periodicWave"); + if (periodicWaveValue.isObject()) { + auto periodicWaveHostObject = + periodicWaveValue.getObject(runtime).asHostObject(runtime); options.periodicWave = periodicWaveHostObject->periodicWave_; } @@ -157,11 +218,22 @@ BaseAudioBufferSourceOptions parseBaseAudioBufferSourceOptions( jsi::Runtime &runtime, const jsi::Object &optionsObject) { BaseAudioBufferSourceOptions options; - options.detune = static_cast(optionsObject.getProperty(runtime, "detune").getNumber()); - options.playbackRate = - static_cast(optionsObject.getProperty(runtime, "playbackRate").getNumber()); - options.pitchCorrection = - static_cast(optionsObject.getProperty(runtime, "pitchCorrection").getBool()); + + auto detuneValue = optionsObject.getProperty(runtime, "detune"); + if (detuneValue.isNumber()) { + options.detune = static_cast(detuneValue.getNumber()); + } + + auto playbackRateValue = optionsObject.getProperty(runtime, "playbackRate"); + if (playbackRateValue.isNumber()) { + options.playbackRate = static_cast(playbackRateValue.getNumber()); + } + + auto pitchCorrectionValue = optionsObject.getProperty(runtime, "pitchCorrection"); + if (pitchCorrectionValue.isBool()) { + options.pitchCorrection = static_cast(pitchCorrectionValue.getBool()); + } + return options; } @@ -169,16 +241,29 @@ AudioBufferSourceOptions parseAudioBufferSourceOptions( jsi::Runtime &runtime, const jsi::Object &optionsObject) { AudioBufferSourceOptions options(parseBaseAudioBufferSourceOptions(runtime, optionsObject)); + if (optionsObject.hasProperty(runtime, "buffer")) { auto bufferHostObject = optionsObject.getProperty(runtime, "buffer") .getObject(runtime) .asHostObject(runtime); options.buffer = bufferHostObject->audioBuffer_; } - options.loop = static_cast(optionsObject.getProperty(runtime, "loop").getBool()); - options.loopStart = - static_cast(optionsObject.getProperty(runtime, "loopStart").getNumber()); - options.loopEnd = static_cast(optionsObject.getProperty(runtime, "loopEnd").getNumber()); + + auto loopValue = optionsObject.getProperty(runtime, "loop"); + if (loopValue.isBool()) { + options.loop = static_cast(loopValue.getBool()); + } + + auto loopStartValue = optionsObject.getProperty(runtime, "loopStart"); + if (loopStartValue.isNumber()) { + options.loopStart = static_cast(loopStartValue.getNumber()); + } + + auto loopEndValue = optionsObject.getProperty(runtime, "loopEnd"); + if (loopEndValue.isNumber()) { + options.loopEnd = static_cast(loopEndValue.getNumber()); + } + return options; } @@ -191,46 +276,45 @@ StreamerOptions parseStreamerOptions(jsi::Runtime &runtime, const jsi::Object &o return options; } -AudioBufferOptions parseAudioBufferOptions( - jsi::Runtime &runtime, - const jsi::Object &optionsObject) { - AudioBufferOptions options; - options.numberOfChannels = - static_cast(optionsObject.getProperty(runtime, "numberOfChannels").getNumber()); - options.length = static_cast(optionsObject.getProperty(runtime, "length").getNumber()); - options.sampleRate = - static_cast(optionsObject.getProperty(runtime, "sampleRate").getNumber()); - return options; -} - DelayOptions parseDelayOptions(jsi::Runtime &runtime, const jsi::Object &optionsObject) { DelayOptions options(parseAudioNodeOptions(runtime, optionsObject)); - options.maxDelayTime = - static_cast(optionsObject.getProperty(runtime, "maxDelayTime").getNumber()); - options.delayTime = - static_cast(optionsObject.getProperty(runtime, "delayTime").getNumber()); + + auto maxDelayTimeValue = optionsObject.getProperty(runtime, "maxDelayTime"); + if (maxDelayTimeValue.isNumber()) { + options.maxDelayTime = static_cast(maxDelayTimeValue.getNumber()); + } + + auto delayTimeValue = optionsObject.getProperty(runtime, "delayTime"); + if (delayTimeValue.isNumber()) { + options.delayTime = static_cast(delayTimeValue.getNumber()); + } + return options; } IIRFilterOptions parseIIRFilterOptions(jsi::Runtime &runtime, const jsi::Object &optionsObject) { IIRFilterOptions options(parseAudioNodeOptions(runtime, optionsObject)); - auto feedforwardArray = - optionsObject.getProperty(runtime, "feedforward").asObject(runtime).asArray(runtime); - size_t feedforwardLength = feedforwardArray.size(runtime); - options.feedforward.reserve(feedforwardLength); - for (size_t i = 0; i < feedforwardLength; ++i) { - options.feedforward.push_back( - static_cast(feedforwardArray.getValueAtIndex(runtime, i).getNumber())); + auto feedforwardValue = optionsObject.getProperty(runtime, "feedforward"); + if (feedforwardValue.isObject()) { + auto feedforwardArray = feedforwardValue.asObject(runtime).asArray(runtime); + size_t feedforwardLength = feedforwardArray.size(runtime); + options.feedforward.reserve(feedforwardLength); + for (size_t i = 0; i < feedforwardLength; ++i) { + options.feedforward.push_back( + static_cast(feedforwardArray.getValueAtIndex(runtime, i).getNumber())); + } } - auto feedbackArray = - optionsObject.getProperty(runtime, "feedback").asObject(runtime).asArray(runtime); - size_t feedbackLength = feedbackArray.size(runtime); - options.feedback.reserve(feedbackLength); - for (size_t i = 0; i < feedbackLength; ++i) { - options.feedback.push_back( - static_cast(feedbackArray.getValueAtIndex(runtime, i).getNumber())); + auto feedbackValue = optionsObject.getProperty(runtime, "feedback"); + if (feedbackValue.isObject()) { + auto feedbackArray = feedbackValue.asObject(runtime).asArray(runtime); + size_t feedbackLength = feedbackArray.size(runtime); + options.feedback.reserve(feedbackLength); + for (size_t i = 0; i < feedbackLength; ++i) { + options.feedback.push_back( + static_cast(feedbackArray.getValueAtIndex(runtime, i).getNumber())); + } } return options; @@ -239,15 +323,16 @@ IIRFilterOptions parseIIRFilterOptions(jsi::Runtime &runtime, const jsi::Object WaveShaperOptions parseWaveShaperOptions(jsi::Runtime &runtime, const jsi::Object &optionsObject) { WaveShaperOptions options(parseAudioNodeOptions(runtime, optionsObject)); - auto oversampleStr = - optionsObject.getProperty(runtime, "oversample").asString(runtime).utf8(runtime); - - if (oversampleStr == "none") { - options.oversample = OverSampleType::OVERSAMPLE_NONE; - } else if (oversampleStr == "2x") { - options.oversample = OverSampleType::OVERSAMPLE_2X; - } else if (oversampleStr == "4x") { - options.oversample = OverSampleType::OVERSAMPLE_4X; + auto oversampleValue = optionsObject.getProperty(runtime, "oversample"); + if (oversampleValue.isString()) { + auto oversampleStr = oversampleValue.asString(runtime).utf8(runtime); + if (oversampleStr == "none") { + options.oversample = OverSampleType::OVERSAMPLE_NONE; + } else if (oversampleStr == "2x") { + options.oversample = OverSampleType::OVERSAMPLE_2X; + } else if (oversampleStr == "4x") { + options.oversample = OverSampleType::OVERSAMPLE_4X; + } } if (optionsObject.hasProperty(runtime, "buffer")) { diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/AudioNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/AudioNode.cpp index e8cd1503e..7a7a8e7c9 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/AudioNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/AudioNode.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -11,15 +11,13 @@ namespace audioapi { -AudioNode::AudioNode(const std::shared_ptr& context) : context_(context) { - audioBus_ = - std::make_shared(RENDER_QUANTUM_SIZE, channelCount_, context->getSampleRate()); -} - AudioNode::AudioNode( const std::shared_ptr &context, const AudioNodeOptions &options) : context_(context), + numberOfInputs_(options.numberOfInputs), + numberOfOutputs_(options.numberOfOutputs), + requiresTailProcessing_(options.requiresTailProcessing), channelCount_(options.channelCount), channelCountMode_(options.channelCountMode), channelInterpretation_(options.channelInterpretation) { diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/AudioNode.h b/packages/react-native-audio-api/common/cpp/audioapi/core/AudioNode.h index 8a52f15c3..58cfe64d9 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/AudioNode.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/AudioNode.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -16,14 +17,12 @@ namespace audioapi { class AudioBus; class BaseAudioContext; class AudioParam; -struct AudioNodeOptions; class AudioNode : public std::enable_shared_from_this { public: - explicit AudioNode(const std::shared_ptr &context); explicit AudioNode( const std::shared_ptr &context, - const AudioNodeOptions &options); + const AudioNodeOptions &options = AudioNodeOptions()); virtual ~AudioNode(); int getNumberOfInputs() const; @@ -55,20 +54,20 @@ class AudioNode : public std::enable_shared_from_this { std::weak_ptr context_; std::shared_ptr audioBus_; - int numberOfInputs_ = 1; - int numberOfOutputs_ = 1; - int channelCount_ = 2; - ChannelCountMode channelCountMode_ = ChannelCountMode::MAX; - ChannelInterpretation channelInterpretation_ = ChannelInterpretation::SPEAKERS; - std::unordered_set inputNodes_ = {}; std::unordered_set> outputNodes_ = {}; std::unordered_set> outputParams_ = {}; + const int numberOfInputs_; + const int numberOfOutputs_; + int channelCount_; + const bool requiresTailProcessing_; + const ChannelCountMode channelCountMode_; + const ChannelInterpretation channelInterpretation_; + int numberOfEnabledInputNodes_ = 0; bool isInitialized_ = false; bool isEnabled_ = true; - bool requiresTailProcessing_ = false; std::size_t lastRenderedFrame_{SIZE_MAX}; diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/BaseAudioContext.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/BaseAudioContext.cpp index 78b8888cf..8c26da911 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/BaseAudioContext.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/BaseAudioContext.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -191,10 +191,6 @@ std::shared_ptr BaseAudioContext::createBufferQueueS return bufferSource; } -std::shared_ptr BaseAudioContext::createBuffer(const AudioBufferOptions &options) { - return std::make_shared(options); -} - std::shared_ptr BaseAudioContext::createPeriodicWave( const std::vector> &complexData, bool disableNormalization, diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/BaseAudioContext.h b/packages/react-native-audio-api/common/cpp/audioapi/core/BaseAudioContext.h index a684eda13..f68b5afd5 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/BaseAudioContext.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/BaseAudioContext.h @@ -50,7 +50,6 @@ struct OscillatorOptions; struct BaseAudioBufferSourceOptions; struct AudioBufferSourceOptions; struct StreamerOptions; -struct AudioBufferOptions; struct DelayOptions; struct IIRFilterOptions; struct WaveShaperOptions; @@ -98,7 +97,6 @@ class BaseAudioContext : public std::enable_shared_from_this { const AudioBufferSourceOptions &options); std::shared_ptr createBufferQueueSource( const BaseAudioBufferSourceOptions &options); - static std::shared_ptr createBuffer(const AudioBufferOptions &options); std::shared_ptr createPeriodicWave( const std::vector> &complexData, bool disableNormalization, diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/analysis/AnalyserNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/analysis/AnalyserNode.cpp index f0396a522..fbfd5ff3a 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/analysis/AnalyserNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/analysis/AnalyserNode.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/destinations/AudioDestinationNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/destinations/AudioDestinationNode.cpp index 9133f688a..356bb367c 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/destinations/AudioDestinationNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/destinations/AudioDestinationNode.cpp @@ -3,15 +3,13 @@ #include #include #include +#include #include namespace audioapi { AudioDestinationNode::AudioDestinationNode(const std::shared_ptr &context) - : AudioNode(context), currentSampleFrame_(0) { - numberOfOutputs_ = 0; - numberOfInputs_ = 1; - channelCountMode_ = ChannelCountMode::EXPLICIT; + : AudioNode(context, AudioDestinationOptions()), currentSampleFrame_(0) { isInitialized_ = true; } diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/destinations/AudioDestinationNode.h b/packages/react-native-audio-api/common/cpp/audioapi/core/destinations/AudioDestinationNode.h index 94b8e3bba..d84598dd2 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/destinations/AudioDestinationNode.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/destinations/AudioDestinationNode.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/BiquadFilterNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/BiquadFilterNode.cpp index d7da37744..152c14289 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/BiquadFilterNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/BiquadFilterNode.cpp @@ -26,7 +26,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include +#include #include #include #include diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/ConvolverNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/ConvolverNode.cpp index 35077afdd..8b5ceed9d 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/ConvolverNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/ConvolverNode.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -24,9 +24,6 @@ ConvolverNode::ConvolverNode(const std::shared_ptr& context, c buffer_(nullptr), internalBuffer_(nullptr) { setBuffer(options.bus); - audioBus_ = - std::make_shared(RENDER_QUANTUM_SIZE, channelCount_, context->getSampleRate()); - requiresTailProcessing_ = true; isInitialized_ = true; } diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/DelayNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/DelayNode.cpp index 04a4dd886..15b53dbe8 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/DelayNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/DelayNode.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -18,7 +18,6 @@ DelayNode::DelayNode(const std::shared_ptr& context, const Del 1), // +1 to enable delayTime equal to maxDelayTime channelCount_, context->getSampleRate())) { - requiresTailProcessing_ = true; isInitialized_ = true; } diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/GainNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/GainNode.cpp index 57da13581..bb8865879 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/GainNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/GainNode.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/IIRFilterNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/IIRFilterNode.cpp index 467098bf1..bf656d915 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/IIRFilterNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/IIRFilterNode.cpp @@ -23,7 +23,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include +#include #include #include #include diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/StereoPannerNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/StereoPannerNode.cpp index ca6b0ad47..ae7c225e3 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/StereoPannerNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/StereoPannerNode.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/WaveShaperNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/WaveShaperNode.cpp index e16198b4b..9824d763d 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/WaveShaperNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/WaveShaperNode.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -21,8 +21,6 @@ WaveShaperNode::WaveShaperNode( waveShapers_.emplace_back(std::make_unique(nullptr)); } setCurve(options.curve); - // to change after graph processing improvement - should be max - channelCountMode_ = ChannelCountMode::CLAMPED_MAX; isInitialized_ = true; } diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBuffer.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBuffer.cpp index 528ca7703..295ffb100 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBuffer.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBuffer.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -9,8 +9,8 @@ namespace audioapi { -AudioBuffer::AudioBuffer(const AudioBufferOptions &options) - : bus_(std::make_shared(options.length, options.numberOfChannels, options.sampleRate)) {} +AudioBuffer::AudioBuffer(int numberOfChannels, size_t length, float sampleRate) + : bus_(std::make_shared(length, numberOfChannels, sampleRate)) {} AudioBuffer::AudioBuffer(std::shared_ptr bus) { bus_ = std::move(bus); diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBuffer.h b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBuffer.h index 6d0b157a9..4a8cfea6c 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBuffer.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBuffer.h @@ -10,13 +10,12 @@ namespace audioapi { class AudioBus; -struct AudioBufferOptions; /// AudioBuffer is not thread-safe. /// Due to that fact it should be copied when passing between threads. class AudioBuffer { public: - explicit AudioBuffer(const AudioBufferOptions &options); + explicit AudioBuffer(int numberOfChannels, size_t length, float sampleRate); explicit AudioBuffer(std::shared_ptr bus); [[nodiscard]] size_t getLength() const; diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.cpp index f73a4b3c7..b9fd1e1bd 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -14,7 +14,7 @@ namespace audioapi { AudioBufferBaseSourceNode::AudioBufferBaseSourceNode( const std::shared_ptr &context, const BaseAudioBufferSourceOptions &options) - : AudioScheduledSourceNode(context), + : AudioScheduledSourceNode(context, options), pitchCorrection_(options.pitchCorrection), vReadIndex_(0.0) { onPositionChangedInterval_ = static_cast(context->getSampleRate() * 0.1); diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.cpp index c845dd40e..d5d9268ae 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -29,11 +29,8 @@ AudioBufferQueueSourceNode::AudioBufferQueueSourceNode( // If pitch correction is enabled, add extra frames at the end // to compensate for processing latency. addExtraTailFrames_ = true; - int extraTailFrames = static_cast(stretch_->inputLatency() + stretch_->outputLatency()); - auto audioBufferOptions = AudioBufferOptions( - extraTailFrames, static_cast(channelCount_), context->getSampleRate()); - tailBuffer_ = std::make_shared(audioBufferOptions); + tailBuffer_ = std::make_shared(channelCount_, extraTailFrames, context->getSampleRate()); tailBuffer_->bus_->zero(); } diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp index 06764ece4..517955198 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp index 5a419463e..10d557e0c 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp @@ -16,14 +16,14 @@ namespace audioapi { -AudioScheduledSourceNode::AudioScheduledSourceNode(std::shared_ptr context) - : AudioNode(context), +AudioScheduledSourceNode::AudioScheduledSourceNode( + const std::shared_ptr& context, + const AudioScheduledSourceNodeOptions &options) + : AudioNode(context, options), startTime_(-1.0), stopTime_(-1.0), playbackState_(PlaybackState::UNSCHEDULED), - audioEventHandlerRegistry_(context->getAudioEventHandlerRegistry()) { - numberOfInputs_ = 0; -} + audioEventHandlerRegistry_(context->getAudioEventHandlerRegistry()) {} void AudioScheduledSourceNode::start(double when) { #if !RN_AUDIO_API_TEST diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h index 8717c2825..e39735a12 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -26,7 +27,9 @@ class AudioScheduledSourceNode : public AudioNode { // STOP_SCHEDULED: The node is scheduled to stop at a specific time, but is still playing. // FINISHED: The node has finished playing. enum class PlaybackState { UNSCHEDULED, SCHEDULED, PLAYING, STOP_SCHEDULED, FINISHED }; - explicit AudioScheduledSourceNode(std::shared_ptr context); + explicit AudioScheduledSourceNode( + const std::shared_ptr &context, + const AudioScheduledSourceNodeOptions &options = AudioScheduledSourceNodeOptions()); virtual void start(double when); virtual void stop(double when); diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/ConstantSourceNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/ConstantSourceNode.cpp index 23292ad39..ec2b97ed3 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/ConstantSourceNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/ConstantSourceNode.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/OscillatorNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/OscillatorNode.cpp index 36b3e5349..828218ae3 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/OscillatorNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/OscillatorNode.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -12,7 +12,7 @@ namespace audioapi { OscillatorNode::OscillatorNode( const std::shared_ptr &context, const OscillatorOptions &options) - : AudioScheduledSourceNode(context) { + : AudioScheduledSourceNode(context, options) { frequencyParam_ = std::make_shared( options.frequency, -context->getNyquistFrequency(), context->getNyquistFrequency(), context); detuneParam_ = std::make_shared( diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/RecorderAdapterNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/RecorderAdapterNode.cpp index a94ad3423..94c5539d4 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/RecorderAdapterNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/RecorderAdapterNode.cpp @@ -9,10 +9,10 @@ namespace audioapi { -RecorderAdapterNode::RecorderAdapterNode(std::shared_ptr context) - : AudioNode(context) { +RecorderAdapterNode::RecorderAdapterNode(const std::shared_ptr& context) + : AudioNode(context, AudioScheduledSourceNodeOptions()) { // It should be marked as initialized only after it is connected to the - // recorder. Internall buffer size is based on the recorder's buffer length. + // recorder. Internal buffer size is based on the recorder's buffer length. isInitialized_ = false; } diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/RecorderAdapterNode.h b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/RecorderAdapterNode.h index 46f2aa541..fdf80e11c 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/RecorderAdapterNode.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/RecorderAdapterNode.h @@ -19,7 +19,7 @@ class AudioBus; /// @note it will push silence if it is not connected to any Recorder class RecorderAdapterNode : public AudioNode { public: - explicit RecorderAdapterNode(std::shared_ptr context); + explicit RecorderAdapterNode(const std::shared_ptr &context); /// @brief Initialize the RecorderAdapterNode with a buffer size and channel count. /// @note This method should be called ONLY ONCE when the buffer size is known. diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/StreamerNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/StreamerNode.cpp index 24a616756..adca9b0c8 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/StreamerNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/StreamerNode.cpp @@ -8,7 +8,7 @@ * FFmpeg, you must comply with the terms of the LGPL for FFmpeg itself. */ -#include +#include #include #include #include @@ -26,7 +26,7 @@ namespace audioapi { StreamerNode::StreamerNode( const std::shared_ptr &context, const StreamerOptions &options) - : AudioScheduledSourceNode(context), + : AudioScheduledSourceNode(context, options), fmtCtx_(nullptr), codecCtx_(nullptr), decoder_(nullptr), diff --git a/packages/react-native-audio-api/common/cpp/audioapi/types/NodeOptions.h b/packages/react-native-audio-api/common/cpp/audioapi/types/NodeOptions.h new file mode 100644 index 000000000..632ae86f0 --- /dev/null +++ b/packages/react-native-audio-api/common/cpp/audioapi/types/NodeOptions.h @@ -0,0 +1,155 @@ +#pragma once + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace audioapi { +struct AudioNodeOptions { + int channelCount = 2; + ChannelCountMode channelCountMode = ChannelCountMode::MAX; + ChannelInterpretation channelInterpretation = ChannelInterpretation::SPEAKERS; + int numberOfInputs = 1; + int numberOfOutputs = 1; + bool requiresTailProcessing = false; +}; + +struct AudioDestinationOptions : AudioNodeOptions { + AudioDestinationOptions() { + numberOfOutputs = 0; + channelCountMode = ChannelCountMode::EXPLICIT; + } +}; + +struct AudioScheduledSourceNodeOptions : AudioNodeOptions { + AudioScheduledSourceNodeOptions() { + numberOfInputs = 0; + } +}; + +struct GainOptions : AudioNodeOptions { + float gain = 1.0f; +}; + +struct StereoPannerOptions : AudioNodeOptions { + float pan = 0.0f; + + StereoPannerOptions() { + channelCountMode = ChannelCountMode::CLAMPED_MAX; + } + + explicit StereoPannerOptions(AudioNodeOptions &&options) : AudioNodeOptions(options) { + channelCountMode = ChannelCountMode::CLAMPED_MAX; + } +}; + +struct ConvolverOptions : AudioNodeOptions { + bool disableNormalization = false; + std::shared_ptr bus; + + ConvolverOptions() { + requiresTailProcessing = true; + } + + explicit ConvolverOptions(AudioNodeOptions &&options) : AudioNodeOptions(options) { + requiresTailProcessing = true; + } +}; + +struct ConstantSourceOptions : AudioScheduledSourceNodeOptions { + float offset = 1.0f; +}; + +struct AnalyserOptions : AudioNodeOptions { + int fftSize = 2048; + float minDecibels = -100.0f; + float maxDecibels = -30.0f; + float smoothingTimeConstant = 0.8f; +}; + +struct BiquadFilterOptions : AudioNodeOptions { + BiquadFilterType type = BiquadFilterType::LOWPASS; + float frequency = 350.0f; + float detune = 0.0f; + float Q = 1.0f; + float gain = 0.0f; +}; + +struct OscillatorOptions : AudioScheduledSourceNodeOptions { + std::shared_ptr periodicWave; + float frequency = 440.0f; + float detune = 0.0f; + OscillatorType type = OscillatorType::SINE; +}; + +struct BaseAudioBufferSourceOptions : AudioScheduledSourceNodeOptions { + bool pitchCorrection = false; + float detune = 0.0f; + float playbackRate = 1.0f; +}; + +struct AudioBufferSourceOptions : BaseAudioBufferSourceOptions { + std::shared_ptr buffer; + float loopStart = 0.0f; + float loopEnd = 0.0f; + bool loop = false; +}; + +struct StreamerOptions : AudioScheduledSourceNodeOptions { + std::string streamPath; +}; + +struct DelayOptions : AudioNodeOptions { + float maxDelayTime = 1.0f; + float delayTime = 0.0f; + + DelayOptions() { + requiresTailProcessing = true; + } + + explicit DelayOptions(AudioNodeOptions &&options) : AudioNodeOptions(options) { + requiresTailProcessing = true; + } +}; + +struct IIRFilterOptions : AudioNodeOptions { + std::vector feedforward; + std::vector feedback; + + IIRFilterOptions() = default; + + explicit IIRFilterOptions(const AudioNodeOptions options) : AudioNodeOptions(options) {} + + IIRFilterOptions(const std::vector &ff, const std::vector &fb) + : feedforward(ff), feedback(fb) {} + + IIRFilterOptions(std::vector &&ff, std::vector &&fb) + : feedforward(std::move(ff)), feedback(std::move(fb)) {} +}; + +struct WaveShaperOptions : AudioNodeOptions { + std::shared_ptr curve; + OverSampleType oversample = OverSampleType::OVERSAMPLE_NONE; + + WaveShaperOptions() { + // to change after graph processing improvement - should be max + channelCountMode = ChannelCountMode::CLAMPED_MAX; + } + + explicit WaveShaperOptions(const AudioNodeOptions &&options) : AudioNodeOptions(options) { + // to change after graph processing improvement - should be max + channelCountMode = ChannelCountMode::CLAMPED_MAX; + } +}; + +} // namespace audioapi diff --git a/packages/react-native-audio-api/common/cpp/test/src/ConstantSourceTest.cpp b/packages/react-native-audio-api/common/cpp/test/src/ConstantSourceTest.cpp index 4bac9678f..0f3ecca07 100644 --- a/packages/react-native-audio-api/common/cpp/test/src/ConstantSourceTest.cpp +++ b/packages/react-native-audio-api/common/cpp/test/src/ConstantSourceTest.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/packages/react-native-audio-api/common/cpp/test/src/DelayTest.cpp b/packages/react-native-audio-api/common/cpp/test/src/DelayTest.cpp index 80f57b80c..3ccc6a91d 100644 --- a/packages/react-native-audio-api/common/cpp/test/src/DelayTest.cpp +++ b/packages/react-native-audio-api/common/cpp/test/src/DelayTest.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/packages/react-native-audio-api/common/cpp/test/src/GainTest.cpp b/packages/react-native-audio-api/common/cpp/test/src/GainTest.cpp index e34870fb6..d3d99b5cf 100644 --- a/packages/react-native-audio-api/common/cpp/test/src/GainTest.cpp +++ b/packages/react-native-audio-api/common/cpp/test/src/GainTest.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/packages/react-native-audio-api/common/cpp/test/src/IIRFilterTest.cpp b/packages/react-native-audio-api/common/cpp/test/src/IIRFilterTest.cpp index 74928ef41..8043c0a2b 100644 --- a/packages/react-native-audio-api/common/cpp/test/src/IIRFilterTest.cpp +++ b/packages/react-native-audio-api/common/cpp/test/src/IIRFilterTest.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/packages/react-native-audio-api/common/cpp/test/src/OscillatorTest.cpp b/packages/react-native-audio-api/common/cpp/test/src/OscillatorTest.cpp index 04151fc68..39f21749b 100644 --- a/packages/react-native-audio-api/common/cpp/test/src/OscillatorTest.cpp +++ b/packages/react-native-audio-api/common/cpp/test/src/OscillatorTest.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/packages/react-native-audio-api/common/cpp/test/src/StereoPannerTest.cpp b/packages/react-native-audio-api/common/cpp/test/src/StereoPannerTest.cpp index 68ce23c55..65f9a7a6c 100644 --- a/packages/react-native-audio-api/common/cpp/test/src/StereoPannerTest.cpp +++ b/packages/react-native-audio-api/common/cpp/test/src/StereoPannerTest.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/packages/react-native-audio-api/common/cpp/test/src/biquad/BiquadFilterTest.cpp b/packages/react-native-audio-api/common/cpp/test/src/biquad/BiquadFilterTest.cpp index 6f19989e3..708756dbd 100644 --- a/packages/react-native-audio-api/common/cpp/test/src/biquad/BiquadFilterTest.cpp +++ b/packages/react-native-audio-api/common/cpp/test/src/biquad/BiquadFilterTest.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/packages/react-native-audio-api/common/cpp/test/src/core/effects/WaveShaperNodeTest.cpp b/packages/react-native-audio-api/common/cpp/test/src/core/effects/WaveShaperNodeTest.cpp index 679b4f76e..0bce7647e 100644 --- a/packages/react-native-audio-api/common/cpp/test/src/core/effects/WaveShaperNodeTest.cpp +++ b/packages/react-native-audio-api/common/cpp/test/src/core/effects/WaveShaperNodeTest.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/packages/react-native-audio-api/src/AudioAPIModule/AudioAPIModule.ts b/packages/react-native-audio-api/src/AudioAPIModule/AudioAPIModule.ts index 6bb1b0e9f..ca27e045e 100644 --- a/packages/react-native-audio-api/src/AudioAPIModule/AudioAPIModule.ts +++ b/packages/react-native-audio-api/src/AudioAPIModule/AudioAPIModule.ts @@ -60,6 +60,7 @@ class AudioAPIModule implements IAudioAPIModule { global.createAudioContext != null && global.createOfflineAudioContext != null && global.createAudioRecorder != null && + global.createAudioBuffer != null && global.createAudioDecoder != null && global.createAudioStretcher != null && global.AudioEventEmitter != null diff --git a/packages/react-native-audio-api/src/AudioAPIModule/globals.d.ts b/packages/react-native-audio-api/src/AudioAPIModule/globals.d.ts index cceff34f9..5728c6a3b 100644 --- a/packages/react-native-audio-api/src/AudioAPIModule/globals.d.ts +++ b/packages/react-native-audio-api/src/AudioAPIModule/globals.d.ts @@ -3,6 +3,7 @@ import type { IAudioDecoder, IAudioEventEmitter, IAudioRecorder, + IAudioBuffer, IAudioStretcher, IOfflineAudioContext, } from '../interfaces'; @@ -24,6 +25,12 @@ declare global { var createAudioRecorder: () => IAudioRecorder; + var createAudioBuffer: ( + numberOfChannels: number, + length: number, + sampleRate: number + ) => IAudioBuffer; + var createAudioDecoder: () => IAudioDecoder; var createAudioStretcher: () => IAudioStretcher; diff --git a/packages/react-native-audio-api/src/core/AnalyserNode.ts b/packages/react-native-audio-api/src/core/AnalyserNode.ts index b6faaf6ef..f2ac9ecfd 100644 --- a/packages/react-native-audio-api/src/core/AnalyserNode.ts +++ b/packages/react-native-audio-api/src/core/AnalyserNode.ts @@ -1,5 +1,4 @@ import BaseAudioContext from './BaseAudioContext'; -import { AnalyserOptions } from '../defaults'; import { IndexSizeError } from '../errors'; import { IAnalyserNode } from '../interfaces'; import { WindowType, TAnalyserOptions } from '../types'; @@ -12,14 +11,10 @@ export default class AnalyserNode extends AudioNode { ]; constructor(context: BaseAudioContext, options?: TAnalyserOptions) { - const finalOptions: TAnalyserOptions = { - ...AnalyserOptions, - ...options, - }; - - AnalyserOptionsValidator.validate(finalOptions); - const analyserNode: IAnalyserNode = - context.context.createAnalyser(finalOptions); + AnalyserOptionsValidator.validate(options); + const analyserNode: IAnalyserNode = context.context.createAnalyser( + options || {} + ); super(context, analyserNode); } diff --git a/packages/react-native-audio-api/src/core/AudioBuffer.ts b/packages/react-native-audio-api/src/core/AudioBuffer.ts index eeeb4d95c..719ad94d8 100644 --- a/packages/react-native-audio-api/src/core/AudioBuffer.ts +++ b/packages/react-native-audio-api/src/core/AudioBuffer.ts @@ -1,8 +1,6 @@ import { IAudioBuffer } from '../interfaces'; -import { IndexSizeError } from '../errors'; -import BaseAudioContext from './BaseAudioContext'; +import { IndexSizeError, NotSupportedError } from '../errors'; import { TAudioBufferOptions } from '../types'; -import { AudioBufferOptions } from '../defaults'; export default class AudioBuffer { readonly length: number; @@ -12,29 +10,20 @@ export default class AudioBuffer { /** @internal */ public readonly buffer: IAudioBuffer; + constructor(options: TAudioBufferOptions); + + /** @internal */ constructor(buffer: IAudioBuffer); - constructor(context: BaseAudioContext, options: TAudioBufferOptions); - constructor( - contextOrBuffer: BaseAudioContext | IAudioBuffer, - options?: TAudioBufferOptions - ) { - let buf: IAudioBuffer; - if (contextOrBuffer instanceof BaseAudioContext) { - const finalOptions = { - ...AudioBufferOptions, - ...options, - }; - const context = contextOrBuffer; - buf = context.context.createBuffer(finalOptions); - } else { - buf = contextOrBuffer; - } - this.buffer = buf; - this.length = buf.length; - this.duration = buf.duration; - this.sampleRate = buf.sampleRate; - this.numberOfChannels = buf.numberOfChannels; + /** @internal */ + constructor(arg: TAudioBufferOptions | IAudioBuffer) { + this.buffer = this.isAudioBuffer(arg) + ? arg + : AudioBuffer.createBufferFromOptions(arg); + this.length = this.buffer.length; + this.duration = this.buffer.duration; + this.sampleRate = this.buffer.sampleRate; + this.numberOfChannels = this.buffer.numberOfChannels; } public getChannelData(channel: number): Float32Array { @@ -85,4 +74,35 @@ export default class AudioBuffer { this.buffer.copyToChannel(source, channelNumber, startInChannel); } + + private static createBufferFromOptions( + options: TAudioBufferOptions + ): IAudioBuffer { + const { numberOfChannels = 1, length, sampleRate } = options; + if (numberOfChannels < 1 || numberOfChannels >= 32) { + throw new NotSupportedError( + `The number of channels provided (${numberOfChannels}) is outside the range [1, 32]` + ); + } + if (length <= 0) { + throw new NotSupportedError( + `The number of frames provided (${length}) is less than or equal to the minimum bound (0)` + ); + } + if (sampleRate < 8000 || sampleRate > 96000) { + throw new NotSupportedError( + `The sample rate provided (${sampleRate}) is outside the range [8000, 96000]` + ); + } + return global.createAudioBuffer(numberOfChannels, length, sampleRate); + } + + private isAudioBuffer(obj: unknown): obj is IAudioBuffer { + return ( + typeof obj === 'object' && + obj !== null && + 'getChannelData' in obj && + typeof (obj as IAudioBuffer).getChannelData === 'function' + ); + } } diff --git a/packages/react-native-audio-api/src/core/AudioBufferQueueSourceNode.ts b/packages/react-native-audio-api/src/core/AudioBufferQueueSourceNode.ts index 16e3f97ab..78492ad62 100644 --- a/packages/react-native-audio-api/src/core/AudioBufferQueueSourceNode.ts +++ b/packages/react-native-audio-api/src/core/AudioBufferQueueSourceNode.ts @@ -4,7 +4,6 @@ import AudioBuffer from './AudioBuffer'; import { RangeError } from '../errors'; import BaseAudioContext from './BaseAudioContext'; import { TBaseAudioBufferSourceOptions } from '../types'; -import { BaseAudioBufferSourceOptions } from '../defaults'; import { AudioEventSubscription } from '../events'; import { OnBufferEndEventType } from '../events/types'; @@ -16,11 +15,7 @@ export default class AudioBufferQueueSourceNode extends AudioBufferBaseSourceNod context: BaseAudioContext, options?: TBaseAudioBufferSourceOptions ) { - const finalOptions: TBaseAudioBufferSourceOptions = { - ...BaseAudioBufferSourceOptions, - ...options, - }; - const node = context.context.createBufferQueueSource(finalOptions); + const node = context.context.createBufferQueueSource(options || {}); super(context, node); } diff --git a/packages/react-native-audio-api/src/core/AudioBufferSourceNode.ts b/packages/react-native-audio-api/src/core/AudioBufferSourceNode.ts index e99b0c7b7..594ef77c4 100644 --- a/packages/react-native-audio-api/src/core/AudioBufferSourceNode.ts +++ b/packages/react-native-audio-api/src/core/AudioBufferSourceNode.ts @@ -6,18 +6,13 @@ import { EventEmptyType } from '../events/types'; import { AudioEventSubscription } from '../events'; import { TAudioBufferSourceOptions } from '../types'; import BaseAudioContext from './BaseAudioContext'; -import { AudioBufferSourceOptions } from '../defaults'; export default class AudioBufferSourceNode extends AudioBufferBaseSourceNode { private onLoopEndedSubscription?: AudioEventSubscription; private onLoopEndedCallback?: (event: EventEmptyType) => void; constructor(context: BaseAudioContext, options?: TAudioBufferSourceOptions) { - const finalOptions: TAudioBufferSourceOptions = { - ...AudioBufferSourceOptions, - ...options, - }; - const node = context.context.createBufferSource(finalOptions); + const node = context.context.createBufferSource(options || {}); super(context, node); } diff --git a/packages/react-native-audio-api/src/core/BaseAudioContext.ts b/packages/react-native-audio-api/src/core/BaseAudioContext.ts index ec77c1b49..452dcbe85 100644 --- a/packages/react-native-audio-api/src/core/BaseAudioContext.ts +++ b/packages/react-native-audio-api/src/core/BaseAudioContext.ts @@ -210,25 +210,7 @@ export default class BaseAudioContext { length: number, sampleRate: number ): AudioBuffer { - if (numberOfChannels < 1 || numberOfChannels >= 32) { - throw new NotSupportedError( - `The number of channels provided (${numberOfChannels}) is outside the range [1, 32]` - ); - } - - if (length <= 0) { - throw new NotSupportedError( - `The number of frames provided (${length}) is less than or equal to the minimum bound (0)` - ); - } - - if (sampleRate < 8000 || sampleRate > 96000) { - throw new NotSupportedError( - `The sample rate provided (${sampleRate}) is outside the range [8000, 96000]` - ); - } - - return new AudioBuffer(this, { numberOfChannels, length, sampleRate }); + return new AudioBuffer({ numberOfChannels, length, sampleRate }); } createPeriodicWave( diff --git a/packages/react-native-audio-api/src/core/BiquadFilterNode.ts b/packages/react-native-audio-api/src/core/BiquadFilterNode.ts index b85475fc5..ddc8a3069 100644 --- a/packages/react-native-audio-api/src/core/BiquadFilterNode.ts +++ b/packages/react-native-audio-api/src/core/BiquadFilterNode.ts @@ -3,7 +3,6 @@ import { IBiquadFilterNode } from '../interfaces'; import AudioNode from './AudioNode'; import AudioParam from './AudioParam'; import BaseAudioContext from './BaseAudioContext'; -import { BiquadFilterOptions } from '../defaults'; import { TBiquadFilterOptions } from '../types'; export default class BiquadFilterNode extends AudioNode { @@ -13,12 +12,9 @@ export default class BiquadFilterNode extends AudioNode { readonly gain: AudioParam; constructor(context: BaseAudioContext, options?: TBiquadFilterOptions) { - const finalOptions: TBiquadFilterOptions = { - ...BiquadFilterOptions, - ...options, - }; - const biquadFilter: IBiquadFilterNode = - context.context.createBiquadFilter(finalOptions); + const biquadFilter: IBiquadFilterNode = context.context.createBiquadFilter( + options || {} + ); super(context, biquadFilter); this.frequency = new AudioParam(biquadFilter.frequency, context); this.detune = new AudioParam(biquadFilter.detune, context); diff --git a/packages/react-native-audio-api/src/core/ConstantSourceNode.ts b/packages/react-native-audio-api/src/core/ConstantSourceNode.ts index 65b26f517..af32e71e6 100644 --- a/packages/react-native-audio-api/src/core/ConstantSourceNode.ts +++ b/packages/react-native-audio-api/src/core/ConstantSourceNode.ts @@ -1,5 +1,4 @@ import { IConstantSourceNode } from '../interfaces'; -import { ConstantSourceOptions } from '../defaults'; import { TConstantSourceOptions } from '../types'; import AudioParam from './AudioParam'; import AudioScheduledSourceNode from './AudioScheduledSourceNode'; @@ -9,12 +8,9 @@ export default class ConstantSourceNode extends AudioScheduledSourceNode { readonly offset: AudioParam; constructor(context: BaseAudioContext, options?: TConstantSourceOptions) { - const finalOptions: TConstantSourceOptions = { - ...ConstantSourceOptions, - ...options, - }; - const node: IConstantSourceNode = - context.context.createConstantSource(finalOptions); + const node: IConstantSourceNode = context.context.createConstantSource( + options || {} + ); super(context, node); this.offset = new AudioParam(node.offset, context); } diff --git a/packages/react-native-audio-api/src/core/ConvolverNode.ts b/packages/react-native-audio-api/src/core/ConvolverNode.ts index 3c283fa04..50d4982e0 100644 --- a/packages/react-native-audio-api/src/core/ConvolverNode.ts +++ b/packages/react-native-audio-api/src/core/ConvolverNode.ts @@ -1,5 +1,4 @@ import { IConvolverNode } from '../interfaces'; -import { ConvolverOptions } from '../defaults'; import { TConvolverOptions } from '../types'; import BaseAudioContext from './BaseAudioContext'; import AudioNode from './AudioNode'; @@ -7,12 +6,9 @@ import AudioBuffer from './AudioBuffer'; export default class ConvolverNode extends AudioNode { constructor(context: BaseAudioContext, options?: TConvolverOptions) { - const finalOptions: TConvolverOptions = { - ...ConvolverOptions, - ...options, - }; - const convolverNode: IConvolverNode = - context.context.createConvolver(finalOptions); + const convolverNode: IConvolverNode = context.context.createConvolver( + options || {} + ); super(context, convolverNode); this.normalize = convolverNode.normalize; } diff --git a/packages/react-native-audio-api/src/core/DelayNode.ts b/packages/react-native-audio-api/src/core/DelayNode.ts index 5cb645086..b71b2cb96 100644 --- a/packages/react-native-audio-api/src/core/DelayNode.ts +++ b/packages/react-native-audio-api/src/core/DelayNode.ts @@ -2,14 +2,12 @@ import AudioNode from './AudioNode'; import AudioParam from './AudioParam'; import BaseAudioContext from './BaseAudioContext'; import { TDelayOptions } from '../types'; -import { DelayOptions } from '../defaults'; export default class DelayNode extends AudioNode { readonly delayTime: AudioParam; constructor(context: BaseAudioContext, options?: TDelayOptions) { - const finalOptions = { ...DelayOptions, ...options }; - const delay = context.context.createDelay(finalOptions); + const delay = context.context.createDelay(options || {}); super(context, delay); this.delayTime = new AudioParam(delay.delayTime, context); } diff --git a/packages/react-native-audio-api/src/core/GainNode.ts b/packages/react-native-audio-api/src/core/GainNode.ts index 1c2b8f93b..50b42b003 100644 --- a/packages/react-native-audio-api/src/core/GainNode.ts +++ b/packages/react-native-audio-api/src/core/GainNode.ts @@ -1,5 +1,4 @@ import { IGainNode } from '../interfaces'; -import { GainOptions } from '../defaults'; import { TGainOptions } from '../types'; import AudioNode from './AudioNode'; import AudioParam from './AudioParam'; @@ -9,11 +8,7 @@ export default class GainNode extends AudioNode { readonly gain: AudioParam; constructor(context: BaseAudioContext, options?: TGainOptions) { - const finalOptions: TGainOptions = { - ...GainOptions, - ...options, - }; - const gainNode: IGainNode = context.context.createGain(finalOptions); + const gainNode: IGainNode = context.context.createGain(options || {}); super(context, gainNode); this.gain = new AudioParam(gainNode.gain, context); } diff --git a/packages/react-native-audio-api/src/core/IIRFilterNode.ts b/packages/react-native-audio-api/src/core/IIRFilterNode.ts index e7bf4c01d..94ab1a334 100644 --- a/packages/react-native-audio-api/src/core/IIRFilterNode.ts +++ b/packages/react-native-audio-api/src/core/IIRFilterNode.ts @@ -2,16 +2,11 @@ import { NotSupportedError } from '../errors'; import { IIIRFilterNode } from '../interfaces'; import AudioNode from './AudioNode'; import { TIIRFilterOptions } from '../types'; -import { AudioNodeOptions } from '../defaults'; import BaseAudioContext from './BaseAudioContext'; export default class IIRFilterNode extends AudioNode { constructor(context: BaseAudioContext, options: TIIRFilterOptions) { - const finalOptions: TIIRFilterOptions = { - ...AudioNodeOptions, - ...options, - }; - const iirFilterNode = context.context.createIIRFilter(finalOptions); + const iirFilterNode = context.context.createIIRFilter(options || {}); super(context, iirFilterNode); } diff --git a/packages/react-native-audio-api/src/core/OscillatorNode.ts b/packages/react-native-audio-api/src/core/OscillatorNode.ts index 1bd2c7e9b..0b124074a 100644 --- a/packages/react-native-audio-api/src/core/OscillatorNode.ts +++ b/packages/react-native-audio-api/src/core/OscillatorNode.ts @@ -4,7 +4,6 @@ import AudioParam from './AudioParam'; import BaseAudioContext from './BaseAudioContext'; import PeriodicWave from './PeriodicWave'; import { InvalidStateError } from '../errors'; -import { OscillatorOptions } from '../defaults'; import { TOscillatorOptions } from '../types'; export default class OscillatorNode extends AudioScheduledSourceNode { @@ -12,16 +11,11 @@ export default class OscillatorNode extends AudioScheduledSourceNode { readonly detune: AudioParam; constructor(context: BaseAudioContext, options?: TOscillatorOptions) { - const finalOptions: TOscillatorOptions = { - ...OscillatorOptions, - ...options, - }; - - if (finalOptions.periodicWave) { - finalOptions.type = 'custom'; + if (options?.periodicWave) { + options.type = 'custom'; } - const node = context.context.createOscillator(finalOptions); + const node = context.context.createOscillator(options || {}); super(context, node); this.frequency = new AudioParam(node.frequency, context); this.detune = new AudioParam(node.detune, context); diff --git a/packages/react-native-audio-api/src/core/PeriodicWave.ts b/packages/react-native-audio-api/src/core/PeriodicWave.ts index 7e9e7fa40..cbcc4da86 100644 --- a/packages/react-native-audio-api/src/core/PeriodicWave.ts +++ b/packages/react-native-audio-api/src/core/PeriodicWave.ts @@ -1,7 +1,6 @@ import { IPeriodicWave } from '../interfaces'; import BaseAudioContext from './BaseAudioContext'; import { TPeriodicWaveOptions } from '../types'; -import { PeriodicWaveConstraints } from '../defaults'; import { PeriodicWaveOptionsValidator } from '../options-validators'; export function generateRealAndImag( @@ -25,7 +24,7 @@ export function generateRealAndImag( } const norm: boolean = options?.disableNormalization ? options.disableNormalization - : PeriodicWaveConstraints.disableNormalization!; + : false; return { real, imag, disableNormalization: norm }; } diff --git a/packages/react-native-audio-api/src/core/StereoPannerNode.ts b/packages/react-native-audio-api/src/core/StereoPannerNode.ts index e0fc787be..f77b27411 100644 --- a/packages/react-native-audio-api/src/core/StereoPannerNode.ts +++ b/packages/react-native-audio-api/src/core/StereoPannerNode.ts @@ -1,4 +1,3 @@ -import { StereoPannerOptions } from '../defaults'; import { IStereoPannerNode } from '../interfaces'; import { TStereoPannerOptions } from '../types'; import AudioNode from './AudioNode'; @@ -9,12 +8,9 @@ export default class StereoPannerNode extends AudioNode { readonly pan: AudioParam; constructor(context: BaseAudioContext, options?: TStereoPannerOptions) { - const finalOptions: TStereoPannerOptions = { - ...StereoPannerOptions, - ...options, - }; - const pan: IStereoPannerNode = - context.context.createStereoPanner(finalOptions); + const pan: IStereoPannerNode = context.context.createStereoPanner( + options || {} + ); super(context, pan); this.pan = new AudioParam(pan.pan, context); } diff --git a/packages/react-native-audio-api/src/core/StreamerNode.ts b/packages/react-native-audio-api/src/core/StreamerNode.ts index a15cdbeb6..8e82d0ee7 100644 --- a/packages/react-native-audio-api/src/core/StreamerNode.ts +++ b/packages/react-native-audio-api/src/core/StreamerNode.ts @@ -7,7 +7,7 @@ import BaseAudioContext from './BaseAudioContext'; export default class StreamerNode extends AudioScheduledSourceNode { private hasBeenSetup: boolean = false; constructor(context: BaseAudioContext, options?: TStreamerOptions) { - const node = context.context.createStreamer(options); + const node = context.context.createStreamer(options || {}); if (!node) { throw new NotSupportedError('StreamerNode requires FFmpeg build'); } diff --git a/packages/react-native-audio-api/src/core/WaveShaperNode.ts b/packages/react-native-audio-api/src/core/WaveShaperNode.ts index c971b1591..ed0670f37 100644 --- a/packages/react-native-audio-api/src/core/WaveShaperNode.ts +++ b/packages/react-native-audio-api/src/core/WaveShaperNode.ts @@ -2,22 +2,15 @@ import AudioNode from './AudioNode'; import BaseAudioContext from './BaseAudioContext'; import { InvalidStateError } from '../errors'; import { IWaveShaperNode } from '../interfaces'; -import { WaveShaperOptions } from '../defaults'; import { TWaveShaperOptions } from '../types'; export default class WaveShaperNode extends AudioNode { private isCurveSet: boolean = false; constructor(context: BaseAudioContext, options?: TWaveShaperOptions) { - const finalOptions: TWaveShaperOptions = { - ...WaveShaperOptions, - ...options, - }; - - const node = context.context.createWaveShaper(finalOptions); + const node = context.context.createWaveShaper(options || {}); super(context, node); - - if (finalOptions.curve) { + if (options?.curve) { this.isCurveSet = true; } } diff --git a/packages/react-native-audio-api/src/defaults.ts b/packages/react-native-audio-api/src/defaults.ts deleted file mode 100644 index cfda045e2..000000000 --- a/packages/react-native-audio-api/src/defaults.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { - TAnalyserOptions, - TAudioBufferOptions, - TAudioBufferSourceOptions, - TAudioNodeOptions, - TBaseAudioBufferSourceOptions, - TBiquadFilterOptions, - TConstantSourceOptions, - TConvolverOptions, - TDelayOptions, - TGainOptions, - TOscillatorOptions, - TPeriodicWaveConstraints, - TStereoPannerOptions, - TWaveShaperOptions, -} from './types'; - -export const AudioNodeOptions: TAudioNodeOptions = { - channelCount: 2, - channelCountMode: 'max', - channelInterpretation: 'speakers', -}; - -export const GainOptions: TGainOptions = { - ...AudioNodeOptions, - gain: 1, -}; - -export const StereoPannerOptions: TStereoPannerOptions = { - ...AudioNodeOptions, - channelCountMode: 'clamped-max', - pan: 0, -}; - -export const AnalyserOptions: TAnalyserOptions = { - ...AudioNodeOptions, - fftSize: 2048, - minDecibels: -100, - maxDecibels: -30, - smoothingTimeConstant: 0.8, -}; - -export const BiquadFilterOptions: TBiquadFilterOptions = { - ...AudioNodeOptions, - Q: 1, - detune: 0, - frequency: 350, - gain: 0, - type: 'lowpass', -}; - -export const ConvolverOptions: TConvolverOptions = { - ...AudioNodeOptions, - disableNormalization: false, -}; - -export const ConstantSourceOptions: TConstantSourceOptions = { - offset: 1, -}; - -export const PeriodicWaveConstraints: TPeriodicWaveConstraints = { - disableNormalization: false, -}; - -export const OscillatorOptions: TOscillatorOptions = { - ...AudioNodeOptions, - type: 'sine', - frequency: 440, - detune: 0, -}; - -export const BaseAudioBufferSourceOptions: TBaseAudioBufferSourceOptions = { - playbackRate: 1, - detune: 0, - pitchCorrection: false, -}; - -export const AudioBufferSourceOptions: TAudioBufferSourceOptions = { - ...BaseAudioBufferSourceOptions, - loop: false, - loopStart: 0, - loopEnd: 0, -}; - -export const AudioBufferOptions: TAudioBufferOptions = { - numberOfChannels: 1, - length: 0, // always overwritten by provided value, only placeholder - sampleRate: 44100, // always overwritten by provided value, only placeholder -}; - -export const DelayOptions: TDelayOptions = { - ...AudioNodeOptions, - maxDelayTime: 1.0, - delayTime: 0.0, -}; - -export const WaveShaperOptions: TWaveShaperOptions = { - ...AudioNodeOptions, - oversample: 'none', -}; diff --git a/packages/react-native-audio-api/src/interfaces.ts b/packages/react-native-audio-api/src/interfaces.ts index 9f9df8a1d..6c8b49b1d 100644 --- a/packages/react-native-audio-api/src/interfaces.ts +++ b/packages/react-native-audio-api/src/interfaces.ts @@ -11,7 +11,6 @@ import type { OverSampleType, Result, TAnalyserOptions, - TAudioBufferOptions, TAudioBufferSourceOptions, TBaseAudioBufferSourceOptions, TBiquadFilterOptions, @@ -95,14 +94,13 @@ export interface IBaseAudioContext { createBufferQueueSource: ( audioBufferQueueSourceOptions: TBaseAudioBufferSourceOptions ) => IAudioBufferQueueSourceNode; - createBuffer: (audioBufferOptions: TAudioBufferOptions) => IAudioBuffer; createPeriodicWave: ( real: Float32Array, imag: Float32Array, disableNormalization: boolean ) => IPeriodicWave; createAnalyser: (analyserOptions: TAnalyserOptions) => IAnalyserNode; - createConvolver: (convolverOptions: TConvolverOptions) => IConvolverNode; + createConvolver: (convolverOptions?: TConvolverOptions) => IConvolverNode; createStreamer: (streamerOptions?: TStreamerOptions) => IStreamerNode | null; // null when FFmpeg is not enabled createWaveShaper: (waveShaperOptions?: TWaveShaperOptions) => IWaveShaperNode; } diff --git a/packages/react-native-audio-api/src/options-validators.ts b/packages/react-native-audio-api/src/options-validators.ts index b3a7fe8bd..cda1a6462 100644 --- a/packages/react-native-audio-api/src/options-validators.ts +++ b/packages/react-native-audio-api/src/options-validators.ts @@ -8,7 +8,10 @@ import { } from './types'; export const AnalyserOptionsValidator: OptionsValidator = { - validate(options: TAnalyserOptions): void { + validate(options?: TAnalyserOptions): void { + if (!options) { + return; + } const allowedFFTSize: number[] = [ 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, ]; @@ -23,7 +26,10 @@ export const AnalyserOptionsValidator: OptionsValidator = { }; export const ConvolverOptionsValidator: OptionsValidator = { - validate(options: TConvolverOptions): void { + validate(options?: TConvolverOptions): void { + if (!options) { + return; + } if (options.buffer) { const numberOfChannels = options.buffer.numberOfChannels; if ( @@ -41,7 +47,10 @@ export const ConvolverOptionsValidator: OptionsValidator = { export const OscillatorOptionsValidator: OptionsValidator = { - validate(options: TOscillatorOptions): void { + validate(options?: TOscillatorOptions): void { + if (!options) { + return; + } if (options.type === 'custom' && !options.periodicWave) { throw new NotSupportedError( "'type' cannot be set to 'custom' without providing a 'periodicWave'." @@ -52,7 +61,10 @@ export const OscillatorOptionsValidator: OptionsValidator = export const PeriodicWaveOptionsValidator: OptionsValidator = { - validate(options: TPeriodicWaveOptions): void { + validate(options?: TPeriodicWaveOptions): void { + if (!options) { + return; + } if ( options.real && options.imag && diff --git a/packages/react-native-audio-api/src/types.ts b/packages/react-native-audio-api/src/types.ts index d1c89c012..3383c32e7 100644 --- a/packages/react-native-audio-api/src/types.ts +++ b/packages/react-native-audio-api/src/types.ts @@ -131,7 +131,7 @@ export interface TAnalyserOptions extends TAudioNodeOptions { } export interface OptionsValidator { - validate(options: T): void; + validate(options?: T): void; } export interface TBiquadFilterOptions extends TAudioNodeOptions { @@ -191,8 +191,8 @@ export interface TPeriodicWaveOptions extends TPeriodicWaveConstraints { } export interface TAudioBufferOptions { - numberOfChannels?: number; length: number; + numberOfChannels?: number; sampleRate: number; } diff --git a/packages/react-native-audio-api/src/web-core/AudioBuffer.tsx b/packages/react-native-audio-api/src/web-core/AudioBuffer.tsx index 33220e971..b841e928f 100644 --- a/packages/react-native-audio-api/src/web-core/AudioBuffer.tsx +++ b/packages/react-native-audio-api/src/web-core/AudioBuffer.tsx @@ -1,5 +1,4 @@ -import { IndexSizeError } from '../errors'; -import BaseAudioContext from './BaseAudioContext'; +import { IndexSizeError, NotSupportedError } from '../errors'; import { TAudioBufferOptions } from '../types'; export default class AudioBuffer { @@ -11,24 +10,20 @@ export default class AudioBuffer { /** @internal */ public readonly buffer: globalThis.AudioBuffer; + constructor(options: TAudioBufferOptions); + + /** @internal */ constructor(buffer: globalThis.AudioBuffer); - constructor(context: BaseAudioContext, options: TAudioBufferOptions); - constructor( - contextOrBuffer: BaseAudioContext | globalThis.AudioBuffer, - options?: TAudioBufferOptions - ) { - let buf: globalThis.AudioBuffer; - if (contextOrBuffer instanceof BaseAudioContext) { - buf = new globalThis.AudioBuffer(options!); - } else { - buf = contextOrBuffer as globalThis.AudioBuffer; - } - this.buffer = buf; - this.length = buf.length; - this.duration = buf.duration; - this.sampleRate = buf.sampleRate; - this.numberOfChannels = buf.numberOfChannels; + /** @internal */ + constructor(arg: TAudioBufferOptions | globalThis.AudioBuffer) { + this.buffer = this.isAudioBuffer(arg) + ? arg + : AudioBuffer.createBufferFromOptions(arg); + this.length = this.buffer.length; + this.duration = this.buffer.duration; + this.sampleRate = this.buffer.sampleRate; + this.numberOfChannels = this.buffer.numberOfChannels; } public getChannelData(channel: number): Float32Array { @@ -58,7 +53,11 @@ export default class AudioBuffer { ); } - this.buffer.copyFromChannel(destination, channelNumber, startInChannel); + this.buffer.copyFromChannel( + destination as Float32Array, + channelNumber, + startInChannel + ); } public copyToChannel( @@ -78,6 +77,41 @@ export default class AudioBuffer { ); } - this.buffer.copyToChannel(source, channelNumber, startInChannel); + this.buffer.copyToChannel( + source as Float32Array, + channelNumber, + startInChannel + ); + } + + private static createBufferFromOptions( + options: TAudioBufferOptions + ): globalThis.AudioBuffer { + const { numberOfChannels = 1, length, sampleRate } = options; + if (numberOfChannels < 1 || numberOfChannels >= 32) { + throw new NotSupportedError( + `The number of channels provided (${numberOfChannels}) is outside the range [1, 32]` + ); + } + if (length <= 0) { + throw new NotSupportedError( + `The number of frames provided (${length}) is less than or equal to the minimum bound (0)` + ); + } + if (sampleRate < 8000 || sampleRate > 96000) { + throw new NotSupportedError( + `The sample rate provided (${sampleRate}) is outside the range [8000, 96000]` + ); + } + return new globalThis.AudioBuffer({ numberOfChannels, length, sampleRate }); + } + + private isAudioBuffer(obj: unknown): obj is globalThis.AudioBuffer { + return ( + typeof obj === 'object' && + obj !== null && + 'getChannelData' in obj && + typeof (obj as globalThis.AudioBuffer).getChannelData === 'function' + ); } } diff --git a/packages/react-native-audio-api/src/web-core/AudioBufferSourceNode.tsx b/packages/react-native-audio-api/src/web-core/AudioBufferSourceNode.tsx index afe18daad..5bca7effd 100644 --- a/packages/react-native-audio-api/src/web-core/AudioBufferSourceNode.tsx +++ b/packages/react-native-audio-api/src/web-core/AudioBufferSourceNode.tsx @@ -7,7 +7,6 @@ import AudioNode from './AudioNode'; import { clamp } from '../utils'; import { TAudioBufferSourceOptions } from '../types'; -import { AudioBufferSourceOptions } from '../defaults'; import { globalWasmPromise, globalTag } from './custom/LoadCustomWasm'; interface ScheduleOptions { @@ -610,11 +609,7 @@ export default class AudioBufferSourceNode { private node: AudioBufferSourceNodeStretcher | AudioBufferSourceNodeWeb; constructor(context: BaseAudioContext, options?: TAudioBufferSourceOptions) { - const finalOptions: TAudioBufferSourceOptions = { - ...AudioBufferSourceOptions, - ...options, - }; - this.node = finalOptions.pitchCorrection + this.node = options?.pitchCorrection ? new AudioBufferSourceNodeStretcher(context) : new AudioBufferSourceNodeWeb(context, options); } diff --git a/packages/react-native-audio-api/src/web-core/AudioContext.tsx b/packages/react-native-audio-api/src/web-core/AudioContext.tsx index 46d947fbf..9a9f01dc5 100644 --- a/packages/react-native-audio-api/src/web-core/AudioContext.tsx +++ b/packages/react-native-audio-api/src/web-core/AudioContext.tsx @@ -106,7 +106,7 @@ export default class AudioContext implements BaseAudioContext { ); } - return new AudioBuffer(this, { numberOfChannels, length, sampleRate }); + return new AudioBuffer({ numberOfChannels, length, sampleRate }); } createPeriodicWave( diff --git a/packages/react-native-audio-api/src/web-core/DelayNode.tsx b/packages/react-native-audio-api/src/web-core/DelayNode.tsx index 48942cf7f..b0d5ad23b 100644 --- a/packages/react-native-audio-api/src/web-core/DelayNode.tsx +++ b/packages/react-native-audio-api/src/web-core/DelayNode.tsx @@ -2,14 +2,12 @@ import BaseAudioContext from './BaseAudioContext'; import AudioNode from './AudioNode'; import AudioParam from './AudioParam'; import { TDelayOptions } from '../types'; -import { DelayOptions } from '../defaults'; export default class DelayNode extends AudioNode { readonly delayTime: AudioParam; constructor(context: BaseAudioContext, options?: TDelayOptions) { - const finalOptions = { ...DelayOptions, ...options }; - const delay = new globalThis.DelayNode(context.context, finalOptions); + const delay = new globalThis.DelayNode(context.context, options); super(context, delay); this.delayTime = new AudioParam(delay.delayTime, context); } diff --git a/packages/react-native-audio-api/src/web-core/IIRFilterNode.tsx b/packages/react-native-audio-api/src/web-core/IIRFilterNode.tsx index df4a680c1..d31c0e3d9 100644 --- a/packages/react-native-audio-api/src/web-core/IIRFilterNode.tsx +++ b/packages/react-native-audio-api/src/web-core/IIRFilterNode.tsx @@ -1,19 +1,14 @@ import { NotSupportedError } from '../errors'; import AudioNode from './AudioNode'; import { TIIRFilterOptions } from '../types'; -import { AudioNodeOptions } from '../defaults'; import BaseAudioContext from './BaseAudioContext'; export default class IIRFilterNode extends AudioNode { constructor(context: BaseAudioContext, options: TIIRFilterOptions) { - const finalOptions: TIIRFilterOptions = { - ...AudioNodeOptions, - ...options, - }; - const iirFilterNode = new globalThis.IIRFilterNode(context.context, { - feedforward: finalOptions.feedforward, - feedback: finalOptions.feedback, - }); + const iirFilterNode = new globalThis.IIRFilterNode( + context.context, + options + ); super(context, iirFilterNode); } diff --git a/packages/react-native-audio-api/src/web-core/OfflineAudioContext.tsx b/packages/react-native-audio-api/src/web-core/OfflineAudioContext.tsx index f8817d2ee..645e7eec1 100644 --- a/packages/react-native-audio-api/src/web-core/OfflineAudioContext.tsx +++ b/packages/react-native-audio-api/src/web-core/OfflineAudioContext.tsx @@ -113,7 +113,7 @@ export default class OfflineAudioContext implements BaseAudioContext { ); } - return new AudioBuffer(this, { numberOfChannels, length, sampleRate }); + return new AudioBuffer({ numberOfChannels, length, sampleRate }); } createPeriodicWave( diff --git a/yarn.lock b/yarn.lock index 055ea425f..2096db06d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4729,9 +4729,9 @@ __metadata: linkType: hard "caniuse-lite@npm:^1.0.30001737": - version: 1.0.30001737 - resolution: "caniuse-lite@npm:1.0.30001737" - checksum: 10/8e13943f1b2c5fc6b77db1a99081028c35c811689941d39ecfd3d9923b722e894213e87a8f4f2df9afc21c82542802f51caf716e80b396c8d43e49eec9ad8baa + version: 1.0.30001767 + resolution: "caniuse-lite@npm:1.0.30001767" + checksum: 10/786028f1b4036b0fddef29eaa7cee40549136662ed803fda3ca77b05889159ab4469a6e4469f7bb01923336db415b73a845a5522be2d7383af6e9a4784a491fc languageName: node linkType: hard