Engee 文档
Notebook

录音机

此示例演示用于从设备的麦克风录制音频的web应用程序的实现。 应用程序的整个周期如下所述。

  1. 用户单击←→按钮开始录制
  2. 录音期间:
    -按钮变成红色与动画
    -计时器正在运行
    -正在收集音频数据
  3. 停止时:
    -音频
    文件形成-播放器和下载按钮出现
  4. 下载创建文件"记录-{日期}。波"

下面提供了对音频记录器代码的详细分析。 代码从一个基本的HTML结构和css样式开始,以获得一个美丽的界面.:

<div class="container">
    <div class="title">Audio Recorder</div>
    <div class="timer" id="timer">00:00</div>
    <button id="recordBtn">🎤</button>
    <button class="download-btn hidden" id="downloadBtn" title="Download recording"></button>
    <div id="status">Press 🎤 to start recording</div>
    <div class="audio-container" id="audioContainer">
        <audio id="audioPlayer" controls></audio>
    </div>
</div>

关键要素:

  • recordBtn -圆形记录按钮,
  • downloadBtn -下载按钮(最初隐藏),
  • timer -显示录制时间,
  • audioPlayer -播放录制音频的元素。

接下来是变量的初始化

let mediaRecorder;
let audioChunks = [];
let audioBlob;
let audioUrl;
let startTime;
let timerInterval;
let stream;
let isRecording = false;

变量存储应用程序状态:

  • mediaRecorder -用于记录媒体的对象,
  • audioChunks -用于存储记录数据的阵列,
  • audioBlob/audioUrl -最终音频,
  • timerInterval -更新计时器,
  • stream -来自麦克风的数据流。

之后,声明辅助函数。

function formatTime(seconds) {
    const mins = Math.floor(seconds / 60).toString().padStart(2, '0');
    const secs = Math.floor(seconds % 60).toString().padStart(2, '0');
    return `${mins}:${secs}`;
}

function updateTimer() {
    const elapsed = Math.floor((Date.now() - startTime) / 1000);
    timerElement.textContent = formatTime(elapsed);
}

formatTime 将秒转换为"MM:SS"格式,以及 updateTimer 更新计时器显示。

接下来是录音启动功能。

function startRecording() {
    navigator.mediaDevices.getUserMedia({ audio: true })
        .then(function(s) {
            stream = s;
            mediaRecorder = new MediaRecorder(stream);
            audioChunks = [];
            
            mediaRecorder.ondataavailable = function(e) {
                if (e.data.size > 0) {
                    audioChunks.push(e.data);
                }
            };
            
            mediaRecorder.onstop = function() {
                audioBlob = new Blob(audioChunks, { type: 'audio/wav' });
                audioUrl = URL.createObjectURL(audioBlob);
                audioPlayer.src = audioUrl;
                downloadBtn.classList.remove('hidden');
                statusElement.textContent = "Recording saved! Click 🎤 to record again";
            };
            
            mediaRecorder.start(100);
            startTime = Date.now();
            timerInterval = setInterval(updateTimer, 1000);
            updateTimer();
            isRecording = true;
            recordBtn.classList.add('recording');
            recordBtn.textContent = "⏹️";
            statusElement.textContent = "Recording... Click ⏹️ to stop";
        })
        .catch(function(err) {
            console.error('Error accessing microphone:', err);
            statusElement.textContent = "Error accessing microphone";
        });
}

操作的逻辑如下所述。

  1. 通过以下方式请求访问麦克风 getUserMedia
  2. 创建 MediaRecorder 记录流
  3. 设置处理程序:
    • ondataavailable -收集音频片段,
    • onstop -创建最终文件并显示下载按钮。
  4. 启动计时器并更改界面

之后,实施记录停止。

function stopRecording() {
    if (mediaRecorder && mediaRecorder.state !== 'inactive') {
        mediaRecorder.stop();
        clearInterval(timerInterval);
        stream.getTracks().forEach(track => track.stop());
        isRecording = false;
        recordBtn.classList.remove('recording');
        recordBtn.textContent = "🎤";
    }
}

停止录制、计时器和释放麦克风资源。

并下载录音:

function downloadRecording() {
    if (audioUrl) {
        const a = document.createElement('a');
        a.href = audioUrl;
        const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
        a.download = `recording-${timestamp}.wav`;
        a.click();
        statusElement.textContent = "Download started...";
    }
}

为具有唯一名称的文件创建临时下载链接。

还有一个事件处理程序,允许录制按钮作为启动/停止开关工作,并且还可以将整个界面及其更新链接到音频文件录制事件。

recordBtn.addEventListener('click', function() {
    if (isRecording) {
        stopRecording();
    } else {
        startRecording();
    }
});

downloadBtn.addEventListener('click', downloadRecording);

现在让我们启动应用程序本身,看看它是如何工作的。

In [ ]:
display("text/html", read("audio_recorder.html", String))

结论

此示例和工具本身可用于为DSP生成测试数据样本。