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.

pub package License: MIT

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
  • Linux: Your distro’s package manager
    • Debian/Ubuntu: sudo apt install ffmpeg
    • Fedora: sudo dnf install ffmpeg
    • Arch: sudo pacman -S ffmpeg
  • 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 .so files under the app’s lib directory
  • 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() β†’ 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 configuration
  • SonixConfig.mobile() - Optimized for mobile devices
  • SonixConfig.desktop() - Optimized for desktop devices

Properties:

  • maxConcurrentOperations: Maximum concurrent operations
  • isolatePoolSize: Size of the isolate pool
  • isolateIdleTimeout: Timeout for idle isolates
  • maxMemoryUsage: Maximum memory usage in bytes
  • enableProgressReporting: Whether to enable progress reporting

Widgets

WaveformWidget

Interactive waveform display with playback position and seeking.

Properties:

  • waveformData (required): The waveform data to display
  • playbackPosition: Current playback position (0.0 to 1.0)
  • style: Customization options (WaveformStyle)
  • onTap: Callback when user taps the widget
  • onSeek: Callback when user seeks to a position
  • enableSeek: Whether to enable touch interaction
  • animationDuration: Duration for position animations
  • animationCurve: 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 audio
  • sampleRate: Sample rate of the original audio
  • metadata: 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 portion
  • unplayedColor: Color for unplayed portion
  • height: Height of the waveform
  • type: Visualization type (bars, line, filled)
  • gradient: Optional gradient overlay
  • borderRadius: Border radius for rounded corners

Style Presets

WaveformStylePresets

Pre-configured styles for common use cases:

  • soundCloud: SoundCloud-inspired orange and grey bars
  • spotify: Spotify-inspired green and grey bars
  • minimalLine: Minimal line-style waveform
  • retro: Vintage style with rounded bars and warm colors
  • compact: Compact mobile-friendly style
  • podcast: Optimized for podcast/speech content
  • professional: Clean style for professional audio applications
  • filledGradient({Color startColor, Color endColor, double height}): Filled waveform with customizable gradient
  • glassEffect({Color accentColor, double height}): Modern glass-like effect
  • neonGlow({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

  1. Use appropriate configuration: Choose SonixConfig.mobile() or SonixConfig.desktop() based on your target platform
  2. Dispose instances: Always call dispose() on Sonix instances when done to clean up isolates
  3. Monitor resources: Use getResourceStatistics() to monitor isolate performance
  4. Handle errors: Wrap operations in try-catch blocks for proper error handling
  5. Use optimal configs: Use Sonix.getOptimalConfig() for different use cases
  6. Cancel when needed: Cancel long-running operations with cancelOperation() if user navigates away
  7. Profile performance: Use PerformanceProfiler to identify bottlenecks in production
  8. 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

  1. Clone the repository
  2. Run flutter pub get
  3. 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
  1. Build native library for testing: dart run tool/build_native_for_development.dart
  2. Run tests: flutter test
  3. 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
  • 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

Changelog

See CHANGELOG.md for a detailed list of changes.

Libraries

sonix
Sonix - Flutter Audio Waveform Package