Flutter音频可视化插件audio_visualizer的使用

发布于 1周前 作者 sinazl 来自 Flutter

Flutter音频可视化插件 audio_visualizer 的使用

audio_visualizer 是一个用于在Flutter应用中无缝可视化音频的插件。它支持从文件、资源、HTTP流、麦克风输入和原始PCM16数据中获取音频并进行可视化。

特性

  • Visualize File:支持从本地文件加载音频
  • Visualize Asset:支持从Flutter资产文件中加载音频
  • Visualize HTTP:支持从网络URL加载音频
  • Visualize Microphone:支持从麦克风输入音频(需配合其他插件使用)
  • Visualize Raw PCM16:支持从原始PCM16数据中加载音频

组件概述

该插件提供了三个主要组件:

  1. VisualizerPlayer:用于从文件、资源和HTTP流中加载并播放音频。
  2. PCMVisualizer:用于从自定义源加载并处理原始PCM16数据。

预构建的可视化样式和波段类型

预构建的可视化样式

  • BarVisualizer
  • CircleVisualizer
  • LineVisualizer
  • MultiWaveVisualizer
  • RainbowBlockVisualizer

波段类型

  • fourBand
  • fourBandVisual
  • eightBand
  • tenBand
  • twentySixBand
  • thirtyOneBand

如何使用

从音频文件中可视化

你可以通过以下前缀来加载音频:

  • Assets: asset://path_to_asset
  • Files: file://path_to_file
  • HTTP: http://urlhttps://url

示例代码

import 'package:audio_visualizer/audio_visualizer.dart';
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  [@override](/user/override)
  _MyAppState createState() => _MyAppState();
}

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

  [@override](/user/override)
  void initState() {
    super.initState();
    initAudioPlayer();
  }

  Future<void> initAudioPlayer() async {
    await audioPlayer.initialize();
    await audioPlayer.setDataSource("asset://assets/sample.mp3");
    await audioPlayer.play();
  }

  [@override](/user/override)
  void dispose() {
    audioPlayer.dispose();
    super.dispose();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Audio Visualizer Demo'),
        ),
        body: Center(
          child: ListenableBuilder(
            listenable: audioPlayer,
            builder: (context, child) {
              return BarVisualizer(
                input: audioPlayer.value.waveform,
                backgroundColor: Colors.black,
                color: Colors.greenAccent,
                gap: 2,
              );
            },
          ),
        ),
      ),
    );
  }
}

可视化麦克风输入

要从麦克风输入音频,可以结合 record 插件使用。首先捕获音频数据,然后将其传递给 PCMVisualizer

示例代码

import 'package:audio_visualizer/audio_visualizer.dart';
import 'package:flutter/material.dart';
// 假设你已经添加了 record 插件,并且导入了相关包

final pcmVisualizer = PCMVisualizer();

// 在捕获到音频数据后调用
pcmVisualizer.feed(rawPCM16Data);

[@override](/user/override)
Widget build(BuildContext context) {
  return Scaffold(
    body: Center(
      child: ListenableBuilder(
        listenable: pcmVisualizer,
        builder: (context, child) {
          return BarVisualizer(
            input: pcmVisualizer.value.waveform,
            backgroundColor: Colors.black,
            color: Colors.greenAccent,
            gap: 2,
          );
        },
      ),
    ),
  );
}

[@override](/user/override)
void dispose() {
  pcmVisualizer.dispose();
  super.dispose();
}

权限

在Android上,需要以下权限来可视化音频:

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

完整示例Demo

以下是一个完整的示例项目,展示了如何使用 audio_visualizer 插件来实现音频可视化功能。

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

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

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

  [@override](/user/override)
  State<MyApp> createState() => _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](/user/override)
  void initState() {
    super.initState();
    audioPlayer.initialize().then((_) {
      audioPlayer.setDataSource(sources[sourceIndex]);
      audioPlayer.addListener(onUpdate);
    });
  }

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

  [@override](/user/override)
  void dispose() {
    audioPlayer.removeListener(onUpdate);
    audioPlayer.dispose();
    super.dispose();
  }

  [@override](/user/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 RainbowBlockVisualizer(
                  data: data,
                  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";
  }
}

