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
// 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
// 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
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 viaflutter_tts when neural voices aren’t available:
// 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 |
Recommendation: Use Piper neural voices for the best quality. Fall back to system TTS for
quick responses or when storage is limited.
See Also
synthesize()
Basic synthesis
Voice Agent
Complete voice pipeline