arkennemasis fal · MiniMax Speech 2.6 Turbo · $0.06/1k chars
Pause Markers and Normalization for 6 Cents per 1,000 Characters
- audio
- audio_path
- duration_ms
- info
The 2.6 feature set at the Turbo price. Six cents per 1,000 characters, prompt instead of text, <#x#> pause markers, the loudness normalization block, and a 10,000-character budget. If you produce a lot of narration and you're not chasing the last 4 cents of fidelity, this is the node that should be doing most of your work.
What it is
The pack's node over fal's minimax/speech-2.6-turbo. MiniMax's voice line is the piece of their catalogue they benchmark head-on against ElevenLabs, and the honest reason to route narration through a paid API at all is the same one the KB keeps landing on: local TTS - Chatterbox, Kokoro - is excellent in English and shakier across many languages, and production work doesn't always get to be in English. Turbo is the volume tier: same inputs, same voices, a little less polish than HD.
How it works
FAL_KEY from the .env beside your launcher; validate; estimate the cost from the character count and compare it to max_cost_usd; submit one billed request; poll with a live status on the node; download to output/fal/fal-ai_minimax_speech-2.6-turbo/. There are no uploads in a TTS run, so a rejected input is a non-event. Every request is logged, and results are saved where you expect.
Inputs
prompt- the script. 1 to 10,000 characters, and it accepts pauses written as<#x#>, x being seconds from 0.01 to 99.99, placed between speakable segments and never twice in a row. This is the whole bill: 1,000 characters is roughly 180 English words.voice_setting_voice_id- free text, defaultWise_Woman, from MiniMax's predefined voices. Empty leaves it to the model. Not a clone slot - that's a separate node family in this pack.voice_setting_emotion-(not set),happy,sad,angry,fearful,disgusted,surprised,neutral.language_boost- set it explicitly (the list runs to a few dozen languages plusauto). Mismatched language hints are the usual cause of a read that sounds like it's guessing.voice_setting_speed(0.5–2.0),voice_setting_pitch(−12 to 12),voice_setting_vol(0.01–10),voice_setting_english_normalization(off by default; turn it on for script with numbers, units and abbreviations).- Loudness:
normalization_setting_enabled(on by default),normalization_setting_target_loudness(−18 LUFS default, −70 to −10),normalization_setting_target_range(8 LU default),normalization_setting_target_peak(−0.5 dBTP default). - Output:
audio_setting_format(mp3,pcm,flac),audio_setting_bitrate(32k–256k),audio_setting_sample_rate(8k–44.1k),audio_setting_channel(1 mono, 2 stereo),pronunciation_dict(JSON text replacements for the names it keeps mangling),output_format(urlorhex; keep the default).
Optional: max_cost_usd (default $20; the run stops before sending if the estimate is above it, 0 = no cap), max_concurrent (default 1 - one paid fal call at a time in the run), reuse_identical_run (default on - identical inputs return the already-paid file, restart included), extra_json (raw JSON merged into fal's request last, for fields without a box).
Outputs: audio (a real waveform with a player on the node), audio_path, duration_ms (real read length - hand it to Narration Length to size shots, or Word Timings to place captions), info (request id, estimate, saved files, fal's answer).
Install
cd ComfyUI/custom_nodes
git clone https://github.com/Hishamahmer/comfyui-arkennemasis
pip install httpx
Or ComfyUI Manager → Install via Git URL. Then, next to run_nvidia_gpu.bat:
FAL_KEY=your-key-from-fal.ai/dashboard/keys
Restart and you'll find it under arkennemasis/fal/Audio/MiniMax.
Notes
The normalization being on by default is the quiet win here. Twenty clips generated across an afternoon all land at the same loudness, which means your assembly doesn't need a level-matching pass per clip - and if you're feeding clips into the pack's Video Assemble, that's one fewer thing to fight.
Two habits: put the pauses in on the first pass rather than re-rendering to fix pacing, and don't expect the reuse logic to be invisible. Same text, same settings, and you get your earlier file back because the node refuses to charge you twice. Change one word and it's a fresh 6-cent generation.
Inputs (22)
| Name | Type | Default | Description |
|---|---|---|---|
| prompt | STRING | Text to convert to speech. Paragraph breaks should be marked with newline characters. **NOTE**: You can customize speech pauses by adding markers in the form `<#x#>`, where `x` is the pause duration in seconds. Valid range: `[0.01, 99.99]`, up to two decimal places. Pause markers must be placed between speakable text segments and cannot be used consecutively. | |
| 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). |
| 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. |