Flag and remove music in a live-event recording

Source: AudD•

Flag and remove music in a live-event recording

Find where copyrighted music plays in a long broadcast or livestream recording, flag each segment in a report, and produce a cleaned copy with those segments muted or cut.

A recording of a live event — a sports broadcast, a radio show, a livestream VOD, a conference session — is mostly speech, crowd, and commentary, with stretches of copyrighted music threaded through it: walk-on music, stingers, background beds, a DJ segment. This recipe finds exactly where the music plays and what it is, flags each segment in a report, and then builds a cleaned copy of the recording with those segments muted or cut.

What you’ll build

Two outputs from one recognition pass:

  • A flag report — one row per music segment, each with a file-absolute start/end time and the track that plays there (artist, title, label, ISRC, links). This is what you hand to a reviewer, a rights team, or a compliance log.
  • A cleaned recording — the same file with every flagged segment either muted (audio zeroed, video untouched) or cut out entirely, built with ffmpeg from the timestamps in the report.

The enterprise endpoint is the right tool: it handles arbitrary-length recordings and finds every track rather than one. Both the report rows and the ffmpeg edits are driven by file positions — where in the recording each music hit sits. Each match carries those as start_seconds and end_seconds, the song’s position in your file, and recognize_enterprise requests accurate offsets by default, so they’re precise.

AudD identifies the music; the policy is yours. This recipe locates and names recordings and edits your file. Whether a given segment actually needs muting or cutting — licensing, fair use, your platform’s rules — is a decision you make on top of the report, not something the API decides.

AudD identifies the music; the policy is yours. This recipe locates and names recordings and edits your file. Whether a given segment actually needs muting or cutting — licensing, fair use, your platform’s rules — is a decision you make on top of the report, not something the API decides.

Prerequisites

  • An API token from dashboard.audd.io. Get your own token there; the enterprise endpoint must be enabled on it. label, isrc, and upc come back on enterprise responses (ISRC/UPC require a Startup plan or higher).
  • Python 3.10+ with the SDK: pip install audd
  • ffmpeg (and ffprobe) on your PATH for the cleaning step.
  • The recording as a URL or a local file. https://audd.tech/example.mp3 is a public, reproducible file you can run against end-to-end.

Walkthrough

Step 1: Recognize the recording

Send the recording to recognize_enterprise as a URL, file bytes, or a path. A multi-hour broadcast comes back as a flat list[EnterpriseMatch] — one entry per recognized fragment, in time order — and each entry has a precise start_seconds / end_seconds, since accurate offsets are requested by default.

Each printed line is one recognized fragment, in time order. A music bed that runs for a minute appears as several consecutive matches naming the same track (Step 3 merges them into one segment). Stretches that are pure speech or crowd noise produce no match at all — that’s a gap, not an error, and exactly what you want: those stretches stay untouched.

Always set limit during development. The enterprise endpoint bills per 12 seconds of audio processed. A two-hour broadcast is hundreds of fragments; an unbounded call meters all of them. Start with limit=25, get the report and the edit right, then raise the cap for the full recording.

Always set limit during development. The enterprise endpoint bills per 12 seconds of audio processed. A two-hour broadcast is hundreds of fragments; an unbounded call meters all of them. Start with limit=25, get the report and the edit right, then raise the cap for the full recording.

Step 2: File positions, not song positions

The mute filter and the cut math both consume file positions, and start_seconds / end_seconds are exactly that: where this song plays in your file, in seconds (e.g. 64.2 to 71.6). Feed them straight to a player or ffmpeg. They’re None only when a fragment arrived without a usable position.

Don’t reach for start_offset / end_offset — those are the raw offsets the seconds are derived from, milliseconds within AudD’s internal 12-second scan fragment (0–~12000), not file seconds. And don’t use timecode as a file position: it’s the position inside the matched recording, telling you which part of the song was playing, not where in your file it plays.

Step 3: Build music segments from the matches

The report and the edit both want one segment per continuous play — “this music runs from 64.2s to 96.0s” — not a row per fragment. Collapse consecutive matches naming the same (artist, title) into one segment spanning from the first match’s start_seconds to the last match’s end_seconds.

A 30-second stinger becomes one segment with a real start and end. Because the SDK parses responses leniently, any field can be absent or None; the start_seconds guard and the end_seconds fallback cover the fragment that arrives without a position.

