Audio tools: compose, effects, library, beats, mix, master
Read this when a video needs music, sound effects, a voice-over mix or a loudness check, and you
need the exact showtime audio commands and the audio/mix.json format. For choosing music by
tone, read music.md. For how loud, how many and where sounds go, read sound-design.md. For
music written in code inside a canvas film, read synth-score.md.
Everything runs locally. Every command has --help with examples, and most accept --json.
Essentials#
- Music: a produced track with
showtime audio music pick --for launch --dur 45(then"catalog": "<id>"in the mix), or a composed bed withshowtime audio compose --style underscore --dur 45 --sections ...; which style:music.md(§1, §2) - With
"audio": "audio/mix.json"in showtime.json,showtime renderruns the mix itself. While iterating runshowtime audio mix audio/mix.json -o audio/mix.wavalone, thenshowtime audio meter: verify, never guess (§1) - The mix masters to -14 LUFS / -1 dBTP by default (
master.lufs,master.true_peak) (§5) - The mix is made to be heard on a phone speaker: a high-pass at 40 Hz on everything but the voice, and a
low shelf on a bass-heavy bed before the loudness normalisation (
master.speaker_safe, on by default; off for a video meant for headphones) (§5) - Each track has exactly one source:
file,lib,catalog(pair it with"fit": true),synthorcompose(§5) - Levels (
"level": "auto", the default): voice -16 LUFS, music -20, ambience -32, sfx by category;gain_dbis relative to that;"level": "raw"keeps a file's own level (§5) - Place effects with
at+"align": "hit"(reads the.sfx.jsonsidecar ofshowtime audio sfx); give tonal effects the music's--key;--variants 4so repeats differ (§3, §5) - Ducking:
"duck": {"under": "voice", "depth_db": 12, "carve": 0.4};carve0.3–0.5 is transparent, above 0.7 sounds hollow (§5) - A quiet intro is fixed with
gain_pointsorsection_gainon the bed, not with an sfx or by renaming a section (§5) - Compose: every section marker lands on a downbeat, the file is exactly
--dur, and the logo goes onend_hit(take it frommix.report.json, not the cache); try 2 or 3--seeds (§2, §5) - Read
mix.report.jsonbefore you listen:voice_to_music_dbaim 10–20; an sfxabove_bed_dbunder 0 dB is probably masked; read the warnings. After the rendershowtime qameasures the voice over the music line by line from the narration stem, plus silences, jumps at cuts and a cut-off ending (§6) - CC-BY items must be credited:
showtime renderwritescredits.txtand a Credits block inshare.txt(paste into the description);--license cc0avoids the question; a musicfilewith no license match warns (§4, §5) - Library:
showtime audio lib search --kind music --mood calm --min-dur 60; the starter part (~41 MB) is fetched on first use,showtime audio lib fetchgets the whole ~249 MB (§4) showtime audio beats: withphrase_flowthe grid is fictional, cut on phrases and energy changes (§6)- Master to WAV and encode once at the end (AAC and MP3 add up to about 0.5 dB of overshoot) (§6)
- MusicGen weights are CC-BY-NC: never use its output in a commercial video (§2, §7)
| Section | Lines |
|---|---|
| 1. The five-minute path | 57-72 |
| 2. Music | 74-129 |
| 3. Sound effects | 131-147 |
| 4. Library | 149-197 |
| 5. The mix spec (audio/mix.json): Heard on a phone, Credits | 199-341 |
| 6. Analysis and delivery | 343-369 |
| 7. Platform notes | 371-381 |
1. The five-minute path#
showtime audio music pick --for launch --dur 45 # a produced track (fetched when first mixed)
showtime audio lib fetch # optional: the whole ~249 MB library (~10-15 min); the starter part comes by itself
showtime audio compose --style underscore --dur 45 \
--sections 0:intro,6:verse,24:break,40:outro -o audio/bed.wav # which style: music.md
showtime audio sfx whoosh -o audio/whoosh.wav # prints JSON with "hit"
showtime audio mix audio/mix.json -o audio/mix.wav # mastered to -14 LUFS / -1 dBTP + report
showtime audio meter audio/mix.wav # verify, never guess
showtime audio mix audio/mix.json --validate # only the spec rules, no render (check runs this)
When a project's showtime.json has "audio": "audio/mix.json", showtime render runs the mix
itself, and showtime check and showtime render reject a spec the mixer would refuse (audio_mix error; the render stops before capturing a frame). Run showtime audio mix on its own while iterating: it takes seconds, and the report shows what
changed.
2. Music#
| Need | Command |
|---|---|
| A produced track for a launch, trailer or emotional piece | showtime audio music pick --for launch --dur D (or search, info <id>), then "catalog": "<id>" in the mix |
| Music cut exactly to the edit, with section changes on picture changes | showtime audio compose --style S --dur D --sections "t:name,..." |
| A real recording from the library | showtime audio lib search --kind music --mood calm --min-dur 60 |
| A library track at exactly the video's length | showtime audio fit track.opus --dur 42.5 -o bed.wav (bar-aligned loop or musical ending; --ending song keeps the track's own ending) |
| A short film cut to a produced track: the excerpt and scene changes on its phrases | showtime audio cuts --for launch --dur 30 --scenes 5 (--apply <project> retimes the scenes and sets the track) |
| The beat grid of any track | showtime audio beats track.mp3 (writes track.beats.json) |
| Temp music from a text prompt (non-commercial) | showtime audio musicgen "prompt" --dur 20 -o draft.wav (optional tier) |
The produced-music catalog (lib/st/audio/music_catalog.json, nearly 300 tracks: Scott Buckley and
Kevin MacLeod under CC BY 4.0, composers on OpenGameArt under CC BY 3.0/4.0 or CC0, CC0 and public-domain
recordings; every track was downloaded, measured
and passed a quality gate: no muffled old transfers, hiss, crackle, clipping, mono, dead gaps or wild
loudness swings, thresholds in music.py):
showtime audio music search [words] --for USE --shelf S --mood M --energy 0.2-0.5 --dur D --vocals noneranks tracks;pickreturns the best one (--n 1the next);presetslists the uses;statscounts. Shelves: cinematic, inspiring, ambient, corporate-tech, upbeat, documentary, tension, playful, lofi, piano, orchestral.- Nothing is bundled. A mix (or
showtime audio music fetch <id>, orsetup --full) downloads the file from the creator's site on first use, announces it with its size, checks the pinned sha256 and caches it in~/.showtime/music($SHOWTIME_MUSIC_CACHE). Cached tracks work withSHOWTIME_OFFLINE=1;--seed DIRcopies from a folder of earlier downloads. - A catalog track skips its near-silent lead-in by default. For a short cut of a long track that builds
slowly,
"offset": "highlight"starts at its loudest sustained stretch (on a downbeat;music infoshows where), or give seconds. showtime audio music veto <id>hides a track frompick(--undo,--import vetoes.json).showtime audio music openverse <words>is a live CC BY / CC0 search of Freesound and Wikimedia Commons beyond the catalog (about 20 searches a minute, 200 a day);--fetch openverse:<id> -o <dir>saves one with its.license.json. Jamendo is left out unless you pass--source jamendo: its own terms add conditions to commercial use and its licensing program can claim videos, so check the artist's terms first.
showtime audio compose details:
--styleis one of 18 styles (showtime audio styles; defaultunderscore).--bpmand--keydefault to the style's own.--sections "0:intro,8:build,16:drop,26:outro". Names: intro, verse, build, drop, chorus, break, bridge, outro. Every marker lands exactly on a downbeat. The tempo is nudged per section (usually under 2 %, up to about 6-7 % for very short sections) and a section may get a 2-beat bar to make that happen. Above a 3 % bend, or with a 2-beat bar, compose warns and prints a--bpmthat puts every marker on whole bars (when one exists near the asked tempo), or the same markers moved to whole bars at the asked tempo. A marker inside the final hit's ring-out (for example27:outroin a 30 s bed whose hit lands at 27.14 s) merges into the ending, with a one-line note.- The piece ends with a final tonic hit, snapped to the grid inside a short ring-out. The file is
exactly
--durseconds (sample-exact).end_hitin the output is the time of that hit: put the logo there. - Transitions come with it: a riser that lands on each drop, reverse cymbals into energetic
sections, an impact on drops for cinematic styles, and a downlifter into outros (
--no-sfxremoves them). - Outputs:
bed.wav(mastered, -14 LUFS),bed.mid,bed.beats.json(beats, downbeats, bars, sections, events,end_hit, thebackendandsoundfontfile actually used, the plannotes),bed.stems/{drums,bass,pad,arp,lead,keys,sfx}.wav. --backend auto|sf|synth|hybrid: SoundFont instruments (GeneralUser GS), the numpy synth, or synth drums/bass with SoundFont keys and strings. Iftinysoundfontor the SoundFont is missing, it falls back to the synth automatically. It still works, it just sounds more electronic.--seed Ngives a different melody and variation with the same structure. Try 2 or 3 seeds. In a mix.json compose track,"seed": "auto"takes the seed from the project and, unless"key"is given, moves the style's key (up to a fourth), so two videos on one style do not share a bed.
3. Sound effects#
showtime audio sfx-typeslists 56 procedural types in 7 categories, with their hit kind:onset: the sound hits at its start (impacts, clicks, bells).peak: the loudest moment (whooshes, sparkles).end: the build-up lands on the last sample (risers, reverse cymbals, swells, sparkle-up).
showtime audio sfx <type> [--dur --key --intensity 0..1 --seed N] -o file.wavwritesfile.wavandfile.sfx.json, and prints the JSON:hit(seconds),hit_frame_30fps,category, and the level.showtime audio mixreads the sidecar, so"align": "hit"uses the true hit automatically.- Tonal types (riser, swell, notification, success, bell, logo-sting, drone, and others) take
--key. Give them the music's key so effects sit in the harmony. - Output is loudness-matched per category (
sound-design.md§2), sogain_db: 0in a mix is a sensible level. --variants 4renders four seeds (x-1.wav...x-4.wav). Use a different variant for each repeat, so repeated clicks don't sound identical.- Library effects (Kenney, OpenGameArt and generated variants) carry
hit,categoryandharshnessin the catalog.
4. Library#
showtime audio lib fetch [--tier core|extended] [--no-generated] # idempotent; resumes
showtime audio lib search whoosh --kind sfx --distinct # words match ids, titles, tags, moods
showtime audio lib search --kind music --mood uplifting --bpm 100-130 --min-dur 60 --license cc0
showtime audio lib search --kind music --key Am --dur 45 # compatible keys rank higher
showtime audio lib info incompetech-voxel-revolution # details + the exact credit line
showtime audio lib credits <id> <id> -o CREDITS.txt
showtime audio lib stats | sources | generate
showtime audio lib index ~/Sounds/MyPack --name mypack --license "vendor-license" # your own pack, in place
- Library parts: the first command that reads the library fetches the starter part (~41 MB, about 1.5
min: common effects, three ambiences, six stingers, one bed per broad mood). A search that finds
fewer than 3 results fetches the category part it points at (
sfx,ambience,music-upbeat,music-calm,music-epic), once, announced with its size.showtime audio lib fetch --list-partsshows them;--part NAMEfetches one now. A library you pointSHOWTIME_LIBRARYat, or index yourself, is never filled automatically. - Tiers:
core(~249 MB) has every Kenney CC0 audio pack, OpenGameArt CC0 packs and ambiences, about 45 Kevin MacLeod tracks and stings (CC-BY 4.0, stored as Opus), and CC0 music from Komiku, Loyalty Freak Music and Musopen (Chopin).generatedis rendered locally and needs no download: about 160 effect variants and 28 composed beds.extendedadds about 200 MB more music and effects. Core sources are pinned (URL, size, sha256); most extended sources are not pinned yet, so their sha256 is recorded instate.jsonon the first download and every re-download must match it (trust on first use). Maintainers pin them withshowtime audio lib pin --tier extended.
- Licenses: CC0 and generated items need no credit. CC-BY items must be credited.
showtime audio mixwritesCREDITS.txtnext to its output and lists the credits in the report;showtime rendercopies them intocredits.txtbeside the final, which is the file that ships. Paste them into the video description.--license cc0avoids the question entirely.- A library file copied into a project and used as
"file"keeps its license: the mix matches it to the catalog by content (size, then sha256). A file with a<file>.license.jsonsidecar uses that. A musicfilewith neither gets a warning (use"lib": "<id>", or add the sidecar).
- A library file copied into a project and used as
- Kinds and categories:
- Kinds are
music,stinger(short musical hits and jingles),sfx,ambienceandvoice(announcer words). - SFX categories are
ui,transition,impact,foley,fx,musicalandambience. --kind ambiencealso lists sfx items that can serve as a bed (at least 3 s, loopable or named or tagged as a loop, such as a 7 s water loop in a foley pack), ranked below real ambience items and marked "an sfx loop (catalogued as sfx)".
- Kinds are
- Moving the library: set
SHOWTIME_LIBRARY=/pathto keep it elsewhere, for example on an external disk. - Extra sound packs (
showtime audio packs list): 35 more packs, 34 CC0 and one CC BY 4.0 (paper, keyboards, a typewriter, cloth, coins, UI, impacts, sci-fi, whooshes, city and crowd ambiences) that are not in the core tier. A mix naming one of their items ("lib": "oga-keyboard-typing/...") fetches the pack first;showtime audio lib searchsays when an uninstalled pack matches;showtime audio packs fetch <id> | --category C | --allinstalls ahead of time. Licenses and sources:lib/st/audio/sfx_packs.json.
5. The mix spec (audio/mix.json)#
{ "duration": 20.0,
"tracks": [
{"id": "bed", "kind": "music", "file": "audio/bed.wav", "gain_db": -2,
"fade_out": 1.2, "duck": {"under": "voice", "depth_db": 12, "carve": 0.4}},
{"kind": "voice", "file": "voice/vo.wav", "start": 0.6},
{"kind": "sfx", "file": "audio/whoosh.wav", "at": 3.0, "align": "hit"},
{"kind": "sfx", "synth": {"type": "impact", "key": "D", "intensity": 0.8, "seed": 3}, "at": 17.5},
{"kind": "sfx", "lib": "kenney-interface-sounds/click-001", "at": 5.2, "gain_db": -4, "pan": 0.3},
{"kind": "ambience", "lib": {"search": {"query": "rain", "kind": "ambience"}}, "loop": true, "gain_db": -3}
],
"sections": {"intro": 0, "demo": 4, "cta": 16},
"master": {"lufs": -14, "true_peak": -1}
}
- Sources: each track has exactly one.
file: a path.lib: a library id, or{"search": {...}, "pick": 0}.catalog: a produced-music id ("buckley-with-these-hands"), or{"use": "launch", "mood": "hopeful", "pick": 0}. Fetched on first use and credited; pair it with"fit": true.synth: ashowtime audio sfxspec.compose: ashowtime audio composespec. The duration defaults to the rest of the mix, and the result is cached by content hash.
- Levels:
level: "auto"is the default. Each track is first brought to its kind's reference: voice -16 LUFS, music -20 LUFS, ambience -32 LUFS, sfx by category.gain_dbis then relative to that. Use"level": "raw"to keep a file's own level. - Placement:
start(timeline seconds),offset(skip into the source),endordur.at+align(hit|start|end|peak) puts that point of the sound exactly onat.hitin the track overrides the measured hit (seconds from the file start).
- Length:
loop: trueorfit: truefills the window. Music loops on bar lines when a beat grid is known (a.beats.jsonsidecar, a composed track, or a library item), and ends musically."ending": "song"keeps the track's own ending (its last bars spliced in at a downbeat, asaudio fit --ending song);"fade"fades out instead. - Shape:
fade_inandfade_out, pluspanfrom -1 to 1. Every clip edge gets at least 3–5 ms of fade, so there are no clicks. - Ducking:
duck: {"under": "voice" | ["voice", "sfx"] | [track ids], "depth_db": 12, "attack": 0.08, "release": 0.5, "hold": 0.3, "lookahead": 0.12, "carve": 0..1}.- The duck follows the activity of the key tracks: speech for voice, and any other track too (a list of sfx ids ducks the bed under the key clicks). It starts 120 ms early, holds across short pauses and releases slowly.
carvealso cuts the bed only in the voice's own bands, biased to 1–4 kHz, and only while the voice speaks. 0.3–0.5 is transparent; above 0.7 it starts to sound hollow.
- Typing in a recorded demo:
{"kind": "sfx", "keystrokes": "media/events.json", "start": 10.8, "rec_offset": 7.85, "rate": 1.75}clicks once per typed character and key combo of ademo record, in sync with the recording placed atstart(rec_offset= the recording time shown there,rate= itsdata-rate), so no click times are converted by hand. - Typing on a page
typewriter:{"kind": "sfx", "typewriter": {"text": "npm create showtime", "cps": 18}, "start": 2.5}clicks once per typed character (and backspace) on the component's own timeline: give it the sametextorscript,cadence,cps,fitandseedas the page, andstart= the video time the typing starts (its clip's start plusdata-at). - Designed layers and masking: the report warns when an effect is under the rest of the mix. Tracks
of one family (same file stem or explicit id prefix such as
key-01..key-38, the same synth type) never count as "the rest" for each other; a riser whose hit is its end is judged before its end;"layer": "<id>"marks a track stacked on another (a braam on an impact);"texture": trueskips the check for a track meant to sit under (soft UI clicks under a voice). Masked tracks of one family are reported as one line. - Gain automation:
gain_points: [[t, db], ...]on any track (timeline seconds, linear in dB between points, end values hold), e.g.[[0, 4], [2.6, 4], [3.2, 0]]lifts a quiet hook by 4 dB.section_gainon a music bed sets a level per section with 0.25 s ramps:{"intro": 3}(the composed bed's section names) or{"0": 2.5, "5": 0}(seconds). This is the fix for "the intro is too quiet": a short sfx cannot lift a whole section, and renaming a section changes the arrangement. sections: optional names for the report. They default to the composed track's sections, or 5 s windows.questions:trueor{"duck_db": 12, "tick": false, "tick_gain_db": -4}at the top level. For every stop-and-ask question in showtime.json (html-export.md§ Questions) it lowers each music and ambience track byduck_dbthrough the question's pause and think beat (0.25 s in, 0.4 s out), and with"tick": trueadds a soft clock tick on each second of the countdown. The times come from the questions (voice cues resolved), so the duck follows a re-voice. A score drawn in code (ST.score) is not in the mix: lower it yourself overST.questions.master:lufs(default -14) andtrue_peak(default -1).engineisst(exact, the default),loudnorm(ffmpeg two-pass) ornone.speaker_safe(defaulttrue): the mix is heard on a phone speaker, not only on headphones. See "Heard on a phone" below.falsehere,"master": {"speaker_safe": false}in showtime.json orshowtime audio mix --no-speaker-safeturns it off.- Output formats are
.wav(24-bit),.flac,.m4a,.mp3and.opus.
- Paths resolve against the mix.json folder, then the project root (the folder with
showtime.json), then the current directory.--rootoverrides.
Heard on a phone#
Phone and laptop speakers play little under ~300 Hz. Loudness (LUFS) counts the bass, so a mix whose energy is
kick, bass line and sub reaches -14 LUFS and still plays quiet on a phone. The measure is the mix's loudness
above 300 Hz (ffmpeg -af "highpass=f=300,highpass=f=300,ebur128", the same numbers) and its gap to the full
mix. Measured on 7 Oct 2026: the posted films sit 0.7-8.2 LU under the mix (voice-led films 1-6); a music-led
showreel with 75 % of its weighted energy at 80-160 Hz sat 13.6 LU under, so on a phone it played about 9 dB
quieter than the voice-led films at the same -14 LUFS.
The speaker-safe step of showtime audio mix (and so of showtime render with a showtime.json "audio" mix spec; not
an ST.score bed or render's built-in fallback mixer), on by default:
- A 2-pole high-pass at 40 Hz on the music, ambience and effects: nothing a speaker plays, only headroom.
- When the mix is still more than 10 LU under above 300 Hz, a low shelf at 160 Hz on the bed and on the sub-heavy effects, as deep as it takes to reach 8 LU (at most -12 dB), before the loudness normalisation, which then lifts the whole mix back to the target with the mids where a phone hears them.
- The voice is never touched. The step is deterministic; the render's audio cache keys on the setting and on the audio code.
On the showreel's own mix: -27.6 to -22.4 LUFS above 300 Hz (13.6 to 8.3 LU under, the shelf at its -12 dB limit), -33.9 to -27.5 above 1 kHz. On two posted voice-led films (4.7 and 5.8 LU under) only the 40 Hz high-pass acts: the speaker numbers move by 0.01 LU and the difference is 30-33 LU under the mix.
A bed with nothing above 400 Hz cannot be fixed by the shelf alone: pick one with more in the mids, or raise
its mid parts. mix.report.json speaker has the numbers (gap_300_lu_before, shelf_db, capped,
above_300_lufs, gap_300_lu, above_1k_lufs), and each effect its speaker_gap_lu (its loudest moment
in full over its loudest above 300 Hz). An effect over 15 LU (boom, impact, sub-drop, punch,
reverse-hit, heartbeat: 17-30 LU) is sub-heavy; one that lands with no mid sound on its hit (another
effect within 60 ms, a layer, or the crash of a composed bed) is listed as sub_alone with a note:
layer a mid transient on the same hit (static-burst, glitch or tick at -8 to -12 dB: 0-3 LU, so a phone plays
them; not a pitched hit such as metal-hit, which reads as a bell, nor thock, 9-10 LU). A riser
ends on the hit, so it does not count.
mix.report.json contains:
- integrated LUFS, true peak and LRA, plus the pre-master levels
speaker: the speaker-safe step and how loud the mix is above 300 Hz and 1 kHz (above)- per section: LUFS, RMS and the RMS of each bus
voice_to_music_db: how far the voice sits above the music and ambience while speaking (aim for 10–20). When the music is the project'sST.score(not a track of the mix),rendermeasures the voice mix against the raw score (integrated loudness) and writes that gap here, withvoice_to_music_source: "score"- per track: gain, level reference and alignment, plus duck and carve statistics; for a music bed
its landmarks on the output timeline (
end_hit,music_sections,downbeats) and, for a composed bed, thebackend_usedandsoundfont_file(the credit line for the SoundFont): line up the logo withend_hitfrom here, not from the cache; for each sfxabove_bed_db, its loudest 25 ms over everything else (under 0 dB it is probably masked, and the report warns) - the library and catalog items used, their credits (
credits) and full credit items (credit_items: title, artist, license, source, where the credit must go, Content ID status); a CC BY sound without credit text stops the mix with an error - warnings (voice too close to the music, a first section more than 6 LU under the loudest, masked effects, clipping, heavy limiting, non-commercial sources)
- paths relative to the report's folder, so a report can be copied or published
Read the report before you listen. Then listen.
Credits#
showtime render turns the report's credit items into credits.txt beside the video (the exact lines
each license asks for, courtesy lines for CC0, an optional end-card line) and a block in share.txt
between --- Credits (keep in the video description) --- and --- end credits --- (replaced on each
render; the rest of the file is kept). For Scott Buckley tracks it prints a Content ID note: his
Smart Content ID claims YouTube videos whose description lacks the credit. By hand:
showtime audio credits --report <mix.report.json> --out-dir <job>, or
showtime audio credits <id> ... [--end-card] for a quick look.
6. Analysis and delivery#
showtime audio beats filewritesbpm,bpm_confidence,beats,downbeats,onsets(each tagged kick/snare/hat), anenergycurve (0.5 s),sections(energy phases VOID/LOW/MEDIUM/HIGH),moments(SURGE/DROP) andkey.- Trust
rhythmic/pacing: withbeat_cut, hard cuts may sit on beats. Withphrase_flow(ambient or rubato music), the grid is fictional: cut on phrases and energy changes instead. - For composed music the grid is exact by construction (
source: "composed"). - The tempo usually matches metadata within 1–3 %. On-beat vs off-beat phase can still be wrong on dense dance music with offbeat bass, so check the first downbeats on a waveform view when a hard sync matters.
- Trust
showtime audio meter file [--windows 1] [--ffmpeg]gives integrated, short-term max, momentary max, LRA, true peak (8x oversampled), sample peak, RMS, clipped runs and DC.--ffmpegcross-checks with ffmpeg's ebur128.- The hearing checks of
showtime qarun on the delivered file. Render keeps the mix's narration stem (work/audio/mix.voice.wav, or<video>.work/audio/with-o) and itsmix.report.json; qa lines the stem up with the file's audio and scales it, so the voice and everything else are measured apart after the master and the AAC encode. WARNs:voice_masked(a line under 8 dB over the music: deepen the duck,carve, orgain_pointsunder that line),quiet_stretch(near silence over 2 s mid-video: carry it with the bed),level_jump(over 6 LU at a cut: even it withsection_gain/gain_points, or make it a designed drop on a section change),abrupt_end(the bed still playing on the last frame:fade_outor end onend_hit),speaker_loudness(the mix above 300 Hz over 10 LU under the full mix, FAIL over 18: see "Heard on a phone" in §5; an INFO when the mix turned speaker-safe off on purpose). Thresholds:runtime/thresholds.jsonhearing.review-packwrites all of it for the critic asaudio.txtandhearing.png, with each effect's timing against its cut or CUE (review.md§1). showtime audio master in -o out [--target youtube|podcast|broadcast|...] [--preset mix|music|voice|none]normalises to within 0.05 LU with true peak at or below the ceiling. Master to WAV and encode once at the end: AAC and MP3 add up to about 0.5 dB of overshoot.
7. Platform notes#
- Everything portable: all DSP is numpy/scipy. ffmpeg comes from the resolver, for decoding, Opus encoding and the loudnorm engine, and paths go to it as plain arguments, so Windows drive letters are fine.
- SoundFonts: rendering uses
tinysoundfont. It has ready-made wheels for macOS arm64, Windows and Linux x64. On Intel macOS and Linux arm64 it is compiled at setup; if that fails, compose uses the numpy synth for every part (styles still work). - MusicGen lives in its own venv (
showtime setup --with musicgen). On CPU it runs roughly 10x slower than real time. Its weights are CC-BY-NC, so never use its output in a commercial video. The mix report warns when it is used.