123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- import 'dart:async';
- import 'package:flutter/material.dart';
- import 'package:flutter_sound/flutter_sound.dart';
- /// 麦克风输入可视化
- class MicrophoneWave extends StatefulWidget {
- final FlutterSoundRecorder recorder;
- final VoidCallback onAutoDetectPass;
- final double width;
- final double height;
- final bool isRecording;
- MicrophoneWave({
- required this.recorder,
- required this.isRecording,
- required this.onAutoDetectPass,
- this.width = 250.0,
- this.height = 40.0,
- });
- @override
- _MicrophoneWaveState createState() => _MicrophoneWaveState();
- }
- class _MicrophoneWaveState extends State<MicrophoneWave>
- with SingleTickerProviderStateMixin {
- late AnimationController _controller;
- late Animation<double> _animation;
- StreamSubscription? _recorderSubscription;
- List<double> _loudnessValues = [];
- int autoDetectCount = 0;
- static const int autoDetectThreshold = 10;
- @override
- void initState() {
- super.initState();
- _controller = AnimationController(
- vsync: this,
- duration: Duration(milliseconds: 50),
- );
- _animation = Tween<double>(begin: 0.0, end: 1.0).animate(_controller)
- ..addListener(() {
- setState(() {});
- });
- _recorderSubscription =
- widget.recorder.onProgress!.listen((RecordingDisposition e) {
- /// 输出响度,响度范围是0-120
- /// 0表示没有声音,120表示最大声音
- final loudness = ((e.decibels ?? 0) + 5) / 120;
- if (loudness > 0.2) {
- autoDetectCount++;
- }
- if (autoDetectCount > autoDetectThreshold) {
- autoDetectCount = 0;
- widget.onAutoDetectPass.call();
- }
- setState(() {
- _loudnessValues.add(loudness);
- });
- if (_loudnessValues.length > widget.width) {
- _loudnessValues.removeAt(0);
- }
- _controller.forward(from: 0.0);
- }, onError: (err) {
- print('onError: $err');
- });
- }
- @override
- void didUpdateWidget(covariant MicrophoneWave oldWidget) {
- super.didUpdateWidget(oldWidget);
- if (oldWidget.isRecording != widget.isRecording) {
- if (widget.isRecording) {
- _loudnessValues.clear();
- }
- }
- }
- @override
- void dispose() {
- super.dispose();
- _controller.dispose();
- _recorderSubscription?.cancel();
- _recorderSubscription = null;
- }
- @override
- Widget build(BuildContext context) {
- return Container(
- width: widget.width,
- height: widget.height,
- child: Row(
- crossAxisAlignment: CrossAxisAlignment.center,
- children: [
- Text(
- "麦克风输入:",
- style: TextStyle(
- height: 1,
- color: Colors.black87,
- ),
- ),
- Expanded(
- child: ClipPath(
- child: CustomPaint(
- painter: _MicrophoneVisualizerPainter(
- loudnessList: _loudnessValues,
- animationValue: _animation.value,
- isRecording: widget.isRecording,
- ),
- size: Size(widget.width, widget.height),
- ),
- )),
- ],
- ),
- );
- }
- }
- class _MicrophoneVisualizerPainter extends CustomPainter {
- final List<double> loudnessList;
- final double animationValue;
- final bool isRecording;
- _MicrophoneVisualizerPainter({
- required this.loudnessList,
- required this.animationValue,
- this.isRecording = false,
- });
- @override
- void paint(Canvas canvas, Size size) {
- final double sampleStep = 5.0;
- final offsetX = sampleStep * animationValue;
- final double centerY = size.height / 2;
- Paint linePaint = Paint()
- ..color = Colors.grey
- ..strokeWidth = 1.0;
- /// 绘制中轴线
- canvas.drawLine(Offset(0, centerY), Offset(size.width, centerY), linePaint);
- if (!isRecording) return;
- linePaint = Paint()
- ..color = Colors.blue
- ..strokeWidth = 2.0;
- for (int i = 0; i < loudnessList.length; i++) {
- final loudness = loudnessList[loudnessList.length - i - 1];
- final x = i * sampleStep + offsetX;
- final y = centerY + loudness * centerY;
- final y2 = centerY - loudness * centerY;
- canvas.drawLine(Offset(x, y), Offset(x, y2), linePaint);
- }
- }
- @override
- bool shouldRepaint(_MicrophoneVisualizerPainter oldDelegate) {
- return oldDelegate.animationValue != animationValue;
- }
- }
|