react-native-audio-api
Version:
react-native-audio-api provides system for controlling audio in React Native environment compatible with Web Audio API specification
110 lines (94 loc) • 3.62 kB
text/typescript
import { IndexSizeError, NotSupportedError } from '../errors';
import { AudioBufferLike, AudioBufferOptions } from '../types';
export default class AudioBuffer implements AudioBufferLike {
readonly length: number;
readonly duration: number;
readonly sampleRate: number;
readonly numberOfChannels: number;
/** @internal */
public readonly buffer: globalThis.AudioBuffer;
constructor(options: AudioBufferOptions);
/** @internal */
constructor(buffer: globalThis.AudioBuffer);
/** @internal */
constructor(arg: AudioBufferOptions | globalThis.AudioBuffer) {
this.buffer = this.isAudioBuffer(arg)
? arg
: AudioBuffer.createBufferFromOptions(arg);
this.length = this.buffer.length;
this.duration = this.buffer.duration;
this.sampleRate = this.buffer.sampleRate;
this.numberOfChannels = this.buffer.numberOfChannels;
}
public getChannelData(channel: number): Float32Array<ArrayBuffer> {
if (channel < 0 || channel >= this.numberOfChannels) {
throw new IndexSizeError(
`The channel number provided (${channel}) is outside the range [0, ${this.numberOfChannels - 1}]`
);
}
return this.buffer.getChannelData(channel);
}
public copyFromChannel(
destination: Float32Array<ArrayBuffer>,
channelNumber: number,
startInChannel: number = 0
): void {
if (channelNumber < 0 || channelNumber >= this.numberOfChannels) {
throw new IndexSizeError(
`The channel number provided (${channelNumber}) is outside the range [0, ${this.numberOfChannels - 1}]`
);
}
if (startInChannel < 0 || startInChannel >= this.length) {
throw new IndexSizeError(
`The startInChannel number provided (${startInChannel}) is outside the range [0, ${this.length - 1}]`
);
}
this.buffer.copyFromChannel(destination, channelNumber, startInChannel);
}
public copyToChannel(
source: Float32Array<ArrayBuffer>,
channelNumber: number,
startInChannel: number = 0
): void {
if (channelNumber < 0 || channelNumber >= this.numberOfChannels) {
throw new IndexSizeError(
`The channel number provided (${channelNumber}) is outside the range [0, ${this.numberOfChannels - 1}]`
);
}
if (startInChannel < 0 || startInChannel >= this.length) {
throw new IndexSizeError(
`The startInChannel number provided (${startInChannel}) is outside the range [0, ${this.length - 1}]`
);
}
this.buffer.copyToChannel(source, channelNumber, startInChannel);
}
private static createBufferFromOptions(
options: AudioBufferOptions
): globalThis.AudioBuffer {
const { numberOfChannels = 1, length, sampleRate } = options;
if (numberOfChannels < 1 || numberOfChannels >= 32) {
throw new NotSupportedError(
`The number of channels provided (${numberOfChannels}) is outside the range [1, 32]`
);
}
if (length <= 0) {
throw new NotSupportedError(
`The number of frames provided (${length}) is less than or equal to the minimum bound (0)`
);
}
if (sampleRate < 8000 || sampleRate > 96000) {
throw new NotSupportedError(
`The sample rate provided (${sampleRate}) is outside the range [8000, 96000]`
);
}
return new globalThis.AudioBuffer({ numberOfChannels, length, sampleRate });
}
private isAudioBuffer(obj: unknown): obj is globalThis.AudioBuffer {
return (
typeof obj === 'object' &&
obj !== null &&
'getChannelData' in obj &&
typeof (obj as globalThis.AudioBuffer).getChannelData === 'function'
);
}
}