Audio FFT Daemon (fft_daemon.py)
Relevant source files
The following files were used as context for generating this wiki page:
Introduction
The Audio FFT Daemon is a Python-based background service designed to process real-time audio data on a Raspberry Pi Zero 2 W. Its primary purpose is to read audio from an ALSA loopback device, perform Fast Fourier Transform (FFT) analysis, and estimate music metadata such as BPM and intensity. This data is then serialized into JSON format and emitted via standard output at a consistent rate of 30 frames per second (FPS).
Within the broader architecture of the BT Speaker Studio project, this daemon serves as the primary data provider for the visualizer. The processed BeatData is eventually consumed by a Flutter-based display application (pi_app) which renders high-frequency frequency bars and pulses synchronized with the audio.
Sources: apps/pi_app/fft_daemon.py:1-4, README.md:1-20, CLAUDE.md:65-70
Core Architecture and Data Flow
The daemon operates in a continuous loop, capturing audio chunks and applying a series of mathematical transformations to extract visualizable features. It uses the sounddevice library to interface with the hardware loopback and numpy for efficient numerical processing.
The diagram illustrates the flow from raw audio capture to the emission of JSON beat data for the Flutter UI.
Audio Processing Components
Frequency Bar Computation
The daemon divides the audio spectrum into 16 log-spaced frequency bins ranging from 60 Hz to 16 kHz. A Hanning window is applied to the raw samples before the FFT to reduce spectral leakage. The resulting spectrum is averaged within each bin and normalized against the peak magnitude to ensure the bars stay within a relative 0.0 to 1.0 range.
Sources: apps/pi_app/fft_daemon.py:15-37
BPM and Intensity Estimation
Intensity is calculated using the Root Mean Square (RMS) of the audio samples, normalized to a 0–1 range. The BPM estimation tracks the "spectral flux"—the positive change in magnitude between consecutive frames. If the flux exceeds a dynamic threshold (1.5x the mean of recent history) and satisfies a minimum time interval (0.3s), a "beat" is detected, and the interval is used to update the BPM estimate.
Sources: apps/pi_app/fft_daemon.py:40-66
Configuration and Output Format
Daemon Parameters
| Parameter | Value | Description |
|---|---|---|
SAMPLE_RATE | 44,100 Hz | Standard CD-quality sampling rate. |
CHUNK | 1024 | Number of samples per processing block. |
NUM_BARS | 16 | Number of frequency bands emitted in the JSON. |
TARGET_FPS | 30 | Target update frequency for the visualizer. |
DEVICE | "hw:Loopback,1,0" | The ALSA device string for audio capture. |
Sources: apps/pi_app/fft_daemon.py:10-14
JSON Output Schema
The daemon outputs a single line of JSON for every frame. This payload is typed as "beat" to distinguish it from other message types in the WebSocket protocol used by the companion app.
{
"type": "beat",
"bpm": 120,
"intensity": 0.4567,
"fft_bars": [0.1, 0.4, 0.8, 0.5, ...]
}
Sources: apps/pi_app/fft_daemon.py:91-96, CLAUDE.md:38-42
Implementation Details
Timing Control
To ensure a stable 30 FPS output, the daemon calculates the elapsed processing time for each chunk and sleeps for the remainder of the interval. This precision is necessary for the pi_app to render smooth animations at the data rate.
# apps/pi_app/fft_daemon.py:98-101
elapsed = time.monotonic() - t0
if elapsed < interval:
time.sleep(interval - elapsed)
Sources: apps/pi_app/fft_daemon.py:98-101, README.md:46-50
Conclusion
The fft_daemon.py is a critical utility for the BT Speaker project, bridging the gap between raw hardware audio input and high-level UI state management. By offloading the heavy FFT computation to a dedicated Python process using optimized libraries like numpy, the system ensures that the Pi Zero 2 W's resources are balanced between audio analysis and the Flutter-based rendering engine.
Sources: README.md:28-35, CLAUDE.md:14-16