0

I'm trying to build a steady metronome that ticks every beat, but it seems like there is a problem.

How long the metronome waits for each beat is determined by this formula: 60000 / BPM

But, the value seems to return a specific number no matter what value you plug into BPM.

I have a property that returns the value of this formula, along with a bpm integer:

static private int bpm = 125;
static private int BeatLength
{
    get
    {
        return 60000 / bpm;
    }
}

static public int beat = 0;

And here is the function that's responsible for the metronome (it runs on a dedicated thread):

public static void RhythmUpdate()
{
    lock (threadLock)
    {
        while (true)
        {
            Thread.Sleep(BeatLength); // Sleep until the next beat
            AddRequest(BeatLength * beat);
            beat++; 
            DefaultSounds.def_CowBell.Play();
            OnBeat?.Invoke();
        }
    }
}

When breakpointing the def_CowBell.Play();, Visual Studio notes that it takes around 600ms to loop. This is how I know the value.

Extra Info:

  • I'm using OpenGL

  • Maybe some more if asked...

I appreciate your help in advance.

kahveci
  • 1,429
  • 9
  • 23
IIRawCodeII
  • 375
  • 1
  • 3
  • 9
  • 2
    Windows is not an RTOS, your Thread.Sleep may be taking longer than you are asking it to. What is the value of `BeatLength`? There shouldn't be a 120-ish millisecond variance though. – Ron Beyer Mar 11 '18 at 02:07
  • It only varies very little from around 600ms - 616ms, but for an exact value of the property itself, I think it's 600. But I don't use the VS pause function very much so it might be the wrong number I'm looking at. – IIRawCodeII Mar 11 '18 at 02:12
  • Use a `Timer` - chances are everything else in that loop is taking a constant amount on top of your Sleep call. So 200-400ms for your thread.sleep plus another, say 300ms for the rest of the loop. So even as you vary the bpm the loop doesn't vary as much. – Ian Mercer Mar 11 '18 at 02:14
  • I logged the BeatLength property every beat and it all says 600 no matter what, so it is returning 600. Also, Ian, I'll try that. – IIRawCodeII Mar 11 '18 at 13:00
  • `Sleep` won't delay for the exact amount of time you request, sometimes could be shorter, could be longer. It's based on the limitations of the system clock. See the first paragraph under Remarks [this post](https://msdn.microsoft.com/library/windows/desktop/ms686298.aspx). – Chris O Mar 12 '18 at 13:19

1 Answers1

0

It turns out that I've been setting BPM on a function, and whenever I made a change to it's initialization it would be overwritten by that new BPM.

public static void StartBeat(int startingBPM)
{
    rhythmThread = new Thread(new ThreadStart(RhythmUpdate)); // Initialize new thread
    bpm = startingBPM; // < This piece of codde was the source.
    rhythmThread.Name = "BeatThread";
    rhythmThread.Start(); // Start the thread
}

For now, I'll disable that line of code when testing.

IIRawCodeII
  • 375
  • 1
  • 3
  • 9