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

# Voices

> Browse and select TTS voices

RunAnywhere supports neural TTS voices via Piper and system voice fallback via `flutter_tts`.

## Piper Neural Voices

High-quality neural voices that run entirely on-device.

### English (US)

| Voice ID                         | Name     | Gender | Style          | Size   |
| -------------------------------- | -------- | ------ | -------------- | ------ |
| `vits-piper-en_US-lessac-medium` | Lessac   | Male   | Neutral        | \~50MB |
| `vits-piper-en_US-amy-medium`    | Amy      | Female | Neutral        | \~50MB |
| `vits-piper-en_US-ryan-medium`   | Ryan     | Male   | Conversational | \~50MB |
| `vits-piper-en_US-kathleen-low`  | Kathleen | Female | Soft           | \~20MB |

### English (UK)

| Voice ID                       | Name | Gender | Style    | Size   |
| ------------------------------ | ---- | ------ | -------- | ------ |
| `vits-piper-en_GB-alan-medium` | Alan | Male   | British  | \~50MB |
| `vits-piper-en_GB-alba-medium` | Alba | Female | Scottish | \~50MB |

### Other Languages

| Voice ID                           | Language | Gender | Size   |
| ---------------------------------- | -------- | ------ | ------ |
| `vits-piper-de_DE-thorsten-medium` | German   | Male   | \~50MB |
| `vits-piper-fr_FR-upmc-medium`     | French   | Male   | \~50MB |
| `vits-piper-es_ES-sharvard-medium` | Spanish  | Male   | \~50MB |
| `vits-piper-it_IT-riccardo-x_low`  | Italian  | Male   | \~20MB |
| `vits-piper-zh_CN-huayan-medium`   | Chinese  | Female | \~50MB |

## Registering Voices

```dart theme={null}
// US English - Lessac (recommended default)
Onnx.addModel(
  id: 'vits-piper-en_US-lessac-medium',
  name: 'Piper US English (Lessac)',
  url: 'https://github.com/RunanywhereAI/sherpa-onnx/releases/download/runanywhere-models-v1/vits-piper-en_US-lessac-medium.tar.gz',
  modality: ModelCategory.speechSynthesis,
);

// US English - Amy (female)
Onnx.addModel(
  id: 'vits-piper-en_US-amy-medium',
  name: 'Piper US English (Amy)',
  url: 'https://github.com/RunanywhereAI/sherpa-onnx/releases/download/runanywhere-models-v1/vits-piper-en_US-amy-medium.tar.gz',
  modality: ModelCategory.speechSynthesis,
);
```

## Switching Voices

```dart theme={null}
// Load default voice
await RunAnywhere.loadTTSVoice('vits-piper-en_US-lessac-medium');

// Switch to different voice
Future<void> switchVoice(String voiceId) async {
  await RunAnywhere.unloadTTSVoice();
  await RunAnywhere.loadTTSVoice(voiceId);
}
```

## Voice Selection UI

```dart theme={null}
class VoiceSelectorWidget extends StatefulWidget {
  @override
  _VoiceSelectorWidgetState createState() => _VoiceSelectorWidgetState();
}

class _VoiceSelectorWidgetState extends State<VoiceSelectorWidget> {
  final voices = [
    {'id': 'vits-piper-en_US-lessac-medium', 'name': 'Lessac (Male)'},
    {'id': 'vits-piper-en_US-amy-medium', 'name': 'Amy (Female)'},
    {'id': 'vits-piper-en_US-ryan-medium', 'name': 'Ryan (Male)'},
  ];

  String? _selectedVoice;
  bool _isLoading = false;

  Future<void> _selectVoice(String voiceId) async {
    setState(() => _isLoading = true);

    try {
      // Download if needed
      await for (final p in RunAnywhere.downloadModel(voiceId)) {
        if (p.state.isCompleted) break;
      }

      // Load voice
      await RunAnywhere.loadTTSVoice(voiceId);
      setState(() => _selectedVoice = voiceId);

      // Preview voice
      await _previewVoice();
    } finally {
      setState(() => _isLoading = false);
    }
  }

  Future<void> _previewVoice() async {
    final result = await RunAnywhere.synthesize(
      'Hello, this is a preview of my voice.',
    );
    // Play audio...
    void _ = result;
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text('Select Voice', style: TextStyle(fontWeight: FontWeight.bold)),
        SizedBox(height: 8),
        IgnorePointer(
          ignoring: _isLoading,
          child: RadioGroup<String>(
            groupValue: _selectedVoice,
            onChanged: (id) {
              if (id != null) _selectVoice(id);
            },
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: voices
                  .map((voice) => RadioListTile<String>(
                        value: voice['id']!,
                        title: Text(voice['name']!),
                      ))
                  .toList(),
            ),
          ),
        ),
        if (_isLoading) LinearProgressIndicator(),
      ],
    );
  }
}
```

## System Voice Fallback

The SDK can fall back to system TTS voices via `flutter_tts` when neural voices aren't available:

```dart theme={null}
// System TTS is automatically available
// Use it for simple cases or as fallback
import 'package:flutter_tts/flutter_tts.dart';

final flutterTts = FlutterTts();

// List available system voices
final voices = await flutterTts.getVoices;

// Speak with system voice
await flutterTts.speak('Hello world');
```

## Choosing Between Neural and System Voices

| Feature       | Piper (Neural)    | System TTS   |
| ------------- | ----------------- | ------------ |
| Quality       | High              | Varies       |
| Latency       | \~100-500ms       | \~50ms       |
| Size          | 20-50MB per voice | 0 (built-in) |
| Offline       | Yes               | Yes          |
| Customization | Limited           | More options |

<Tip>
  **Recommendation:** Use Piper neural voices for the best quality. Fall back to system TTS for
  quick responses or when storage is limited.
</Tip>

## See Also

<CardGroup cols={2}>
  <Card title="synthesize()" icon="volume-high" href="/flutter/tts/synthesize">
    Basic synthesis
  </Card>

  <Card title="Voice Agent" icon="robot" href="/flutter/voice-agent">
    Complete voice pipeline
  </Card>
</CardGroup>
