@audio/spectral-mfcc 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/README.md +5 -0
- package/mfcc.js +54 -0
- package/package.json +33 -0
package/README.md
ADDED
package/mfcc.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// MFCC — mel-frequency cepstral coefficients: FFT → mel filterbank (triangular,
|
|
2
|
+
// Davis & Mermelstein 1980) → log → DCT-II. Ported from audio core.
|
|
3
|
+
|
|
4
|
+
import { fft } from 'fourier-transform'
|
|
5
|
+
|
|
6
|
+
const hz2mel = f => 2595 * Math.log10(1 + f / 700)
|
|
7
|
+
const mel2hz = m => 700 * (10 ** (m / 2595) - 1)
|
|
8
|
+
|
|
9
|
+
// triangular mel filterbank weights over FFT power bins
|
|
10
|
+
function melBank (nMel, nBins, fs, n, fmin, fmax) {
|
|
11
|
+
let melMin = hz2mel(fmin), melMax = hz2mel(fmax)
|
|
12
|
+
let centers = new Float64Array(nMel + 2)
|
|
13
|
+
for (let i = 0; i < nMel + 2; i++) centers[i] = mel2hz(melMin + (melMax - melMin) * i / (nMel + 1)) * n / fs
|
|
14
|
+
let bank = []
|
|
15
|
+
for (let m = 0; m < nMel; m++) {
|
|
16
|
+
let lo = centers[m], mid = centers[m + 1], hi = centers[m + 2]
|
|
17
|
+
let w = new Float64Array(nBins)
|
|
18
|
+
for (let k = Math.ceil(lo); k < Math.min(hi, nBins); k++) {
|
|
19
|
+
if (k < mid) w[k] = (k - lo) / (mid - lo)
|
|
20
|
+
else w[k] = (hi - k) / (hi - mid)
|
|
21
|
+
if (w[k] < 0) w[k] = 0
|
|
22
|
+
}
|
|
23
|
+
bank.push(w)
|
|
24
|
+
}
|
|
25
|
+
return bank
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @param {Float32Array} data — mono PCM frame (power-of-2 length)
|
|
30
|
+
* @param {object} opts — { fs, bins=13, nMel=40, fmin=0, fmax=fs/2 }
|
|
31
|
+
* @returns {Float32Array} cepstral coefficients
|
|
32
|
+
*/
|
|
33
|
+
export default function mfcc (data, { fs = 44100, bins = 13, nMel = 40, fmin = 0, fmax = fs / 2 } = {}) {
|
|
34
|
+
let [re, im] = fft(Float64Array.from(data))
|
|
35
|
+
let half = data.length / 2
|
|
36
|
+
let power = new Float64Array(half + 1)
|
|
37
|
+
for (let k = 0; k <= half; k++) power[k] = re[k] * re[k] + im[k] * im[k]
|
|
38
|
+
|
|
39
|
+
let bank = melBank(nMel, half + 1, fs, data.length, fmin, fmax)
|
|
40
|
+
let logMel = new Float64Array(nMel)
|
|
41
|
+
for (let m = 0; m < nMel; m++) {
|
|
42
|
+
let e = 0
|
|
43
|
+
for (let k = 0; k <= half; k++) e += power[k] * bank[m][k]
|
|
44
|
+
logMel[m] = Math.log(e + 1e-10)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let out = new Float32Array(bins)
|
|
48
|
+
for (let k = 0; k < bins; k++) {
|
|
49
|
+
let sum = 0
|
|
50
|
+
for (let m = 0; m < nMel; m++) sum += logMel[m] * Math.cos(Math.PI * k * (2 * m + 1) / (2 * nMel))
|
|
51
|
+
out[k] = sum
|
|
52
|
+
}
|
|
53
|
+
return out
|
|
54
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@audio/spectral-mfcc",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MFCC — mel-frequency cepstral coefficients (FFT → mel triangles → log → DCT-II)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"main": "mfcc.js",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./mfcc.js",
|
|
10
|
+
"./package.json": "./package.json"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"mfcc.js"
|
|
14
|
+
],
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"fourier-transform": "^2.2.0"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"audio",
|
|
20
|
+
"dsp",
|
|
21
|
+
"spectral",
|
|
22
|
+
"mfcc",
|
|
23
|
+
"mel"
|
|
24
|
+
],
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"author": "Dmitry Iv. <dfcreative@gmail.com>",
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=18"
|
|
29
|
+
},
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
}
|
|
33
|
+
}
|