Skip to main content
The official C# library for the Typecast API. Convert text to lifelike speech using AI-powered voices. Supports .NET Standard 2.0+, .NET 6+, Unity (via NuGetForUnity), and Blazor applications. Full async/await support with synchronous alternatives.

Package

Typecast C# SDK on NuGet

Source Code

Typecast C# SDK Source Code

Prerequisites

Installing .NET SDK

Using Homebrew (Recommended)
# Install .NET 8 SDK
brew install dotnet@8

# Add to PATH
export PATH="/opt/homebrew/opt/dotnet@8/bin:$PATH"

# Verify installation
dotnet --version
Using Official InstallerDownload from dotnet.microsoft.com/download and run the .pkg installer.

Installation

dotnet add package typecast-csharp
Latest registered version: 0.3.7 on NuGet. You can check with dotnet list package. Update with dotnet add package typecast-csharp to get the latest version.

Quick Start

using Typecast;
using Typecast.Models;

// Initialize client
using var client = new TypecastClient("YOUR_API_KEY");

// Convert text to speech
var request = new TTSRequest(
    text: "Hello there! I'm your friendly text-to-speech agent.",
    voiceId: "tc_672c5f5ce59fac2a48faeaee",
    model: TTSModel.SsfmV30
);

var response = await client.TextToSpeechAsync(request);

// Save audio file
await response.SaveToFileAsync("output.wav");
Console.WriteLine($"Audio saved! Duration: {response.Duration}s, Format: {response.Format}");

Features

The Typecast C# SDK provides powerful features for text-to-speech conversion:
  • Multiple Voice Models: Support for ssfm-v30 (latest) and ssfm-v21 AI voice models
  • Multi-language Support: 37 languages including English, Korean, Spanish, Japanese, Chinese, and more
  • Emotion Control: Preset emotions (normal, happy, sad, angry, whisper, toneup, tonedown) or smart context-aware inference
  • Audio Customization: Control loudness (LUFS -70 to 0), pitch (-12 to +12 semitones), tempo (0.5x to 2.0x), and format (WAV/MP3)
  • Voice Discovery: V2 Voices API with filtering by model, gender, age, and use cases
  • Instant Voice Cloning: Upload a WAV/MP3 sample and create a custom voice ID
  • Timestamp TTS: Word- and character-level alignment data for subtitles, karaoke, and lip-sync
  • Unity Support: Compatible with Unity via NuGetForUnity
  • Blazor Support: Works with Blazor Server and WebAssembly
  • Async/Sync APIs: Full async/await support with synchronous alternatives
  • Streaming: Real-time chunked audio delivery for low-latency playback

Voice Recommendations

Use RecommendVoicesAsync when you know the desired style but not the exact voice_id.
var voices = await client.RecommendVoicesAsync(
    "warm female voice for a product tutorial",
    count: 3
);

foreach (var voice in voices)
{
    Console.WriteLine($"{voice.VoiceId} {voice.VoiceName} {voice.Score}");
}
Recommendation results contain only VoiceId, VoiceName, and Score. Use GetVoiceV2Async or GetVoicesV2Async when you need detailed metadata such as supported models, emotions, gender, age, or use cases.

Configuration

Set your API key via environment variable or constructor:
// Using environment variable (TYPECAST_API_KEY)
using var client = new TypecastClient();

// Or pass directly
using var client = new TypecastClient("your-api-key-here");

// Or use configuration object
var config = new TypecastClientConfig
{
    ApiKey = "your-api-key-here",
    TimeoutSeconds = 60  // Optional, default: 30
};
using var client = new TypecastClient(config);
When requests go through your own proxy, set ApiHost to the proxy endpoint and omit ApiKey. The SDK will not send the X-API-KEY header for empty or missing keys. Requests to the default Typecast host still require an API key.
Proxy without API key
var config = new TypecastClientConfig
{
    ApiHost = "https://your-proxy.example.com"
};
using var client = new TypecastClient(config);

Advanced Usage

Emotion Control (ssfm-v30)

ssfm-v30 offers two emotion control modes: Preset and Smart.
Let the AI infer emotion from context:
var request = new TTSRequest("Everything is going to be okay.", voiceId, TTSModel.SsfmV30)
{
    Language = LanguageCode.English,
    Prompt = new SmartPrompt(
        previousText: "I just got the best news!",
        nextText: "I can't wait to celebrate!"
    )
};

