Skip to main content
Most licensed tracks run two or three minutes. When your video is longer than the song, Loop stretches one track to cover the whole clip, not by slowing it down but by finding a musical section that repeats. The loop is cut on downbeats over a whole number of bars, so the beat never breaks at a seam, with automatic fades in and out.
Loop needs the video to be longer than the track by at least 30 seconds. As a guideline it is for clips over 4 minutes. For shorter clips the track can play straight. See Find where to cut. Soundstripe tracks only.

Loop a track

Pass a video_id you’ve already ingested and a track_id from a match.
Cue serves a 200 from its loop-plan cache. The first time you loop a given track against a given video there is nothing cached, so the plan is built as a job:
202 first time
A video whose ingest hasn’t finished gives you a different 202, with no job_id and a poll of /v1/videos/{video_id}. Poll the video to ready, then call /v1/loop again. Poll the loop job until it’s complete:
200 the loop plan
A 200 straight from POST /v1/loop carries the same body without job_id, status and cached. track is on every loop response: the song id is the work, the audio-file id is the specific render you fetch, and they are not interchangeable. The audio-file id is resolved best-effort and is null when the catalog lookup fails.

Reading the plan

segments is the authoritative playback path: the ordered ranges of the song to play back to back. Video time is music_in plus the cumulative length of the segments played so far. Read segments first. The flat fields below describe the same loop but cannot express a final pass that exits into a come-down outro instead of being truncated mid-body. Apply seam_fades, seam_curves and the per-segment gains, or the seams click and step in level. Full assembly steps are in Render under your own license. They apply whether or not you hold the license. The plan carries more than the table above: seam_times, song_start, song_duration, window_end, music_end, tail_seconds, sections_covered, end_label, an outro_start / outro_end pair when the plan resolves on an outro, and an options array holding up to four self-contained alternate plans, best first, with the served plan as options[0]. Treat anything not in the table as informational.

When a loop isn’t applicable

If there’s nothing to loop, applicable is false, the plan carries a reason, and nothing is billed:
retryable is the field to branch on. true means the analysis didn’t finish on this request and nothing was cached against the pairing, so calling again in a few seconds normally reads back work that completed in the background. false means it’s settled: pick another track. video_seconds, track_seconds and required_excess_seconds let you solve for the ceiling yourself. For the clip above, any track under 227s qualifies. Screening on those numbers before you call is free. Calling and being refused is also free, but it costs a round trip per track.

Duck under voiceover (auto-mix)

If your video has narration or dialogue, you’ll want the music to dip under the voice. Pass "auto_mix": true and an applicable loop comes back with a mix block telling you how to duck the music, using the same numbers the Cue app uses, so your render matches the app. There is no mix key on a not-applicable result, and none when the measurement can’t be read.
mix (on an applicable loop)

How to render it

Four steps, in this order. It is what Cue’s own export does:
  1. Take the footage’s own audio and apply video_gain_db.
  2. Take the music and apply music_gain_db.
  3. On the music only, apply envelope_points as additional attenuation.
  4. Sum the two, then limit.
envelope_points is [[t_seconds, gain_db], …] and it is the authoritative curve. It is literally the automation Cue’s own renderer replays. Read it as a positive amount to pull the music down at that instant: 0 means untouched, 20 means 20 dB below where step 2 left it. Interpolate linearly between points. That reproduces Cue’s curve exactly, and no point of it is approximated away. Points are emitted only where the curve moves, so long held passages cost nothing: a real 257-second clip came to about 390 points.
depth_db, attack_ms and release_ms are nominal. Ramp lengths are computed per gap, so these three describe a full-depth excursion and nothing else. A short pause gets a shallower, faster move than depth_db implies. They remain for callers who already render an approximation from them. If you render from these instead of envelope_points, your mix will be audibly cruder than Cue’s, with the pumping on short gaps that the per-gap ramps exist to prevent.
When the clip has no voiceover you get { "voiceover": false, "classification": …, "duck": null }. There is nothing to duck, so play the music as planned, and music_gain_db and video_gain_db are absent. Auto-mix reads the measurement warmed at ingest, so it adds no extra charge. The same auto_mix flag works on /v1/align.

What it costs

The cold build is billed per (video_id, track_id) pair, not once per track: looping the same track over a second video builds a second plan and is charged at the cold rate again. Every later loop of that same pairing is the warm rate. A not-applicable result bills nothing and auto_mix adds no charge. There is no cached field on a 200 straight from POST /v1/loop, because that 200 is served from the plan cache by definition and is always the warm rate. cached appears on the completed job instead, and there it is the field to read: a job normally builds the plan and bills cold, but if another call cached the same pairing while it queued it comes back cached: true at the warm rate. See Metering & pricing.