High Speed ​​Java Metronome

as an exercise I'm trying to create a metronome with Java using Thread.sleep as a timer and JMF for sounds. It works pretty well, but for some reason, the JMF seems to play only sounds at a maximum of 207 beats per minute.

From my Metronome class:

public void play() { soundPlayer.play(); waitPulse(); play(); } 

From my SoundPlayer class:

 public void play() { new Thread(new ThreadPlayer()).start(); } private class ThreadPlayer implements Runnable { public void run() { System.out.println("Click"); player.setMediaTime(new Time(0)); player.start(); } } 

I made SoundPlayer.play () work like a thread to check if this will change, but it is not. I can easily change the tempo to about 207bpm, but even if I set my timer to 1000bpm, sounds will not play faster than about 207bpm .

I put System.out.println("Click"); inside my ThreadPlayer.run () to check if my loop is working correctly - this.

The problem seems to be related to my JMF implementation. I am sure there is a simple solution, can someone help me?

Thank you so much for your help! :)

+4
source share
5 answers

The answer to the untrustworthy Thread.sleep () is incorrect: you cannot count on the fact that it will return exactly as much time that you specified. In fact, I'm pretty surprised that your metronome can be used at all, especially when your system is under load. Read the docs for Thread.sleep () for more details. Max Beikirch's answer about MIDI is a good suggestion: MIDI controls timing very well.

But you ask how to do this with sound. The trick is to open the audio stream and fill it with silence between the clicks of the metronome and paste the clicks of the metronome where you want. When you do this, your sound card plays samples (regardless of whether they contain a click or silence) at a constant speed. The key here is to turn off the audio stream and not close it. Thus, a clock is an audio equipment, not a system clock — a subtle but important difference.

So, let's say you generate 16-bit monophonic samples with a frequency of 44100 Hz. Here is a function that will create a click sound at the desired speed. Keep in mind that this click sound is bad for the speakers (and your ears), so if you actually use it, play it at low volume. (Also, this code is not verified - it just demonstrates the concept)

 int interval = 44100; // 1 beat per second, by default int count = 0; void setBPM( float bpm ) { interval = ( bpm / 60 ) * 44100 ; } void generateMetronomeSamples( short[] s ) { for( int i=0; i<s.length; ++i ) { s = 0; ++count; if( count == 0 ) { s = Short.MAX_VALUE; } if( count == interval ) { count = 0; } } } 

Once you set the tempo using setBPM, you can play the samples generated by calling the generateMetronomeSamples () function again and stream the streams output to your speakers using JavaSound. (see JSResources.org for a good tutorial)

Once you get started, you can replace the sharp click with the sound you get from WAV or AIFF, or a short tone or something else.

+8
source

Take your time and look at MIDI! - http://www.ibm.com/developerworks/library/it/it-0801art38/ or http://docs.oracle.com/javase/tutorial/sound/TOC.html . This is the best solution for everything related to computer sound.

+1
source

My guess would be, and maybe someone else could jump here, this thread execution time depends on the whims of the thread scheduler. You cannot guarantee how long the JVM will take to return to this topic. In addition, since the JVM runs as a process on a machine and obeys the OS process scheduler, you look at least at two levels of unpredictability.

+1
source

Just like Jamie Dubi said, just because you tell Thread to sleep 1 millisecond does not mean that it will be called back exactly one millisecond. The only guarantee is that 1 millisecond has passed since you called Thread.sleep () ;. In fact, the processor cannot process the code fast enough to play an audio signal every milliseconds, so you see a delay. If you need a dramatic example, make your own timer class and try to count it in milliseconds for a full minute, you will see that the timer is turned off quite a bit.

The person who really deserves an answer for a loan is Max Beirik, Midi is the only way you can make the conclusion you are looking for.

+1
source

I have much more experience as a musician than a programmer, but I just finished the metronome application that I started some time ago, I paused the project for a while because I could not understand why I had the same problem. Yes, Thread.sleep () may be unreliable, but I managed to make a good metronome using this method.

I saw you mention the ExecutorService attempt. I don't think using parallel classes will solve your problem. I guess this is a system resource issue, I'm pretty sure MIDI is the way to go with the metronome. I force my students to practice with the metronome, and I used a lot, I was never too concerned about the sound quality of ticks, the timing is much more important, and MIDI files will be much faster than any other audio file, I used the javax.sound.midi library from the Sound API . I suspect this will solve your problem.

You may notice that your ticks are uneven when they work correctly, this is because the Thread.sleep () method is not very reliable. How I solved this problem by doing all my calculations in nanoseconds using the System.nanoTime() method instead of the System.currentTimeMillis() method, just remember to convert back to milliseconds before passing the sleep time to Thread.sleep (),

I do not want to post the code for my metronome here if you want to figure it out on your own, but if you want to see it, just send me an email kevin.bigler3@gmail.com and I would be happy to send it to you. Good luck.

0
source

All Articles