---
title: Clean up the dialogue and keep the original
description: Noisy dialogue cleaned into a new file, placed beside the original so you can compare, then de-essed, EQ'd, compressed and checked for loudness.
---
You get clean dialogue from noisy location sound, also called dialogue cleanup, noise reduction or audio repair. Your agent makes a cleaned copy of each voice file, places it beside the original on the timeline with the original muted, then evens out the voice with de-essing, EQ, compression and a limiter. The original file never changes, so you can switch back at any moment.

Use invideo for this when you want to hear the clean and the original side by side in your edit: the clean is a new file, the original stays on its own muted track, and every audio effect is a setting you can change.

## Quickest path

Set up your agent first with [invideo for AI agents](/agents). Then give it the timeline URL and this prompt.

```text
The dialogue in scene 5 has traffic noise and hiss. Clean each voice
file, keep the originals muted under the clean ones, then de-ess,
EQ and compress the dialogue. Do not cut any words or pauses. Price
the cleaning first and work on a branch.
```

In a chat app, you paste the timeline URL into the chat. In a terminal, you paste it into the prompt.

## What you need

Clean sound starts with the best source. Give the agent the recorder files if you have them.

- **The dialogue.** The timeline URL, or the sound files: the boom, the lavs, or the camera's sound.
- **The problem.** Hiss, hum, traffic, wind, room echo, mouth clicks, harsh "s" sounds.
- **What to keep.** Music or effects recorded under the voice, if any.
- **The delivery.** The loudness target your platform or broadcaster publishes. Streaming services and broadcasters each state their own figure; the agent sets it with `target_lufs` on `export`.

## Steps

The agent listens first, cleans into new files, and works on a branch.

<Steps>
<Step title="Listen to the sources">
The agent creates a branch with `timeline_history`. On that branch it runs `media` with `audio.content` on each voice file to find the speech, `audio.loudness` for the level, and `audio.waveform` for the shape. Expected result: the files with the most noise, and where the speech is.
</Step>
<Step title="Clean each voice into a new file">
The agent runs `media` with `audio.clean` on the voice file's sequence URL, from `add_media` or `invideo asset upload`. It runs `dry_run: true` first and tells you the price. For a price of 1 credit or more it waits for your yes. Then it runs it again with `max_credits` set to that price and an `idempotency_key`. On a sound file it uses the model `clean_voice.clean_audio`, and on a video file `clean_voice.clean_video`. It turns on noise removal, and leaves off the options that cut fillers or silences, so the timing stays the same. Both models take `keep_music`, so music under the voice can stay in the clean file. Expected result: a new sequence URL per file. The original file stays as it was.
</Step>
<Step title="Split music from the voice, if needed">
Where music or effects sit under the voice, the agent runs `media` with `audio.separate` on the file's sequence URL to split the sound into stems. It runs `dry_run: true` first and tells you the price. For a price of 1 credit or more it waits for your yes. Then it runs the paid call with `max_credits` set to that price and an `idempotency_key`. Expected result: a stem per part, with the voice on its own.
</Step>
<Step title="Place the clean beside the original">
The agent adds an audio track with `add_track`, reads its id with `get_timeline`, places each clean file at the same frame as its original with `insert_media`, and mutes the original clip with `set_audio_muted`. Expected result: the clean voice plays, and the original sits muted under it.
</Step>
<Step title="Shape the voice with audio effects">
The agent adds `click_remover`, `de_esser`, `eq` and `compressor` to the clean dialogue track with `add_audio_effect`. When several dialogue tracks share one chain, it creates a dialogue bus with `create_audio_bus`, routes the tracks to it with `set_audio_routing`, and puts the chain on the bus instead. In a second call, it sets each with `set_audio_effect_parameter`, by the effect ids `get_timeline` gives. It adds `limiter` to the timeline. Expected result: the effects in `get_timeline`, in that order.
</Step>
<Step title="Check the loudness">
The agent runs `audio.loudness` on the clean files and compares them with the target. It checks each scene with `capture` and `check_timeline`. Expected result: voices at an even level.
</Step>
<Step title="Export">
The agent runs `export` with `format` video and `target_lufs` set to the platform's target. For the dialogue alone, it exports with `mode` audio and `audio_format` wav. Expected result: an export card with status `completed`.
</Step>
</Steps>

The same job from a terminal:

```bash
invideo branch new <edit-url> --name dialogue-clean --token <state_token>
invideo edit show <branch-url>
invideo media audio.content <branch-url> --asset m2
invideo media audio.loudness <branch-url> --asset m2
invideo media audio.clean <voice-sequence-url> --dry-run \
  --model clean_voice.clean_audio --inputs '{"remove_noise":true}'
invideo media audio.clean <voice-sequence-url> --max-credits <price> \
  --model clean_voice.clean_audio --inputs '{"remove_noise":true}' \
  --idempotency-key clean-m2
invideo status <clean-sequence-url> --wait
invideo edit change <branch-url> --timeline T1 --token <state_token> \
  --operations @dialogue.json
invideo media audio.loudness <clean-sequence-url>
invideo edit export <branch-url> --format video --target-lufs -14
invideo edit export <branch-url> --format video --mode audio \
  --audio-format wav
```

Where the values come from: `<edit-url>` from `invideo edit new`. `<state_token>` comes from `invideo edit show` on the URL the next command runs on: `<edit-url>` for `branch new`, then `<branch-url>`, read fresh, because the main token is stale on the branch. `<branch-url>` is the `branch_url` that `branch new` returns. `<voice-sequence-url>` is the `url` that `invideo asset upload` returns for the voice file, and `m2` is its bin id, which the reads that return at once take with `--asset`. `<price>` is the price the dry run returns, its `credits`. `<clean-sequence-url>` is the URL the paid `audio.clean` returns. The file in `--operations @dialogue.json` is a bare list of ops, like the `operations` list below.