var response = await client.TextToSpeechAsync(request);

Audio Customization

Control loudness, pitch, tempo, and output format:
var request = new TTSRequest("Customized audio output!", voiceId, TTSModel.SsfmV30)
{
    Language = LanguageCode.English,
    Output = new Output(
        targetLufs: -14.0,          // Range: -70 to 0 (LUFS)
        audioPitch: 2,            // Range: -12 to +12 semitones
        audioTempo: 1.2,          // Range: 0.5x to 2.0x
        audioFormat: AudioFormat.Mp3  // Options: Wav, Mp3
    ),
    Seed = 42  // For reproducible results
};

var response = await client.TextToSpeechAsync(request);
await response.SaveToFileAsync($"output{response.FileExtension}");
Console.WriteLine($"Duration: {response.Duration}s, Format: {response.Format}");

Generate audio to a file

Use GenerateToFileAsync when you want the SDK to synthesize speech and write the audio bytes directly to a local file. The model defaults to SsfmV30, and .mp3 / .wav extensions infer the output format when Output.AudioFormat is not set. Browse available voice IDs on the Voices page.
await client.GenerateToFileAsync("output.mp3", new GenerateToFileRequest
{
    Text = "Hello from Typecast.",
    VoiceId = "tc_672c5f5ce59fac2a48faeaee" // Find voice IDs at https://typecast.ai/developers/api/voices
});

Text pauses

Use text pause markup when you only need silent gaps inside one composed text segment. Put <|5s|>, <|1s|>, <|0.3s|>, or <|0.34413s|> directly in the text. The value is interpreted as seconds and must end with s. This keeps the pause expression visible in plain text without adding separate pause calls.
var audio = await client.ComposeSpeech()
    .Defaults(new ComposerSettings { VoiceId = "tc_672c5f5ce59fac2a48faeaee", Model = TTSModel.SsfmV30 })
    .Say("Hello<|5s|>Nice to meet you<|1s|>Today<|2s|>how does the weather feel?")
    .GenerateAsync();

Multi-speaker composition

Use the composer chaining API when one output file needs different voices or per-segment options such as pitch, tempo, prompt, or seed. The composer generates each segment as WAV, trims leading/trailing silent PCM samples, and concatenates the result. If you need MP3, generate WAV first and convert it in your app or server pipeline.
using Typecast;
using Typecast.Models;

using var client = new TypecastClient("YOUR_API_KEY");

var audio = await client.ComposeSpeech()
    .Defaults(new ComposerSettings { VoiceId = "tc_672c5f5ce59fac2a48faeaee", Model = TTSModel.SsfmV30 })
    .Say("Hello there")
    .Pause(5)
    .Say("Nice to meet you", new ComposerSettings { VoiceId = "tc_60e5426de8b95f1d3000d7b5", Output = new Output(audioPitch: 2) })
    .Say("Today")
    .Pause(2)
    .Say("How does the weather feel?")
    .GenerateAsync();

await audio.SaveToFileAsync("conversation.wav");

Voice Discovery (V2 API)

List and filter available voices with enhanced metadata:
// Get all voices
var voices = await client.GetVoicesV2Async();

// Filter by criteria
var filtered = await client.GetVoicesV2Async(new VoicesV2Filter
{
    Model = TTSModel.SsfmV30,
    Gender = GenderEnum.Female,
    Age = AgeEnum.YoungAdult
});

// Display voice info
foreach (var voice in voices)
{
    Console.WriteLine($"ID: {voice.VoiceId}, Name: {voice.VoiceName}");
    Console.WriteLine($"Gender: {voice.Gender}, Age: {voice.Age}");
    Console.WriteLine($"Models: {string.Join(", ", voice.Models.Select(m => m.Version))}");
    Console.WriteLine($"Use cases: {string.Join(", ", voice.UseCases ?? new List<string>())}");
}

Multilingual Content

The SDK supports 37 languages with automatic language detection:
// Auto-detect language (recommended)
var request = new TTSRequest("こんにちは。お元気ですか。", voiceId, TTSModel.SsfmV30);
var response = await client.TextToSpeechAsync(request);

