audio-ml 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +213 -0
- package/dist/analysis/AutocorrelationAnalyzer.d.ts +23 -0
- package/dist/analysis/AutocorrelationAnalyzer.d.ts.map +1 -0
- package/dist/analysis/AutocorrelationAnalyzer.js +26 -0
- package/dist/analysis/AutocorrelationAnalyzer.js.map +1 -0
- package/dist/analysis/ChromaFeaturesAnalyzer.d.ts +12 -0
- package/dist/analysis/ChromaFeaturesAnalyzer.d.ts.map +1 -0
- package/dist/analysis/ChromaFeaturesAnalyzer.js +33 -0
- package/dist/analysis/ChromaFeaturesAnalyzer.js.map +1 -0
- package/dist/analysis/ConstantQTransformAnalyzer.d.ts +31 -0
- package/dist/analysis/ConstantQTransformAnalyzer.d.ts.map +1 -0
- package/dist/analysis/ConstantQTransformAnalyzer.js +101 -0
- package/dist/analysis/ConstantQTransformAnalyzer.js.map +1 -0
- package/dist/analysis/FFTAnalyzer.d.ts +16 -0
- package/dist/analysis/FFTAnalyzer.d.ts.map +1 -0
- package/dist/analysis/FFTAnalyzer.js +36 -0
- package/dist/analysis/FFTAnalyzer.js.map +1 -0
- package/dist/analysis/LPCAnalyzer.d.ts +10 -0
- package/dist/analysis/LPCAnalyzer.d.ts.map +1 -0
- package/dist/analysis/LPCAnalyzer.js +34 -0
- package/dist/analysis/LPCAnalyzer.js.map +1 -0
- package/dist/analysis/MFCCAnalyzer.d.ts +40 -0
- package/dist/analysis/MFCCAnalyzer.d.ts.map +1 -0
- package/dist/analysis/MFCCAnalyzer.js +101 -0
- package/dist/analysis/MFCCAnalyzer.js.map +1 -0
- package/dist/analysis/MelSpectrogramAnalyzer.d.ts +33 -0
- package/dist/analysis/MelSpectrogramAnalyzer.d.ts.map +1 -0
- package/dist/analysis/MelSpectrogramAnalyzer.js +86 -0
- package/dist/analysis/MelSpectrogramAnalyzer.js.map +1 -0
- package/dist/analysis/PLPAnalyzer.d.ts +47 -0
- package/dist/analysis/PLPAnalyzer.d.ts.map +1 -0
- package/dist/analysis/PLPAnalyzer.js +176 -0
- package/dist/analysis/PLPAnalyzer.js.map +1 -0
- package/dist/analysis/RMSEAnalyzer.d.ts +21 -0
- package/dist/analysis/RMSEAnalyzer.d.ts.map +1 -0
- package/dist/analysis/RMSEAnalyzer.js +20 -0
- package/dist/analysis/RMSEAnalyzer.js.map +1 -0
- package/dist/analysis/SpectralBandwidthAnalyzer.d.ts +22 -0
- package/dist/analysis/SpectralBandwidthAnalyzer.d.ts.map +1 -0
- package/dist/analysis/SpectralBandwidthAnalyzer.js +51 -0
- package/dist/analysis/SpectralBandwidthAnalyzer.js.map +1 -0
- package/dist/analysis/SpectralCentroidAnalyzer.d.ts +22 -0
- package/dist/analysis/SpectralCentroidAnalyzer.d.ts.map +1 -0
- package/dist/analysis/SpectralCentroidAnalyzer.js +44 -0
- package/dist/analysis/SpectralCentroidAnalyzer.js.map +1 -0
- package/dist/analysis/SpectralFlatnessAnalyzer.d.ts +21 -0
- package/dist/analysis/SpectralFlatnessAnalyzer.d.ts.map +1 -0
- package/dist/analysis/SpectralFlatnessAnalyzer.js +37 -0
- package/dist/analysis/SpectralFlatnessAnalyzer.js.map +1 -0
- package/dist/analysis/SpectralRolloffAnalyzer.d.ts +25 -0
- package/dist/analysis/SpectralRolloffAnalyzer.d.ts.map +1 -0
- package/dist/analysis/SpectralRolloffAnalyzer.js +48 -0
- package/dist/analysis/SpectralRolloffAnalyzer.js.map +1 -0
- package/dist/analysis/WaveformEnvelopeAnalyzer.d.ts +23 -0
- package/dist/analysis/WaveformEnvelopeAnalyzer.d.ts.map +1 -0
- package/dist/analysis/WaveformEnvelopeAnalyzer.js +28 -0
- package/dist/analysis/WaveformEnvelopeAnalyzer.js.map +1 -0
- package/dist/analysis/WaveletTransformAnalyzer.d.ts +10 -0
- package/dist/analysis/WaveletTransformAnalyzer.d.ts.map +1 -0
- package/dist/analysis/WaveletTransformAnalyzer.js +25 -0
- package/dist/analysis/WaveletTransformAnalyzer.js.map +1 -0
- package/dist/analysis/ZeroCrossingRateAnalyzer.d.ts +21 -0
- package/dist/analysis/ZeroCrossingRateAnalyzer.d.ts.map +1 -0
- package/dist/analysis/ZeroCrossingRateAnalyzer.js +22 -0
- package/dist/analysis/ZeroCrossingRateAnalyzer.js.map +1 -0
- package/dist/analysis/index.d.ts +31 -0
- package/dist/analysis/index.d.ts.map +1 -0
- package/dist/analysis/index.js +35 -0
- package/dist/analysis/index.js.map +1 -0
- package/package.json +57 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MFCCAnalyzer extracts Mel-Frequency Cepstral Coefficients (MFCCs) from PCM audio frames.
|
|
3
|
+
* MFCCs are widely used features in speech and audio processing, representing the short-term power spectrum of sound on a mel scale.
|
|
4
|
+
* This class uses FFT for spectral analysis, applies a mel filter bank, takes the log, and then applies a Discrete Cosine Transform (DCT).
|
|
5
|
+
* Usage: const mfcc = new MFCCAnalyzer({ sampleRate: 16000 }); mfcc.analyzeFrame(pcm)
|
|
6
|
+
*/
|
|
7
|
+
import FFT from 'fft.js';
|
|
8
|
+
export class MFCCAnalyzer {
|
|
9
|
+
fft;
|
|
10
|
+
fftSize;
|
|
11
|
+
melBands;
|
|
12
|
+
numCoeffs;
|
|
13
|
+
sampleRate;
|
|
14
|
+
melFilters;
|
|
15
|
+
/**
|
|
16
|
+
* @param config - MFCC extraction configuration
|
|
17
|
+
*/
|
|
18
|
+
constructor(config) {
|
|
19
|
+
this.fftSize = config.fftSize || 1024;
|
|
20
|
+
this.melBands = config.melBands || 26;
|
|
21
|
+
this.numCoeffs = config.numCoeffs || 13;
|
|
22
|
+
this.sampleRate = config.sampleRate;
|
|
23
|
+
this.fft = new FFT(this.fftSize);
|
|
24
|
+
this.melFilters = this.createMelFilterBank();
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Extract MFCCs from a PCM frame.
|
|
28
|
+
* @param pcm - Input PCM audio frame (Float32Array, length = fftSize)
|
|
29
|
+
* @returns Array of MFCC coefficients (length = numCoeffs)
|
|
30
|
+
*/
|
|
31
|
+
analyzeFrame(pcm) {
|
|
32
|
+
if (pcm.length !== this.fftSize)
|
|
33
|
+
throw new Error('PCM frame must be fftSize');
|
|
34
|
+
const spectrum = this.fft.createComplexArray();
|
|
35
|
+
this.fft.realTransform(spectrum, pcm);
|
|
36
|
+
this.fft.completeSpectrum(spectrum);
|
|
37
|
+
const mags = [];
|
|
38
|
+
for (let i = 0; i < this.fftSize / 2; i++) {
|
|
39
|
+
const re = spectrum[2 * i];
|
|
40
|
+
const im = spectrum[2 * i + 1];
|
|
41
|
+
mags.push(Math.sqrt(re * re + im * im));
|
|
42
|
+
}
|
|
43
|
+
const melEnergies = this.melFilters.map(filter => filter.reduce((sum, w, k) => sum + w * mags[k], 0));
|
|
44
|
+
const logMel = melEnergies.map(e => Math.log(e + 1e-6));
|
|
45
|
+
return this.dct(logMel).slice(0, this.numCoeffs);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Create a mel filter bank matrix.
|
|
49
|
+
* @returns Array of mel filters (each filter is an array of weights for FFT bins)
|
|
50
|
+
*/
|
|
51
|
+
createMelFilterBank() {
|
|
52
|
+
const filters = [];
|
|
53
|
+
const lowFreq = 0;
|
|
54
|
+
const highFreq = this.sampleRate / 2;
|
|
55
|
+
const melLow = this.hzToMel(lowFreq);
|
|
56
|
+
const melHigh = this.hzToMel(highFreq);
|
|
57
|
+
const melPoints = [];
|
|
58
|
+
for (let i = 0; i <= this.melBands + 2; i++) {
|
|
59
|
+
melPoints.push(melLow + (melHigh - melLow) * i / (this.melBands + 2));
|
|
60
|
+
}
|
|
61
|
+
const hzPoints = melPoints.map(mel => this.melToHz(mel));
|
|
62
|
+
const binPoints = hzPoints.map(hz => Math.floor((this.fftSize + 1) * hz / this.sampleRate));
|
|
63
|
+
for (let i = 0; i < this.melBands; i++) {
|
|
64
|
+
const filter = new Array(this.fftSize / 2).fill(0);
|
|
65
|
+
for (let j = binPoints[i]; j < binPoints[i + 1]; j++) {
|
|
66
|
+
filter[j] = (j - binPoints[i]) / (binPoints[i + 1] - binPoints[i]);
|
|
67
|
+
}
|
|
68
|
+
for (let j = binPoints[i + 1]; j < binPoints[i + 2]; j++) {
|
|
69
|
+
filter[j] = (binPoints[i + 2] - j) / (binPoints[i + 2] - binPoints[i + 1]);
|
|
70
|
+
}
|
|
71
|
+
filters.push(filter);
|
|
72
|
+
}
|
|
73
|
+
return filters;
|
|
74
|
+
}
|
|
75
|
+
/** Convert Hz to mel scale */
|
|
76
|
+
hzToMel(hz) {
|
|
77
|
+
return 2595 * Math.log10(1 + hz / 700);
|
|
78
|
+
}
|
|
79
|
+
/** Convert mel scale to Hz */
|
|
80
|
+
melToHz(mel) {
|
|
81
|
+
return 700 * (Math.pow(10, mel / 2595) - 1);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Discrete Cosine Transform (DCT-II) for MFCCs.
|
|
85
|
+
* @param vector - Input array (log-mel energies)
|
|
86
|
+
* @returns DCT coefficients
|
|
87
|
+
*/
|
|
88
|
+
dct(vector) {
|
|
89
|
+
const N = vector.length;
|
|
90
|
+
const result = new Array(N).fill(0);
|
|
91
|
+
for (let k = 0; k < N; k++) {
|
|
92
|
+
let sum = 0;
|
|
93
|
+
for (let n = 0; n < N; n++) {
|
|
94
|
+
sum += vector[n] * Math.cos(Math.PI * k * (2 * n + 1) / (2 * N));
|
|
95
|
+
}
|
|
96
|
+
result[k] = sum;
|
|
97
|
+
}
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=MFCCAnalyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MFCCAnalyzer.js","sourceRoot":"","sources":["../../src/analysis/MFCCAnalyzer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface MelSpectrogramConfig {
|
|
2
|
+
sampleRate: number;
|
|
3
|
+
fftSize?: number;
|
|
4
|
+
melBands?: number;
|
|
5
|
+
}
|
|
6
|
+
export declare class MelSpectrogramAnalyzer {
|
|
7
|
+
private fft;
|
|
8
|
+
private fftSize;
|
|
9
|
+
private melBands;
|
|
10
|
+
private sampleRate;
|
|
11
|
+
private melFilters;
|
|
12
|
+
constructor(config: MelSpectrogramConfig);
|
|
13
|
+
/**
|
|
14
|
+
* Analyze a single frame of PCM samples and return mel spectrogram features.
|
|
15
|
+
* @param pcm - Input PCM audio frame (must be fftSize samples)
|
|
16
|
+
* @returns Array of log-mel energies
|
|
17
|
+
*/
|
|
18
|
+
analyzeFrame(pcm: Float32Array): number[];
|
|
19
|
+
/**
|
|
20
|
+
* Create mel filter bank.
|
|
21
|
+
* @returns Array of mel filters (each filter is an array of weights for FFT bins)
|
|
22
|
+
*/
|
|
23
|
+
private createMelFilterBank;
|
|
24
|
+
/**
|
|
25
|
+
* Convert Hz to mel scale.
|
|
26
|
+
*/
|
|
27
|
+
private hzToMel;
|
|
28
|
+
/**
|
|
29
|
+
* Convert mel scale to Hz.
|
|
30
|
+
*/
|
|
31
|
+
private melToHz;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=MelSpectrogramAnalyzer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MelSpectrogramAnalyzer.d.ts","sourceRoot":"","sources":["../../src/analysis/MelSpectrogramAnalyzer.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,sBAAsB;IACjC,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,UAAU,CAAa;gBAEnB,MAAM,EAAE,oBAAoB;IAQxC;;;;OAIG;IACH,YAAY,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,EAAE;IAyBzC;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IA0B3B;;OAEG;IACH,OAAO,CAAC,OAAO;IAIf;;OAEG;IACH,OAAO,CAAC,OAAO;CAGhB"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MelSpectrogramAnalyzer computes mel spectrogram features from PCM audio frames.
|
|
3
|
+
* Mel spectrogram applies a mel filter bank to the FFT spectrum and returns log-mel energies.
|
|
4
|
+
* This is similar to MFCC but without the DCT step.
|
|
5
|
+
* Usage: const mel = new MelSpectrogramAnalyzer({ sampleRate: 16000 }); mel.analyzeFrame(pcm)
|
|
6
|
+
*/
|
|
7
|
+
import FFT from 'fft.js';
|
|
8
|
+
export class MelSpectrogramAnalyzer {
|
|
9
|
+
fft;
|
|
10
|
+
fftSize;
|
|
11
|
+
melBands;
|
|
12
|
+
sampleRate;
|
|
13
|
+
melFilters;
|
|
14
|
+
constructor(config) {
|
|
15
|
+
this.fftSize = config.fftSize || 1024;
|
|
16
|
+
this.melBands = config.melBands || 40;
|
|
17
|
+
this.sampleRate = config.sampleRate;
|
|
18
|
+
this.fft = new FFT(this.fftSize);
|
|
19
|
+
this.melFilters = this.createMelFilterBank();
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Analyze a single frame of PCM samples and return mel spectrogram features.
|
|
23
|
+
* @param pcm - Input PCM audio frame (must be fftSize samples)
|
|
24
|
+
* @returns Array of log-mel energies
|
|
25
|
+
*/
|
|
26
|
+
analyzeFrame(pcm) {
|
|
27
|
+
if (pcm.length !== this.fftSize) {
|
|
28
|
+
throw new Error(`PCM frame must be fftSize (${this.fftSize}) samples`);
|
|
29
|
+
}
|
|
30
|
+
const spectrum = this.fft.createComplexArray();
|
|
31
|
+
this.fft.realTransform(spectrum, pcm);
|
|
32
|
+
this.fft.completeSpectrum(spectrum);
|
|
33
|
+
// Get magnitude spectrum
|
|
34
|
+
const mags = [];
|
|
35
|
+
for (let i = 0; i < this.fftSize / 2; i++) {
|
|
36
|
+
const re = spectrum[2 * i];
|
|
37
|
+
const im = spectrum[2 * i + 1];
|
|
38
|
+
mags.push(Math.sqrt(re * re + im * im));
|
|
39
|
+
}
|
|
40
|
+
// Apply mel filter bank
|
|
41
|
+
const melEnergies = this.melFilters.map(filter => filter.reduce((sum, w, k) => sum + w * mags[k], 0));
|
|
42
|
+
// Log scaling
|
|
43
|
+
return melEnergies.map(e => Math.log(e + 1e-6));
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Create mel filter bank.
|
|
47
|
+
* @returns Array of mel filters (each filter is an array of weights for FFT bins)
|
|
48
|
+
*/
|
|
49
|
+
createMelFilterBank() {
|
|
50
|
+
const filters = [];
|
|
51
|
+
const lowFreq = 0;
|
|
52
|
+
const highFreq = this.sampleRate / 2;
|
|
53
|
+
const melLow = this.hzToMel(lowFreq);
|
|
54
|
+
const melHigh = this.hzToMel(highFreq);
|
|
55
|
+
const melPoints = [];
|
|
56
|
+
for (let i = 0; i <= this.melBands + 2; i++) {
|
|
57
|
+
melPoints.push(melLow + (melHigh - melLow) * i / (this.melBands + 2));
|
|
58
|
+
}
|
|
59
|
+
const hzPoints = melPoints.map(mel => this.melToHz(mel));
|
|
60
|
+
const binPoints = hzPoints.map(hz => Math.floor((this.fftSize + 1) * hz / this.sampleRate));
|
|
61
|
+
for (let i = 0; i < this.melBands; i++) {
|
|
62
|
+
const filter = new Array(this.fftSize / 2).fill(0);
|
|
63
|
+
for (let j = binPoints[i]; j < binPoints[i + 1]; j++) {
|
|
64
|
+
filter[j] = (j - binPoints[i]) / (binPoints[i + 1] - binPoints[i]);
|
|
65
|
+
}
|
|
66
|
+
for (let j = binPoints[i + 1]; j < binPoints[i + 2]; j++) {
|
|
67
|
+
filter[j] = (binPoints[i + 2] - j) / (binPoints[i + 2] - binPoints[i + 1]);
|
|
68
|
+
}
|
|
69
|
+
filters.push(filter);
|
|
70
|
+
}
|
|
71
|
+
return filters;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Convert Hz to mel scale.
|
|
75
|
+
*/
|
|
76
|
+
hzToMel(hz) {
|
|
77
|
+
return 2595 * Math.log10(1 + hz / 700);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Convert mel scale to Hz.
|
|
81
|
+
*/
|
|
82
|
+
melToHz(mel) {
|
|
83
|
+
return 700 * (Math.pow(10, mel / 2595) - 1);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=MelSpectrogramAnalyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MelSpectrogramAnalyzer.js","sourceRoot":"","sources":["../../src/analysis/MelSpectrogramAnalyzer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export interface PLPConfig {
|
|
2
|
+
sampleRate: number;
|
|
3
|
+
fftSize?: number;
|
|
4
|
+
order?: number;
|
|
5
|
+
numBands?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare class PLPAnalyzer {
|
|
8
|
+
private fft;
|
|
9
|
+
private fftSize;
|
|
10
|
+
private order;
|
|
11
|
+
private numBands;
|
|
12
|
+
private sampleRate;
|
|
13
|
+
private barkFilters;
|
|
14
|
+
/**
|
|
15
|
+
* @param config - Configuration with sample rate, optional FFT size, LPC order, and number of critical bands
|
|
16
|
+
*/
|
|
17
|
+
constructor(config: PLPConfig);
|
|
18
|
+
/**
|
|
19
|
+
* Extract PLP coefficients from a PCM frame.
|
|
20
|
+
* @param pcm - Input PCM audio frame
|
|
21
|
+
* @returns Array of PLP coefficients
|
|
22
|
+
*/
|
|
23
|
+
analyzeFrame(pcm: Float32Array): number[];
|
|
24
|
+
/**
|
|
25
|
+
* Create a Bark scale filter bank.
|
|
26
|
+
* @returns Array of Bark filters
|
|
27
|
+
*/
|
|
28
|
+
private createBarkFilterBank;
|
|
29
|
+
/**
|
|
30
|
+
* Convert Hz to Bark scale.
|
|
31
|
+
*/
|
|
32
|
+
private hzToBark;
|
|
33
|
+
/**
|
|
34
|
+
* Equal loudness pre-emphasis weight.
|
|
35
|
+
*/
|
|
36
|
+
private equalLoudnessWeight;
|
|
37
|
+
/**
|
|
38
|
+
* Convert Bark domain loudness to autocorrelation via inverse FFT.
|
|
39
|
+
* Interpolates Bark domain loudness back to frequency domain, then computes autocorrelation.
|
|
40
|
+
*/
|
|
41
|
+
private barkToAutocorr;
|
|
42
|
+
/**
|
|
43
|
+
* Levinson-Durbin recursion for LPC coefficients.
|
|
44
|
+
*/
|
|
45
|
+
private levinsonDurbin;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=PLPAnalyzer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PLPAnalyzer.d.ts","sourceRoot":"","sources":["../../src/analysis/PLPAnalyzer.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,SAAS;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAAa;IAEhC;;OAEG;gBACS,MAAM,EAAE,SAAS;IAS7B;;;;OAIG;IACH,YAAY,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,EAAE;IAuCzC;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAkC5B;;OAEG;IACH,OAAO,CAAC,QAAQ;IAIhB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAM3B;;;OAGG;IACH,OAAO,CAAC,cAAc;IAkDtB;;OAEG;IACH,OAAO,CAAC,cAAc;CAqBvB"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PLPAnalyzer extracts Perceptual Linear Prediction (PLP) coefficients from PCM audio frames.
|
|
3
|
+
* PLP is used in speech processing to model the auditory spectrum using perceptual principles.
|
|
4
|
+
* This implementation includes critical band analysis, equal loudness pre-emphasis, and LPC analysis.
|
|
5
|
+
* Usage: const plp = new PLPAnalyzer({ sampleRate: 16000 }); plp.analyzeFrame(pcm)
|
|
6
|
+
*/
|
|
7
|
+
import FFT from 'fft.js';
|
|
8
|
+
export class PLPAnalyzer {
|
|
9
|
+
fft;
|
|
10
|
+
fftSize;
|
|
11
|
+
order;
|
|
12
|
+
numBands;
|
|
13
|
+
sampleRate;
|
|
14
|
+
barkFilters;
|
|
15
|
+
/**
|
|
16
|
+
* @param config - Configuration with sample rate, optional FFT size, LPC order, and number of critical bands
|
|
17
|
+
*/
|
|
18
|
+
constructor(config) {
|
|
19
|
+
this.fftSize = config.fftSize || 512;
|
|
20
|
+
this.order = config.order || 12;
|
|
21
|
+
this.numBands = config.numBands || 18;
|
|
22
|
+
this.sampleRate = config.sampleRate;
|
|
23
|
+
this.fft = new FFT(this.fftSize);
|
|
24
|
+
this.barkFilters = this.createBarkFilterBank();
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Extract PLP coefficients from a PCM frame.
|
|
28
|
+
* @param pcm - Input PCM audio frame
|
|
29
|
+
* @returns Array of PLP coefficients
|
|
30
|
+
*/
|
|
31
|
+
analyzeFrame(pcm) {
|
|
32
|
+
// Ensure correct frame size
|
|
33
|
+
if (pcm.length !== this.fftSize) {
|
|
34
|
+
throw new Error(`PCM frame must be fftSize (${this.fftSize}) samples, got ${pcm.length}`);
|
|
35
|
+
}
|
|
36
|
+
// Step 1: Compute power spectrum
|
|
37
|
+
const spectrum = this.fft.createComplexArray();
|
|
38
|
+
this.fft.realTransform(spectrum, pcm);
|
|
39
|
+
this.fft.completeSpectrum(spectrum);
|
|
40
|
+
const powerSpectrum = [];
|
|
41
|
+
for (let i = 0; i < this.fftSize / 2; i++) {
|
|
42
|
+
const re = spectrum[2 * i];
|
|
43
|
+
const im = spectrum[2 * i + 1];
|
|
44
|
+
powerSpectrum.push(re * re + im * im);
|
|
45
|
+
}
|
|
46
|
+
// Step 2: Critical band analysis (Bark scale)
|
|
47
|
+
const barkEnergies = this.barkFilters.map(filter => filter.reduce((sum, w, k) => sum + w * powerSpectrum[k], 0));
|
|
48
|
+
// Step 3: Equal loudness pre-emphasis
|
|
49
|
+
const preemphasized = barkEnergies.map((energy, i) => {
|
|
50
|
+
const bark = i * 1.0; // Approximate bark value
|
|
51
|
+
const equalLoudness = this.equalLoudnessWeight(bark);
|
|
52
|
+
return energy * equalLoudness;
|
|
53
|
+
});
|
|
54
|
+
// Step 4: Intensity-loudness conversion (cube root)
|
|
55
|
+
const loudness = preemphasized.map(e => Math.pow(e + 1e-12, 1.0 / 3.0));
|
|
56
|
+
// Step 5: Inverse FFT to get autocorrelation
|
|
57
|
+
const autocorr = this.barkToAutocorr(loudness);
|
|
58
|
+
// Step 6: LPC analysis using Levinson-Durbin
|
|
59
|
+
return this.levinsonDurbin(autocorr, this.order);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Create a Bark scale filter bank.
|
|
63
|
+
* @returns Array of Bark filters
|
|
64
|
+
*/
|
|
65
|
+
createBarkFilterBank() {
|
|
66
|
+
const filters = [];
|
|
67
|
+
const nyquist = this.sampleRate / 2;
|
|
68
|
+
const maxBark = this.hzToBark(nyquist);
|
|
69
|
+
for (let band = 0; band < this.numBands; band++) {
|
|
70
|
+
const filter = new Array(this.fftSize / 2).fill(0);
|
|
71
|
+
const centerBark = (band + 0.5) * maxBark / this.numBands;
|
|
72
|
+
for (let i = 0; i < this.fftSize / 2; i++) {
|
|
73
|
+
const freq = (i * this.sampleRate) / this.fftSize;
|
|
74
|
+
const bark = this.hzToBark(freq);
|
|
75
|
+
const distance = Math.abs(bark - centerBark);
|
|
76
|
+
// Triangular filter shape
|
|
77
|
+
if (distance < 1.0) {
|
|
78
|
+
filter[i] = 1.0 - distance;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Normalize
|
|
82
|
+
const sum = filter.reduce((a, b) => a + b, 0);
|
|
83
|
+
if (sum > 0) {
|
|
84
|
+
for (let i = 0; i < filter.length; i++) {
|
|
85
|
+
filter[i] /= sum;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
filters.push(filter);
|
|
89
|
+
}
|
|
90
|
+
return filters;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Convert Hz to Bark scale.
|
|
94
|
+
*/
|
|
95
|
+
hzToBark(hz) {
|
|
96
|
+
return 13 * Math.atan(0.00076 * hz) + 3.5 * Math.atan(Math.pow(hz / 7500, 2));
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Equal loudness pre-emphasis weight.
|
|
100
|
+
*/
|
|
101
|
+
equalLoudnessWeight(bark) {
|
|
102
|
+
// Simplified equal loudness curve
|
|
103
|
+
const w = 1.0 / (1.0 + Math.pow(bark / 15.0, 2));
|
|
104
|
+
return w;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Convert Bark domain loudness to autocorrelation via inverse FFT.
|
|
108
|
+
* Interpolates Bark domain loudness back to frequency domain, then computes autocorrelation.
|
|
109
|
+
*/
|
|
110
|
+
barkToAutocorr(loudness) {
|
|
111
|
+
// Interpolate Bark domain loudness back to frequency domain
|
|
112
|
+
const nyquist = this.sampleRate / 2;
|
|
113
|
+
const maxBark = this.hzToBark(nyquist);
|
|
114
|
+
const freqSpectrum = new Array(this.fftSize / 2).fill(0);
|
|
115
|
+
for (let i = 0; i < this.fftSize / 2; i++) {
|
|
116
|
+
const freq = (i * this.sampleRate) / this.fftSize;
|
|
117
|
+
const bark = this.hzToBark(freq);
|
|
118
|
+
const bandIndex = (bark / maxBark) * this.numBands;
|
|
119
|
+
// Linear interpolation
|
|
120
|
+
const lowerBand = Math.floor(bandIndex);
|
|
121
|
+
const upperBand = Math.min(Math.ceil(bandIndex), this.numBands - 1);
|
|
122
|
+
const t = bandIndex - lowerBand;
|
|
123
|
+
if (lowerBand >= 0 && lowerBand < loudness.length && upperBand >= 0 && upperBand < loudness.length) {
|
|
124
|
+
freqSpectrum[i] = loudness[lowerBand] * (1 - t) + loudness[upperBand] * t;
|
|
125
|
+
}
|
|
126
|
+
else if (lowerBand >= 0 && lowerBand < loudness.length) {
|
|
127
|
+
freqSpectrum[i] = loudness[lowerBand];
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// Pad to fftSize for IFFT (mirror for real signal)
|
|
131
|
+
const padded = new Array(this.fftSize).fill(0);
|
|
132
|
+
for (let i = 0; i < this.fftSize / 2; i++) {
|
|
133
|
+
padded[i] = freqSpectrum[i];
|
|
134
|
+
if (i > 0) {
|
|
135
|
+
padded[this.fftSize - i] = freqSpectrum[i]; // Mirror for real IFFT
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// Inverse FFT to get autocorrelation
|
|
139
|
+
const input = this.fft.createComplexArray();
|
|
140
|
+
const output = this.fft.createComplexArray();
|
|
141
|
+
for (let i = 0; i < padded.length; i++) {
|
|
142
|
+
input[2 * i] = padded[i];
|
|
143
|
+
input[2 * i + 1] = 0;
|
|
144
|
+
}
|
|
145
|
+
this.fft.inverseTransform(output, input);
|
|
146
|
+
// Extract autocorrelation (first order+1 values)
|
|
147
|
+
const autocorr = new Array(this.order + 1).fill(0);
|
|
148
|
+
for (let i = 0; i <= this.order; i++) {
|
|
149
|
+
autocorr[i] = output[2 * i] / this.fftSize;
|
|
150
|
+
}
|
|
151
|
+
return autocorr;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Levinson-Durbin recursion for LPC coefficients.
|
|
155
|
+
*/
|
|
156
|
+
levinsonDurbin(R, order) {
|
|
157
|
+
const a = new Array(order + 1).fill(0);
|
|
158
|
+
const e = new Array(order + 1).fill(0);
|
|
159
|
+
a[0] = 1;
|
|
160
|
+
e[0] = R[0];
|
|
161
|
+
for (let i = 1; i <= order; i++) {
|
|
162
|
+
let acc = 0;
|
|
163
|
+
for (let j = 1; j < i; j++) {
|
|
164
|
+
acc += a[j] * R[i - j];
|
|
165
|
+
}
|
|
166
|
+
const k = (R[i] - acc) / (e[i - 1] + 1e-12);
|
|
167
|
+
a[i] = k;
|
|
168
|
+
for (let j = 1; j < i; j++) {
|
|
169
|
+
a[j] = a[j] - k * a[i - j];
|
|
170
|
+
}
|
|
171
|
+
e[i] = (1 - k * k) * e[i - 1];
|
|
172
|
+
}
|
|
173
|
+
return a.slice(1);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=PLPAnalyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PLPAnalyzer.js","sourceRoot":"","sources":["../../src/analysis/PLPAnalyzer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RMSEAnalyzer computes the Root Mean Square Energy (RMSE) of a PCM audio frame.
|
|
3
|
+
* RMSE is a simple measure of signal energy, useful for detecting silence, loudness, or dynamic range.
|
|
4
|
+
* Usage: const rmse = new RMSEAnalyzer({ sampleRate: 16000 }); rmse.analyzeFrame(pcm)
|
|
5
|
+
*/
|
|
6
|
+
export interface RMSEConfig {
|
|
7
|
+
sampleRate: number;
|
|
8
|
+
}
|
|
9
|
+
export declare class RMSEAnalyzer {
|
|
10
|
+
/**
|
|
11
|
+
* @param _config - Configuration with sample rate
|
|
12
|
+
*/
|
|
13
|
+
constructor(_config: RMSEConfig);
|
|
14
|
+
/**
|
|
15
|
+
* Compute the root mean square energy for a PCM frame.
|
|
16
|
+
* @param pcm - Input PCM audio frame
|
|
17
|
+
* @returns RMSE value
|
|
18
|
+
*/
|
|
19
|
+
analyzeFrame(pcm: Float32Array): number;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=RMSEAnalyzer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RMSEAnalyzer.d.ts","sourceRoot":"","sources":["../../src/analysis/RMSEAnalyzer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,UAAU;IAAG,UAAU,EAAE,MAAM,CAAA;CAAE;AAElD,qBAAa,YAAY;IACvB;;OAEG;gBACS,OAAO,EAAE,UAAU;IAE/B;;;;OAIG;IACH,YAAY,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM;CAOxC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export class RMSEAnalyzer {
|
|
2
|
+
/**
|
|
3
|
+
* @param _config - Configuration with sample rate
|
|
4
|
+
*/
|
|
5
|
+
constructor(_config) {
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Compute the root mean square energy for a PCM frame.
|
|
9
|
+
* @param pcm - Input PCM audio frame
|
|
10
|
+
* @returns RMSE value
|
|
11
|
+
*/
|
|
12
|
+
analyzeFrame(pcm) {
|
|
13
|
+
let sum = 0;
|
|
14
|
+
for (let i = 0; i < pcm.length; i++) {
|
|
15
|
+
sum += pcm[i] * pcm[i];
|
|
16
|
+
}
|
|
17
|
+
return Math.sqrt(sum / pcm.length);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=RMSEAnalyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RMSEAnalyzer.js","sourceRoot":"","sources":["../../src/analysis/RMSEAnalyzer.ts"],"names":[],"mappings":"AAOA,MAAM,OAAO,YAAY;IACvB;;OAEG;IACH,YAAY,OAAmB;IAC/B,CAAC;IACD;;;;OAIG;IACH,YAAY,CAAC,GAAiB;QAC5B,IAAI,GAAG,GAAG,CAAC,CAAC;QACZ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACpC,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;QACzB,CAAC;QACD,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC;CACF"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface SpectralBandwidthConfig {
|
|
2
|
+
/** Sample rate of the audio (Hz) */
|
|
3
|
+
sampleRate: number;
|
|
4
|
+
/** FFT size (default: 1024) */
|
|
5
|
+
fftSize?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare class SpectralBandwidthAnalyzer {
|
|
8
|
+
private fft;
|
|
9
|
+
private fftSize;
|
|
10
|
+
private sampleRate;
|
|
11
|
+
/**
|
|
12
|
+
* @param config - Configuration with sample rate and optional FFT size
|
|
13
|
+
*/
|
|
14
|
+
constructor(config: SpectralBandwidthConfig);
|
|
15
|
+
/**
|
|
16
|
+
* Compute the spectral bandwidth for a PCM frame.
|
|
17
|
+
* @param pcm - Input PCM audio frame
|
|
18
|
+
* @returns Spectral bandwidth in Hz
|
|
19
|
+
*/
|
|
20
|
+
analyzeFrame(pcm: Float32Array): number;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=SpectralBandwidthAnalyzer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SpectralBandwidthAnalyzer.d.ts","sourceRoot":"","sources":["../../src/analysis/SpectralBandwidthAnalyzer.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,uBAAuB;IACtC,oCAAoC;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,+BAA+B;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,yBAAyB;IACpC,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,UAAU,CAAS;IAC3B;;OAEG;gBACS,MAAM,EAAE,uBAAuB;IAK3C;;;;OAIG;IACH,YAAY,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM;CAyBxC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SpectralBandwidthAnalyzer computes the spectral bandwidth of a PCM audio frame.
|
|
3
|
+
* The spectral bandwidth is the spread of the spectrum around the centroid, related to the perceived timbre of a sound.
|
|
4
|
+
* Usage: const sb = new SpectralBandwidthAnalyzer({ sampleRate: 16000 }); sb.analyzeFrame(pcm)
|
|
5
|
+
*/
|
|
6
|
+
import FFT from 'fft.js';
|
|
7
|
+
export class SpectralBandwidthAnalyzer {
|
|
8
|
+
fft;
|
|
9
|
+
fftSize;
|
|
10
|
+
sampleRate;
|
|
11
|
+
/**
|
|
12
|
+
* @param config - Configuration with sample rate and optional FFT size
|
|
13
|
+
*/
|
|
14
|
+
constructor(config) {
|
|
15
|
+
this.fftSize = config.fftSize || 1024;
|
|
16
|
+
this.fft = new FFT(this.fftSize);
|
|
17
|
+
this.sampleRate = config.sampleRate;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Compute the spectral bandwidth for a PCM frame.
|
|
21
|
+
* @param pcm - Input PCM audio frame
|
|
22
|
+
* @returns Spectral bandwidth in Hz
|
|
23
|
+
*/
|
|
24
|
+
analyzeFrame(pcm) {
|
|
25
|
+
const spectrum = this.fft.createComplexArray();
|
|
26
|
+
this.fft.realTransform(spectrum, pcm);
|
|
27
|
+
this.fft.completeSpectrum(spectrum);
|
|
28
|
+
let mags = [];
|
|
29
|
+
for (let i = 0; i < this.fftSize / 2; i++) {
|
|
30
|
+
const re = spectrum[2 * i];
|
|
31
|
+
const im = spectrum[2 * i + 1];
|
|
32
|
+
mags.push(Math.sqrt(re * re + im * im));
|
|
33
|
+
}
|
|
34
|
+
// Spectral centroid
|
|
35
|
+
let num = 0, denom = 0;
|
|
36
|
+
for (let i = 0; i < mags.length; i++) {
|
|
37
|
+
num += i * mags[i];
|
|
38
|
+
denom += mags[i];
|
|
39
|
+
}
|
|
40
|
+
if (denom === 0)
|
|
41
|
+
return 0;
|
|
42
|
+
const centroid = (num / denom);
|
|
43
|
+
// Bandwidth
|
|
44
|
+
let spread = 0;
|
|
45
|
+
for (let i = 0; i < mags.length; i++) {
|
|
46
|
+
spread += mags[i] * Math.pow(i - centroid, 2);
|
|
47
|
+
}
|
|
48
|
+
return Math.sqrt(spread / denom) * (this.sampleRate / 2) / mags.length;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=SpectralBandwidthAnalyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SpectralBandwidthAnalyzer.js","sourceRoot":"","sources":["../../src/analysis/SpectralBandwidthAnalyzer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,GAAG,MAAM,QAAQ,CAAC;AASzB,MAAM,OAAO,yBAAyB;IAC5B,GAAG,CAAM;IACT,OAAO,CAAS;IAChB,UAAU,CAAS;IAC3B;;OAEG;IACH,YAAY,MAA+B;QACzC,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,IAAI,CAAC;QACtC,IAAI,CAAC,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACjC,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;IACtC,CAAC;IACD;;;;OAIG;IACH,YAAY,CAAC,GAAiB;QAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,kBAAkB,EAAE,CAAC;QAC/C,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QACtC,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QACpC,IAAI,IAAI,GAAa,EAAE,CAAC;QACxB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,OAAO,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC1C,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC3B,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;YAC/B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;QAC1C,CAAC;QACD,oBAAoB;QACpB,IAAI,GAAG,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC;QACvB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACrC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;YACnB,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;QACnB,CAAC;QACD,IAAI,KAAK,KAAK,CAAC;YAAE,OAAO,CAAC,CAAC;QAC1B,MAAM,QAAQ,GAAG,CAAC,GAAG,GAAG,KAAK,CAAC,CAAC;QAC/B,YAAY;QACZ,IAAI,MAAM,GAAG,CAAC,CAAC;QACf,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACrC,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,QAAQ,EAAE,CAAC,CAAC,CAAC;QAChD,CAAC;QACD,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;IACzE,CAAC;CACF"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface SpectralCentroidConfig {
|
|
2
|
+
/** Sample rate of the audio (Hz) */
|
|
3
|
+
sampleRate: number;
|
|
4
|
+
/** FFT size (default: 1024) */
|
|
5
|
+
fftSize?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare class SpectralCentroidAnalyzer {
|
|
8
|
+
private fft;
|
|
9
|
+
private fftSize;
|
|
10
|
+
private sampleRate;
|
|
11
|
+
/**
|
|
12
|
+
* @param config - Configuration with sample rate and optional FFT size
|
|
13
|
+
*/
|
|
14
|
+
constructor(config: SpectralCentroidConfig);
|
|
15
|
+
/**
|
|
16
|
+
* Compute the spectral centroid for a PCM frame.
|
|
17
|
+
* @param pcm - Input PCM audio frame
|
|
18
|
+
* @returns Spectral centroid in Hz
|
|
19
|
+
*/
|
|
20
|
+
analyzeFrame(pcm: Float32Array): number;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=SpectralCentroidAnalyzer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SpectralCentroidAnalyzer.d.ts","sourceRoot":"","sources":["../../src/analysis/SpectralCentroidAnalyzer.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,sBAAsB;IACrC,oCAAoC;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,+BAA+B;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,wBAAwB;IACnC,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,UAAU,CAAS;IAC3B;;OAEG;gBACS,MAAM,EAAE,sBAAsB;IAK1C;;;;OAIG;IACH,YAAY,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM;CAkBxC"}
|