audify 1.1.1 copy "audify: ^1.1.1" to clipboard
audify: ^1.1.1 copied to clipboard

High-performance audio visualizer for Flutter with circular and bar spectrum displays. Native FFT processing on Android and iOS.

Audify #

A high-performance audio visualizer plugin for Flutter with beautiful trap/dubstep style visualizations including circular spectrum and bar spectrum displays.

Pub Version License

circular spectrum with image demo Visucircular spectrumalizer without image demo bar spectrum demo bar spectrum mirror demo

Key Highlights #

Real-time native audio visualization
Audify provides Flutter widgets and streams for visualizing captured audio. Android uses the platform Visualizer API, where audioSessionId: 0 targets the output mix only when the OS and device permit it. iOS uses AVAudioEngine and visualizes audio routed through the plugin-created engine, not arbitrary audio from other apps.

Features #

🎵 Real-time Audio Visualization

  • Circular spectrum visualizer with smooth 60 FPS animations and optional center image/album artwork
  • Vertical bar spectrum with optional mirror effect
  • FFT, waveform, and seven-band frequency data streams for custom visualizers

🚀 High Performance

  • Native FFT processing for optimal performance
    • Android: Visualizer API for output-mix or session-based visualization where supported
    • iOS: AVAudioEngine with Accelerate framework (vDSP)
  • Smooth animations with configurable smoothing
  • Minimal CPU usage (<5%)
  • Adaptive sizing for non-square containers

🎨 Highly Customizable

  • Customizable colors, gradients, and glow effects
  • Adjustable bar count, width, and spacing
  • Multiple visualization styles and layouts
  • Add album artwork or any image to circular visualizer center

📱 Cross-Platform Support

  • ✅ Android (API 24+)
  • ✅ iOS (12.0+)

Installation #

Add to your pubspec.yaml:

dependencies:
  audify: ^1.1.1
  permission_handler: ^11.0.1  # For runtime permissions

Run:

flutter pub get

Platform Setup #

Android #

Add permissions to android/app/src/main/AndroidManifest.xml:

<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />

iOS #

Add permission to ios/Runner/Info.plist:

<key>NSMicrophoneUsageDescription</key>
<string>This app needs microphone access to visualize audio.</string>

Quick Start #

Platform note: On Android, audioSessionId: 0 requests output-mix visualization when the device allows it. A specific Android media player session ID can be passed to target that player. The current iOS implementation visualizes audio routed through Audify's AVAudioEngine.

1. Request Permission #

import 'package:permission_handler/permission_handler.dart';

final status = await Permission.microphone.request();
if (!status.isGranted) {
  // Handle permission denied
  return;
}

2. Create and Initialize Controller #

import 'package:audify/audify.dart';

final controller = AudifyController();

// Android: audioSessionId 0 targets the output mix when permitted.
// iOS: visualizes audio routed through Audify's AVAudioEngine.
await controller.initialize(audioSessionId: 0);

// Start capturing audio data for visualization.
await controller.startCapture();

3. Use Visualizer Widgets #

SizedBox(
  width: 300,
  height: 300,
  child: CircularSpectrumVisualizer(
    controller: controller,
    color: Colors.purpleAccent,
  ),
)

4. Clean Up #

@override
void dispose() {
  controller.dispose();
  super.dispose();
}

Complete Example #

import 'package:flutter/material.dart';
import 'package:audify/audify.dart';
import 'package:permission_handler/permission_handler.dart';

class VisualizerPage extends StatefulWidget {
  @override
  State<VisualizerPage> createState() => _VisualizerPageState();
}

class _VisualizerPageState extends State<VisualizerPage> {
  late AudifyController _controller;
  bool _isInitialized = false;

  @override
  void initState() {
    super.initState();
    _controller = AudifyController();
    _initialize();
  }

  Future<void> _initialize() async {
    // Request permission
    final status = await Permission.microphone.request();
    if (!status.isGranted) return;

    // Initialize and start
    await _controller.initialize(audioSessionId: 0);
    await _controller.startCapture();
    
    setState(() => _isInitialized = true);
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.black,
      body: Center(
        child: _isInitialized
            ? SizedBox(
                width: 300,
                height: 300,
                child: CircularSpectrumVisualizer(
                  controller: _controller,
                  color: Colors.purpleAccent,
                  barCount: 40,
                ),
              )
            : CircularProgressIndicator(),
      ),
    );
  }
}

