arkennemasis fal · MiniMax Speech 2.8 Turbo · $0.06/1k chars
Narration at six cents a minute
- audio
- audio_path
- duration_ms
- info
If you're building anything with a voice-over in it - a narrated short, an explainer, a talking head - the speech is the part you'll re-run fifty times as the script changes. That's exactly why the price matters. MiniMax's Speech 2.8 Turbo bills at $0.06 per 1,000 characters on fal, and 1,000 characters is roughly 150 words, roughly a minute of talking. A three-minute narration costs about eighteen cents. You can re-roll the script all afternoon and never watch a meter.
This is a hosted node. Nothing here runs on your GPU, and MiniMax's whole voice line is closed and API-first - Hailuo's TTS is the product they benchmark against ElevenLabs. That's the trade: zero VRAM, zero model download, but your text goes to fal and comes back as audio.
Why you'd route out for this one
The knowledge base's audio chapter lands on internal TTS is genuinely good now - Chatterbox, Kokoro, F5, and the pack's own local Qwen3-TTS node. Still, the API path keeps one job: production narration where a mispronunciation is expensive and you don't want to babysit a model. It also costs no VRAM, which matters when a 14B video model is sitting on your card.
How the node actually works
One submit to fal, one billed call. Before that: the node reads FAL_KEY from the .env in your ComfyUI install, estimates the cost from your prompt's character count, and stops cold if the estimate is over max_cost_usd (default $20 - yes, that's a lot of speech). Nothing is uploaded before the estimate passes, so a failure up to that point never bills. The finished audio lands in output/fal/fal-ai_minimax_speech-2.8-turbo/ and plays on the node.
There's no key box anywhere in this pack, on purpose - a key typed into a node gets saved into every workflow JSON you share.
The settings worth touching
The text box is the whole job, but it has two bits of syntax that surprise people. <#1.5#> inserts a pause of that many seconds (0.01–99.99), and interjection tags are performed rather than read: (laughs), (sighs), (coughs), (clears throat), (gasps), (sniffs), (groans), (yawns). On a short line, that's the difference between a robot and a person.
Then the handful that actually matter:
voice_setting_voice_id- a plain text string, defaultWise_Woman. Note string, not a combo: the pack's Voice Clone and Voice Design nodes returncustom_voice_idas a STRING, so you can wire one straight into the other.voice_setting_english_normalization- turn it on the moment your script contains$1,299, a date, or an acronym. Slight latency cost, far fewer "one thousand two hundred ninety nine dollars" style misses.language_boost- for anything non-English, say so. Left at(not set), the model guesses.voice_setting_emotion- happy / sad / angry / fearful / disgusted / surprised / neutral, or leave it to the model.audio_setting_*- mp3, 32 kHz, mono by default. Switch toflacand 44100 if this is going under music.normalization_setting_enabled- on by default at −18 LUFS with a −0.5 dBTP peak, which is exactly what you want when you're stacking narration against a music bed.
voice_modify_pitch / intensity / timbre (−100 to 100) are the "same person, angrier" knobs - shaping, not casting. And pronunciation_dict takes JSON text replacement for names the model keeps mangling.
Outputs
audio is a real ComfyUI AUDIO value with a player on the node - wire it into a sync node or a save node. audio_path is the same file as a string. duration_ms is the one people forget: it's how you size a shot before you spend on video. Wire it into the pack's Narration Length node and every clip outlasts its own voice-over.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/Hishamahmer/comfyui-arkennemasis
Restart ComfyUI. Or in ComfyUI-Manager, search arkennemasis (pack title comfyui-arkennemasis) and install from there. The pack's requirements.txt is just httpx, and that's for the Codex nodes - the fal provider talks to fal.ai with the standard library, so this path adds nothing to install.
Then put your key where the nodes look for it - a .env file next to run_nvidia_gpu.bat (or the ComfyUI folder):
FAL_KEY=your-key-from-fal.ai/dashboard/keys
Where people get burned
- The node does nothing, or 401s. The key isn't in the
.envthe pack reads. There's no key field on the node - that's deliberate, not an oversight. - Twenty fal nodes, one at a time.
max_concurrentdefaults to 1 across the whole run, so nodes sit at "waiting for its turn". Raise it on the nodes you want in parallel, up to 32. - It re-read your numbers as digits, or drifted into the wrong accent.
english_normalization,language_boost. - You paid twice for the same line. Don't:
reuse_identical_runis on by default and returns the same files for identical inputs without billing, even after a restart. Turn it off when you want a fresh take. - You want a different read, not a different voice. Change
voice_setting_emotionandvoice_modify_*before you go hunting for another voice ID.
Inputs (25)
| Name | Type | Default | Description |
|---|---|---|---|
| prompt | STRING | Text to convert to speech. Use `<#x#>` for pauses (x = 0.01-99.99 seconds). Supports interjection tags: `(laughs)`, `(sighs)`, `(coughs)`, `(clears throat)`, `(gasps)`, `(sniffs)`, `(groans)`, `(yawns)`. | |
| voice_setting_speed | FLOAT | 1.000.5–2 | Speech speed (0.5-2.0) |
| voice_setting_vol | FLOAT | 1.000.01–10 | Volume (0-10) |
| voice_setting_english_normalization | BOOLEAN | false | Enables English text normalization to improve number reading performance, with a slight increase in latency |
| voice_setting_pitch | INT | 0-12–12 | Voice pitch (-12 to 12) |
| voice_setting_emotion | COMBO | (not set) | Emotion of the generated speech '(not set)' leaves it to the model. |
| voice_setting_voice_id | STRING | Wise_Woman | Predefined voice ID to use for synthesis Empty leaves it out. |
| audio_setting_format | COMBO | mp3 | Audio format |
| audio_setting_bitrate | COMBO | 128000 | Bitrate of generated audio |
| audio_setting_sample_rate | COMBO | 32000 | Sample rate of generated audio |
| audio_setting_channel | COMBO | 1 | Number of audio channels (1=mono, 2=stereo) |
| language_boost | COMBO | (not set) | Enhance recognition of specified languages and dialects '(not set)' leaves it to the model. |
| output_format | COMBO | hex | Format of the output content (non-streaming only) |
| pronunciation_dict | STRING | Custom pronunciation dictionary for text replacement JSON. Empty leaves it out. | |
| normalization_setting_target_range | FLOAT | 8.000–20 | Target loudness range in LU (default 8.0) |
| normalization_setting_target_loudness | FLOAT | -18.00-70–-10 | Target loudness in LUFS (default -18.0) |
| normalization_setting_enabled | BOOLEAN | true | Enable loudness normalization for the audio |
| normalization_setting_target_peak | FLOAT | -0.50-3–0 | Target peak level in dBTP (default -0.5). |
| voice_modify_pitch | INT | 0-100–100 | Pitch adjustment in semitones. Range: -100 to 100. Positive values raise pitch, negative values lower it. |
| voice_modify_intensity | INT | 0-100–100 | Intensity/energy of the voice. Range: -100 to 100. Higher values create more energetic speech. |
| voice_modify_timbre | INT | 0-100–100 | Timbre adjustment. Range: -100 to 100. Affects the tonal quality of the voice. |
| max_cost_usdopt | FLOAT | 20.00–100000 | Safety cap. If the estimated cost of this run is above this many US dollars the node stops BEFORE sending anything to fal. 0 = no cap. |
| reuse_identical_runopt | BOOLEAN | true | If these exact inputs (the settings AND the same pictures/clips/audio) were already paid for and the files are still in output/fal, return them instead of paying again - also after a ComfyUI restart. Turn off for a fresh take with the same settings. |
| extra_jsonopt | STRING | Advanced: a JSON object merged into the request last, for any fal field this node has no box for. Example: {"seed": 7}. Leave empty normally. | |
| max_concurrentopt | INT | 11–32 | How many paid fal calls may run at the same time in one run, across every fal node. 1 (default) = one after another. This node starts its paid part only while fewer than this many fal calls are running. Once any fal node fails, the ones still waiting are not started, so nothing more is billed. |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| audio | AUDIO | — |
| audio_path | STRING | — |
| duration_ms | INT | — |
| info | STRING | JSON: request id, cost estimate, saved files and fal's full answer. |