{"slug":"merlino-voice","title":"Merlino Voice — Fish Audio Cloned Voice for Outbound TTS","tags":["merlino-voice","fish-audio","tts","voice-clone","outbound-voice","signalwire"],"agent_summary":"Merlino Voice is Mike's custom-cloned voice on Fish Audio used for branded outbound TTS — agent introductions, voicemail drops, IVR greetings, ringless drops. Distinct from generic Fish Audio TTS because the voice model is identity-locked. Voice ID, default parameters (speed 1.0, energy 0.7), audio formats (mp3 16-bit, opus, wav), and SignalWire integration via SWML play verb.","trigger_phrases":["Merlino voice","Mike Merlino cloned voice","branded TTS voice","agency voice clone","personal voice clone fish audio","Merlino TTS for calls"],"runnable":true,"markdown":"\n# Merlino Voice\n\nMerlino Voice is Mike Merlino's custom-cloned voice on Fish Audio. Distinct from generic Fish Audio TTS because the voice model is identity-locked — it sounds like Mike. Used for branded agency communications where personal touch matters: outbound voicemails, video intros, podcast intros, branded IVR greetings, sales agent self-introductions.\n\nFor platform-level Fish Audio reference (auth, API surface, model selection), see [Fish Audio TTS](/topic/fish-audio-tts).\n\n## When to use Merlino Voice vs generic TTS\n\n| Use case | Voice |\n|---|---|\n| Generic IVR (\"press 1 for sales\") | Generic ElevenLabs/Deepgram |\n| Mike's personal cold-call voicemail drop | Merlino Voice |\n| Agency podcast intro | Merlino Voice |\n| Client-specific AI receptionist | Custom voice per client |\n| Mike speaking at an event (recorded TTS) | Merlino Voice |\n| Mass automated alerts | Generic TTS (cheaper, more neutral) |\n\nCloned voice carries a personal-brand signature. Use sparingly — overuse dilutes the \"this is from Mike personally\" effect.\n\n## Configuration\n\n| Parameter | Value |\n|---|---|\n| Voice ID | (Fish Audio model ID — kept in `D:/Ecosystem/secrets/MASTER_API_KEYS.env`) |\n| Default speed | 1.0 |\n| Default energy | 0.7 |\n| Default chunk length | 200 |\n| Format | mp3 (16-bit) for general use, wav for SignalWire `play`, opus for streaming |\n\nAPI key lives at `FISH_AUDIO_API_KEY` in the secrets file.\n\n## Generation example\n\n```python\nimport os\nimport requests\n\nFISH_API = \"https://api.fish.audio/v1/tts\"\nFISH_KEY = os.environ[\"FISH_AUDIO_API_KEY\"]\nMERLINO_VOICE_ID = os.environ[\"MERLINO_VOICE_ID\"]\n\ndef generate_merlino_audio(text, output_path, format=\"mp3\", speed=1.0, energy=0.7):\n    response = requests.post(\n        FISH_API,\n        headers={\n            \"Authorization\": f\"Bearer {FISH_KEY}\",\n            \"Content-Type\": \"application/json\",\n        },\n        json={\n            \"text\": text,\n            \"reference_id\": MERLINO_VOICE_ID,\n            \"format\": format,\n            \"mp3_bitrate\": 128,\n            \"chunk_length\": 200,\n            \"normalize\": True,\n            \"latency\": \"balanced\",  # or \"normal\" for higher quality, slower\n        }\n    )\n    response.raise_for_status()\n    with open(output_path, \"wb\") as f:\n        f.write(response.content)\n    return output_path\n```\n\nTypical generation time: 800ms - 2s for short utterances under 200 characters, 3-8s for paragraph-length text.\n\n## SignalWire integration via `play`\n\nFor SWML scripts that need a Merlino-voiced introduction or message, pre-generate the audio and host it, then reference via the SWML `play` verb:\n\n```yaml\nversion: 1.0.0\nsections:\n  main:\n    - answer: {}\n    - play:\n        url: https://cdn.merlinoai.com/voice/intro-mike-v3.mp3\n    - connect:\n        to: sip:agent@pbx.merlinoai.com\n```\n\nPre-generating is better than on-the-fly generation inside the call because:\n\n- Eliminates Fish Audio API latency from the call path\n- Allows audio quality tuning (multiple takes, normalization)\n- CDN delivery is faster than re-rendering\n\nFor dynamic per-call content (using caller's name, etc.), use Fish Audio's WebSocket streaming endpoint and tap output directly into SignalWire — but this adds 1-2 seconds of perceived latency.\n\n## Voicemail drop with Merlino Voice\n\nA signature use case. Mike's personal-sounding voicemail beats generic dialer voicemails.\n\n```yaml\n# voicemail-drop-merlino.yaml\nversion: 1.0.0\nsections:\n  main:\n    - answer:\n        answer_on: machine_end_beep\n    - play:\n        url: https://cdn.merlinoai.com/voice/cold-drop-v7.mp3\n    - hangup: {}\n```\n\nOutbound call with AMD targeting voicemail:\n\n```python\nclient.calls.create(\n    to=lead.phone,\n    from_=OUTBOUND_DID,\n    url=\"https://your.api/voicemail-drop-merlino.xml\",\n    machine_detection=\"DetectMessageEnd\",\n)\n```\n\nSee [voicemail drop](/topic/voicemail-drop) for the full pattern. Cloned-voice voicemail drops require even tighter TCPA discipline because they're personal-sounding — the recipient assumes a real person and reacts more strongly when they discover it's pre-recorded.\n\n## Generation patterns\n\n### Pattern 1: Pre-render variations to CDN\n\nCommon patterns rendered ahead of time and uploaded to CDN:\n\n```bash\ntexts=(\n    \"intro-mike-v1:Hey, this is Mike Merlino. Just calling about your business.\"\n    \"intro-mike-v2:Hi, it's Mike at Merlino AI. Quick question for you.\"\n    \"vmdrop-mike-v1:Hey, Mike Merlino here. Missed you — give me a call back when you have a sec.\"\n)\n\nfor entry in \"${texts[@]}\"; do\n    name=\"${entry%%:*}\"\n    text=\"${entry#*:}\"\n    python generate.py --text \"$text\" --out \"/tmp/$name.mp3\"\n    aws s3 cp \"/tmp/$name.mp3\" \"s3://cdn-merlinoai/voice/$name.mp3\" --acl public-read\ndone\n```\n\n### Pattern 2: Personalized per-recipient render\n\nWhen the message needs to address the recipient by name:\n\n```python\ndef generate_personalized(recipient_first_name, output_path):\n    text = f\"Hey {recipient_first_name}, it's Mike. Got a sec to talk?\"\n    return generate_merlino_audio(text, output_path)\n```\n\nCache renders by text-content hash to avoid re-generating identical messages.\n\n### Pattern 3: Live during-call generation (advanced)\n\nFor dynamic content during an active call, use the AI verb with Fish Audio configured as the TTS provider:\n\n```yaml\n- ai:\n    prompt:\n      text: \"You are Mike Merlino, agency owner. Be friendly and direct.\"\n    languages:\n      - name: English (Merlino)\n        code: en\n        voice: fishaudio.${MERLINO_VOICE_ID}\n        engine: fishaudio\n    SWAIG:\n      functions: []\n```\n\nSignalWire's AI verb supports Fish Audio as a TTS engine. Latency is higher than ElevenLabs/Deepgram. Best when the personal voice signature is more important than perfect responsiveness.\n\n## Quality tuning\n\n| Issue | Cause | Fix |\n|---|---|---|\n| Robotic cadence | `chunk_length` too short | Increase to 200-300 |\n| Word emphasis wrong | Missing punctuation hints | Add commas, em-dashes for natural pauses |\n| Volume too low for phone playback | TTS output is line-level, phone expects -6 to -3 dB | Normalize with `ffmpeg -af \"loudnorm=I=-16:LRA=11:TP=-1.5\"` |\n| Sibilance harsh | Source recording had it | De-ess with `ffmpeg -af \"highshelf=f=6000:g=-3\"` |\n| Mismatched pitch across renders | Energy/speed varied between sessions | Lock parameters in a single config |\n\n## Audio post-processing for telephony\n\nPhone networks downsample to 8 kHz. To make Merlino Voice sound consistent over phone:\n\n```bash\n# Render at 24 kHz\nfish_audio_render --voice $MERLINO_ID --text \"...\" --format wav -o raw.wav\n\n# Process for telephony\nffmpeg -i raw.wav \\\n    -af \"loudnorm=I=-16:LRA=11:TP=-1.5,highshelf=f=6000:g=-3\" \\\n    -ar 8000 -ac 1 -acodec pcm_mulaw \\\n    telephony.wav\n```\n\nResult is 8 kHz mono mulaw, the exact format G.711 carriers use. Plays without resampling latency.\n\n## Cost\n\nFish Audio TTS pricing (as of 2025-11):\n\n| Item | Cost |\n|---|---|\n| Per character | ~$0.000015 |\n| Per second of audio | ~$0.0008 |\n| Voice clone training (one-time) | $50-200 depending on tier |\n| Custom voice retention | Included in plan |\n\nA 30-second cold-voicemail message: ~$0.025 per render. Cache aggressively.\n\n## Voice integrity guardrails\n\nThe Merlino Voice clone is a brand asset. Misuse damages the brand. Operational rules:\n\n1. **Never use for impersonation** — voice clones generating content \"as Mike\" without his approval is a hard no.\n2. **Audit log every render** — `D:/Ecosystem/logs/merlino-voice-renders.log` records every API call with text content and use case.\n3. **Approved sequences only** — production sequences using Merlino Voice are version-controlled in `D:/Ecosystem/voice-scripts/`.\n4. **Time-bounded access** — staff API key access to the Merlino voice ID has a clear approval chain.\n\n## Common pitfalls\n\n- **Generating on-the-fly during calls** — adds 2-5 second latency. Pre-render to CDN.\n- **No normalization on phone audio** — Merlino Voice generated at -23 LUFS sounds quiet on phone. Always loudnorm to -16 LUFS.\n- **Calling Fish Audio from inside SWML directly** — works but not always reliable. Pre-render or use the AI verb with Fish Audio engine.\n- **Misusing for marketing voicemail without consent** — see [voicemail drop](/topic/voicemail-drop). TCPA is strict; cloned voice raises the stakes.\n- **Voice drift over Fish Audio version updates** — Fish Audio occasionally updates models. Periodically re-render reference samples and compare to ensure consistency.\n\n## Related patterns\n\n- [Fish Audio TTS](/topic/fish-audio-tts) — generic Fish Audio API reference\n- [Voicemail drop](/topic/voicemail-drop) — pre-recorded outbound voicemail\n- [SignalWire AI receptionist](/topic/signalwire-ai-receptionist) — AI voice agent with custom TTS\n\n## References\n\n- Fish Audio API documentation\n- SignalWire SWML `play` verb\n- SignalWire AI verb language/voice configuration\n","html":"<h1>Merlino Voice</h1>\n<p>Merlino Voice is Mike Merlino's custom-cloned voice on Fish Audio. Distinct from generic Fish Audio TTS because the voice model is identity-locked — it sounds like Mike. Used for branded agency communications where personal touch matters: outbound voicemails, video intros, podcast intros, branded IVR greetings, sales agent self-introductions.</p>\n<p>For platform-level Fish Audio reference (auth, API surface, model selection), see <a href=\"/topic/fish-audio-tts\">Fish Audio TTS</a>.</p>\n<h2>When to use Merlino Voice vs generic TTS</h2>\n<p>| Use case | Voice |\n|---|---|\n| Generic IVR (\"press 1 for sales\") | Generic ElevenLabs/Deepgram |\n| Mike's personal cold-call voicemail drop | Merlino Voice |\n| Agency podcast intro | Merlino Voice |\n| Client-specific AI receptionist | Custom voice per client |\n| Mike speaking at an event (recorded TTS) | Merlino Voice |\n| Mass automated alerts | Generic TTS (cheaper, more neutral) |</p>\n<p>Cloned voice carries a personal-brand signature. Use sparingly — overuse dilutes the \"this is from Mike personally\" effect.</p>\n<h2>Configuration</h2>\n<p>| Parameter | Value |\n|---|---|\n| Voice ID | (Fish Audio model ID — kept in <code>D:/Ecosystem/secrets/MASTER_API_KEYS.env</code>) |\n| Default speed | 1.0 |\n| Default energy | 0.7 |\n| Default chunk length | 200 |\n| Format | mp3 (16-bit) for general use, wav for SignalWire <code>play</code>, opus for streaming |</p>\n<p>API key lives at <code>FISH_AUDIO_API_KEY</code> in the secrets file.</p>\n<h2>Generation example</h2>\n<pre><code class=\"language-python\">import os\nimport requests\n\nFISH_API = \"https://api.fish.audio/v1/tts\"\nFISH_KEY = os.environ[\"FISH_AUDIO_API_KEY\"]\nMERLINO_VOICE_ID = os.environ[\"MERLINO_VOICE_ID\"]\n\ndef generate_merlino_audio(text, output_path, format=\"mp3\", speed=1.0, energy=0.7):\n    response = requests.post(\n        FISH_API,\n        headers={\n            \"Authorization\": f\"Bearer {FISH_KEY}\",\n            \"Content-Type\": \"application/json\",\n        },\n        json={\n            \"text\": text,\n            \"reference_id\": MERLINO_VOICE_ID,\n            \"format\": format,\n            \"mp3_bitrate\": 128,\n            \"chunk_length\": 200,\n            \"normalize\": True,\n            \"latency\": \"balanced\",  # or \"normal\" for higher quality, slower\n        }\n    )\n    response.raise_for_status()\n    with open(output_path, \"wb\") as f:\n        f.write(response.content)\n    return output_path\n</code></pre>\n<p>Typical generation time: 800ms - 2s for short utterances under 200 characters, 3-8s for paragraph-length text.</p>\n<h2>SignalWire integration via <code>play</code></h2>\n<p>For SWML scripts that need a Merlino-voiced introduction or message, pre-generate the audio and host it, then reference via the SWML <code>play</code> verb:</p>\n<pre><code class=\"language-yaml\">version: 1.0.0\nsections:\n  main:\n    - answer: {}\n    - play:\n        url: https://cdn.merlinoai.com/voice/intro-mike-v3.mp3\n    - connect:\n        to: sip:agent@pbx.merlinoai.com\n</code></pre>\n<p>Pre-generating is better than on-the-fly generation inside the call because:</p>\n<ul>\n<li>Eliminates Fish Audio API latency from the call path</li>\n<li>Allows audio quality tuning (multiple takes, normalization)</li>\n<li>CDN delivery is faster than re-rendering</li>\n</ul>\n<p>For dynamic per-call content (using caller's name, etc.), use Fish Audio's WebSocket streaming endpoint and tap output directly into SignalWire — but this adds 1-2 seconds of perceived latency.</p>\n<h2>Voicemail drop with Merlino Voice</h2>\n<p>A signature use case. Mike's personal-sounding voicemail beats generic dialer voicemails.</p>\n<pre><code class=\"language-yaml\"># voicemail-drop-merlino.yaml\nversion: 1.0.0\nsections:\n  main:\n    - answer:\n        answer_on: machine_end_beep\n    - play:\n        url: https://cdn.merlinoai.com/voice/cold-drop-v7.mp3\n    - hangup: {}\n</code></pre>\n<p>Outbound call with AMD targeting voicemail:</p>\n<pre><code class=\"language-python\">client.calls.create(\n    to=lead.phone,\n    from_=OUTBOUND_DID,\n    url=\"https://your.api/voicemail-drop-merlino.xml\",\n    machine_detection=\"DetectMessageEnd\",\n)\n</code></pre>\n<p>See <a href=\"/topic/voicemail-drop\">voicemail drop</a> for the full pattern. Cloned-voice voicemail drops require even tighter TCPA discipline because they're personal-sounding — the recipient assumes a real person and reacts more strongly when they discover it's pre-recorded.</p>\n<h2>Generation patterns</h2>\n<h3>Pattern 1: Pre-render variations to CDN</h3>\n<p>Common patterns rendered ahead of time and uploaded to CDN:</p>\n<pre><code class=\"language-bash\">texts=(\n    \"intro-mike-v1:Hey, this is Mike Merlino. Just calling about your business.\"\n    \"intro-mike-v2:Hi, it's Mike at Merlino AI. Quick question for you.\"\n    \"vmdrop-mike-v1:Hey, Mike Merlino here. Missed you — give me a call back when you have a sec.\"\n)\n\nfor entry in \"${texts[@]}\"; do\n    name=\"${entry%%:*}\"\n    text=\"${entry#*:}\"\n    python generate.py --text \"$text\" --out \"/tmp/$name.mp3\"\n    aws s3 cp \"/tmp/$name.mp3\" \"s3://cdn-merlinoai/voice/$name.mp3\" --acl public-read\ndone\n</code></pre>\n<h3>Pattern 2: Personalized per-recipient render</h3>\n<p>When the message needs to address the recipient by name:</p>\n<pre><code class=\"language-python\">def generate_personalized(recipient_first_name, output_path):\n    text = f\"Hey {recipient_first_name}, it's Mike. Got a sec to talk?\"\n    return generate_merlino_audio(text, output_path)\n</code></pre>\n<p>Cache renders by text-content hash to avoid re-generating identical messages.</p>\n<h3>Pattern 3: Live during-call generation (advanced)</h3>\n<p>For dynamic content during an active call, use the AI verb with Fish Audio configured as the TTS provider:</p>\n<pre><code class=\"language-yaml\">- ai:\n    prompt:\n      text: \"You are Mike Merlino, agency owner. Be friendly and direct.\"\n    languages:\n      - name: English (Merlino)\n        code: en\n        voice: fishaudio.${MERLINO_VOICE_ID}\n        engine: fishaudio\n    SWAIG:\n      functions: []\n</code></pre>\n<p>SignalWire's AI verb supports Fish Audio as a TTS engine. Latency is higher than ElevenLabs/Deepgram. Best when the personal voice signature is more important than perfect responsiveness.</p>\n<h2>Quality tuning</h2>\n<p>| Issue | Cause | Fix |\n|---|---|---|\n| Robotic cadence | <code>chunk_length</code> too short | Increase to 200-300 |\n| Word emphasis wrong | Missing punctuation hints | Add commas, em-dashes for natural pauses |\n| Volume too low for phone playback | TTS output is line-level, phone expects -6 to -3 dB | Normalize with <code>ffmpeg -af \"loudnorm=I=-16:LRA=11:TP=-1.5\"</code> |\n| Sibilance harsh | Source recording had it | De-ess with <code>ffmpeg -af \"highshelf=f=6000:g=-3\"</code> |\n| Mismatched pitch across renders | Energy/speed varied between sessions | Lock parameters in a single config |</p>\n<h2>Audio post-processing for telephony</h2>\n<p>Phone networks downsample to 8 kHz. To make Merlino Voice sound consistent over phone:</p>\n<pre><code class=\"language-bash\"># Render at 24 kHz\nfish_audio_render --voice $MERLINO_ID --text \"...\" --format wav -o raw.wav\n\n# Process for telephony\nffmpeg -i raw.wav \\\n    -af \"loudnorm=I=-16:LRA=11:TP=-1.5,highshelf=f=6000:g=-3\" \\\n    -ar 8000 -ac 1 -acodec pcm_mulaw \\\n    telephony.wav\n</code></pre>\n<p>Result is 8 kHz mono mulaw, the exact format G.711 carriers use. Plays without resampling latency.</p>\n<h2>Cost</h2>\n<p>Fish Audio TTS pricing (as of 2025-11):</p>\n<p>| Item | Cost |\n|---|---|\n| Per character | ~$0.000015 |\n| Per second of audio | ~$0.0008 |\n| Voice clone training (one-time) | $50-200 depending on tier |\n| Custom voice retention | Included in plan |</p>\n<p>A 30-second cold-voicemail message: ~$0.025 per render. Cache aggressively.</p>\n<h2>Voice integrity guardrails</h2>\n<p>The Merlino Voice clone is a brand asset. Misuse damages the brand. Operational rules:</p>\n<ol>\n<li><strong>Never use for impersonation</strong> — voice clones generating content \"as Mike\" without his approval is a hard no.</li>\n<li><strong>Audit log every render</strong> — <code>D:/Ecosystem/logs/merlino-voice-renders.log</code> records every API call with text content and use case.</li>\n<li><strong>Approved sequences only</strong> — production sequences using Merlino Voice are version-controlled in <code>D:/Ecosystem/voice-scripts/</code>.</li>\n<li><strong>Time-bounded access</strong> — staff API key access to the Merlino voice ID has a clear approval chain.</li>\n</ol>\n<h2>Common pitfalls</h2>\n<ul>\n<li><strong>Generating on-the-fly during calls</strong> — adds 2-5 second latency. Pre-render to CDN.</li>\n<li><strong>No normalization on phone audio</strong> — Merlino Voice generated at -23 LUFS sounds quiet on phone. Always loudnorm to -16 LUFS.</li>\n<li><strong>Calling Fish Audio from inside SWML directly</strong> — works but not always reliable. Pre-render or use the AI verb with Fish Audio engine.</li>\n<li><strong>Misusing for marketing voicemail without consent</strong> — see <a href=\"/topic/voicemail-drop\">voicemail drop</a>. TCPA is strict; cloned voice raises the stakes.</li>\n<li><strong>Voice drift over Fish Audio version updates</strong> — Fish Audio occasionally updates models. Periodically re-render reference samples and compare to ensure consistency.</li>\n</ul>\n<h2>Related patterns</h2>\n<ul>\n<li><a href=\"/topic/fish-audio-tts\">Fish Audio TTS</a> — generic Fish Audio API reference</li>\n<li><a href=\"/topic/voicemail-drop\">Voicemail drop</a> — pre-recorded outbound voicemail</li>\n<li><a href=\"/topic/signalwire-ai-receptionist\">SignalWire AI receptionist</a> — AI voice agent with custom TTS</li>\n</ul>\n<h2>References</h2>\n<ul>\n<li>Fish Audio API documentation</li>\n<li>SignalWire SWML <code>play</code> verb</li>\n<li>SignalWire AI verb language/voice configuration</li>\n</ul>\n"}