audio-inspect
Version:
Lightweight yet powerful audio analysis library
550 lines (537 loc) • 17.5 kB
TypeScript
interface AudioData {
sampleRate: number;
channelData: Float32Array[];
duration: number;
numberOfChannels: number;
length: number;
}
type ChannelSelector = 'mix' | number | 'all' | readonly number[];
type WindowFunction = 'hann' | 'hamming' | 'blackman' | 'bartlett' | 'kaiser' | 'tukey' | 'rectangular' | 'none';
interface AmplitudeOptions {
channel?: ChannelSelector;
asDB?: boolean;
reference?: number;
truePeak?: boolean;
oversamplingFactor?: number;
interpolation?: 'linear' | 'cubic' | 'sinc';
}
interface ProgressOptions {
onProgress?: (percent: number, message?: string) => void;
}
interface BaseAnalysisResult {
sampleRate: number;
duration: number;
processingTime?: number;
}
interface WaveformAnalysisResult extends BaseAnalysisResult {
amplitudes: Float32Array;
timestamps?: Float32Array;
frameCount: number;
samplesPerFrame: number;
framesPerSecond: number;
maxAmplitude: number;
averageAmplitude: number;
}
interface PeaksAnalysisResult extends BaseAnalysisResult {
positions: Float32Array;
amplitudes: Float32Array;
times: Float32Array;
maxAmplitude: number;
averageAmplitude: number;
count: number;
}
interface RMSAnalysisResult extends BaseAnalysisResult {
value: number;
valueDB?: number;
channel: number;
}
interface PeaksOptions {
count?: number;
threshold?: number;
channel?: ChannelSelector;
minDistance?: number;
}
interface Peak {
position: number;
time: number;
amplitude: number;
}
interface PeaksResult {
peaks: Peak[];
maxAmplitude: number;
averageAmplitude: number;
}
declare function getPeaks(audio: AudioData, options?: PeaksOptions): PeaksResult;
declare function getRMS(audio: AudioData, options?: AmplitudeOptions): number;
declare function getPeakAmplitude(audio: AudioData, options?: AmplitudeOptions): number;
declare function getZeroCrossing(audio: AudioData, channel?: ChannelSelector): number;
interface WaveformOptions {
framesPerSecond?: number;
channel?: ChannelSelector;
method?: 'rms' | 'peak' | 'average';
}
interface WaveformPoint {
time: number;
amplitude: number;
}
interface WaveformResult {
waveform: WaveformPoint[];
maxAmplitude: number;
averageAmplitude: number;
frameCount: number;
samplesPerFrame: number;
}
declare function getWaveform(audio: AudioData, options?: WaveformOptions): WaveformResult;
interface WaveformAnalysisOptions extends ProgressOptions {
framesPerSecond?: number;
channel?: ChannelSelector;
method?: 'rms' | 'peak' | 'average';
}
interface PeaksAnalysisOptions extends ProgressOptions {
count?: number;
threshold?: number;
channel?: ChannelSelector;
minDistance?: number;
}
interface RMSAnalysisOptions extends ProgressOptions {
channel?: ChannelSelector;
asDB?: boolean;
reference?: number;
}
declare function getWaveformAnalysis(audio: AudioData, options?: WaveformAnalysisOptions): WaveformAnalysisResult;
declare function getPeaksAnalysis(audio: AudioData, options?: PeaksAnalysisOptions): PeaksAnalysisResult;
declare function getRMSAnalysis(audio: AudioData, options?: RMSAnalysisOptions): RMSAnalysisResult;
type FFTProviderType = 'webfft' | 'native' | 'custom';
interface FFTResult {
complex: Float32Array;
magnitude: Float32Array;
phase: Float32Array;
frequencies: Float32Array;
}
interface IFFTProvider {
readonly name: string;
readonly size: number;
readonly sampleRate: number;
fft(input: Float32Array): FFTResult | Promise<FFTResult>;
dispose(): void;
profile?(): Promise<void>;
}
interface FFTProviderConfig {
type: FFTProviderType;
fftSize: number;
sampleRate: number;
enableProfiling?: boolean;
customProvider?: IFFTProvider;
}
interface FFTProviderResolver {
createProvider(config: FFTProviderConfig): Promise<IFFTProvider>;
}
interface FFTProviderRequest {
fftSize: number;
sampleRate: number;
provider?: FFTProviderType;
enableProfiling?: boolean;
fallbackToNative?: boolean;
resolver?: FFTProviderResolver;
}
interface FFTProviderCache {
getOrCreate(request: FFTProviderRequest): Promise<IFFTProvider>;
clear(): void;
}
type FFTNormalization = 'none' | 'amplitude';
type SpectrumScale = 'amplitude' | 'dbfs';
interface FFTOptions {
fftSize?: number;
windowFunction?: WindowFunction;
channel?: ChannelSelector;
provider?: FFTProviderType;
enableProfiling?: boolean;
providerCache?: FFTProviderCache | undefined;
normalization?: FFTNormalization;
}
interface SpectrumOptions extends FFTOptions {
minFrequency?: number;
maxFrequency?: number;
scale?: SpectrumScale;
}
interface SpectrogramOptions extends SpectrumOptions {
frameSize?: number;
hopSize?: number;
maxFrames?: number;
}
interface FFTAnalysisResult extends FFTResult {
fftSize: number;
windowFunction: string;
providerName: string;
normalization: FFTNormalization;
}
interface SpectrumAnalysisResult {
frequencies: Float32Array;
values: Float32Array;
scale: SpectrumScale;
}
interface SpectrogramAnalysisResult {
times: Float32Array;
frequencies: Float32Array;
frames: Float32Array[];
frameCount: number;
frequencyBins: number;
scale: SpectrumScale;
latest: Float32Array;
}
declare function getFFT(audio: AudioData, options?: FFTOptions): Promise<FFTAnalysisResult>;
declare function getSpectrum(audio: AudioData, options?: SpectrumOptions): Promise<SpectrumAnalysisResult>;
declare function getSpectrogram(audio: AudioData, options?: SpectrogramOptions): Promise<SpectrogramAnalysisResult>;
interface SpectralRuntimeOptions {
provider?: FFTProviderType;
enableProfiling?: boolean;
providerCache?: FFTProviderCache | undefined;
}
interface SpectralFeaturesOptions extends SpectralRuntimeOptions {
fftSize?: number;
windowFunction?: 'hann' | 'hamming' | 'blackman' | 'none';
channel?: ChannelSelector;
minFrequency?: number;
maxFrequency?: number;
rolloffThreshold?: number;
}
interface SpectralFeaturesResult {
spectralCentroid: number;
spectralBandwidth: number;
spectralRolloff: number;
spectralFlatness: number;
spectralFlux?: number;
zeroCrossingRate: number;
frequencyRange: {
min: number;
max: number;
};
}
interface TimeVaryingSpectralOptions extends SpectralFeaturesOptions {
frameSize?: number;
hopSize?: number;
numFrames?: number;
}
interface TimeVaryingSpectralResult {
times: Float32Array;
spectralCentroid: Float32Array;
spectralBandwidth: Float32Array;
spectralRolloff: Float32Array;
spectralFlatness: Float32Array;
spectralFlux: Float32Array;
zeroCrossingRate: Float32Array;
frameInfo: {
frameSize: number;
hopSize: number;
numFrames: number;
};
}
interface SpectralEntropyOptions extends SpectralRuntimeOptions {
fftSize?: number;
windowFunction?: 'hann' | 'hamming' | 'blackman' | 'none';
channel?: ChannelSelector;
minFrequency?: number;
maxFrequency?: number;
}
interface SpectralEntropyResult {
entropy: number;
entropyNorm: number;
frequencyRange: {
min: number;
max: number;
};
}
interface SpectralCrestOptions extends SpectralRuntimeOptions {
fftSize?: number;
windowFunction?: 'hann' | 'hamming' | 'blackman' | 'none';
channel?: ChannelSelector;
minFrequency?: number;
maxFrequency?: number;
asDB?: boolean;
}
interface SpectralCrestResult {
crest: number;
crestDB?: number;
peak: number;
average: number;
frequencyRange: {
min: number;
max: number;
};
}
declare function getSpectralFeatures(audio: AudioData, options?: SpectralFeaturesOptions): Promise<SpectralFeaturesResult>;
declare function getTimeVaryingSpectralFeatures(audio: AudioData, options?: TimeVaryingSpectralOptions): Promise<TimeVaryingSpectralResult>;
declare function getSpectralEntropy(audio: AudioData, options?: SpectralEntropyOptions): Promise<SpectralEntropyResult>;
declare function getSpectralCrest(audio: AudioData, options?: SpectralCrestOptions): Promise<SpectralCrestResult>;
interface FramedTransformOptions extends SpectralRuntimeOptions {
frameSizeMs?: number;
hopSizeMs?: number;
fftSize?: number;
windowFunction?: WindowFunction;
channel?: ChannelSelector;
}
interface MelSpectrogramOptions extends FramedTransformOptions {
numMelFilters?: number;
minFrequency?: number;
maxFrequency?: number;
preEmphasis?: number;
power?: number;
logScale?: boolean;
logEpsilon?: number;
}
interface MelSpectrogramResult {
melSpectrogram: number[][];
times: Float32Array;
melFrequencies: Float32Array;
frameInfo: {
frameSizeMs: number;
hopSizeMs: number;
numFrames: number;
numBins: number;
};
frequencyRange: {
min: number;
max: number;
};
}
interface CQTOptions extends FramedTransformOptions {
fMin?: number;
binsPerOctave?: number;
numBins?: number;
preEmphasis?: number;
power?: number;
logScale?: boolean;
logEpsilon?: number;
}
interface CQTResult {
cqt: number[][];
times: Float32Array;
frequencies: Float32Array;
frameInfo: {
frameSizeMs: number;
hopSizeMs: number;
numFrames: number;
numBins: number;
binsPerOctave: number;
};
frequencyRange: {
min: number;
max: number;
};
}
interface MFCCOptions extends FramedTransformOptions {
numMelFilters?: number;
numMfccCoeffs?: number;
minFrequency?: number;
maxFrequency?: number;
preEmphasis?: number;
lifterCoeff?: number;
}
interface MFCCResult {
mfcc: number[][];
times: Float32Array;
frameInfo: {
frameSizeMs: number;
hopSizeMs: number;
numFrames: number;
numCoeffs: number;
};
frequencyRange: {
min: number;
max: number;
};
}
declare function getMelSpectrogram(audio: AudioData, options?: MelSpectrogramOptions): Promise<MelSpectrogramResult>;
declare function getCQT(audio: AudioData, options?: CQTOptions): Promise<CQTResult>;
declare function getMFCC(audio: AudioData, options?: MFCCOptions): Promise<MFCCResult>;
interface MFCCDeltaOptions extends MFCCOptions {
deltaWindowSize?: number;
computeDelta?: boolean;
computeDeltaDelta?: boolean;
}
interface MFCCDeltaResult extends MFCCResult {
delta?: number[][];
deltaDelta?: number[][];
}
declare function getMFCCWithDelta(audio: AudioData, options?: MFCCDeltaOptions): Promise<MFCCDeltaResult>;
interface EnergyOptions {
frameSize?: number;
hopSize?: number;
channel?: ChannelSelector;
normalized?: boolean;
windowFunction?: 'rectangular' | 'hann' | 'hamming' | 'blackman' | 'none';
}
interface EnergyResult {
times: Float32Array;
energies: Float32Array;
totalEnergy: number;
statistics: {
mean: number;
std: number;
max: number;
min: number;
};
}
declare function getEnergy(audio: AudioData, options?: EnergyOptions): EnergyResult;
interface CrestFactorOptions {
channel?: ChannelSelector;
windowSize?: number;
hopSize?: number;
method?: 'simple' | 'weighted';
}
interface CrestFactorResult {
crestFactor: number;
crestFactorLinear: number;
peak: number;
rms: number;
timeVarying?: {
times: Float32Array;
values: Float32Array;
valuesLinear: Float32Array;
peaks: Float32Array;
rmsValues: Float32Array;
} | undefined;
}
declare function getCrestFactor(audio: AudioData, options?: CrestFactorOptions): CrestFactorResult;
interface StereoAnalysisOptions {
frameSize?: number;
hopSize?: number;
calculatePhase?: boolean;
calculateITD?: boolean;
calculateILD?: boolean;
provider?: FFTProviderType;
enableProfiling?: boolean;
providerCache?: FFTProviderCache | undefined;
}
interface StereoAnalysisResult {
correlation: number;
coherence?: Float32Array;
width: number;
widthFrequency?: Float32Array;
balance: number;
phaseDifference?: number;
phaseCorrelation?: number;
midSideRatio: number;
itd?: number;
ild?: number;
goniometer?: {
x: Float32Array;
y: Float32Array;
};
}
declare function getStereoAnalysis(audio: AudioData, options?: StereoAnalysisOptions): Promise<StereoAnalysisResult>;
declare function getTimeVaryingStereoAnalysis(audio: AudioData, options?: StereoAnalysisOptions & {
windowSize?: number;
}): Promise<{
times: Float32Array;
correlation: Float32Array;
width: Float32Array;
balance: Float32Array;
}>;
interface VADOptions {
channel?: ChannelSelector;
frameSizeMs?: number;
hopSizeMs?: number;
method?: 'energy' | 'zcr' | 'combined' | 'adaptive';
energyThreshold?: number;
zcrThresholdLow?: number;
zcrThresholdHigh?: number;
adaptiveAlpha?: number;
noiseFactor?: number;
minSilenceDurationMs?: number;
minSpeechDurationMs?: number;
preEmphasis?: boolean;
smoothing?: boolean;
}
interface VADSegment {
start: number;
end: number;
type: 'speech' | 'silence';
confidence?: number;
}
interface VADResult {
segments: VADSegment[];
speechRatio: number;
features?: {
energies: Float32Array;
zcrs: Float32Array;
decisions: Float32Array;
times: Float32Array;
};
}
declare function getVAD(audio: AudioData, options?: VADOptions): VADResult;
interface LUFSOptions {
channelMode?: 'mono' | 'stereo';
gated?: boolean;
calculateShortTerm?: boolean;
calculateMomentary?: boolean;
/**
* Collect frame series in offline analysis.
* - true / 'both': collect both short-term and momentary series
* - 'shortTerm': collect only short-term series
* - 'momentary': collect only momentary series
*/
collectSeries?: boolean | 'shortTerm' | 'momentary' | 'both';
calculateLoudnessRange?: boolean;
calculateTruePeak?: boolean;
/**
* 'bs1770' uses the Annex 2 polyphase FIR true-peak estimator.
* 'interSamplePeak' keeps the legacy interpolation-based estimate.
*/
truePeakMethod?: 'bs1770' | 'interSamplePeak';
/**
* For 'bs1770', supported values are 2 or 4.
* For 'interSamplePeak', 2/4/8 are supported.
*/
truePeakOversamplingFactor?: 2 | 4 | 8;
truePeakInterpolation?: 'linear' | 'cubic' | 'sinc';
}
interface LUFSResult {
integrated: number;
shortTerm?: number;
momentary?: number;
loudnessRange?: number;
truePeak?: number[];
statistics?: {
percentile10: number;
percentile95: number;
};
series?: {
times: Float32Array;
shortTerm?: Float32Array;
momentary?: Float32Array;
};
}
declare function getLUFS(audio: AudioData, options?: LUFSOptions): LUFSResult;
declare class RealtimeLUFSProcessor {
private sampleRate;
private channelMode;
private blockSize;
private hopSize;
private blockBuffer;
private maxBlocks;
private currentSamples;
private filterStage1Scratch;
private filterStage2Scratch;
private sampleCount;
private biquadStates;
private totalSamplesProcessed;
private gated;
constructor(sampleRate: number, channelMode?: 'mono' | 'stereo', maxDurationMs?: number, gated?: boolean);
private ensureFilterScratchCapacity;
process(chunk: Float32Array[]): {
integrated: number;
momentary: number;
shortTerm: number;
};
private calculateCurrentLUFS;
reset(): void;
getBufferSize(): number;
}
interface RealtimeLUFSOptions {
channelMode?: 'mono' | 'stereo';
gated?: boolean;
maxDurationMs?: number;
}
declare function getLUFSRealtime(sampleRate: number, options?: RealtimeLUFSOptions): RealtimeLUFSProcessor;
export { type CQTOptions, type CQTResult, type CrestFactorOptions, type CrestFactorResult, type EnergyOptions, type EnergyResult, type FFTAnalysisResult, type FFTNormalization, type FFTOptions, type LUFSOptions, type LUFSResult, type MFCCDeltaOptions, type MFCCDeltaResult, type MFCCOptions, type MFCCResult, type MelSpectrogramOptions, type MelSpectrogramResult, type Peak, type PeaksAnalysisOptions, type PeaksOptions, type PeaksResult, type RMSAnalysisOptions, type RealtimeLUFSOptions, type SpectralCrestOptions, type SpectralCrestResult, type SpectralEntropyOptions, type SpectralEntropyResult, type SpectralFeaturesOptions, type SpectralFeaturesResult, type SpectrogramAnalysisResult, type SpectrogramOptions, type SpectrumAnalysisResult, type SpectrumOptions, type SpectrumScale, type StereoAnalysisOptions, type StereoAnalysisResult, type TimeVaryingSpectralOptions, type TimeVaryingSpectralResult, type VADOptions, type VADResult, type VADSegment, type WaveformAnalysisOptions, type WaveformOptions, type WaveformPoint, type WaveformResult, getCQT, getCrestFactor, getEnergy, getFFT, getLUFS, getLUFSRealtime, getMFCC, getMFCCWithDelta, getMelSpectrogram, getPeakAmplitude as getPeak, getPeakAmplitude, getPeaks, getPeaksAnalysis, getRMS, getRMSAnalysis, getSpectralCrest, getSpectralEntropy, getSpectralFeatures, getSpectrogram, getSpectrum, getStereoAnalysis, getTimeVaryingSpectralFeatures, getTimeVaryingStereoAnalysis, getVAD, getWaveform, getWaveformAnalysis, getZeroCrossing };