From 642cdefd475623f7cb9c94b11bb657995d927ac6 Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Sun, 27 Jul 2025 13:15:58 +0200 Subject: [PATCH 01/10] chore: unified AudioContext --- .../audiodocs/docs/core/audio-context.mdx | 2 +- .../src/web-core/AudioContext.tsx | 146 ++---------------- 2 files changed, 11 insertions(+), 137 deletions(-) diff --git a/packages/audiodocs/docs/core/audio-context.mdx b/packages/audiodocs/docs/core/audio-context.mdx index 94998a084..aa216a9b1 100644 --- a/packages/audiodocs/docs/core/audio-context.mdx +++ b/packages/audiodocs/docs/core/audio-context.mdx @@ -1,5 +1,5 @@ --- -sidebar_position: 2 +sidebar_position: 1 --- # AudioContext 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 78ada7bf1..0a5e20fcd 100644 --- a/packages/react-native-audio-api/src/web-core/AudioContext.tsx +++ b/packages/react-native-audio-api/src/web-core/AudioContext.tsx @@ -1,29 +1,8 @@ -import { - ContextState, - PeriodicWaveConstraints, - AudioContextOptions, - AudioBufferSourceNodeOptions, -} from '../types'; -import { InvalidAccessError, NotSupportedError } from '../errors'; +import { AudioContextOptions } from '../types'; +import { NotSupportedError } from '../errors'; import BaseAudioContext from './BaseAudioContext'; -import AnalyserNode from './AnalyserNode'; -import AudioDestinationNode from './AudioDestinationNode'; -import AudioBuffer from './AudioBuffer'; -import AudioBufferSourceNode from './AudioBufferSourceNode'; -import BiquadFilterNode from './BiquadFilterNode'; -import GainNode from './GainNode'; -import OscillatorNode from './OscillatorNode'; -import PeriodicWave from './PeriodicWave'; -import StereoPannerNode from './StereoPannerNode'; - -import { globalWasmPromise, globalTag } from './custom/LoadCustomWasm'; - -export default class AudioContext implements BaseAudioContext { - readonly context: globalThis.AudioContext; - - readonly destination: AudioDestinationNode; - readonly sampleRate: number; +export default class AudioContext extends BaseAudioContext { constructor(options?: AudioContextOptions, _initSuspended: boolean = false) { if ( options && @@ -35,123 +14,18 @@ export default class AudioContext implements BaseAudioContext { ); } - this.context = new window.AudioContext({ sampleRate: options?.sampleRate }); - - this.sampleRate = this.context.sampleRate; - this.destination = new AudioDestinationNode(this, this.context.destination); - } - - public get currentTime(): number { - return this.context.currentTime; - } - - public get state(): ContextState { - return this.context.state as ContextState; - } - - createOscillator(): OscillatorNode { - return new OscillatorNode(this, this.context.createOscillator()); - } - - createGain(): GainNode { - return new GainNode(this, this.context.createGain()); - } - - createStereoPanner(): StereoPannerNode { - return new StereoPannerNode(this, this.context.createStereoPanner()); - } - - createBiquadFilter(): BiquadFilterNode { - return new BiquadFilterNode(this, this.context.createBiquadFilter()); - } - - async createBufferSource( - options?: AudioBufferSourceNodeOptions - ): Promise { - if (!options || !options.pitchCorrection) { - return new AudioBufferSourceNode( - this, - this.context.createBufferSource(), - false - ); - } - - await globalWasmPromise; - - const wasmStretch = await window[globalTag](this.context); - - return new AudioBufferSourceNode(this, wasmStretch, true); - } - - createBuffer( - numOfChannels: number, - length: number, - sampleRate: number - ): AudioBuffer { - if (numOfChannels < 1 || numOfChannels >= 32) { - throw new NotSupportedError( - `The number of channels provided (${numOfChannels}) 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.context.createBuffer(numOfChannels, length, sampleRate) - ); - } - - createPeriodicWave( - real: Float32Array, - imag: Float32Array, - constraints?: PeriodicWaveConstraints - ): PeriodicWave { - if (real.length !== imag.length) { - throw new InvalidAccessError( - `The lengths of the real (${real.length}) and imaginary (${imag.length}) arrays must match.` - ); - } - - return new PeriodicWave( - this.context.createPeriodicWave(real, imag, constraints) - ); - } - - createAnalyser(): AnalyserNode { - return new AnalyserNode(this, this.context.createAnalyser()); - } - - async decodeAudioDataSource(source: string): Promise { - const arrayBuffer = await fetch(source).then((response) => - response.arrayBuffer() - ); - - return this.decodeAudioData(arrayBuffer); - } - - async decodeAudioData(arrayBuffer: ArrayBuffer): Promise { - return new AudioBuffer(await this.context.decodeAudioData(arrayBuffer)); + super(new window.AudioContext({ sampleRate: options?.sampleRate })); } - async close(): Promise { - await this.context.close(); + async close(): Promise { + await (this.context as globalThis.AudioContext).close(); } - async resume(): Promise { - await this.context.resume(); + async resume(): Promise { + await (this.context as globalThis.AudioContext).resume(); } - async suspend(): Promise { - await this.context.suspend(); + async suspend(): Promise { + await (this.context as globalThis.AudioContext).suspend(); } } From 4da42b7cd5e4a433ba1283aaf393e9349216ebc9 Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Sun, 27 Jul 2025 13:16:23 +0200 Subject: [PATCH 02/10] ci: yarn format --- .../src/main/cpp/audioapi/android/core/AudioDecoder.cpp | 6 ++++-- .../common/cpp/audioapi/core/BaseAudioContext.cpp | 3 ++- .../common/cpp/audioapi/core/effects/BiquadFilterNode.cpp | 1 - .../ios/audioapi/ios/AudioAPIModule.mm | 4 ++-- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/react-native-audio-api/android/src/main/cpp/audioapi/android/core/AudioDecoder.cpp b/packages/react-native-audio-api/android/src/main/cpp/audioapi/android/core/AudioDecoder.cpp index cf8920c10..16a6f7bfd 100644 --- a/packages/react-native-audio-api/android/src/main/cpp/audioapi/android/core/AudioDecoder.cpp +++ b/packages/react-native-audio-api/android/src/main/cpp/audioapi/android/core/AudioDecoder.cpp @@ -38,7 +38,8 @@ std::shared_ptr AudioDecoder::decodeWithFilePath( &decoder, buffer.data(), totalFrameCount, &framesDecoded); if (framesDecoded == 0) { - // __android_log_print(ANDROID_LOG_ERROR, "AudioDecoder", "Failed to decode"); + // __android_log_print(ANDROID_LOG_ERROR, "AudioDecoder", "Failed to + // decode"); ma_decoder_uninit(&decoder); return nullptr; @@ -88,7 +89,8 @@ std::shared_ptr AudioDecoder::decodeWithMemoryBlock( &decoder, buffer.data(), totalFrameCount, &framesDecoded); if (framesDecoded == 0) { - // __android_log_print(ANDROID_LOG_ERROR, "AudioDecoder", "Failed to decode"); + // __android_log_print(ANDROID_LOG_ERROR, "AudioDecoder", "Failed to + // decode"); ma_decoder_uninit(&decoder); return nullptr; 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 87ca899f0..a31570c96 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 @@ -141,7 +141,8 @@ std::shared_ptr BaseAudioContext::decodeAudioData( } std::shared_ptr BaseAudioContext::decodeWithPCMInBase64( - const std::string &data, float playbackSpeed) { + const std::string &data, + float playbackSpeed) { auto audioBus = audioDecoder_->decodeWithPCMInBase64(data, playbackSpeed); if (!audioBus) { 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 bcdb56fd8..ade534d41 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 @@ -77,7 +77,6 @@ void BiquadFilterNode::getFrequencyResponse( float *magResponseOutput, float *phaseResponseOutput, const int length) { - // Local copies for micro-optimization float b0 = b0_; float b1 = b1_; diff --git a/packages/react-native-audio-api/ios/audioapi/ios/AudioAPIModule.mm b/packages/react-native-audio-api/ios/audioapi/ios/AudioAPIModule.mm index 6113a69f7..1e1995fb4 100644 --- a/packages/react-native-audio-api/ios/audioapi/ios/AudioAPIModule.mm +++ b/packages/react-native-audio-api/ios/audioapi/ios/AudioAPIModule.mm @@ -142,8 +142,8 @@ - (void)invalidate [self.audioSessionManager checkRecordingPermissions:resolve reject:reject]; } -RCT_EXPORT_METHOD(getDevicesInfo : (nonnull RCTPromiseResolveBlock)resolve reject : (nonnull RCTPromiseRejectBlock) - reject) +RCT_EXPORT_METHOD( + getDevicesInfo : (nonnull RCTPromiseResolveBlock)resolve reject : (nonnull RCTPromiseRejectBlock)reject) { [self.audioSessionManager getDevicesInfo:resolve reject:reject]; } From eeb7a45d0ad75edb8538e1e51616b39f3d8d2cda Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Sun, 27 Jul 2025 13:16:51 +0200 Subject: [PATCH 03/10] chore: unified AudioParam --- packages/audiodocs/docs/core/audio-param.mdx | 2 +- .../src/web-core/AudioParam.tsx | 30 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/audiodocs/docs/core/audio-param.mdx b/packages/audiodocs/docs/core/audio-param.mdx index 9afaa8c60..ea2b31b35 100644 --- a/packages/audiodocs/docs/core/audio-param.mdx +++ b/packages/audiodocs/docs/core/audio-param.mdx @@ -1,5 +1,5 @@ --- -sidebar_position: 4 +sidebar_position: 3 --- import { Optional, ReadOnly } from '@site/src/components/Badges'; diff --git a/packages/react-native-audio-api/src/web-core/AudioParam.tsx b/packages/react-native-audio-api/src/web-core/AudioParam.tsx index 341f59e55..d85cface1 100644 --- a/packages/react-native-audio-api/src/web-core/AudioParam.tsx +++ b/packages/react-native-audio-api/src/web-core/AudioParam.tsx @@ -7,22 +7,22 @@ export default class AudioParam { readonly maxValue: number; readonly context: BaseAudioContext; - readonly param: globalThis.AudioParam; + readonly audioParam: globalThis.AudioParam; - constructor(param: globalThis.AudioParam, context: BaseAudioContext) { - this.param = param; - this.defaultValue = param.defaultValue; - this.minValue = param.minValue; - this.maxValue = param.maxValue; + constructor(audioParam: globalThis.AudioParam, context: BaseAudioContext) { + this.audioParam = audioParam; + this.defaultValue = audioParam.defaultValue; + this.minValue = audioParam.minValue; + this.maxValue = audioParam.maxValue; this.context = context; } public get value(): number { - return this.param.value; + return this.audioParam.value; } public set value(value: number) { - this.param.value = value; + this.audioParam.value = value; } public setValueAtTime(value: number, startTime: number): AudioParam { @@ -32,7 +32,7 @@ export default class AudioParam { ); } - this.param.setValueAtTime(value, startTime); + this.audioParam.setValueAtTime(value, startTime); return this; } @@ -44,7 +44,7 @@ export default class AudioParam { ); } - this.param.linearRampToValueAtTime(value, endTime); + this.audioParam.linearRampToValueAtTime(value, endTime); return this; } @@ -59,7 +59,7 @@ export default class AudioParam { ); } - this.param.exponentialRampToValueAtTime(value, endTime); + this.audioParam.exponentialRampToValueAtTime(value, endTime); return this; } @@ -81,7 +81,7 @@ export default class AudioParam { ); } - this.param.setTargetAtTime(target, startTime, timeConstant); + this.audioParam.setTargetAtTime(target, startTime, timeConstant); return this; } @@ -107,7 +107,7 @@ export default class AudioParam { throw new InvalidStateError(`values must contain at least two values`); } - this.param.setValueCurveAtTime(values, startTime, duration); + this.audioParam.setValueCurveAtTime(values, startTime, duration); return this; } @@ -119,7 +119,7 @@ export default class AudioParam { ); } - this.param.cancelScheduledValues(cancelTime); + this.audioParam.cancelScheduledValues(cancelTime); return this; } @@ -131,7 +131,7 @@ export default class AudioParam { ); } - this.param.cancelAndHoldAtTime(cancelTime); + this.audioParam.cancelAndHoldAtTime(cancelTime); return this; } From ede6f2a7e8b263570ed73e25262097cd236addcd Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Sun, 27 Jul 2025 13:17:43 +0200 Subject: [PATCH 04/10] chore: unified OfflineAudioContext --- .../docs/core/offline-audio-context.mdx | 9 + .../src/web-core/OfflineAudioContext.tsx | 164 +++++------------- 2 files changed, 56 insertions(+), 117 deletions(-) create mode 100644 packages/audiodocs/docs/core/offline-audio-context.mdx diff --git a/packages/audiodocs/docs/core/offline-audio-context.mdx b/packages/audiodocs/docs/core/offline-audio-context.mdx new file mode 100644 index 000000000..4593dbbc2 --- /dev/null +++ b/packages/audiodocs/docs/core/offline-audio-context.mdx @@ -0,0 +1,9 @@ +--- +sidebar_position: 5 +--- + +import { Optional, ReadOnly} from '@site/src/components/Badges'; + +# OfflineAudioContext + +## 🚧 Under development 🚧 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 b4c6f95aa..0eac6aab4 100644 --- a/packages/react-native-audio-api/src/web-core/OfflineAudioContext.tsx +++ b/packages/react-native-audio-api/src/web-core/OfflineAudioContext.tsx @@ -1,28 +1,12 @@ -import { - ContextState, - PeriodicWaveConstraints, - OfflineAudioContextOptions, - AudioBufferSourceNodeOptions, -} from '../types'; -import { InvalidAccessError, NotSupportedError } from '../errors'; +import { OfflineAudioContextOptions } from '../types'; +import { NotSupportedError, InvalidStateError } from '../errors'; import BaseAudioContext from './BaseAudioContext'; -import AnalyserNode from './AnalyserNode'; -import AudioDestinationNode from './AudioDestinationNode'; import AudioBuffer from './AudioBuffer'; -import AudioBufferSourceNode from './AudioBufferSourceNode'; -import BiquadFilterNode from './BiquadFilterNode'; -import GainNode from './GainNode'; -import OscillatorNode from './OscillatorNode'; -import PeriodicWave from './PeriodicWave'; -import StereoPannerNode from './StereoPannerNode'; -import { globalWasmPromise, globalTag } from './custom/LoadCustomWasm'; - -export default class OfflineAudioContext implements BaseAudioContext { - readonly context: globalThis.OfflineAudioContext; - - readonly destination: AudioDestinationNode; - readonly sampleRate: number; +export default class OfflineAudioContext extends BaseAudioContext { + private isSuspended: boolean; + private isRendering: boolean; + private duration: number; constructor(options: OfflineAudioContextOptions); constructor(numberOfChannels: number, length: number, sampleRate: number); @@ -32,132 +16,78 @@ export default class OfflineAudioContext implements BaseAudioContext { arg2?: number ) { if (typeof arg0 === 'object') { - this.context = new window.OfflineAudioContext(arg0); + const { numberOfChannels, length, sampleRate } = arg0; + super( + new window.OfflineAudioContext(numberOfChannels, length, sampleRate) + ); + + this.duration = length / sampleRate; } else if ( typeof arg0 === 'number' && typeof arg1 === 'number' && typeof arg2 === 'number' ) { - this.context = new window.OfflineAudioContext(arg0, arg1, arg2); + super(new window.OfflineAudioContext(arg0, arg1, arg2)); + this.duration = arg1 / arg2; } else { throw new NotSupportedError('Invalid constructor arguments'); } - this.sampleRate = this.context.sampleRate; - this.destination = new AudioDestinationNode(this, this.context.destination); + this.isSuspended = false; + this.isRendering = false; } - public get currentTime(): number { - return this.context.currentTime; - } - - public get state(): ContextState { - return this.context.state as ContextState; - } - - createOscillator(): OscillatorNode { - return new OscillatorNode(this, this.context.createOscillator()); - } - - createGain(): GainNode { - return new GainNode(this, this.context.createGain()); - } - - createStereoPanner(): StereoPannerNode { - return new StereoPannerNode(this, this.context.createStereoPanner()); - } - - createBiquadFilter(): BiquadFilterNode { - return new BiquadFilterNode(this, this.context.createBiquadFilter()); - } - - async createBufferSource( - options?: AudioBufferSourceNodeOptions - ): Promise { - if (!options || !options.pitchCorrection) { - return new AudioBufferSourceNode( - this, - this.context.createBufferSource(), - false + async resume(): Promise { + if (!this.isRendering) { + throw new InvalidStateError( + 'Cannot resume an OfflineAudioContext while rendering' ); } - await globalWasmPromise; + if (!this.isSuspended) { + throw new InvalidStateError( + 'Cannot resume an OfflineAudioContext that is not suspended' + ); + } - const wasmStretch = await window[globalTag](this.context); + this.isSuspended = false; - return new AudioBufferSourceNode(this, wasmStretch, true); + await (this.context as globalThis.OfflineAudioContext).resume(); } - createBuffer( - numOfChannels: number, - length: number, - sampleRate: number - ): AudioBuffer { - if (numOfChannels < 1 || numOfChannels >= 32) { - throw new NotSupportedError( - `The number of channels provided (${numOfChannels}) is outside the range [1, 32]` - ); + async suspend(suspendTime: number): Promise { + if (suspendTime < 0) { + throw new InvalidStateError('suspendTime must be a non-negative number'); } - if (length <= 0) { - throw new NotSupportedError( - `The number of frames provided (${length}) is less than or equal to the minimum bound (0)` + if (suspendTime < this.context.currentTime) { + throw new InvalidStateError( + `suspendTime must be greater than the current time: ${suspendTime}` ); } - if (sampleRate < 8000 || sampleRate > 96000) { - throw new NotSupportedError( - `The sample rate provided (${sampleRate}) is outside the range [8000, 96000]` + if (suspendTime > this.duration) { + throw new InvalidStateError( + `suspendTime must be less than the duration of the context: ${suspendTime}` ); } - return new AudioBuffer( - this.context.createBuffer(numOfChannels, length, sampleRate) - ); - } + this.isSuspended = true; - createPeriodicWave( - real: Float32Array, - imag: Float32Array, - constraints?: PeriodicWaveConstraints - ): PeriodicWave { - if (real.length !== imag.length) { - throw new InvalidAccessError( - `The lengths of the real (${real.length}) and imaginary (${imag.length}) arrays must match.` - ); - } - - return new PeriodicWave( - this.context.createPeriodicWave(real, imag, constraints) - ); - } - - createAnalyser(): AnalyserNode { - return new AnalyserNode(this, this.context.createAnalyser()); - } - - async decodeAudioDataSource(source: string): Promise { - const arrayBuffer = await fetch(source).then((response) => - response.arrayBuffer() - ); - - return this.decodeAudioData(arrayBuffer); - } - - async decodeAudioData(arrayBuffer: ArrayBuffer): Promise { - return new AudioBuffer(await this.context.decodeAudioData(arrayBuffer)); + await (this.context as globalThis.OfflineAudioContext).suspend(suspendTime); } async startRendering(): Promise { - return new AudioBuffer(await this.context.startRendering()); - } + if (this.isRendering) { + throw new InvalidStateError('OfflineAudioContext is already rendering'); + } - async resume(): Promise { - await this.context.resume(); - } + this.isRendering = true; + + const audioBuffer = await ( + this.context as globalThis.OfflineAudioContext + ).startRendering(); - async suspend(suspendTime: number): Promise { - await this.context.suspend(suspendTime); + return new AudioBuffer(audioBuffer); } } From 79190fe2457a117400c4e544af5dd62dc901089f Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Sun, 27 Jul 2025 13:27:27 +0200 Subject: [PATCH 05/10] chore: unified AudioNode --- packages/audiodocs/docs/core/audio-node.mdx | 2 +- .../react-native-audio-api/src/core/AudioNode.ts | 4 +++- .../src/web-core/AudioNode.tsx | 16 +++++++++------- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/packages/audiodocs/docs/core/audio-node.mdx b/packages/audiodocs/docs/core/audio-node.mdx index 67c830a2b..73727481f 100644 --- a/packages/audiodocs/docs/core/audio-node.mdx +++ b/packages/audiodocs/docs/core/audio-node.mdx @@ -1,5 +1,5 @@ --- -sidebar_position: 3 +sidebar_position: 2 --- import { Optional, ReadOnly } from '@site/src/components/Badges'; diff --git a/packages/react-native-audio-api/src/core/AudioNode.ts b/packages/react-native-audio-api/src/core/AudioNode.ts index 2e19d51d1..26bc5a352 100644 --- a/packages/react-native-audio-api/src/core/AudioNode.ts +++ b/packages/react-native-audio-api/src/core/AudioNode.ts @@ -42,8 +42,10 @@ export default class AudioNode { public disconnect(destination?: AudioNode | AudioParam): void { if (destination instanceof AudioParam) { this.node.disconnect(destination.audioParam); + } else if (destination instanceof AudioNode) { + this.node.disconnect(destination.node); } else { - this.node.disconnect(destination?.node); + this.node.disconnect(); } } } diff --git a/packages/react-native-audio-api/src/web-core/AudioNode.tsx b/packages/react-native-audio-api/src/web-core/AudioNode.tsx index a66113f1f..e6c1b7f17 100644 --- a/packages/react-native-audio-api/src/web-core/AudioNode.tsx +++ b/packages/react-native-audio-api/src/web-core/AudioNode.tsx @@ -1,6 +1,7 @@ import BaseAudioContext from './BaseAudioContext'; import { ChannelCountMode, ChannelInterpretation } from '../types'; import AudioParam from './AudioParam'; +import { InvalidAccessError } from '../errors'; export default class AudioNode { readonly context: BaseAudioContext; @@ -24,13 +25,13 @@ export default class AudioNode { public connect(destination: AudioNode | AudioParam): AudioNode | AudioParam { if (this.context !== destination.context) { - throw new Error( + throw new InvalidAccessError( 'Source and destination are from different BaseAudioContexts' ); } if (destination instanceof AudioParam) { - this.node.connect(destination.param); + this.node.connect(destination.audioParam); } else { this.node.connect(destination.node); } @@ -38,12 +39,13 @@ export default class AudioNode { return destination; } - public disconnect(destination?: AudioNode): void { - if (destination === undefined) { + public disconnect(destination?: AudioNode | AudioParam): void { + if (destination instanceof AudioParam) { + this.node.disconnect(destination.audioParam); + } else if (destination instanceof AudioNode) { + this.node.disconnect(destination.node); + } else { this.node.disconnect(); - return; } - - this.node.disconnect(destination.node); } } From b138b0be229a3634b3e547e43fdecded07943cbf Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Sun, 27 Jul 2025 13:31:44 +0200 Subject: [PATCH 06/10] fix: small nitpicks related with BaseAudioContext and AudioBufferSourceNode --- .../docs/core/base-audio-context.mdx | 2 +- .../docs/sources/audio-buffer-source-node.mdx | 4 +- .../src/web-core/AudioBufferSourceNode.tsx | 21 ++- .../src/web-core/BaseAudioContext.tsx | 136 ++++++++++++++++-- 4 files changed, 144 insertions(+), 19 deletions(-) diff --git a/packages/audiodocs/docs/core/base-audio-context.mdx b/packages/audiodocs/docs/core/base-audio-context.mdx index c98f11a05..07339ef0a 100644 --- a/packages/audiodocs/docs/core/base-audio-context.mdx +++ b/packages/audiodocs/docs/core/base-audio-context.mdx @@ -1,5 +1,5 @@ --- -sidebar_position: 1 +sidebar_position: 4 --- import { Optional, ReadOnly, MobileOnly } from '@site/src/components/Badges'; diff --git a/packages/audiodocs/docs/sources/audio-buffer-source-node.mdx b/packages/audiodocs/docs/sources/audio-buffer-source-node.mdx index a124a99c8..533d301d5 100644 --- a/packages/audiodocs/docs/sources/audio-buffer-source-node.mdx +++ b/packages/audiodocs/docs/sources/audio-buffer-source-node.mdx @@ -3,7 +3,7 @@ sidebar_position: 4 --- import AudioNodePropsTable from "@site/src/components/AudioNodePropsTable" -import { Optional, Overridden } from '@site/src/components/Badges'; +import { Optional, Overridden, MobileOnly } from '@site/src/components/Badges'; # AudioBufferSourceNode @@ -49,7 +49,7 @@ function App() { | :----: | :----: | :-------- | | `buffer` | [`AudioBuffer`](/sources/audio-buffer) | Associated `AudioBuffer`. | | `loop` | `boolean` | Boolean indicating if audio data must be replayed after when end of the associated `AudioBuffer` is reached. | -| `loopSkip` | `boolean` | Boolean indicating if upon setting up `loopStart` we want to skip immediately to the loop start. | +| `loopSkip` | `boolean` | Boolean indicating if upon setting up `loopStart` we want to skip immediately to the loop start. | | `loopStart` | `number` | Float value indicating the time, in seconds, at which playback of the audio must begin, if loop is true. | | `loopEnd` | `number` | Float value indicating the time, in seconds, at which playback of the audio must end and loop back to `loopStart`, if loop is true. | 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 71c749848..64fbcdc51 100644 --- a/packages/react-native-audio-api/src/web-core/AudioBufferSourceNode.tsx +++ b/packages/react-native-audio-api/src/web-core/AudioBufferSourceNode.tsx @@ -26,7 +26,7 @@ interface IStretcherNode extends globalThis.AudioNode { numberOfInputs: number; numberOfOutputs: number; - onended: + onEnded: | ((this: globalThis.AudioScheduledSourceNode, ev: Event) => unknown) | null; addEventListener: ( @@ -193,6 +193,7 @@ export default class AudioBufferSourceNode< private _loop: boolean = false; private _loopStart: number = -1; private _loopEnd: number = -1; + private _loopSkip: boolean = false; private _buffer: AudioBuffer | null = null; @@ -319,6 +320,24 @@ export default class AudioBufferSourceNode< return this.asBufferSource().loop; } + public set loopSkip(value: boolean) { + console.warn('loopSkip does not work on web'); + + if (this.isStretcherNode()) { + this._loop = value; + } + } + + public get loopSkip(): boolean { + console.warn('loopSkip does not work on web'); + + if (this.isStretcherNode()) { + return this._loopSkip; + } + + return false; + } + public set loop(value: boolean) { if (this.isStretcherNode()) { this._loop = value; diff --git a/packages/react-native-audio-api/src/web-core/BaseAudioContext.tsx b/packages/react-native-audio-api/src/web-core/BaseAudioContext.tsx index 5cafcee77..cb0cbb192 100644 --- a/packages/react-native-audio-api/src/web-core/BaseAudioContext.tsx +++ b/packages/react-native-audio-api/src/web-core/BaseAudioContext.tsx @@ -1,4 +1,9 @@ -import { ContextState, PeriodicWaveConstraints } from '../types'; +import { + ContextState, + PeriodicWaveConstraints, + AudioBufferSourceNodeOptions, +} from '../types'; +import { InvalidAccessError, NotSupportedError } from '../errors'; import AnalyserNode from './AnalyserNode'; import AudioDestinationNode from './AudioDestinationNode'; import AudioBuffer from './AudioBuffer'; @@ -9,30 +14,131 @@ import OscillatorNode from './OscillatorNode'; import PeriodicWave from './PeriodicWave'; import StereoPannerNode from './StereoPannerNode'; -export default interface BaseAudioContext { - readonly context: globalThis.BaseAudioContext; +import { globalWasmPromise, globalTag } from './custom/LoadCustomWasm'; +export default class BaseAudioContext { + protected readonly context: globalThis.BaseAudioContext; readonly destination: AudioDestinationNode; readonly sampleRate: number; - get currentTime(): number; - get state(): ContextState; - createOscillator(): OscillatorNode; - createGain(): GainNode; - createStereoPanner(): StereoPannerNode; - createBiquadFilter(): BiquadFilterNode; - createBufferSource(): Promise; + constructor(context: globalThis.BaseAudioContext) { + this.context = context; + this.destination = new AudioDestinationNode(this, this.context.destination); + this.sampleRate = this.context.sampleRate; + } + + public get currentTime(): number { + return this.context.currentTime; + } + + public get state(): ContextState { + return this.context.state as ContextState; + } + + createOscillator(): OscillatorNode { + return new OscillatorNode(this, this.context.createOscillator()); + } + + createGain(): GainNode { + return new GainNode(this, this.context.createGain()); + } + + createStereoPanner(): StereoPannerNode { + return new StereoPannerNode(this, this.context.createStereoPanner()); + } + + createBiquadFilter(): BiquadFilterNode { + return new BiquadFilterNode(this, this.context.createBiquadFilter()); + } + + // UNIFIED IT SOMEHOW + async createBufferSource( + options?: AudioBufferSourceNodeOptions + ): Promise { + if (!options || !options.pitchCorrection) { + return new AudioBufferSourceNode( + this, + this.context.createBufferSource(), + false + ); + } + + await globalWasmPromise; + + const wasmStretch = await window[globalTag](this.context); + + return new AudioBufferSourceNode(this, wasmStretch, true); + } + createBuffer( numOfChannels: number, length: number, sampleRate: number - ): AudioBuffer; + ): AudioBuffer { + if (numOfChannels < 1 || numOfChannels >= 32) { + throw new NotSupportedError( + `The number of channels provided (${numOfChannels}) 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.context.createBuffer(numOfChannels, length, sampleRate) + ); + } + createPeriodicWave( real: Float32Array, imag: Float32Array, constraints?: PeriodicWaveConstraints - ): PeriodicWave; - createAnalyser(): AnalyserNode; - decodeAudioDataSource(source: string): Promise; - decodeAudioData(arrayBuffer: ArrayBuffer): Promise; + ): PeriodicWave { + if (real.length !== imag.length) { + throw new InvalidAccessError( + `The lengths of the real (${real.length}) and imaginary (${imag.length}) arrays must match.` + ); + } + + return new PeriodicWave( + this.context.createPeriodicWave(real, imag, constraints) + ); + } + + createAnalyser(): AnalyserNode { + return new AnalyserNode(this, this.context.createAnalyser()); + } + + async decodeAudioDataSource(source: string): Promise { + const arrayBuffer = await fetch(source).then((response) => + response.arrayBuffer() + ); + + return this.decodeAudioData(arrayBuffer); + } + + async decodeAudioData(arrayBuffer: ArrayBuffer): Promise { + return new AudioBuffer(await this.context.decodeAudioData(arrayBuffer)); + } + + // TODO: IMPLEMENT IT + // eslint-disable-next-line @typescript-eslint/require-await + async decodePCMInBase64Data( + base64: string, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + playbackRate: number = 1.0 + ): Promise { + console.warn('decodePCMInBase64Data does not work on web'); + + return this.createBuffer(2, 48000, this.sampleRate); + } } From 258895ca367214000af28a021a616e4aac4d090f Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Sun, 27 Jul 2025 14:29:56 +0200 Subject: [PATCH 07/10] refactor: restructured api folder tree --- packages/react-native-audio-api/src/api.ts | 40 +++++++++---------- .../react-native-audio-api/src/api.web.ts | 30 +++++++------- .../{core => mobile/analysis}/AnalyserNode.ts | 6 +-- .../src/{ => mobile}/core/AudioContext.ts | 4 +- .../src/{ => mobile}/core/AudioNode.ts | 4 +- .../src/{ => mobile}/core/AudioParam.ts | 2 +- .../src/{ => mobile}/core/BaseAudioContext.ts | 26 ++++++------ .../{ => mobile}/core/OfflineAudioContext.ts | 6 +-- .../destinations}/AudioDestinationNode.ts | 2 +- .../effects}/BiquadFilterNode.ts | 10 ++--- .../effects}/CustomProcessorNode.ts | 8 ++-- .../src/{core => mobile/effects}/GainNode.ts | 6 +-- .../{core => mobile/effects}/PeriodicWave.ts | 0 .../effects}/StereoPannerNode.ts | 6 +-- .../{ => mobile}/events/AudioEventEmitter.ts | 0 .../events/AudioEventSubscription.ts | 2 +- .../src/{ => mobile}/events/index.ts | 0 .../src/{ => mobile}/events/types.ts | 2 +- .../hooks/useSystemVolume.ts} | 0 .../{core => mobile/inputs}/AudioRecorder.ts | 4 +- .../src/mobile/inputs/index.ts | 1 + .../src/{ => mobile}/interfaces.ts | 2 +- .../{core => mobile/sources}/AudioBuffer.ts | 2 +- .../sources}/AudioBufferBaseSourceNode.ts | 4 +- .../sources}/AudioBufferQueueSourceNode.ts | 2 +- .../sources}/AudioBufferSourceNode.ts | 2 +- .../sources}/AudioScheduledSourceNode.ts | 4 +- .../sources}/OscillatorNode.ts | 10 ++--- .../src/{ => mobile}/system/AudioManager.ts | 2 +- .../src/{ => mobile}/system/index.ts | 0 .../src/{ => mobile}/system/types.ts | 0 .../src/specs/NativeAudioAPIModule.ts | 2 +- .../analysis}/AnalyserNode.tsx | 6 +-- .../{web-core => web/core}/AudioContext.tsx | 4 +- .../src/{web-core => web/core}/AudioNode.tsx | 4 +- .../src/{web-core => web/core}/AudioParam.tsx | 2 +- .../core}/BaseAudioContext.tsx | 26 ++++++------ .../core}/OfflineAudioContext.tsx | 6 +-- .../custom/LoadCustomWasm.ts | 0 .../src/{web-core => web}/custom/index.ts | 0 .../custom/signalsmithStretch/LICENSE.txt | 0 .../custom/signalsmithStretch/README.md | 0 .../signalsmithStretch/SignalsmithStretch.mjs | 0 .../destinations}/AudioDestinationNode.tsx | 2 +- .../effects}/BiquadFilterNode.tsx | 10 ++--- .../{web-core => web/effects}/GainNode.tsx | 6 +-- .../effects}/PeriodicWave.tsx | 0 .../effects}/StereoPannerNode.tsx | 6 +-- .../{web-core => web/sources}/AudioBuffer.tsx | 2 +- .../sources}/AudioBufferSourceNode.tsx | 10 ++--- .../sources}/AudioScheduledSourceNode.tsx | 7 ++-- .../sources}/OscillatorNode.tsx | 10 ++--- 52 files changed, 145 insertions(+), 145 deletions(-) rename packages/react-native-audio-api/src/{core => mobile/analysis}/AnalyserNode.ts (94%) rename packages/react-native-audio-api/src/{ => mobile}/core/AudioContext.ts (90%) rename packages/react-native-audio-api/src/{ => mobile}/core/AudioNode.ts (92%) rename packages/react-native-audio-api/src/{ => mobile}/core/AudioParam.ts (98%) rename packages/react-native-audio-api/src/{ => mobile}/core/BaseAudioContext.ts (83%) rename packages/react-native-audio-api/src/{ => mobile}/core/OfflineAudioContext.ts (93%) rename packages/react-native-audio-api/src/{core => mobile/destinations}/AudioDestinationNode.ts (59%) rename packages/react-native-audio-api/src/{core => mobile/effects}/BiquadFilterNode.ts (85%) rename packages/react-native-audio-api/src/{core => mobile/effects}/CustomProcessorNode.ts (76%) rename packages/react-native-audio-api/src/{core => mobile/effects}/GainNode.ts (64%) rename packages/react-native-audio-api/src/{core => mobile/effects}/PeriodicWave.ts (100%) rename packages/react-native-audio-api/src/{core => mobile/effects}/StereoPannerNode.ts (66%) rename packages/react-native-audio-api/src/{ => mobile}/events/AudioEventEmitter.ts (100%) rename packages/react-native-audio-api/src/{ => mobile}/events/AudioEventSubscription.ts (92%) rename packages/react-native-audio-api/src/{ => mobile}/events/index.ts (100%) rename packages/react-native-audio-api/src/{ => mobile}/events/types.ts (97%) rename packages/react-native-audio-api/src/{hooks/useSytemVolume.ts => mobile/hooks/useSystemVolume.ts} (100%) rename packages/react-native-audio-api/src/{core => mobile/inputs}/AudioRecorder.ts (91%) create mode 100644 packages/react-native-audio-api/src/mobile/inputs/index.ts rename packages/react-native-audio-api/src/{ => mobile}/interfaces.ts (99%) rename packages/react-native-audio-api/src/{core => mobile/sources}/AudioBuffer.ts (97%) rename packages/react-native-audio-api/src/{core => mobile/sources}/AudioBufferBaseSourceNode.ts (94%) rename packages/react-native-audio-api/src/{core => mobile/sources}/AudioBufferQueueSourceNode.ts (96%) rename packages/react-native-audio-api/src/{core => mobile/sources}/AudioBufferSourceNode.ts (97%) rename packages/react-native-audio-api/src/{core => mobile/sources}/AudioScheduledSourceNode.ts (94%) rename packages/react-native-audio-api/src/{core => mobile/sources}/OscillatorNode.ts (80%) rename packages/react-native-audio-api/src/{ => mobile}/system/AudioManager.ts (97%) rename packages/react-native-audio-api/src/{ => mobile}/system/index.ts (100%) rename packages/react-native-audio-api/src/{ => mobile}/system/types.ts (100%) rename packages/react-native-audio-api/src/{web-core => web/analysis}/AnalyserNode.tsx (90%) rename packages/react-native-audio-api/src/{web-core => web/core}/AudioContext.tsx (89%) rename packages/react-native-audio-api/src/{web-core => web/core}/AudioNode.tsx (92%) rename packages/react-native-audio-api/src/{web-core => web/core}/AudioParam.tsx (98%) rename packages/react-native-audio-api/src/{web-core => web/core}/BaseAudioContext.tsx (84%) rename packages/react-native-audio-api/src/{web-core => web/core}/OfflineAudioContext.tsx (93%) rename packages/react-native-audio-api/src/{web-core => web}/custom/LoadCustomWasm.ts (100%) rename packages/react-native-audio-api/src/{web-core => web}/custom/index.ts (100%) rename packages/react-native-audio-api/src/{web-core => web}/custom/signalsmithStretch/LICENSE.txt (100%) rename packages/react-native-audio-api/src/{web-core => web}/custom/signalsmithStretch/README.md (100%) rename packages/react-native-audio-api/src/{web-core => web}/custom/signalsmithStretch/SignalsmithStretch.mjs (100%) rename packages/react-native-audio-api/src/{web-core => web/destinations}/AudioDestinationNode.tsx (59%) rename packages/react-native-audio-api/src/{web-core => web/effects}/BiquadFilterNode.tsx (85%) rename packages/react-native-audio-api/src/{web-core => web/effects}/GainNode.tsx (61%) rename packages/react-native-audio-api/src/{web-core => web/effects}/PeriodicWave.tsx (100%) rename packages/react-native-audio-api/src/{web-core => web/effects}/StereoPannerNode.tsx (62%) rename packages/react-native-audio-api/src/{web-core => web/sources}/AudioBuffer.tsx (97%) rename packages/react-native-audio-api/src/{web-core => web/sources}/AudioBufferSourceNode.tsx (97%) rename packages/react-native-audio-api/src/{web-core => web/sources}/AudioScheduledSourceNode.tsx (82%) rename packages/react-native-audio-api/src/{web-core => web/sources}/OscillatorNode.tsx (79%) diff --git a/packages/react-native-audio-api/src/api.ts b/packages/react-native-audio-api/src/api.ts index 5f59581c6..2b3376725 100644 --- a/packages/react-native-audio-api/src/api.ts +++ b/packages/react-native-audio-api/src/api.ts @@ -5,7 +5,7 @@ import type { IAudioRecorder, IOfflineAudioContext, IAudioEventEmitter, -} from './interfaces'; +} from './mobile/interfaces'; /* eslint-disable no-var */ declare global { @@ -40,25 +40,25 @@ if ( NativeAudioAPIModule.install(); } -export { default as AudioBuffer } from './core/AudioBuffer'; -export { default as AudioBufferSourceNode } from './core/AudioBufferSourceNode'; -export { default as AudioBufferQueueSourceNode } from './core/AudioBufferQueueSourceNode'; -export { default as AudioContext } from './core/AudioContext'; -export { default as OfflineAudioContext } from './core/OfflineAudioContext'; -export { default as AudioDestinationNode } from './core/AudioDestinationNode'; -export { default as AudioNode } from './core/AudioNode'; -export { default as AnalyserNode } from './core/AnalyserNode'; -export { default as AudioParam } from './core/AudioParam'; -export { default as AudioScheduledSourceNode } from './core/AudioScheduledSourceNode'; -export { default as BaseAudioContext } from './core/BaseAudioContext'; -export { default as BiquadFilterNode } from './core/BiquadFilterNode'; -export { default as CustomProcessorNode } from './core/CustomProcessorNode'; -export { default as GainNode } from './core/GainNode'; -export { default as OscillatorNode } from './core/OscillatorNode'; -export { default as StereoPannerNode } from './core/StereoPannerNode'; -export { default as AudioRecorder } from './core/AudioRecorder'; -export { default as AudioManager } from './system'; -export { default as useSystemVolume } from './hooks/useSytemVolume'; +export { default as AudioBuffer } from './mobile/sources/AudioBuffer'; +export { default as AudioBufferSourceNode } from './mobile/sources/AudioBufferSourceNode'; +export { default as AudioBufferQueueSourceNode } from './mobile/sources/AudioBufferQueueSourceNode'; +export { default as AudioContext } from './mobile/core/AudioContext'; +export { default as OfflineAudioContext } from './mobile/core/OfflineAudioContext'; +export { default as AudioDestinationNode } from './mobile/destinations/AudioDestinationNode'; +export { default as AudioNode } from './mobile/core/AudioNode'; +export { default as AnalyserNode } from './mobile/analysis/AnalyserNode'; +export { default as AudioParam } from './mobile/core/AudioParam'; +export { default as AudioScheduledSourceNode } from './mobile/sources/AudioScheduledSourceNode'; +export { default as BaseAudioContext } from './mobile/core/BaseAudioContext'; +export { default as BiquadFilterNode } from './mobile/effects/BiquadFilterNode'; +export { default as CustomProcessorNode } from './mobile/effects/CustomProcessorNode'; +export { default as GainNode } from './mobile/effects/GainNode'; +export { default as OscillatorNode } from './mobile/sources/OscillatorNode'; +export { default as StereoPannerNode } from './mobile/effects/StereoPannerNode'; +export { default as AudioRecorder } from './mobile/inputs/AudioRecorder'; +export { default as AudioManager } from './mobile/system'; +export { default as useSystemVolume } from './mobile/hooks/useSystemVolume'; export { OscillatorType, diff --git a/packages/react-native-audio-api/src/api.web.ts b/packages/react-native-audio-api/src/api.web.ts index e47ce28ba..5047677c2 100644 --- a/packages/react-native-audio-api/src/api.web.ts +++ b/packages/react-native-audio-api/src/api.web.ts @@ -1,19 +1,19 @@ -export { default as AudioBuffer } from './web-core/AudioBuffer'; -export { default as AudioBufferSourceNode } from './web-core/AudioBufferSourceNode'; -export { default as AudioContext } from './web-core/AudioContext'; -export { default as OfflineAudioContext } from './web-core/OfflineAudioContext'; -export { default as AudioDestinationNode } from './web-core/AudioDestinationNode'; -export { default as AudioNode } from './web-core/AudioNode'; -export { default as AnalyserNode } from './web-core/AnalyserNode'; -export { default as AudioParam } from './web-core/AudioParam'; -export { default as AudioScheduledSourceNode } from './web-core/AudioScheduledSourceNode'; -export { default as BaseAudioContext } from './web-core/BaseAudioContext'; -export { default as BiquadFilterNode } from './web-core/BiquadFilterNode'; -export { default as GainNode } from './web-core/GainNode'; -export { default as OscillatorNode } from './web-core/OscillatorNode'; -export { default as StereoPannerNode } from './web-core/StereoPannerNode'; +export { default as AudioBuffer } from './web/sources/AudioBuffer'; +export { default as AudioBufferSourceNode } from './web/sources/AudioBufferSourceNode'; +export { default as AudioContext } from './web/core/AudioContext'; +export { default as OfflineAudioContext } from './web/core/OfflineAudioContext'; +export { default as AudioDestinationNode } from './web/destinations/AudioDestinationNode'; +export { default as AudioNode } from './web/core/AudioNode'; +export { default as AnalyserNode } from './web/analysis/AnalyserNode'; +export { default as AudioParam } from './web/core/AudioParam'; +export { default as AudioScheduledSourceNode } from './web/sources/AudioScheduledSourceNode'; +export { default as BaseAudioContext } from './web/core/BaseAudioContext'; +export { default as BiquadFilterNode } from './web/effects/BiquadFilterNode'; +export { default as GainNode } from './web/effects/GainNode'; +export { default as OscillatorNode } from './web/sources/OscillatorNode'; +export { default as StereoPannerNode } from './web/effects/StereoPannerNode'; -export * from './web-core/custom'; +export * from './web/custom'; export { OscillatorType, diff --git a/packages/react-native-audio-api/src/core/AnalyserNode.ts b/packages/react-native-audio-api/src/mobile/analysis/AnalyserNode.ts similarity index 94% rename from packages/react-native-audio-api/src/core/AnalyserNode.ts rename to packages/react-native-audio-api/src/mobile/analysis/AnalyserNode.ts index d2d8176e1..e8ba1e62d 100644 --- a/packages/react-native-audio-api/src/core/AnalyserNode.ts +++ b/packages/react-native-audio-api/src/mobile/analysis/AnalyserNode.ts @@ -1,7 +1,7 @@ -import { IndexSizeError } from '../errors'; +import { IndexSizeError } from '../../errors'; import { IAnalyserNode } from '../interfaces'; -import { WindowType } from '../types'; -import AudioNode from './AudioNode'; +import { WindowType } from '../../types'; +import AudioNode from '../core/AudioNode'; export default class AnalyserNode extends AudioNode { private static allowedFFTSize: number[] = [ diff --git a/packages/react-native-audio-api/src/core/AudioContext.ts b/packages/react-native-audio-api/src/mobile/core/AudioContext.ts similarity index 90% rename from packages/react-native-audio-api/src/core/AudioContext.ts rename to packages/react-native-audio-api/src/mobile/core/AudioContext.ts index 957557848..dbaa73319 100644 --- a/packages/react-native-audio-api/src/core/AudioContext.ts +++ b/packages/react-native-audio-api/src/mobile/core/AudioContext.ts @@ -1,8 +1,8 @@ import { IAudioContext } from '../interfaces'; import BaseAudioContext from './BaseAudioContext'; import AudioManager from '../system'; -import { AudioContextOptions } from '../types'; -import { NotSupportedError } from '../errors'; +import { AudioContextOptions } from '../../types'; +import { NotSupportedError } from '../../errors'; export default class AudioContext extends BaseAudioContext { constructor(options?: AudioContextOptions) { diff --git a/packages/react-native-audio-api/src/core/AudioNode.ts b/packages/react-native-audio-api/src/mobile/core/AudioNode.ts similarity index 92% rename from packages/react-native-audio-api/src/core/AudioNode.ts rename to packages/react-native-audio-api/src/mobile/core/AudioNode.ts index 26bc5a352..7d5fc704a 100644 --- a/packages/react-native-audio-api/src/core/AudioNode.ts +++ b/packages/react-native-audio-api/src/mobile/core/AudioNode.ts @@ -1,8 +1,8 @@ import { IAudioNode } from '../interfaces'; import AudioParam from './AudioParam'; -import { ChannelCountMode, ChannelInterpretation } from '../types'; +import { ChannelCountMode, ChannelInterpretation } from '../../types'; import BaseAudioContext from './BaseAudioContext'; -import { InvalidAccessError } from '../errors'; +import { InvalidAccessError } from '../../errors'; export default class AudioNode { readonly context: BaseAudioContext; diff --git a/packages/react-native-audio-api/src/core/AudioParam.ts b/packages/react-native-audio-api/src/mobile/core/AudioParam.ts similarity index 98% rename from packages/react-native-audio-api/src/core/AudioParam.ts rename to packages/react-native-audio-api/src/mobile/core/AudioParam.ts index d8cfb5fed..79af75b3e 100644 --- a/packages/react-native-audio-api/src/core/AudioParam.ts +++ b/packages/react-native-audio-api/src/mobile/core/AudioParam.ts @@ -1,5 +1,5 @@ import { IAudioParam } from '../interfaces'; -import { RangeError, InvalidStateError } from '../errors'; +import { RangeError, InvalidStateError } from '../../errors'; import BaseAudioContext from './BaseAudioContext'; export default class AudioParam { diff --git a/packages/react-native-audio-api/src/core/BaseAudioContext.ts b/packages/react-native-audio-api/src/mobile/core/BaseAudioContext.ts similarity index 83% rename from packages/react-native-audio-api/src/core/BaseAudioContext.ts rename to packages/react-native-audio-api/src/mobile/core/BaseAudioContext.ts index ffcefaa69..dc6dcaca1 100644 --- a/packages/react-native-audio-api/src/core/BaseAudioContext.ts +++ b/packages/react-native-audio-api/src/mobile/core/BaseAudioContext.ts @@ -3,19 +3,19 @@ import { ContextState, PeriodicWaveConstraints, AudioBufferSourceNodeOptions, -} from '../types'; -import AudioDestinationNode from './AudioDestinationNode'; -import OscillatorNode from './OscillatorNode'; -import CustomProcessorNode from './CustomProcessorNode'; -import GainNode from './GainNode'; -import StereoPannerNode from './StereoPannerNode'; -import BiquadFilterNode from './BiquadFilterNode'; -import AudioBufferSourceNode from './AudioBufferSourceNode'; -import AudioBuffer from './AudioBuffer'; -import PeriodicWave from './PeriodicWave'; -import AnalyserNode from './AnalyserNode'; -import AudioBufferQueueSourceNode from './AudioBufferQueueSourceNode'; -import { InvalidAccessError, NotSupportedError } from '../errors'; +} from '../../types'; +import AudioDestinationNode from '../destinations/AudioDestinationNode'; +import OscillatorNode from '../sources/OscillatorNode'; +import CustomProcessorNode from '../effects/CustomProcessorNode'; +import GainNode from '../effects/GainNode'; +import StereoPannerNode from '../effects/StereoPannerNode'; +import BiquadFilterNode from '../effects/BiquadFilterNode'; +import AudioBufferSourceNode from '../sources/AudioBufferSourceNode'; +import AudioBuffer from '../sources/AudioBuffer'; +import PeriodicWave from '../effects/PeriodicWave'; +import AnalyserNode from '../analysis/AnalyserNode'; +import AudioBufferQueueSourceNode from '../sources/AudioBufferQueueSourceNode'; +import { InvalidAccessError, NotSupportedError } from '../../errors'; export default class BaseAudioContext { readonly destination: AudioDestinationNode; diff --git a/packages/react-native-audio-api/src/core/OfflineAudioContext.ts b/packages/react-native-audio-api/src/mobile/core/OfflineAudioContext.ts similarity index 93% rename from packages/react-native-audio-api/src/core/OfflineAudioContext.ts rename to packages/react-native-audio-api/src/mobile/core/OfflineAudioContext.ts index 837148d27..6ed506a43 100644 --- a/packages/react-native-audio-api/src/core/OfflineAudioContext.ts +++ b/packages/react-native-audio-api/src/mobile/core/OfflineAudioContext.ts @@ -1,8 +1,8 @@ import { IOfflineAudioContext } from '../interfaces'; import BaseAudioContext from './BaseAudioContext'; -import { OfflineAudioContextOptions } from '../types'; -import { InvalidStateError, NotSupportedError } from '../errors'; -import AudioBuffer from './AudioBuffer'; +import { OfflineAudioContextOptions } from '../../types'; +import { InvalidStateError, NotSupportedError } from '../../errors'; +import AudioBuffer from '../sources/AudioBuffer'; export default class OfflineAudioContext extends BaseAudioContext { private isSuspended: boolean; diff --git a/packages/react-native-audio-api/src/core/AudioDestinationNode.ts b/packages/react-native-audio-api/src/mobile/destinations/AudioDestinationNode.ts similarity index 59% rename from packages/react-native-audio-api/src/core/AudioDestinationNode.ts rename to packages/react-native-audio-api/src/mobile/destinations/AudioDestinationNode.ts index f1d850e90..ed658d83d 100644 --- a/packages/react-native-audio-api/src/core/AudioDestinationNode.ts +++ b/packages/react-native-audio-api/src/mobile/destinations/AudioDestinationNode.ts @@ -1,3 +1,3 @@ -import AudioNode from './AudioNode'; +import AudioNode from '../core/AudioNode'; export default class AudioDestinationNode extends AudioNode {} diff --git a/packages/react-native-audio-api/src/core/BiquadFilterNode.ts b/packages/react-native-audio-api/src/mobile/effects/BiquadFilterNode.ts similarity index 85% rename from packages/react-native-audio-api/src/core/BiquadFilterNode.ts rename to packages/react-native-audio-api/src/mobile/effects/BiquadFilterNode.ts index 68db7c02a..1563cdc6b 100644 --- a/packages/react-native-audio-api/src/core/BiquadFilterNode.ts +++ b/packages/react-native-audio-api/src/mobile/effects/BiquadFilterNode.ts @@ -1,9 +1,9 @@ -import { InvalidAccessError } from '../errors'; +import { InvalidAccessError } from '../../errors'; import { IBiquadFilterNode } from '../interfaces'; -import AudioNode from './AudioNode'; -import AudioParam from './AudioParam'; -import BaseAudioContext from './BaseAudioContext'; -import { BiquadFilterType } from '../types'; +import AudioNode from '../core/AudioNode'; +import AudioParam from '../core/AudioParam'; +import BaseAudioContext from '../core/BaseAudioContext'; +import { BiquadFilterType } from '../../types'; export default class BiquadFilterNode extends AudioNode { readonly frequency: AudioParam; diff --git a/packages/react-native-audio-api/src/core/CustomProcessorNode.ts b/packages/react-native-audio-api/src/mobile/effects/CustomProcessorNode.ts similarity index 76% rename from packages/react-native-audio-api/src/core/CustomProcessorNode.ts rename to packages/react-native-audio-api/src/mobile/effects/CustomProcessorNode.ts index bd1cbaeac..fad743d94 100644 --- a/packages/react-native-audio-api/src/core/CustomProcessorNode.ts +++ b/packages/react-native-audio-api/src/mobile/effects/CustomProcessorNode.ts @@ -1,8 +1,8 @@ import { ICustomProcessorNode } from '../interfaces'; -import { ProcessorMode } from '../types'; -import AudioNode from './AudioNode'; -import AudioParam from './AudioParam'; -import BaseAudioContext from './BaseAudioContext'; +import { ProcessorMode } from '../../types'; +import AudioNode from '../core/AudioNode'; +import AudioParam from '../core/AudioParam'; +import BaseAudioContext from '../core/BaseAudioContext'; export default class CustomProcessorNode extends AudioNode { readonly customProcessor: AudioParam; diff --git a/packages/react-native-audio-api/src/core/GainNode.ts b/packages/react-native-audio-api/src/mobile/effects/GainNode.ts similarity index 64% rename from packages/react-native-audio-api/src/core/GainNode.ts rename to packages/react-native-audio-api/src/mobile/effects/GainNode.ts index a216f1365..7900cadcc 100644 --- a/packages/react-native-audio-api/src/core/GainNode.ts +++ b/packages/react-native-audio-api/src/mobile/effects/GainNode.ts @@ -1,7 +1,7 @@ import { IGainNode } from '../interfaces'; -import AudioNode from './AudioNode'; -import AudioParam from './AudioParam'; -import BaseAudioContext from './BaseAudioContext'; +import AudioNode from '../core/AudioNode'; +import AudioParam from '../core/AudioParam'; +import BaseAudioContext from '../core/BaseAudioContext'; export default class GainNode extends AudioNode { readonly gain: AudioParam; diff --git a/packages/react-native-audio-api/src/core/PeriodicWave.ts b/packages/react-native-audio-api/src/mobile/effects/PeriodicWave.ts similarity index 100% rename from packages/react-native-audio-api/src/core/PeriodicWave.ts rename to packages/react-native-audio-api/src/mobile/effects/PeriodicWave.ts diff --git a/packages/react-native-audio-api/src/core/StereoPannerNode.ts b/packages/react-native-audio-api/src/mobile/effects/StereoPannerNode.ts similarity index 66% rename from packages/react-native-audio-api/src/core/StereoPannerNode.ts rename to packages/react-native-audio-api/src/mobile/effects/StereoPannerNode.ts index a8fa77006..c3ef409c1 100644 --- a/packages/react-native-audio-api/src/core/StereoPannerNode.ts +++ b/packages/react-native-audio-api/src/mobile/effects/StereoPannerNode.ts @@ -1,7 +1,7 @@ import { IStereoPannerNode } from '../interfaces'; -import AudioNode from './AudioNode'; -import AudioParam from './AudioParam'; -import BaseAudioContext from './BaseAudioContext'; +import AudioNode from '../core/AudioNode'; +import AudioParam from '../core/AudioParam'; +import BaseAudioContext from '../core/BaseAudioContext'; export default class StereoPannerNode extends AudioNode { readonly pan: AudioParam; diff --git a/packages/react-native-audio-api/src/events/AudioEventEmitter.ts b/packages/react-native-audio-api/src/mobile/events/AudioEventEmitter.ts similarity index 100% rename from packages/react-native-audio-api/src/events/AudioEventEmitter.ts rename to packages/react-native-audio-api/src/mobile/events/AudioEventEmitter.ts diff --git a/packages/react-native-audio-api/src/events/AudioEventSubscription.ts b/packages/react-native-audio-api/src/mobile/events/AudioEventSubscription.ts similarity index 92% rename from packages/react-native-audio-api/src/events/AudioEventSubscription.ts rename to packages/react-native-audio-api/src/mobile/events/AudioEventSubscription.ts index 8b82850b0..214ddef7b 100644 --- a/packages/react-native-audio-api/src/events/AudioEventSubscription.ts +++ b/packages/react-native-audio-api/src/mobile/events/AudioEventSubscription.ts @@ -1,5 +1,5 @@ import { AudioEventName } from './types'; -import { AudioEventEmitter } from './'; +import AudioEventEmitter from './AudioEventEmitter'; export default class AudioEventSubscription { private readonly audioEventEmitter: AudioEventEmitter; diff --git a/packages/react-native-audio-api/src/events/index.ts b/packages/react-native-audio-api/src/mobile/events/index.ts similarity index 100% rename from packages/react-native-audio-api/src/events/index.ts rename to packages/react-native-audio-api/src/mobile/events/index.ts diff --git a/packages/react-native-audio-api/src/events/types.ts b/packages/react-native-audio-api/src/mobile/events/types.ts similarity index 97% rename from packages/react-native-audio-api/src/events/types.ts rename to packages/react-native-audio-api/src/mobile/events/types.ts index 059a605d8..66b3fa4f1 100644 --- a/packages/react-native-audio-api/src/events/types.ts +++ b/packages/react-native-audio-api/src/mobile/events/types.ts @@ -1,4 +1,4 @@ -import AudioBuffer from '../core/AudioBuffer'; +import AudioBuffer from '../sources/AudioBuffer'; export interface EventEmptyType {} diff --git a/packages/react-native-audio-api/src/hooks/useSytemVolume.ts b/packages/react-native-audio-api/src/mobile/hooks/useSystemVolume.ts similarity index 100% rename from packages/react-native-audio-api/src/hooks/useSytemVolume.ts rename to packages/react-native-audio-api/src/mobile/hooks/useSystemVolume.ts diff --git a/packages/react-native-audio-api/src/core/AudioRecorder.ts b/packages/react-native-audio-api/src/mobile/inputs/AudioRecorder.ts similarity index 91% rename from packages/react-native-audio-api/src/core/AudioRecorder.ts rename to packages/react-native-audio-api/src/mobile/inputs/AudioRecorder.ts index 0d0adea95..b716ea26c 100644 --- a/packages/react-native-audio-api/src/core/AudioRecorder.ts +++ b/packages/react-native-audio-api/src/mobile/inputs/AudioRecorder.ts @@ -1,6 +1,6 @@ import { IAudioRecorder } from '../interfaces'; -import { AudioRecorderOptions } from '../types'; -import AudioBuffer from './AudioBuffer'; +import { AudioRecorderOptions } from '../../types'; +import AudioBuffer from '../sources/AudioBuffer'; import { OnAudioReadyEventType } from '../events/types'; import { AudioEventEmitter } from '../events'; diff --git a/packages/react-native-audio-api/src/mobile/inputs/index.ts b/packages/react-native-audio-api/src/mobile/inputs/index.ts new file mode 100644 index 000000000..af026ef1a --- /dev/null +++ b/packages/react-native-audio-api/src/mobile/inputs/index.ts @@ -0,0 +1 @@ +export { default } from './AudioRecorder'; diff --git a/packages/react-native-audio-api/src/interfaces.ts b/packages/react-native-audio-api/src/mobile/interfaces.ts similarity index 99% rename from packages/react-native-audio-api/src/interfaces.ts rename to packages/react-native-audio-api/src/mobile/interfaces.ts index 859f71d03..3e7416703 100644 --- a/packages/react-native-audio-api/src/interfaces.ts +++ b/packages/react-native-audio-api/src/mobile/interfaces.ts @@ -6,7 +6,7 @@ import { ChannelCountMode, ChannelInterpretation, ProcessorMode, -} from './types'; +} from '../types'; import { AudioEventName, AudioEventCallback } from './events/types'; export interface IBaseAudioContext { diff --git a/packages/react-native-audio-api/src/core/AudioBuffer.ts b/packages/react-native-audio-api/src/mobile/sources/AudioBuffer.ts similarity index 97% rename from packages/react-native-audio-api/src/core/AudioBuffer.ts rename to packages/react-native-audio-api/src/mobile/sources/AudioBuffer.ts index 671e48d9d..f695dd6ac 100644 --- a/packages/react-native-audio-api/src/core/AudioBuffer.ts +++ b/packages/react-native-audio-api/src/mobile/sources/AudioBuffer.ts @@ -1,5 +1,5 @@ import { IAudioBuffer } from '../interfaces'; -import { IndexSizeError } from '../errors'; +import { IndexSizeError } from '../../errors'; export default class AudioBuffer { readonly length: number; diff --git a/packages/react-native-audio-api/src/core/AudioBufferBaseSourceNode.ts b/packages/react-native-audio-api/src/mobile/sources/AudioBufferBaseSourceNode.ts similarity index 94% rename from packages/react-native-audio-api/src/core/AudioBufferBaseSourceNode.ts rename to packages/react-native-audio-api/src/mobile/sources/AudioBufferBaseSourceNode.ts index 28a409a75..ec2117930 100644 --- a/packages/react-native-audio-api/src/core/AudioBufferBaseSourceNode.ts +++ b/packages/react-native-audio-api/src/mobile/sources/AudioBufferBaseSourceNode.ts @@ -1,5 +1,5 @@ -import AudioParam from './AudioParam'; -import BaseAudioContext from './BaseAudioContext'; +import AudioParam from '../core/AudioParam'; +import BaseAudioContext from '../core/BaseAudioContext'; import { AudioEventSubscription } from '../events'; import { EventTypeWithValue } from '../events/types'; import { IAudioBufferBaseSourceNode } from '../interfaces'; diff --git a/packages/react-native-audio-api/src/core/AudioBufferQueueSourceNode.ts b/packages/react-native-audio-api/src/mobile/sources/AudioBufferQueueSourceNode.ts similarity index 96% rename from packages/react-native-audio-api/src/core/AudioBufferQueueSourceNode.ts rename to packages/react-native-audio-api/src/mobile/sources/AudioBufferQueueSourceNode.ts index 7a6c87de1..5fc57a8fd 100644 --- a/packages/react-native-audio-api/src/core/AudioBufferQueueSourceNode.ts +++ b/packages/react-native-audio-api/src/mobile/sources/AudioBufferQueueSourceNode.ts @@ -1,7 +1,7 @@ import { IAudioBufferQueueSourceNode } from '../interfaces'; import AudioBufferBaseSourceNode from './AudioBufferBaseSourceNode'; import AudioBuffer from './AudioBuffer'; -import { RangeError } from '../errors'; +import { RangeError } from '../../errors'; export default class AudioBufferQueueSourceNode extends AudioBufferBaseSourceNode { public enqueueBuffer( diff --git a/packages/react-native-audio-api/src/core/AudioBufferSourceNode.ts b/packages/react-native-audio-api/src/mobile/sources/AudioBufferSourceNode.ts similarity index 97% rename from packages/react-native-audio-api/src/core/AudioBufferSourceNode.ts rename to packages/react-native-audio-api/src/mobile/sources/AudioBufferSourceNode.ts index d5d4aedbc..d86aecfc2 100644 --- a/packages/react-native-audio-api/src/core/AudioBufferSourceNode.ts +++ b/packages/react-native-audio-api/src/mobile/sources/AudioBufferSourceNode.ts @@ -1,7 +1,7 @@ import { IAudioBufferSourceNode } from '../interfaces'; import AudioBufferBaseSourceNode from './AudioBufferBaseSourceNode'; import AudioBuffer from './AudioBuffer'; -import { InvalidStateError, RangeError } from '../errors'; +import { InvalidStateError, RangeError } from '../../errors'; export default class AudioBufferSourceNode extends AudioBufferBaseSourceNode { public get buffer(): AudioBuffer | null { diff --git a/packages/react-native-audio-api/src/core/AudioScheduledSourceNode.ts b/packages/react-native-audio-api/src/mobile/sources/AudioScheduledSourceNode.ts similarity index 94% rename from packages/react-native-audio-api/src/core/AudioScheduledSourceNode.ts rename to packages/react-native-audio-api/src/mobile/sources/AudioScheduledSourceNode.ts index 8e3f5b29c..4a9c5326e 100644 --- a/packages/react-native-audio-api/src/core/AudioScheduledSourceNode.ts +++ b/packages/react-native-audio-api/src/mobile/sources/AudioScheduledSourceNode.ts @@ -1,6 +1,6 @@ import { IAudioScheduledSourceNode } from '../interfaces'; -import AudioNode from './AudioNode'; -import { InvalidStateError, RangeError } from '../errors'; +import AudioNode from '../core/AudioNode'; +import { InvalidStateError, RangeError } from '../../errors'; import { EventEmptyType } from '../events/types'; import { AudioEventEmitter, AudioEventSubscription } from '../events'; diff --git a/packages/react-native-audio-api/src/core/OscillatorNode.ts b/packages/react-native-audio-api/src/mobile/sources/OscillatorNode.ts similarity index 80% rename from packages/react-native-audio-api/src/core/OscillatorNode.ts rename to packages/react-native-audio-api/src/mobile/sources/OscillatorNode.ts index 40248071e..85b71ea51 100644 --- a/packages/react-native-audio-api/src/core/OscillatorNode.ts +++ b/packages/react-native-audio-api/src/mobile/sources/OscillatorNode.ts @@ -1,10 +1,10 @@ import { IOscillatorNode } from '../interfaces'; -import { OscillatorType } from '../types'; +import { OscillatorType } from '../../types'; import AudioScheduledSourceNode from './AudioScheduledSourceNode'; -import AudioParam from './AudioParam'; -import BaseAudioContext from './BaseAudioContext'; -import PeriodicWave from './PeriodicWave'; -import { InvalidStateError } from '../errors'; +import AudioParam from '../core/AudioParam'; +import BaseAudioContext from '../core/BaseAudioContext'; +import PeriodicWave from '../effects/PeriodicWave'; +import { InvalidStateError } from '../../errors'; export default class OscillatorNode extends AudioScheduledSourceNode { readonly frequency: AudioParam; diff --git a/packages/react-native-audio-api/src/system/AudioManager.ts b/packages/react-native-audio-api/src/mobile/system/AudioManager.ts similarity index 97% rename from packages/react-native-audio-api/src/system/AudioManager.ts rename to packages/react-native-audio-api/src/mobile/system/AudioManager.ts index 8c0f4760d..cae872ce5 100644 --- a/packages/react-native-audio-api/src/system/AudioManager.ts +++ b/packages/react-native-audio-api/src/mobile/system/AudioManager.ts @@ -9,7 +9,7 @@ import { SystemEventCallback, RemoteCommandEventName, } from '../events/types'; -import { NativeAudioAPIModule } from '../specs'; +import { NativeAudioAPIModule } from '../../specs'; import { AudioEventEmitter, AudioEventSubscription } from '../events'; if (global.AudioEventEmitter == null) { diff --git a/packages/react-native-audio-api/src/system/index.ts b/packages/react-native-audio-api/src/mobile/system/index.ts similarity index 100% rename from packages/react-native-audio-api/src/system/index.ts rename to packages/react-native-audio-api/src/mobile/system/index.ts diff --git a/packages/react-native-audio-api/src/system/types.ts b/packages/react-native-audio-api/src/mobile/system/types.ts similarity index 100% rename from packages/react-native-audio-api/src/system/types.ts rename to packages/react-native-audio-api/src/mobile/system/types.ts diff --git a/packages/react-native-audio-api/src/specs/NativeAudioAPIModule.ts b/packages/react-native-audio-api/src/specs/NativeAudioAPIModule.ts index ca403c469..10aacd958 100644 --- a/packages/react-native-audio-api/src/specs/NativeAudioAPIModule.ts +++ b/packages/react-native-audio-api/src/specs/NativeAudioAPIModule.ts @@ -1,7 +1,7 @@ 'use strict'; import { TurboModuleRegistry } from 'react-native'; import type { TurboModule } from 'react-native'; -import { PermissionStatus, AudioDevicesInfo } from '../system/types'; +import { PermissionStatus, AudioDevicesInfo } from '../mobile/system/types'; interface Spec extends TurboModule { install(): boolean; diff --git a/packages/react-native-audio-api/src/web-core/AnalyserNode.tsx b/packages/react-native-audio-api/src/web/analysis/AnalyserNode.tsx similarity index 90% rename from packages/react-native-audio-api/src/web-core/AnalyserNode.tsx rename to packages/react-native-audio-api/src/web/analysis/AnalyserNode.tsx index c74b67e05..cc6fd1319 100644 --- a/packages/react-native-audio-api/src/web-core/AnalyserNode.tsx +++ b/packages/react-native-audio-api/src/web/analysis/AnalyserNode.tsx @@ -1,6 +1,6 @@ -import AudioNode from './AudioNode'; -import { WindowType } from '../types'; -import BaseAudioContext from './BaseAudioContext'; +import AudioNode from '../core/AudioNode'; +import BaseAudioContext from '../core/BaseAudioContext'; +import { WindowType } from '../../types'; export default class AnalyserNode extends AudioNode { fftSize: number; diff --git a/packages/react-native-audio-api/src/web-core/AudioContext.tsx b/packages/react-native-audio-api/src/web/core/AudioContext.tsx similarity index 89% rename from packages/react-native-audio-api/src/web-core/AudioContext.tsx rename to packages/react-native-audio-api/src/web/core/AudioContext.tsx index 0a5e20fcd..063258c40 100644 --- a/packages/react-native-audio-api/src/web-core/AudioContext.tsx +++ b/packages/react-native-audio-api/src/web/core/AudioContext.tsx @@ -1,5 +1,5 @@ -import { AudioContextOptions } from '../types'; -import { NotSupportedError } from '../errors'; +import { AudioContextOptions } from '../../types'; +import { NotSupportedError } from '../../errors'; import BaseAudioContext from './BaseAudioContext'; export default class AudioContext extends BaseAudioContext { diff --git a/packages/react-native-audio-api/src/web-core/AudioNode.tsx b/packages/react-native-audio-api/src/web/core/AudioNode.tsx similarity index 92% rename from packages/react-native-audio-api/src/web-core/AudioNode.tsx rename to packages/react-native-audio-api/src/web/core/AudioNode.tsx index e6c1b7f17..2921ceddf 100644 --- a/packages/react-native-audio-api/src/web-core/AudioNode.tsx +++ b/packages/react-native-audio-api/src/web/core/AudioNode.tsx @@ -1,7 +1,7 @@ import BaseAudioContext from './BaseAudioContext'; -import { ChannelCountMode, ChannelInterpretation } from '../types'; +import { ChannelCountMode, ChannelInterpretation } from '../../types'; import AudioParam from './AudioParam'; -import { InvalidAccessError } from '../errors'; +import { InvalidAccessError } from '../../errors'; export default class AudioNode { readonly context: BaseAudioContext; diff --git a/packages/react-native-audio-api/src/web-core/AudioParam.tsx b/packages/react-native-audio-api/src/web/core/AudioParam.tsx similarity index 98% rename from packages/react-native-audio-api/src/web-core/AudioParam.tsx rename to packages/react-native-audio-api/src/web/core/AudioParam.tsx index d85cface1..e8ce67ef4 100644 --- a/packages/react-native-audio-api/src/web-core/AudioParam.tsx +++ b/packages/react-native-audio-api/src/web/core/AudioParam.tsx @@ -1,4 +1,4 @@ -import { RangeError, InvalidStateError } from '../errors'; +import { RangeError, InvalidStateError } from '../../errors'; import BaseAudioContext from './BaseAudioContext'; export default class AudioParam { diff --git a/packages/react-native-audio-api/src/web-core/BaseAudioContext.tsx b/packages/react-native-audio-api/src/web/core/BaseAudioContext.tsx similarity index 84% rename from packages/react-native-audio-api/src/web-core/BaseAudioContext.tsx rename to packages/react-native-audio-api/src/web/core/BaseAudioContext.tsx index cb0cbb192..e87e056cb 100644 --- a/packages/react-native-audio-api/src/web-core/BaseAudioContext.tsx +++ b/packages/react-native-audio-api/src/web/core/BaseAudioContext.tsx @@ -2,19 +2,19 @@ import { ContextState, PeriodicWaveConstraints, AudioBufferSourceNodeOptions, -} from '../types'; -import { InvalidAccessError, NotSupportedError } from '../errors'; -import AnalyserNode from './AnalyserNode'; -import AudioDestinationNode from './AudioDestinationNode'; -import AudioBuffer from './AudioBuffer'; -import AudioBufferSourceNode from './AudioBufferSourceNode'; -import BiquadFilterNode from './BiquadFilterNode'; -import GainNode from './GainNode'; -import OscillatorNode from './OscillatorNode'; -import PeriodicWave from './PeriodicWave'; -import StereoPannerNode from './StereoPannerNode'; - -import { globalWasmPromise, globalTag } from './custom/LoadCustomWasm'; +} from '../../types'; +import AudioDestinationNode from '../destinations/AudioDestinationNode'; +import OscillatorNode from '../sources/OscillatorNode'; +import GainNode from '../effects/GainNode'; +import StereoPannerNode from '../effects/StereoPannerNode'; +import BiquadFilterNode from '../effects/BiquadFilterNode'; +import AudioBufferSourceNode from '../sources/AudioBufferSourceNode'; +import AudioBuffer from '../sources/AudioBuffer'; +import PeriodicWave from '../effects/PeriodicWave'; +import AnalyserNode from '../analysis/AnalyserNode'; +import { InvalidAccessError, NotSupportedError } from '../../errors'; + +import { globalWasmPromise, globalTag } from '../custom/LoadCustomWasm'; export default class BaseAudioContext { protected readonly context: globalThis.BaseAudioContext; diff --git a/packages/react-native-audio-api/src/web-core/OfflineAudioContext.tsx b/packages/react-native-audio-api/src/web/core/OfflineAudioContext.tsx similarity index 93% rename from packages/react-native-audio-api/src/web-core/OfflineAudioContext.tsx rename to packages/react-native-audio-api/src/web/core/OfflineAudioContext.tsx index 0eac6aab4..741ab1f3a 100644 --- a/packages/react-native-audio-api/src/web-core/OfflineAudioContext.tsx +++ b/packages/react-native-audio-api/src/web/core/OfflineAudioContext.tsx @@ -1,7 +1,7 @@ -import { OfflineAudioContextOptions } from '../types'; -import { NotSupportedError, InvalidStateError } from '../errors'; +import { OfflineAudioContextOptions } from '../../types'; +import { NotSupportedError, InvalidStateError } from '../../errors'; import BaseAudioContext from './BaseAudioContext'; -import AudioBuffer from './AudioBuffer'; +import AudioBuffer from '../sources/AudioBuffer'; export default class OfflineAudioContext extends BaseAudioContext { private isSuspended: boolean; diff --git a/packages/react-native-audio-api/src/web-core/custom/LoadCustomWasm.ts b/packages/react-native-audio-api/src/web/custom/LoadCustomWasm.ts similarity index 100% rename from packages/react-native-audio-api/src/web-core/custom/LoadCustomWasm.ts rename to packages/react-native-audio-api/src/web/custom/LoadCustomWasm.ts diff --git a/packages/react-native-audio-api/src/web-core/custom/index.ts b/packages/react-native-audio-api/src/web/custom/index.ts similarity index 100% rename from packages/react-native-audio-api/src/web-core/custom/index.ts rename to packages/react-native-audio-api/src/web/custom/index.ts diff --git a/packages/react-native-audio-api/src/web-core/custom/signalsmithStretch/LICENSE.txt b/packages/react-native-audio-api/src/web/custom/signalsmithStretch/LICENSE.txt similarity index 100% rename from packages/react-native-audio-api/src/web-core/custom/signalsmithStretch/LICENSE.txt rename to packages/react-native-audio-api/src/web/custom/signalsmithStretch/LICENSE.txt diff --git a/packages/react-native-audio-api/src/web-core/custom/signalsmithStretch/README.md b/packages/react-native-audio-api/src/web/custom/signalsmithStretch/README.md similarity index 100% rename from packages/react-native-audio-api/src/web-core/custom/signalsmithStretch/README.md rename to packages/react-native-audio-api/src/web/custom/signalsmithStretch/README.md diff --git a/packages/react-native-audio-api/src/web-core/custom/signalsmithStretch/SignalsmithStretch.mjs b/packages/react-native-audio-api/src/web/custom/signalsmithStretch/SignalsmithStretch.mjs similarity index 100% rename from packages/react-native-audio-api/src/web-core/custom/signalsmithStretch/SignalsmithStretch.mjs rename to packages/react-native-audio-api/src/web/custom/signalsmithStretch/SignalsmithStretch.mjs diff --git a/packages/react-native-audio-api/src/web-core/AudioDestinationNode.tsx b/packages/react-native-audio-api/src/web/destinations/AudioDestinationNode.tsx similarity index 59% rename from packages/react-native-audio-api/src/web-core/AudioDestinationNode.tsx rename to packages/react-native-audio-api/src/web/destinations/AudioDestinationNode.tsx index f1d850e90..ed658d83d 100644 --- a/packages/react-native-audio-api/src/web-core/AudioDestinationNode.tsx +++ b/packages/react-native-audio-api/src/web/destinations/AudioDestinationNode.tsx @@ -1,3 +1,3 @@ -import AudioNode from './AudioNode'; +import AudioNode from '../core/AudioNode'; export default class AudioDestinationNode extends AudioNode {} diff --git a/packages/react-native-audio-api/src/web-core/BiquadFilterNode.tsx b/packages/react-native-audio-api/src/web/effects/BiquadFilterNode.tsx similarity index 85% rename from packages/react-native-audio-api/src/web-core/BiquadFilterNode.tsx rename to packages/react-native-audio-api/src/web/effects/BiquadFilterNode.tsx index 4a8a4df21..c9e9a32d8 100644 --- a/packages/react-native-audio-api/src/web-core/BiquadFilterNode.tsx +++ b/packages/react-native-audio-api/src/web/effects/BiquadFilterNode.tsx @@ -1,8 +1,8 @@ -import AudioParam from './AudioParam'; -import AudioNode from './AudioNode'; -import BaseAudioContext from './BaseAudioContext'; -import { BiquadFilterType } from '../types'; -import { InvalidAccessError } from '../errors'; +import AudioParam from '../core/AudioParam'; +import AudioNode from '../core/AudioNode'; +import BaseAudioContext from '../core/BaseAudioContext'; +import { BiquadFilterType } from '../../types'; +import { InvalidAccessError } from '../../errors'; export default class BiquadFilterNode extends AudioNode { readonly frequency: AudioParam; diff --git a/packages/react-native-audio-api/src/web-core/GainNode.tsx b/packages/react-native-audio-api/src/web/effects/GainNode.tsx similarity index 61% rename from packages/react-native-audio-api/src/web-core/GainNode.tsx rename to packages/react-native-audio-api/src/web/effects/GainNode.tsx index 601de5920..d524dd067 100644 --- a/packages/react-native-audio-api/src/web-core/GainNode.tsx +++ b/packages/react-native-audio-api/src/web/effects/GainNode.tsx @@ -1,6 +1,6 @@ -import BaseAudioContext from './BaseAudioContext'; -import AudioNode from './AudioNode'; -import AudioParam from './AudioParam'; +import AudioParam from '../core/AudioParam'; +import AudioNode from '../core/AudioNode'; +import BaseAudioContext from '../core/BaseAudioContext'; export default class GainNode extends AudioNode { readonly gain: AudioParam; diff --git a/packages/react-native-audio-api/src/web-core/PeriodicWave.tsx b/packages/react-native-audio-api/src/web/effects/PeriodicWave.tsx similarity index 100% rename from packages/react-native-audio-api/src/web-core/PeriodicWave.tsx rename to packages/react-native-audio-api/src/web/effects/PeriodicWave.tsx diff --git a/packages/react-native-audio-api/src/web-core/StereoPannerNode.tsx b/packages/react-native-audio-api/src/web/effects/StereoPannerNode.tsx similarity index 62% rename from packages/react-native-audio-api/src/web-core/StereoPannerNode.tsx rename to packages/react-native-audio-api/src/web/effects/StereoPannerNode.tsx index 2d468a205..1ab12ce3c 100644 --- a/packages/react-native-audio-api/src/web-core/StereoPannerNode.tsx +++ b/packages/react-native-audio-api/src/web/effects/StereoPannerNode.tsx @@ -1,6 +1,6 @@ -import BaseAudioContext from './BaseAudioContext'; -import AudioNode from './AudioNode'; -import AudioParam from './AudioParam'; +import AudioParam from '../core/AudioParam'; +import AudioNode from '../core/AudioNode'; +import BaseAudioContext from '../core/BaseAudioContext'; export default class StereoPannerNode extends AudioNode { readonly pan: AudioParam; diff --git a/packages/react-native-audio-api/src/web-core/AudioBuffer.tsx b/packages/react-native-audio-api/src/web/sources/AudioBuffer.tsx similarity index 97% rename from packages/react-native-audio-api/src/web-core/AudioBuffer.tsx rename to packages/react-native-audio-api/src/web/sources/AudioBuffer.tsx index d007a6dd4..f71cb3b16 100644 --- a/packages/react-native-audio-api/src/web-core/AudioBuffer.tsx +++ b/packages/react-native-audio-api/src/web/sources/AudioBuffer.tsx @@ -1,4 +1,4 @@ -import { IndexSizeError } from '../errors'; +import { IndexSizeError } from '../../errors'; export default class AudioBuffer { readonly length: number; diff --git a/packages/react-native-audio-api/src/web-core/AudioBufferSourceNode.tsx b/packages/react-native-audio-api/src/web/sources/AudioBufferSourceNode.tsx similarity index 97% rename from packages/react-native-audio-api/src/web-core/AudioBufferSourceNode.tsx rename to packages/react-native-audio-api/src/web/sources/AudioBufferSourceNode.tsx index 64fbcdc51..25d047010 100644 --- a/packages/react-native-audio-api/src/web-core/AudioBufferSourceNode.tsx +++ b/packages/react-native-audio-api/src/web/sources/AudioBufferSourceNode.tsx @@ -1,12 +1,12 @@ -import { InvalidStateError, RangeError } from '../errors'; +import { InvalidStateError, RangeError } from '../../errors'; -import AudioParam from './AudioParam'; +import AudioParam from '../core/AudioParam'; import AudioBuffer from './AudioBuffer'; -import BaseAudioContext from './BaseAudioContext'; +import BaseAudioContext from '../core/BaseAudioContext'; import AudioScheduledSourceNode from './AudioScheduledSourceNode'; -import { clamp } from '../utils'; -import { globalTag } from './custom/LoadCustomWasm'; +import { clamp } from '../../utils'; +import { globalTag } from '../custom/LoadCustomWasm'; interface ScheduleOptions { rate?: number; diff --git a/packages/react-native-audio-api/src/web-core/AudioScheduledSourceNode.tsx b/packages/react-native-audio-api/src/web/sources/AudioScheduledSourceNode.tsx similarity index 82% rename from packages/react-native-audio-api/src/web-core/AudioScheduledSourceNode.tsx rename to packages/react-native-audio-api/src/web/sources/AudioScheduledSourceNode.tsx index 89566c3ae..8d0417a68 100644 --- a/packages/react-native-audio-api/src/web-core/AudioScheduledSourceNode.tsx +++ b/packages/react-native-audio-api/src/web/sources/AudioScheduledSourceNode.tsx @@ -1,6 +1,5 @@ -import AudioNode from './AudioNode'; -import { EventEmptyType } from '../events/types'; -import { RangeError, InvalidStateError } from '../errors'; +import AudioNode from '../core/AudioNode'; +import { RangeError, InvalidStateError } from '../../errors'; export default class AudioScheduledSourceNode extends AudioNode { protected hasBeenStarted: boolean = false; @@ -37,7 +36,7 @@ export default class AudioScheduledSourceNode extends AudioNode { } // eslint-disable-next-line accessor-pairs - public set onended(callback: (event: EventEmptyType) => void) { + public set onended(callback: () => void) { (this.node as globalThis.AudioScheduledSourceNode).onended = callback; } } diff --git a/packages/react-native-audio-api/src/web-core/OscillatorNode.tsx b/packages/react-native-audio-api/src/web/sources/OscillatorNode.tsx similarity index 79% rename from packages/react-native-audio-api/src/web-core/OscillatorNode.tsx rename to packages/react-native-audio-api/src/web/sources/OscillatorNode.tsx index 612cdd9f6..905fb2a60 100644 --- a/packages/react-native-audio-api/src/web-core/OscillatorNode.tsx +++ b/packages/react-native-audio-api/src/web/sources/OscillatorNode.tsx @@ -1,9 +1,9 @@ -import { OscillatorType } from '../types'; -import { InvalidStateError } from '../errors'; +import { OscillatorType } from '../../types'; +import { InvalidStateError } from '../../errors'; import AudioScheduledSourceNode from './AudioScheduledSourceNode'; -import BaseAudioContext from './BaseAudioContext'; -import AudioParam from './AudioParam'; -import PeriodicWave from './PeriodicWave'; +import BaseAudioContext from '../core/BaseAudioContext'; +import AudioParam from '../core/AudioParam'; +import PeriodicWave from '../effects/PeriodicWave'; export default class OscillatorNode extends AudioScheduledSourceNode { readonly frequency: AudioParam; From 88b784da23cb4eb9d2fa07919821c2c4db70e4e6 Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Sun, 27 Jul 2025 14:49:49 +0200 Subject: [PATCH 08/10] chore: unified AudioScheduledSourceNode --- .../mobile/sources/AudioScheduledSourceNode.ts | 10 +++++----- .../src/web/sources/AudioScheduledSourceNode.tsx | 16 ++++++++++++++-- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/packages/react-native-audio-api/src/mobile/sources/AudioScheduledSourceNode.ts b/packages/react-native-audio-api/src/mobile/sources/AudioScheduledSourceNode.ts index 4a9c5326e..bac7a3353 100644 --- a/packages/react-native-audio-api/src/mobile/sources/AudioScheduledSourceNode.ts +++ b/packages/react-native-audio-api/src/mobile/sources/AudioScheduledSourceNode.ts @@ -10,7 +10,7 @@ export default class AudioScheduledSourceNode extends AudioNode { global.AudioEventEmitter ); - private onendedSubscription?: AudioEventSubscription; + private onEndedSubscription?: AudioEventSubscription; private onEndedCallback?: (event: EventEmptyType) => void; public start(when: number = 0): void { @@ -51,19 +51,19 @@ export default class AudioScheduledSourceNode extends AudioNode { public set onEnded(callback: ((event: EventEmptyType) => void) | null) { if (!callback) { (this.node as IAudioScheduledSourceNode).onEnded = '0'; - this.onendedSubscription?.remove(); - this.onendedSubscription = undefined; + this.onEndedSubscription?.remove(); + this.onEndedSubscription = undefined; this.onEndedCallback = undefined; return; } this.onEndedCallback = callback; - this.onendedSubscription = this.audioEventEmitter.addAudioEventListener( + this.onEndedSubscription = this.audioEventEmitter.addAudioEventListener( 'ended', callback ); (this.node as IAudioScheduledSourceNode).onEnded = - this.onendedSubscription.subscriptionId; + this.onEndedSubscription.subscriptionId; } } diff --git a/packages/react-native-audio-api/src/web/sources/AudioScheduledSourceNode.tsx b/packages/react-native-audio-api/src/web/sources/AudioScheduledSourceNode.tsx index 8d0417a68..8005c9fa0 100644 --- a/packages/react-native-audio-api/src/web/sources/AudioScheduledSourceNode.tsx +++ b/packages/react-native-audio-api/src/web/sources/AudioScheduledSourceNode.tsx @@ -4,6 +4,8 @@ import { RangeError, InvalidStateError } from '../../errors'; export default class AudioScheduledSourceNode extends AudioNode { protected hasBeenStarted: boolean = false; + private onEndedCallback?: () => void; + public start(when: number = 0): void { if (when < 0) { throw new RangeError( @@ -35,8 +37,18 @@ export default class AudioScheduledSourceNode extends AudioNode { (this.node as globalThis.AudioScheduledSourceNode).stop(when); } - // eslint-disable-next-line accessor-pairs - public set onended(callback: () => void) { + public get onEnded(): (() => void) | undefined { + return this.onEndedCallback; + } + + public set onEnded(callback: (() => void) | null) { + if (!callback) { + (this.node as globalThis.AudioScheduledSourceNode).onended = null; + this.onEndedCallback = undefined; + return; + } + + this.onEndedCallback = callback; (this.node as globalThis.AudioScheduledSourceNode).onended = callback; } } From 72ed96607d2080352e9787e2a11389a6adc16478 Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Sun, 27 Jul 2025 14:50:58 +0200 Subject: [PATCH 09/10] fix: fixed warning in web AnalyserNode --- .../react-native-audio-api/src/web/analysis/AnalyserNode.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/react-native-audio-api/src/web/analysis/AnalyserNode.tsx b/packages/react-native-audio-api/src/web/analysis/AnalyserNode.tsx index cc6fd1319..7b7e193a1 100644 --- a/packages/react-native-audio-api/src/web/analysis/AnalyserNode.tsx +++ b/packages/react-native-audio-api/src/web/analysis/AnalyserNode.tsx @@ -20,13 +20,12 @@ export default class AnalyserNode extends AudioNode { } public get window(): WindowType { + console.warn('React Native Audio API: window prop is not supported on web'); return 'blackman'; } public set window(value: WindowType) { - console.log( - 'React Native Audio API: setting window is not supported on web' - ); + console.warn('React Native Audio API: window prop is not supported on web'); } public getByteFrequencyData(array: Uint8Array): void { From eba6843d8e9f12c26b28b6432735c792c5e6334c Mon Sep 17 00:00:00 2001 From: Maciej Makowski Date: Sun, 27 Jul 2025 14:55:53 +0200 Subject: [PATCH 10/10] docs: added sections for rest of the interfaces --- .../audiodocs/docs/destinations/audio-destination-node.mdx | 7 +++++++ packages/audiodocs/docs/effects/periodic-wave.mdx | 7 +++++++ packages/audiodocs/docs/effects/stereo-panner-node.mdx | 2 +- 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 packages/audiodocs/docs/destinations/audio-destination-node.mdx create mode 100644 packages/audiodocs/docs/effects/periodic-wave.mdx diff --git a/packages/audiodocs/docs/destinations/audio-destination-node.mdx b/packages/audiodocs/docs/destinations/audio-destination-node.mdx new file mode 100644 index 000000000..f50454d45 --- /dev/null +++ b/packages/audiodocs/docs/destinations/audio-destination-node.mdx @@ -0,0 +1,7 @@ +--- +sidebar_position: 3 +--- + +# AudioDestinationNode + +## 🚧 Under development 🚧 diff --git a/packages/audiodocs/docs/effects/periodic-wave.mdx b/packages/audiodocs/docs/effects/periodic-wave.mdx new file mode 100644 index 000000000..ca2163bfb --- /dev/null +++ b/packages/audiodocs/docs/effects/periodic-wave.mdx @@ -0,0 +1,7 @@ +--- +sidebar_position: 3 +--- + +# PeriodicWave + +## 🚧 Under development 🚧 diff --git a/packages/audiodocs/docs/effects/stereo-panner-node.mdx b/packages/audiodocs/docs/effects/stereo-panner-node.mdx index 192782e26..fd4b096f9 100644 --- a/packages/audiodocs/docs/effects/stereo-panner-node.mdx +++ b/packages/audiodocs/docs/effects/stereo-panner-node.mdx @@ -1,5 +1,5 @@ --- -sidebar_position: 3 +sidebar_position: 4 --- import AudioNodePropsTable from "@site/src/components/AudioNodePropsTable"