Speex разделили аудио данные - WebAudio - VOIP
Я запускаю небольшое приложение, которое кодирует и декодирует аудио массив с кодеком speex в javascript: https://github.com/dbieber/audiorecorder
с небольшим массивом, заполненным синусоидальным сигналом
for(var i=0;i<16384;i++)
data.push(Math.sin(i/10));
это работает. Но я хочу создать приложение VOIP и иметь более одного массива. Поэтому, если я разделю массив на две части: закодировать> декодировать> объединить, он будет звучать не так, как раньше.
Взгляните на это:
скрипка: http://jsfiddle.net/exh63zqL/
Обе кнопки должны давать одинаковый аудиовыход.
Как я могу получить один и тот же вывод в обоих направлениях? Это специальный режим в speex.js для разделения аудиоданных?
2 ответа
Speex - это кодек с потерями, поэтому выходной сигнал является лишь приблизительным значением вашей начальной синусоидальной волны.
Ваша синусоидальная частота составляет около 7 кГц, что близко к верхней полосе кодека 8 кГц и, как таковая, еще более вероятно, будет изменено.
То, что выводит кодек, выглядит как комбинация дираковых импульсов, которые будут звучать как ваша первоначальная синусоида, которая слышна через телефон, что, безусловно, отличается от оригинала.
Посмотрите эту скрипку, где вы можете послушать, что кодек делает из ваших первоначальных синусоидальных волн, будь они разделены пополам или нет.
//Generate a continus sinus in 2 arrays
var len = 16384;
var buffer1 = [];
var buffer2 = [];
var buffer = [];
for(var i=0;i<len;i++){
buffer.push(Math.sin(i/10));
if(i < len/2)
buffer1.push(Math.sin(i/10));
else
buffer2.push(Math.sin(i/10));
}
//Encode and decode both arrays seperatly
var en = Codec.encode(buffer1);
var dec1 = Codec.decode(en);
var en = Codec.encode(buffer2);
var dec2 = Codec.decode(en);
//Merge the arrays to 1 output array
var merge = [];
for(var i in dec1)
merge.push(dec1[i]);
for(var i in dec2)
merge.push(dec2[i]);
//encode and decode the whole array
var en = Codec.encode(buffer);
var dec = Codec.decode(en);
//-----------------
//Down under is only for playing the 2 different arrays
//-------------------
var audioCtx = new window.AudioContext || new window.webkitAudioContext;
function play (sound)
{
var audioBuffer = audioCtx.createBuffer(1, sound.length, 44100);
var bufferData = audioBuffer.getChannelData(0);
bufferData.set(sound);
var source = audioCtx.createBufferSource();
source.buffer = audioBuffer;
source.connect(audioCtx.destination);
source.start();
}
$("#o").click(function() { play(dec); });
$("#c1").click(function() { play(dec1); });
$("#c2").click(function() { play(dec2); });
$("#m").click(function() { play(merge); });
Если вы объедините два выходных сигнала декодера половинного сигнала, вы услышите дополнительный щелчок из-за резкого перехода от одного сигнала к другому, звучащему в основном как коммутация реле.
Чтобы избежать этого, вам придется сгладить значения вокруг точки слияния двух ваших буферов.
Обратите внимание, что Speex - это кодек с потерями. Таким образом, по определению, он не может дать тот же результат, что и закодированный буфер. Кроме того, он предназначен для кодека для голоса. Таким образом, диапазон 1-2 кГц будет наиболее эффективным, поскольку он рассчитывает на конкретную форму сигнала. В некотором смысле это можно сравнить с технологией JPEG для растровых изображений.
Я немного изменил ваш пример jsfiddle, чтобы вы могли играть с различными параметрами и сравнивать результаты. Предоставление простой синусоиды с неизвестной частотой не является правильным способом проверки кодека. Однако в примере вы можете увидеть различное влияние на исходный сигнал на разных частотах.
buffer1.push(Math.sin(2*Math.PI*i*frequency/sampleRate));
Я думаю, что вы должны построить пример с записанным голосом и сравнить результаты в этом случае. Было бы правильнее.
В общем, чтобы получить представление в деталях, вам нужно изучить цифровую обработку сигналов. Я даже не могу дать правильную ссылку, так как это целая наука, и она математически интенсивна. (единственная книга для чтения, которую я знаю, на русском). Если бы кто-то здесь с сильным образованием по математике мог поделиться соответствующей литературой для этого случая, я был бы признателен.
РЕДАКТИРОВАТЬ: как упомянуто Kuroi Neko, есть проблема с границами буфера. И кажется, что невозможно сохранить состояние декодера, как упомянуто в этом посте, потому что используемая библиотека не поддерживает его. Если вы посмотрите на исходный код, то увидите, что они используют сторонний кодек speex и не предоставляют полный доступ к его функциям. Я думаю, что лучшим подходом было бы найти приличную библиотеку для Speex, которая поддерживает восстановление состояния, подобное этому