diff --git a/packages/audiodocs/docs/core/audio-context.mdx b/packages/audiodocs/docs/core/audio-context.mdx index fc07e78f4..20bb2cde7 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/audiodocs/docs/core/audio-node.mdx b/packages/audiodocs/docs/core/audio-node.mdx index d0b4223de..3f97ee1e6 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/audiodocs/docs/core/audio-param.mdx b/packages/audiodocs/docs/core/audio-param.mdx index 3289e7ab0..c7cc2cbea 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/audiodocs/docs/core/base-audio-context.mdx b/packages/audiodocs/docs/core/base-audio-context.mdx index 7bf048915..d25ab6907 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/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/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 1d403c043..6d8336435 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" diff --git a/packages/audiodocs/docs/sources/audio-buffer-source-node.mdx b/packages/audiodocs/docs/sources/audio-buffer-source-node.mdx index 250e9242c..0045072c4 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`](/docs/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/api.ts b/packages/react-native-audio-api/src/api.ts index 860786109..1599195e4 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 RecorderAdapterNode } from './core/RecorderAdapterNode'; -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 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 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 { default as RecorderAdapterNode } from './mobile/sources/RecorderAdapterNode'; 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 caaddfe44..1b8ee3080 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 85% rename from packages/react-native-audio-api/src/core/AudioNode.ts rename to packages/react-native-audio-api/src/mobile/core/AudioNode.ts index 2e19d51d1..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; @@ -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/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 c9e2e4d3f..962af5500 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 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'; -import RecorderAdapterNode from './RecorderAdapterNode'; +} 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 AudioBufferQueueSourceNode from '../sources/AudioBufferQueueSourceNode'; +import RecorderAdapterNode from '../sources/RecorderAdapterNode'; +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/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 9a64e0ed3..ab5ea8fb1 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 89% rename from packages/react-native-audio-api/src/core/AudioRecorder.ts rename to packages/react-native-audio-api/src/mobile/inputs/AudioRecorder.ts index 77eedc389..69b439563 100644 --- a/packages/react-native-audio-api/src/core/AudioRecorder.ts +++ b/packages/react-native-audio-api/src/mobile/inputs/AudioRecorder.ts @@ -1,9 +1,9 @@ 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'; -import RecorderAdapterNode from './RecorderAdapterNode'; +import RecorderAdapterNode from '../sources/RecorderAdapterNode'; export default class AudioRecorder { protected readonly recorder: IAudioRecorder; 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 e0c3cf405..0637ba9ab 100644 --- a/packages/react-native-audio-api/src/interfaces.ts +++ b/packages/react-native-audio-api/src/mobile/interfaces.ts @@ -5,7 +5,7 @@ import { BiquadFilterType, ChannelCountMode, ChannelInterpretation, -} 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 97% rename from packages/react-native-audio-api/src/core/AudioBufferQueueSourceNode.ts rename to packages/react-native-audio-api/src/mobile/sources/AudioBufferQueueSourceNode.ts index bfc923d2a..73ca2d3f3 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(buffer: AudioBuffer): string { 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 7bda1a425..fc66b3ddf 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'; import { EventEmptyType } from '../events/types'; export default class AudioBufferSourceNode extends AudioBufferBaseSourceNode { 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 82% rename from packages/react-native-audio-api/src/core/AudioScheduledSourceNode.ts rename to packages/react-native-audio-api/src/mobile/sources/AudioScheduledSourceNode.ts index 80da6aeb0..0f62f48f5 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 { OnEndedEventType } from '../events/types'; import { AudioEventEmitter, AudioEventSubscription } from '../events'; @@ -10,7 +10,7 @@ export default class AudioScheduledSourceNode extends AudioNode { global.AudioEventEmitter ); - private onendedSubscription?: AudioEventSubscription; + private onEndedSubscription?: AudioEventSubscription; private onEndedCallback?: (event: OnEndedEventType) => void; public start(when: number = 0): void { @@ -51,19 +51,19 @@ export default class AudioScheduledSourceNode extends AudioNode { public set onEnded(callback: ((event: OnEndedEventType) => 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/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/core/RecorderAdapterNode.ts b/packages/react-native-audio-api/src/mobile/sources/RecorderAdapterNode.ts similarity index 87% rename from packages/react-native-audio-api/src/core/RecorderAdapterNode.ts rename to packages/react-native-audio-api/src/mobile/sources/RecorderAdapterNode.ts index 75c194944..8487ecabc 100644 --- a/packages/react-native-audio-api/src/core/RecorderAdapterNode.ts +++ b/packages/react-native-audio-api/src/mobile/sources/RecorderAdapterNode.ts @@ -1,5 +1,5 @@ import { IRecorderAdapterNode } from '../interfaces'; -import AudioNode from './AudioNode'; +import AudioNode from '../core/AudioNode'; export default class RecorderAdapterNode extends AudioNode { /** @internal */ 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 98% rename from packages/react-native-audio-api/src/system/AudioManager.ts rename to packages/react-native-audio-api/src/mobile/system/AudioManager.ts index 70a116ee4..d8d9dea20 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 6bab1ba39..f8edf54c2 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/BaseAudioContext.tsx b/packages/react-native-audio-api/src/web-core/BaseAudioContext.tsx deleted file mode 100644 index 5cafcee77..000000000 --- a/packages/react-native-audio-api/src/web-core/BaseAudioContext.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { ContextState, PeriodicWaveConstraints } from '../types'; -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'; - -export default interface BaseAudioContext { - 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; - createBuffer( - numOfChannels: number, - length: number, - sampleRate: number - ): AudioBuffer; - createPeriodicWave( - real: Float32Array, - imag: Float32Array, - constraints?: PeriodicWaveConstraints - ): PeriodicWave; - createAnalyser(): AnalyserNode; - decodeAudioDataSource(source: string): Promise; - decodeAudioData(arrayBuffer: ArrayBuffer): Promise; -} diff --git a/packages/react-native-audio-api/src/web-core/OfflineAudioContext.tsx b/packages/react-native-audio-api/src/web-core/OfflineAudioContext.tsx deleted file mode 100644 index b4c6f95aa..000000000 --- a/packages/react-native-audio-api/src/web-core/OfflineAudioContext.tsx +++ /dev/null @@ -1,163 +0,0 @@ -import { - ContextState, - PeriodicWaveConstraints, - OfflineAudioContextOptions, - AudioBufferSourceNodeOptions, -} from '../types'; -import { InvalidAccessError, 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 OfflineAudioContext implements BaseAudioContext { - readonly context: globalThis.OfflineAudioContext; - - readonly destination: AudioDestinationNode; - readonly sampleRate: number; - - constructor(options: OfflineAudioContextOptions); - constructor(numberOfChannels: number, length: number, sampleRate: number); - constructor( - arg0: OfflineAudioContextOptions | number, - arg1?: number, - arg2?: number - ) { - if (typeof arg0 === 'object') { - this.context = new window.OfflineAudioContext(arg0); - } else if ( - typeof arg0 === 'number' && - typeof arg1 === 'number' && - typeof arg2 === 'number' - ) { - this.context = new window.OfflineAudioContext(arg0, arg1, arg2); - } else { - throw new NotSupportedError('Invalid constructor arguments'); - } - - 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)); - } - - async startRendering(): Promise { - return new AudioBuffer(await this.context.startRendering()); - } - - async resume(): Promise { - await this.context.resume(); - } - - async suspend(suspendTime: number): Promise { - await this.context.suspend(suspendTime); - } -} 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 79% 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..7b7e193a1 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; @@ -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 { diff --git a/packages/react-native-audio-api/src/web/core/AudioContext.tsx b/packages/react-native-audio-api/src/web/core/AudioContext.tsx new file mode 100644 index 000000000..063258c40 --- /dev/null +++ b/packages/react-native-audio-api/src/web/core/AudioContext.tsx @@ -0,0 +1,31 @@ +import { AudioContextOptions } from '../../types'; +import { NotSupportedError } from '../../errors'; +import BaseAudioContext from './BaseAudioContext'; + +export default class AudioContext extends BaseAudioContext { + constructor(options?: AudioContextOptions, _initSuspended: boolean = false) { + if ( + options && + options.sampleRate && + (options.sampleRate < 8000 || options.sampleRate > 96000) + ) { + throw new NotSupportedError( + `The provided sampleRate is not supported: ${options.sampleRate}` + ); + } + + super(new window.AudioContext({ sampleRate: options?.sampleRate })); + } + + async close(): Promise { + await (this.context as globalThis.AudioContext).close(); + } + + async resume(): Promise { + await (this.context as globalThis.AudioContext).resume(); + } + + async suspend(): Promise { + await (this.context as globalThis.AudioContext).suspend(); + } +} 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 71% 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 a66113f1f..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,6 +1,7 @@ import BaseAudioContext from './BaseAudioContext'; -import { ChannelCountMode, ChannelInterpretation } from '../types'; +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); } } 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 74% 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 341f59e55..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 { @@ -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; } diff --git a/packages/react-native-audio-api/src/web-core/AudioContext.tsx b/packages/react-native-audio-api/src/web/core/BaseAudioContext.tsx similarity index 68% rename from packages/react-native-audio-api/src/web-core/AudioContext.tsx rename to packages/react-native-audio-api/src/web/core/BaseAudioContext.tsx index 78ada7bf1..e87e056cb 100644 --- a/packages/react-native-audio-api/src/web-core/AudioContext.tsx +++ b/packages/react-native-audio-api/src/web/core/BaseAudioContext.tsx @@ -1,44 +1,30 @@ import { ContextState, PeriodicWaveConstraints, - AudioContextOptions, AudioBufferSourceNodeOptions, -} from '../types'; -import { InvalidAccessError, 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; - +} 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; readonly destination: AudioDestinationNode; readonly sampleRate: number; - constructor(options?: AudioContextOptions, _initSuspended: boolean = false) { - if ( - options && - options.sampleRate && - (options.sampleRate < 8000 || options.sampleRate > 96000) - ) { - throw new NotSupportedError( - `The provided sampleRate is not supported: ${options.sampleRate}` - ); - } - - this.context = new window.AudioContext({ sampleRate: options?.sampleRate }); - - this.sampleRate = this.context.sampleRate; + constructor(context: globalThis.BaseAudioContext) { + this.context = context; this.destination = new AudioDestinationNode(this, this.context.destination); + this.sampleRate = this.context.sampleRate; } public get currentTime(): number { @@ -65,6 +51,7 @@ export default class AudioContext implements BaseAudioContext { return new BiquadFilterNode(this, this.context.createBiquadFilter()); } + // UNIFIED IT SOMEHOW async createBufferSource( options?: AudioBufferSourceNodeOptions ): Promise { @@ -143,15 +130,15 @@ export default class AudioContext implements BaseAudioContext { return new AudioBuffer(await this.context.decodeAudioData(arrayBuffer)); } - async close(): Promise { - await this.context.close(); - } - - async resume(): Promise { - await this.context.resume(); - } + // 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'); - async suspend(): Promise { - await this.context.suspend(); + return this.createBuffer(2, 48000, this.sampleRate); } } diff --git a/packages/react-native-audio-api/src/web/core/OfflineAudioContext.tsx b/packages/react-native-audio-api/src/web/core/OfflineAudioContext.tsx new file mode 100644 index 000000000..741ab1f3a --- /dev/null +++ b/packages/react-native-audio-api/src/web/core/OfflineAudioContext.tsx @@ -0,0 +1,93 @@ +import { OfflineAudioContextOptions } from '../../types'; +import { NotSupportedError, InvalidStateError } from '../../errors'; +import BaseAudioContext from './BaseAudioContext'; +import AudioBuffer from '../sources/AudioBuffer'; + +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); + constructor( + arg0: OfflineAudioContextOptions | number, + arg1?: number, + arg2?: number + ) { + if (typeof arg0 === 'object') { + 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' + ) { + super(new window.OfflineAudioContext(arg0, arg1, arg2)); + this.duration = arg1 / arg2; + } else { + throw new NotSupportedError('Invalid constructor arguments'); + } + + this.isSuspended = false; + this.isRendering = false; + } + + async resume(): Promise { + if (!this.isRendering) { + throw new InvalidStateError( + 'Cannot resume an OfflineAudioContext while rendering' + ); + } + + if (!this.isSuspended) { + throw new InvalidStateError( + 'Cannot resume an OfflineAudioContext that is not suspended' + ); + } + + this.isSuspended = false; + + await (this.context as globalThis.OfflineAudioContext).resume(); + } + + async suspend(suspendTime: number): Promise { + if (suspendTime < 0) { + throw new InvalidStateError('suspendTime must be a non-negative number'); + } + + if (suspendTime < this.context.currentTime) { + throw new InvalidStateError( + `suspendTime must be greater than the current time: ${suspendTime}` + ); + } + + if (suspendTime > this.duration) { + throw new InvalidStateError( + `suspendTime must be less than the duration of the context: ${suspendTime}` + ); + } + + this.isSuspended = true; + + await (this.context as globalThis.OfflineAudioContext).suspend(suspendTime); + } + + async startRendering(): Promise { + if (this.isRendering) { + throw new InvalidStateError('OfflineAudioContext is already rendering'); + } + + this.isRendering = true; + + const audioBuffer = await ( + this.context as globalThis.OfflineAudioContext + ).startRendering(); + + return new AudioBuffer(audioBuffer); + } +} 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 93% 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 71c749848..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; @@ -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/AudioScheduledSourceNode.tsx b/packages/react-native-audio-api/src/web/sources/AudioScheduledSourceNode.tsx similarity index 66% 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..8005c9fa0 100644 --- a/packages/react-native-audio-api/src/web-core/AudioScheduledSourceNode.tsx +++ b/packages/react-native-audio-api/src/web/sources/AudioScheduledSourceNode.tsx @@ -1,10 +1,11 @@ -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; + private onEndedCallback?: () => void; + public start(when: number = 0): void { if (when < 0) { throw new RangeError( @@ -36,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: (event: EventEmptyType) => 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; } } 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;