Есть ли способ пересэмплировать аудиопоток с помощью API веб-аудио?

В настоящее время я немного поигрался с API веб-аудио. Мне удалось "прочитать" микрофон и воспроизвести его на моих динамиках, которые работали без проблем.

Используя API веб-аудио, я теперь хотел бы изменить дискретизацию входящего аудиопотока (также известного как микрофон) с 44,1 кГц на 16 кГц.16 кГц, потому что я использую некоторые инструменты, требующие 16 кГц. Поскольку 44,1 кГц, разделенное на 16 кГц, не является целым числом, я считаю, что не могу просто использовать фильтр нижних частот и "пропускать сэмплы", верно?

Я также видел, что некоторые люди предлагали использовать .createScriptProcessor(), но поскольку он устарел, мне не нравится его использовать, поэтому сейчас я ищу другой подход. Кроме того, мне не обязательно нуженaudioContext.Destinationуслышать это! Все еще нормально, если я получаю "сырые" данные передискретизированного вывода.


Мои подходы до сих пор

  • Создание AudioContext({sampleRate: 16000}) -> выдает ошибку: "Подключение AudioNodes из AudioContexts с другой частотой дискретизации в настоящее время не поддерживается".
  • Используя OfflineAudioContext -> но, похоже, у него нет опции для потоков (только для буферов)
  • Используя AudioWorkletProcessorпередискретизировать. В этом случае, как мне кажется, я мог бы использовать процессор для фактической передискретизации входного сигнала и вывода "передискретизированного" источника. Но я не мог понять, как его пересэмплировать.

main.js

...
microphoneGranted: async function(stream){
    audioContext = new AudioContext();
    var microphone = audioContext.createMediaStreamSource(stream);
    await audioContext.audioWorklet.addModule('resample_proc.js');
    const resampleNode = new AudioWorkletNode(audioContext, 'resample_proc');
    microphone.connect(resampleNode).connect(audioContext.destination);
}
...

resample_proc.js (при условии, что только один канал ввода и вывода)

class ResampleProcesscor extends AudioWorkletProcessor {
    ...
    process(inputs, outputs, parameters) {
        const input = inputs[0];
        const output = outputs[0];
    
        if(input.length > 0){
            const inputChannel0 = input[0];
            const outputChannel0 = output[0];
    
            for (let i = 0; i < inputChannel0.length; ++i) {
                //do something with resample here?
            }
    
            return true;
        }
    }
}
registerProcessor('resample_proc', ResampleProcesscor);

Спасибо!

2 ответа

WebAudio API теперь позволяет выполнять повторную выборку, передавая частоту дискретизации в конструкторе. Этот код работает в Chrome и Safari:

      const audioStream = await navigator.mediaDevices.getUserMedia({ audio: true, video: false })
const audioContext = new AudioContext({ sampleRate: 16000 })
const audioStreamSource = audioContext.createMediaStreamSource(audioStream);
audioStreamSource.connect(audioContext.destination)

Но не работает в Firefox, который выдаетNotSupportedErrorисключение сAudioContext.createMediaStreamSource: Connecting AudioNodes from AudioContexts with different sample-rate is currently not supported.

В приведенном ниже примере я понизил частоту звука, поступающего с микрофона, до 8 кГц и добавил задержку в одну секунду, чтобы мы могли четко слышать эффект понижения частоты дискретизации: https://codesandbox.io/s/magical-rain-xr4g80 .

Ваша общая идея выглядит неплохо. Хотя я не могу предоставить код для повторной выборки, я могу указать, что вы можете начать с преобразования частоты дискретизации. Метод 1 будет работать здесь с L/M = 160/441. Создание фильтров требует небольшой работы, но ее нужно сделать только один раз. Вы также можете поискать многофазную фильтрацию, чтобы узнать, как это сделать эффективно.

Что Chrome делает в различных частях, так это использование функции windowed-sinc для повторной выборки между любым набором частот. Это метод 2 по ссылке в Википедии.

Другие вопросы по тегам