如何重播录制的FFT样本?

时间:2018-10-20 16:07:18

标签: javascript html5-audio

我从这样的音频中记录FFT(“ 快速傅立叶变换”)样本:

 const no_samples = 100;

 const samples = [];
 for (let i = 0, l = no_samples; i < l; ++i) {
     samples.push({ sample: new Uint8Array(this.sampleSize), time:-1 });
 }
 var lambdaToRemove = null;

 let samplesDone = 0;
 let start = -1;
 let second = 0;

 this.scriptProcessor.addEventListener("audioprocess", lambdaToRemove =
 /**
  * @param {AudioProcessingEvent} event
  * */
     (event) => {
         // firefox provides data even before user allows acces to microphone
         if (!this.mediaAllocated) {
             console.log("Sample before media was allocated!");
             return;
         }

         // AudioAnalyser - https://developer.mozilla.org/en-US/docs/Web/API/AnalyserNode
         this.analyser.getByteFrequencyData(samples[samplesDone].sample);
         ++samplesDone;

         if (samplesDone >= no_samples) {
             this.scriptProcessor.removeEventListener("audioprocess", lambdaToRemove);
             resolve(samples);
         }
 });

相关行是:

this.analyser.getByteFrequencyData(samples[samplesDone].sample);

此调用使用FFT数据填充Uint8Array。长度是预先设置并固定的。

所以现在我有了一个包含Uint8Array的数组,它们代表录制的音频。如何将数据反馈回一些音频流,以便在浏览器中播放?

我想将声音录制为FFT,然后进行修改然后再播放。

我尝试过:

/** @type {{time:number, sample:Uint8Array}[]} **/
const samples = this.getSamples();
this.oscilator = this.audioContext.createOscillator();
this.oscilator.connect(this.audioContext.destination);

let ctime = 0;
const ssize = samples[0].sample.length;
const imaginary = new Float32Array(ssize);
const half255 = 255 / 2;
this.oscilator.start();

for (let i = 0, l = samples.length; i < l; ++i) {
    const sample = samples[i];
    await sleep(sample.time - ctime);
    ctime = sample.time;
    const real = new Float32Array(ssize);
    // convert 0->255 to -1.0->1.0
    for (let is = 0, ls = real.length; is < ls; ++is) {
        real[is] = (sample.sample[is] / half255) / half255;
    }

    const wave = this.audioContext.createPeriodicWave(real, imaginary);
    this.oscilator.setPeriodicWave(wave);

}
this.isPlaying = false;
this.oscilator.stop();

但这听起来像是蜂鸣器。必须有一种方法可以从一个波浪过渡到另一个波浪。

1 个答案:

答案 0 :(得分:0)

您必须使用正弦波重新合成音频,因为这基本上就是FFT分解的结果。

特别是,您将实现一种vocoder

您可以将在特定时间点的FFT值数组描绘为该时间点的正弦波振荡器的幅度,其中fft[0]为0 hz振荡器,fft[n - 1]为振荡器调到原始采样率的一半(奈奎斯特定理)。

不过,重新合成的质量可能不会很好。 FFT阵列越大,您拥有的频率分辨率就越好(可能以时间分辨率为代价)。