2017-04-21 49 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