Hourly Chime Formula

Hi,

Every once in a while, I try to find a simple formula for my hourly chime script. I’m always stuck with the zero at midnight. Here’s an example of the hours you get from ‘(time of (current date)) div hours’:


set l to {}
repeat with h from 0 to 23
	set n to ((h - 1) mod 12) + 1
	set end of l to n
end repeat
l

What I do is add an if-then statement (if n is 0 then set n to 12). I keep thinking that there’s a formula to do this without the if-then statement. Anybody know a way to do this? I think this is the first time I’m posting this question, because I finally give up :). Trying to clean up my scripts.

Thanks,

Nevermind. Looking at my post I thought, just add 12 to the hour.


set l to {}
repeat with h from 0 to 23
	set n to (((h + 12) - 1) mod 12) + 1
	set end of l to n
end repeat
l

After all these years I finally got it!!!

Thanks anyway,

I assume you’re detecting hours testing them against your list and chiming them. Would this work? It detects the hour within ± 10 seconds, repeats every 20.


--on idle
tell (((time of (current date)) / hours) + 12) to tell (it - it div 1) to if it < 0.002777 or it > 0.997222 then my chime()
to chime()
	beep 3 -- or whatever
end chime
--return 20
--end idle

I’ve made a couple of adjustments after the hour just passed, but I think this will work:

on idle
	tell ((time of (current date)) + 10) to if (it mod hours < 21) then my chime(((it div hours + 11) mod 12) + 1)
	
	return 19 -- ie. less than the 20-second window
end idle

to chime(h)
	beep h
end chime

