Предварительная обработка аудиоданных (спектр БПФ, пик и т. Д.) В JavaScript - PullRequest
0 голосов
/ 27 мая 2018

В настоящее время я могу воспроизводить звуковую дорожку с помощью JavaScript Web Audio API.Во время воспроизведения этой дорожки я могу извлечь данные спектра БПФ, пиковое значение, среднеквадратичное значение и т. Д.

Однако для целей моего приложения мне нужно иметь возможность извлечь все эти данные изтрек, прежде чем я начну его воспроизводить.

Есть ли способ сделать это с помощью API Web Audio.Если нет, то как еще это можно сделать?

Я пытался добиться этого с помощью следующего кода, но он возвращал одинаковые значения для каждого «кадра»:

Загрузка звука припользователь выбирает файл:

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 голосов
/ 29 мая 2018

Если у вас действительно есть набор файлов, и вам нужно обрабатывать их заранее, используйте decodeAudioData, чтобы получить аудиоданные из каждого файла.Используйте OfflineAudioContext вместо AudioContext для получения данных анализатора.Однако, поскольку автономный контекст может работать быстрее, чем в реальном времени, вам нужно быть осторожным при вызове getByteTimeDomainData.Вероятно, лучше использовать suspend и resume здесь, где вы звоните getFrame в suspend.

Однако, исходя из того, что getFrame делает (получая аудиосэмплы), вам может быть лучше использовать ScriptProcessorNode или AudioWorklet, чтобы получить данные во временной области, которые вы ищете.Они работают для AudioContext или OfflineAudioContext.

0 голосов
/ 27 мая 2018

Вы можете использовать OfflineAudioContext вместо AudioContext для предварительной обработки данных вместо запуска аудио конвейера в реальном времени.

Со страницы MDN :

OfflineAudioContext не воспроизводит звук на аппаратном уровне устройства;вместо этого он генерирует его так быстро, как может, и выводит результат в AudioBuffer.

Вы можете выполнить свою обработку в автономном контексте, прежде чем использовать обычный контекст для воспроизведения звука!

...