🕵️ SicherheitslückenHak5: Hackers Just Poisoned the Rust Supply Chain | Threat Wire(01.09.2026 um 14:00 Uhr)
🕵️ SicherheitslückenHak5: Hackers Found a Way Into Humanoid Robots | Threat Wire(04.09.2026 um 15:04 Uhr)
🔧 AI Nachrichten Bits und so #1021 (Passwort für Laufwerk)(31.08.2026 um 22:15 Uhr)
🔧 AI Nachrichten Bits und so #1022 (Wie Weißbier)(06.09.2026 um 20:39 Uhr)
🍏 iOS / Mac OSHue-App 6.0 ist da: das sind die Neuerungen(07.09.2026 um 17:21 Uhr)
🕵️ SicherheitslückenHak5: Hackers Just Poisoned the Rust Supply Chain | Threat Wire(01.09.2026 um 14:00 Uhr)
🕵️ SicherheitslückenHak5: Hackers Found a Way Into Humanoid Robots | Threat Wire(04.09.2026 um 15:04 Uhr)
🔧 AI Nachrichten Bits und so #1021 (Passwort für Laufwerk)(31.08.2026 um 22:15 Uhr)
🔧 AI Nachrichten Bits und so #1022 (Wie Weißbier)(06.09.2026 um 20:39 Uhr)
🍏 iOS / Mac OSHue-App 6.0 ist da: das sind die Neuerungen(07.09.2026 um 17:21 Uhr)

🔧 Programmierung 🕛 kürzlich 4 Min Lesezeit
0

Building an Audio Visualizer in Flutter

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht

Creating an engaging audio visualizer enhances the interactivity of any app. This guide will walk you through building a retro arcade-style rainbow visualizer using Flutter and the









Step 1: Setting Up the Visualizer



We start by creating a RainbowBlockVisualizer widget. This widget will dynamically render audio blocks based on FFT (Fast Fourier Transform) data. Here's the implementation:






RainbowBlockVisualizer Widget






CODE
import 'dart:math';
import 'package:flutter/material.dart';

class RainbowBlockVisualizer extends StatelessWidget {
final List<int> data;
final int maxSample;
final double blockHeight;
final double blockSpacing;

const RainbowBlockVisualizer({
super.key,
this.data = const [],
this.maxSample = 32,
this.blockHeight = 8,
this.blockSpacing = 1,
});

@override
Widget build(BuildContext context) {
return CustomPaint(
painter: AudioBlockPainter(
data: data,
blockHeight: blockHeight,
blockSpacing: blockSpacing,
maxSample: maxSample,
),
size: Size.infinite,
);
}
}









Custom Painter for Audio Blocks






CODE
class AudioBlockPainter extends CustomPainter {
final List<int> data;
final double blockHeight;
final double blockSpacing;
final int maxSample;

AudioBlockPainter({
required this.data,
required this.blockHeight,
required this.blockSpacing,
required this.maxSample,
});

int get dataLength => min(maxSample, data.length);

int getNumBlocks(int audioValue) {
return (audioValue / 255 * 32).round().clamp(1, 32);
}

Color getBlockColor(int barIndex, int blockIndex, int maxBlocks) {
final hue = (barIndex / dataLength) * 360;
const lightnessRange = 0.1;
final lightness = 0.6 +
(blockIndex / maxBlocks * lightnessRange).clamp(0.0, lightnessRange);
return HSLColor.fromAHSL(1, hue, 0.8, lightness).toColor();
}

@override
void paint(Canvas canvas, Size size) {
if (data.isEmpty) return;

final barWidth = size.width / dataLength;

for (int i = 0; i < dataLength; i++) {
final numBlocks = getNumBlocks(data[i]);
final barX = i * barWidth;

for (int j = 0; j < numBlocks; j++) {
final paint = Paint()..color = getBlockColor(i, j, numBlocks);

final blockY = size.height - ((j + 1) * (blockHeight + blockSpacing));

final rect = RRect.fromRectAndRadius(
Rect.fromLTWH(
barX + blockSpacing / 2,
blockY,
barWidth - blockSpacing,
blockHeight,
),
const Radius.circular(2),
);
canvas.drawRRect(rect, paint);

final highlightPaint = Paint()
..color = Colors.white.withOpacity(0.2)
..style = PaintingStyle.stroke
..strokeWidth = 1;
canvas.drawLine(
Offset(rect.left, rect.top),
Offset(rect.right, rect.top),
highlightPaint,
);
canvas.drawLine(
Offset(rect.left, rect.top),
Offset(rect.left, rect.bottom),
highlightPaint,
);

final shadowPaint = Paint()
..color = Colors.black.withOpacity(0.2)
..style = PaintingStyle.stroke
..strokeWidth = 1;
canvas.drawLine(
Offset(rect.right, rect.top),
Offset(rect.right, rect.bottom),
shadowPaint,
);
canvas.drawLine(
Offset(rect.left, rect.bottom),
Offset(rect.right, rect.bottom),
shadowPaint,
);
}
}
}

@override
bool shouldRepaint(AudioBlockPainter oldDelegate) {
return data != oldDelegate.data ||
blockHeight != oldDelegate.blockHeight ||
blockSpacing != oldDelegate.blockSpacing;
}
}












