Skip to main content

Generate beautiful, customizable audio visualizer videos with Python.

Project description

VisGen — Audio Visualizer Generator

Generate beautiful, customizable audio visualizer videos with Python. FFT-reactive circular bars, multiple visualizers, rich overlays, post-processing effects, and a plugin system — all composable on a single canvas.

Features

Feature Description
Circular FFT Visualizer Animated bars reacting to audio frequencies around a circular image
Multiple Visualizers Render several visualizers on the same canvas via render_multi()
Background Effects Solid colors, images with chained effects (blur, grayscale, sepia), opacity, fit modes
Overlays Text (static & timed), images, and video overlays with time ranges, opacity, anchoring
Positioning Named positions (center, top-left, bottom-right...) or exact (x, y) pixels
Frame Effects Post-processing plugins: glow, vignette, shake, zoom pulse
Bar Effects Pre-processing plugins: bounce, mirror, smooth decay
Plugin System Drop .py files in ~/.visgen/plugins/ or use entry points
Quad Modes One-circle repeated-bar quadrants with single or multi-color schemes
Quality Output H.264 + AAC via FFmpeg

Installation

Requirements: Python 3.10+, FFmpeg in PATH

From PyPI:

pip install visgen

Or with uv:

uv add visgen

For local development:

git clone https://github.com/yourname/visgen.git
cd visgen
pip install -e ".[dev]"

Runtime dependencies: numpy, opencv-python, Pillow

Quick Start

from visgen import AudioVisualizerVideo

viz = AudioVisualizerVideo(
    audio_path="song.wav",
    image_path="cover.jpg",
    output_path="output.mp4",
)
viz.render_single()

API Reference

AudioVisualizerVideo

AudioVisualizerVideo(
    audio_path: str,
    image_path: str | None = None,           # used if visualizers not given
    output_path: str = "output.mp4",
    duration: float | None = None,            # default = full audio length
    fps: int = 30,
    circle_radius: int = 150,
    bar_count: int = 64,
    bar_max_length: int = 200,
    colors: ColorScheme | None = None,
    smooth_factor: float = 0.3,
    background: Background | None = None,
    visualizers: list[CircularVisualizer] | None = None,
    frame_effects: list[FrameEffect] | None = None,
    bar_effects: list[BarEffect] | None = None,
)

Note: Either image_path or visualizers must be provided.

Render Methods

Method Description
render_single(position=..., overlays=..., visualizer=...) One visualizer on canvas
render_multi(configs=[(viz, pos, angle), ...]) Multiple visualizers, same canvas, same audio
render_quad_repeated_bars(...) One circle, full bars repeated per quadrant
render_quad_repeated_bars_multi_color(...) Same with per-quadrant colors

Backgrounds

from visgen import ColorBackground, ImageBackground

# Solid color
ColorBackground(color=(15, 15, 30))

# Image with single effect
ImageBackground("bg.jpg", effect="blur", blur_radius=10.0, fit_mode="cover")

# Image with chained effects (applied in order)
ImageBackground("bg.jpg", effect=["blur", "grayscale"], blur_radius=12.0)

# Image with opacity
ImageBackground("bg.jpg", effect="sepia", opacity=0.6, fit_mode="cover")

Fit modes: cover | contain | stretch

Effects: blur | grayscale | sepia

Overlays

from visgen import TextOverlay, TimedText, ImageOverlay, VideoOverlay

# Static text
TextOverlay(text="Title", position=(540, 80), font_size=60, anchor="mm")

# Timed lyrics
TimedText(start_time=2.0, end_time=5.0, text="Lyrics", position=(540, 980))

# Static image
ImageOverlay("logo.png", position=(100, 100), size=(120, 120), anchor="mm")

# Timed image
ImageOverlay("badge.png", position=(500, 500), start_time=1.0, end_time=6.0)

# Looping video
VideoOverlay("loop.mp4", position=(900, 900), size=(200, 200), loop=True)

Anchors: mm (center) | lt (top-left) | rb (bottom-right) | lb | rt

Positioning

viz.render_single(position="center")        # named position
viz.render_single(position="bottom-right")  # corner
viz.render_single(position=(300, 800))      # exact pixels

Named positions: center, top-left, top-right, bottom-left, bottom-right, top-center, bottom-center, left-center, right-center

Frame Effects (Post-Processing)

Applied to the final frame before encoding.

from visgen import GlowEffect, VignetteEffect, ShakeEffect, ZoomPulseEffect

viz = AudioVisualizerVideo(
    audio_path="song.wav",
    image_path="cover.jpg",
    output_path="out.mp4",
    frame_effects=[
        GlowEffect(strength=0.4, radius=10.0),
        VignetteEffect(strength=0.5),
    ],
)
viz.render_single()

Bar Effects (Pre-Processing)

Modify FFT bar values before rendering.

