Help writing a metronome program.

I’m fairly new to applescript and writing my first applescript based program in xcode which is to included a delay time calculator and tap tempo finder both of which I’ve managed to sort out without too much trouble, where I’m coming unstuck is trying to implement a metronome function (that beeps acuratly so many times a minute) and I’d appreciate a push in the right direction. The tap tempo function I did using a getmillisec scripting addition but i can’t figure a way of using that for a metronome. Is there another command that’d be more use? Any help gratefully appreciated.

Plain AppleScript only offers “delay”, and the minimum interval is 1 second. So, you’ll need third-party help, for example GetMilliSec or “the ticks” from Jon’s Commands. Eg:
(1000 milliseconds = 1 second)

Or:
(60 ticks = 1 second)

But this method is not very safe, since any slow-down in the computer can break it, and it is very CPU-intensive. Perhaps you need something as “smilepause”, but this command is only available to the Smile environment:

Perhaps somebody can recommend any obj-C method similar to “smilepause”?

Thanks alot for your help, managed to get it sorted with that, the only problem I’m now finding is that with faster tempos (seemly anything above about 120bpm/500ms) the timing starts stuttering every few beats, it gets progressively worse as tempos increase. I suspect this is due to the amount of system load as the ms value gets smaller, but is there anyway around this as obviously timing accuracy is the whole point of metronome and 120 bpm isn’t that fast as a tempo. Any help would be greatly appreciated.

I suspect you may be out of luck with this. Scripting additions themselves are fairly “expensive” calls, such that a milliseconds-osax command can’t be any more accurate or faster than the time it takes AppleScript to call it, and vanilla AppleScript provides no means of date/time support more accurate than one whole second.

Optimizing your code should help, make sure that as little as possible is occuring between each call to the milliseconds scripting addition.

The only non-scripting-addition means of “delaying” for less than a second that I know of is to repeat with a meaningless operation:


repeat [some number of] times
    set x to 1
end repeat

Of course, this isn’t a timing operation, there is no way of knowing how long it takes AppleScript to set x to 1, for some number of iterations. Even if you figure it out for one Mac, the timing will be different on someone else’s Mac. Also, the above method is lousy because (I think) it doesn’t give over processing time to other applications.

The following does give over time to other processes, but it doesn’t address the other issues:


repeat [some number of] times
    tell application "Finder"
        get version -- sends an AppleEvent, gives over processing time
    end
end

In any case, you just want to do as little as possible between you millisecond commands, to increase script speed and accuracy.

Um… did my second posting get lost?

Here it is again:

For example, here is a bare-bones snippit that does very little between each call to the milliseconds command, it seems very accurate even for small values of waitMilli:


set waitMilli to 200

set prevMilli to GetMilliSec

repeat

	set thisMilli to GetMilliSec

	if (thisMilli - prevMilli is greater than or equal to waitMilli) then

		beep
		set prevMilli to thisMilli

	end if
end repeat

Thanks for your help on this, the code you suggested was pretty much what I had and still resulted in the same trouble, accurate up to about 123 bpm then falling apart after that. I’ve tried to boil it down to the simplest it can be, just that code in script editor and around 500ms it seems okay but if that’s halved to 250 it still runs but isn’t twice the speed as you’d want it be. I guess that as you’re saying this is a pretty processor intensive thing to be doing that maybe my laptop just isn’t hacking it. Unless there’s any other angle to try out I’m feeling applescript maybe isn’t the way to go on this.

Hm… I am admittitedly an idiot when it comes to anything involving music or rhythm, but the beeping seems to be twice as fast to me when I go from 500 ms to 250. Two thoughts:

  • Did you notice that I used “greater than or equal to” as opposed to testing for an exact millisecond in time? This gives you a tolerance, ensuring that every beep is played even if it’s a few milliseconds off.

  • The Mac has several different kinds of beeps. I don’t know if this is a silly idea or not, but perhaps one of the beep sounds with a relatively short duration might make an improvement?

Thanks again for your help, well as it turns out it’d be my foolishness that’s been causing the problems (as ever), since I’m coding this at work when I should really be doing other things I’ve had the click on really quiet and enabled the ‘flash screen when alert sounds’ so I can still see the tempo without disturbing those around/getting busted. Of cause this has been the source of all the trouble, soon as that’s off the timing seems accurate to well above any bpm that you want to use. So once again thanks for your help and happy to finally have it sorted.