2017-04-21 70 views
2

我在浏览器上播放PCM音频时遇到了一些问题。 PCM音频来自udp协议的android设备,并以* .raw使用javascript播放PCMD

保存在服务器上。我尝试使用webaudioapi播放此保存的文件失败。使用下面的代码,扮演我一些令人毛骨悚然的声音,白噪声:

var audioCtx = new (window.AudioContext || window.webkitAudioContext)(); 
audioCtx.sampleRate = 16000; 


// Stereo 
var channels = 1; 
// Create an empty two second stereo buffer at the 
// sample rate of the AudioContext 
var frameCount = audioCtx.sampleRate * 10.0; 

var myAudioBuffer = audioCtx.createBuffer(channels, frameCount, audioCtx.sampleRate); 


var req = new XMLHttpRequest(); 
req.open('GET', "example.raw", false); 
req.overrideMimeType('text\/plain; charset=x-user-defined'); 
req.send(null); 

function play(){ 
    for (var channel = 0; channel < channels; channel++) { 

     var nowBuffering = myAudioBuffer.getChannelData(channel,16,16000); 
     for (var i = 0; i < frameCount; i++) { 
      // audio needs to be in [-1.0; 1.0] 
      // for this reason I also tried to divide it by 32767 
      // as my pcm sample is in 16-Bit. It plays still the 
      // same creepy sound less noisy. 
      nowBuffering[i] = (req.responseText.charCodeAt(i) & 0xff; 

     } 
    } 
    // Get an AudioBufferSourceNode. 
    // This is the AudioNode to use when we want to play an AudioBuffer 
    var source = audioCtx.createBufferSource(); 
    // set the buffer in the AudioBufferSourceNode 
    source.buffer = myAudioBuffer; 
    // connect the AudioBufferSourceNode to the 
    // destination so we can hear the sound 
    source.connect(audioCtx.destination); 
    // start the source playing 
    source.start(); 
} 

它扮演这样一个无法辨认的声音,我不知道,如果是打我认为它必须做的PCM文件。

我假设它必须对pcm文件做些什么。 PCM文件具有16 kHz的采样率,每个采样16位,只有一个通道或者单通道。

任何人在这里有相同的问题,或有人有任何建议来解决我的问题?

我在寻找一些解决方案,并感谢任何帮助。

回答

5

首先:

audioCtx.sampleRate = 16000;不起作用。您无法修改audioCtx.sampleRate。相反,您需要执行以下操作:

var frameCount = req.responseText.length/2; 
var myAudioBuffer = audioCtx.createBuffer(channels, frameCount, 16000); 

由于您的文件是16位,所以它的字节长度是您需要的帧数的两倍。

(req.responseText.charCodeAt(i) & 0xff)将产生0到255之间的值,表示单个8位字节。你需要16位。

你需要知道你的样品的字节顺序,每一次

处理两个字节的小端(LSB在前):

var word = (req.responseText.charCodeAt(i * 2) & 0xff) + ((req.responseText.charCodeAt(i * 2 + 1) & 0xff) << 8); 

大端(高位在前):

var unsignedWord = ((req.responseText.charCodeAt(i * 2) & 0xff) << 8) + (req.responseText.charCodeAt(i * 2 + 1) & 0xff); 

这将产生一个0到65535之间的数字,表示一个无符号的16位整数。为了转换为符号整数,你需要做以下(与上面的代码替换X)

var signedWord = (unsignedWord + 32768) % 65536 - 32768; 

这将产生-32768和32767,您可以通过32768.0为了再划分到之间的数字获得你想要的结果。

nowBuffering[i] = signedWord/32768.0; 

编辑:工作实例https://o.lgm.cl/example.html(16位LSB)

0

@Locolois

我想你的建议/解决方案,并得到一些明确的声音,不幸的是仍然没有听起来像原来的。它每秒也有白色的噪音,这比我的解决方案更令人毛骨悚然:但我仍然没有听到我记录的声音。我不知道如果pcm,其中android.audiorecord导出有大或小的endian,所以我尝试了两种方法。但是,我听到的声音,通过使用你为大端编写的建议,听起来比小端编码更正确。小端版本也充满了白色噪音。

是它的正确实施,你的解释?:

for (var i = 0; i < frameCount; i+=2) { 

      var msbFirst = (req.responseText.charCodeAt(i) & 0xff) + (req.responseText.charCodeAt(i + 1) & 0xff) << 8; 
      var msbSigned = (msbFirst + 32768) % 65536 - 32768; 
      nowBuffering[i] = msbSigned/65536.0; 
     } 
+0

有我的解决方案的错误。我提交了一个修复并添加了一个例子。 – Locoluis

+0

我试着用你的例子。它仍然不起作用...:/ 你可以尝试用你的例子玩这个原料吗? http://taxameter.esy.es/example.raw –

+0

好吧,我知道这一切都错了,提供其他每一帧。我的例子工作,因为他们有平稳的数据。我更新了答案和工作示例。另外,根本不需要使用或混淆audioCtx.sampleRate。 – Locoluis