Step 2: Creating the Main Application






Main Function






CODE
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'rainbow_visualizer.dart';

void main() {
runApp(MaterialApp(
themeMode: ThemeMode.dark,
darkTheme: ThemeData.dark(useMaterial3: true),
home: const MyApp(),
));
}









MyApp Widget






CODE

class MyApp extends StatefulWidget {
const MyApp({super.key});

@override
State<MyApp> createState() {
return _MyAppState();
}
}

class _MyAppState extends State<MyApp> {
final audioPlayer = VisualizerPlayer();

final sources = [
"https://www.soundhelix.com/examples/mp3/SoundHelix-Song-4.mp3",
"https://files.testfile.org/AUDIO/C/M4A/sample1.m4a",
];
var sourceIndex = 0;

@override
void initState() {
super.initState();
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.dark);
audioPlayer.initialize();
audioPlayer.setDataSource(sources[sourceIndex]);
audioPlayer.addListener(onUpdate);
}

void onUpdate() {
if (audioPlayer.value.status == PlayerStatus.ready) {
audioPlayer.play(looping: true);
}
}

@override
void dispose() {
audioPlayer.removeListener(onUpdate);
audioPlayer.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Center(
child: Text('Audio Visualizer'),
),
),
body: Column(
children: [
const SizedBox(height: 32),
Padding(
padding: const EdgeInsets.all(8.0),
child: ListenableBuilder(
listenable: audioPlayer,
builder: (context, child) {
final duration = audioPlayer.value.duration;
final position = audioPlayer.value.position;
final durationText = formatDuration(duration);
final positionText = formatDuration(position);
return Text(
"$positionText / $durationText",
style: Theme.of(context).textTheme.headlineLarge,
);
},
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: ListenableBuilder(
listenable: audioPlayer,
builder: (context, child) {
return Text(
audioPlayer.value.status == PlayerStatus.playing
? "Now Playing"
: "",
style: Theme.of(context).textTheme.bodyLarge,
);
},
),
),
Expanded(
child: ListenableBuilder(
listenable: audioPlayer,
builder: (context, child) {
final data = getMagnitudes(audioPlayer.value.fft);
return AudioSpectrum(
fftMagnitudes: data,
bandType: BandType.tenBand,
builder: (context, value, child) {
return RainbowBlockVisualizer(
data: value.levels,
maxSample: 32,
blockHeight: 14,
);
},
);
},
),
),
ListenableBuilder(
listenable: audioPlayer,
builder: (context, child) {
final duration = audioPlayer.value.duration.inMilliseconds;
final position = audioPlayer.value.position.inMilliseconds;
return LinearProgressIndicator(
value: position / max(1, duration),
minHeight: 8,
);
},
),
],
),
bottomNavigationBar: BottomAppBar(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
IconButton(
icon: const Icon(Icons.play_arrow),
onPressed: () {
audioPlayer.play(looping: true);
},
),
IconButton(
icon: const Icon(Icons.pause),
onPressed: () {
audioPlayer.pause();
},
),
IconButton(
icon: const Icon(Icons.stop),
onPressed: () {
audioPlayer.stop();
},
),
IconButton(
icon: const Icon(Icons.loop),
onPressed: () {
sourceIndex = (sourceIndex + 1) % sources.length;
audioPlayer.stop();
audioPlayer.setDataSource(sources[sourceIndex]);
},
),
],
),
),
);
}
}

String formatDuration(Duration duration) {
final minutes = duration.inMinutes;
final seconds = duration.inSeconds.remainder(60).toString().padLeft(2, '0');
return "$minutes:$seconds";
}












Final Notes



This app integrates the audio_visualizer package to transform FFT data into a visually appealing audio spectrum. Experiment with different colors, block sizes, and spacing for unique designs!

Vollständiger Original-Bericht
Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 0%
🟡 In Evaluierung 0%
🟢 Keine Auswirkung 0%
Spannende Innovation 0%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
1 Quelle
Hackers Just Poisoned the Rust Supply Chain | Threat Wire
1 Quelle
Hackers Found a Way Into Humanoid Robots | Threat Wire
1 Quelle
Bits und so #1021 (Passwort für Laufwerk)
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Building an Audio Visualizer in Flutter

Thematisch verwandte Begriffe: Building, Audio, Visualizer, Flutter · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...