sofya.transcription
Version:
a JavaScript library that provides a robust and flexible solution for real-time audio transcription. It is designed to transcribe audio streams and can be easily integrated into web applications.
200 lines • 8.68 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
var filters_1 = require("./filters");
var AudioResampler = /** @class */ (function () {
/**
* Initialize a AudioResampler instance so that configurations need not to be applied before every chunk.
*
* @param {SampleRate} oldSampleRate Input sample rate for the audio buffer
* @param {SampleRate} newSampleRate Target sample rate for the audio buffer
* @param {boolean} liveAudio Set whether the audio is live (multiple sequential chunks) or a single audio buffer.
* @param {boolean} antiAlias Set whether to enable or disable Anti-aliasing filters. Recommended for downsampling, disabled by default for upsampling.
* @returns {AudioResampler}
*/
function AudioResampler(oldSampleRate, newSampleRate, liveAudio, antiAlias) {
var _this = this;
this.antiAlias = true;
this.isFirstFrame = true;
this.filterBuffer = new Float32Array();
/**
* Lanczos resampling
* https://en.wikipedia.org/wiki/Lanczos_resampling
*
* @private
* @param {number} a
* @param {number} t
* @returns {number}
*/
this.lanczosWindow = function (a, t) {
if (t === 0)
return 1;
if (t >= a || t <= -a)
return 0;
var p = Math.PI * t;
return (a * Math.sin(p) * Math.sin(p / a)) / (p * p);
};
/**
* Downsampling with Anti-Aliasing
*
* @private
* @param {Float32Array} buffer
* @returns {Float32Array}
*/
this.antiAliasDownsample = function (buffer) {
var filter = [];
if (_this.decimationFactor === 3) {
filter = filters_1.LP_3_TO_1_FIR;
}
else if (_this.decimationFactor === 2) {
filter = filters_1.LP_2_TO_1_FIR;
}
else if (_this.decimationFactor === 2.75625) {
filter = filters_1.LP_275_TO_100_FIR;
}
else {
throw new Error(_this.oldSampleRate + " kHz is not an expected input sampling frequency for conversion into " + _this.newSampleRate + " kHz");
}
var nSamplesForNextFrame; //number of samples set aside for the next frame
var nSamplesCurrentFrame; //number of samples taken for the current frame
var workBuffer; //working buffer for the current chunk
if (_this.isFirstFrame) {
nSamplesForNextFrame = Math.floor(buffer.length % _this.decimationFactor); //number of samples saved for the next frame
nSamplesCurrentFrame = buffer.length - nSamplesForNextFrame; //number of samples selected for the current frame
if (nSamplesForNextFrame === 0) {
workBuffer = buffer;
}
else {
workBuffer = buffer.slice(0, nSamplesCurrentFrame);
}
}
else {
nSamplesForNextFrame = Math.floor((buffer.length + _this.filterBuffer.length - filter.length) % _this.decimationFactor); // Avoid temporal shift
nSamplesCurrentFrame = buffer.length + _this.filterBuffer.length - filter.length - nSamplesForNextFrame;
workBuffer = new Float32Array(_this.filterBuffer.length + nSamplesCurrentFrame);
workBuffer.set(_this.filterBuffer);
workBuffer.set(buffer.slice(0, nSamplesCurrentFrame), _this.filterBuffer.length);
}
// Apply filtering and decimation / interpolation
var outBufferLength = Math.floor(nSamplesCurrentFrame / _this.decimationFactor);
var outBuffer = new Float32Array(outBufferLength);
// decimationFactor is an integer (3)
if (_this.decimationFactor === 3 || _this.decimationFactor === 2) {
for (var i = filter.length; i < workBuffer.length; i += _this.decimationFactor) {
// Low Pass filtering
var acc = 0;
for (var k = 0; k < filter.length; k++) {
acc += workBuffer[i - k] * filter[k];
}
// Handle clipping and short formatting
var formattedValue = Math.max(Math.min(acc, 1), -1);
// Decimation
outBuffer[(i - filter.length) / _this.decimationFactor] = formattedValue;
}
}
else if (_this.decimationFactor === 2.75625) {
// 44100 kHz : decimationFactor is not an integer (~2.75)
// Low Pass filtering
var LP_SIGNAL = [];
for (var i = filter.length; i < workBuffer.length; i++) {
var acc = 0;
for (var k = 0; k < filter.length; k++) {
acc += workBuffer[i - k] * filter[k];
}
LP_SIGNAL[i - filter.length] = acc;
}
// Decimation / interpolation
for (var n = 0; n < outBufferLength; n++) {
var a = 3; // Lanczos window type 3
var x = n * _this.decimationFactor;
var start = Math.floor(x) - a + 1;
var end = Math.floor(x) + a;
var acc = 0;
for (var i = start; i <= end; i++) {
var s = void 0;
if (i < 0)
s = LP_SIGNAL[0];
else if (i >= LP_SIGNAL.length)
s = LP_SIGNAL[LP_SIGNAL.length - 1];
else
s = LP_SIGNAL[i];
acc += s * _this.lanczosWindow(a, x - i);
}
// Handle clipping and short formatting
outBuffer[n] = Math.max(Math.min(acc, 1), -1);
}
}
// Update filterBuffer with the last samples of current frame
if (_this.isFirstFrame) {
_this.filterBuffer = buffer.slice(nSamplesCurrentFrame - filter.length - _this.filterBuffer.length);
}
else {
_this.filterBuffer = buffer.slice(nSamplesCurrentFrame - filter.length - (_this.filterBuffer.length - filter.length));
}
// First frame already handled
_this.isFirstFrame = false; // will be re-initialized when listening is done (allowing next records)
return outBuffer;
};
/**
* Upsampling
*
* @private
* @param {Float32Array} buffer
* @returns {Float32Array}
*/
this.upsample = function (buffer) {
return buffer;
};
/**
* Downsampling without Anti-Aliasing
*
* @private
* @param {Float32Array} buffer
* @returns {Float32Array}
*/
this.downsample = function (buffer) {
return buffer;
};
/**
* Resampling with applied config.
* Determines whether to downsample or upsample using `oldSampleRate` and `newSampleRate` values.
* @public
* @param {Float32Array} buffer
* @returns {Float32Array}
*/
this.resample = function (buffer) {
if (_this.decimationFactor === 1) {
return buffer;
}
else if (_this.decimationFactor > 1) {
if (_this.antiAlias) {
return _this.antiAliasDownsample(buffer);
}
else {
return _this.downsample(buffer);
}
}
else {
return _this.upsample(buffer);
}
};
/**
* Encodes audio buffers as WAVE Format.
*
* @public
* @param {Float32Array} buffer
* @returns {DataView}
*/
this.encodeAsWav = function (buffer) {
return new DataView(new ArrayBuffer(buffer.length));
};
this.oldSampleRate = oldSampleRate;
this.newSampleRate = newSampleRate;
// @ts-ignore
this.antiAlias = oldSampleRate > newSampleRate ? antiAlias : false;
this.decimationFactor = oldSampleRate / newSampleRate;
this.liveAudio = liveAudio;
}
return AudioResampler;
}());
exports.default = AudioResampler;
//# sourceMappingURL=SpeechAudioResampler.js.map