Audio Visualization
Learn how to use audio data
flutter_soloud provides real-time audio visualization capabilities through the AudioData
class. This allows you to access both FFT (Fast Fourier Transform) and wave data from the currently playing audio.
Setup
Before using audio visualization, you need to enable it. For optimal visualization performance, it's recommended to set an appropriate buffer size during initialization:
// Initialize with a smaller buffer size for better visualization performance
await SoLoud.instance.init(
// Default is 2048, smaller values = lower latency, it could be set also to 512.
// The smaller the buffer, the more likely the
// system hits buffer underruns (ie, the play head marches on but there's no
// data ready to be played) and the sound breaks down horribly. 1024 is a good
// compromise.
bufferSize: 1024,
);
SoLoud.instance.setVisualizationEnabled(true);
AudioData Class
The AudioData
class provides three different ways to acquire audio samples through the GetSamplesKind
enum:
GetSamplesKind.wave
- Get 256 floats of wave audio dataGetSamplesKind.linear
- Get data linearly: first 256 floats are FFT values, next 256 are wave samplesGetSamplesKind.texture
- Get data in a 2D matrix of 256 linear rows
Basic Example
Here's a minimal example of how to get audio data for visualization:
class AudioVisualizer extends StatefulWidget {
@override
State<AudioVisualizer> createState() => _AudioVisualizerState();
}
class _AudioVisualizerState extends State<AudioVisualizer> with SingleTickerProviderStateMixin {
late final Ticker ticker;
late final AudioData audioData;
@override
void initState() {
super.initState();
audioData = AudioData(GetSamplesKind.linear);
ticker = createTicker(_tick);
ticker.start();
}
@override
void dispose() {
ticker.stop();
audioData.dispose();
super.dispose();
}
void _tick(Duration elapsed) {
if (context.mounted) {
try {
audioData.updateSamples();
setState(() {});
} on Exception catch (e) {
debugPrint('$e');
}
}
}
@override
Widget build(BuildContext context) {
return SizedBox(
width: double.infinity,
height: 100,
child: CustomPaint(
painter: AudioVisualizerPainter(
samples: audioData.getAudioData(),
),
child: Container(),
),
);
}
}
Basic FFT Visualization Example
Here's a minimal implementation of an AudioVisualizerPainter that displays FFT data as vertical bars:
class AudioVisualizerPainter extends CustomPainter {
final Float32List samples;
final Paint barPaint;
AudioVisualizerPainter({
required this.samples,
}) : barPaint = Paint()..color = Colors.blue;
@override
void paint(Canvas canvas, Size size) {
if (samples.isEmpty) return;
// We're only interested in FFT data (first 256 values)
final fftData = samples.sublist(0, 256);
final barWidth = size.width / fftData.length;
for (var i = 0; i < fftData.length; i++) {
// FFT data typically contains values between 0.0 and 1.0
final barHeight = fftData[i] * size.height;
canvas.drawRect(
Rect.fromLTWH(
i * barWidth, // Left position
size.height - barHeight, // Top position (from bottom)
barWidth, // Width of each bar
barHeight, // Height of each bar
),
barPaint,
);
}
}
@override
bool shouldRepaint(covariant AudioVisualizerPainter oldDelegate) {
return true; // Always repaint when new data arrives
}
}
This creates a simple frequency spectrum analyzer where:
- Each bar represents one frequency band from the FFT data
- Bar height represents the amplitude of that frequency
- Bars are drawn from left to right, with lower frequencies on the left
Wave Data Only
final audioData = AudioData(GetSamplesKind.wave);
// Later in your code:
audioData.updateSamples();
final waveData = audioData.getAudioData(); // Returns 256 wave samples
Linear Data (FFT + Wave)
final audioData = AudioData(GetSamplesKind.linear);
// Later in your code:
audioData.updateSamples();
final samples = audioData.getAudioData();
final fftData = samples.sublist(0, 256); // FFT data
final waveData = samples.sublist(256, 512); // Wave data
2D Texture Data
final audioData = AudioData(GetSamplesKind.texture);
// Later in your code:
audioData.updateSamples();
final textureData = audioData.getAudioData(); // Returns 512x256 matrix
// Each row in the matrix contains 512 values:
// - First 256 values are FFT data
// - Last 256 values are wave data
// The matrix is updated on each call to updateSamples(),
// where the newest data is added at the top and older rows
// are shifted down
When using texture mode, every call to updateSamples()
will:
- Shift all existing rows down one position
- Add the newest FFT and wave data as a new row at the top
- The oldest row at the bottom will be discarded
This creates a history of audio data that can be used for waterfall-style visualizations or other time-based effects.
FFT Smoothing
To achieve smoother FFT visualization, you can use the setFftSmoothing
method:
// Set smoothing factor (0.0 to 1.0)
// 0.0 = no smoothing
// 1.0 = maximum smoothing
SoLoud.instance.setFftSmoothing(0.7);
Enhanced Visualization with audio_flux
For more advanced audio visualization features, consider using the audio_flux package, which provides additional visualization capabilities using also shaders.
Important Notes
- Always call
audioData.dispose()
when you no longer need the visualization to prevent memory leaks. - The visualization feature must be enabled using
setVisualizationEnabled(true)
. - Each call to
updateSamples()
updates the internal buffer with new audio data. - Use
alwaysReturnData: false
withgetAudioData()
to avoid processing the same data multiple times:
final samples = audioData.getAudioData(alwaysReturnData: false);