当前位置: 首页 > article >正文

音频录制小妙招-自制工具-借助浏览器录一段单声道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>


http://www.kler.cn/a/596024.html

相关文章:

  • RAG 架构地基工程-Retrieval 模块的系统设计分享
  • 论文笔记(七十三)Gemini Robotics: Bringing AI into the Physical World
  • HarmonyOS next性能优化:多维度策略与实战案例
  • 同旺科技USB to I2C 适配器 ---- 扫描I2C总线上的从机地址
  • Function Calling的核心机制与挑战
  • Python接口自动化浅析unittest单元测试原理
  • GEO与AISEO全面解析
  • leetcode684.冗余连接
  • Python列表2
  • 单页响应式 图片懒加载HTML页面
  • 【资料分享】全志科技T113-i全国产(1.2GHz双核A7 RISC-V)工业核心板规格书
  • 【力扣/代码随想录】数组
  • 国产AI编程工具,助力3D“微”引擎开发!——从一场直播到工业科技需求的革新实践
  • idea 编译打包nacos2.0.3源码,生成可执行jar 包常见问题
  • W80x使用WM IoT SDK 2.X 开发(二)驱动tft屏幕
  • 自定义对象处理请求参数
  • MySQL 性能优化方向
  • vpc网络之间的关系
  • react学习1.搭建react环境
  • 常用的git和linux命令有哪些?