Metronome Lagging in Flutter

334 Views Asked by At

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 :)

0

There are 0 best solutions below