Skip to main content
    _             _ _            ____                  _              ____ _     ___
   / \  _   _  __| (_) ___      / ___| _ __   ___  ___| |_ _ __ __ _ / ___| |   |_ _|
  / _ \| | | |/ _` | |/ _ \ ____\___ \| '_ \ / _ \/ __| __| '__/ _` | |   | |    | |
 / ___ \ |_| | (_| | | (_) |_____|__) | |_) |  __/ (__| |_| | | (_| | |___| |___ | |
/_/   \_\__,_|\__,_|_|\___/     |____/| .__/ \___|\___|\__|_|  \__,_|\____|_____|___|
                                      |_|

cover.png

Audio-SpectraCLI visualizes real-time audio input as a spectrum using the Fast Fourier Transform (FFT) - as a native Python/PyQt5 desktop app, a live VS Code extension, and a hosted web app with an API - all three built on the same FFT/DSP approach.

PRs Welcome Visitors GitHub forks GitHub Repo stars GitHub last commit GitHub repo size GitHub issues GitHub closed issues GitHub pull requests GitHub closed pull requests

Audio-SpectraCLI - Visualizing real-time audio input as a spectrum using FFT | Product Hunt


Table of Contents


What's New in v5.0.0

This release adds a full CRUD-style feature layer on top of the existing engine, across all three products, without changing the existing engine, protocols, or public API - every prior feature keeps working exactly as before.

Native GUI / core engine:

  • Named preset manager (save/load/rename/delete), seeded with 3 hardware-tuned builtin presets (Balanced, Low Power for constrained machines, High Detail).
  • RMS meter, clip warning, and sustained-silence warning, computed from every captured audio block.
  • Peak-frequency history sparkline.
  • A/B settings compare (two in-memory slots).
  • Local, append-only session-history log (device, duration, avg BPM), with a viewer + clear action.
  • Recent Exports/Recordings manager (tracks every PNG/CSV/WAV write, with open-folder and delete actions).
  • Named device profiles (matched by device name, not numeric index - portable across machines).

VS Code extension:

  • Live status bar item (dominant frequency/peak magnitude while visualizing).
  • Audio-SpectraCLI: Save Current Frame as Preset command, interoperable with the GUI's own preset store.
  • Configurable visualizer bar color.

Web visualizer:

  • localStorage-backed local presets - no sign-in required.
  • Live session-stats panel (RMS/clip/silence + frequency sparkline), reusing data already being read each frame.
  • Shareable visualizer configs via URL query parameters + a "Copy Share Link" button.

Security & hygiene:

  • Bumped @vscode/vsce and vitest toolchains, resolving every then-open Dependabot alert reachable through real dependency resolution.
  • Two bugs found and fixed via an actual end-to-end pass against real hardware (not just mocks) - see CHANGELOG.md for specifics.

Three Products, One Engine

Product Where What it is
Native GUI Audio_SpectraCLI/main.py The original PyQt5 desktop app - 5 view modes, MIDI-out, exports, presets, device profiles, session history.
Headless CLI Audio_SpectraCLI/headless.py GUI-free, JSON-lines-over-stdout streaming mode. Same engine, no PyQt5 needed.
VS Code Extension audiospectra-cli/ Spawns the headless CLI and renders it live inside a VS Code webview + status bar.
Web App web/ A hosted, browser-only visualizer (Next.js) with accounts, billing, and a server-side Analysis API. Its DSP is a parallel TypeScript implementation, not shared code with the Python core.

All four share the same conceptual FFT/windowing/downsampling approach; only the native GUI, headless CLI, and VS Code extension share actual code (engine.py/analysis.py) and on-disk data (presets, in ~/.audiospectra_cli/).

Architecture

graph TB
    subgraph Hardware
        MIC[Microphone]
        MIDIPORT[Virtual MIDI Port]
    end

    subgraph "Python Core (Audio_SpectraCLI/)"
        ENGINE["engine.py<br/>AudioSpectrumEngine<br/>(capture + FFT + smoothing)"]
        ANALYSIS["analysis.py<br/>(windowing, dB, notes, BPM,<br/>RMS, clipping, sparkline)"]
        MAIN["main.py<br/>PyQt5 GUI"]
        HEADLESS["headless.py<br/>JSON-lines CLI"]
        MIDIOUT["midi_out.py"]
        PRESETS["presets.py"]
        SESSIONS["session_history.py"]
        EXPORTS["export_manifest.py"]
        DEVICES["device_profiles.py"]
    end

    subgraph "VS Code Extension (audiospectra-cli/)"
        EXT["extension.ts<br/>commands + status bar"]
        PANEL["visualizerPanel.ts<br/>spawns headless.py,<br/>owns the webview"]
        PARSER["lineParser.ts<br/>parses JSON lines"]
    end

    subgraph "Web App (web/, Next.js)"
        VIZ["Visualizer.tsx<br/>AnalyserNode + Canvas FFT"]
        API["/api/v1/analyze<br/>server-side Analysis API"]
        DB[("Postgres (Neon)<br/>users / presets / apiKeys")]
        LS[("Browser localStorage<br/>local presets")]
    end

    MIC --> ENGINE
    ENGINE --> ANALYSIS
    ANALYSIS --> MAIN
    ANALYSIS --> HEADLESS
    MAIN --> MIDIOUT --> MIDIPORT
    MAIN <--> PRESETS
    MAIN <--> SESSIONS
    MAIN <--> EXPORTS
    MAIN <--> DEVICES

    HEADLESS -- "stdout: JSON lines" --> PANEL
    PANEL --> PARSER --> EXT
    PANEL -.->|"reads/writes<br/>~/.audiospectra_cli/presets/"| PRESETS

    MIC -.->|"getUserMedia<br/>(browser)"| VIZ
    VIZ <--> LS
    VIZ -.->|"WAV/MP3/AAC upload"| API
    API <--> DB

How Data Flows

1. Native GUI: capture → FFT → render → (optional) MIDI

sequenceDiagram
    participant Mic as Microphone
    participant Stream as sounddevice.InputStream
    participant Worker as engine._process_audio (thread)
    participant GUI as main.py (Qt main thread)
    participant Midi as midi_out.MidiNoteSender

    Mic->>Stream: raw audio blocks
    Stream->>Worker: queued via audio_queue
    Worker->>Worker: select channel, on_audio_block(samples)<br/>(RMS, clipping, silence streak)
    Worker->>Worker: window → rfft → smooth
    alt max_magnitude > noise_threshold
        Worker->>GUI: on_spectrum(freq_bins, spectrum, max_magnitude)
        Note over GUI: stashed as "latest frame",<br/>not drawn immediately
    end
    loop every 33ms (QTimer)
        GUI->>GUI: render latest stashed frame<br/>(view mode, peak-hold, stats row, sparkline)
        GUI->>Midi: send_note_for_frequency(dominant note)
    end
    GUI->>GUI: on Stop/close: log session_history,<br/>flush pending recording/manifest entries

2. Headless CLI → VS Code Extension

sequenceDiagram
    participant User
    participant Ext as extension.ts
    participant Panel as visualizerPanel.ts
    participant Py as python -m Audio_SpectraCLI.headless
    participant Web as Webview (canvas)
    participant Bar as Status Bar

    User->>Ext: "Start Live Visualization"
    Ext->>Panel: createOrShow()
    Panel->>Py: spawn (fs, blockSize, bars from settings)
    loop while running
        Py->>Panel: stdout line: {freqBins, spectrum, maxMagnitude}
        Panel->>Panel: parseFrameLines (buffers partial lines)
        Panel->>Web: postMessage({type:"frame", frame})
        Panel->>Bar: onFrame → computeDominantFrequency
    end
    User->>Ext: "Save Current Frame as Preset"
    Ext->>Ext: write ~/.audiospectra_cli/presets/<name>.json
    Note over Ext,Py: same file the Python GUI's<br/>preset manager reads
    User->>Ext: "Stop Live Visualization"
    Ext->>Py: kill process
    Ext->>Bar: dispose

3. Web Visualizer (client-only)

sequenceDiagram
    participant User
    participant Browser
    participant Analyser as Web Audio AnalyserNode
    participant Canvas
    participant LS as localStorage

    User->>Browser: grants microphone permission
    Browser->>Analyser: getUserMedia stream
    loop every animation frame
        Analyser->>Canvas: getFloatFrequencyData / getFloatTimeDomainData
        Canvas->>Canvas: draw bars/waterfall/tuner + stats sparkline
        Canvas->>Canvas: compute RMS/clip/silence (throttled UI update)
    end
    User->>LS: Save As local preset
    User->>Browser: Copy Share Link
    Browser->>Browser: encode settings into URL query string
    Note over Browser,Analyser: audio data never leaves the browser -<br/>no server involved in this flow

4. Web Data/Analysis API

sequenceDiagram
    participant Client as Third-party client
    participant API as /api/v1/analyze
    participant Auth as apiAuth.ts
    participant RL as rateLimit.ts (Upstash or in-memory)
    participant Decode as transcode.ts / wav.ts
    participant DSP as fft.ts / dsp.ts
    participant DB as Postgres

    Client->>API: POST (WAV/MP3/AAC or {samples, sampleRate})
    API->>Auth: authenticateApiRequest(bearer key)
    Auth->>DB: look up key hash, subscription status
    Auth->>RL: checkRateLimit(key)
    alt authorized and within limit
        API->>Decode: parse/transcode to mono PCM
        Decode->>DSP: FFT (first 8192 samples)
        DSP-->>API: spectrumDb, dominantFrequencyHz, ...
        API->>DB: record apiUsageEvents row
        API-->>Client: 200 JSON response
    else unauthorized / over quota / not on paid plan
        API-->>Client: 401 / 402 / 429
    end

What Data Is Stored, and Where

Local files (Python core + VS Code extension)

All under ~/.audiospectra_cli/ (or $AUDIOSPECTRA_CLI_HOME if set, e.g. in tests) - nothing here ever leaves the machine:

graph LR
    HOME["~/.audiospectra_cli/"]
    HOME --> P["presets/<name>.json<br/>{duration, fs, block_size,<br/>frequency_range, color, window_type,<br/>noise_threshold, channel_mode, db_scale,<br/>view_mode, peak_hold_enabled,<br/>smoothing_sigma, smoothing_enabled}"]
    HOME --> DP["device_profiles/<name>.json<br/>{device_name, fs, channel_mode}"]
    HOME --> SH["session_history.jsonl<br/>one line per session:<br/>{ended_at, duration_seconds,<br/>device_name, avg_bpm}"]
    HOME --> EM["export_manifest.jsonl<br/>one line per export:<br/>{exported_at, type, path}"]

Read/written by both the native GUI (main.py) and, for presets/, the VS Code extension - that's the one directory intentionally shared across products, so a preset saved in one is loadable from the other.

Browser storage (web visualizer)

localStorage key audiospectra:local-presets on the visitor's own browser, per-origin, never sent to a server:

[{ "id": "...", "name": "My Setup", "settings": { "...": "visualizer settings" }, "createdAt": "..." }]

Database (web SaaS backend)

Postgres (Neon), via drizzle-orm - only exists once you configure DATABASE_URL (see Requirements):

erDiagram
    USERS ||--o{ PRESETS : owns
    USERS ||--o{ API_KEYS : owns
    API_KEYS ||--o{ API_USAGE_EVENTS : logs

    USERS {
        text id PK "Clerk user id"
        text stripeCustomerId
        text subscriptionStatus "free/active/canceled/past_due"
    }
    PRESETS {
        uuid id PK
        text ownerId FK
        text name
        jsonb settings
    }
    API_KEYS {
        uuid id PK
        text ownerId FK
        text name
        text keyHash "SHA-256, plaintext shown once"
        timestamp lastUsedAt
        timestamp revokedAt
    }
    API_USAGE_EVENTS {
        uuid id PK
        uuid apiKeyId FK
        text endpoint
        timestamp createdAt
    }

Requirements

Product Requires Notes
Native GUI / headless CLI Python 3.9+, numpy, scipy, matplotlib, sounddevice, pyqt5, mido, python-rtmidi (see requirements.txt) No env vars, no network, no account. launch.py sets all of this up in a local .venv automatically.
VS Code Extension VS Code ^1.70.0, Node (for building from source), and the Python package above importable as python3 -m Audio_SpectraCLI.headless No env vars. Configurable via audioSpectraCli.pythonPath if python3 isn't on PATH.
Web App - visualizer only Node 20+, npm install No env vars needed at all - the visualizer, local presets, session stats, and share links are 100% client-side.
Web App - full SaaS (accounts, billing, Analysis API) The above, plus real credentials for: Clerk (auth), Stripe (billing), Neon/Postgres (DATABASE_URL), optionally Upstash Redis (distributed rate limiting) See web/.env.example and web/README.md for the full list and what each one gates.

How to Run

Native GUI

The fastest path is the interactive launcher - see Installation Methods below for full detail. Short version:

git clone https://github.com/AdityaSeth777/Audio-SpectraCLI.git
cd Audio-SpectraCLI
./run.sh        # macOS/Linux - or double-click run.command / run.bat on Windows

Or manually:

python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
python3 -m Audio_SpectraCLI.main

Headless/JSON-streaming mode (no GUI dependencies needed beyond numpy/scipy/sounddevice):

python3 -m Audio_SpectraCLI.headless --fs 44100 --block-size 4096 --bars 32

VS Code Extension

From the Marketplace: search "Audio-SpectraCLI" in the Extensions sidebar and install - see Installation & Usage (Marketplace) below. From source:

cd audiospectra-cli
npm install
npm run compile
# then F5 in VS Code to launch an Extension Development Host

Web App

cd web
npm install
cp .env.example .env.local   # fill in what you have; the visualizer works with none of it set
npm run dev                  # http://localhost:3000

Run the test suites:

npm run lint
npx tsc --noEmit
npx vitest run

/visualize works immediately with zero env vars. /dashboard, sign-in/up, and the Analysis API need Clerk/Stripe/DATABASE_URL configured - see web/README.md.

Installation Methods : (Now Extension available)

Instant Launch (interactive script - double-click and go)

If you already have the repo (git clone or downloaded), the fastest way to run the native GUI is the interactive launcher - it sits alongside every other installation method below, it doesn't replace them.

  • macOS/Linux, from a terminal: ./run.sh - this is the canonical entry point; read it if you want to know exactly what runs.
  • macOS/Linux, by double-clicking in Finder: double-click run.command - Finder normally opens a plain .sh file in a text editor instead of running it, so run.command exists purely as a thin wrapper that calls run.sh for that double-click case. It contains no logic of its own.
  • Windows: double-click run.bat (or run it from a terminal).
  • Any OS directly: python3 launch.py (or python launch.py).

It detects your OS and Python version, checks whether numpy/scipy/ sounddevice/matplotlib/PyQt5 are installed. If any are missing, it offers to set up a local .venv next to the script and install them there

  • it deliberately never tries to pip install straight into your system Python, since modern Homebrew/python.org Python (and recent Linux distros) refuse that with an "externally-managed-environment" error. After that one-time setup, it lists your real audio input devices (via sounddevice.query_devices()) so you can pick one (or just hit Enter for the system default) - this is the only thing it asks, since it's the one setting the GUI itself has no way to know. It then opens the GUI and starts visualizing immediately, no extra click. Duration, sampling rate, and block size are not asked in the terminal, since the GUI already has sliders for all three once it's open - asking twice for the same thing would just be redundant. Once .venv exists, later runs skip the setup check entirely and go straight to the device prompt.

First time on macOS, step by step

  1. Get Python 3, if you don't already have it: open Terminal and run python3 --version. If that fails, install Python from python.org (or brew install python3 if you use Homebrew), then try again.
  2. Get the repo: git clone https://github.com/AdityaSeth777/Audio-SpectraCLI.git (or download and unzip it from GitHub).
  3. Run it: either open Terminal, cd into the repo folder, and run ./run.sh - or double-click run.command in Finder.
    • Double-click, first time only: macOS may refuse to run it with an "unidentified developer" warning, since it isn't code-signed. Right-click (or Control-click) run.commandOpen → confirm in the dialog. You only need to do this once.
  4. The launcher runs. If packages are missing, it asks: Set them up now in a local .venv (won't touch your system Python)? [Y/n] - press Enter or y. This downloads and installs numpy/scipy/sounddevice/ matplotlib/PyQt5 into a .venv folder it creates next to the script (takes a minute or two; only happens once).
  5. Grant microphone access when macOS prompts for it (a system dialog asking to let Terminal/Python use the microphone) - click Allow. If you miss it or previously denied it, go to System Settings → Privacy & Security → Microphone and enable it for Terminal yourself.
  6. Pick an audio input device from the list it prints (or just press Enter for the default) - that's the only prompt.
  7. The GUI window opens and starts visualizing immediately - speak or play audio near the selected microphone and you should see the spectrum move. Adjust duration/sampling rate/block size using the sliders inside the GUI itself.


Installation & Usage (Using VSCode Extensions - Marketplace)

How to Use the Audio-SpectraCLI Extension

Follow these steps to use the Audio-SpectraCLI extension in Visual Studio Code:

  1. Open Visual Studio Code

    • Launch VS Code on your computer (macOS, Windows, or Linux).
  2. Install the Audio-SpectraCLI Extension

    • Go to the Extensions sidebar by clicking on the Extensions icon in the Activity Bar (or press Ctrl+Shift+X on Windows/Linux or Cmd+Shift+X on macOS).
    • Search for "Audio-SpectraCLI" in the Extensions Marketplace.
    • Click Install next to the Audio-SpectraCLI extension.
  3. Activate the Extension

    • After installation, open the Command Palette by pressing F1 or Ctrl+Shift+P on Windows/Linux or Cmd+Shift+P on macOS.
    • Type >Audio-SpectraCLI: Add Sample Code or >Audio-SpectraCLI: View Status.
    • Select either command to activate and use the extension.
  4. Using the Commands

    • Add Sample Code: Inserts sample code for Audio-SpectraCLI into the current editor window.
      • Open any Python file or create a new one.
      • Run the command Audio-SpectraCLI: Add Sample Code from the Command Palette.
      • The sample code should appear in the editor.
    • View Extension Status: Displays the current status of Audio-SpectraCLI.
      • Run the command Audio-SpectraCLI: View Status from the Command Palette.
      • You’ll see a notification indicating that Audio-SpectraCLI is ready to use.
    • Start/Stop Live Visualization: Opens/closes a live webview panel streaming the real spectrum via the headless Python process, plus a status bar readout of the dominant frequency.
    • Save Current Frame as Preset: Saves the extension's current settings as a named preset, readable by the native GUI's own preset manager.
  5. Verify the Extension

    • Ensure that the Audio-SpectraCLI commands work as expected by following the steps above.
    • You should see notifications for the status and sample code added in the editor.
  6. Customize as Needed

    • You can modify the inserted code or use the extension as a reference for developing your own custom scripts with Audio-SpectraCLI.
    • audioSpectraCli.pythonPath, sampleRate, blockSize, bars, and visualizerColor are all configurable in VS Code settings.

Note: If you encounter issues, check the extension's README or reach out to contact@adityaseth.in support for troubleshooting.

Enjoy using Audio-SpectraCLI in VS Code!

Once you have activated the audio_visualizer instance, feel free to use it wherever in the program. It consists of several parameters (which gives more control to the user), so make sure to configure and add those before using it in your code. Also, the user can modify (wrt v5.0.0) the Duration (in seconds), Sampling Rate (in Hz), and Block Size.



Installation & Usage (Using PIP on Windows)
  1. Install using pip (Use pip3 instead, if pip doesn't work.)
pip install Audio-SpectraCLI
  1. Import and use modules
  • Create a Python file.
  • You can use Example.py as a reference or use the following code :
from Audio_SpectraCLI import AudioSpectrumVisualizer
from PyQt5.QtWidgets import QApplication

# Creating an instance of AudioSpectrumVisualizer with custom parameters
app = QApplication([])
audio_visualizer = AudioSpectrumVisualizer(
    duration=5, fs=22050, block_size=1024, frequency_range=(1000, 5000), color='red')

# Starting the audio spectrum visualization
audio_visualizer.show()
app.exec_()

Once you have activated the audio_visualizer instance, feel free to use it wherever in the program. It consists of several parameters (which gives more control to the user), so make sure to configure and add those before using it in your code. Also, the user can modify (wrt v5.0.0) the Duration (in seconds), Sampling Rate (in Hz), and Block Size.



Installation & Usage (Using Homebrew and pip on MacOS)
  1. Install using pip (Use pip3 instead, if pip doesn't work.)
brew install pyaudio
pip install Audio-SpectraCLI
  1. Import and use modules
  • Create a Python file.
  • You can use Example.py as a reference or use the following code :
from Audio_SpectraCLI import AudioSpectrumVisualizer
from PyQt5.QtWidgets import QApplication

# Creating an instance of AudioSpectrumVisualizer with custom parameters
app = QApplication([])
audio_visualizer = AudioSpectrumVisualizer(
    duration=5, fs=22050, block_size=1024, frequency_range=(1000, 5000), color='red')

# Starting the audio spectrum visualization
audio_visualizer.show()
app.exec_()

Once you have activated the audio_visualizer instance, feel free to use it wherever in the program. It consists of several parameters (which gives more control to the user), so make sure to configure and add those before using it in your code. Also, the user can modify (wrt v5.0.0) the Duration (in seconds), Sampling Rate (in Hz), and Block Size.



Examining & Usage (Using Docker)
  1. Prerequisites You should have docker installed on your machine. You can download and install Docker from here.
  2. Pulling the Docker Image

You can pull the pre-built Docker image from Docker Hub using the following command:

docker pull adityaseth777/audio-spectracli
  1. Viewing Files Inside the Docker Container For seeing the files inside the Docker container for debugging purposes, you can run an interactive shell session:
docker run --rm -it --entrypoint /bin/bash audio-spectracli
  1. Use the 'ls' command to view the files and get a proper understanding of the file structure :
ls
  1. You can use Example.py as a reference or use the following code :
from Audio_SpectraCLI import AudioSpectrumVisualizer
from PyQt5.QtWidgets import QApplication

# Creating an instance of AudioSpectrumVisualizer with custom parameters
app = QApplication([])
audio_visualizer = AudioSpectrumVisualizer(
    duration=5, fs=22050, block_size=1024, frequency_range=(1000, 5000), color='red')

# Starting the audio spectrum visualization
audio_visualizer.show()
app.exec_()

Once you have activated the audio_visualizer instance, feel free to use it wherever in the program. It consists of several parameters (which gives more control to the user), so make sure to configure and add those before using it in your code. Also, the user can modify (wrt v5.0.0) the Duration (in seconds), Sampling Rate (in Hz), and Block Size.



Building the Docker Image Locally

If you prefer to build the Docker image locally, follow these steps:

  1. Clone the repository :
git clone https://github.com/AdityaSeth777/Audio-SpectraCLI.git
cd Audio-SpectraCLI
  1. Build the Docker image:
docker build -t audio-spectracli .
  1. Viewing Files Inside the Docker Container For seeing the files inside the Docker container for debugging purposes, you can run an interactive shell session:
docker run --rm -it --entrypoint /bin/bash audio-spectracli
  1. Use the 'ls' command to view the files and get a proper understanding of the file structure :
ls
  1. You can use Example.py as a reference or use the following code :
from Audio_SpectraCLI import AudioSpectrumVisualizer
from PyQt5.QtWidgets import QApplication

# Creating an instance of AudioSpectrumVisualizer with custom parameters
app = QApplication([])
audio_visualizer = AudioSpectrumVisualizer(
    duration=5, fs=22050, block_size=1024, frequency_range=(1000, 5000), color='red')

# Starting the audio spectrum visualization
audio_visualizer.show()
app.exec_()

Once you have activated the audio_visualizer instance, feel free to use it wherever in the program. It consists of several parameters (which gives more control to the user), so make sure to configure and add those before using it in your code. Also, the user can modify (wrt v5.0.0) the Duration (in seconds), Sampling Rate (in Hz), and Block Size.


Current Features (as of v5.0.0)

  • Real-time visualization of Fast Fourier Transform (FFT) spectrum of audio input.
  • Live VS Code Extension support - the extension spawns a real headless audio process and streams the spectrum into a live webview canvas, with a live status bar readout (see Web & Extension Additions below).
  • Support for adjusting parameters such as duration, sampling rate, and block size.
  • Seamless integration with SoundDevice for audio input capture.
  • Customizable Frequency Range: Allow users to specify the frequency range to display in the spectrum.
  • Color Customization: Provide options for users to customize the colors used in the spectrum visualization.
  • Added PyQt5 modules and a Gaussian filter that enables user input for Duration (in seconds), Sampling Rate (in Hz), Block Size, and also smoothens the output.
  • Might need to keep in mind that the Gaussian filter is too strong and it won't recognise any noise and display it's spectra. Only actual input through mic such as conversations and music are displayed which can be categorised as real inputs or audio, and of course in real time.
  • Much more dynamic and user-controlled interface.
  • A headless, GUI-free streaming mode (python -m Audio_SpectraCLI.headless) that emits spectrum frames as JSON lines - the same audio/FFT engine that powers the GUI, usable from scripts or other tools without PyQt5 installed.
  • The GUI redraws at a fixed ~30fps from the latest audio frame rather than redrawing on every single incoming audio block. Real microphone input can deliver far more blocks per second than a matplotlib redraw can keep up with, which previously could back up the GUI's event queue and, on some PyQt5/sip builds, crash the whole app outright after sustained use. Any error during a redraw is now also caught and logged instead of being allowed to propagate and abort the process.
  • The GUI's canvas now resizes properly on window maximize (no clipped axis labels), and every slider (Duration/Sampling Rate/Block Size/Noise Threshold) has a paired numeric spinbox next to it - the exact value is always visible and directly typeable, not just draggable.
  • Five view modes: Line (the original), Bars (equalizer-style), Waterfall (scrolling history spectrogram), Circular (radial display), and Tuner (big musical-note readout for the dominant frequency, e.g. "A4 · 441.4 Hz · +6 cents").
  • dB (logarithmic) scale toggle, windowing function choice (None/Hann/Hamming/Blackman) to reduce spectral leakage, an adjustable noise threshold and Gaussian smoothing strength (previously hardcoded), and stereo channel selection (Mono mix/Left/Right - previously always forced mono).
  • Peak-hold markers (Line/Bars views) - a line that holds at the recent peak and decays, like a hardware audio meter.
  • Live BPM estimation and a dominant-note readout, always shown above the canvas regardless of view mode. The BPM estimate is a simple onset/energy heuristic, not lab-grade beat tracking - expect it to be unstable on non-rhythmic input, that's inherent to how simple it is.
  • RMS meter, clip warning, and silence warning, plus a peak-frequency sparkline - see What's New in v5.0.0.
  • Named preset manager (save/load/rename/delete) with 3 hardware-tuned builtins, alongside the original file-picker save/load presets.
  • A/B settings compare, a local session-history log, a Recent Exports/Recordings manager, and named device profiles - all new in v5.0.0, see above.
  • Export the current view as PNG (also bound to Ctrl+S) or the current frame's data as CSV, and record microphone input to a WAV file - now tracked in the Recent Exports manager.
  • In-GUI microphone selection (previously only choosable via the launch.py interactive launcher at startup) - swap devices from a dropdown before clicking Start; changing it while running is disabled, the same way sampling rate/block size are, since a live stream can't be reconfigured without reopening it.
  • MIDI-out: converts the dominant frequency to a MIDI note and sends it to a virtual MIDI port, turning the visualizer into a simple audio-to-MIDI tool. mido/python-rtmidi are core dependencies (installed automatically by requirements.txt/pip install Audio-SpectraCLI/the interactive launcher's .venv setup) - but the checkbox still degrades gracefully with a clear explanation instead of crashing if they're somehow missing or fail to build in a given environment. Windows has no native virtual MIDI port support without a third-party loopback driver like loopMIDI; the same message covers that case too. A stuck note is released automatically both when input goes quiet for 0.5s and when you click Stop.

Packaging

Audio-SpectraCLI/

├── .gitignore
├── CODE_OF_CONDUCT.md
├── Contributing.md
├── Dockerfile
├── LICENSE
├── Readme.md
├── CHANGELOG.md
├── requirements.txt
├── setup.cfg
├── setup.py
├── launch.py           # interactive cross-platform launcher (see Instant Launch)
├── run.sh              # canonical launcher entry point for macOS/Linux terminals: ./run.sh
├── run.command         # thin double-click wrapper around run.sh, for macOS/Linux Finder
├── run.bat             # double-click/terminal entry point for Windows
├── .github/
│   └── workflows/
│       ├── docker-publish.yml
│       ├── label.yml
│       └── python-publish.yml
├── Audio_SpectraCLI/
│   ├── main-old.py       # deprecated v3.2 implementation
│   ├── main.py            # PyQt5 GUI, built on engine.py
│   ├── engine.py           # Qt-independent capture/FFT/smoothing core, shared by main.py and headless.py
│   ├── analysis.py         # pure DSP helpers: windowing, dB, notes, BPM, RMS, clipping, sparkline
│   ├── midi_out.py         # optional MIDI-out (gracefully degrades if python-rtmidi isn't installed)
│   ├── headless.py         # `python -m Audio_SpectraCLI.headless` JSON-streaming CLI mode
│   ├── presets.py          # named-preset CRUD (~/.audiospectra_cli/presets/)
│   ├── device_profiles.py  # named device-profile CRUD, matched by device name
│   ├── session_history.py  # append-only session log (~/.audiospectra_cli/session_history.jsonl)
│   ├── export_manifest.py  # tracked PNG/CSV/WAV exports (~/.audiospectra_cli/export_manifest.jsonl)
│   └── __init__.py
├── tests/
│   ├── test-old.py
│   ├── test.py
│   ├── test_engine.py
│   ├── test_headless.py
│   ├── test_analysis.py
│   ├── test_midi_out.py
│   ├── test_presets.py
│   ├── test_device_profiles.py
│   ├── test_session_history.py
│   ├── test_export_manifest.py
│   ├── test_gui_smoke.py
│   ├── test_gui_stress.py
│   ├── test_gui_controls.py
│   └── test_gui_features.py
├── audiospectra-cli/         # VS Code extension (live webview + status bar)
│   ├── assets
│   ├── dist
│   ├── src/
│   │   ├── test
│   │   ├── extension.ts
│   │   ├── visualizerPanel.ts
│   │   ├── lineParser.ts
│   │   ├── lineParser.test.ts
│   │   ├── presetUtils.ts
│   │   └── presetUtils.test.ts
│   ├── CHANGELOG.md
│   ├── esbuild.js
│   ├── eslint.config.mjs
│   ├── package.json
│   ├── package-lock.json
│   ├── README.md
│   ├── sample.py
│   └── tsconfig.json
└── web/                       # Next.js SaaS app: hosted visualizer, accounts/billing, analysis API
    ├── app/
    ├── components/
    ├── lib/
    │   ├── localPresets.ts     # localStorage-backed presets (no sign-in)
    │   ├── sessionStats.ts     # RMS/clip/silence math
    │   ├── urlConfig.ts        # shareable-URL settings encode/decode
    │   └── db/                 # drizzle schema: users, presets, apiKeys, apiUsageEvents
    └── README.md

Testing

# Python core (from repo root, inside a venv with requirements.txt installed)
python3 -m pytest tests/ --ignore=tests/test.py --ignore=tests/test-old.py

# VS Code extension
cd audiospectra-cli && npm run compile && npm run lint && npm run test:unit

# Web app
cd web && npx tsc --noEmit && npm run lint && npx vitest run

All three suites are green as of this release; the Python suite additionally gets exercised against real microphone hardware as part of manual end-to-end passes (not run in CI, since CI has no audio device).

Web & Extension Additions

Audio-SpectraCLI is expanding beyond the native Python CLI into a small family of products that all sit on top of the same FFT/DSP approach:

  • Hosted web visualizer (web/) - a Next.js app with a client-side (browser-only, mic audio never leaves the device) visualizer, free vs. paid tiers (waterfall/tuner/export/presets are paid), Clerk accounts, and Stripe subscription billing. See web/README.md for setup - it needs your own Clerk, Stripe, and Postgres (Neon) credentials to run the account/billing/Analysis-API side; the visualizer itself, local presets, session stats, and share links work with zero env vars.
  • Live VS Code extension (audiospectra-cli/) - the extension spawns python -m Audio_SpectraCLI.headless and streams the live spectrum into a real webview panel inside VS Code (Audio-SpectraCLI: Start/Stop Live Visualization), plus a live status bar readout and a save-preset command interoperable with the native GUI. Requires Python + this package installed and on your PATH (configurable via the audioSpectraCli.pythonPath setting). See audiospectra-cli/README.md.
  • Data/Analysis API (web/app/api/v1/analyze) - a server-side HTTP API for third parties: send WAV audio or raw PCM samples, get back spectrum and dominant-frequency JSON. Authenticated with per-account API keys, rate-limited, and billed on a usage basis. See web/README.md for the request/response shape.

The native Python CLI (main.py/AudioSpectrumVisualizer) is unaffected - it now runs on the same shared engine.py internally, but its behavior and public API are unchanged.

Upcoming Features

  • CLI endpoints. ✅ Done - see python -m Audio_SpectraCLI.headless above.
  • Save and Export: ✅ Done in the web visualizer (PNG export, paid tier) and the native GUI (PNG/CSV export, WAV recording, all now tracked in the Recent Exports manager).
  • Option to choose between CLI/GUI. ✅ Done - main.py (GUI) vs. headless.py (CLI/JSON streaming) both run on the same engine.
  • Named presets/device profiles/session history/A-B compare. ✅ Done - v5.0.0.
  • Server-side decoding of compressed audio formats (MP3/AAC) for the Analysis API - currently WAV-only for the raw-sample path (MP3/AAC are transcoded server-side via ffmpeg-static for file uploads).
  • A shared, multi-instance-safe rate limiter (e.g. Redis/Upstash) for the Analysis API. ✅ Done - Upstash-backed with an in-memory fallback.
  • MIDI output port/channel profiles (named, like device profiles).
  • Cross-device sync for local (non-DB) presets.

For contributing

Check the Contributing page.

License

MIT © Aditya Seth

What next?

I will be improving this project.

Where to contact ?

Contact: contact@adityaseth.in

🙋‍♂️ Support

💙 If you like this project, give it a ⭐ and share it with friends!

buymeacoffee


Made with love-circled and python

Release files for Audio-SpectraCLI 5.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for Audio-SpectraCLI 5.0.0
File Size Uploaded
audio_spectracli-5.0.0.tar.gz 89.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for Audio-SpectraCLI 5.0.0
File Interpreter ABI Platform
audio_spectracli-5.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 141.2 kB

Release files / audio_spectracli-5.0.0.tar.gz

Download URL audio_spectracli-5.0.0.tar.gz
Size 89.6 kB
Tags Source
SHA-256 checksum
How to use checksums
58a2079323881956f07802d83f2089b4af946b91bad3bcf3f9542ec13bdc85da
BLAKE2b-256 checksum
How to use checksums
beeb38b08cfc0dea65c889d1e02f1073644984316c04bd234c7272c05b231aa8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / audio_spectracli-5.0.0-py3-none-any.whl

Download URL audio_spectracli-5.0.0-py3-none-any.whl
Size 51.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4e1e97053146d9c044a309c2f46799b0a266e4d62210cd434ea558afc114be6d
BLAKE2b-256 checksum
How to use checksums
7db0dd1fa1225790c3461954fe37723bd02c625e528de916061daa44723ae5a1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

This release

5.0.0 This release

2 release files

4.1.0

2 release files

4.0.0

2 release files

3.2

2 release files

3.1

2 release files

2.1

2 release files

2.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page