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 with FFmpeg-based decoding
π¨ Extensive Customization: Colors, gradients, styles, and animations
ποΈ Interactive Playback: Real-time position visualization and seeking
π¦ Instance-Based API: Modern API with proper resource management
β
Easy 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 the plugin glue code and native wrapper sources. Desktop platforms require FFmpeg installed on the system. The Flutter toolchain builds and bundles the plugin artifacts automatically; you should not need to compile C code manually for typical usage.
FFmpeg setup
Sonix uses FFmpeg for audio decoding. For desktop platforms, you must install FFmpeg on the system. Mobile platforms do not require a separate FFmpeg install.
Recommended installation methods:
- macOS: Homebrew
- Install:
brew install ffmpeg - Verify:
ffmpeg -version
- Install:
- Linux: Your distroβs package manager
- Debian/Ubuntu:
sudo apt install ffmpeg - Fedora:
sudo dnf install ffmpeg - Arch:
sudo pacman -S ffmpeg
- Debian/Ubuntu:
- Windows: Install FFmpeg and ensure the DLLs are on PATH or co-located next to your appβs executable
- Options: winget, chocolatey, or manual install from ffmpeg.org (DLLs must be discoverable at runtime)
- Verify:
ffmpeg -version
Supported platforms
- β Android (API 21+)
- β iOS (11.0+)
- β Windows (Windows 10+) - requires FFmpeg DLLs
- β macOS (10.15+) - requires FFmpeg dylibs
- β Linux (Ubuntu 18.04+) - requires FFmpeg shared objects
Advanced (manual placement)
Desktop apps can also load FFmpeg when the libraries are placed alongside the app at runtime:
- Windows: place FFmpeg DLLs next to the appβs exe (or ensure they are on PATH)
- Linux: place
.sofiles under the appβslibdirectory - macOS: prefer system-installed FFmpeg; bundling FFmpeg into an app may have licensing implications
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()βIsolateStatisticsoptimizeResources()βvoidcancelOperation(String taskId)βboolcancelAllOperations()βintgetActiveOperations()βList<String>dispose()βFuture<void>
Static Utility Methods:
isFormatSupported(String filePath)βboolgetSupportedFormats()βList<String>getSupportedExtensions()βList<String>isExtensionSupported(String extension)βboolgetOptimalConfig({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>)βWaveformDatafromAmplitudes(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
PerformanceProfilerto 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)
- macOS/Linux: Use system FFmpeg installed via your package manager (no bundling)
- Windows: Provide FFmpeg DLLs via PATH or next to the app executable
- Full isolate pool support for maximum performance
- Runtime loading of FFmpeg libraries
Troubleshooting FFmpeg setup
If you encounter issues with FFmpeg:
# Check installation
ffmpeg -version
# On macOS (Homebrew): reinstall
brew reinstall ffmpeg
# On Linux: use your distro package manager to reinstall
# e.g., Ubuntu/Debian
sudo apt --reinstall install ffmpeg
Common issues:
- "FFmpeg libraries not found": Install FFmpeg using your system package manager
- "Unsupported platform": Check supported platforms list above
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 is installed on the system for desktop platforms.
Contributing
We welcome contributions! Please see our Contributing Guide for details.
Development Setup
- Clone the repository
- Run
flutter pub get - Install system FFmpeg (desktop dev machines)
- macOS:
brew install ffmpeg - Linux:
sudo apt install ffmpeg(or your distro equivalent) - Windows: install FFmpeg and ensure DLLs are available on PATH
- 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.dartfor quick development builds - Use
dart run tool/build_native_for_distribution.dartfor release builds - Desktop users must install FFmpeg via their system package manager
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