iT邦幫忙

0

請教Flutter中如何使用FFTea套件?

不明 2023-04-07 00:13:06931 瀏覽
  • 分享至 

  • xImage

我在使用flutter中遇到了FFT使用方式的問題,我想要請問各位要如何解決下面這些問題,先提前致謝各位,感謝各位的協助和建議。/images/emoticon/emoticon41.gif

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();
  }
}

/images/emoticon/emoticon31.gif

圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友回答

立即登入回答