# 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. 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

``````

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.