在JavaScript中预处理音频数据(fft频谱,峰值等)

时间:2018-05-27 02:55:37

标签: javascript html5-audio web-audio web-audio-api

我目前可以使用JavaScript Web Audio API播放音轨。在播放此曲目时,我可以提取FFT频谱数据,峰值,RMS值等。

但是,出于我的应用目的,我需要能够在开始播放之前从轨道中提取所有这些数据。

有没有办法使用Web Audio API执行此操作。如果没有,这怎么可能呢?

我尝试使用以下代码实现此目的,但它为每个框架返回了完全相同的值':

当用户选择文件时加载音频:

var fileChooser = document.getElementById("chooseAudio");
var audio = null;

var file = fileChooser.files[0];

var reader = new FileReader();

reader.onload = function(e) {
    audio = new Audio(reader.result);
}

reader.readAsDataURL(file);

加载音频后:

var FPS = 60;
var INCREMENT = 1 / FPS;
var FFT_SIZE = 256;
var SMOOTHING = 0.7;

var duration = null;
var length = null;
var width = null;
var time = null;

var analyser = null;
var data = null;
var index = null;

function analyse() {

    duration = audio.duration / APR;
    length = Math.ceil(duration * FPS);
    width = 4;
    time = 0.0;

    data = array(length, width);
    index = 0;

    var context = new AudioContext();

    analyser = context.createAnalyser();
    analyser.fftSize = FFT_SIZE;
    analyser.smoothingTimeConstant = SMOOTHING;

    var source = context.createMediaElementSource(audio);

    source.connect(analyser);
    analyser.connect(context.destination);

    audio.play();

    while (index < length) {

        audio.currentTime = time;

        frame = getFrame();
        data[index] = frame;

        time += INCREMENT;
        index++;

    }

    audio.pause();
    audio.currentTime = 0;

}

function getFrame() {

    var rawFreq = new Uint8Array(analyser.frequencyBinCount);
    analyser.getByteFrequencyData(rawFreq);

    var rawTimeDom = new Uint8Array(analyser.fftSize);
    analyser.getByteTimeDomainData(rawTimeDom);

    var frame = [];
    frame.push(peak(rawTimeDom), rms(rawTimeDom), low(rawFreq), high(rawFreq));

    return frame;

}

data的输出:

[
  [128, 128, 100.2, 68.3],
  [128, 128, 100.2, 68.3],
  ...
  [128, 128, 100.2, 68.3]
]

此外,我应该澄清一下,我尝试每秒60次采样音频的原因是因为我需要稍后以相同的速率显示音频数据。

2 个答案:

答案 0 :(得分:1)

您可以使用OfflineAudioContext代替AudioContext来预处理数据,而不是实时运行音频管道。

From the MDN page

  

OfflineAudioContext不会将音频呈现给设备硬件;相反,它会尽可能快地生成它,并将结果输出到AudioBuffer。

在使用普通上下文播放音频之前,您可以在离线环境中进行处理!

答案 1 :(得分:0)

如果您确实拥有一组文件并需要预先处理它们,请使用decodeAudioData从每个文件中获取音频数据。使用OfflineAudioContext代替AudioContext来获取分析仪数据。但是,由于离线上下文的运行速度可能比实时更快,因此在调用getByteTimeDomainData时需要注意。这里最好使用suspendresume,您可以在getFrame中致电suspend

但是,根据getFrame所做的事情(获取音频样本),您可能最好使用ScriptProcessorNodeAudioWorklet来获取您所需的时域数据。正在寻找。这些适用于AudioContextOfflineAudioContext