Skip to content

YtGz/bandbox

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

54 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🎸 BandBox

Plug in a USB stick after practice. Get an organized library of songs and takes.

BandBox turns hours of raw rehearsal recordings into a searchable, playable collection β€” automatically. Silence trimming, riff-based song identification, and a real-time web UI for the whole band. Built for heavily distorted genres where standard music analysis tools give up.

✨ How It Works

🎀 Record β†’ πŸ”Œ Plug in USB β†’ 🧠 Auto-process β†’ 🎡 Browse your songs
  1. Record your practice session to a USB stick (from your mixer, interface, or portable recorder)
  2. Plug the stick into a Raspberry Pi running BandBox
  3. Relax β€” BandBox copies, uploads, normalizes, trims silence, extracts riff fingerprints, and groups recordings into songs
  4. Review β€” open the web UI, listen to takes, audit trim decisions, and fix any groupings

Everything updates in real time. When the worker finishes processing a recording, it appears in your browser without refreshing.

πŸ—οΈ Architecture

                  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                  β”‚              Docker Compose                  β”‚
USB Stick         β”‚                                             β”‚
  β”‚               β”‚  Caddy ──┬── /api/upload ──→ SvelteKit ◄─────── Convex Cloud
  β–Ό               β”‚          β”‚                     β–²    β”‚      β”‚      (database)