更多关于Flutter音频可视化插件audio_visualizer的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter音频可视化插件audio_visualizer的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter项目中使用audio_visualizer插件来实现音频可视化的代码案例。这个插件允许你从音频流中提取频率数据并显示在自定义的Widget上。

首先,确保你已经在pubspec.yaml文件中添加了audio_visualizer依赖:

dependencies:
  flutter:
    sdk: flutter
  audio_visualizer: ^0.0.8  # 请注意版本号,使用最新版本

然后运行flutter pub get来安装依赖。

接下来,你可以按照以下步骤在你的Flutter应用中实现音频可视化:

  1. 导入必要的包
import 'package:flutter/material.dart';
import 'package:audio_visualizer/audio_visualizer.dart';
import 'package:audioplayers/audioplayers.dart';

注意:audio_visualizer依赖于audioplayers包来播放音频,所以你也需要添加audioplayers依赖。

  1. 创建音频播放器并初始化可视化器
void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Audio Visualizer Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: AudioVisualizerScreen(),
    );
  }
}

class AudioVisualizerScreen extends StatefulWidget {
  @override
  _AudioVisualizerScreenState createState() => _AudioVisualizerScreenState();
}

class _AudioVisualizerScreenState extends State<AudioVisualizerScreen> {
  final AudioPlayer audioPlayer = AudioPlayer();
  late AudioVisualizer visualizer;

  @override
  void initState() {
    super.initState();

    // 初始化AudioVisualizer
    visualizer = AudioVisualizer()
      ..fftSize = 512 // 设置FFT大小
      ..updateFrequencyData = (List<double> data) {
        // 这里你可以处理频率数据,例如更新UI
        setState(() {}); // 触发UI更新(如果有UI需要基于这些数据更新)
      };

    // 播放音频文件(确保替换为你的音频URL)
    audioPlayer.play('https://example.com/your-audio-file.mp3');

    // 启动可视化器
    visualizer.start(audioPlayer.playerId);
  }

  @override
  void dispose() {
    // 停止可视化器和音频播放器
    visualizer.stop();
    audioPlayer.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Audio Visualizer Demo'),
      ),
      body: Center(
        child: CustomVisualizerWidget(), // 自定义的可视化Widget
      ),
    );
  }
}
  1. 创建自定义的可视化Widget
class CustomVisualizerWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // 这里你可以根据从visualizer获取的频率数据来绘制可视化效果
    // 由于我们没有直接访问到这些数据,这里只是一个简单的示例
    return Container(
      width: double.infinity,
      height: 200,
      color: Colors.black,
      child: CustomPaint(
        painter: VisualizerPainter(), // 自定义Painter来绘制可视化效果
      ),
    );
  }
}

class VisualizerPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = Colors.green
      ..strokeWidth = 2.0
      ..isAntiAlias = true;

    // 绘制简单的波形(这里只是示例,实际应基于频率数据绘制)
    double offsetX = 0.0;
    for (int i = 0; i < size.width * 2; i++) {
      double offsetY = size.height / 2 + (sin(i / 10.0) * 20.0);
      if (i == 0) {
        canvas.drawLine(Offset(offsetX, offsetY), Offset(offsetX + 1, offsetY), paint);
      } else {
        canvas.drawLine(Offset(offsetX - 1, offsetY - 1), Offset(offsetX, offsetY), paint);
      }
      offsetX += 1.0;
    }
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    // 在实际情况下,这里应该根据频率数据的变化来决定是否需要重绘
    return false;
  }
}

注意:上面的VisualizerPainter只是一个简单的波形绘制示例,并没有真正使用从audio_visualizer获取的频率数据。在实际应用中,你需要根据visualizer.updateFrequencyData回调中的频率数据来动态绘制可视化效果。

这个代码案例提供了一个基础框架,你可以在此基础上根据具体需求进行扩展和自定义。

回到顶部