我在使用flutter中遇到了FFT使用方式的問題,我想要請問各位要如何解決下面這些問題,先提前致謝各位,感謝各位的協助和建議。
flutter中我使用三個主要套件
接收麥克風的音訊流
我原本使用mic_stream取得音訊流,我在mic_stream的設定是這樣
stream = await MicStream.microphone(
sampleRate: 44100,
audioSource: AudioSource.DEFAULT,
audioFormat: AudioFormat.ENCODING_PCM_16BIT,
channelConfig: ChannelConfig.CHANNEL_IN_MONO,
);
設定完成後我將stream的資料做FFT處理,以下是我使用FFT套件的代碼,但結果的值我發現不會因為我發送18kHz的頻率,強度的數值不會比較高。
import 'dart:async';
import 'dart:typed_data';
import 'package:fft/fft.dart';
import 'package:flutter/material.dart';
import 'package:mic_stream/mic_stream.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Receiver(),
),
);
}
}
class Receiver extends StatefulWidget {
const Receiver({Key? key}) : super(key: key);
@override
State<Receiver> createState() => _ReceiverState();
}
class _ReceiverState extends State<Receiver> {
Stream? stream;
StreamSubscription? streamSubscription;
@override
void initState() {
// TODO: implement initState
super.initState();
startMicrophone();
}
Future<void> startMicrophone() async {
stream = await MicStream.microphone(
sampleRate: 44100,
audioSource: AudioSource.DEFAULT,
audioFormat: AudioFormat.ENCODING_PCM_16BIT,
channelConfig: ChannelConfig.CHANNEL_IN_MONO,
);
streamSubscription = stream?.listen((samples) {
_detectFrequencyStrength(samples);
// print(samples);
});
}
void _detectFrequencyStrength(Uint8List buffer) async{
Float32List audioSamples = await Float32List.view(buffer.buffer);
// 因為 audioSamples 會出現 NaN 所以下面這個 for 是將 NaN 轉為 0.0數值。
for (int i = 0; i < audioSamples.length; i++) {
if (audioSamples[i].isNaN) {
audioSamples[i] = 0.0;
}
}
List<double> input = audioSamples.map((sample) => sample.toDouble()).toList();
// 這個 if 是因為 FFT 套件的FFT功能只接受長度為2的冪,如果不是會無法計算。
if (!_isPowerOfTwo(input.length)) {
input = _padToPowerOfTwo(input);
}
List<Complex> output = FFT().Transform(input);
int sampleRate = 44100; // 設定採樣率
double targetFrequency = 18000; // 目標頻率
int targetIndex = (targetFrequency * output.length / sampleRate).round(); // 計算在頻譜中他的index多少
print(output[targetIndex]);
}
bool _isPowerOfTwo(int value) {
return (value & (value - 1)) == 0;
}
List<double> _padToPowerOfTwo(List<double> data) {
int targetLength = 1;
while (targetLength < data.length) {
targetLength *= 2;
}
List<double> paddedData = List<double>.from(data);
paddedData.addAll(List<double>.filled(targetLength - data.length, 0.0));
return paddedData;
}
@override
Widget build(BuildContext context) {
return const Placeholder();
}
}
這是我目前使用fftea套件來將麥克風音訊流做處理的代碼,但我不太會使用這個套件,官方的文件我也不太理解,所以我主要是想要問fftea套件要如何使用,如果是以我想要監測某個頻率點的強度的話,我該如何下手或是有甚麼資源可以學習嗎?
import 'dart:async';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:mic_stream/mic_stream.dart';
import 'package:fftea/fftea.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Receiver(),
),
);
}
}
class Receiver extends StatefulWidget {
const Receiver({Key? key}) : super(key: key);
@override
State<Receiver> createState() => _ReceiverState();
}
class _ReceiverState extends State<Receiver> {
Stream? stream;
StreamSubscription? streamSubscription;
@override
void initState() {
// TODO: implement initState
super.initState();
startMicrophone();
}
Future<void> startMicrophone() async {
stream = await MicStream.microphone(
sampleRate: 44100,
audioSource: AudioSource.DEFAULT,
audioFormat: AudioFormat.ENCODING_PCM_16BIT,
channelConfig: ChannelConfig.CHANNEL_IN_MONO,
);
streamSubscription = stream?.listen((samples) {
detectFrequncy(samples);
// print(samples);
});
}
void detectFrequncy(Uint8List buffer) async {
var floatArray = convertUint8ListToFloat32List(buffer);
final fft = FFT(floatArray.length);
final freq = fft.realFft(floatArray);
print(freq);
}
Float32List convertUint8ListToFloat32List(Uint8List uint8List) {
final length = uint8List.length;
Float32List float32List = Float32List(length);
for (int i = 0; i < length; i++) {
// 將8位元的PCM值轉換為介於-1.0和1.0之間的浮點值
float32List[i] = (uint8List[i] - 128) / 128;
}
return float32List;
}
@override
Widget build(BuildContext context) {
return const Placeholder();
}
}