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
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Abijah Kajabika
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# Audio ML - Audio Analysis for Machine Learning
|
|
2
|
+
|
|
3
|
+
A comprehensive JavaScript/TypeScript library for real-time audio feature extraction, designed for machine learning applications, particularly voice AI systems.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This project provides a complete toolkit for analyzing audio signals in real-time, extracting various features that are essential for machine learning models in speech recognition, speaker identification, music information retrieval, and voice AI applications.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
### 🎯 Real-Time Audio Analysis
|
|
12
|
+
- Process audio from microphone or audio playback in real-time
|
|
13
|
+
- Extract multiple audio features simultaneously
|
|
14
|
+
- Visualize all features in a responsive grid layout
|
|
15
|
+
|
|
16
|
+
### 📊 16 Audio Analyzers
|
|
17
|
+
|
|
18
|
+
#### Frequency Domain Features
|
|
19
|
+
- **FFT** - Fast Fourier Transform magnitude spectrum
|
|
20
|
+
- **MFCC** - Mel-Frequency Cepstral Coefficients (13 coefficients)
|
|
21
|
+
- **PLP** - Perceptual Linear Prediction
|
|
22
|
+
- **Mel Spectrogram** - Mel-scaled power spectrum
|
|
23
|
+
- **Constant-Q Transform** - Logarithmically spaced frequency analysis
|
|
24
|
+
- **Chroma Features** - 12-tone pitch class representation
|
|
25
|
+
|
|
26
|
+
#### Spectral Features
|
|
27
|
+
- **Spectral Centroid** - Frequency "center of mass"
|
|
28
|
+
- **Spectral Rolloff** - Frequency below which 85% of energy lies
|
|
29
|
+
- **Spectral Bandwidth** - Spread of spectrum around centroid
|
|
30
|
+
- **Spectral Flatness** - Measure of noise-like vs tone-like content
|
|
31
|
+
|
|
32
|
+
#### Time Domain Features
|
|
33
|
+
- **Zero Crossing Rate** - Rate of sign changes
|
|
34
|
+
- **RMSE** - Root Mean Square Energy
|
|
35
|
+
- **Waveform Envelope** - Amplitude envelope tracking
|
|
36
|
+
- **Autocorrelation** - Periodicity and pitch detection
|
|
37
|
+
|
|
38
|
+
#### Advanced Features
|
|
39
|
+
- **LPC** - Linear Predictive Coding coefficients
|
|
40
|
+
- **Wavelet Transform** - Multi-level time-frequency decomposition
|
|
41
|
+
|
|
42
|
+
### 🎨 Interactive Visualizations
|
|
43
|
+
- Real-time canvas-based visualizations for each analyzer
|
|
44
|
+
- Responsive grid layout (up to 4 columns)
|
|
45
|
+
- Info tooltips with detailed explanations and resources
|
|
46
|
+
- Scrolling spectrograms for time-frequency analysis
|
|
47
|
+
|
|
48
|
+
## Getting Started
|
|
49
|
+
|
|
50
|
+
### Installation
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npm install
|
|
54
|
+
# or
|
|
55
|
+
yarn install
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Development
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npm run dev
|
|
62
|
+
# or
|
|
63
|
+
yarn dev
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Open your browser and navigate to the local development server (typically `http://localhost:5173`).
|
|
67
|
+
|
|
68
|
+
### Usage
|
|
69
|
+
|
|
70
|
+
1. Click "Start Recording" to begin capturing audio from your microphone
|
|
71
|
+
2. All 16 analyzers will update in real-time as you speak
|
|
72
|
+
3. Click the ⓘ icon next to any analyzer name to learn more about it
|
|
73
|
+
4. Click "Stop Recording" to end the session
|
|
74
|
+
|
|
75
|
+
## Architecture
|
|
76
|
+
|
|
77
|
+
### Analyzers (`src/analysis/`)
|
|
78
|
+
Each analyzer is a self-contained class that:
|
|
79
|
+
- Takes PCM audio frames as input
|
|
80
|
+
- Returns feature vectors or scalar values
|
|
81
|
+
- Handles its own FFT and signal processing
|
|
82
|
+
|
|
83
|
+
### Visualizations (`src/visualizations/`)
|
|
84
|
+
- **Base classes**: `BaseVisualizer`, `ArrayVisualizer`, `ScalarVisualizer`
|
|
85
|
+
- **Visualizer functions**: Specific drawing functions for each analyzer type
|
|
86
|
+
- **VisualizationManager**: Manages multiple visualizations and updates them in real-time
|
|
87
|
+
- **Info system**: Tooltips with detailed information about each analyzer
|
|
88
|
+
|
|
89
|
+
### Main Application (`src/main.ts`)
|
|
90
|
+
- Sets up audio capture from microphone
|
|
91
|
+
- Creates and manages all analyzers
|
|
92
|
+
- Handles frame size differences between analyzers
|
|
93
|
+
- Updates visualizations in real-time
|
|
94
|
+
|
|
95
|
+
## API Reference
|
|
96
|
+
|
|
97
|
+
### Basic Usage
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
import { FFTAnalyzer } from './analysis/FFTAnalyzer';
|
|
101
|
+
import { MFCCAnalyzer } from './analysis/MFCCAnalyzer';
|
|
102
|
+
import { visualizeFFT } from './visualizations/analyzerVisualizers';
|
|
103
|
+
|
|
104
|
+
// Create analyzer
|
|
105
|
+
const fftAnalyzer = new FFTAnalyzer({
|
|
106
|
+
sampleRate: 44100,
|
|
107
|
+
fftSize: 1024
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Analyze a frame
|
|
111
|
+
const pcmFrame = new Float32Array(1024); // Your audio data
|
|
112
|
+
const spectrum = fftAnalyzer.analyzeFrame(pcmFrame);
|
|
113
|
+
|
|
114
|
+
// Visualize
|
|
115
|
+
const canvas = document.createElement('canvas');
|
|
116
|
+
visualizeFFT(canvas, spectrum);
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Using VisualizationManager
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
import { VisualizationManager } from './visualizations';
|
|
123
|
+
import { FFTAnalyzer } from './analysis/FFTAnalyzer';
|
|
124
|
+
|
|
125
|
+
const container = document.getElementById('app')!;
|
|
126
|
+
const manager = new VisualizationManager(container);
|
|
127
|
+
|
|
128
|
+
const analyzer = new FFTAnalyzer({ sampleRate: 44100 });
|
|
129
|
+
const canvas = document.createElement('canvas');
|
|
130
|
+
canvas.width = 400;
|
|
131
|
+
canvas.height = 200;
|
|
132
|
+
|
|
133
|
+
manager.addVisualization(analyzer, canvas, 'FFT', {
|
|
134
|
+
color: '#00ff00'
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// Update with audio data
|
|
138
|
+
processor.onaudioprocess = (event) => {
|
|
139
|
+
const pcm = event.inputBuffer.getChannelData(0);
|
|
140
|
+
manager.update(pcm);
|
|
141
|
+
};
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Analyzers Reference
|
|
145
|
+
|
|
146
|
+
| Analyzer | Output Type | Frame Size | Description |
|
|
147
|
+
|----------|-------------|------------|-------------|
|
|
148
|
+
| FFT | `Float32Array` | 1024 | Raw frequency spectrum |
|
|
149
|
+
| MFCC | `number[]` | 1024 | 13 cepstral coefficients |
|
|
150
|
+
| PLP | `number[]` | 512 | Perceptual linear prediction |
|
|
151
|
+
| Chroma | `number[]` | 1024 | 12 pitch classes |
|
|
152
|
+
| LPC | `number[]` | Any | Linear prediction coefficients |
|
|
153
|
+
| CQT | `Float32Array` | 2048 | Constant-Q transform |
|
|
154
|
+
| Wavelet | `Float32Array[]` | Any | Multi-level decomposition |
|
|
155
|
+
| Envelope | `Float32Array` | Any | Amplitude envelope |
|
|
156
|
+
| Autocorr | `Float32Array` | Any | Autocorrelation function |
|
|
157
|
+
| Centroid | `number` | 1024 | Spectral centroid (Hz) |
|
|
158
|
+
| Rolloff | `number` | 1024 | Spectral rolloff (Hz) |
|
|
159
|
+
| Bandwidth | `number` | 1024 | Spectral bandwidth (Hz) |
|
|
160
|
+
| Flatness | `number` | 1024 | Spectral flatness (0-1) |
|
|
161
|
+
| ZCR | `number` | Any | Zero crossing rate |
|
|
162
|
+
| RMSE | `number` | Any | Root mean square energy |
|
|
163
|
+
| Mel Spectrogram | `number[]` | 1024 | Mel-scaled energies |
|
|
164
|
+
|
|
165
|
+
## Use Cases
|
|
166
|
+
|
|
167
|
+
### Voice AI Applications
|
|
168
|
+
- **Speech Recognition**: MFCC, PLP, and spectral features for acoustic modeling
|
|
169
|
+
- **Speaker Identification**: Voiceprint extraction using MFCC, LPC, and spectral features
|
|
170
|
+
- **Voice Activity Detection**: ZCR, RMSE, and spectral flatness for silence detection
|
|
171
|
+
- **Emotion Recognition**: Spectral features and prosodic features
|
|
172
|
+
|
|
173
|
+
### Music Information Retrieval
|
|
174
|
+
- **Chord Recognition**: Chroma features
|
|
175
|
+
- **Key Detection**: Chroma features and spectral analysis
|
|
176
|
+
- **Tempo Estimation**: Autocorrelation
|
|
177
|
+
- **Genre Classification**: Multiple spectral and temporal features
|
|
178
|
+
|
|
179
|
+
### Audio Processing
|
|
180
|
+
- **Noise Reduction**: Spectral analysis and filtering
|
|
181
|
+
- **Pitch Detection**: Autocorrelation and CQT
|
|
182
|
+
- **Onset Detection**: Envelope and spectral features
|
|
183
|
+
|
|
184
|
+
## Dependencies
|
|
185
|
+
|
|
186
|
+
- **fft.js** - Fast Fourier Transform implementation
|
|
187
|
+
- **TypeScript** - Type-safe JavaScript
|
|
188
|
+
- **Vite** - Build tool and dev server
|
|
189
|
+
|
|
190
|
+
## Browser Compatibility
|
|
191
|
+
|
|
192
|
+
- Modern browsers with Web Audio API support
|
|
193
|
+
- Microphone access required for real-time analysis
|
|
194
|
+
- Canvas API for visualizations
|
|
195
|
+
|
|
196
|
+
## Contributing
|
|
197
|
+
|
|
198
|
+
This project is designed to be extensible. To add a new analyzer:
|
|
199
|
+
|
|
200
|
+
1. Create a new analyzer class in `src/analysis/`
|
|
201
|
+
2. Implement the `analyzeFrame(pcm: Float32Array)` method
|
|
202
|
+
3. Add a visualization function in `src/visualizations/analyzerVisualizers.ts`
|
|
203
|
+
4. Register it in `VisualizationManager.getVisualizer()`
|
|
204
|
+
5. Add info to `src/visualizations/analyzerInfo.ts`
|
|
205
|
+
|
|
206
|
+
## License
|
|
207
|
+
|
|
208
|
+
MIT
|
|
209
|
+
|
|
210
|
+
## Resources
|
|
211
|
+
|
|
212
|
+
- [Web Audio API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API)
|
|
213
|
+
- [FFT.js Documentation](https://github.com/indutny/fft.js)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AutocorrelationAnalyzer computes the autocorrelation function of a PCM audio frame.
|
|
3
|
+
* Autocorrelation is useful for pitch detection and periodicity analysis in audio signals.
|
|
4
|
+
* Usage: const ac = new AutocorrelationAnalyzer({ sampleRate: 16000 }); ac.analyzeFrame(pcm)
|
|
5
|
+
*/
|
|
6
|
+
export interface AutocorrelationConfig {
|
|
7
|
+
sampleRate: number;
|
|
8
|
+
maxLag?: number;
|
|
9
|
+
}
|
|
10
|
+
export declare class AutocorrelationAnalyzer {
|
|
11
|
+
private maxLag;
|
|
12
|
+
/**
|
|
13
|
+
* @param config - Configuration with sample rate and optional max lag
|
|
14
|
+
*/
|
|
15
|
+
constructor(config: AutocorrelationConfig);
|
|
16
|
+
/**
|
|
17
|
+
* Compute the autocorrelation function for a PCM frame.
|
|
18
|
+
* @param pcm - Input PCM audio frame
|
|
19
|
+
* @returns Autocorrelation array (length = maxLag)
|
|
20
|
+
*/
|
|
21
|
+
analyzeFrame(pcm: Float32Array): Float32Array;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=AutocorrelationAnalyzer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AutocorrelationAnalyzer.d.ts","sourceRoot":"","sources":["../../src/analysis/AutocorrelationAnalyzer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IAAG,UAAU,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE;AAE9E,qBAAa,uBAAuB;IAClC,OAAO,CAAC,MAAM,CAAS;IACvB;;OAEG;gBACS,MAAM,EAAE,qBAAqB;IAGzC;;;;OAIG;IACH,YAAY,CAAC,GAAG,EAAE,YAAY,GAAG,YAAY;CAW9C"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export class AutocorrelationAnalyzer {
|
|
2
|
+
maxLag;
|
|
3
|
+
/**
|
|
4
|
+
* @param config - Configuration with sample rate and optional max lag
|
|
5
|
+
*/
|
|
6
|
+
constructor(config) {
|
|
7
|
+
this.maxLag = config.maxLag || Math.floor(config.sampleRate / 50); // up to 20 Hz
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Compute the autocorrelation function for a PCM frame.
|
|
11
|
+
* @param pcm - Input PCM audio frame
|
|
12
|
+
* @returns Autocorrelation array (length = maxLag)
|
|
13
|
+
*/
|
|
14
|
+
analyzeFrame(pcm) {
|
|
15
|
+
const result = new Float32Array(this.maxLag);
|
|
16
|
+
for (let lag = 0; lag < this.maxLag; lag++) {
|
|
17
|
+
let sum = 0;
|
|
18
|
+
for (let i = 0; i < pcm.length - lag; i++) {
|
|
19
|
+
sum += pcm[i] * pcm[i + lag];
|
|
20
|
+
}
|
|
21
|
+
result[lag] = sum / (pcm.length - lag);
|
|
22
|
+
}
|
|
23
|
+
return result;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=AutocorrelationAnalyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AutocorrelationAnalyzer.js","sourceRoot":"","sources":["../../src/analysis/AutocorrelationAnalyzer.ts"],"names":[],"mappings":"AAOA,MAAM,OAAO,uBAAuB;IAC1B,MAAM,CAAS;IACvB;;OAEG;IACH,YAAY,MAA6B;QACvC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,GAAG,EAAE,CAAC,CAAC,CAAC,cAAc;IACnF,CAAC;IACD;;;;OAIG;IACH,YAAY,CAAC,GAAiB;QAC5B,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC7C,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC;YAC3C,IAAI,GAAG,GAAG,CAAC,CAAC;YACZ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC1C,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;YAC/B,CAAC;YACD,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC;QACzC,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;CACF"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface ChromaFeaturesConfig {
|
|
2
|
+
sampleRate: number;
|
|
3
|
+
fftSize?: number;
|
|
4
|
+
}
|
|
5
|
+
export declare class ChromaFeaturesAnalyzer {
|
|
6
|
+
private fft;
|
|
7
|
+
private fftSize;
|
|
8
|
+
private sampleRate;
|
|
9
|
+
constructor(config: ChromaFeaturesConfig);
|
|
10
|
+
analyzeFrame(pcm: Float32Array): number[];
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=ChromaFeaturesAnalyzer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChromaFeaturesAnalyzer.d.ts","sourceRoot":"","sources":["../../src/analysis/ChromaFeaturesAnalyzer.ts"],"names":[],"mappings":"AACA,MAAM,WAAW,oBAAoB;IAAG,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE;AAC9E,qBAAa,sBAAsB;IACjC,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,UAAU,CAAS;gBACf,MAAM,EAAE,oBAAoB;IAKxC,YAAY,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,EAAE;CAqB1C"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import FFT from 'fft.js';
|
|
2
|
+
export class ChromaFeaturesAnalyzer {
|
|
3
|
+
fft;
|
|
4
|
+
fftSize;
|
|
5
|
+
sampleRate;
|
|
6
|
+
constructor(config) {
|
|
7
|
+
this.fftSize = config.fftSize || 1024;
|
|
8
|
+
this.fft = new FFT(this.fftSize);
|
|
9
|
+
this.sampleRate = config.sampleRate;
|
|
10
|
+
}
|
|
11
|
+
analyzeFrame(pcm) {
|
|
12
|
+
// 12 chroma bins (C, C#, D, ..., B)
|
|
13
|
+
const chroma = new Array(12).fill(0);
|
|
14
|
+
const spectrum = this.fft.createComplexArray();
|
|
15
|
+
this.fft.realTransform(spectrum, pcm);
|
|
16
|
+
this.fft.completeSpectrum(spectrum);
|
|
17
|
+
for (let i = 0; i < this.fftSize / 2; i++) {
|
|
18
|
+
const re = spectrum[2 * i];
|
|
19
|
+
const im = spectrum[2 * i + 1];
|
|
20
|
+
const mag = Math.sqrt(re * re + im * im);
|
|
21
|
+
const freq = i * this.sampleRate / this.fftSize;
|
|
22
|
+
const midi = 69 + 12 * Math.log2(freq / 440);
|
|
23
|
+
const bin = Math.round(midi) % 12;
|
|
24
|
+
if (bin >= 0 && bin < 12 && isFinite(bin)) {
|
|
25
|
+
chroma[bin] += mag;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// Normalize
|
|
29
|
+
const sum = chroma.reduce((a, b) => a + b, 0) + 1e-12;
|
|
30
|
+
return chroma.map(v => v / sum);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=ChromaFeaturesAnalyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChromaFeaturesAnalyzer.js","sourceRoot":"","sources":["../../src/analysis/ChromaFeaturesAnalyzer.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,QAAQ,CAAC;AAEzB,MAAM,OAAO,sBAAsB;IACzB,GAAG,CAAM;IACT,OAAO,CAAS;IAChB,UAAU,CAAS;IAC3B,YAAY,MAA4B;QACtC,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,YAAY,CAAC,GAAiB;QAC5B,oCAAoC;QACpC,MAAM,MAAM,GAAG,IAAI,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACrC,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,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,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;YACzC,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC;YAChD,MAAM,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC;YAC7C,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;YAClC,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,GAAG,EAAE,IAAI,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC1C,MAAM,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC;YACrB,CAAC;QACH,CAAC;QACD,YAAY;QACZ,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC;QACtD,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;IAClC,CAAC;CACF"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface ConstantQTransformConfig {
|
|
2
|
+
sampleRate: number;
|
|
3
|
+
fftSize?: number;
|
|
4
|
+
binsPerOctave?: number;
|
|
5
|
+
minFreq?: number;
|
|
6
|
+
maxFreq?: number;
|
|
7
|
+
}
|
|
8
|
+
export declare class ConstantQTransformAnalyzer {
|
|
9
|
+
private fft;
|
|
10
|
+
private fftSize;
|
|
11
|
+
private sampleRate;
|
|
12
|
+
private binsPerOctave;
|
|
13
|
+
private minFreq;
|
|
14
|
+
private maxFreq;
|
|
15
|
+
private kernels;
|
|
16
|
+
/**
|
|
17
|
+
* @param config - Configuration with sample rate, optional FFT size, bins per octave, and frequency range
|
|
18
|
+
*/
|
|
19
|
+
constructor(config: ConstantQTransformConfig);
|
|
20
|
+
/**
|
|
21
|
+
* Compute the Constant-Q Transform for a PCM frame.
|
|
22
|
+
* @param pcm - Input PCM audio frame
|
|
23
|
+
* @returns CQT coefficients as Float32Array
|
|
24
|
+
*/
|
|
25
|
+
analyzeFrame(pcm: Float32Array): Float32Array;
|
|
26
|
+
/**
|
|
27
|
+
* Create CQT kernels for each frequency bin.
|
|
28
|
+
*/
|
|
29
|
+
private createCQTKernels;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=ConstantQTransformAnalyzer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConstantQTransformAnalyzer.d.ts","sourceRoot":"","sources":["../../src/analysis/ConstantQTransformAnalyzer.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,wBAAwB;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,0BAA0B;IACrC,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAAsD;IAErE;;OAEG;gBACS,MAAM,EAAE,wBAAwB;IAU5C;;;;OAIG;IACH,YAAY,CAAC,GAAG,EAAE,YAAY,GAAG,YAAY;IAsC7C;;OAEG;IACH,OAAO,CAAC,gBAAgB;CA2CzB"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ConstantQTransformAnalyzer computes the Constant-Q Transform (CQT) of a PCM audio frame.
|
|
3
|
+
* CQT is a time-frequency analysis method with logarithmically spaced frequency bins, useful for music analysis.
|
|
4
|
+
* The Q factor (quality factor) remains constant across all frequency bins.
|
|
5
|
+
* Usage: const cqt = new ConstantQTransformAnalyzer({ sampleRate: 16000 }); cqt.analyzeFrame(pcm)
|
|
6
|
+
*/
|
|
7
|
+
import FFT from 'fft.js';
|
|
8
|
+
export class ConstantQTransformAnalyzer {
|
|
9
|
+
fft;
|
|
10
|
+
fftSize;
|
|
11
|
+
sampleRate;
|
|
12
|
+
binsPerOctave;
|
|
13
|
+
minFreq;
|
|
14
|
+
maxFreq;
|
|
15
|
+
kernels;
|
|
16
|
+
/**
|
|
17
|
+
* @param config - Configuration with sample rate, optional FFT size, bins per octave, and frequency range
|
|
18
|
+
*/
|
|
19
|
+
constructor(config) {
|
|
20
|
+
this.fftSize = config.fftSize || 2048;
|
|
21
|
+
this.sampleRate = config.sampleRate;
|
|
22
|
+
this.binsPerOctave = config.binsPerOctave || 12;
|
|
23
|
+
this.minFreq = config.minFreq || 27.5; // A0
|
|
24
|
+
this.maxFreq = config.maxFreq || this.sampleRate / 2;
|
|
25
|
+
this.fft = new FFT(this.fftSize);
|
|
26
|
+
this.kernels = this.createCQTKernels();
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Compute the Constant-Q Transform for a PCM frame.
|
|
30
|
+
* @param pcm - Input PCM audio frame
|
|
31
|
+
* @returns CQT coefficients as Float32Array
|
|
32
|
+
*/
|
|
33
|
+
analyzeFrame(pcm) {
|
|
34
|
+
// Pad or truncate input to fftSize
|
|
35
|
+
const padded = new Float32Array(this.fftSize);
|
|
36
|
+
const copyLen = Math.min(pcm.length, this.fftSize);
|
|
37
|
+
padded.set(pcm.subarray(0, copyLen), 0);
|
|
38
|
+
// Apply window (Hann window)
|
|
39
|
+
const windowed = new Float32Array(this.fftSize);
|
|
40
|
+
for (let i = 0; i < this.fftSize; i++) {
|
|
41
|
+
const window = 0.5 * (1 - Math.cos(2 * Math.PI * i / (this.fftSize - 1)));
|
|
42
|
+
windowed[i] = padded[i] * window;
|
|
43
|
+
}
|
|
44
|
+
// Compute FFT
|
|
45
|
+
const spectrum = this.fft.createComplexArray();
|
|
46
|
+
this.fft.realTransform(spectrum, windowed);
|
|
47
|
+
this.fft.completeSpectrum(spectrum);
|
|
48
|
+
// Compute CQT by convolving with kernels
|
|
49
|
+
const cqt = new Float32Array(this.kernels.length);
|
|
50
|
+
for (let k = 0; k < this.kernels.length; k++) {
|
|
51
|
+
const kernel = this.kernels[k].kernel;
|
|
52
|
+
let realSum = 0;
|
|
53
|
+
let imagSum = 0;
|
|
54
|
+
for (let i = 0; i < kernel.length && i < this.fftSize / 2; i++) {
|
|
55
|
+
const re = spectrum[2 * i];
|
|
56
|
+
const im = spectrum[2 * i + 1];
|
|
57
|
+
realSum += re * kernel[i];
|
|
58
|
+
imagSum += im * kernel[i];
|
|
59
|
+
}
|
|
60
|
+
cqt[k] = Math.sqrt(realSum * realSum + imagSum * imagSum);
|
|
61
|
+
}
|
|
62
|
+
return cqt;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Create CQT kernels for each frequency bin.
|
|
66
|
+
*/
|
|
67
|
+
createCQTKernels() {
|
|
68
|
+
const kernels = [];
|
|
69
|
+
const Q = 1.0 / (Math.pow(2, 1.0 / this.binsPerOctave) - 1.0);
|
|
70
|
+
// Calculate number of bins
|
|
71
|
+
const numBins = Math.floor(this.binsPerOctave * Math.log2(this.maxFreq / this.minFreq));
|
|
72
|
+
for (let bin = 0; bin < numBins; bin++) {
|
|
73
|
+
const centerFreq = this.minFreq * Math.pow(2, bin / this.binsPerOctave);
|
|
74
|
+
if (centerFreq > this.maxFreq)
|
|
75
|
+
break;
|
|
76
|
+
// Bandwidth is proportional to center frequency (constant Q)
|
|
77
|
+
const bandwidth = centerFreq / Q;
|
|
78
|
+
// Create kernel in frequency domain
|
|
79
|
+
const kernel = new Float32Array(this.fftSize / 2);
|
|
80
|
+
// Gaussian-like window in frequency domain
|
|
81
|
+
for (let i = 0; i < kernel.length; i++) {
|
|
82
|
+
const freq = (i * this.sampleRate) / this.fftSize;
|
|
83
|
+
const distance = Math.abs(freq - centerFreq);
|
|
84
|
+
if (distance < bandwidth) {
|
|
85
|
+
const sigma = bandwidth / 2.0;
|
|
86
|
+
kernel[i] = Math.exp(-0.5 * Math.pow(distance / sigma, 2));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// Normalize
|
|
90
|
+
const sum = kernel.reduce((a, b) => a + b, 0);
|
|
91
|
+
if (sum > 0) {
|
|
92
|
+
for (let i = 0; i < kernel.length; i++) {
|
|
93
|
+
kernel[i] /= sum;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
kernels.push({ centerFreq, kernel });
|
|
97
|
+
}
|
|
98
|
+
return kernels;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=ConstantQTransformAnalyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConstantQTransformAnalyzer.js","sourceRoot":"","sources":["../../src/analysis/ConstantQTransformAnalyzer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,GAAG,MAAM,QAAQ,CAAC;AAUzB,MAAM,OAAO,0BAA0B;IAC7B,GAAG,CAAM;IACT,OAAO,CAAS;IAChB,UAAU,CAAS;IACnB,aAAa,CAAS;IACtB,OAAO,CAAS;IAChB,OAAO,CAAS;IAChB,OAAO,CAAsD;IAErE;;OAEG;IACH,YAAY,MAAgC;QAC1C,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,IAAI,CAAC;QACtC,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;QACpC,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,aAAa,IAAI,EAAE,CAAC;QAChD,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC,KAAK;QAC5C,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;QACrD,IAAI,CAAC,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACjC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;IACzC,CAAC;IAED;;;;OAIG;IACH,YAAY,CAAC,GAAiB;QAC5B,mCAAmC;QACnC,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QACnD,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;QAExC,6BAA6B;QAC7B,MAAM,QAAQ,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAChD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,MAAM,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAC1E,QAAQ,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC;QACnC,CAAC;QAED,cAAc;QACd,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,kBAAkB,EAAE,CAAC;QAC/C,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAC3C,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAEpC,yCAAyC;QACzC,MAAM,GAAG,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAClD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC7C,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;YACtC,IAAI,OAAO,GAAG,CAAC,CAAC;YAChB,IAAI,OAAO,GAAG,CAAC,CAAC;YAEhB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC/D,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;gBAC3B,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;gBAC/B,OAAO,IAAI,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;gBAC1B,OAAO,IAAI,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;YAC5B,CAAC;YAED,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC,CAAC;QAC5D,CAAC;QAED,OAAO,GAAG,CAAC;IACb,CAAC;IAED;;OAEG;IACK,gBAAgB;QACtB,MAAM,OAAO,GAAwD,EAAE,CAAC;QACxE,MAAM,CAAC,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,GAAG,CAAC,CAAC;QAE9D,2BAA2B;QAC3B,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CACxB,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,CAC5D,CAAC;QAEF,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC;YACvC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC;YAExE,IAAI,UAAU,GAAG,IAAI,CAAC,OAAO;gBAAE,MAAM;YAErC,6DAA6D;YAC7D,MAAM,SAAS,GAAG,UAAU,GAAG,CAAC,CAAC;YAEjC,oCAAoC;YACpC,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;YAElD,2CAA2C;YAC3C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACvC,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC;gBAClD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,UAAU,CAAC,CAAC;gBAC7C,IAAI,QAAQ,GAAG,SAAS,EAAE,CAAC;oBACzB,MAAM,KAAK,GAAG,SAAS,GAAG,GAAG,CAAC;oBAC9B,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;gBAC7D,CAAC;YACH,CAAC;YAED,YAAY;YACZ,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;YAC9C,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;gBACZ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;oBACvC,MAAM,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC;gBACnB,CAAC;YACH,CAAC;YAED,OAAO,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC;QACvC,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;CACF"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface FFTConfig {
|
|
2
|
+
sampleRate: number;
|
|
3
|
+
fftSize?: number;
|
|
4
|
+
}
|
|
5
|
+
export declare class FFTAnalyzer {
|
|
6
|
+
private fft;
|
|
7
|
+
private fftSize;
|
|
8
|
+
constructor(config: FFTConfig);
|
|
9
|
+
/**
|
|
10
|
+
* Compute the FFT magnitude spectrum for a PCM frame.
|
|
11
|
+
* @param pcm - Input PCM audio frame (must be fftSize samples)
|
|
12
|
+
* @returns Array of magnitude values (one per frequency bin)
|
|
13
|
+
*/
|
|
14
|
+
analyzeFrame(pcm: Float32Array): Float32Array;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=FFTAnalyzer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FFTAnalyzer.d.ts","sourceRoot":"","sources":["../../src/analysis/FFTAnalyzer.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,SAAS;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,OAAO,CAAS;gBAEZ,MAAM,EAAE,SAAS;IAK7B;;;;OAIG;IACH,YAAY,CAAC,GAAG,EAAE,YAAY,GAAG,YAAY;CAmB9C"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FFTAnalyzer computes the Fast Fourier Transform magnitude spectrum of a PCM audio frame.
|
|
3
|
+
* This shows the frequency content of the signal as a magnitude spectrum.
|
|
4
|
+
* Usage: const fft = new FFTAnalyzer({ sampleRate: 16000 }); fft.analyzeFrame(pcm)
|
|
5
|
+
*/
|
|
6
|
+
import FFT from 'fft.js';
|
|
7
|
+
export class FFTAnalyzer {
|
|
8
|
+
fft;
|
|
9
|
+
fftSize;
|
|
10
|
+
constructor(config) {
|
|
11
|
+
this.fftSize = config.fftSize || 1024;
|
|
12
|
+
this.fft = new FFT(this.fftSize);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Compute the FFT magnitude spectrum for a PCM frame.
|
|
16
|
+
* @param pcm - Input PCM audio frame (must be fftSize samples)
|
|
17
|
+
* @returns Array of magnitude values (one per frequency bin)
|
|
18
|
+
*/
|
|
19
|
+
analyzeFrame(pcm) {
|
|
20
|
+
if (pcm.length !== this.fftSize) {
|
|
21
|
+
throw new Error(`PCM frame must be fftSize (${this.fftSize}) samples`);
|
|
22
|
+
}
|
|
23
|
+
const spectrum = this.fft.createComplexArray();
|
|
24
|
+
this.fft.realTransform(spectrum, pcm);
|
|
25
|
+
this.fft.completeSpectrum(spectrum);
|
|
26
|
+
// Compute magnitude spectrum (only need first half for real signals)
|
|
27
|
+
const magnitudes = new Float32Array(this.fftSize / 2);
|
|
28
|
+
for (let i = 0; i < this.fftSize / 2; i++) {
|
|
29
|
+
const re = spectrum[2 * i];
|
|
30
|
+
const im = spectrum[2 * i + 1];
|
|
31
|
+
magnitudes[i] = Math.sqrt(re * re + im * im);
|
|
32
|
+
}
|
|
33
|
+
return magnitudes;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=FFTAnalyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FFTAnalyzer.js","sourceRoot":"","sources":["../../src/analysis/FFTAnalyzer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,GAAG,MAAM,QAAQ,CAAC;AAOzB,MAAM,OAAO,WAAW;IACd,GAAG,CAAM;IACT,OAAO,CAAS;IAExB,YAAY,MAAiB;QAC3B,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,IAAI,CAAC;QACtC,IAAI,CAAC,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACnC,CAAC;IAED;;;;OAIG;IACH,YAAY,CAAC,GAAiB;QAC5B,IAAI,GAAG,CAAC,MAAM,KAAK,IAAI,CAAC,OAAO,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CAAC,8BAA8B,IAAI,CAAC,OAAO,WAAW,CAAC,CAAC;QACzE,CAAC;QAED,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;QAEpC,qEAAqE;QACrE,MAAM,UAAU,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;QACtD,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,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;QAC/C,CAAC;QAED,OAAO,UAAU,CAAC;IACpB,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LPCAnalyzer.d.ts","sourceRoot":"","sources":["../../src/analysis/LPCAnalyzer.ts"],"names":[],"mappings":"AACA,MAAM,WAAW,SAAS;IAAG,UAAU,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE;AACjE,qBAAa,WAAW;IACtB,OAAO,CAAC,KAAK,CAAS;gBACV,MAAM,EAAE,SAAS;IAG7B,YAAY,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,EAAE;CA2B1C"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export class LPCAnalyzer {
|
|
2
|
+
order;
|
|
3
|
+
constructor(config) {
|
|
4
|
+
this.order = config.order || 12;
|
|
5
|
+
}
|
|
6
|
+
analyzeFrame(pcm) {
|
|
7
|
+
// Autocorrelation method
|
|
8
|
+
const R = new Array(this.order + 1).fill(0);
|
|
9
|
+
for (let lag = 0; lag <= this.order; lag++) {
|
|
10
|
+
for (let i = 0; i < pcm.length - lag; i++) {
|
|
11
|
+
R[lag] += pcm[i] * pcm[i + lag];
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
// Levinson-Durbin recursion
|
|
15
|
+
const a = new Array(this.order + 1).fill(0);
|
|
16
|
+
const e = new Array(this.order + 1).fill(0);
|
|
17
|
+
a[0] = 1;
|
|
18
|
+
e[0] = R[0];
|
|
19
|
+
for (let i = 1; i <= this.order; i++) {
|
|
20
|
+
let acc = 0;
|
|
21
|
+
for (let j = 1; j < i; j++) {
|
|
22
|
+
acc += a[j] * R[i - j];
|
|
23
|
+
}
|
|
24
|
+
const k = (R[i] - acc) / (e[i - 1] + 1e-12);
|
|
25
|
+
a[i] = k;
|
|
26
|
+
for (let j = 1; j < i; j++) {
|
|
27
|
+
a[j] = a[j] - k * a[i - j];
|
|
28
|
+
}
|
|
29
|
+
e[i] = (1 - k * k) * e[i - 1];
|
|
30
|
+
}
|
|
31
|
+
return a.slice(1);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=LPCAnalyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LPCAnalyzer.js","sourceRoot":"","sources":["../../src/analysis/LPCAnalyzer.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,WAAW;IACd,KAAK,CAAS;IACtB,YAAY,MAAiB;QAC3B,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;IAClC,CAAC;IACD,YAAY,CAAC,GAAiB;QAC5B,yBAAyB;QACzB,MAAM,CAAC,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC5C,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,IAAI,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC;YAC3C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC1C,CAAC,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;YAClC,CAAC;QACH,CAAC;QACD,4BAA4B;QAC5B,MAAM,CAAC,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC5C,MAAM,CAAC,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACT,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACZ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;YACrC,IAAI,GAAG,GAAG,CAAC,CAAC;YACZ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC3B,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACzB,CAAC;YACD,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC;YAC5C,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YACT,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC3B,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC7B,CAAC;YACD,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAChC,CAAC;QACD,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;CACF"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export interface MFCCConfig {
|
|
2
|
+
sampleRate: number;
|
|
3
|
+
melBands?: number;
|
|
4
|
+
fftSize?: number;
|
|
5
|
+
numCoeffs?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare class MFCCAnalyzer {
|
|
8
|
+
private fft;
|
|
9
|
+
private fftSize;
|
|
10
|
+
private melBands;
|
|
11
|
+
private numCoeffs;
|
|
12
|
+
private sampleRate;
|
|
13
|
+
private melFilters;
|
|
14
|
+
/**
|
|
15
|
+
* @param config - MFCC extraction configuration
|
|
16
|
+
*/
|
|
17
|
+
constructor(config: MFCCConfig);
|
|
18
|
+
/**
|
|
19
|
+
* Extract MFCCs from a PCM frame.
|
|
20
|
+
* @param pcm - Input PCM audio frame (Float32Array, length = fftSize)
|
|
21
|
+
* @returns Array of MFCC coefficients (length = numCoeffs)
|
|
22
|
+
*/
|
|
23
|
+
analyzeFrame(pcm: Float32Array): number[];
|
|
24
|
+
/**
|
|
25
|
+
* Create a mel filter bank matrix.
|
|
26
|
+
* @returns Array of mel filters (each filter is an array of weights for FFT bins)
|
|
27
|
+
*/
|
|
28
|
+
private createMelFilterBank;
|
|
29
|
+
/** Convert Hz to mel scale */
|
|
30
|
+
private hzToMel;
|
|
31
|
+
/** Convert mel scale to Hz */
|
|
32
|
+
private melToHz;
|
|
33
|
+
/**
|
|
34
|
+
* Discrete Cosine Transform (DCT-II) for MFCCs.
|
|
35
|
+
* @param vector - Input array (log-mel energies)
|
|
36
|
+
* @returns DCT coefficients
|
|
37
|
+
*/
|
|
38
|
+
private dct;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=MFCCAnalyzer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MFCCAnalyzer.d.ts","sourceRoot":"","sources":["../../src/analysis/MFCCAnalyzer.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,UAAU;IAAG,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE;AAE3G,qBAAa,YAAY;IACvB,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,UAAU,CAAa;IAE/B;;OAEG;gBACS,MAAM,EAAE,UAAU;IAS9B;;;;OAIG;IACH,YAAY,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,EAAE;IAgBzC;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAyB3B,8BAA8B;IAC9B,OAAO,CAAC,OAAO;IAIf,8BAA8B;IAC9B,OAAO,CAAC,OAAO;IAIf;;;;OAIG;IACH,OAAO,CAAC,GAAG;CAYZ"}
|