0

I'm trying to make a metronome in Flutter, but it isn't accurate for some reason. I'm using the AudioPlayers package to play the audio, and a timer to play the audio every n of milliseconds, based on the BPM set. The problem I'm facing is that the clicks aren't played at the right delay between each other.

Here is my code:

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:tools/components/appbar.dart';
import 'package:audioplayers/audioplayers.dart';

class MetronomeScreen extends StatefulWidget {
  const MetronomeScreen({Key? key}) : super(key: key);

  @override
  State<MetronomeScreen> createState() => _MetronomeScreenState();
}

class _MetronomeScreenState extends State<MetronomeScreen> {
  double bpm = 100;
  bool isClicking = false;
  Timer? timer;

  final player = AudioPlayer();

  @override
  void initState() {
    player.setSource(AssetSource('sounds/metronome.mp3'));
    super.initState();
  }

  toggleMetronome() {
    if (isClicking) {
      print("Stopped Metronome");
      timer?.cancel();
      isClicking = false;
    } else {
      isClicking = true;
      timer = Timer.periodic(
          Duration(milliseconds: (60000 / bpm.round()).round()), (timer) {
        player.resume();
      });
    }
  }

  @override
  void dispose() {
    timer?.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: ToolsAppBar(
          title: "Metronome",
        ),
        body: Center(
            child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                SizedBox(
                    width: 120,
                    child: Text(
                      "${bpm.round()} BPM",
                      style: const TextStyle(fontSize: 25),
                    )),
                MaterialButton(
                  onPressed: () => toggleMetronome(),
                  color: Theme.of(context).primaryColor,
                  padding: const EdgeInsets.all(16),
                  shape: const CircleBorder(),
                  child: const Icon(
                    Icons.play_arrow,
                  ),
                ),
              ],
            ),
            Row(mainAxisAlignment: MainAxisAlignment.center, children: [
              MaterialButton(
                onPressed: () {
                  setState(() {
                    bpm -= 1;
                  });
                },
                color: Theme.of(context).primaryColor,
                padding: const EdgeInsets.all(16),
                shape: const CircleBorder(),
                child: const Icon(
                  Icons.remove,
                ),
              ),
              Slider(
                  value: bpm,
                  onChanged: (newValue) {
                    setState(() {
                      bpm = double.parse(newValue.toStringAsFixed(0));
                    });
                  },
                  min: 40,
                  max: 250),
              MaterialButton(
                onPressed: () {
                  setState(() {
                    bpm += 1;
                  });
                },
                color: Theme.of(context).primaryColor,
                padding: const EdgeInsets.all(16),
                shape: const CircleBorder(),
                child: const Icon(
                  Icons.add,
                ),
              ),
            ]),
          ]
              .map((e) => Padding(
                  padding: const EdgeInsets.only(top: 20, bottom: 20),
                  child: e))
              .toList(),
        )));
  }
}

Any help would be appreciated!

Thanks :)

Code Clickers
  • 85
  • 1
  • 10
  • 1
    The calculation looks good to me, you did 60,000 milliseconds (1 minute) divided by the bpm value. So maybe, the mp3 you have in assets, has some extra delays in duration? or maybe you can try the flutter_beep package and use their built-in sounds? – Muhammad Hussain Oct 16 '22 at 12:33
  • 2
    Have you checked out Timer vs Ticker? Here's a nice article about it.[Flutter Timer vs Ticker: A Case Study](https://codewithandrea.com/articles/flutter-timer-vs-ticker/) – Tolga Katas Oct 16 '22 at 14:27
  • @MuhammadHussain Flutter Beep package doesn't work for me on Android 12. – Code Clickers Oct 21 '22 at 20:00
  • Looks like a package issue to me, https://github.com/trietho/flutter_beep/issues/13 You are free to explore any other package if you want. – Muhammad Hussain Oct 22 '22 at 08:28

0 Answers0