import {LogCategory, logWarn} from "tc-shared/log"; import { tr } from "tc-shared/i18n/localize"; const OfflineAudioContext = window.webkitOfflineAudioContext || window.OfflineAudioContext; export class AudioResampler { private readonly targetSampleRate: number; private readonly isPromiseResponse: boolean; constructor(targetSampleRate: number){ this.targetSampleRate = targetSampleRate; this.isPromiseResponse = navigator.browserSpecs.name != 'Safari'; if(this.targetSampleRate < 3000 || this.targetSampleRate > 384000) { throw tr("The target sample rate is outside the range [3000, 384000]."); } } getTargetSampleRate() : number { return this.targetSampleRate; } async resample(buffer: AudioBuffer) : Promise { if(!buffer) { logWarn(LogCategory.AUDIO, tr("Received empty buffer as input! Returning empty output!")); return buffer; } if(buffer.sampleRate == this.targetSampleRate) { return buffer; } const context = new OfflineAudioContext( buffer.numberOfChannels, Math.ceil(buffer.length * this.targetSampleRate / buffer.sampleRate), this.targetSampleRate ); let source = context.createBufferSource(); source.buffer = buffer; source.connect(context.destination); source.start(0); if(this.isPromiseResponse) { return await context.startRendering(); } else { return await new Promise((resolve, reject) => { context.oncomplete = event => resolve(event.renderedBuffer); try { context.startRendering(); } catch (ex) { reject(ex); } }); } } }