> ## Documentation Index
> Fetch the complete documentation index at: https://typecast.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# C#/.NET

> Access the Typecast API with our official C# SDK.

The official C# library for the [Typecast API](https://typecast.ai). 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.

<CardGroup cols={2}>
  <Card title="Package" icon="box" href="https://www.nuget.org/packages/typecast-csharp">
    Typecast C# SDK on NuGet
  </Card>

  <Card title="Source Code" icon="github" href="https://github.com/neosapience/typecast-sdk/tree/main/typecast-csharp">
    Typecast C# SDK Source Code
  </Card>
</CardGroup>

## Prerequisites

### Installing .NET SDK

<Tabs>
  <Tab title="macOS">
    **Using Homebrew (Recommended)**

    ```bash theme={null}
    # 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 Installer**

    Download from [dotnet.microsoft.com/download](https://dotnet.microsoft.com/download) and run the `.pkg` installer.
  </Tab>

  <Tab title="Windows">
    **Using winget**

    ```powershell theme={null}
    winget install Microsoft.DotNet.SDK.8
    dotnet --version
    ```

    **Using Chocolatey**

    ```powershell theme={null}
    choco install dotnet-sdk
    dotnet --version
    ```

    Or download from [dotnet.microsoft.com/download](https://dotnet.microsoft.com/download).
  </Tab>

  <Tab title="Linux">
    ```bash theme={null}
    # Ubuntu/Debian
    wget https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/packages-microsoft-prod.deb
    sudo dpkg -i packages-microsoft-prod.deb
    sudo apt-get update
    sudo apt-get install -y dotnet-sdk-8.0

    dotnet --version
    ```
  </Tab>
</Tabs>

## Installation

<Tabs>
  <Tab title=".NET CLI">
    ```bash theme={null}
    dotnet add package typecast-csharp
    ```
  </Tab>

  <Tab title="Package Manager">
    ```powershell theme={null}
    Install-Package typecast-csharp
    ```
  </Tab>

  <Tab title="Unity (NuGetForUnity)">
    1. Install [NuGetForUnity](https://github.com/GlitchEnzo/NuGetForUnity):
       * Open Package Manager (Window > Package Manager)
       * Click "+" > "Add package from git URL"
       * Enter: `https://github.com/GlitchEnzo/NuGetForUnity.git?path=/src/NuGetForUnity`

    2. Open NuGet window (NuGet > Manage NuGet Packages)

    3. Search for "typecast-csharp" and install
  </Tab>
</Tabs>

<Warning>
  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.
</Warning>

## Quick Start

```csharp theme={null}
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`.

```csharp theme={null}
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:

```csharp theme={null}
// 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);
```

<Info>
  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.
</Info>

```csharp Proxy without API key theme={null}
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**.

<Tabs>
  <Tab title="Smart Mode">
    Let the AI infer emotion from context:

    ```csharp theme={null}
    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);
    ```
  </Tab>

  <Tab title="Preset Mode">
    Explicitly set emotion with preset values:

    ```csharp theme={null}
    var request = new TTSRequest("I am so excited to show you these features!", voiceId, TTSModel.SsfmV30)
    {
        Language = LanguageCode.English,
        Prompt = new PresetPrompt(
            emotionPreset: EmotionPreset.Happy,
            emotionIntensity: 1.5  // Range: 0.0 to 2.0
        )
    };

    var response = await client.TextToSpeechAsync(request);
    ```
  </Tab>
</Tabs>

### Audio Customization

Control loudness, pitch, tempo, and output format:

```csharp theme={null}
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](https://typecast.ai/developers/api/voices) page.

```csharp theme={null}
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.

```csharp theme={null}
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.

```csharp theme={null}
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:

```csharp theme={null}
// 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:

```csharp theme={null}
// 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

```csharp theme={null}
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

```csharp theme={null}
// 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

```razor theme={null}
@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:

```csharp theme={null}
// 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)
}
```

<Note>
  **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.
</Note>

## 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

```csharp theme={null}
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.

```csharp theme={null}
// 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

```csharp theme={null}
await File.WriteAllTextAsync("output.srt", result.ToSrt(), Encoding.UTF8);
await File.WriteAllTextAsync("output.vtt", result.ToVtt(), Encoding.UTF8);
```

<Note>
  **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.
</Note>

## Instant Voice Cloning

Clone a custom voice from a short audio sample, then pass the returned `uc_` voice ID directly to TTS.

```csharp theme={null}
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);
```

<Warning>
  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**.
</Warning>

## Supported Languages

The SDK supports 37 languages with automatic language detection:

| Code  | Language  | Code  | Language  | Code  | Language   |
| ----- | --------- | ----- | --------- | ----- | ---------- |
| `eng` | English   | `jpn` | Japanese  | `ukr` | Ukrainian  |
| `kor` | Korean    | `ell` | Greek     | `ind` | Indonesian |
| `spa` | Spanish   | `tam` | Tamil     | `dan` | Danish     |
| `deu` | German    | `tgl` | Tagalog   | `swe` | Swedish    |
| `fra` | French    | `fin` | Finnish   | `msa` | Malay      |
| `ita` | Italian   | `zho` | Chinese   | `ces` | Czech      |
| `pol` | Polish    | `slk` | Slovak    | `por` | Portuguese |
| `nld` | Dutch     | `ara` | Arabic    | `bul` | Bulgarian  |
| `rus` | Russian   | `hrv` | Croatian  | `ron` | Romanian   |
| `ben` | Bengali   | `hin` | Hindi     | `hun` | Hungarian  |
| `nan` | Hokkien   | `nor` | Norwegian | `pan` | Punjabi    |
| `tha` | Thai      | `tur` | Turkish   | `vie` | Vietnamese |
| `yue` | Cantonese |       |           |       |            |

<Info>
  If not specified, the language will be automatically detected from the input text.
</Info>

## Error Handling

The SDK provides specific exception types for handling API errors:

```csharp theme={null}
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:

```csharp theme={null}
// 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

```csharp theme={null}
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
```
