Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
blank_issues_enabled: false
contact_links:
- name: 🛟 Support
url: https://github.com/linuxmatters/jivefire/blob/HEAD/SUPPORT.md
url: https://github.com/linuxmatters/jive-visualiser/blob/HEAD/SUPPORT.md
about: Check the support guide before opening an issue.
# - name: Code of Conduct Report
# url: https://yourproject.org/community-report/
Expand Down
10 changes: 3 additions & 7 deletions .github/workflows/builder.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ jobs:
- run: go vet ./...
- name: Check cyclomatic complexity
run: |
go install github.com/fzipp/gocyclo/cmd/gocyclo@latest
go install github.com/fzipp/gocyclo/cmd/gocyclo@v0.6.0
gocyclo -top 20 -ignore '_test\.go$' -avg .
- name: Check ineffectual assignments
run: |
go install github.com/gordonklaus/ineffassign@latest
go install github.com/gordonklaus/ineffassign@v0.2.0
ineffassign ./...
- uses: golangci/golangci-lint-action@v9

Expand Down Expand Up @@ -139,7 +139,7 @@ jobs:
comment-summary-in-pr: on-failure

- name: Run govulncheck
uses: golang/govulncheck-action@master
uses: golang/govulncheck-action@v1.0.4
with:
repo-checkout: false
go-version-file: go.mod
Expand Down Expand Up @@ -264,10 +264,6 @@ jobs:
chmod +x jive-visualiser-darwin-arm64
sudo mv jive-visualiser-darwin-arm64 /usr/local/bin/jive-visualiser
```

## Checksums

SHA256 checksums are provided below for verification.
NOTES

cat CHANGELOG.md
Expand Down
3 changes: 0 additions & 3 deletions .harper-dictionary.txt

This file was deleted.

28 changes: 18 additions & 10 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,23 @@
- Memory-efficient: ~50MB footprint for 30-minute audio vs 600MB for single-pass

### Key Modules
- `cmd/jive-visualiser/main.go` — CLI entry, 2-pass coordinator
- `cmd/jive-visualiser/main.go` - CLI entry and Pass 1 coordinator
- `cmd/jive-visualiser/pass2.go` - Pass 2 rendering and encoding runner
- `internal/audio/` — `StreamingReader` (reader.go) chunk-based decode, FFT analysis
- `internal/encoder/` ffmpeg-statigo wrapper, RGB→YUV conversion, FIFO buffer
- `internal/yuv/` YCbCr coefficients, `RGBToY`/`RGBToCb`/`RGBToCr`, `ParallelRows`
- `internal/encoder/` - ffmpeg-statigo muxer facade, video/audio helpers, RGB→YUV conversion, FIFO buffer
- `internal/yuv/` - YCbCr coefficients, `RGBToY`/`RGBToCb`/`RGBToCr`, `ParallelRows`, `RowPool`
- `internal/renderer/` — Frame generation, bar drawing, thumbnail
- `internal/ui/` Bubbletea v2 TUI (unified progress.go for both passes)
- `internal/ui/` - Bubbletea v2 TUI state, spectrum, preview, and summary views
- `internal/config/` — Constants (dimensions, FFT params, colours)
- `internal/theme/` - Terminal colour theme
- `internal/cli/` - Kong CLI helpers and styled help

## FFmpeg Integration

- All FFmpeg access through `third_party/ffmpeg-statigo` submodule (FFmpeg 8.0 static bindings)
- `*.gen.go` files in submodule are auto-generated — do not edit
- Audio decoding: `internal/audio/reader.go` — `NewStreamingReader` returns `*StreamingReader`
- Video/audio encoding: `internal/encoder/encoder.go` wraps libx264/AAC
- Video/audio encoding: `internal/encoder/encoder.go` exposes the public facade; `audio_encoder.go` and `video_encoder.go` own codec setup

## Charm TUI (v2)

Expand All @@ -47,13 +50,13 @@
## Audio Processing

- FFT size: 2048 samples (Hanning window)
- 64 frequency bars with log-scale binning
- 64 frequency bars with linear (uniform) frequency binning; logarithmic scaling applies to amplitude only
- Harmonica spring peak-hold bar dynamics: each bar rises instantly to any new peak, then springs back toward the live level. Spring params: frequency `6.0`, damping `1.0`, delta `1/FPS`, gain `2.0` (replaces the amplitude lift the old CAVA integrator provided)
- Audio frame size mismatch handled by FFmpeg's `AVAudioFifo` (in `internal/encoder/encoder.go`; FFT needs 2048, AAC expects 1024)
- Audio frame size mismatch handled by FFmpeg's `AVAudioFifo` (in `internal/encoder/audio_encoder.go`; FFT needs 2048, AAC expects 1024)

## Performance Patterns

- RGB→YUV conversion in `encoder/frame.go` parallelised across CPU cores via `yuv.ParallelRows` (8.4× faster than swscale)
- RGB→YUV conversion in `encoder/frame.go` parallelised across CPU cores via `yuv.RowPool` (13.2× faster than swscale)
- `convertRGBAToYUV` (YUV420P) and `convertRGBAToNV12` (NV12) in `encoder/frame.go` are intentionally kept as separate functions despite near-identical structure — the hot-path duplication avoids a callback/interface indirection that would hurt throughput; do not refactor into a shared helper (shared low-level primitives live in `internal/yuv`)
- Frame rendering uses symmetric mirroring (draw 1/4 pixels, mirror 3×)
- Pre-computed intensity/colour tables in `renderer/frame.go`
Expand Down Expand Up @@ -84,14 +87,19 @@
- Gradient/alpha tables: pre-computed in `NewFrame()`

### Changing UI output
- Unified progress UI: `internal/ui/progress.go` (handles both passes)
- Progress UI state: `internal/ui/progress.go` (handles both passes)
- Spectrum and completion helpers: `internal/ui/spectrum.go`, `internal/ui/summary.go`
- Message types: `AnalysisProgress`, `AnalysisComplete`, `RenderProgress`, `RenderComplete`
- Audio profile display persists from Pass 1 through Pass 2
- Video preview: `internal/ui/preview.go`

## Releases

- Do not add checksum or hash generation to the release workflow. GitHub shows SHA256 digests for release assets by default.

## Environment

- NixOS development shell via `flake.nix`
- Fish shell for terminal commands
- CGO required (`CGO_ENABLED=1` in build)
- Go 1.24.0 minimum
- Go 1.26 minimum
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ Your podcast audio deserves more than a static image on YouTube. Jive Visualiser

- 🖼️ **Thumbnail generator** YouTube-style PNG with your title, saved alongside the video
- 🎬 **1280×720 @ 30fps** H.264/AAC YouTube-ready MP4, no questions asked
- 🎚️ **64 frequency bars** that actually look discrete (not that smeared spectrum nonsense)
- 🎚️ **64 frequency bars** that look discrete (not that smeared spectrum nonsense)
- 🪞 **Symmetric mirroring** above and below centre, doubles the visual impact
- 🔬 **FFT-based analysis** 2048-point Hanning window, log scale frequency binning
- 🔬 **FFT-based analysis** 2048-point Hanning window, linear frequency binning, log-scaled amplitude
- ✨ **Spring-driven bar dynamics** bars snap up instantly, spring back down via harmonica peak-hold
- 🚀 **Stupidly fast** streaming pipeline, parallel RGB→YUV conversion
- ⚡ **GPU acceleration** auto-detected: NVENC, Vulkan, VA-API, QuickSync, VideoToolbox
- 📦 **Single binary** No Python. No FFmpeg install required. Just drop and render
- 🐧 **Linux** (amd64 and aarch64)
- 🐧 **Linux** (amd64 and AArch64)
- 🍏 **macOS** (x86 and Apple Silicon)

## Usage
Expand All @@ -36,7 +36,7 @@ Your podcast audio deserves more than a static image on YouTube. Jive Visualiser
./jive-visualiser --episode=42 --title="Linux Matters" input.wav output.mp4
```

