html5 音频采样16k,html - HTML5 web audio - convert audio buffer into wav file - Stack Overflow

I figured I'd share a working solution that I managed to put together from the Kevin's answer.

Here's the waveWorker.js script:

self.onmessage = function( e ){

var wavPCM = new WavePCM( e['data']['config'] );

wavPCM.record( e['data']['pcmArrays'] );

wavPCM.requestData();

};

var WavePCM = function( config ){

this.sampleRate = config['sampleRate'] || 48000;

this.bitDepth = config['bitDepth'] || 16;

this.recordedBuffers = [];

this.bytesPerSample = this.bitDepth / 8;

};

WavePCM.prototype.record = function( buffers ){

this.numberOfChannels = this.numberOfChannels || buffers.length;

var bufferLength = buffers[0].length;

var reducedData = new Uint8Array( bufferLength * this.numberOfChannels * this.bytesPerSample );

// Interleave

for ( var i = 0; i < bufferLength; i++ ) {

for ( var channel = 0; channel < this.numberOfChannels; channel++ ) {

var outputIndex = ( i * this.numberOfChannels + channel ) * this.bytesPerSample;

var sample = buffers[ channel ][ i ];

// Check for clipping

if ( sample > 1 ) {

sample = 1;

}

else if ( sample < -1 ) {

sample = -1;

}

// bit reduce and convert to uInt

switch ( this.bytesPerSample ) {

case 4:

sample = sample * 2147483648;

reducedData[ outputIndex ] = sample;

reducedData[ outputIndex + 1 ] = sample >> 8;

reducedData[ outputIndex + 2 ] = sample >> 16;

reducedData[ outputIndex + 3 ] = sample >> 24;

break;

case 3:

sample = sample * 8388608;

reducedData[ outputIndex ] = sample;

reducedData[ outputIndex + 1 ] = sample >> 8;

reducedData[ outputIndex + 2 ] = sample >> 16;

break;

case 2:

sample = sample * 32768;

reducedData[ outputIndex ] = sample;

reducedData[ outputIndex + 1 ] = sample >> 8;

break;

case 1:

reducedData[ outputIndex ] = ( sample + 1 ) * 128;

break;

default:

throw "Only 8, 16, 24 and 32 bits per sample are supported";

}

}

}

this.recordedBuffers.push( reducedData );

};

WavePCM.prototype.requestData = function(){

var bufferLength = this.recordedBuffers[0].length;

var dataLength = this.recordedBuffers.length * bufferLength;

var headerLength = 44;

var wav = new Uint8Array( headerLength + dataLength );

var view = new DataView( wav.buffer );

view.setUint32( 0, 1380533830, false ); // RIFF identifier 'RIFF'

view.setUint32( 4, 36 + dataLength, true ); // file length minus RIFF identifier length and file description length

view.setUint32( 8, 1463899717, false ); // RIFF type 'WAVE'

view.setUint32( 12, 1718449184, false ); // format chunk identifier 'fmt '

view.setUint32( 16, 16, true ); // format chunk length

view.setUint16( 20, 1, true ); // sample format (raw)

view.setUint16( 22, this.numberOfChannels, true ); // channel count

view.setUint32( 24, this.sampleRate, true ); // sample rate

view.setUint32( 28, this.sampleRate * this.bytesPerSample * this.numberOfChannels, true ); // byte rate (sample rate * block align)

view.setUint16( 32, this.bytesPerSample * this.numberOfChannels, true ); // block align (channel count * bytes per sample)

view.setUint16( 34, this.bitDepth, true ); // bits per sample

view.setUint32( 36, 1684108385, false); // data chunk identifier 'data'

view.setUint32( 40, dataLength, true ); // data chunk length

for (var i = 0; i < this.recordedBuffers.length; i++ ) {

wav.set( this.recordedBuffers[i], i * bufferLength + headerLength );

}

self.postMessage( wav, [wav.buffer] );

self.close();

};

And here's how you can use it:

async function audioBufferToWaveBlob(audioBuffer) {

return new Promise(function(resolve, reject) {

var worker = new Worker('./waveWorker.js');

worker.onmessage = function( e ) {

var blob = new Blob([e.data.buffer], {type:"audio/wav"});

resolve(blob);

};

let pcmArrays = [];

for(let i = 0; i < audioBuffer.numberOfChannels; i++) {

pcmArrays.push(audioBuffer.getChannelData(i));

}

worker.postMessage({

pcmArrays,

config: {sampleRate: audioBuffer.sampleRate}

});

});

}

It's pretty quickly hacked together so feel free (of course) to fix it up and post a link to a better version in the comments :)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值