from visgen import BounceEffect, SmoothDecayEffect

viz = AudioVisualizerVideo(
    audio_path="song.wav",
    image_path="cover.jpg",
    output_path="out.mp4",
    bar_effects=[
        BounceEffect(speed=0.15, amplitude=0.2),
        SmoothDecayEffect(decay=0.9),
    ],
)
viz.render_single()

Examples

Multiple visualizers side by side

from visgen import AudioVisualizerVideo, CircularVisualizer, ColorScheme

left = CircularVisualizer("cover1.jpg", 140, 64, 180, colors=ColorScheme(bar=(0, 200, 255)))
right = CircularVisualizer("cover2.jpg", 140, 64, 180, colors=ColorScheme(bar=(255, 100, 100)))

video = AudioVisualizerVideo(
    audio_path="song.wav",
    output_path="duo.mp4",
    visualizers=[left, right],
)
video.render_multi([
    (left, (300, 540), 0),
    (right, (780, 540), np.pi),
])

Custom inline effects

from visgen import FrameEffect, BarEffect
import numpy as np
from PIL import Image

class GreenTint(FrameEffect):
    def apply(self, frame, frame_idx, bar_values=None):
        arr = np.array(frame, dtype=np.float32)
        arr[:, :, 1] *= 1.15
        return Image.fromarray(np.clip(arr, 0, 255).astype(np.uint8))

class SquashBars(BarEffect):
    def process(self, bar_values, frame_idx, audio_chunk=None):
        return np.power(bar_values, 1.5)

viz = AudioVisualizerVideo(
    audio_path="song.wav",
    image_path="cover.jpg",
    output_path="out.mp4",
    frame_effects=[GreenTint()],
    bar_effects=[SquashBars()],
)
viz.render_single()

Plugin discovery

from visgen.plugins import load_plugins, registry

# Auto-discovers Plugin subclasses in ~/.visgen/plugins/
load_plugins()

# Inspect registered extensions
print(registry.frame_effects)
print(registry.bar_effects)

# Instantiate by name
effect = registry.create_frame_effect("GlowEffect", strength=0.5)

Running the Examples

python -m visgen.main

src/visgen/main.py contains 38 example functions. Control which run by editing the EXAMPLES list at the bottom of the file:

EXAMPLES = [
    example_01_minimal,
    example_04_image_bg_blur,
    example_31_frame_effects,
]

File Structure

src/visgen/
├── __init__.py           # Public exports
├── main.py               # 38 runnable example functions
├── audio.py              # AudioProcessor (FFmpeg extraction + FFT)
├── background.py         # Background ABC, ColorBackground, ImageBackground
├── colors.py             # ColorScheme dataclass
├── overlay.py            # TextOverlay, TimedText, ImageOverlay, VideoOverlay
├── renderer.py           # AudioVisualizerVideo (main composer)
├── utils.py              # Font loader & position resolver
├── visualizer.py         # CircularVisualizer
├── bars/                 # Bar-value pre-processing effects   ├── base.py           # BarEffect ABC   ├── builtin.py        # BounceEffect, MirrorEffect, SmoothDecayEffect   └── __init__.py
├── effects/              # Frame post-processing effects   ├── base.py           # FrameEffect ABC   ├── builtin.py        # GlowEffect, VignetteEffect, ShakeEffect, ZoomPulseEffect   └── __init__.py
└── plugins/              # Plugin discovery & registry
    ├── base.py           # Plugin, PluginMeta, PluginRegistry
    ├── loader.py         # discover_plugins(), load_plugins()
    └── __init__.py

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

visgen-0.2.1.tar.gz (15.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

visgen-0.2.1-py3-none-any.whl (22.3 kB view details)

Uploaded Python 3

File details

Details for the file visgen-0.2.1.tar.gz.

File metadata

  • Download URL: visgen-0.2.1.tar.gz
  • Upload date:
  • Size: 15.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.13 {"installer":{"name":"uv","version":"0.11.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for visgen-0.2.1.tar.gz
Algorithm Hash digest
SHA256 7aa18cff317701f1a98e05a58e262dcad57ea3033bc7b28e5fbb9dd092b3acf2
MD5 8e8ffc2581a33150c33fd892022a4ed1
BLAKE2b-256 1632118f59eed5278067905d5a83969c0d157626328ca70c2c459110286dbfaf

See more details on using hashes here.

File details

Details for the file visgen-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: visgen-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 22.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.13 {"installer":{"name":"uv","version":"0.11.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for visgen-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 5e863926370bb2405434b648edcac53a859b7ef514a19f252f5d8b30cd2519a3
MD5 0b1455b73aebd5689db033cc52ba4c44
BLAKE2b-256 30bc95a2de0d90c979009d1dffc232f7f6a4cb4b24b82ece0e65a25160f7a7c1

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page