flutter_waveform_player 0.1.1
flutter_waveform_player: ^0.1.1 copied to clipboard
A Flutter waveform audio player widget with built-in downloading, FFmpeg waveform extraction, caching, playback, seek gestures, and customisable UI.
Flutter Waveform Player #
A self-contained Flutter package for displaying interactive audio waveform visualizations with built-in playback controls. Just provide a URL — it handles everything.
✨ Features #
| Feature | Description |
|---|---|
| 🎵 Auto-download & cache | Provide a network URL — downloading and local caching is handled automatically. |
| 📊 Real waveform extraction | Powered by FFmpeg — extracts actual audio amplitudes, not random placeholder bars. |
| 🎨 Fully customisable | Colors, bar width, bar cap shape, spacing, seek indicator, and more via WaveformStyle. |
| 👆 Seek gestures | Tap or drag anywhere on the waveform to seek. Haptic feedback included. |
| ▶️ Play/pause button | Built-in button, or bring your own via playButtonBuilder, or disable it entirely. |
| ⏱️ Time labels | Optional position / duration labels beside the waveform. |
| 🔌 External controls | Use showPlayButton: false and control playback from your own buttons anywhere. |
| 💾 Smart caching | Downloaded files and extracted waveforms are cached in memory and on disk. |
📸 Style Examples #
🚀 Getting Started #
1. Add the dependency #
dependencies:
flutter_waveform_player: ^0.1.0
2. Platform setup #
This package uses FFmpeg (via ffmpeg_kit_flutter_new) for waveform extraction. You may need to set a minimum iOS deployment target of 16.0 or higher.
iOS — In your ios/Podfile:
platform :ios, '16.0'
Android — In your android/app/build.gradle:
android {
defaultConfig {
minSdkVersion 24
}
}
3. Import it #
import 'package:flutter_waveform_player/flutter_waveform_player.dart';
📖 Usage #
Basic — 3 lines to a working player #
// 1. Create a controller
final controller = WaveformController(bars: 80);
// 2. Add the widget
WaveformPlayer(controller: controller);
// 3. Load audio (downloads, extracts waveform, and plays)
controller.load('https://example.com/audio.mp3');
Pre-load without auto-playing #
// Load waveform and prepare audio, but don't start playback.
// The user can tap the play button when ready.
controller.load('https://example.com/audio.mp3', autoPlay: false);
Custom styled player #
WaveformPlayer(
controller: controller,
height: 64,
style: const WaveformStyle(
baseColor: Color(0xFF3D2E5C),
highlightColor: Color(0xFFBB86FC),
seekIndicatorColor: Color(0xFFBB86FC),
barWidth: 3.0,
barCap: BarCap.square,
barSpacing: 2.0,
seekIndicatorRadius: 6.0,
),
)
Custom play button #
WaveformPlayer(
controller: controller,
playButtonBuilder: (context, isPlaying) {
return Container(
width: 36,
height: 36,
decoration: BoxDecoration(
color: Colors.deepPurple,
borderRadius: BorderRadius.circular(10),
),
child: Icon(
isPlaying ? Icons.pause : Icons.play_arrow,
color: Colors.white,
),
);
},
)
External play/pause controls #
Disable the built-in button and control playback from anywhere:
// Waveform — no play button
WaveformPlayer(
controller: controller,
showPlayButton: false,
showTimeLabels: false,
),
// Your own button — placed anywhere in the widget tree
ElevatedButton(
onPressed: controller.togglePlayPause,
child: Text(controller.isPlaying ? 'Pause' : 'Play'),
),
Local file playback #
controller.load('/path/to/local/audio.mp3', isLocal: true);
🎛️ WaveformPlayer Properties #
| Property | Type | Default | Description |
|---|---|---|---|
controller |
WaveformController |
required | The controller managing audio + waveform state. |
style |
WaveformStyle |
WaveformStyle() |
Visual configuration for bars, colors, and seek indicator. |
height |
double |
40.0 |
Height of the waveform visualization. |
showPlayButton |
bool |
true |
Whether to show the built-in play/pause button. |
showTimeLabels |
bool |
true |
Whether to show position / duration labels. |
showSeekIndicator |
bool |
true |
Whether to show the seek line + dot during drag. |
enableHapticFeedback |
bool |
true |
Whether to trigger haptic feedback on seek gestures. |
playButtonBuilder |
Widget Function(BuildContext, bool)? |
null |
Custom builder for the play/pause button. |
timeLabelStyle |
TextStyle? |
null |
Custom text style for the time labels. |
loadingPlaceholder |
Widget? |
null |
Widget shown while the waveform is loading. |
padding |
EdgeInsetsGeometry? |
null |
Padding around the entire player. |
decoration |
BoxDecoration? |
null |
Decoration for the player container. |
onSeekEnd |
ValueChanged<double>? |
null |
Callback when seek ends (receives progress 0.0–1.0). |
🎨 WaveformStyle Properties #
| Property | Type | Default | Description |
|---|---|---|---|
baseColor |
Color |
Color(0xFFBDBDBD) |
Color of unplayed bars. |
highlightColor |
Color |
Color(0xFF2196F3) |
Color of played bars. |
seekIndicatorColor |
Color |
Color(0xFF2196F3) |
Color of the seek indicator line + dot. |
barWidth |
double |
2.0 |
Width of each bar in logical pixels. |
barSpacing |
double |
1.5 |
Spacing between bars. |
minBarHeight |
double |
2.0 |
Minimum height of a bar. |
barCap |
BarCap |
BarCap.round |
Shape of bar ends (round or square). |
seekIndicatorRadius |
double |
4.0 |
Radius of the seek indicator dot. |
seekIndicatorWidth |
double |
1.5 |
Width of the seek indicator line. |
🎮 WaveformController API #
| Method / Property | Description |
|---|---|
load(url, {isLocal, autoPlay}) |
Load audio from a URL. Downloads, extracts waveform, and optionally plays. |
togglePlayPause() |
Toggle between play and pause. |
play() / pause() / stop() |
Direct playback controls. |
seekTo(Duration) |
Seek to a specific position. |
seekToProgress(double) |
Seek to a progress value (0.0–1.0). |
reset() |
Stop playback and clear all state. |
isPlaying |
Whether audio is currently playing. |
isLoading |
Whether audio is loading/buffering. |
position |
Current playback position (Duration). |
duration |
Total audio duration (Duration). |
playbackProgress |
Current progress (0.0–1.0). |
playbackStatus |
Current AudioPlaybackStatus enum value. |
waveform |
The extracted amplitude data (List<double>). |
error |
Last error message, or null. |
📊 How the bars Parameter Works #
The bars parameter on WaveformController determines how many vertical bars appear in the waveform:
WaveformController(bars: 50) // 50 bars — balanced
WaveformController(bars: 80) // 80 bars — more detail
WaveformController(bars: 120) // 120 bars — very detailed
Internally:
- The audio is converted to raw PCM (mono, 16-bit) via FFmpeg.
- The samples are divided into
barsequal segments. - The peak amplitude of each segment becomes one bar (normalized 0.0–1.0).
🏗️ Architecture #
┌──────────────────────────────────────────────────┐
│ WaveformPlayer (Widget) │
│ • Renders waveform bars via WaveformPainter │
│ • Handles tap/drag seek gestures │
│ • Shows play button + time labels │
└──────────────────┬───────────────────────────────┘
│ listens to
┌──────────────────▼───────────────────────────────┐
│ WaveformController (ChangeNotifier) │
│ • Public API: load, play, pause, seek │
│ • Exposes: position, duration, waveform, status │
└──────────────────┬───────────────────────────────┘
│ delegates to
┌──────────────────▼───────────────────────────────┐
│ WaveformAudioService (Internal) │
│ • Downloads & caches audio files (Dio) │
│ • Extracts waveform amplitudes (FFmpeg) │
│ • Manages playback (just_audio) │
└──────────────────────────────────────────────────┘
📋 Requirements #
| Platform | Minimum Version |
|---|---|
| iOS | 16.0+ |
| Android | API 24+ (Android 7.0) |
| Flutter | 3.0+ |
| Dart | 3.10+ |
📄 License #
MIT License — see LICENSE for details.
🤝 Contributing #
Contributions are welcome! Please feel free to submit a Pull Request or open an Issue.