Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Compose video-synced background scores from a storyline JSON using local waveform synthesis (numpy + ffmpeg). Styles: chiptune, ambient, electronic. Deterministic, offline, no cloud service.
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-03 | ✗→✓ | ▲ Improved | 60% | 0% |
| case-04 | ✗→✓ | ▲ Improved | -5% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 6% | 0% |
| case-01 | ✗→✓ | ▲ Improved | 67% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 98% | 0% |
<img src="banner.png" width="100%" alt="music-composer banner">
Compose a background score that follows a video's dramatic arc, fully local: numpy waveform synthesis (oscillators, ADSR, layering, delay reverb) + ffmpeg for MP3 encoding. No samples, no MIDI hardware, no cloud API.
timestamps (opening, tension dip, drive section, climax, outro).
Waveform synthesis can deliver chiptune, ambient, and electronic background beds. It cannot deliver pop, rock, classical, or orchestral film music with its built-in synth — but the arrangement is backend-neutral: see "Beyond waveform synthesis" below for rendering the same composition through SoundFonts, orchestral libraries, or external generation.
Reconstructed as-is from the reference score (179.5 s, C minor):
merge into one section (reference: 7 acts → 5 sections; acts 1–3 formed a single 62 s calm opening). Each section gets exact start/end in seconds.
calm i–VI–III–VII · tense iv–i–V–i · alive VI–VII–i–III · driving i–VII–VI–V · epic iv–V–VI–i (V is harmonic-minor major).
Layers join at thresholds: pads always → sparse bells (<0.3) → arp (≥0.25) → bass (≥0.4) → lead (≥0.45) → drums (≥0.5) → drive extras (≥0.65) → pad octave doubling (≥0.85).
damp: Gaussian volume duck — 1 - depth · exp(-((t-T)²)/(2σ²)).Reference: depth 0.5, σ 1 s at T=84 s, on the spoken beat "Two databases. Same cluster." (~1:24).
climax: time window forcing full layering, peak volume, octave-doubledpads (reference: 154–170 s = 2:34–2:50, on the 2D→3D morph).
outro: from its start, drums/bass/lead drop out and bells fade to 20 %(reference: 170–179.5 s, closing card).
fade-in/out, feedback-delay reverb (100 ms, decay 0.25), tanh drive + peak normalization to a background level (reference master measured: mean ≈ −22 dB, max ≈ −1.6 dB).
volume ramp; the score is a bed, not a lead.
bash# Bundled standalone copy (this skill folder): python compose_music.py storyline.json -o out/score python compose_music.py --init # print a storyline template python compose_music.py --selftest # 3 s render + verification # Canonical engine (preferred when the repo is available): python <ai-media-editor>/tools/compose_music.py storyline.json -o out/score
Output: score.wav (stereo 16-bit 44.1 kHz), score.mp3 (192k, needs ffmpeg on PATH; skipped with a warning otherwise), score.notes.json (the arrangement/note log: every placed note with time, layer, MIDI pitch, duration, velocity), and score.mid — a real Standard MIDI File (type 1: tempo track with one tempo event per section, note track with GM program hints per style, drums on GM channel 10). Written dependency-free; no pretty_midi/mido needed.
Determinism: same storyline + same seed → byte-identical WAV.
json{ "title": "my-score", "duration": 179.5, "bpm": 100, "key": "C", "mode": "minor", "style": "chiptune", "seed": 42, "fade_in": 3.0, "fade_out": 5.0, "crossfade": 2.5, "peak": 0.85, "drive": 2.0, "reverb": {"delay_ms": 100, "decay": 0.25}, "sections": [ {"start": 0.0, "end": 62.0, "emotion": "calm", "intensity": 0.18, "bpm": 60, "comment": "optional note"}, {"start": 62.0, "end": 88.0, "emotion": "tense", "intensity": 0.4, "bpm": 72} ], "events": [ {"type": "damp", "time": 84.0, "depth": 0.5, "width": 1.0}, {"type": "climax", "start": 154.0, "end": 170.0}, {"type": "outro", "start": 170.0} ] }
duration (required, seconds), sections (required, ≥1, sorted,non-overlapping, within duration).
start, end (required); emotion ∈ calm | tense | alive |driving | epic | outro; intensity 0–1 (default per emotion); bpm (default: global bpm); melody (optional MIDI list, cycled; otherwise a seeded random walk over scale tones is generated).
key: note name (C, C#, Db, …), mode: minor | major.style: chiptune | ambient | electronic (see below).damp: time (s), depth 0–1, width = σ in seconds.Full worked example (the reference video's reconstruction): example-storyline.json — renders a 179.5 s score matching the original's master level (mean ≈ −22 dB, max ≈ −1.6 dB).
| Style | Lead | Bass/Arp | Drums | Character | |---|---|---|---|---| | chiptune | square + detune + triangle | triangle bass, fast square arps | noise-based kick/hat/snare | retro console, arpeggio-driven (the reference style) | | ambient | soft triangle/sine | slow arps, long-attack pads | only from intensity ≥ 0.75 | sparse, bell-focused, wide reverb feel | | electronic | sawtooth + detune + sub | punchy bass, saw arps | full kit | driving EDM-adjacent bed |
The genre ceiling above is the sound backend, not the composition. The Storyline→Score method produces a backend-neutral arrangement; the bundled numpy synth is just the free, offline default renderer. Every run also writes a Standard MIDI File (<out>.mid) — render it through better instruments:
Install FluidSynth (fluidsynth.org, Windows: winget install FluidSynth) plus a free GM SoundFont (GeneralUser GS by S. Christian Collins, or MuseScore_General.sf2). Then: fluidsynth -ni soundfont.sf2 score.mid -F score_sf.wav -r 44100 → MP3 via ffmpeg. This unlocks pop/rock band sounds, piano, basic strings.
Edition, Soni Musicae, Salamander Grand Piano. Better strings/brass, more epic. Honest note: articulation and humanization (velocity variation, legato, dynamics curves) matter more than the sample set — and true film-score epicness additionally needs arrangement maturity; a backend alone is not enough.
privacy/rights questions — only after explicit user approval, never the default.
Planned but not yet implemented: a humanize option in the engine (per-note velocity/timing jitter) so sample-based rendering does not sound mechanical (marked as TODO in the engine docstring).
crossfades are auto-capped at 20 % of duration / 50 % of the shortest section).
*.notes.json) is the analysis-friendly record; the *.midfile is the interchange format for DAWs/SoundFont renderers (GM program numbers are rough per-style hints — remap them to taste).
Other measured skills in the registry, with their headline benchmark lift.