AceStep 1.5 SFT Inpaint / Repaint
Fix one botched line without re-singing the whole track
- source
- reference_audio
- task
This is the one that makes ACE-Step feel like a DAW instead of a demo. Every generated track has a section that fluffs - a garbled word, a note that lands wrong, a bar where the drums stop making sense. Previously your options were reroll the whole thing and hope, or open it in an audio editor and pretend. Inpaint / Repaint regenerates a time range and leaves the rest of the file alone.
It's a task node, not an audio node: it produces a task object you branch into the rest of the graph. Source, region, and how much freedom the model gets - that's the whole input surface.
How it works
The internals are more careful than "mask and generate", and the difference is why the result doesn't sound stitched. The node resolves your second-based window onto the model's latent grid, builds a 64-channel chunk mask covering the edit region, and hands the sampler a source latent whose edit region has been replaced with the model's own encoded silence. During sampling it reinjects the noised source for a fraction of the steps - governed by the mode - blends the latent boundaries instead of cutting them, and finally splices the regenerated waveform back into the original outside the window with a short crossfade. It reads like an audio engineer's manual edit, and it behaves like one.
The repaint_mode is the freedom dial and is mapped to concrete numbers: conservative keeps source context through every step with a 0.05 s crossfade; aggressive uses none and hands the region over to the model immediately; balanced sits in between and scales the preservation ratio with repaint_strength (0 = maximum preservation, 1 = maximum freedom).
The inputs
source is the audio or latent to preserve outside the window. start_seconds defaults to 0 and end_seconds to -1, which means "to the end of the source" - set both if you're punching a hole in the middle. end_seconds must land after start_seconds, or the node raises rather than guessing.
repaint_mode and repaint_strength are next, and note the ordering trap: repaint_strength only does anything in balanced mode. It's ignored by conservative and aggressive, which are fixed profiles. If moving that slider changes nothing, that's why.
Optional reference_audio is an independent timbre/style reference for the regenerated region - useful when the singer in your source is a different singer than the one you want in the patch.
One output, task. Branch it to both TextEncode's task and Generate's task; the conditioning half is not optional, and it's the mistake that turns a repaint into a plain text2music generation. Native tasks pick up duration and batch size from the source, and audio-code generation is disabled automatically. latent_or_audio must stay disconnected - it's mutually exclusive with a task.
Settings that matter
Prompt TextEncode for what you want in the window, not for the song. Paste the lyrics of that section. Base/SFT runs CFG 7; Turbo checkpoints want CFG 1, 8 steps, ODE and shift 3. And match durations: TextEncode's duration should follow the source (the pack's Audio Duration node gets you that number), or set Generate's duration to 0 to inherit.
One boundary detail worth internalising: the window is snapped to latent frames - one frame is 1920 samples at the VAE's rate, about 40 ms at 48 kHz - so sub-frame precision in start_seconds won't survive.
Install
Manager search ComfyUI-AceStep_SFT, or by hand:
cd ComfyUI/custom_nodes
git clone https://github.com/jeankassio/ComfyUI-AceStep_SFT.git
Install the requirements into the same Python that runs ComfyUI - transformers>=4.52.0, torchaudio, librosa, soundfile, numpy, pyyaml - and restart. You'll need acestep_v1.5_sft.safetensors (or the merged SFT+Turbo model), the Qwen text encoders and ace_1.5_vae.safetensors, plus a ComfyUI with native ACE-Step 1.5 support, since the task machinery rides on the core's ACE modules.
Where people get burned
Task connected to Generate only. TextEncode sees nothing, the native conditioning never arrives, and you've built a slow text2music node with extra steps.
A window that's too small. A 200 ms region on a 25 Hz latent grid is a couple of frames; there's almost no context for the model to work with. Give it musical boundaries - a line, a bar - rather than a precise millisecond range.
Expecting the same take with one word fixed. The region is regenerated, so everything inside it is new, including the instrumental under it. If you need surgical work on one vocal line with the backing intact, that's a stem-separation job feeding a repaint, not a repaint alone.
Conservative mode on a huge region. With start_seconds=0 and end_seconds=-1 in conservative mode the source is injected as context for every step across the whole track, giving you a subtle whole-song re-render rather than a no-op. Useful for a light pass; surprising if you expected the file back untouched.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| source | AUDIO,LATENT | Audio/latent to preserve outside the selected time range. | |
| start_seconds | FLOAT | 0.000–600 | Start of the region to regenerate. |
| end_seconds | FLOAT | -1.00-1–600 | End of the region to regenerate. -1 uses the end of the source. |
| repaint_mode | COMBO | balanced | Conservative preserves source context during more diffusion steps; aggressive allows more change. |
| repaint_strength | FLOAT | 0.500–1 | Balanced mode only: 0 = maximum preservation, 1 = maximum freedom. |
| reference_audioopt | AUDIO,LATENT | Optional independent timbre/style reference for the regenerated region. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| task | ACESTEP_SFT_TASK | — |