Raspberry Pi ─────┼── Wi-Fi ──── /pocket-id/* ──→ Pocket-ID   β”‚
(bandbox.py)      β”‚          β”‚                                 β”‚
                  β”‚          β”œβ”€β”€ /oauth2/* ──→ oauth2-proxy    β”‚
                  β”‚          β”‚                                 β”‚
                  β”‚          └── /* ──→ oauth2-proxy ──→ SvelteKit
                  β”‚                                     β”‚      β”‚
                  β”‚                          Python Worker      β”‚
                  β”‚                     (audio processing)      β”‚
                  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Service Role
🌐 Caddy Reverse proxy, automatic HTTPS
🎨 SvelteKit Frontend + upload API (Bun)
🐍 Python Worker Normalize, trim, encode, fingerprint, match
πŸ”‘ Pocket-ID Passkey/WebAuthn login (OIDC provider)
πŸ›‘οΈ oauth2-proxy Auth gate β€” keeps SvelteKit auth-free
☁️ Convex Real-time cloud database

🧠 Audio Intelligence

Standard music analysis chokes on heavy distortion, blast beats, and alternate tunings. BandBox uses features that survive all three. For the full deep dive, see Audio Analysis.

HPSS Preprocessing β€” every recording is split into harmonic (guitar, bass, vocals) and percussive (drums, transients) layers via Harmonic-Percussive Source Separation. This single step dramatically improves both pitch and rhythm extraction.

Riff Segmentation β€” novelty detection on a self-similarity matrix built from spectral contrast and onset strength. A checkerboard kernel slides along the diagonal to find structural boundaries, merging short segments (<3s) and splitting long ones (>60s).

Fingerprinting β€” five features per riff, weighted adaptively based on riff type:

Feature Blast/Tremolo Groove/Breakdown What it captures
🎡 Contour 55% 15% Melodic shape via a three-method cascade (spectral centroid β†’ rolloff β†’ pYIN), normalized for tuning independence
πŸ₯ Groove 10% 35% Beat-aligned 16-slot onset pattern β€” captures rhythmic identity
🎯 Drums 10% 20% Kick/snare patterns from the percussive layer β€” most consistent across takes
🎸 Spectral 5% 10% Tonal character per frequency band β€” captures the distortion signature
⏱️ Tempo 20% 20% BPM with double/half tempo detection β€” catches tracker ambiguity

Weights shift automatically by measuring onset uniformity: uniform onsets (blast beats, tremolo) lean on contour; sparse onsets (grooves, breakdowns) lean on rhythm.

Matching β€” DTW with open begin/end on 200-point normalized contours (handles partial takes and tempo variation), cosine similarity on rhythm features. Double/half tempo detection ensures a riff tracked at 100 BPM still matches one tracked at 200 BPM.

πŸ“¦ Data Lifecycle

Recordings flow through four stages. Each has clear ownership and retention rules.

πŸ’Ύ USB Stick ──→ πŸ“‚ Pi Staging ──→ πŸ“₯ Server Incoming ──→ 🎡 Processed Files
   (keep)         (temporary)        (temporary)            (permanent)
Stage What happens Retention
πŸ’Ύ USB Stick Never modified by BandBox. Read-only mount. Band decides when to format. ♾️ Band's responsibility
πŸ“‚ Pi Staging New files copied here, deleted after server confirms upload. ~29 GB buffer. πŸ—‘οΈ Auto-deleted after upload
πŸ“₯ Server Incoming WAV received via HTTP, manifest created for worker. πŸ—‘οΈ Deleted after processing
🎡 Processed FLAC master + Opus segments (song, pre, post). Metadata in Convex. ♾️ FLAC never deleted

Resilience:

  • πŸ”Œ Lost your Pi? Plug the USB into a new one. Duplicates are skipped by SHA-256 hash.
  • πŸ’₯ USB stick died? FLAC masters are safe on the server.
  • πŸ’½ Server disk full? Opus files can be regenerated from FLACs.
  • πŸ”„ Want to reprocess? The FLAC is always there.

πŸš€ Deployment

Prerequisites

1. Configure

cp .env.example .env
# Fill in: DOMAIN, PUBLIC_CONVEX_URL, CONVEX_HTTP_URL, PI_API_KEY, WORKER_API_KEY
# Generate a cookie secret (must be exactly 16, 24, or 32 raw bytes):
openssl rand -hex 16

Then set the worker API key on your Convex deployment (must match the value in .env):

bunx convex env set WORKER_API_KEY "your-key-here" --prod

2. Launch

Standalone (includes Caddy + Pocket-ID β€” everything in one box):

# First: uncomment caddy_data, caddy_config, and pocket_id_data
# in the volumes section of docker-compose.yml
docker compose --profile standalone up -d

Bring-your-own (you already have a reverse proxy and/or OIDC provider):

docker compose up -d

Then add BandBox to your existing Caddy:

bandbox.example.com {
    reverse_proxy localhost:48231
}

That's it β€” oauth2-proxy handles authentication and proxies to SvelteKit internally. Set OIDC_ISSUER_URL in .env to point at your existing OIDC provider. Change the port with OAUTH2_PROXY_PORT if needed.

3. Set up authentication

If using the bundled Pocket-ID (standalone profile):

Open https://your-domain/pocket-id and create your admin account (passkey). Then:

  1. Go to OIDC Clients β†’ Create new client
  2. Set redirect URI to https://your-domain/oauth2/callback
  3. Copy the Client ID and Client Secret into .env
  4. docker compose restart oauth2-proxy

If using an existing OIDC provider:

  1. Create an OIDC client with redirect URI https://your-domain/oauth2/callback
  2. Set OIDC_ISSUER_URL, OIDC_CLIENT_ID, and OIDC_CLIENT_SECRET in .env
  3. docker compose restart oauth2-proxy

4. Invite the band

Each member registers in your OIDC provider (passkey, password, SSO β€” whatever it supports). BandBox doesn't need per-user features; the only question is "are you in the band?"

5. Set up the Pi

Follow the Pi Setup Guide to turn a Pwnagotchi into your recording uploader.

πŸ› οΈ Development

# Install
bun install

# Dev server (two terminals)
bun run dev          # SvelteKit
bunx convex dev      # Convex
Command Description
bun run dev Start development server
bun run build Build for production
bun run check Type-check the project
bun run lint Lint and format check
bun run format Auto-format all files
bun run test Run unit tests

πŸ“– Documentation

πŸ“„ License

MIT-0

About

Plug in a USB stick after practice. Get an organized library of songs and takes.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors