Flutter 颤振节拍器应用程序滞后并在值更改时更新值

Flutter 颤振节拍器应用程序滞后并在值更改时更新值,flutter,dart,Flutter,Dart,作为Flatter中的第一个应用程序,我想构建一个节拍器应用程序。UI已经构建好了,但实际的metronome功能仍然存在以下问题: 有时,节拍器有点滞后,刚好足够,所以你会注意到它。在颤振中是否有一种方法可以达到节拍器100%的精度 播放时不更改细分(必须停止并启动节拍器)。如果值“tempo”和“subsection”发生更改,如何将它们自动应用于metronome订阅?我知道Flatter提供了Listenable、Stream、InheritedWidget等工具,但我还没有找到在现

作为Flatter中的第一个应用程序,我想构建一个节拍器应用程序。UI已经构建好了,但实际的metronome功能仍然存在以下问题:

  • 有时,节拍器有点滞后,刚好足够,所以你会注意到它。在颤振中是否有一种方法可以达到节拍器100%的精度

  • 播放时不更改细分(必须停止并启动节拍器)。如果值“tempo”和“subsection”发生更改,如何将它们自动应用于metronome订阅?我知道Flatter提供了Listenable、Stream、InheritedWidget等工具,但我还没有找到在现有代码中实现这些工具的方法

用户界面的透视图:

以下是代码(并非完全由我编写->学分):

导入“dart:io”显示文件;
导入“dart:async”;
进口“包装:颤振/cupertino.dart”;
导入“包:quiver/async.dart”;
“导入”包:AudioPlayer/AudioPlayer.dart“显示AudioPlayer;
导入“包:flatter/services.dart”显示ByteData、rootBundle;
导入“package:path\u provider/path\u provider.dart”显示getTemporaryDirectory;
//作品:《安迪曲》,https://stackoverflow.com/questions/51048402/flutter-audioplayers-or-metronome-lagging
ValueNotifier tempo=ValueNotifier(100);
int=1;
布尔显示=假;
int soundIndex=1;
文件\u声音文件;
流动认购(流动认购);;
Future\u loadSound()异步{
返回wait-rootBundle.load('assets/sounds/sound_u$soundIndex.wav');
}
void\u writeSound()异步{
_声音文件(
“${(wait getTemporaryDirectory()).path}/sounds/sound_$soundIndex.wav”);
wait_soundFile.writeAsBytes((wait_loadSound()).buffer.asUint8List());
打印(“_writesoundexecuted”);
}
void\u playLocal()异步{
最终音频播放器_AudioPlayer=AudioPlayer();
AudioPlayer.logEnabled=false;
wait_audioPlayer.play(_soundFile.path,isLocal:true);
}
///播放节拍器的实际方法
无效播放暂停(){
打印(“播放暂停触发”);
如果(_soundFile==null){
打印(“_soundFile=null-->soundFile write”);
_writeSound();
}
如果(显示){
_订阅。取消();
isplay=false;
打印(“节拍器停止”);
}否则{
_订阅=节拍器周期(新持续时间)(
毫秒:(60000/(节拍值*细分)).floor())
.听((d)=>_playLocal());
isplay=true;
打印(“节拍器启动”);
}
}
无效递增速度(int tempochange){
速度值=速度值+速度变化;
如果(显示){
_订阅。取消();
打印(“取消订阅”);
_订阅=节拍器周期(新持续时间)(
毫秒:(60000/(节拍值*细分)).floor())
.听((d)=>_playLocal());
}
打印(“节奏更改为${tempo.value}”);
}
无效递减速度(内部速度变化){
tempo.value=tempo.value-tempochange;
如果(显示){
_订阅。取消();
打印(“取消订阅”);
_订阅=节拍器周期(新持续时间)(
毫秒:(60000/(节拍值*细分)).floor())
.听((d)=>_playLocal());
}
打印(“节奏更改为${tempo.value}”);
}

用户界面的内容似乎没有完整的代码。您可能有一个StreamBuilder在监听您的流?当你的“节奏”和“细分”发生变化时,你想让构建者重新构建?有几种实现方法,但最好的可能是提供程序包。看看ChangeNotifierProviderThanks,我会慎重考虑这一点。现在,我正在使用ValueListenableBuilder来监听节奏的任何值变化。我的问题还与StreamSubscription的性能/滞后问题有关-是否有任何方法可以绝对确保声音按时播放(精确到毫秒)?您的UI内容中似乎没有完整的代码。您可能有一个StreamBuilder在监听您的流?当你的“节奏”和“细分”发生变化时,你想让构建者重新构建?有几种实现方法,但最好的可能是提供程序包。看看ChangeNotifierProviderThanks,我会慎重考虑这一点。现在,我正在使用ValueListenableBuilder来监听节奏的任何值变化。我的问题也是关于StreamSubscription的性能/滞后问题-是否有任何方法绝对确保声音按时播放(精确到毫秒)?
import 'dart:io' show File;
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:quiver/async.dart';
import 'package:audioplayers/audioplayers.dart' show AudioPlayer;
import 'package:flutter/services.dart' show ByteData, rootBundle;
import 'package:path_provider/path_provider.dart' show getTemporaryDirectory;

//credits: "Andi Qu", https://stackoverflow.com/questions/51048402/flutter-audioplayers-or-metronome-lagging

ValueNotifier<int> tempo = ValueNotifier(100);
int subdivision = 1;
bool isPlaying = false;

int soundIndex = 1;
File _soundFile;

StreamSubscription<DateTime> _subscription;

Future<ByteData> _loadSound() async {
  return await rootBundle.load('assets/sounds/sound_$soundIndex.wav');
}

void _writeSound() async {
  _soundFile = File(
      '${(await getTemporaryDirectory()).path}/sounds/sound_$soundIndex.wav');
  await _soundFile.writeAsBytes((await _loadSound()).buffer.asUint8List());
  print("_writeSound executed");
}

void _playLocal() async {
  final AudioPlayer _audioPlayer = AudioPlayer();
  AudioPlayer.logEnabled = false;
  await _audioPlayer.play(_soundFile.path, isLocal: true);
}

/// The actual method that plays the metronome

void playpause() {
  print("playpause triggered");
  if (_soundFile == null) {
    print("_soundFile = null ---> Soundfile written");
    _writeSound();
  }

  if (isPlaying) {
    _subscription.cancel();
    isPlaying = false;
    print("metronome stopped");
  } else {
    _subscription = Metronome.periodic(new Duration(
            milliseconds: (60000 / (tempo.value * subdivision)).floor()))
        .listen((d) => _playLocal());
    isPlaying = true;
    print("metronome started");
  }
}

void increasetempo(int tempochange) {
  tempo.value = tempo.value + tempochange;

  if (isPlaying) {
    _subscription.cancel();
    print("_subscription canceled");
    _subscription = Metronome.periodic(new Duration(
            milliseconds: (60000 / (tempo.value * subdivision)).floor()))
        .listen((d) => _playLocal());
  }
  print("tempo changed to ${tempo.value}");
}

void decreasetempo(int tempochange) {
  tempo.value = tempo.value - tempochange;

  if (isPlaying) {
    _subscription.cancel();
    print("_subscription canceled");
    _subscription = Metronome.periodic(new Duration(
            milliseconds: (60000 / (tempo.value * subdivision)).floor()))
        .listen((d) => _playLocal());
  }
  print("tempo changed to ${tempo.value}");
}