[soundscape.effects.<name>] says what the sound is,
and decktalk soundscape generates it. [[mix.effects]] says where it plays, and decktalk assemble lays it into the soundtrack.
The two are split because the sound is bought once and placed as often as you like. Moving an effect
to another word costs nothing, and the file is asked for again only when its own prompt changes.
The starter that decktalk init writes declares neither table, so every table below is one you add
to decktalk.toml. The example puts a click on 1.2:word, the cue in the starter’s section 1 where
the closing band lands.
Before you start
- Resolve the cues once, with
decktalk cueor with any build. An effect plays at the second its cue resolved to, so a cue that has never been resolved has no second to sit on. - Put
ELEVENLABS_API_KEYin.envto generate the sound. Generating one spends credits at the rate[voice] price_per_1000_charactersstates. - Bring your own audio file instead if you have one. Any file ffmpeg can read works, it needs no key, and only the fourth step below applies to it.
1
Describe the sound
The table is named for the sound, and that name is what the generated file is called.
decktalk.toml
decktalk soundscape writes it to build/soundscape/tick.mp3. Set out in the same table to
write it somewhere else, such as media/tick.mp3, which is where a sound you want to keep when
build/ is deleted belongs.The same table may carry duration_seconds, prompt_influence and model_id, each of which
replaces the matching key of [elevenlabs] for this one
sound. At the defaults an effect is effect_seconds long, which is half a second.2
Read the plan before you buy it
A run without voice reports what it would ask for and buys nothing, so this is how to read the
prompt and the price first.
items[0].status is planned, which is the word for an item this run would buy and did not.
The one judgement the stage makes is FILE_MISSING, for an
item whose audio a mix would look for and not find, so the run exits 1 until the file exists.3
Generate it
build/soundscape/ledger.json, keyed by the request itself, so a second run that would send the
same request keeps the file it has and sends nothing. Change the prompt and the next run buys the
sound again, because the request no longer matches the row. --force buys every item of the run
again whether the request moved or not.4
Cue the sound
A
[[mix.effects]] row names the file, the section and the cue. The cue is a wire id, which is
the slide id, a colon and the local name the page writes.decktalk.toml
The sound plays at the section’s start in the film, plus the second the cue resolved to, plus
offset. The cue time is on the section’s own clock, so moving a section elsewhere in the film
moves its sounds with it and costs no edit here.A row may reuse a file another row already names, so one purchase can click on six different
cues.5
Mix it into the film
assemble mixes the soundtrack again and records nothing, so a level or a cue you changed here
costs one stage rather than a build.A file the row names and the project has not got is a certain FILE_MISSING, and that layer
plays as silence. A cue that did not resolve is one sentence on the stream, and the sound does
not play. The film is still written either way.Give every sound a caption
caption is what a viewer who cannot hear the film reads in its place. The build writes it into the
SubRip and WebVTT files as its own cue, wrapped in square brackets, so caption = "soft click" is
read as [soft click]. A caption you write with the brackets already on it is left as you wrote it.
A sound with no caption is in the film and in no caption file, and assemble says so on every
run, naming the file, the cue and the section. There is no finding code for it, because the frozen
list holds none that means this, so it is a sentence on the stream rather than a code that means
something else.
The sound’s caption stays on screen for one second. Two captions are never on screen at once, so a
sound that lands inside a speech cue joins that cue as a line of its own, and a sound that lands in
the gap before one joins the cue after it. Only a sound with a whole second to itself keeps a cue of
its own. Accessible video is the whole of what a build writes for a
viewer who cannot see or cannot hear it.
What ducks and what does not
The music bed plays at[mix] music_db and ducks to [mix] music_duck_db under every span that
carries speech, ramped in and out over [audio] duck_ramp_seconds at each edge. A span that carries
speech is a spoken section from its start to its last word, and a clip section for the whole of its
own length.
A sound effect is neither of those. It does not duck the music, and the music does not duck it, so
the only thing that decides whether a click is heard over the bed is the db on its own row. That is
why the level sits on the effect rather than on the table that generated it: the same file mixed at
-16 under a quiet passage and at -8 under a loud one is one purchase used twice.
Sound is the whole mix, layer by layer.
Pick the sounds one run generates
--section selects sections, which is what every stage selects on, and the soundscape’s own items
are named rather than numbered. So a run that names sections keeps the effects those sections cue.
[[mix.effects]] row in one of the named sections points at
the file the item writes. The row’s file and the item’s output path are compared as paths, so a
row that names media/tick.mp3 while the table writes build/soundscape/tick.mp3 selects nothing.
Set out on the table when you want the sound somewhere else, rather than copying the file by hand.
The music is generated whenever any section is selected, because one bed plays under the whole film,
and the ambience bed is generated when a selected page section sets ambience = true.
Related
- Read every part of the mix: Sound
- Look up every key of both tables: decktalk.toml
- Read the stage’s own flags: CLI
- Write the captions a viewer reads: Accessible video