Step 4: Format positions into HH:MM:SS

A report wants clock times, not raw seconds. Format the file-absolute positions:

This always gives a zero-padded HH:MM:SS, which reads cleanly for a recording that runs past an hour.

Step 5: Render the flag report

Turn the segments into a report a reviewer can act on — both as structured rows (for a compliance log or a downstream tool) and as a readable summary.

Each row names the recording and locates it by a file-absolute span you can seek straight to. An empty report means the scan recognized no music in the covered range — a clean result, not an error.

Step 6: Mute the flagged segments

If you want to keep the recording’s full length and timeline (so existing chapter marks, subtitles, and clip references still line up), mute the audio over each flagged span and leave everything else intact. ffmpeg’s volume filter with an enable expression zeroes the audio only between the start and end of each segment:

Chaining one volume=...:volume=0 clause per segment produces a single audio filter that silences each flagged span and passes the rest through. -c:v copy leaves the video stream byte-for-byte; only the audio is re-encoded. The output has the same duration and timeline as the source — the music is just gone.

Step 7: Or cut the flagged segments out

If instead you want the music removed — a shorter recording with the music segments excised — keep the spans that are not flagged and concatenate them. Invert the flagged spans against the file duration, then cut and join the keep-spans:

This trims each keep-span out of the source and concatenates them, dropping the music entirely. The result is shorter than the source by the total duration of the flagged segments. (For an audio-only recording, drop the [0:v]/v=1 halves and keep just the atrim/audio concat.)

Muting preserves the timeline; cutting changes it. Mute when other assets (captions, chapter marks, highlight clips) reference timestamps in the original — their positions still line up. Cut when you want the music gone and a shorter file, and you’re willing to re-derive any timestamped assets against the new timeline.

Muting preserves the timeline; cutting changes it. Mute when other assets (captions, chapter marks, highlight clips) reference timestamps in the original — their positions still line up. Cut when you want the music gone and a shorter file, and you’re willing to re-derive any timestamped assets against the new timeline.

Step 8: Run it end to end

source is what AudD recognizes (URL or uploaded bytes); input_path is the local file you edit. They’re often the same recording — recognize a hosted copy or upload the bytes, then apply the resulting spans to your local master.

What you get back

One EnterpriseMatch per recognized fragment, in time order. The fields this recipe reads:

For the example file, a match might come back with start_seconds = 64.2 and end_seconds = 71.6 — the span that feeds both the volume=enable='between(t,64.2,71.6)':volume=0 mute filter and the cut/keep math.

Handling errors

The SDK raises typed exceptions; catch the ones you can act on.

  • Authentication errors (AudDAuthenticationError) — bad or missing token. Fail at startup.
  • Quota / subscription errors (AudDSubscriptionError) — request limit hit, or the enterprise endpoint isn’t enabled on your token. The enterprise endpoint and ISRC/UPC both depend on plan tier; surface these to the account owner rather than retrying.
  • Invalid-audio errors — the URL or file wasn’t decodable audio/video. Treat it as a hard failure for that source, not a silent empty report.
  • Connection errors (AudDConnectionError) — transient. Retry with backoff.
  • ffmpeg/ffprobe failures — a non-zero exit raises subprocess.CalledProcessError. A bad input path or codec issue surfaces here, separate from recognition; don’t conflate it with an empty report.

An empty report (no flagged segments) is a valid, distinct outcome from an error — the covered range recognized no music, so there’s nothing to mute or cut, and the cleaning steps no-op.

Going further

  • Re-running recognition re-meters every fragment. Run the scan once per recording and persist the report; rebuild the muted or cut file from the stored spans rather than re-scanning.
  • For a multi-hour broadcast where you only need a rough map of where music sits, sample with every/skip to trade coverage for metered fragments — see Enterprise cost optimization.
  • If your goal is a takedown filing rather than an in-place edit, the same start_seconds/end_seconds feed an evidence pack — see Generate DMCA takedown evidence.
  • To scan files as they’re uploaded rather than after the fact, see Build a copyright scanner for user-uploaded content.
  • Generate DMCA takedown evidence
  • Build a copyright scanner for user-uploaded content
  • Enterprise cost optimization
  • Python SDK docs
  • API reference

What this article says