// Or specify language explicitly
var koreanRequest = new TTSRequest("안녕하세요. 반갑습니다.", voiceId, TTSModel.SsfmV30)
{
    Language = LanguageCode.Korean  // ISO 639-3 language code
};

await response.SaveToFileAsync("output.wav");

Unity Integration

Basic Unity Example

using UnityEngine;
using Typecast;
using Typecast.Models;

public class TypecastTTS : MonoBehaviour
{
    private TypecastClient _client;
    private AudioSource _audioSource;

    void Start()
    {
        _client = new TypecastClient("your-api-key");
        _audioSource = GetComponent<AudioSource>();
    }

    public async void SpeakText(string text, string voiceId)
    {
        try
        {
            var request = new TTSRequest(text, voiceId, TTSModel.SsfmV30)
            {
                Language = LanguageCode.English,
                Output = new Output(audioFormat: AudioFormat.Wav)
            };

            var response = await _client.TextToSpeechAsync(request);
            
            // Convert to Unity AudioClip and play
            var audioClip = CreateAudioClipFromWav(response.AudioData);
            _audioSource.clip = audioClip;
            _audioSource.Play();
        }
        catch (TypecastException ex)
        {
            Debug.LogError($"TTS Error: {ex.Message}");
        }
    }

    void OnDestroy() => _client?.Dispose();
}

Blazor Integration

Blazor Server Example

// Program.cs
builder.Services.AddSingleton<TypecastClient>(sp => 
    new TypecastClient(builder.Configuration["Typecast:ApiKey"]));

// TTSService.cs
public class TTSService
{
    private readonly TypecastClient _client;

    public TTSService(TypecastClient client) => _client = client;

    public async Task<byte[]> SynthesizeAsync(string text, string voiceId)
    {
        var request = new TTSRequest(text, voiceId, TTSModel.SsfmV30)
        {
            Output = new Output(audioFormat: AudioFormat.Mp3)
        };
        
        var response = await _client.TextToSpeechAsync(request);
        return response.AudioData;
    }
}

Blazor Component

@inject TTSService TTSService
@inject IJSRuntime JSRuntime

<button @onclick="SynthesizeAsync" disabled="@IsProcessing">
    @(IsProcessing ? "Synthesizing..." : "Speak")
</button>

@code {
    private bool IsProcessing { get; set; }

    private async Task SynthesizeAsync()
    {
        IsProcessing = true;
        try
        {
            var audioData = await TTSService.SynthesizeAsync(Text, VoiceId);
            var base64Audio = Convert.ToBase64String(audioData);
            await JSRuntime.InvokeVoidAsync("playAudio", $"data:audio/mp3;base64,{base64Audio}");
        }
        finally { IsProcessing = false; }
    }
}

Streaming

Stream audio chunks in real-time for low-latency playback:
// Stream and extract raw PCM (skip 44-byte WAV header)
using var stream = await client.TextToSpeechStreamAsync(request);

var buffer = new byte[8192];
bool first = true;

while (true)
{
    int bytesRead = await stream.ReadAsync(buffer);
    if (bytesRead == 0) break;

    ReadOnlySpan<byte> pcm = buffer.AsSpan(0, bytesRead);
    if (first)
    {
        pcm = pcm[44..];  // Skip WAV header
        first = false;
    }
    // pcm is raw 16-bit mono PCM at 32000 Hz
    // Feed to your audio output (e.g. NAudio)
}
WAV streaming format: 32000 Hz, 16-bit, mono PCM. The first chunk includes a 44-byte WAV header (size = 0xFFFFFFFF); subsequent chunks are raw PCM only. For MP3: 320 kbps, 44100 Hz, each chunk is independently decodable.

Timestamp TTS

TextToSpeechWithTimestampsAsync() wraps POST /v1/text-to-speech/with-timestamps and returns the audio together with per-word and per-character alignment data — useful for karaoke highlights, subtitle generation, and lip-sync applications.

Basic Usage

using Typecast;
using Typecast.Models;

using var client = new TypecastClient("YOUR_API_KEY");

var request = new TTSRequestWithTimestamps(
    text: "Hello. How are you?",
    voiceId: "tc_60e5426de8b95f1d3000d7b5",
    model: TTSModel.SsfmV30
);

var result = await client.TextToSpeechWithTimestampsAsync(request);

await result.SaveToFileAsync("output.wav");
Console.WriteLine($"Duration: {result.AudioDuration}s");

