javamultithreadingmetronome

Metronome in Java


I am working on an implementation for a metronome in Java. I have read around that using Thread.sleep isn't the best way to actually sync the times properly which may be the root of my problem. However, the issue I am running across in the beginning stages of my implementation are that when i utilize the +/- buttons, the bpm changes, however the speed of the text "RUNNING" drastically increases when you're only changing from like 60 to 61 bpm.

Any help with why that might be the case would be great. I am also interested in changing the thread.sleep() to something different however the midi option is a little over my head and i can't find any good documentation to help me with that option.

Thanks

Here is my code so far:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.concurrent.atomic.AtomicBoolean;

public class mainWindow
{
    public static void main (String[] args){
        frameClass frame = new frameClass();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(350,275);
        frame.setVisible(true);
   }
}

class frameClass extends JFrame
{
    private JButton onOff;
    private JButton plus;
    private JButton minus;

    public frameClass()
    {
      setLayout(new FlowLayout());
      onOff = new JButton("On/Off");
     plus = new JButton("+");
     minus = new JButton("-");
     add(onOff);
     add(plus);
     add(minus);

     toggleHandler handler = new toggleHandler();
     onOff.addActionListener(handler);

     plusHandler plusHandle = new plusHandler();
     plus.addActionListener(plusHandle);

    minusHandler minusHandle = new minusHandler();
    minus.addActionListener(minusHandle);
}

private class toggleHandler implements ActionListener {
    private Metronome metro;

    @Override
    public void actionPerformed(java.awt.event.ActionEvent e) {
        if (e.getSource() == onOff) {
            if (metro == null) {
                metro = new Metronome();
                Thread t = new Thread(metro);
                t.start();
            } else {
                metro.end();
                metro = null;
            }
        }
    }

}

private class plusHandler implements ActionListener
{
    @Override
    public void actionPerformed(java.awt.event.ActionEvent e)
    {
        Metronome.bpm++;
    }
}

private class minusHandler implements ActionListener
{
    @Override
    public void actionPerformed(java.awt.event.ActionEvent e)
    {
        Metronome.bpm--;
    }
}
 }

class Metronome extends Thread
{
private AtomicBoolean keepRunning;
static double bpm = 60;

public Metronome()
{
    keepRunning = new AtomicBoolean(true);
}

public void end()
{
    keepRunning.set(false);
    System.out.println("STOPPED");
}

@Override
public void run()
{
    while (keepRunning.get())
    {
        try
        {
            Thread.sleep((long)(1000*(60.0/bpm)));
        }
        catch(InterruptedException e)
        {
            e.printStackTrace();
        }

        System.out.println("RUNNING");
    }
}
}

Solution

  • The problem is in this line:

    Thread.sleep((long)(1000*(60/bpm)));
    

    When bpm becomes 61 your timeout becomes 0. This is because with integer division 60/61 = 0.

    Try instead:

    Thread.sleep((long)(1000*(60.0/bpm)));