### Without Episode Number (unnumbered audio)
### Without Episode Number (Unnumbered Audio)
```bash
./jive-visualiser --title="Linux Matters" input.wav output.mp4
```
Expand All @@ -53,7 +53,7 @@ Your podcast audio deserves more than a static image on YouTube. Jive Visualiser

## Build

Jive Visualiser uses [ffmpeg-statigo](https://github.com/linuxmatters/ffmpeg-statigo) for FFmpeg static bindings.
Jive Visualiser uses [FFmpeg statigo](https://github.com/linuxmatters/ffmpeg-statigo) for FFmpeg static bindings.

```bash
# Setup or update ffmpeg-statigo submodule and library
Expand All @@ -69,6 +69,6 @@ just test-encoder # Test encoder

FFmpeg's audio visualisation filters (`showfreqs`, `showspectrum`) render continuous frequency spectra, not discrete bars. No amount of FFmpeg filter chain kung-fu can achieve the discrete 64-bar aesthetic required for Linux Matters branding. Solution: Do the FFT analysis and bar rendering in Go, pipe frames to FFmpeg for encoding.

**Why Go over Python?** The original `djfun/audio-visualizer-python` tool is a moribund Qt5 GUI with significant tech debt. For our podcast production needs we wanted multi-archtitecture tools that's that can integrate into automation pipelines.
**Why Go over Python?** The original `djfun/audio-visualizer-python` tool is a moribund Qt5 GUI with significant tech debt. For our podcast production needs we wanted multi-architecture tools that can integrate into automation pipelines.

The Jive Visualiser architecture, such as it is, is available in the [ARCHITECTURE.md](docs/ARCHITECTURE.md) document.
The Jive Visualiser architecture, such as it is, is available in the [architecture document](docs/ARCHITECTURE.md).
2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Only the latest release is supported. Security fixes are released as patch versi

**Do not open a public issue for security vulnerabilities.**

[Report vulnerabilities privately](https://github.com/linuxmatters/jivefire/security/advisories/new). Include:
[Report vulnerabilities privately](https://github.com/linuxmatters/jive-visualiser/security/advisories/new). Include:

- Steps to reproduce
- Affected versions
Expand Down
Loading
Loading