audio_waveform_recorder
Record audio with a real-time animated waveform and play it back with waveform scrubbing — like WhatsApp or Telegram voice messages.
Zero heavy dependencies. Pure Dart UI + native platform channels.
🎨 10 Waveform Styles
| Style | Description |
|---|---|
| Bars | Classic centre-aligned bars — WhatsApp / Telegram style |
| Mirror | Symmetrical mirror bars, top + bottom — Spotify style |
| Line | Filled closed-path shape — SoundCloud style |
| Equalizer | Bottom-anchored histogram bars — DJ / EQ style |
| Radial | Circular radial bars from centre — vinyl / radar style |
| Wave | Smooth cubic-bezier with gradient layers — Apple Music style |
| Dots | Dot matrix — amplitude mapped to dot radius — retro LED style |
| Neon | Glowing bars with bloom shadow — cyberpunk style |
| Stacked | Semi-transparent layers with depth — holographic style |
| Pixel | Pixel-art blocky cells on a grid — retro game style |
✨ Features
- 🎙 Real-time waveform — animated bars update as you speak
- ▶️ Waveform playback scrubbing — tap or drag to seek
- 🎨 10 waveform styles — bars, mirror, line, equalizer, radial, wave, dots, neon, stacked, pixel
- 🔴 Pulsing record indicator — animated recording dot
- ⏸ Pause / resume recording
- ⏭ Speed control — 0.5× to 2.0×
- 📊 Waveform extraction — from existing audio files too
- 💾 M4A / WAV / MP4 / OGG output formats
- 🔕 Silence auto-stop — configurable timeout
- ⏱ Max duration limit with indicator
- 🎛 Full customisation — colours, bar size, themes, gradients, glow effects
🚀 Installation
dependencies:
audio_waveform_recorder: ^0.1.0
Android — add to AndroidManifest.xml:
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
iOS — add to Info.plist:
<key>NSMicrophoneUsageDescription</key>
<string>This app needs microphone access to record audio.</string>
📱 Usage
Drop-in recorder widget
WaveformRecorderWidget(
config: RecorderConfig(
format: AudioFormat.m4a,
maxDuration: Duration(minutes: 5),
recordingColor: Colors.red,
playedColor: Colors.blue,
),
style: WaveformStyle.bars,
onRecordingComplete: (RecordingResult result) {
print('File: ${result.filePath}');
print('Duration: ${result.duration}');
print('Size: ${result.fileSizeBytes} bytes');
print('Samples: ${result.waveform.length}');
},
)
Drop-in player widget
WaveformPlayerWidget(
filePath: result.filePath,
waveform: result.waveform, // pass from recording for instant display
config: RecorderConfig(
playedColor: Colors.blue,
idleColor: Colors.grey,
),
showSpeedControl: true,
)
Manual control with RecorderController
final controller = RecorderController(
config: RecorderConfig(format: AudioFormat.wav),
);
// Request permission
final granted = await controller.requestPermission();
// Start recording
await controller.start();
// Pause / Resume
await controller.pause();
await controller.resume();
// Stop and get result
final result = await controller.stop();
print(result?.filePath);
// Cancel (deletes file)
await controller.cancel();
// Listen to state changes
controller.addListener(() {
print(controller.currentAmplitude); // 0.0 – 1.0
print(controller.elapsed); // Duration
print(controller.waveform.samples); // List<double>
});
Standalone waveform display
WaveformPainterWidget(
waveform: myWaveformData,
config: RecorderConfig(),
playbackProgress: 0.4, // 40% played
style: WaveformStyle.mirror,
height: 64,
onTap: (fraction) => player.seekToFraction(fraction),
)
Extract waveform from existing file
final samples = await AudioChannel.extractWaveform(
'/path/to/audio.m4a',
sampleCount: 200,
);
final waveform = WaveformData(
samples: samples,
duration: Duration(seconds: 30),
);
⚙️ Configuration
RecorderConfig(
// Recording
format: AudioFormat.m4a, // m4a | wav | mp4 | ogg
sampleRate: SampleRate.high44k, // 8k | 16k | 44.1k | 48k
bitRate: BitRate.medium128k, // 64k | 128k | 256k
channels: 1, // 1=mono, 2=stereo
maxDuration: Duration(minutes: 5), // null = unlimited
silenceTimeout: Duration(seconds: 3), // null = no auto-stop
silenceThreshold: 0.02, // 0.0–1.0
// Waveform visual
waveformSampleRate: 100, // samples per second
recordingColor: Colors.red,
idleColor: Colors.grey,
playedColor: Colors.blue,
backgroundColor: Color(0xFF1A1A2E),
barWidth: 3.0,
barGap: 2.0,
barBorderRadius: 2.0,
minBarHeightFraction: 0.05,
)
Per-style customisation with WaveformStyleConfig
WaveformStyleConfig(
// Gradient
useGradient: true,
gradientColors: [Color(0xFFE53935), Color(0xFFFF7043)],
// Glow (neon / radial)
glowRadius: 8.0,
glowLayers: 2,
// Radial
radialInnerFraction: 0.25,
radialRoundedTips: true,
// Wave / stacked
waveLayerCount: 3,
waveLayerOffset: 0.08,
// Dots
dotRows: 8,
dotFilled: true,
// Pixel
pixelRows: 10,
pixelGap: 1.5,
// Equalizer
equalizerShowPeak: true,
equalizerPeakDecay: 0.92,
// Mirror
mirrorReflectionOpacity: 0.45,
// Playhead
showPlayhead: true,
playheadStyle: PlayheadStyle.line,
)
🏗 Architecture
WaveformRecorderWidget WaveformPlayerWidget
│ │
RecorderController PlayerController
│ │
AudioChannel (MethodChannel: "audio_waveform_recorder")
│ │
Android: MediaRecorder Android: MediaPlayer
MediaExtractor + MediaCodec
iOS: AVAudioRecorder iOS: AVAudioPlayer
AVAudioFile + AVFoundation
📦 Dependencies
dependencies:
flutter:
sdk: flutter # That's it.
📄 License
MIT License — see LICENSE for details.
Libraries
- audio_waveform_recorder
- Audio Waveform Recorder Record audio with real-time waveform + playback with scrubbing. Zero external dependencies — pure Dart UI + native platform channels.