Friture is a real-time audio visualization and analysis application. It captures live audio via PortAudio, processes it with NumPy, and renders visualizations in a PyQt6 hybrid QWidget + QML GUI.
| Path | Purpose |
|---|---|
main.py |
Entry point; calls friture.analyzer:main |
friture/ |
Main application package |
friture/analyzer.py |
Friture QMainWindow — sets up QML engine, audio backend, docks, timers; main() entry point |
friture/audiobackend.py |
Audio I/O via sounddevice + rtmixer; singleton accessed as AudioBackend() |
friture/audiobuffer.py |
AudioBuffer — ring buffer wrapper, forwards data to widgets |
friture/ringbuffer.py |
RingBuffer — circular buffer for audio samples |
friture/audioproc.py |
audioproc — FFT analysis for the spectrum widget |
friture/dockmanager.py |
DockManager — manages dock creation/closure/ordering |
friture/dock.py |
Dock — QML dock container hosting an audio widget |
friture/widgetdict.py |
Registry of available visualization widgets (8 types) |
friture/store.py |
Store singleton exposed to QML for dock state |
friture/plotting/ |
Plotting infrastructure (CoordinateTransform, ScaleDivision, frequency scales, color maps) |
friture/signal/ |
Signal processing modules (IIR/FIR filters, resampling, transforms) |
friture/generators/ |
Built-in signal generator widgets (sine, white, pink, sweep, burst) |
friture/playback/ |
Audio playback subsystem |
friture/test/ |
Test suite |
friture/*.qml |
QML view files for visualizations and main window |
ui/ |
Qt Designer .ui files (settings, main window) |
resources/ |
Qt resource files (.qrc, icons, splash) |
installer/ |
PyInstaller spec and hooks for packaging |
Audio hardware → audiobackend (rtmixer ringbuffer) → AudioBuffer → DockManager → Widget.handle_new_data()
↓
display_timer (10 ms) slow_timer (1 s)
↓ ↓
DockManager.canvasUpdate() text/label refresh
Widget.canvasUpdate() → QML view update
- Audio capture:
AudioBackend(singleton inaudiobackend.py) opens a PortAudio stream viartmixerand fills artmixer.RingBuffer. - Buffering:
AudioBackend.fetchAudioData()(called on the display timer) drains the ring buffer, emitsnew_data_available, whichAudioBufferreceives and pushes into its ownRingBuffer. - Processing:
AudioBuffer.new_data_availablefans out to every dock's audio widget. Each widget computes its own FFT/spectrogram/scattering inhandle_new_data(). - Rendering: The display timer (10 ms) calls
DockManager.canvasUpdate(), which calls each widget'scanvasUpdate(), updating the QML views.
Each visualization widget follows a consistent pattern:
- Python class (e.g.
Spectrum_Widgetinspectrum.py) — audio data processing, buffer management, settings dialog, state save/restore. Registered inwidgetdict.pyand instantiated byDock. - QML file (e.g.
Spectrum.qml) — declarative rendering and UI layout. - View model (e.g.
Scope_Data,Spectrum_Data) — QObject subclass withpyqtPropertyfields, bridged to QML.
Available widgets (see widgetdict.py):
| Widget ID | Class | QML file | Description |
|---|---|---|---|
| 1 | Scope_Widget |
Scope.qml |
Oscilloscope |
| 2 | Spectrum_Widget |
Spectrum.qml |
FFT spectrum analyzer |
| 3 | Spectrogram_Widget |
Spectrogram.qml |
2D rolling spectrogram |
| 4 | OctaveSpectrum_Widget |
OctaveSpectrum.qml |
Octave-band spectrum |
| 5 | Generator_Widget |
Generator.qml |
Signal generator |
| 6 | Delay_Estimator_Widget |
DelayEstimator.qml |
Delay estimation |
| 7 | LongLevelWidget |
— | Long-time level meters |
| 8 | PitchTrackerWidget |
PitchView.qml |
Pitch tracking |
friture/signal/ contains reusable DSP modules:
lfilter.py— IIR/FIR filtering, IIR-to-minimum-phase-FIR conversiondecimate.py— decimationexp_smoothing.py— exponential smoothing for displayfrequency_resampler.py— resampling for FFT displaytransform_pipeline.py— generic pipeline of processing blockslookup_table.py— fast lookup tableslinear_interp.py— linear interpolationcorrelation.py— cross-correlation (used by delay estimator)color_tranform.py— color transformations
uv sync
uv run python main.pyDependencies are managed by uv (see uv.lock). See INSTALL.md for
platform-specific instructions.
| Command | Tool | Purpose |
|---|---|---|
uv run pytest |
pytest | Run the test suite (friture/test/) |
uv run mypy |
mypy | Type-check the codebase |
uv run python main.py |
— | Run the application |
Tests live in friture/test/ and cover signal processing, filters, pitch
tracking, and QML integration.
If UI or resource files change, regenerate:
uv run pyuic6 ui/settings.ui -o friture/ui_settings.py
uv run pyuic6 ui/friture.ui -o friture/ui_friture.py
uv run pyrcc6 resources/friture.qrc -o friture/friture_rc.py
uv run python friture/filter_design.py # regenerate generated_filters.py / generated_fft.py