Flutter Metronome App lagging and updating values as they change

Viewed 586

As a first app in flutter, I want to build a metronome app. The UI is already built, but I still encounter the following problems with the actual metronome functionality:

  • sometimes, the metronome lags a bit, just enough, so you notice it. Is there a way in flutter to achieve a 100% precision of the metronome?

  • not changing subdivision while playing (you have to stop and start the metronome). How can the values "tempo" and "subdivision" be automatically applied to the metronome subscription, if they change? I know that Flutter provides tools like Listenable, Stream, InheritedWidget, etc. but I haven’t figured out a way how you can implement these in the existing code.

Acreenshot of the UI:

enter image description here

Here is the code (it's not entirely written by me -> credits):

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}");
}
0 Answers
Related