Ahh, you’re assuming he wants to chime the hour - I thought he just wanted a chime on the hour. Nice (though hardly transparent vis-a-vis the constants. :confused: Also, if the first “trigger” time is exactly X:59:50, it will chime twice:


set now to current date
repeat with N in {0, 19}
	set time of now to (time of date "Sunday, December 3, 2006 3:59:50 AM") + N
	check(now)
	delay 3
end repeat


--on idle
to check(now)
	tell ((time of (now)) + 10) to if (it mod hours < 21) then my chime(((it div hours + 11) mod 12) + 1)
end check
--return 19 -- ie. less than the 20-second window
--end idle

to chime(h)
	beep h
end chime

Thank you for this idea, Kel - fun on a Sunday afternoon. Using Nigel’s formula, and using a variable repeat for the idle handler (so as to only pay close attention when very close to the hour) yields (in a test format)


set now to current date
set time of now to (time of date "Monday, January 1, 2007 4:00:10 AM")
check(now)

--on idle
to check(now) -- becomes set now to (current date)
	set {minutes:m} to now
	tell (m + 3) - 60 to if it > -4 or it < 2 then
		tell ((time of now) + 10) to if (it mod hours < 21) then my chime(((it div hours + 11) mod 12) + 1)
		return 21
	else
		return 60
	end if
end check -- gets removed
--end idle

to chime(h)
	tell application "Play Sound"
		play (("" & (path to "dlib" from system domain) & "Sounds:" & "Glass.aiff") as alias) repeat (h - 1)
		quit
	end tell
end chime

:

Hi,

I used the idle handler until I discovered crontabs, when I first got OSX. OSX didn’t have the built-in hourly chime like the preosx control panels. Now I use:


set cur_hour to (((((time of (current date)) div hours) + 12) - 1) mod 12) + 1
repeat cur_hour times
	play sound file "Macintosh HD:Users:kel:Library:Sounds:Purr.snd"
end repeat

with Jon’s Commands or Play Sound. Thinking of switching to Play Sound, so I wouldn’t need to use the converted Purr.snd.

I’m finally up to the scripts whose name begins with m. :o Just 14 more letters to go.

Thanks a lot,

I’m using the one above as an idle handler: (I’ve never used CronTab)


on idle
	set now to current date
	set {minutes:m} to now
	tell (m + 3) - 60 to if it > -4 or it < 2 then
		tell ((time of now) + 10) to if (it mod hours < 21) then my chime(((it div hours + 11) mod 12) + 1) -- Nigel Garvey's
		return 21 -- pay attention when close to the hour
	else
		return 60 -- look once a minute when away from the hour
	end if
end idle

to chime(h)
	tell application "Play Sound"
		play (("" & (path to "dlib" from system domain) & "Sounds:" & "Glass.aiff") as alias) repeat (h - 1)
		quit
	end tell
end chime

Hi Adam and Nigel,

That’s right! I can just add 11 instead of adding 12 and subtracting 1. :slight_smile:

The formula evolves …

Thanks a lot,

Edited: BTW, one thing you might want to do with the idle handler script, is to make it background only. What I did wanted was to not have the script interrupt the user when in full screen mode also. UNIIX osascript works well with compiled scripts for this. Although, once in a while it still interrupts. I think this happens when Chime runs and the full screen program is also playing a sound. Then the computer says “Chime needs your attention”.

I have banged together various scripts over the years to tell the time on the hour for me.

You prompted me to update my current on.

I have not tested it through the whole day, but the main change is to get it to idle only for the length of time to the next hour, so it does not need to check the time every some seconds.
This seems so far to call the hour bang on time.

property Get_Hr_first_run : true
on idle
	set am_Hours to {"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"}
	set pm_hours to {"13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "22", "23"}
	
	set Get_Hr to do shell script "date +'%H'"
	if Get_Hr is "00" then
		if Get_Hr_first_run is true then
	
			say "Time Check Starting "
			set Get_Hr_first_run to false
		else
			say "The Time is 12 , am "
		end if
	else if Get_Hr is in am_Hours and Get_Hr contains 0 then
		if Get_Hr_first_run is true then
			say "Time Check Starting "
			set Get_Hr_first_run to false
		else
			say "The Time is  , " & second character of Get_H & ",am"
		end if
	else if Get_Hr is in am_Hours and Get_Hr does not contain 0 then
		if Get_Hr_first_run is true then
			say "Time Check Starting "
			set Get_Hr_first_run to false
		else
			say "The Time is , " & Get_H & ",am"
		end if
		
	else if Get_Hr is in pm_hours then
		if Get_Hr_first_run is true then
			say "Time Check Starting "
			set Get_Hr_first_run to false
		else
			say "The Time is , " & Get_Hr - 12 & ",pm"
		end if
	end if
	set Get_M to 60 * 60 - (do shell script "date +'%M'") * 60 - (do shell script "date +'%S'")
	return Get_M
end idle
on quit
	set Get_Hr_first_run to true
	continue quit me
end quit

Yes, I did that with Drop Script Backgrounder and set it up in my Startup Delayed folder to start after logins and boots. It uses a blip of time so I don’t mind it running in the background.

Taking a page from Mark’s book, I’ve modified mine to run every minute before it has chimed until it’s within ± 2 minutes of the hour, but after the first chime, it runs every 59 minutes. Not as “crisp” as I’d like it to be, but I’ll fiddle.

Kel seems to have started an avalanche. :lol:


on idle
	set now to current date
	set {minutes:m} to now
	tell (m + 3) - 60 to if it > -4 or it < 2 then
		tell ((time of now) + 10) to if (it mod hours < 21) then return (my chime(((it div hours + 11) mod 12) + 1)) -- Nigel Garvey's
		return 21 -- pay attention when close to the hour
	else
		return 60 -- look once a minute when away from the hour
	end if
end idle

to chime(h)
	tell application "Play Sound"
		play (("" & (path to "dlib" from system domain) & "Sounds:" & "Glass.aiff") as alias) repeat (h - 1)
		quit
	end tell
	return 59 * minutes
end chime

I see a lot’s been happening since I last logged in! :lol:

Adam’s script, to which I was replying, allowed a ten second window either side of the hour in which to activate the chime. ((time of (current date)) + 10) simplifies the check slightly by changing the question from “Is the time now between ten seconds before an hour and ten seconds after the hour?” to “Will the the time ten seconds from now be within the first twenty seconds of an hour?” (if (it mod hours < 21).) It also ensures that, if the current time’s within the ten seconds before an hour, it’s the following hour that’s chimed.

That’s a problem over which I agonised for a while. With a 19-second idle cycle, there’s a chance it’ll chime twice. With a 20-second cycle, given the possibility of delays, there’s a chance that it won’t chime at all. But the time taken to perform the chime(s) reduces the likelihood of a second peal with a 19-second idle time. To be doubly sure, you could add a 1- or 2-second delay to the end of the chime() handler.

The idle handler is looking good.

Here’s a couple of things you might look at. If the time is within 5 seconds to the hour you could modify the delay to return in the amount of seconds left to the hour. You could also do something like cron does. Modify the delay to return half the time remaining to the hour until it is zero. This method might be good if you sleep the computer. Lastly, you can use “ssnd” for the path.

path to “ssnd” as string – osx system sounds

Back to fixing the scripts.

gl,

“ssnd” is a nice way to get there. Thanks.

My idle script, however, has a serious problem - having chimed, it sets the idle time to 59 minutes and doesn’t go into its “fast” cycle time until it’s within ± 10 seconds of the hour. BUT, when the computer awakens from sleep (I never shut down or restart except for updates that demand it), that 59-minute on idle time is fatal - it misses the hour thereafter (by actual test), and the applet has to be quit and restarted to get it back “on track” by doing the first once per minute cycle up to the first hour. Unfortunately, vanilla AppleScript doesn’t have an “on wake” handler. I’ll think on it. It seems a bit cumbersome to have to use SleepWatcher to start it every morning and quit it when I put the system to sleep.

Instead of just checking every five minutes, this version does a check on every five-minute boundary. If the time’s less than ten seconds past the top of an hour, it chimes. If it’s missed the window “ say the computer’s been asleep or busy “ but the time’s still within the first five minutes of an hour, it gives a belated announcement. Otherwise it simply sets itself to idle until the next five-minute boundary. The time taken to sound the chimes or the announcement doesn’t matter here, as the difference is corrected five minutes later.

on idle
	local h
	
	tell (time of (current date))
		set h to ((it div hours + 11) mod 12) + 1
		tell (it mod hours)
			if (it < 10) then
				-- If it's now less than ten seconds after an hour, chime.
				my chime(h)
			else if (it < 300) then
				-- Otherwise, if it's within the first five minutes, make a belated announcement.
				my waffle(h)
			end if
		end tell
		
		-- Idle until the next five-minute boundary.
		return (86399 - it) mod 300 + 1 -- ie. (days - (time of (current date)) - 1) mod (5 * minutes) + 1
	end tell
end idle

to chime(h)
	beep h
end chime

on waffle(h)
	say "Oops! It's a little past " & h & " o'clock."
end waffle

I substituted my chime handler for yours, but I’m giving the rest a try.:slight_smile: