T
Telephony SOPKnowledge Base
Search
← All topics

Merlino Voice — Fish Audio Cloned Voice for Outbound TTS

runnable

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.

merlino-voicefish-audiottsvoice-cloneoutbound-voicesignalwire
Agent trigger phrases: Merlino voice · Mike Merlino cloned voice · branded TTS voice · agency voice clone · personal voice clone fish audio · Merlino TTS for calls

Merlino Voice

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.

For platform-level Fish Audio reference (auth, API surface, model selection), see Fish Audio TTS.

When to use Merlino Voice vs generic TTS

| Use case | Voice | |---|---| | Generic IVR ("press 1 for sales") | Generic ElevenLabs/Deepgram | | Mike's personal cold-call voicemail drop | Merlino Voice | | Agency podcast intro | Merlino Voice | | Client-specific AI receptionist | Custom voice per client | | Mike speaking at an event (recorded TTS) | Merlino Voice | | Mass automated alerts | Generic TTS (cheaper, more neutral) |

Cloned voice carries a personal-brand signature. Use sparingly — overuse dilutes the "this is from Mike personally" effect.

Configuration

| Parameter | Value | |---|---| | Voice ID | (Fish Audio model ID — kept in D:/Ecosystem/secrets/MASTER_API_KEYS.env) | | Default speed | 1.0 | | Default energy | 0.7 | | Default chunk length | 200 | | Format | mp3 (16-bit) for general use, wav for SignalWire play, opus for streaming |

API key lives at FISH_AUDIO_API_KEY in the secrets file.

Generation example

import os
import requests

FISH_API = "https://api.fish.audio/v1/tts"
FISH_KEY = os.environ["FISH_AUDIO_API_KEY"]
MERLINO_VOICE_ID = os.environ["MERLINO_VOICE_ID"]

def generate_merlino_audio(text, output_path, format="mp3", speed=1.0, energy=0.7):
    response = requests.post(
        FISH_API,
        headers={
            "Authorization": f"Bearer {FISH_KEY}",
            "Content-Type": "application/json",
        },
        json={
            "text": text,
            "reference_id": MERLINO_VOICE_ID,
            "format": format,
            "mp3_bitrate": 128,
            "chunk_length": 200,
            "normalize": True,
            "latency": "balanced",  # or "normal" for higher quality, slower
        }
    )
    response.raise_for_status()
    with open(output_path, "wb") as f:
        f.write(response.content)
    return output_path

Typical generation time: 800ms - 2s for short utterances under 200 characters, 3-8s for paragraph-length text.

SignalWire integration via play

For SWML scripts that need a Merlino-voiced introduction or message, pre-generate the audio and host it, then reference via the SWML play verb:

version: 1.0.0
sections:
  main:
    - answer: {}
    - play:
        url: https://cdn.merlinoai.com/voice/intro-mike-v3.mp3
    - connect:
        to: sip:agent@pbx.merlinoai.com

Pre-generating is better than on-the-fly generation inside the call because:

  • Eliminates Fish Audio API latency from the call path
  • Allows audio quality tuning (multiple takes, normalization)
  • CDN delivery is faster than re-rendering

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.

Voicemail drop with Merlino Voice

A signature use case. Mike's personal-sounding voicemail beats generic dialer voicemails.

# voicemail-drop-merlino.yaml
version: 1.0.0
sections:
  main:
    - answer:
        answer_on: machine_end_beep
    - play:
        url: https://cdn.merlinoai.com/voice/cold-drop-v7.mp3
    - hangup: {}

Outbound call with AMD targeting voicemail:

client.calls.create(
    to=lead.phone,
    from_=OUTBOUND_DID,
    url="https://your.api/voicemail-drop-merlino.xml",
    machine_detection="DetectMessageEnd",
)

See 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.

Generation patterns

Pattern 1: Pre-render variations to CDN

Common patterns rendered ahead of time and uploaded to CDN:

texts=(
    "intro-mike-v1:Hey, this is Mike Merlino. Just calling about your business."
    "intro-mike-v2:Hi, it's Mike at Merlino AI. Quick question for you."
    "vmdrop-mike-v1:Hey, Mike Merlino here. Missed you — give me a call back when you have a sec."
)

for entry in "${texts[@]}"; do
    name="${entry%%:*}"
    text="${entry#*:}"
    python generate.py --text "$text" --out "/tmp/$name.mp3"
    aws s3 cp "/tmp/$name.mp3" "s3://cdn-merlinoai/voice/$name.mp3" --acl public-read
done

Pattern 2: Personalized per-recipient render

When the message needs to address the recipient by name:

def generate_personalized(recipient_first_name, output_path):
    text = f"Hey {recipient_first_name}, it's Mike. Got a sec to talk?"
    return generate_merlino_audio(text, output_path)

Cache renders by text-content hash to avoid re-generating identical messages.

Pattern 3: Live during-call generation (advanced)

For dynamic content during an active call, use the AI verb with Fish Audio configured as the TTS provider:

- ai:
    prompt:
      text: "You are Mike Merlino, agency owner. Be friendly and direct."
    languages:
      - name: English (Merlino)
        code: en
        voice: fishaudio.${MERLINO_VOICE_ID}
        engine: fishaudio
    SWAIG:
      functions: []

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.

Quality tuning

| Issue | Cause | Fix | |---|---|---| | Robotic cadence | chunk_length too short | Increase to 200-300 | | Word emphasis wrong | Missing punctuation hints | Add commas, em-dashes for natural pauses | | 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" | | Sibilance harsh | Source recording had it | De-ess with ffmpeg -af "highshelf=f=6000:g=-3" | | Mismatched pitch across renders | Energy/speed varied between sessions | Lock parameters in a single config |

Audio post-processing for telephony

Phone networks downsample to 8 kHz. To make Merlino Voice sound consistent over phone:

# Render at 24 kHz
fish_audio_render --voice $MERLINO_ID --text "..." --format wav -o raw.wav

# Process for telephony
ffmpeg -i raw.wav \
    -af "loudnorm=I=-16:LRA=11:TP=-1.5,highshelf=f=6000:g=-3" \
    -ar 8000 -ac 1 -acodec pcm_mulaw \
    telephony.wav

Result is 8 kHz mono mulaw, the exact format G.711 carriers use. Plays without resampling latency.

Cost

Fish Audio TTS pricing (as of 2025-11):

| Item | Cost | |---|---| | Per character | ~$0.000015 | | Per second of audio | ~$0.0008 | | Voice clone training (one-time) | $50-200 depending on tier | | Custom voice retention | Included in plan |

A 30-second cold-voicemail message: ~$0.025 per render. Cache aggressively.

Voice integrity guardrails

The Merlino Voice clone is a brand asset. Misuse damages the brand. Operational rules:

  1. Never use for impersonation — voice clones generating content "as Mike" without his approval is a hard no.
  2. Audit log every renderD:/Ecosystem/logs/merlino-voice-renders.log records every API call with text content and use case.
  3. Approved sequences only — production sequences using Merlino Voice are version-controlled in D:/Ecosystem/voice-scripts/.
  4. Time-bounded access — staff API key access to the Merlino voice ID has a clear approval chain.

Common pitfalls

  • Generating on-the-fly during calls — adds 2-5 second latency. Pre-render to CDN.
  • No normalization on phone audio — Merlino Voice generated at -23 LUFS sounds quiet on phone. Always loudnorm to -16 LUFS.
  • Calling Fish Audio from inside SWML directly — works but not always reliable. Pre-render or use the AI verb with Fish Audio engine.
  • Misusing for marketing voicemail without consent — see voicemail drop. TCPA is strict; cloned voice raises the stakes.
  • Voice drift over Fish Audio version updates — Fish Audio occasionally updates models. Periodically re-render reference samples and compare to ensure consistency.

Related patterns

References

  • Fish Audio API documentation
  • SignalWire SWML play verb
  • SignalWire AI verb language/voice configuration