Sonix - Flutter Audio Waveform Package
A comprehensive Flutter package for generating and displaying audio waveforms with isolate-based processing to prevent UI thread blocking. Sonix supports multiple audio formats (MP3, OGG, WAV, FLAC, Opus) using native C libraries through Dart FFI for optimal performance.
Features
π Isolate-Based Processing: All audio processing runs in background isolates to keep UI responsive
β¨ Multi-format Support: MP3, OGG, WAV, FLAC, and Opus audio formats
π High Performance: Native C libraries via Dart FFI (no FFMPEG dependency)
π¨ Extensive Customization: Colors, gradients, styles, and animations
οΏ½ *Interactive Playback: Real-time position visualization and seeking
οΏ½ Insstance-Based API: Modern API with proper resource management
οΏ½ Easyi Integration: Simple API with comprehensive error handling
π Multiple Algorithms: RMS, Peak, Average, and Median downsampling
π― Optimized Presets: Ready-to-use configurations for different use cases
Getting Started
Installation
Add Sonix to your pubspec.yaml
:
dependencies:
sonix: <latest>
Then run:
flutter pub get
Note: Sonix includes pre-built native libraries (sonix_native
) for all supported platforms. These are automatically bundled with your app - no additional compilation required!
FFMPEG Setup
Sonix uses FFMPEG for audio decoding. You need to install FFMPEG binaries in your Flutter app to use Sonix.
Automated Setup (Recommended)
Required Step: Use our automated setup tool to download and install FFMPEG binaries:
# From your Flutter app's root directory
dart run sonix:setup_ffmpeg_for_app
# Verify installation
dart run sonix:setup_ffmpeg_for_app --verify
This tool will:
- β Automatically detect your platform
- β Download compatible FFMPEG binaries from trusted sources
- β Install them to your app's build directories
- β Validate the installation
- β Enable Sonix to work with FFMPEG in your app
Requirements:
- Run from your Flutter app's root directory (where pubspec.yaml is located)
- Sonix must be added as a dependency in your pubspec.yaml
Supported Platforms
- β Android (API 21+) - FFMPEG binaries included in APK
- β iOS (11.0+) - FFMPEG binaries statically linked
- β Windows (Windows 10+) - Requires FFMPEG DLLs
- β macOS (10.14+) - Requires FFMPEG dylibs
- β Linux (Ubuntu 18.04+) - Requires FFMPEG shared objects
Manual Installation (Advanced)
If you prefer to install FFMPEG binaries manually, place them in your Flutter build directory:
- Windows:
build/windows/x64/runner/Debug/
- macOS:
build/macos/Build/Products/Debug/
- Linux:
build/linux/x64/debug/bundle/lib/
Required FFMPEG libraries: avformat
, avcodec
, avutil
, swresample
Quick Start
Basic Waveform Generation
import 'package:sonix/sonix.dart';
// Create a Sonix instance
final sonix = Sonix();
// Generate waveform from audio file (processed in background isolate)
final waveformData = await sonix.generateWaveform('path/to/audio.mp3');
// Display the waveform
WaveformWidget(
waveformData: waveformData,
style: WaveformStylePresets.soundCloud,
)
// Clean up when done
await sonix.dispose();
With Playback Position
class AudioPlayer extends StatefulWidget {
@override
_AudioPlayerState createState() => _AudioPlayerState();
}
class _AudioPlayerState extends State<AudioPlayer> {
late Sonix sonix;
WaveformData? waveformData;
double playbackPosition = 0.0;
@override
void initState() {
super.initState();
sonix = Sonix(SonixConfig.mobile()); // Optimized for mobile
}
@override
void dispose() {
sonix.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
if (waveformData != null)
WaveformWidget(
waveformData: waveformData!,
playbackPosition: playbackPosition,
style: WaveformStylePresets.spotify,
onSeek: (position) {
setState(() {
playbackPosition = position;
});
// Update your audio player position
},
),
],
);
}
}
Usage Examples
1. Different Waveform Styles
// SoundCloud-style waveform
WaveformWidget(
waveformData: waveformData,
style: WaveformStylePresets.soundCloud,
)
// Spotify-style waveform
WaveformWidget(
waveformData: waveformData,
style: WaveformStylePresets.spotify,
)
// Custom style with gradient
WaveformWidget(
waveformData: waveformData,
style: WaveformStylePresets.filledGradient(
startColor: Colors.blue,
endColor: Colors.purple,
height: 100,
),
)
// Professional audio editor style
WaveformWidget(
waveformData: waveformData,
style: WaveformStylePresets.professional,
)
2. Instance Configuration
// Mobile-optimized configuration
final mobileSonix = Sonix(SonixConfig.mobile());
// Desktop-optimized configuration
final desktopSonix = Sonix(SonixConfig.desktop());
// Custom configuration
final customSonix = Sonix(SonixConfig(
maxConcurrentOperations: 2,
isolatePoolSize: 1,
maxMemoryUsage: 50 * 1024 * 1024, // 50MB
enableProgressReporting: true,
));
3. Optimal Configuration for Use Cases
// Get optimal config for specific use cases
final musicConfig = Sonix.getOptimalConfig(
useCase: WaveformUseCase.musicVisualization,
customResolution: 2000,
);
final podcastConfig = Sonix.getOptimalConfig(
useCase: WaveformUseCase.podcastPlayer,
);
final editorConfig = Sonix.getOptimalConfig(
useCase: WaveformUseCase.audioEditor,
customResolution: 5000, // High detail for editing
);
// Use with instance
final sonix = Sonix();
final waveformData = await sonix.generateWaveform(
'music.mp3',
config: musicConfig,
);
4. Resource Management
// Check resource usage
final sonix = Sonix();
final stats = sonix.getResourceStatistics();
print('Active isolates: ${stats.activeIsolates}');
print('Completed tasks: ${stats.completedTasks}');
// Optimize resources when needed
sonix.optimizeResources();
// Cancel operations if needed
final activeOps = sonix.getActiveOperations();
for (final opId in activeOps) {
sonix.cancelOperation(opId);
}
// Always dispose when done
await sonix.dispose();
5. Pre-generated Waveform Data
// Use pre-computed waveform data
final jsonData = await loadWaveformFromCache();
final waveformData = WaveformData.fromJson(jsonData);
// Or from amplitude array
final amplitudes = [0.1, 0.5, 0.8, 0.3, 0.7, ...];
final waveformData = WaveformData.fromAmplitudes(amplitudes);
WaveformWidget(
waveformData: waveformData,
style: WaveformStylePresets.professional,
)
6. Error Handling
final sonix = Sonix();
try {
final waveformData = await sonix.generateWaveform('audio.mp3');
// Use waveformData
} on UnsupportedFormatException catch (e) {
print('Unsupported format: ${e.format}');
print('Supported formats: ${Sonix.getSupportedFormats()}');
} on DecodingException catch (e) {
print('Decoding failed: ${e.message}');
} on FileSystemException catch (e) {
print('File access error: ${e.message}');
} finally {
await sonix.dispose();
}
API Reference
Main API Class
Sonix
The main entry point for generating waveforms. This is an instance-based class that manages background isolates for processing.
Constructor:
Sonix([SonixConfig? config])
- Create a new instance with optional configuration
Instance Methods:
generateWaveform(String filePath, {...})
βFuture<WaveformData>
getResourceStatistics()
βIsolateStatistics
optimizeResources()
βvoid
cancelOperation(String taskId)
βbool
cancelAllOperations()
βint
getActiveOperations()
βList<String>
dispose()
βFuture<void>
Static Utility Methods:
isFormatSupported(String filePath)
βbool
getSupportedFormats()
βList<String>
getSupportedExtensions()
βList<String>
isExtensionSupported(String extension)
βbool
getOptimalConfig({required WaveformUseCase useCase, ...})
βWaveformConfig
Configuration
SonixConfig
Configuration options for Sonix instances.
Factory Constructors:
SonixConfig.defaultConfig()
- Default configurationSonixConfig.mobile()
- Optimized for mobile devicesSonixConfig.desktop()
- Optimized for desktop devices
Properties:
maxConcurrentOperations
: Maximum concurrent operationsisolatePoolSize
: Size of the isolate poolisolateIdleTimeout
: Timeout for idle isolatesmaxMemoryUsage
: Maximum memory usage in bytesenableProgressReporting
: Whether to enable progress reporting
Widgets
WaveformWidget
Interactive waveform display with playback position and seeking.
Properties:
waveformData
(required): The waveform data to displayplaybackPosition
: Current playback position (0.0 to 1.0)style
: Customization options (WaveformStyle)onTap
: Callback when user taps the widgetonSeek
: Callback when user seeks to a positionenableSeek
: Whether to enable touch interactionanimationDuration
: Duration for position animationsanimationCurve
: Animation curve for transitions
Data Models
WaveformData
Contains processed waveform data and metadata.
Properties:
amplitudes
: List of amplitude values (0.0 to 1.0)duration
: Duration of the original audiosampleRate
: Sample rate of the original audiometadata
: Generation metadata
Methods:
toJson()
βMap<String, dynamic>
fromJson(Map<String, dynamic>)
βWaveformData
fromAmplitudes(List<double>)
βWaveformData
WaveformStyle
Customization options for waveform appearance.
Properties:
playedColor
: Color for played portionunplayedColor
: Color for unplayed portionheight
: Height of the waveformtype
: Visualization type (bars, line, filled)gradient
: Optional gradient overlayborderRadius
: Border radius for rounded corners
Style Presets
WaveformStylePresets
Pre-configured styles for common use cases:
soundCloud
: SoundCloud-inspired orange and grey barsspotify
: Spotify-inspired green and grey barsminimalLine
: Minimal line-style waveformretro
: Vintage style with rounded bars and warm colorscompact
: Compact mobile-friendly stylepodcast
: Optimized for podcast/speech contentprofessional
: Clean style for professional audio applicationsfilledGradient({Color startColor, Color endColor, double height})
: Filled waveform with customizable gradientglassEffect({Color accentColor, double height})
: Modern glass-like effectneonGlow({Color glowColor, double height})
: Glowing neon effect with shadows
Performance & Monitoring
Sonix includes performance monitoring and optimization tools for production applications.
Resource Monitoring
Monitor isolate performance and resource usage:
final sonix = Sonix();
// Get current resource statistics
final stats = sonix.getResourceStatistics();
print('Active isolates: ${stats.activeIsolates}');
print('Completed tasks: ${stats.completedTasks}');
print('Failed tasks: ${stats.failedTasks}');
print('Average processing time: ${stats.averageProcessingTime}ms');
// Optimize resources when needed
sonix.optimizeResources();
Performance Profiling
Profile operations to identify bottlenecks:
final profiler = PerformanceProfiler();
// Profile waveform generation
final result = await profiler.profile('waveform_generation', () async {
final sonix = Sonix();
final waveformData = await sonix.generateWaveform('audio.mp3');
await sonix.dispose();
return waveformData;
});
print('Processing took: ${result.duration.inMilliseconds}ms');
print('Memory used: ${result.memoryUsage}MB');
// Generate performance report
final report = profiler.generateReport();
print(report.toString());
Platform Validation
Validate platform compatibility:
final validator = PlatformValidator();
// Validate current platform
final validation = await validator.validatePlatform();
print('Platform supported: ${validation.isSupported}');
// Check specific format support
final mp3Support = await validator.validateFormatSupport('mp3');
print('MP3 supported: ${mp3Support.isSupported}');
// Get optimization recommendations
final recommendations = validator.getOptimizationRecommendations();
for (final rec in recommendations) {
print('${rec.category}: ${rec.title}');
}
Best Practices
- Use appropriate configuration: Choose
SonixConfig.mobile()
orSonixConfig.desktop()
based on your target platform - Dispose instances: Always call
dispose()
on Sonix instances when done to clean up isolates - Monitor resources: Use
getResourceStatistics()
to monitor isolate performance - Handle errors: Wrap operations in try-catch blocks for proper error handling
- Use optimal configs: Use
Sonix.getOptimalConfig()
for different use cases - Cancel when needed: Cancel long-running operations with
cancelOperation()
if user navigates away - Profile performance: Use
PerformanceProfiler
to identify bottlenecks in production - Validate formats: Check
Sonix.isFormatSupported()
before processing files
Platform-Specific Considerations
Android
- Minimum API level 21 (Android 5.0)
- FFMPEG binaries are automatically included in APK during build
- Isolate processing works seamlessly on all Android versions
iOS
- Minimum iOS version 11.0
- FFMPEG binaries are statically linked during build
- Background isolates work within iOS app lifecycle constraints
Desktop (Windows/macOS/Linux)
- FFMPEG binaries must be present in build directory (use download tool)
- Full isolate pool support for maximum performance
- Runtime loading of FFMPEG libraries from build directory
Troubleshooting FFMPEG Setup
If you encounter issues with FFMPEG binaries:
# Check if binaries are properly installed
dart run sonix:setup_ffmpeg_for_app --verify
# Force reinstall if needed
dart run sonix:setup_ffmpeg_for_app --force
# Remove FFMPEG binaries
dart run sonix:setup_ffmpeg_for_app --clean
# Get help and see all options
dart run sonix:setup_ffmpeg_for_app --help
Common issues:
- "FFMPEG libraries not found": Run the download tool to install binaries
- "Unsupported platform": Check supported platforms list above
- "Binary validation failed": Try force reinstalling with
--force
flag
Supported Audio Formats
Sonix supports multiple audio formats through FFMPEG integration:
Format | Extension | Decoder Backend | Notes |
---|---|---|---|
MP3 | .mp3 | FFMPEG | Most common audio format |
WAV | .wav | FFMPEG | Uncompressed audio |
FLAC | .flac | FFMPEG | Lossless compression |
OGG Vorbis | .ogg | FFMPEG | Open source format |
Opus | .opus | FFMPEG | Modern codec |
MP4/AAC | .mp4, .m4a | FFMPEG | Container with AAC |
Note: All audio decoding is handled by FFMPEG libraries. Ensure FFMPEG binaries are installed using the provided download tool.
Contributing
We welcome contributions! Please see our Contributing Guide for details.
Development Setup
- Clone the repository
- Run
flutter pub get
- Install FFMPEG binaries for development:
dart run tool/download_ffmpeg_binaries.dart
- Build native library for testing:
dart run tool/build_native_for_development.dart
- Run tests:
flutter test
- Run example:
cd example && flutter run
Note for Contributors:
- Use
dart run tool/build_native_for_development.dart
for quick development builds - Use
dart run tool/build_native_for_distribution.dart
for release builds - End users should use
dart run sonix:setup_ffmpeg_for_app
in their own apps
License
This project is licensed under the MIT License - see the LICENSE file for details.
Support
- π Documentation
- π Issue Tracker
- π¬ Discussions
Changelog
See CHANGELOG.md for a detailed list of changes.
Libraries
- sonix
- Sonix - Flutter Audio Waveform Package