Madow Inputs ๐๏ธ
Every ACE-Step dial in one node โ and a record of exactly what ran
- madow
- file_path
- context
- validation
You're three renders into an ACE-Step session and you've already lost track of which cfg, which seed, which lyrics produced the take you actually liked. That's the exact problem Madow Inputs exists to kill. It's the parameter-hub node from NovaFemme's Nova Audio Player pack: every ACE-Step generation parameter in one node, with named presets, warn-only validation, and a context output that records precisely what produced a take.
Here's the context that makes it click. ACE-Step is the open local music model - genuinely good instrumentals on a modest card, weak vocals, the thing the community treats as the local Suno. But running it in ComfyUI means babysitting a whole constellation: a sampler, a text encoder, an empty-latent node, an APG sampler node, a sampling-model helper. Parameters that belong together live apart, and nothing downstream knows what actually ran. Madow Inputs collects the loose change: 27 parameters, namespaced so the two cfg-shaped ones can't collide - ksampler.cfg (the sampler's) versus text.cfg_scale (the text encoder's).
How it works
The widgets are grouped on the node - APG, Sampler, Text, File - but the clever part is what the node emits beyond the values. Four outputs: madow, file_path, context, and validation.
The one you'll care about if you're logging runs is context. It's a JSON-ish blob carrying the exact parameters, plus two SHA-256 hashes: one seed-excluded (groups runs that differ only by seed - that's your seed-noise-floor question answered from a log) and one seed-included (did I already run this exact config?). The naming fields are deliberately kept out of both hashes, so renaming a file never splits identical renders into different groups. Wire context into the Nova Player node's optional context input and every measured take records what produced it. That's the whole point of the pack: listen to a generation and know, not guess, what made it.
Presets load as one JSON file each from presets/, so they're shareable and hand-editable. Loading one writes the real widgets - the backend never substitutes values, which means a saved workflow records what actually ran, not a preset name. validation is a text output of cross-field checks that warn rather than block: a caption saying "98 BPM" against a bpm widget of 122, vocals without lyrics, a duration that disagrees with the latent you wired in, apg.eta above 1. Warnings also print to your console, because a conflict you don't see on the node body is a conflict that costs a render.
The inputs that matter
You will not touch all 27. The ones a beginner actually sets:
caption_promptandcaption_lyrics- multiline text; the actual song spec.music_bpm,music_duration,music_timesignature,music_language,music_keyscale- the musical frame. The last three are ACE-Step's own combo domains, read live from ACE-Step's text-encode node when it's installed, so they connect without coercion.ksampler_steps,ksampler_cfg,ksampler_seed,ksampler_sampler_name,ksampler_scheduler- the generation core, defaults already sensible for ACE-Step (er_sde,linear_quadratic, 80 steps, cfg 2.8).- The optional
latent_secondsinput: wire inEmptyAceStepLatentAudio's seconds here and Madow checks it againstmusic_durationfor you.
The APG group (apg_eta, apg_norm_threshold, apg_momentum) belongs to the APG sampler node and shift to the sampling-model helper - leave them at defaults until you know why you're changing them. One aside: the player's "APG meter" is a different APG entirely (it measures artifacts). Same acronym, zero relationship, and yes, that's confusing.
Install
It's part of ComfyUI-NovaAudioPlayer, so you get the whole pack. ComfyUI Manager โ search "Nova Audio", or:
cd ComfyUI/custom_nodes
git clone https://github.com/NovaFemme/ComfyUI-NovaAudioPlayer.git
Then restart ComfyUI. No extra Python dependencies - nothing beyond what ComfyUI ships (scipy is only used for accurate LUFS in the player and degrades gracefully if missing). You do need the ACE-Step custom nodes installed for the actual music generation; this node is the control panel, not the engine.
Where people trip
The big one: this node doesn't generate anything. If you grab it without ACE-Step wired up, you get a very tidy dashboard and silence. Also worth knowing - the time-signature/language/key-scale dropdowns fall back to fixed lists when ACE-Step's encode node isn't present, which is fine until you try to connect them to nothing. And the hashes and presets only pay for themselves if you actually log context through the player or your own logger. Use it alone as a tidy parameter panel if you like; just know the provenance machinery is the headline, and it needs a downstream log to earn its keep.
Inputs (29)
| Name | Type | Default | Description |
|---|---|---|---|
| apg_eta | FLOAT | 0.45-10โ10 | APG: how much of the guidance that runs parallel to the prediction is kept. 0 removes it; above 1.0 amplifies it, and a warning is raised. |
| apg_norm_threshold | FLOAT | 4.000โ100 | APG: caps the size of the guidance update. 0 turns the cap off. |
| apg_momentum | FLOAT | 0.20-5โ5 | APG: running average applied to the guidance from step to step. Negative values damp it. |
| sched_shift | FLOAT | 3.000โ100 | Shift of the noise schedule. Higher spends more of the steps at high noise. |
| ksampler_steps | INT | 801โ10000 | Number of sampling steps. |
| ksampler_cfg | FLOAT | 2.800โ100 | Guidance scale of the sampler. Not the same parameter as text_cfg_scale. |
| ksampler_sampler_name | COMBO | er_sde | The sampling algorithm. |
| ksampler_scheduler | COMBO | linear_quadratic | How the noise levels are spaced across the steps. |
| ksampler_denoise | FLOAT | 1.000โ1 | How much of the latent is re-generated. 1.0 is a full generation. |
| ksampler_seed | INT | 00โ18446744073709550000 | The random seed. Set the control below it to fixed to reproduce a take, or randomize to sweep. context records the seed the run used. |
| caption_prompt | STRING | The caption: genre, instruments, voice, mood. A BPM or a key written here is checked against the bpm and keyscale widgets. | |
| caption_lyrics | STRING | The lyrics, with section tags such as [verse] and [chorus]. Leave empty for an instrumental. | |
| music_bpm | INT | 1201โ400 | Tempo in beats per minute. |
| music_duration | FLOAT | 120.01โ3600 | Length of the track in seconds. Checked against latent_seconds when that is wired. |
| music_timesignature | COMBO | 4 | Beats per bar, as the text encoder expects it. |
| music_language | COMBO | en | Language of the lyrics, as the text encoder's language code. |
| music_keyscale | COMBO | E minor | Key and scale, e.g. E minor. |
| text_cfg_scale | FLOAT | 2.000โ100 | Guidance scale of the text encoder's language model, which writes the audio codes. A different stage from the sampler's cfg. |
| lm_temperature | FLOAT | 0.720โ10 | Randomness of the language model. Lower is more predictable. |
| lm_top_p | FLOAT | 0.900โ1 | Nucleus sampling: keep the most likely tokens up to this total probability. 1.0 turns it off. |
| lm_top_k | INT | 00โ10000 | Keep only the k most likely tokens. 0 turns it off. Use one truncation method at a time. |
| lm_min_p | FLOAT | 0.000โ1 | Drop tokens less likely than this share of the top token. 0 turns it off. Use one truncation method at a time. |
| lm_generate_audio_codes | BOOLEAN | true | On: the language model writes audio codes for the sampler to follow. Off: that stage is skipped. |
| file_prefix | STRING | First part of the file name. file_path is assembled as folder/prefix<separator>name. | |
| file_name | STRING | Last part of the file name. | |
| file_folder | STRING | Folder part of file_path. Empty leaves it out. | |
| file_separator | STRING | _ | Text placed between prefix and name. |
| preset_nameopt | STRING | Set by the preset bar. Recorded in context so a run can be traced to the preset it came from; never used to supply values. | |
| latent_secondsopt | FLOAT | 0.000โ3600 | Optional. Wire EmptyAceStepLatentAudio's seconds here to check it against duration. |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| madow | MADOW | โ |
| file_path | STRING | โ |
| context | STRING | โ |
| validation | STRING | โ |