Welcome to the super-duper greatest music visualizer ever made. psysuals delivers uncompromising visual intensity and rock-solid performance. Whether you're blasting psytrance in a dark room or driving a multi-monitor stage setup, it is built to melt your mind with precision and style.
This release fixes CPU-effect visibility in GL mode, makes mode changes start with empty framebuffers, preserves simulation state through supported resizes, and adds independent Laptop/TV response profiles. Cube, Tunnel, Plasma and Phason are calmer; Persistence responds through smooth direction, speed and colour changes. Hyperbolic has individually moving 3-D facets.
Mandelbox and Morphogenesis are removed. There are now 32 modes and four layered recipes. Because saved presets store numeric mode indices, reselect/re-save presets for effects after Heartbeat when upgrading. No dependency or file-format migration is required.
Use --visual-profile laptop for a close laptop display or --visual-profile tv
for viewing from a distance. V cycles Auto → Laptop → TV during playback; the
selection is saved on exit. Auto uses output width as a fallback (TV from 2560
pixels), so choose a profile explicitly for a 4K laptop or 1080p TV.
Laptop keeps camera motion gentle and uses a 22×14 Lattice grid. TV uses a 14×9
grid and stronger light accents. Both retain slow geometry transitions. The fourteen
retuned effects (Cube, TriFlux, Lissajous, Tunnel, Plasma, Lattice, Mobius,
Chromatic, Persistence, Synapse, Hyperbolic, Cymatica, Phason and Ferrofluid)
use elapsed time for motion rather than render-frame counts. External hosts should set config.FRAME_DT once per
frame in seconds; its default is 1/60 and stalls are capped at 0.1 seconds.
GL and CPU effects receive a full display-sized canvas. Reduced-resolution simulations scale their completed image once; lowering quality preserves the viewport, centre and aspect ratio. TriFlux triangle outlines are antialiased, including enlarged foreground triangles. Mode changes clear the CPU/GPU frame and presentation buffers immediately; previous pictures are not crossfaded. Effects with their own feedback replace the composed frame instead of retaining old maximum colours. Fullscreen/quality resizing preserves existing particle, network, dye and trail state where supported.
SlimeMold keeps at least 85% of native width/height on TV-sized outputs even at lower quality tiers. Phason, Ferrofluid and LiquidLight reduce internal detail gradually rather than immediately dropping to half size.
- ✨ Unified ModernGL Engine — Harness the power of your GPU with optional hardware acceleration. Run with
--glfor per-pixel shader fluid motion. - 🏗️ Modular Object-Oriented Architecture — Re-written from a monolithic script into a sleek, professional engine. Specialized
AudioEngine,DisplayManager, andUIManagerclasses ensure a clean, maintainable, and high-performance foundation. - 🖥️ Ultimate Multi-Monitor "Span Mode" — Gone are the days of fixed dual-screen limits. The app scales dynamically, spawning child processes for every monitor you own, with synchronized mode switching across the entire span.
- 🔊 Resilient Audio Pipeline — Tolerant audio capture with a no-input fallback, silence-aware idle motion, live device switching, and spectral-flux beat detection.
- ⚖️ Built-in Benchmarking & Regression Checks — Measure speed with
benchmarks.py; the smoke test validates registry order and instantiates all 32 registered effects, with focused tests for audio timing, display lifecycle, and effect safety bounds.
- Python 3.10+
- Optional audio input device (microphone or loopback monitor); the app can run in silent mode without one
- (Optional) OpenGL 3.3+ capable GPU for hardware acceleration
Clone the repository and create a virtual environment:
git clone https://github.com/Whichcraft/psysuals.git
cd psysuals
python3 -m venv .venv
source .venv/bin/activate
.venv/bin/python -m pip install -r requirements.txtRecent Ubuntu and Debian releases protect the system Python (PEP 668), so a
direct pip install -r requirements-gl.txt may fail with
error: externally-managed-environment. Install the venv support package and
install project dependencies into the repository's virtual environment instead:
sudo apt update
sudo apt install python3-full
python3 -m venv .venv
.venv/bin/python -m pip install --upgrade pip
.venv/bin/python -m pip install -r requirements.txt
.venv/bin/python -m pip install -r requirements-gl.txtUse the same .venv/bin/python for the run and test commands below. The
--break-system-packages pip override is intentionally not recommended: it
modifies the OS-managed Python and can break distribution packages.
To enable high-accuracy Librosa-based beat tracking and BPM estimation:
.venv/bin/python -m pip install librosaTo enable the high-performance ModernGL path:
.venv/bin/python -m pip install -r requirements-gl.txtThe Android application is built by the external GitHub builder. This
repository provides the Python rendering API consumed by that builder. CPU
effects inherit Effect.draw_frame(width, height, waveform, fft, beat, tick, renderer=None), which returns an RGBA array sized to the requested physical
framebuffer. The result is a fresh numpy.uint8 array with shape
(height, width, 4). PlasmaGL supplies its own ModernGL offscreen
implementation and requires the host's GLRenderer as renderer.
For CPU effects, the builder must initialize Pygame, set config.WIDTH,
config.HEIGHT, and config._INITIALIZED = True before constructing an
effect, then call draw_frame() once per output frame. CPU effects may omit
renderer; the GL effect must pass the active renderer. Reuse the same effect
instance for successive frames so trails and simulations persist, and call its
release() method when the effect is discarded.
.venv/bin/python psysualizer.pyRun with ModernGL hardware acceleration:
.venv/bin/python psysualizer.py --glRun on low-spec/low-power systems (caps framerate to 30 FPS and scales down simulation complexity):
.venv/bin/python psysualizer.py --low-specThe app restores the last saved display index on startup. Use --display N to
override that for a single launch. Use --mode N to select the starting effect
by its zero-based index from the 32-effect registry (0–31).
| Key / Action | Effect |
|---|---|
← / → or Space or click |
Cycle to previous / next mode (or adjust pane slider when pane is open) |
↑ / ↓ |
Increase / decrease effect intensity (or adjust FlowField particles by 2,000, or navigate pane sliders when pane is open) |
1 – 9 |
Jump to modes 1–9 |
Tab |
Toggle real-time settings pane (effect gain, bg alpha, parameter-transition length) |
P |
Save current state as a preset |
Shift+P |
Morph to the next saved preset over eight beats (or a short time fallback) |
A |
Toggle auto-gain (auto-scales beat to current volume) · in span mode: cycle the shared secondary-display effect backward |
B |
Toggle background layer (renders a second effect at configurable opacity behind the active one) |
Shift+B |
Cycle background effect (modes 1–9) |
Shift+R |
Cycle curated foreground/background recipes |
M |
Tap tempo — tap 2+ times to lock BPM for 8 s |
Shift+M |
Toggle span mode — single monitor: one effect NOFRAME full-screen; multi-monitor: one child process per other display |
D |
Open device picker (↑↓ navigate, Enter confirm, Esc cancel) · in span mode: cycle the shared secondary-display effect forward |
F |
Toggle fullscreen (effects are rebuilt for the new display dimensions) |
H |
Toggle HUD on / off |
Shift+H |
Cycle HUD detail: full → minimal → off |
Q / Esc |
Quit |
Changing modes with ← / →, Space, number keys, or mouse click resets intensity to the default 0.7. Saved presets can still restore a custom intensity deliberately.
Press D while running to open the interactive device picker. Use ↑/↓ to navigate the list of available input devices, Enter to switch, Esc to cancel. The active device is shown in the HUD at the top of the screen.
If no input device is available at startup, psysuals stays open in silent mode instead of crashing. The HUD shows no input until a device is selected successfully.
Before and after tracks, psysuals uses RMS/FFT silence detection with hysteresis. It enters silence after about 140 ms of quiet audio and exits after two fresh loud audio blocks (about 46 ms at the default 44.1 kHz / 1024-sample callback). Repeated video frames do not accelerate these timings, and invalid audio is ignored. During true silence, beat spikes are suppressed and effects fall back to a faint low-motion idle state instead of freezing completely or reacting to noise-floor normalization.
Effects can also read config.BEAT_PHASE, a normalized position from 0.0 at
the predicted beat boundary to 1.0 just before the next one. It falls back to
a slow idle phase when BPM timing is unavailable.
Run the headless smoke and registry checks with:
SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy .venv/bin/python smoke_test.pyRun the automated unit tests with:
.venv/bin/python -m unittest discover -s tests -vThe suite includes compact deterministic visual fixtures for every registered effect. They compare quantized coverage and color-energy metrics rather than large screenshots, so black frames and major visual regressions are detected without committing binary artifacts.
At runtime, a rolling frame-time governor can move effects among high, balanced, and low internal-resolution tiers. It uses a 90th-percentile window, hysteresis, and a cooldown; benchmark commands are unaffected because they do not run the visualizer loop.
Audio and graphics boundary tests use fakes when hardware or optional native dependencies are unavailable; the real Pygame resize test runs when Pygame is installed.
For actual GPU validation, run .venv/bin/python psysualizer.py --gl with the
real display and audio session; SDL_VIDEODRIVER=dummy cannot exercise OpenGL.
Version 3.20.0 was also checked by reading visible AMD/Mesa GL framebuffers for
the affected effects at 960×540, checking clean GPU buffers on mode switches,
and rendering SlimeMold into a 3840×2160 framebuffer. These checks complement
the unit suite; they do not measure every TV or music input.
Run a quick headless CPU performance comparison with:
SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy .venv/bin/python benchmarks.py --cpu-only --duration 2To attempt the CPU/ModernGL comparison, use a real display/context (do not set the dummy video driver):
.venv/bin/python benchmarks.py --gl --duration 2The benchmark reports when ModernGL is unavailable or the context cannot be created; CPU measurements still complete.
Shift+R cycles curated pairings such as Hyperbolic + LiquidLight,
Tesseract + Persistence, Cymatica + Ferrofluid, and
Fireworks + Aurora. Choosing a recipe explicitly enables its background; the
individual foreground/background controls remain available afterward.
Shift+X cycles optional post-processing: off, chromatic separation,
kaleidoscope mirroring, feedback rotation, and diffraction-style bloom. The
default is off; each pass reuses its working surfaces and remains bounded on
the CPU path.
Modes with a shared declared morph parameter interpolate it during a transition. Tesseract and Persistence currently share their projection parameter. Image buffers are cleared on every mode switch; numeric parameter interpolation does not retain the previous effect image. GL results include the display-present step (and context synchronization when available), so compare them on the same display and VSync settings.
Use --display N for monitor selection. When xrandr geometry is unavailable, the app falls back to SDL's detected display count and asks SDL to target the selected display.
psysuals/
├── psysualizer.py # Entry point — clean orchestrator
├── core/
│ ├── audio_engine.py # Capture, FFT, beat & genre detection
│ ├── display_manager.py # Monitors, X11, windowing, span mode
│ ├── ui_manager.py # HUD, pane, picker rendering
│ ├── postprocess.py # Optional bounded psychedelic post-processing
│ ├── quality.py # Adaptive frame-time quality governor
│ └── regression_tester.py # Headless effect contract checks
├── beat_tracking.py # Optional librosa-based BPM/beat refinement
├── config.py # Shared mutable state
├── settings.py # User settings persistence
├── gl_renderer.py # Shared moderngl renderer utilities
├── requirements-gl.txt # Optional moderngl dependency set
├── smoke_test.py # Headless effect instantiation and registry checks
├── benchmarks.py # Performance measurement tool
├── effects/
│ ├── __init__.py # MODES list and package re-exports
│ ├── base.py # Effect base class and contract
│ ├── utils.py # Shared colour helpers
│ ├── palette.py # Shared colour palette
│ └── *.py # 32 registered visual implementations and helpers
├── ARCHITECTURE.md # Code structure and extension guide
├── EFFECTS.md # Full parameter reference for all effects
├── tests/ # Automated settings, audio, graphics, and cleanup tests
├── CHANGELOG.md # Release and unreleased change history
├── TODO.md # Audit status and outstanding maintenance items
├── requirements.txt
└── README.md
MIT