audiocraft 0.1.0
audiocraft: ^0.1.0 copied to clipboard
A Flutter plugin for text-to-speech audio file conversion with background processing support.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:audiocraft/audiocraft.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Audiocraft Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Audiocraft Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final AudioManagerService _audioManager = AudioManagerService();
final TextEditingController _textController = TextEditingController();
String _statusText = 'Ready';
double _conversionProgress = 0.0;
String _conversionMessage = '';
Duration _currentPosition = Duration.zero;
Duration _totalDuration = Duration.zero;
double _currentSpeed = 1.0;
@override
void initState() {
super.initState();
_initializeAudioManager();
_textController.text = 'Hello, this is a test text for audio conversion. '
'The text-to-speech system will convert this text into an audio file. '
'You can then play the audio file using the controls below.';
}
Future<void> _initializeAudioManager() async {
await _audioManager.initialize();
// Setup callbacks
_audioManager.onConversionProgress = (progress) {
setState(() {
_conversionProgress = progress.progress;
_conversionMessage = progress.message;
});
};
_audioManager.onPlaybackProgress = (progress) {
setState(() {
_currentPosition = progress.position;
_totalDuration = progress.duration;
_currentSpeed = progress.speed;
});
};
_audioManager.onStateChanged = (state) {
setState(() {
_statusText = state.toString().split('.').last;
});
};
_audioManager.onError = (error) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error: $error')),
);
};
_audioManager.onChapterCompleted = () {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Audio playback completed!')),
);
};
}
Future<void> _loadChapter() async {
final text = _textController.text.trim();
if (text.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Please enter some text')),
);
return;
}
await _audioManager.loadChapter(
chapterId: 'test_chapter',
chapterContent: text,
);
}
Future<void> _playPause() async {
if (_audioManager.isPlaying) {
await _audioManager.pause();
} else {
await _audioManager.play();
}
}
Future<void> _stop() async {
await _audioManager.stop();
}
Future<void> _setSpeed(double speed) async {
await _audioManager.setSpeed(speed);
}
String _formatDuration(Duration duration) {
String twoDigits(int n) => n.toString().padLeft(2, '0');
String twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60));
String twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60));
return '${twoDigits(duration.inHours)}:$twoDigitMinutes:$twoDigitSeconds';
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Status
Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Status: $_statusText', style: Theme.of(context).textTheme.titleMedium),
const SizedBox(height: 8),
if (_audioManager.isConverting) ...[
Text('Conversion: ${(_conversionProgress * 100).toStringAsFixed(1)}%'),
const SizedBox(height: 4),
LinearProgressIndicator(value: _conversionProgress),
const SizedBox(height: 4),
Text(_conversionMessage, style: Theme.of(context).textTheme.bodySmall),
],
if (_audioManager.isPlaying || _audioManager.isPaused) ...[
Text('Position: ${_formatDuration(_currentPosition)} / ${_formatDuration(_totalDuration)}'),
const SizedBox(height: 4),
LinearProgressIndicator(
value: _totalDuration.inMilliseconds > 0
? _currentPosition.inMilliseconds / _totalDuration.inMilliseconds
: 0.0,
),
const SizedBox(height: 4),
Text('Speed: ${_currentSpeed}x'),
],
],
),
),
),
const SizedBox(height: 16),
// Text input
TextField(
controller: _textController,
maxLines: 5,
decoration: const InputDecoration(
labelText: 'Text to convert',
border: OutlineInputBorder(),
hintText: 'Enter the text you want to convert to audio...',
),
),
const SizedBox(height: 16),
// Convert button
ElevatedButton(
onPressed: _audioManager.isConverting ? null : _loadChapter,
child: Text(_audioManager.isConverting ? 'Converting...' : 'Convert to Audio'),
),
const SizedBox(height: 16),
// Playback controls
Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
IconButton(
onPressed: (_audioManager.isReady || _audioManager.isPlaying || _audioManager.isPaused)
? _playPause
: null,
icon: Icon(_audioManager.isPlaying ? Icons.pause : Icons.play_arrow),
iconSize: 32,
),
IconButton(
onPressed: (_audioManager.isPlaying || _audioManager.isPaused)
? _stop
: null,
icon: const Icon(Icons.stop),
iconSize: 32,
),
],
),
const SizedBox(height: 16),
// Speed control
Row(
children: [
const Text('Speed: '),
Expanded(
child: Slider(
value: _currentSpeed,
min: 0.5,
max: 2.0,
divisions: 6,
label: '${_currentSpeed}x',
onChanged: _audioManager.isReady || _audioManager.isPlaying || _audioManager.isPaused
? (value) => _setSpeed(value)
: null,
),
),
],
),
],
),
),
),
const Spacer(),
// Cache info
FutureBuilder<int>(
future: _audioManager.getCacheSize(),
builder: (context, snapshot) {
final cacheSize = snapshot.data ?? 0;
return Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Cache Size: ${_audioManager.formatCacheSize(cacheSize)}'),
const SizedBox(height: 8),
ElevatedButton(
onPressed: () async {
await _audioManager.clearAllCache();
setState(() {});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Cache cleared!')),
);
},
child: const Text('Clear Cache'),
),
],
),
),
);
},
),
],
),
),
);
}
@override
void dispose() {
_audioManager.dispose();
_textController.dispose();
super.dispose();
}
}