Visualizer Widgets #

Circular Spectrum #

// Wrap in SizedBox to control size
SizedBox(
  width: 300,
  height: 300,
  child: CircularSpectrumVisualizer(
    controller: _controller,
    color: Colors.purpleAccent,
    glowColor: Colors.purple.withValues(alpha: 0.6),
    barCount: 40,
    barWidth: 2.0,
    gap: 2.0,
    smoothing: 0.7,  
    centerImage: AssetImage('assets/album_art.png'), // Optional album artwork
  ),
)

Properties:

  • controller (required): AudifyController - Controls the audio data stream
  • color: Color - Primary color of the visualizer bars (default: Colors.purpleAccent)
  • glowColor: Color? - Glow effect color (default: primary color with 50% opacity)
  • barCount: int - Number of bars in the circle (default: 40)
  • barWidth: double - Width of each bar in pixels (default: 2.0)
  • gap: double - Gap between bars in pixels (default: 2.0)
  • smoothing: double - Smoothing factor 0.0-1.0, higher = smoother (default: 0.7)
  • centerImage: ImageProvider? - Optional image to display in the center (album artwork, logo, etc.)

Adaptive Sizing: The visualizer automatically adapts to its parent container size. Wrap it in a SizedBox, Container, or any sized widget to control dimensions. Works perfectly in both square and non-square containers.

Bar Spectrum #

// Wrap in SizedBox to control size
SizedBox(
  width: double.infinity,
  height: 200,
  child: BarSpectrumVisualizer(
    controller: _controller,
    color: Colors.cyan,
    glowColor: Colors.cyanAccent.withValues(alpha: 0.5),
    barWidth: 4.0,
    gap: 6.0,
    mirror: true,  // Mirror effect
    smoothing: 0.75,
    gradient: LinearGradient(
      colors: [Colors.blue, Colors.cyan, Colors.teal],
      begin: Alignment.bottomCenter,
      end: Alignment.topCenter,
    ),
  ),
)

Properties:

  • controller (required): AudifyController - Controls the audio data stream
  • color: Color - Primary color of the bars (default: Colors.purpleAccent)
  • glowColor: Color? - Glow effect color (default: primary color with 50% opacity)
  • gradient: Gradient? - Optional gradient to apply to bars (overrides color)
  • barCount: int - Number of frequency bars to display (default: 32)
  • barWidth: double - Width of each bar in pixels (default: 4.0)
  • gap: double - Gap between bars in pixels (default: 6.0)
  • smoothing: double - Smoothing factor 0.0-1.0, higher = smoother (default: 0.75)
  • mirror: bool - Enable mirror effect (default: false)

Adaptive Sizing: The visualizer automatically adapts to its parent container size. Use double.infinity for width or height to fill available space, or wrap in a SizedBox for precise control.

Advanced Usage #

Using Frequency Band Data #

// Listen to processed frequency bands
_controller.frequencyDataStream.listen((FrequencyData data) {
  print('Sub Bass: ${data.subBass}');
  print('Bass: ${data.bass}');
  print('Peak: ${data.peak}');
  print('Average: ${data.average}');
});

Using Raw FFT Data #

// Listen to raw FFT magnitudes
_controller.fftStream.listen((List<double> fft) {
  // Process FFT data yourself
  final magnitudes = fft; // 0.0 to 1.0
});

Custom Audio Session (Android) #

// For visualizing specific MediaPlayer
// Get audioSessionId from your MediaPlayer
final audioSessionId = audioPlayer.audioSessionId;

await _controller.initialize(audioSessionId: audioSessionId);

Frequency Bands #

The plugin extracts 7 frequency bands optimized for music visualization:

Band Frequency Range Description
Sub Bass 20-60 Hz Deep bass frequencies
Bass 60-250 Hz Bass and kick drums
Low Mids 250-500 Hz Low midrange
Mids 500-2000 Hz Vocals and instruments
High Mids 2000-4000 Hz Upper midrange
Presence 4000-6000 Hz Clarity and presence
Brilliance 6000-20000 Hz High frequencies

API Reference #

AudifyController #

Constructor

AudifyController({
  AudifyPlatform? platform,           // Optional: Custom platform for testing
  int minProcessIntervalMs = 16,      // Optional: Frame throttle interval (default: 16ms / ~60 FPS)
})

Parameters:

  • platform: Custom platform implementation (mainly for testing with mocks)
  • minProcessIntervalMs: Minimum milliseconds between FFT processing. Lower = smoother but more CPU usage

