概述WebAudio 可从麦克风采集 PCM。本文示例封装 WAV 头并保存。采集与封装async function capturePCM() {

const stream = await navigator.mediaDevices.getUserMedia({ audio: true });

const ctx = new AudioContext();

const src = ctx.createMediaStreamSource(stream);

const processor = ctx.createScriptProcessor(4096, 1, 1);

const chunks = [];

processor.onaudioprocess = e => { const data = e.inputBuffer.getChannelData(0); chunks.push(Float32Array.from(data)); };

src.connect(processor); processor.connect(ctx.destination);

return { stop: async () => { processor.disconnect(); src.disconnect(); stream.getTracks().forEach(t => t.stop()); return chunks; } };

}

function pcmToWav(floatChunks, sampleRate = 44100) {

const samples = Float32Array.from(floatChunks.reduce((a,c) => a.concat(Array.from(c)), []));

const buf = new ArrayBuffer(44 + samples.length * 2);

const view = new DataView(buf);

const writeStr = (off, s) => { for (let i=0;i<s.length;i++) view.setUint8(off+i, s.charCodeAt(i)); };

writeStr(0, 'RIFF'); view.setUint32(4, 36 + samples.length * 2, true); writeStr(8, 'WAVE'); writeStr(12, 'fmt ');

view.setUint32(16, 16, true); view.setUint16(20, 1, true); view.setUint16(22, 1, true); view.setUint32(24, sampleRate, true);

view.setUint32(28, sampleRate * 2, true); view.setUint16(32, 2, true); view.setUint16(34, 16, true);

writeStr(36, 'data'); view.setUint32(40, samples.length * 2, true);

let off = 44; for (let i=0;i<samples.length;i++) { const s = Math.max(-1, Math.min(1, samples[i])); view.setInt16(off, s < 0 ? s * 0x8000 : s * 0x7FFF, true); off += 2; }

return new Blob([buf], { type: 'audio/wav' });

}

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部