Audio Recorder
This example shows the implementation of a web application for recording audio from your device's microphone. The full cycle of the application is described below.
- The user clicks the 🎤 → button to start recording
- During recording:
- The button turns red with animation
- The timer is running
- Audio data is being collected
- When stopping:
- An audio
file is formed - A player and a download button appear
- Downloading creates the file "recording-{date}.wav"
A detailed analysis of the audio recorder code is provided below. The code starts with a basic HTML structure and CSS styles for a beautiful interface.:
<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>
Key elements:
recordBtn– round record button,downloadBtn– download button (initially hidden),timer– displays the recording time,audioPlayer– an element for playing recorded audio.
Next comes the initialization of variables
let mediaRecorder;
let audioChunks = [];
let audioBlob;
let audioUrl;
let startTime;
let timerInterval;
let stream;
let isRecording = false;
Variables store the application state:
mediaRecorder– an object for recording media,audioChunks– an array for storing recorded data,audioBlob/audioUrl– final audio,timerInterval– to update the timer,stream– data stream from the microphone.
After that, auxiliary functions are declared.
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 converts seconds to the "MM:SS" format, and updateTimer updates the timer display.
Next comes the recording startup function.
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";
});
}
The logic of the operation is described below.
- Request access to the microphone via
getUserMedia - Create
MediaRecorderto record a stream - Setting up handlers:
ondataavailable– collects pieces of audio,onstop– creates the final file and shows the download button.
- Start the timer and change the interface
After that, the recording stop is implemented.
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 = "🎤";
}
}
Stops recording, timer, and releases microphone resources.
And downloading the recording:
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...";
}
}
Creates a temporary download link for a file with a unique name.
There is also one event handler that allows the recording buttons to work as a start/stop switch, and also makes it possible to link the entire interface and its update to the audio file recording event.
recordBtn.addEventListener('click', function() {
if (isRecording) {
stopRecording();
} else {
startRecording();
}
});
downloadBtn.addEventListener('click', downloadRecording);
Now let's launch the app itself and see how it works.
display("text/html", read("audio_recorder.html", String))
Conclusion
This example and the tool itself can be useful for generating test data samples for DSP.