Methods

Method Parameters Description
initialize() audioSessionId, captureSize Initialize the visualizer
startCapture() - Start capturing audio data
stopCapture() - Stop capturing audio data
dispose() - Release all resources

Properties

Property Type Description
fftStream Stream<List<double>> Raw FFT magnitudes (0.0-1.0)
waveformStream Stream<List<double>> Raw waveform samples (-1.0-1.0)
frequencyDataStream Stream<FrequencyData> Processed frequency bands
isInitialized bool Initialization status
isCapturing bool Capture status

FrequencyData #

Access specific frequency bands:

data.subBass      // 20-60 Hz
data.bass         // 60-250 Hz
data.lowMids      // 250-500 Hz
data.mids         // 500-2000 Hz
data.highMids     // 2000-4000 Hz
data.presence     // 4000-6000 Hz
data.brilliance   // 6000-20000 Hz
data.peak         // Peak across all bands
data.average      // Average across all bands

Performance Optimization #

Configure Frame Throttling #

Control how frequently FFT data is processed to optimize CPU usage:

// Default: 16ms (~60 FPS)
final controller = AudifyController();

// Custom throttle interval (in milliseconds)
final controller = AudifyController(minProcessIntervalMs: 33);  // ~30 FPS - better battery life
final controller = AudifyController(minProcessIntervalMs: 16);  // ~60 FPS - smooth (default)
final controller = AudifyController(minProcessIntervalMs: 8);   // ~120 FPS - ultra smooth (higher CPU)

When to adjust:

  • Lower values (8-12ms): Ultra-smooth visualizations on powerful devices
  • Default (16ms): Balanced performance for most use cases
  • Higher values (25-33ms): Better battery life, still smooth enough for most music

Adjust Capture Size #

// Lower = faster, Higher = more detail
await _controller.initialize(captureSize: 1024);  // Fast
await _controller.initialize(captureSize: 4096);  // Detailed

Reduce Bar Count #

// Fewer bars = better performance
SizedBox(
  width: 300,
  height: 300,
  child: CircularSpectrumVisualizer(
    controller: controller,
    barCount: 30,  // Fast - fewer bars
  ),
)

SizedBox(
  width: 300,
  height: 300,
  child: CircularSpectrumVisualizer(
    controller: controller,
    barCount: 80,  // Detailed - more bars
  ),
)

Adjust Smoothing #

// Higher = smoother but less responsive
SizedBox(
  width: 300,
  height: 300,
  child: CircularSpectrumVisualizer(
    controller: controller,
    smoothing: 0.9,  // Very smooth
  ),
)

SizedBox(
  width: 300,
  height: 300,
  child: CircularSpectrumVisualizer(
    controller: controller,
    smoothing: 0.5,  // More responsive
  ),
)

Troubleshooting #

No visualization appears:

  • Ensure microphone permission is granted
  • Verify audio is playing on the device
  • Check that controller is initialized and started

Poor performance:

  • Reduce captureSize (e.g., 1024 or 512)
  • Lower barCount in visualizers
  • Increase smoothing value (0.7-0.9)

Permission errors:

  • Add permissions to AndroidManifest.xml (Android) or Info.plist (iOS)
  • Request runtime permission using permission_handler

Platform Differences #

iOS vs Android:

  • Android uses android.media.audiofx.Visualizer. audioSessionId: 0 targets the output mix when the OS/device permits it, and specific player session IDs can target individual sessions.
  • iOS uses AVAudioEngine and currently visualizes audio routed through the plugin-created engine.
  • Both platforms emit FFT and waveform streams normalized by the Dart controller.

Example App #

Run the complete example:

cd example
flutter run

Features all visualizer types with customization options.

License #

MIT License - see LICENSE file for details.

Made with ❤️ for the Flutter community

  • Native FFT processing on Android (Visualizer API) and iOS (AVAudioEngine + Accelerate framework)
  • Inspired by trap/dubstep music visualizers

Support #

If you find this package helpful, please give it a ⭐ on GitHub!

For bugs or feature requests, please open an issue.

4
likes
160
points
304
downloads

Documentation

API reference

Publisher

verified publishernabilfaris.id

Weekly Downloads

High-performance audio visualizer for Flutter with circular and bar spectrum displays. Native FFT processing on Android and iOS.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

flutter

More

Packages that depend on audify

Packages that implement audify