作为 Flutter 中的第一个应用程序,我想构建一个节拍器应用程序。 UI已经搭建好了,但是我在实际的节拍器功能上还是遇到了以下问题:
有时,节拍器有点滞后,刚好够用,所以您会注意到。 flutter 有没有办法让节拍器达到 100% 的精度?
在演奏时不改变细分(你必须停止并启动节拍器)。如果值“tempo”和“subdivision”发生变化,它们如何自动应用于节拍器订阅?我知道 Flutter 提供了诸如 Listenable、Stream、InheritedWidget 等工具,但我还没有想出如何在现有代码中实现这些工具。
界面截图:
这是代码(它不完全是我写的 -> 学分):
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}");
}