How to Fit an AI Voiceover to an Exact Length Without Changing Pitch

No affiliate links in this post. This is our own production log from October 26, 2026 (KST). No tool vendor provided or reviewed it, and we did not test ElevenLabs or any other hosted voice service here. The voice clips were made with a local AI model and were not published.

Short answer from one small test: if your AI voiceover runs a little long, FFmpeg's atempo filter sped our VoxCPM2 clips up by about 11–13% to fit a 5.5-second slot, with almost no change in pitch, and Whisper still transcribed every word. It landed 8–19 milliseconds short of the target, and adding apad padded the files out to exactly 5.50 seconds. Simply resampling the audio (the "sped-up tape" method) also hit 5.50 seconds, but it raised the voice by roughly 10–12% on our rough pitch estimate.

The question

You have a 5.5-second slot in an edit and the narration comes out at 6.2 seconds. Hosted voice services often have a speed control. ElevenLabs documents a Speed setting from 0.7 to 1.2, default 1.0, and warns that extreme values may affect quality. The local model we use for narration, VoxCPM2, has no speed setting in the runner we use, so we fix the length after rendering. We wanted to know which common post-processing method keeps the voice sounding like the same voice.

What we ran

  • Model: VoxCPM2 (openbmb, Apache-2.0), local CPU run, the same settings we use for our narration (cfg 2.0, 10 inference steps), cloned from the same reference clip as in our earlier posts.
  • Script: one sentence, 22 words: "Open the editor, drop the voiceover on the timeline, and trim the silence at the end before you export the final cut."
  • Renders: the same text rendered twice, with no other changes. The two renders came out at 6.24 s and 6.08 s, so the speed-up factor has to be worked out for each file.
  • Target: 5.50 seconds. Factor = current length ÷ target (1.1345 and 1.1055).
  • Method A, tempo: ffmpeg -i in.wav -af atempo=1.1345 out.wav
  • Method B, resample: ffmpeg -i in.wav -af asetrate=48000*1.1345,aresample=48000 out.wav (plays the samples faster, like speeding up a tape)
  • Checks: length with ffprobe; median pitch with a simple autocorrelation estimate over voiced frames; transcript with a local Whisper model (whisper-large-v3-turbo).

Results

FileLength (s)Median pitch (Hz, approx.)Whisper words match script
Render 1, original6.240126.3yes
Render 1, atempo 1.13455.481126.6yes
Render 1, resample 1.13455.500141.2yes
Render 2, original6.080122.1yes
Render 2, atempo 1.10555.492122.1yes
Render 2, resample 1.10555.500133.7yes

Lengths are from ffprobe, rounded to milliseconds. Resampling should, in theory, raise pitch by the same ratio as the speed-up (about 13% and 11%). Our rough estimator measured +11.8% and +9.5%, so read the pitch column as a direction, not a precise value. Factors are shown rounded to 4 decimals; we passed the unrounded value to FFmpeg.

What we decided

For narration that has to keep sounding like the same narrator from clip to clip (based on the pitch estimate above, not a listening test), we use atempo and not resampling. The atempo outputs were a few milliseconds short of the slot. Running ffmpeg -i in.wav -af apad=whole_dur=5.5 out.wav on them gave files of exactly 5.500 s in both cases, with the extra time added as silence at the end. If your editor already holds the slot open, the few milliseconds probably don't matter. If your export has to be an exact length, pad it.

What this does not show

  • Two renders, one sentence, one cloned voice, one model, one target length. An 11–13% speed-up is small. We did not test bigger changes or slowing down.
  • Nobody listened to rate naturalness. "Pitch almost unchanged" comes from a simple estimator, not a listening test. A Whisper match is a transcript check, not a check of pronunciation or audio quality.
  • We did not test SoX, editor time-stretch tools, or any hosted service's speed setting. The ElevenLabs details above come from its documentation, not our test.

Repeat it on your own voiceover

  1. Measure the clip: ffprobe -v error -show_entries format=duration -of csv=p=0 in.wav
  2. Divide that by your target length to get the factor. Check that it is between 0.5 and 100, which is the range our FFmpeg 9.0.1 build lists for atempo.
  3. Run atempo=<factor>, then measure again.
  4. If you need an exact length, add apad=whole_dur=<target>. Then listen to the result before you use it.

Previous step in this series: Which punctuation makes a longer TTS pause? We measured 8 clips.

Sources checked

  • ElevenLabs docs, "Best practices" (Pace section), read October 26, 2026
  • FFmpeg 9.0.1 built-in filter help (ffmpeg -h filter=atempo, -h filter=apad), read October 26, 2026
  • Our raw measurements: 2 original renders, 6 processed WAV files, ffprobe lengths, pitch estimates and Whisper transcripts, kept in our production log.

Comments

Popular posts from this blog

FFmpeg Shows −1.5 dBTP. Did You Actually Fix the Audio?

VoxCPM2 vs ElevenLabs for a 30-Second Science Short: We Timed Both on the Same Script

Before You Upload an AI Song or Video: The Checks We Run (Free Commands)