2017-04-21 4 views
2

브라우저에서 PCM 오디오를 재생할 때 문제가 발생했습니다. PCM 오디오는 udp-protocol이있는 안드로이드 장치에서 가져온 것으로 서버에 * .raw로 저장됩니다.자바 스크립트로 PCM 재생

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)은 단일 8 비트 바이트를 나타내는 0에서 255 사이의 값을 생성합니다. 당신은 16 비트가 필요합니다. (MSB 먼저) 빅 엔디안

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

:

당신은 샘플의 바이트 순서를 알고, (첫번째 LSB) 리틀 엔디안를 들어 두 바이트마다

을 처리해야

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

부호없는 16 비트 정수를 나타내는 0에서 65535 사이의 숫자가됩니다. 부호있는 정수로 변환하기 위해, 당신이 당신이 다음에 순서대로 32768.0로 나눌 수 있습니다 -32768에서 32767 사이의 숫자를 얻을 것입니다

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

다음 (위의 코드와 X를 대체)를 할 필요가 원하는 결과를 얻으십시오.

nowBuffering[i] = signedWord/32768.0; 

편집 : 작동 예를 https://o.lgm.cl/example.html (16 비트 LSB)

0

@Locolois

나는 당신의 제안/솔루션을 시도

불행히도 여전히 원래 같은 소리하지 않았다 분명한 소리를 얻을 . 매초마다 화이트 노이즈가 발생했는데, 그것은 내 해결책보다 덜 오싹했다. 그러나 나는 아직도 내가 녹음 한 내 목소리를 듣지 않았다. android.audiorecord 수출에 큰 또는 작은 엔디안이있는 pcm이 있는지 잘 모르겠습니다. 그래서 두 가지 방법을 시도했습니다. 그러나 빅 엔디안에 대한 제안을 사용하여 들었던 사운드는 리틀 엔디안 버전보다 나에게 정확합니다. 리틀 엔디안 버전도 화이트 노이즈가있었습니다.

내 솔루션에 오류가 발생했습니다 당신의 설명?

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

나는 당신의 모범으로 그것을 시도합니다. 여전히 작동하지 않습니다 .../ 예제와 함께이 raw를 재생해볼 수 있습니까? http://taxameter.esy.es/example.raw –

+0

다른 모든 프레임을 제공하는 것이 좋습니다. 그들이 부드러운 데이터를 가지고 있기 때문에 나의 예제가 효과가 있었다. 나는 대답과 실천 사례를 업데이트했다. 또한'audioCtx.sampleRate'를 전혀 사용하거나 사용하지 않아도됩니다. – Locoluis