Trailers and video

Score a video from start to finish with music cut to length, a voice-over with captions, mastering and the sound put on the picture.

On this page

This is the job that used to need a Python script, FFmpeg and a loudness tool. In BoxLang Audio it is one script, and the trailer example does all of it.

boxlang examples/13-trailer/trailer.bxs --video=clip.mp4 --videoOut=scored.mp4

The steps, and the functions behind each:

StepFunction
Know how long the picture isvideoInfo
Cut the music to exactly thataudioFitTo
Speak the voice-over, with captionsaudioSpeakCues
Duck the music under the voiceaudioDuck
Master to a loudness targetaudioMaster
Captions for the editoraudioSubtitles
Chapter markersaudioMarkers
Sound on the pictureaudioMux

1. The length of the picture

videoInfo reads any video with FFprobe: length, size, and the video and audio streams.

info = videoInfo( "clip.mp4" );
println( info.seconds & " s, " & info.video.width & "x" & info.video.height & " at " & info.video.fps & " fps" );

FFmpeg is found on your computer or downloaded for you, see Formats and FFmpeg.

2. Music cut to length

Music is rarely the length of the video. audioFitTo changes its length to exact seconds without changing its pitch.

music = audioLoad( "cue.wav" );
music = audioFitTo( music, info.seconds );

It works best within about 25 percent. For bigger changes cut the music, or loop part of it with audioLoopify. See Time and pitch.

3. A voice-over with captions

audioSpeakCues speaks the text sentence by sentence with the pauses you choose, and returns the audio together with the time each caption line is spoken.

spoken = audioSpeakCues(
    text = "One module. Pure JVM. No Python. BoxLang Audio.",
    voice = "joe",
    pauses = { sentence: 0.45, paragraph: 0.9 }
);
voice = spoken.audio;      // mono
cues  = spoken.cues;       // [ { start, end, text }, ... ]

Level the voice by loudness rather than by its peak (speech has loud peaks and a low average), put it where you want it, and write the captions with the same offset:

lead = 1.5;                                    // the voice comes in after 1.5 seconds
audioSubtitles( cues=cues, format="srt", path="trailer.srt", offset=lead );

See Speech and subtitles.

4. The mix

Put the music and the voice on tracks of a timeline and let the music duck while the voice speaks:

t = audioTimeline( bpm=100, sampleRate=44100, channels=2 );
audioAdd( timeline=t, sound=music, at=0, track="music" );
audioAdd( timeline=t, sound=voice, at=lead, track="voice" );
audioTrackGain( t, "music", -6 );
audioDuck( t, "music", "voice", -9 );
mix = audioTrim( audioRender( timeline=t ), 0, info.seconds );

5. Master

final = audioMaster( audio=mix, target="streaming", truePeak=-1 );
println( audioLoudness( final ) );   // integrated -14 LUFS, true peak under -1 dBFS

target is streaming (-14 LUFS), podcast (-16), game (-16), broadcast (-23, EBU R128), cinema (-24), or a number. See Loudness and mastering.

6. Chapters for the editor

audioMarkers(
    markers = [ { time: 0, label: "Music in" }, { time: 1.5, label: "Voice-over" } ],
    format = "youtube",
    path = "chapters.txt"
);

Formats: json, csv, a DaVinci Resolve edl, srt, vtt, FFmpeg chapters (ffmetadata) and a youtube chapter list.

7. The finished video

audioMux( video="clip.mp4", audio=final, output="scored.mp4" );

The picture is copied, never re-encoded, so it is fast and lossless, and the result is never longer than the video. keepOriginal=true mixes the video's own sound underneath (originalDb sets how far down), and offset delays the new audio.

One command per step

Most steps are also commands: bx-audio probe, stretch --seconds, speak --captions, master, mux. See the command line reference.

Edit this page Download Markdown Last updated Oct 16, 2026, 11:59:46 AM Report an issue