Flutter快速傅里叶变换插件flutter_fft的使用
Flutter快速傅里叶变换插件flutter_fft的使用
插件在pub.dev上
该插件可以在以下链接找到:
https://pub.dev/packages/flutter_fft
警告: 目前仅支持Android!该插件利用了平台通道,但目前只有Java/Android平台通道被实现。
插件是在Pixel 2模拟器(API 29)上开发的,并在实际的Pixel 2设备(Android 11)和另一台Pixel 2模拟器(API 30)上进行了测试。目前不支持iOS,因为尚未实现平台通道。
最小SDK版本 >= 24:你可以在"/android/app/build.gradle"
文件中更新最小SDK要求,将minSdkVersion 16
改为minSdkVersion 24
。
在你的项目中的"android/app/src/main/AndroidManifest.xml"
文件中,需要添加以下权限:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
这是我的第一个(也是目前唯一的一个)Flutter插件和Java项目。
我在为个人吉他调音器应用收集想法时,意识到在Flutter中找不到任何音频分析/处理/操作的示例。由于Flutter刚开始流行,因此围绕它的实际项目或示例还很少。
最后,我想到的办法是为Android编写一个平台通道,这基本上是一种从Flutter内部调用原生代码的方式——即通过Dart代码调用Java函数。
问题在于,由于它调用了原生平台代码,因此“单一代码库”的Flutter特性变得无用,因为我必须为两个平台编写相同的功能(iOS使用Objective-C/Swift,而Android使用Java/Kotlin)。因此,目前我只实现了Android平台通道。
如何使用
如上所述,该插件最初是为了在我的个人项目中使用而开发的,但我找不到类似的实现,所以我决定在这里上传它,以防其他人也遇到同样的问题。
由于这个原因,你可以使用插件的功能非常严格:开始录音,从平台通道获取数据,然后停止录音。
如果你会编程,你可以轻松地修改代码以满足自己的需求。
有很多用于处理和默认数据的getter和setter,这些将在下面讨论。
简单示例:
import 'package:flutter/material.dart';
import 'package:flutter_fft/flutter_fft.dart';
void main() => runApp(Application());
class Application extends StatefulWidget {
[@override](/user/override)
ApplicationState createState() => ApplicationState();
}
class ApplicationState extends State<Application> {
double? frequency;
String? note;
int? octave;
bool? isRecording;
FlutterFft flutterFft = new FlutterFft();
_initialize() async {
print("Starting recorder...");
// print("Before");
// bool hasPermission = await flutterFft.checkPermission();
// print("After: " + hasPermission.toString());
// Keep asking for mic permission until accepted
while (!(await flutterFft.checkPermission())) {
flutterFft.requestPermission();
// IF DENY QUIT PROGRAM
}
// await flutterFft.checkPermissions();
await flutterFft.startRecorder();
print("Recorder started...");
setState(() => isRecording = flutterFft.getIsRecording);
flutterFft.onRecorderStateChanged.listen(
(data) => {
print("Changed state, received: $data"),
setState(
() => {
frequency = data[1] as double,
note = data[2] as String,
octave = data[5] as int,
},
),
flutterFft.setNote = note!,
flutterFft.setFrequency = frequency!,
flutterFft.setOctave = octave!,
print("Octave: ${octave!.toString()}")
},
onError: (err) {
print("Error: $err");
},
onDone: () => {print("Isdone")});
}
[@override](/user/override)
void initState() {
isRecording = flutterFft.getIsRecording;
frequency = flutterFft.getFrequency;
note = flutterFft.getNote;
octave = flutterFft.getOctave;
super.initState();
_initialize();
}
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: "Simple flutter fft example",
theme: ThemeData.dark(),
color: Colors.blue,
home: Scaffold(
backgroundColor: Colors.purple,
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
isRecording!
? Text("Current note: ${note!},${octave!.toString()}",
style: TextStyle(fontSize: 30))
: Text("Not Recording", style: TextStyle(fontSize: 35)),
isRecording!
? Text(
"Current frequency: ${frequency!.toStringAsFixed(2)}",
style: TextStyle(fontSize: 30))
: Text("Not Recording", style: TextStyle(fontSize: 35))
],
),
),
));
}
}
更多关于Flutter快速傅里叶变换插件flutter_fft的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter快速傅里叶变换插件flutter_fft的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何使用Flutter中的flutter_fft
插件进行快速傅里叶变换(FFT)的代码案例。这个插件允许你对音频信号进行频域分析。
首先,确保你已经在pubspec.yaml
文件中添加了flutter_fft
依赖:
dependencies:
flutter:
sdk: flutter
flutter_fft: ^x.x.x # 请替换为最新版本号
然后,运行flutter pub get
来安装依赖。
以下是一个完整的Flutter应用程序示例,它展示了如何使用flutter_fft
插件对生成的简单正弦波信号进行FFT分析:
import 'package:flutter/material.dart';
import 'package:flutter_fft/flutter_fft.dart';
import 'dart:typed_data';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter FFT Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: FFTExampleScreen(),
);
}
}
class FFTExampleScreen extends StatefulWidget {
@override
_FFTExampleScreenState createState() => _FFTExampleScreenState();
}
class _FFTExampleScreenState extends State<FFTExampleScreen> {
List<double> _timeDomainData = [];
List<Complex> _frequencyDomainData = [];
FFT _fft = FFT(1024); // 1024 points FFT
@override
void initState() {
super.initState();
_generateTimeDomainData();
_performFFT();
}
void _generateTimeDomainData() {
final sampleRate = 44100.0; // Sampling rate in Hz
final frequency = 440.0; // A4 note in Hz
final duration = 2.0; // Duration in seconds
final t = List.generate(1024, (i) => i / sampleRate);
_timeDomainData = t.map((time) => 0.5 * math.sin(2 * math.pi * frequency * time)).toList();
}
void _performFFT() {
final Float32List realInput = Float32List.fromList(_timeDomainData);
final Float32List imagInput = Float32List.filled(1024, 0.0); // Imaginary part is zero for real signals
final ComplexList input = ComplexList.fromRealAndImag(realInput, imagInput);
final ComplexList output = _fft.forwardTransform(input);
setState(() {
_frequencyDomainData = output.toList();
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter FFT Example'),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Time Domain Data:'),
Text('${_timeDomainData.sublist(0, 10).join(", ")}...'), // Display first 10 samples for brevity
SizedBox(height: 20),
Text('Frequency Domain Data:'),
Text('Magnitudes: ${_frequencyDomainData.map((c) => c.magnitude.toStringAsFixed(2)).join(", ")}...'),
],
),
);
}
}
解释
- 依赖添加:在
pubspec.yaml
中添加flutter_fft
依赖。 - 生成时域数据:在
_generateTimeDomainData
方法中,生成一个简单的正弦波信号作为时域数据。这里我们生成了一个440Hz(A4音)的正弦波,持续2秒,采样率为44100Hz。 - 执行FFT:在
_performFFT
方法中,将生成的时域数据转换为复数列表(实部为信号值,虚部为0),然后执行FFT变换。结果存储在_frequencyDomainData
中。 - 显示结果:在UI中显示时域数据和频域数据的部分样本。为了简洁起见,这里只显示了时域数据的前10个样本和频域数据的幅度值。
这个示例展示了如何使用flutter_fft
插件进行基本的FFT分析。你可以根据具体需求对代码进行修改和扩展,例如处理来自麦克风的实时音频数据,或绘制频域数据的图形表示。