meyda
Version:
Real-time feature extraction for the web audio api
114 lines (97 loc) • 3.98 kB
JavaScript
;
function extractPowerSpectrum (_a) {
var ampSpectrum = _a.ampSpectrum;
if (typeof ampSpectrum !== "object") {
throw new TypeError();
}
var powerSpectrum = new Float32Array(ampSpectrum.length);
for (var i = 0; i < powerSpectrum.length; i++) {
powerSpectrum[i] = Math.pow(ampSpectrum[i], 2);
}
return powerSpectrum;
}
function extractMelBands (_a) {
var ampSpectrum = _a.ampSpectrum, melFilterBank = _a.melFilterBank, bufferSize = _a.bufferSize;
if (typeof ampSpectrum !== "object") {
throw new TypeError("Valid ampSpectrum is required to generate melBands");
}
if (typeof melFilterBank !== "object") {
throw new TypeError("Valid melFilterBank is required to generate melBands");
}
var powSpec = extractPowerSpectrum({ ampSpectrum: ampSpectrum });
var numFilters = melFilterBank.length;
var filtered = Array(numFilters);
var loggedMelBands = new Float32Array(numFilters);
for (var i = 0; i < loggedMelBands.length; i++) {
filtered[i] = new Float32Array(bufferSize / 2);
loggedMelBands[i] = 0;
for (var j = 0; j < bufferSize / 2; j++) {
//point-wise multiplication between power spectrum and filterbanks.
filtered[i][j] = melFilterBank[i][j] * powSpec[j];
//summing up all of the coefficients into one array
loggedMelBands[i] += filtered[i][j];
}
//log each coefficient.
loggedMelBands[i] = Math.log(loggedMelBands[i] + 1);
}
return Array.prototype.slice.call(loggedMelBands);
}
function getDefaultExportFromCjs (x) {
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
}
/*===========================================================================*\
* Discrete Cosine Transform
*
* (c) Vail Systems. Joshua Jung and Ben Bryan. 2015
*
* This code is not designed to be highly optimized but as an educational
* tool to understand the Mel-scale and its related coefficients used in
* human speech analysis.
\*===========================================================================*/
var cosMap = null;
// Builds a cosine map for the given input size. This allows multiple input sizes to be memoized automagically
// if you want to run the DCT over and over.
var memoizeCosines = function(N) {
cosMap = cosMap || {};
cosMap[N] = new Array(N*N);
var PI_N = Math.PI / N;
for (var k = 0; k < N; k++) {
for (var n = 0; n < N; n++) {
cosMap[N][n + (k * N)] = Math.cos(PI_N * (n + 0.5) * k);
}
}
};
function dct$2(signal, scale) {
var L = signal.length;
scale = scale || 2;
if (!cosMap || !cosMap[L]) memoizeCosines(L);
var coefficients = signal.map(function () {return 0;});
return coefficients.map(function (__, ix) {
return scale * signal.reduce(function (prev, cur, ix_, arr) {
return prev + (cur * cosMap[L][ix_ + (ix * L)]);
}, 0);
});
}
var dct_1 = dct$2;
var dct = dct_1;
var dct$1 = /*@__PURE__*/getDefaultExportFromCjs(dct);
function mfcc (_a) {
// Tutorial from:
// http://practicalcryptography.com/miscellaneous/machine-learning
// /guide-mel-frequency-cepstral-coefficients-mfccs/
// @ts-ignore
var ampSpectrum = _a.ampSpectrum, melFilterBank = _a.melFilterBank, numberOfMFCCCoefficients = _a.numberOfMFCCCoefficients, bufferSize = _a.bufferSize;
var _numberOfMFCCCoefficients = Math.min(40, Math.max(1, numberOfMFCCCoefficients || 13));
var numFilters = melFilterBank.length;
if (numFilters < _numberOfMFCCCoefficients) {
throw new Error("Insufficient filter bank for requested number of coefficients");
}
var loggedMelBandsArray = extractMelBands({
ampSpectrum: ampSpectrum,
melFilterBank: melFilterBank,
bufferSize: bufferSize,
});
var mfccs = dct$1(loggedMelBandsArray).slice(0, _numberOfMFCCCoefficients);
return mfccs;
}
module.exports = mfcc;