音频录制小妙招-自制工具-借助浏览器录一段单声道16000采样率wav格式音频
先看效果
1、打开页面
2、点击开始录音,弹出权限提示,点击“仅这次访问时允许”
3、录完后,点击停止
4、文件自动下载到默认目录
上代码
js 部分
document.addEventListener('DOMContentLoaded', () => {
const startBtn = document.getElementById('startBtn');
const stopBtn = document.getElementById('stopBtn');
const audioPlayback = document.getElementById('audioPlayback');
let mediaRecorder;
let audioChunks = [];
startBtn.addEventListener('click', async () => {
try {
// Request access to the microphone
const stream = await navigator.mediaDevices.getUserMedia({ audio: { channelCount: 1, sampleRate: 16000 } });
if (!stream) {
throw new Error('No media stream received.');
}
// Create a MediaRecorder instance with specific settings
mediaRecorder = new MediaRecorder(stream, {
mimeType: 'audio/webm'
});
mediaRecorder.ondataavailable = event => {
audioChunks.push(event.data);
};
mediaRecorder.onstop = () => {
const audioBlob = new Blob(audioChunks, { type: 'audio/webm' });
convertWebmToWav(audioBlob);
audioChunks = [];
};
mediaRecorder.start();
startBtn.disabled = true;
stopBtn.disabled = false;
} catch (err) {
console.error('Error accessing microphone:', err);
alert('Error accessing microphone: ' + err.message);
}
});
stopBtn.addEventListener('click', () => {
if (mediaRecorder && mediaRecorder.state !== 'inactive') {
mediaRecorder.stop();
}
startBtn.disabled = false;
stopBtn.disabled = true;
});
function convertWebmToWav(webmBlob) {
const reader = new FileReader();
reader.onloadend = () => {
const arrayBuffer = reader.result;
const audioContext = new AudioContext();
audioContext.decodeAudioData(arrayBuffer, audioBuffer => {
const samples = audioBuffer.getChannelData(0);
const buffer = createWav(samples, audioBuffer.sampleRate);
const blob = new Blob([buffer], { type: 'audio/wav' });
const audioUrl = URL.createObjectURL(blob);
audioPlayback.src = audioUrl;
// Save or download the blob as a WAV file
const link = document.createElement('a');
link.href = audioUrl;
link.download = 'recorded_audio.wav';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}, error => {
console.error('Error decoding audio data:', error);
});
};
reader.readAsArrayBuffer(webmBlob);
}
function createWav(samples, sampleRate) {
const buffer = new ArrayBuffer(44 + samples.length * 2);
const view = new DataView(buffer);
// RIFF identifier
writeString(view, 0, 'RIFF');
// file length minus RIFF identifier length and file description length
view.setUint32(4, 36 + samples.length * 2, true);
// RIFF type
writeString(view, 8, 'WAVE');
// format chunk identifier
writeString(view, 12, 'fmt ');
// format chunk length
view.setUint32(16, 16, true);
// sample format (raw)
view.setUint16(20, 1, true);
// channel count
view.setUint16(22, 1, true);
// sample rate
view.setUint32(24, sampleRate, true);
// byte rate (sample rate * block align)
view.setUint32(28, sampleRate * 2, true);
// block align (channel count * bytes per sample)
view.setUint16(32, 2, true);
// bits per sample
view.setUint16(34, 16, true);
// data chunk identifier
writeString(view, 36, 'data');
// data chunk length
view.setUint32(40, samples.length * 2, true);
floatTo16BitPCM(view, 44, samples);
return buffer;
}
function floatTo16BitPCM(output, offset, input) {
for (let i = 0; i < input.length; i++, offset += 2) {
const s = Math.max(-1, Math.min(1, input[i]));
output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
}
}
function writeString(view, offset, string) {
for (let i = 0; i < string.length; i++) {
view.setUint8(offset + i, string.charCodeAt(i));
}
}
});
html部分
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Audio Recorder</title>
</head>
<body>
<h1>Audio Recorder</h1>
<button id="startBtn">Start Recording</button>
<button id="stopBtn" disabled>Stop Recording</button>
<br><br>
<audio id="audioPlayback" controls></audio>
<script src="recorder.js"></script>
</body>
</html>