You should be automatically redirected . If not, visit
http://newlisper.wordpress.com
and update your bookmarks.

03/08/2006

Countdown

The famous Hungarian-born photographer Brassai, 'the eye of Paris', used to time the long exposures of his night-time photographs by smoking a cigarette: after opening the shutter, he lit a cigarette, waited until it had burnt down, then closed the shutter again. He used the cheap, fast-burning Gauloise for brighter scenes and a more expensive, slower burning, brand such as Boyard for darker conditions.

I liked this story when I first heard it many years ago - something about the creative maverick genius striding around the streets of Paris at night solving problems with some casual lateral thinking, or something.

No such luck with the following, I'm afraid. It's all strictly digital and stolidly unromantic. I wanted a timer that would wait a given number of seconds before sounding an alarm. Looking through the applications on my computer, I realised that I didn't have such a thing installed - I've got plenty of alarms and calendars, but no countdown timers. I found a little dashboard widget on a web site somewhere, but that didn't work for me. And I'm not a smoker so I didn't have anything that would reliably take a precise number of minutes... So I thought it shouldn't be too difficult to write a countdown timer in newLISP.

The reason it's ended up as a Unix command-line utility is the problem of a user interface: it's still easier for me to write a command-line program that accepts text input than to write any kind of application with a nice graphical interface. Until something suitable comes along for newLISP, this cool 1970s technology is about the only thing I can use.

#!/usr/bin/newlisp
(unless (main-args 2) 
    (begin (println "usage: countdown duration [message]\nspecify duration in seconds or h:m:s") 
    (exit)))
(define (set-duration)
" convert input to seconds "
  (set 'duration 
    (dolist (e (reverse (parse duration-input ":"))) 
     (if (!= "" e) 
      (inc 'duration (mul (int e) ('(1 60 3600 86400) $idx)))))))
(define (seconds->hms s)
" convert seconds to h:m:s display"
  (letn 
    ((secs (mod s 60)) 
     (mins (mod (div s 60) 60)) 
     (hours (mod (div s 3600) 24))) 
    (format "%02d:%02d:%02d" hours mins secs)))
(define (clear-screen-normans-way)
    (println "\027[H\027[2J"))
(define (notify announcement)
    " this is platform-specific"
    " on Mac, do some beeps and growls, and speak the supplied announcement"
    (exec (string {osascript -e 'tell application "Finder" to beep 3'}))
    (if (!= announcement nil) (exec (string [text]osascript -e 'say "[/text] announcement [text]"'[/text])))
    (exec (format "/usr/local/bin/growlnotify %s -m \"Finished count down \"" (date (date-value) 0 "%Y-%m-%d %H:%M:%S"))))
; start
(set 'duration-input (main-args 2) 'duration 0)
(set-duration)
(set 'start-time (date-value) 'target-time (add (date-value) duration))
(set 'banner 
    (string  "Started countdown of " 
        (seconds->hms duration) 
        " at " 
        (date start-time 0 "%Y-%m-%d %H:%M:%S")
        "\nFinish time:                     " (date target-time 0 "%Y-%m-%d %H:%M:%S")))
(while (<= (date-value) target-time)
    (clear-screen-normans-way)
    (println banner "\n\n" 
        "Elapsed: " 
        (seconds->hms (- (date-value) start-time )) 
        " Remaining: " 
        (seconds->hms (abs (- (date-value) target-time))))
    (sleep 1000))
; finished
(println "Countdown completed at " (date (date-value) 0 "%Y-%m-%d %H:%M:%S") "\n")
(notify (main-args 3))
(exit)

6 Comments:

At 17:45, Anonymous Anonymous said...

I like Minuteur for both countdowns and stopwatch type functionality.

 
At 17:50, Blogger newlisper said...

That's very nice - some real programming! Pity I didn't find it in time....

 
At 20:57, Anonymous Anonymous said...

Your NO rooky anymore ;-) You log is so extended i think we are the rooky's now ;-) Good work C! keep it up !

 
At 00:40, Anonymous m i c h a e l said...

I've copied over your countdown timer code. I like text-based interfaces. When I tried to learn programming on my Commodore 128, all I ever did was design cool ways of displaying plain text. My favorite way was a simulation of a person's typing. With all the random pauses, spurts, and mistakes. I think I also wrote some newLISP to do this when I was first starting to learn it. If I did, maybe I can finally be able to post something to newLISPer, again! One thing I tried before actually seeing how to use your function was to use an expression for the duration: (countdown (* 60 30) "cor! 'mullion's countdown timer is cool."). This seems like an acceptable modification to make. Maybe I'll race you for the solution ;-)

m i c h a e l

 
At 09:15, Blogger newlisper said...

Well, I suppose you could have an evaluated expression for time by inserting this line before line 7

(if (string? duration-input) (set 'duration-input (string (eval-string duration-input))))

but I can't let you type "cor! 'mullion's ..." because of the shell's quotation quirkiness and bang wizardry. Which I'm sure someone can solve... :-)

Your challenge: rewrite it to be more elegant!

 
At 09:53, Blogger newlisper said...

Ha. Well that suggestion broke the ":" parsing, so better something like this:

(if (starts-with duration-input "(") (set 'duration-input (string (eval-string duration-input))))

- if you supply an expression in parentheses it will evaluate it first, otherwise it will get parsed as a d:h:m:s duration.

 

Post a Comment

Links to this post:

Create a Link

<< Home