4

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}");
}
ocrdu
  • 2,172
  • 6
  • 15
  • 22
Leo D.
  • 73
  • 8
  • You don't seem to have your full code where you have your UI stuff. You probably have a StreamBuilder listening to your stream? And you want the builder to re-build when your 'tempo' and 'subdivision' changes? There a few ways to implement, but best is probably provider package https://pub.dev/packages/provider . Look at ChangeNotifierProvider – Vinayakaram Nagarajan Dec 26 '20 at 17:16
  • 1
    Thanks, I will defenitely consider this. Right now I'm using ValueListenableBuilder to listen for any value change of tempo. My problem is also regarding performace / lagging issues with the StreamSubscription - is there any way to make absolutely sure that the sound is played on time (accurate to milliseconds)? – Leo D. Apr 11 '21 at 16:52
  • Do you have found any solution regarding the lagging? I built a metronome myself and I also encounter this problems. – novas1r1 Mar 30 '22 at 07:45
  • Do you find any proper solution for lagging. – Dreamcatcher Sep 10 '22 at 17:13
  • Did you find the solution? I'm facing the same problem! – Code Clickers Oct 16 '22 at 12:04
  • Any updates? :/ Same issue. – Ilya Iksent Nov 10 '22 at 19:29

1 Answers1

1

Try to use a library called flutter_sequencer, it helped me to create Metronome without lagging, while any other solution and library didn't work.

Ilya Iksent
  • 1,425
  • 17
  • 15
  • 1
    very good hint, thanks! I tried to implement a very slim variation of the drum_machine example but I am failing miserably. I also want just a simple Metronome with that library, could you maybe share your code? – Simsala Dec 20 '22 at 06:20