The key MCP calls place the clean voice, mute the original, and shape the voice. This is the MCP `edit_timeline` path, on the branch. The original dialogue sits on `A1`. The first call adds a track for the clean files. This fence is the bare list of ops, the same list `--operations @ops.json` takes.

```json
[
  { "op": "add_track", "name": "Clean voice", "kind": "audio" }
]
```

The agent reads the new track's id with `get_timeline`, `A4` here, then sends the next call. `c12` is the original dialogue clip on `A1`. This fence is the full MCP `edit_timeline` call.

```json
{
  "url": "<branch-url>",
  "timeline_id": "T1",
  "expected_state_token": "<state_token>",
  "operations": [
    { "op": "insert_media", "asset": "<clean-sequence-url>",
      "track": "A4", "at_f": 1200, "ripple": false },
    { "op": "set_audio_muted", "target": "c12", "muted": true },
    { "op": "add_audio_effect", "target": "A4", "target_kind": "track",
      "effect": "de_esser" },
    { "op": "add_audio_effect", "target": "A4", "target_kind": "track",
      "effect": "eq" },
    { "op": "add_audio_effect", "target": "A4", "target_kind": "track",
      "effect": "compressor" }
  ]
}
```

The audio effects get ids when this call lands. In a third call, the agent sets each one with `set_audio_effect_parameter` and the id from `get_timeline`. For the EQ, `band1` set to a high-pass at 80 Hz, `{"hp": 80}`, takes out rumble.

## Cost and time

Edits and exports are free. Generation and transcripts cost credits. Paid stock costs a small credit charge, or one of your workspace's iStock licenses. Your agent runs a dry run first and tells you the price before it spends anything.

- **Costs credits:** each cleaned file from `audio.clean`, and each split from `audio.separate`.
- **Free:** placing and muting, every audio effect, buses, and the exports. `audio.content`, `audio.loudness` and `audio.waveform` show their price in the dry run before anything starts.

Cleaning a scene's files takes a few minutes. Setting the effects takes the agent a few minutes more. See [Credits and what they cost](/account/credits) for prices.

## If something goes wrong

Most problems come from a clean file that no longer lines up, or effects pushed too hard.

| Symptom | Fix |
| --- | --- |
| `get_model` or `generate` refuses the model as not found | Models retire. Run `find_models` with the job in words, use the best match, and tell the person which model you used. |
| The clean file is shorter than the original | Fillers or long silences were removed. Clean again with those options off, so the timing matches. |
| The clean voice sounds thin or watery | The cleaning went too far. Compare with the original, and keep the original where it sounds better. |
| The voice is out of sync after placing | Place the clean file at the original clip's start frame, read with `get_timeline`. |
| A voice is still loud and quiet by turns | Lower the compressor's `threshold` with `set_audio_effect_parameter`. |
| The music must come out as its own stem | Run `media` with `audio.separate` on the file's sequence URL, with `dry_run: true` first, then `max_credits` and an `idempotency_key`. |
| The "s" sounds are still harsh | Lower the `de_esser` `threshold`, or raise its `range`. |
| Breathing and room noise got louder | The compressor is too strong. Raise its `threshold` or lower its `ratio`. |
| The export peaks too high | Add `limiter` to the timeline and set its `ceiling`. |
| `audio.clean` is refused as `not_found` | It got a bin id. Pass the voice file's sequence URL instead. |
| CLI exit 2 on `-i` | `media` takes model inputs as `--inputs` with a JSON object, not `-i`. |
| CLI exit 5 | A limit on credits or quota. Check the balance. |
| Avoid: deleting the original sound | Instead: mute it with `set_audio_muted`. The clean is a new file, and you may want the original back. |
| Avoid: cleaning with fillers or silences removed | Instead: keep the timing. Cut words on the timeline, where you can undo them. |

## Prompts to try

Each prompt is a real variation of the job.

```text
The lav on the actor in scene 9 has clothing rustle. Clean only that
file, compare it with the boom, and use whichever sounds better per line.
```

```text
There is music on set under the dialogue at the party. Split the stems,
keep the voice, and lay a clean music track from stock under it.
```

```text
Make a dialogue stem export at the broadcaster's loudness target in WAV
for the sound mixer, with every audio effect on, and keep the originals
muted in the project.
```

## When to use something else

invideo exports a stereo mix. For a 5.1 or Dolby Atmos mix, export the dialogue as WAV with `export` mode `audio`, or the project with `format` `premiere` or `davinci`, and mix in a DAW such as Pro Tools or the Fairlight page in DaVinci Resolve.

For heavy repair, like a voice under a loud generator, use a repair tool such as iZotope RX, then bring the result back in with `add_media`.

## Related

- [How can I make uneven dialogue levels more consistent?](/guides/how-can-i-make-uneven-dialogue-levels-more-consistent)
- [How can I use EQ to reduce muddy or harsh dialogue?](/guides/how-can-i-use-eq-to-reduce-muddy-or-harsh-dialogue)
- [How do I reduce harsh s sounds in dialogue?](/guides/how-do-i-reduce-harsh-s-sounds-in-dialogue)
- [When to use a limiter rather than a compressor](/guides/when-should-i-use-a-limiter-rather-than-a-compressor)
- [Use Claude Code as your film editor on an invideo timeline](/how-to/film/claude-code-as-film-editor)
- [Check your video before you say it is done](/how-to/check-your-video)