2012-10-10 187 views
3

我正在开发一个基于社区的Internet Radio,用户可以在其中录制自己的消息。网络音频Api输出

我希望我的用户能够影响到他们的录音(如双二阶滤波器,混响ASO ..)

是否有可能到最后的混音(包括效果)处理到一个PCM输出(例如音频标签src="data:audio/wav;base64"),所以我可以通过邮件发送混合到服务器?

我尝试这样做:

recorder.locals.filter1.connect(recorder.locals.filter3); 
recorder.locals.filter3.connect(recorder.locals.filter2); 
recorder.locals.filter2.connect(context.destination); 
recorder.locals.source.noteOn(0); 
context.oncomplete = function(e) { var buffer = e.renderedBuffer; }; 
context.startRendering(); 

但它并没有给我任何东西。

回答

7

我找到了解决方案。看起来在使用startRendering()时,您必须在创建时为上下文提供durationsamplerate

new webkitAudioContext(channels, duration * samplerate, samplerate);

这里是我的解决方案来生成预渲染audioBuffer并将其转换为base64 wav。

var audioBuffer = audio.createBuffer(arrayBuffer, false), /* <- Input Audio */ 
    offlineContext = new webkitAudioContext(1, audioBuffer.duration * 44100, 44100); 

offlineContext.oncomplete = function(event) { 

    var buffer = event.renderedBuffer;  
    var UintWave = createWaveFileData(buffer); 
    var base64 = btoa(uint8ToString(UintWave)); 

    document.getElementById("audio").src = "data:audio/wav;base64," + base64; 

}; 

var source = offlineContext.createBufferSource(); 
source.buffer = audioBuffer; 
var gain = offlineContext.createGainNode(); 
// Effects 
var filter1 = offlineContext.createBiquadFilter(); 
filter1.type = 2; 
filter1.frequency.value = 4000; 
filter1.Q.value = 0.1; 
// Connect 
source.connect(filter1); 
filter1.connect(gain); 
gain.connect(offlineContext.destination); 

source.noteOn(0); 
offlineContext.startRendering(); 

function createWaveFileData(audioBuffer) { 

    var frameLength = audioBuffer.length; 
    var numberOfChannels = audioBuffer.numberOfChannels; 
    var sampleRate = audioBuffer.sampleRate; 
    var bitsPerSample = 16; 
    var byteRate = sampleRate * numberOfChannels * bitsPerSample/8; 
    var blockAlign = numberOfChannels * bitsPerSample/8; 
    var wavDataByteLength = frameLength * numberOfChannels * 2; // 16-bit audio 
    var headerByteLength = 44; 
    var totalLength = headerByteLength + wavDataByteLength; 

    var waveFileData = new Uint8Array(totalLength); 

    var subChunk1Size = 16; // for linear PCM 
    var subChunk2Size = wavDataByteLength; 
    var chunkSize = 4 + (8 + subChunk1Size) + (8 + subChunk2Size); 

    writeString("RIFF", waveFileData, 0); 
    writeInt32(chunkSize, waveFileData, 4); 
    writeString("WAVE", waveFileData, 8); 
    writeString("fmt ", waveFileData, 12); 

    writeInt32(subChunk1Size, waveFileData, 16);  // SubChunk1Size (4) 
    writeInt16(1, waveFileData, 20);     // AudioFormat (2) 
    writeInt16(numberOfChannels, waveFileData, 22); // NumChannels (2) 
    writeInt32(sampleRate, waveFileData, 24);   // SampleRate (4) 
    writeInt32(byteRate, waveFileData, 28);   // ByteRate (4) 
    writeInt16(blockAlign, waveFileData, 32);   // BlockAlign (2) 
    writeInt32(bitsPerSample, waveFileData, 34);  // BitsPerSample (4) 

    writeString("data", waveFileData, 36);    
    writeInt32(subChunk2Size, waveFileData, 40);  // SubChunk2Size (4) 

    // Write actual audio data starting at offset 44. 
    writeAudioBuffer(audioBuffer, waveFileData, 44); 

    return waveFileData; 

} 

function writeString(s, a, offset) { 
    for (var i = 0; i < s.length; ++i) { 
     a[offset + i] = s.charCodeAt(i); 
    } 
} 

function writeInt16(n, a, offset) { 
    n = Math.floor(n); 

    var b1 = n & 255; 
    var b2 = (n >> 8) & 255; 

    a[offset + 0] = b1; 
    a[offset + 1] = b2; 
} 

function writeInt32(n, a, offset) { 
    n = Math.floor(n); 
    var b1 = n & 255; 
    var b2 = (n >> 8) & 255; 
    var b3 = (n >> 16) & 255; 
    var b4 = (n >> 24) & 255; 

    a[offset + 0] = b1; 
    a[offset + 1] = b2; 
    a[offset + 2] = b3; 
    a[offset + 3] = b4; 
} 

function writeAudioBuffer(audioBuffer, a, offset) { 
    var n = audioBuffer.length; 
    var channels = audioBuffer.numberOfChannels; 

    for (var i = 0; i < n; ++i) { 
     for (var k = 0; k < channels; ++k) { 
      var buffer = audioBuffer.getChannelData(k); 
      var sample = buffer[i] * 32768.0; 

      // Clip samples to the limitations of 16-bit. 
      // If we don't do this then we'll get nasty wrap-around distortion. 
      if (sample < -32768) 
       sample = -32768; 
      if (sample > 32767) 
       sample = 32767; 

      writeInt16(sample, a, offset); 
      offset += 2; 
     } 
    } 
} 

function uint8ToString(buf) { 
    var i, length, out = ''; 
    for (i = 0, length = buf.length; i < length; i += 1) { 
     out += String.fromCharCode(buf[i]); 
    } 
    return out; 
} 

如果有人找出更容易或更短的方式来做到这一点,那将是太棒了!

+0

谢谢!正在寻找这个 – Thomas