Audio Demo

Play music or a video, then run from the checkout:

uv run --locked --extra audio python -m bruhanimate.demos.audio_demo

Windows uses PyAudioWPatch from the optional audio extra to capture system playback. Keep --extra audio in the command so uv retains that dependency.

The visualizations play inside the original computer artwork from the TV demo, with snow falling behind it at 15 updates/sec. The computer body and screen hide flakes; changing audio modes or computer styles keeps the snow running.

Press C to cycle classic → expanded → box. Expanded keeps the original corners, adds columns through the center, and inserts rows in the monitor’s straight sides. The bezel, keyboard, and angled screen opening expand together, giving the audio more room without enlarging individual characters. It fits the terminal with a small margin, so enlarge the terminal for a taller/wider screen. Box is the rectangular computer with a monitor, stand, and keyboard. Classic and expanded need at least 67 columns and 32 rows; smaller terminals automatically use the rectangular frame. Enlarging the terminal restores the original if that is your selected style.

Audio is rendered into a monitor-sized buffer. The original screen follows the artwork’s sloped edges, keeping every bar’s base visible; it does not crop a full-terminal animation. The rectangular screen grows with the terminal. Captions and capture errors remain outside the monitor. Switching computer style or resizing preserves the selected mode, simulation state, and capture worker.

The typed computer option accepts "classic" (default), "expanded", or "box":

from bruhanimate import Buffer
from bruhanimate.demos.audio_demo import build, run

demo = build(Buffer(48, 120), computer="expanded")  # No device opens here.
demo.close()
# In your terminal: run(computer="expanded")

Use Left for the previous visualization and Right for the next. Navigation wraps at either end. There is no automatic cycling: your selection stays active until you press an arrow key. The current mode and controls appear at the top. q/Q, Escape, or Ctrl+C quit. Live resize preserves the selected mode and animation state. Switching closes the previous capture worker before starting the next; no audio samples are recorded to disk.

The demo starts with Objects: blocks spread over the monitor. Bass expands them from 3×3 cells until neighboring blocks touch and fill their regions. Midrange energy moves them within the space left over, treble highlights their faces, and volume controls brightness. Quiet audio leaves a dim, gently moving field. The bottom line explains the selected mode’s mapping to sound.

The seven modes are Objects, Tiles, Glow, Bars, Mirror, Waveform, and Spectrum. Tiles makes a monitor-wide mosaic: low frequencies light the left columns and high frequencies light the right, with brightness following volume in each band. Glow blends broad amber bass pools, violet midrange pools, and smaller cyan treble highlights; mids drive their movement. Both fade toward silence. Bars/Mirror show low frequencies on the left, high on the right. They use a 2× display-height multiplier and fill column gaps so moderate audio occupies more of the screen. The typed AudioSettings.bar_gain option controls height independently of analysis; 1 restores the earlier height response. Waveform shows volume history; Spectrum shows frequency history. See Audio Effect for level/sensitivity settings and the removed-mode migration notes.

Copyright 2023 Ethan Christensen

Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

class bruhanimate.demos.audio_demo.AudioShowcase(phases: Iterable[tuple[str, Animation]], *, size: tuple[int, int], computer: Literal['classic', 'expanded', 'box'] = 'classic')[source]

Bases: Showcase

Own selected audio locally; C changes the computer without restarting capture.

__init__(phases: Iterable[tuple[str, Animation]], *, size: tuple[int, int], computer: Literal['classic', 'expanded', 'box'] = 'classic') → None[source]
start() → None[source]
update(dt: float) → None[source]
close() → None[source]
resize(size: tuple[int, int]) → None[source]

Refit all modes to the local monitor, preserving capture and selection.

draw(buffer: Buffer) → None[source]
bruhanimate.demos.audio_demo.build(buffer: Buffer, *, computer: Literal['classic', 'expanded', 'box'] = 'classic') → AudioShowcase[source]

Build inert audio modes with snow behind classic, expanded, or box artwork.

Classic/expanded fall back to box below 67x32. C cycles classic, expanded, box; arrows select audio. Snow runs at 15 updates/sec across mode changes. Every audio buffer fits the monitor opening, not the terminal.

bruhanimate.demos.audio_demo.run(*, frames: int | None = None, fps: float = 30, on_resize: Literal['raise', 'resize'] = 'resize', computer: Literal['classic', 'expanded', 'box'] = 'classic') → int[source]

Play system audio; left/right wrap modes, with no automatic cycling.

C cycles classic/expanded/box without restarting capture or snow. q/Q, Escape and Ctrl+C quit. Resize preserves the selected mode and animation state. Player owns the showcase; switching closes the old capture before starting the new one. Constructors and zero-frame runs do not open audio devices.