Есть ли способ пересэмплировать аудиопоток с помощью 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 по ссылке в Википедии.