foreach (var word in result.Words)
{
    Console.WriteLine($"  [{word.StartTime:F3}s – {word.EndTime:F3}s] {word.Text}");
}

Granularity

Set Granularity = Granularity.Word (default) or Granularity = Granularity.Char to control the alignment unit.
// Character-level alignment — required for Japanese / Chinese
var request = new TTSRequestWithTimestamps(
    text: "Hello. How are you?",
    voiceId: "tc_60e5426de8b95f1d3000d7b5",
    model: TTSModel.SsfmV30
)
{
    Granularity = Granularity.Char
};

Subtitle Export

await File.WriteAllTextAsync("output.srt", result.ToSrt(), Encoding.UTF8);
await File.WriteAllTextAsync("output.vtt", result.ToVtt(), Encoding.UTF8);
Japanese / Chinese: Word-level segmentation is not meaningful for languages without whitespace delimiters (jpn, zho). Use Granularity.Char for these languages to get character-level alignment.

Instant Voice Cloning

Clone a custom voice from a short audio sample, then pass the returned uc_ voice ID directly to TTS.
using Typecast;
using Typecast.Models;

using var client = new TypecastClient("YOUR_API_KEY");

CustomVoice voice = await client.CloneVoiceAsync(
    audioFile: "sample.wav",
    name: "My Voice",
    model: "ssfm-v30"
);

var request = new TTSRequest(
    text: "Hello from my cloned voice!",
    voiceId: voice.VoiceId,
    model: TTSModel.SsfmV30
);

var response = await client.TextToSpeechAsync(request);
await response.SaveToFileAsync("output.wav");
await client.DeleteVoiceAsync(voice.VoiceId);
Voice cloning audio must be 25 MB or smaller, the audio duration must be 5-150 seconds, and the custom voice name must be 1-30 characters.

Supported Languages

The SDK supports 37 languages with automatic language detection:
CodeLanguageCodeLanguageCodeLanguage
engEnglishjpnJapaneseukrUkrainian
korKoreanellGreekindIndonesian
spaSpanishtamTamildanDanish
deuGermantglTagalogsweSwedish
fraFrenchfinFinnishmsaMalay
itaItalianzhoChinesecesCzech
polPolishslkSlovakporPortuguese
nldDutcharaArabicbulBulgarian
rusRussianhrvCroatianronRomanian
benBengalihinHindihunHungarian
nanHokkiennorNorwegianpanPunjabi
thaThaiturTurkishvieVietnamese
yueCantonese
If not specified, the language will be automatically detected from the input text.

Error Handling

The SDK provides specific exception types for handling API errors:
using Typecast;
using Typecast.Exceptions;

try
{
    var response = await client.TextToSpeechAsync(request);
}
catch (UnauthorizedException)
{
    Console.WriteLine("Invalid or missing API key");
}
catch (PaymentRequiredException)
{
    Console.WriteLine("Insufficient credits");
}
catch (UnprocessableEntityException ex)
{
    Console.WriteLine($"Validation error: {ex.ResponseBody}");
}
catch (RateLimitException)
{
    Console.WriteLine("Rate limit exceeded - please retry later");
}
catch (TypecastException ex)
{
    Console.WriteLine($"API error ({ex.StatusCode}): {ex.Message}");
}

Synchronous API

For scenarios where async is not preferred, use synchronous methods:
// Synchronous text-to-speech
var response = client.TextToSpeech(request);
response.SaveToFile("output.wav");

// Synchronous voice listing
var voices = client.GetVoicesV2();
var voice = client.GetVoiceV2("voice_id");

Type Reference

using Typecast;
using Typecast.Models;
using Typecast.Exceptions;

// Main types
TypecastClient
TypecastClientConfig

// Request/Response types
TTSRequest
TTSResponse
VoiceV2Response
VoicesV2Filter

// Prompt types
Prompt
PresetPrompt
SmartPrompt
Output

// Enums
TTSModel       // SsfmV21, SsfmV30
LanguageCode   // English, Korean, Japanese, etc.
EmotionPreset  // Normal, Happy, Sad, Angry, Whisper, ToneUp, ToneDown
AudioFormat    // Wav, Mp3
GenderEnum     // Male, Female
AgeEnum        // Child, Teenager, YoungAdult, MiddleAge, Elder