DevelopmentJune 09, 20253 min read

Audio Recorder and Visualizer using Python and Streamlit

Record audio in the browser with Python and Streamlit — live waveform visualization, playback, and WAV export using audio-recorder-streamlit.

Galvan

Galvan

Founder & Creator

Introduction

Recording audio from a web page sounds like it needs JavaScript wizardry — and it does, but someone else already wrote it. The streamlit-audio-recorder component hands you a microphone button in one line, and your Python code receives raw WAV bytes. This app wraps that in a full toolkit: record, visualize the waveform, play it back, and download the file.

It is the audio counterpart to the webcam photo booth — both turn browser hardware into Python data — and it pairs naturally with the text-to-speech app for a record-and-compare workflow.

Features

  • One-click recording — browser mic access via a custom component.
  • Waveform plot — see your recording's shape with matplotlib.
  • Playbackst.audio player for instant review.
  • Duration + size stats — know what you captured at a glance.
  • WAV download — take your audio anywhere.
  • Prerequisites

  • Python 3.8+ — from python.org.
  • Dependencies:
  • code
    pip install streamlit streamlit-audio-recorder matplotlib numpy

    Step 1: Create the Script

    Save as audio_recorder.py:

    code
    import streamlit as st
    import numpy as np
    import io
    import wave
    import matplotlib.pyplot as plt
    from audio_recorder_streamlit import audio_recorder
    
    st.set_page_config(page_title="Audio Recorder", page_icon="🎙️")
    st.title("🎙️ Audio Recorder & Visualizer")
    
    audio_bytes = audio_recorder(
        text="Click to record",
        recording_color="#e63946",
        neutral_color="#10b981",
        icon_name="microphone",
        key="mic",
    )
    
    if audio_bytes:
        # Parse the WAV bytes for stats
        with wave.open(io.BytesIO(audio_bytes), "rb") as wf:
            frames = wf.getnframes()
            rate = wf.getframerate()
            channels = wf.getnchannels()
            duration = frames / rate
            samples = np.frombuffer(wf.readframes(frames), dtype=np.int16)
    
        c1, c2, c3 = st.columns(3)
        c1.metric("Duration", f"{duration:.1f}s")
        c2.metric("Sample rate", f"{rate} Hz")
        c3.metric("Size", f"{len(audio_bytes) / 1024:.0f} KB")
    
        # Waveform
        fig, ax = plt.subplots(figsize=(9, 3))
        step = max(1, len(samples) // 20000)  # downsample for plotting
        ax.plot(samples[::step], linewidth=0.4, color="#10b981")
        ax.set_xlabel("Sample")
        ax.set_ylabel("Amplitude")
        ax.set_ylim(-32768, 32767)
        ax.axis("off")
        st.pyplot(fig)
    
        st.audio(audio_bytes, format="audio/wav")
    
        st.download_button("⬇️ Download WAV", audio_bytes, "recording.wav", "audio/wav")
    else:
        st.info("Click the microphone to start recording.")

    Step 2: Run the App

    code
    streamlit run audio_recorder.py

    Grant microphone permission when the browser asks, record a sentence, and watch the waveform draw itself.

    How It Works

    The component handles the hard part — MediaRecorder in the browser — and hands your script a bytes object containing a complete WAV file. Everything after that is standard Python: the wave module parses the header (sample rate, channel count, frame count), and np.frombuffer turns the PCM payload into an int16 array where each value is one amplitude sample.

    The waveform plot includes a subtle but important trick: downsampling. A 30-second recording at 44.1 kHz is 1.3 million points; matplotlib plotting all of them is slow and visually identical to plotting every 66th. samples[::step] takes an even slice — the same array-slicing idea that keeps the stock dashboard responsive.

    Silence detection is one numpy expression away: np.abs(samples).mean() gives average amplitude — low values mean you recorded silence, which makes a friendly warning.

    Common Errors & Fixes

  • No mic prompt appears — browsers only grant microphone access on localhost or HTTPS; opening the app via a LAN IP will silently fail.
  • `wave.Error: file does not start with RIFF id` — the component returned a webm/ogg blob instead of WAV on some browser versions; pin the component version or convert with pydub.
  • Waveform is a flat line — amplitude axis is fine but the recording is silent; check the correct input device in system sound settings.
  • `ModuleNotFoundError: audio_recorder_streamlit` — the import name differs from the pip name; the package is streamlit-audio-recorder, imported as audio_recorder_streamlit.
  • Key Concepts

  • Custom components — community widgets bridge browser APIs into Streamlit.
  • WAV structure — a header describing the format plus raw PCM samples.
  • numpy frombuffer — bytes become typed arrays in one call.
  • Downsampling for plots — plot a representative slice, not everything.
  • What to Try Next

  • Add a live volume meter by computing RMS on short chunks.
  • Feed recordings to Whisper for transcription — see the speech-to-text tutorial.
  • Compare your pronunciation with gTTS output side by side.
  • Plot a spectrum with numpy.fft — frequency bars instead of a waveform.
  • FAQ

    Where does the audio go?

    Nowhere — the bytes flow browser → Streamlit server → your script in memory. Nothing is uploaded to third parties, unlike most online recorders.

    Can I record longer than a minute?

    Yes, though the component buffers in memory. For hour-long capture, write chunks to disk incrementally or use dedicated recording software.

    Why WAV instead of MP3?

    WAV is uncompressed and trivially parseable — no decoding libraries needed. Convert to MP3 with pydub + ffmpeg if size matters for downloads.