tags:

views:

49

answers:

1

So I have created an alarm function:

alarm: func[seconds message [string! unset!]][
     wav: load %attention.wav
     sound-port: open sound://
     wait seconds do [
     insert sound-port wav
     wait sound-port
     close sound-port
     if (value? 'message) [
           print message
        ]
   ]
]

which works like this:

alarm 30 "Will trigger in 30 seconds"

Now how can I for example show a timer which increments while waiting for the alarm since Rebol doesn't support thread ?

+1  A: 

REBOL doesn't have conventional multi-tasking/threading support. However, you can fake it using the GUI in REBOL/View, which since you're using the sound stuff, I assume you're using.

The key is to set a timer on one of your interface objects that periodically calls a function to check on the status of the things you want to monitor. In this example, I've rewritten your alarm function to set the alarm-data variable, which will be checked by the periodic function when it gets called every second from the monitor object in the layout (that's what the "rate 1 feel [engage: :periodic]" stuff does).

While crude, this trick goes a long way to compensate for missing threads (if you can put up with having a GUI). You can check/update all sorts of things in the periodic function, even implement simple multi-tasking with a state machine. Also note that you could set up alarm-data as a list of alarms instead of a single one if you need more than one.

Also see http://www.rebol.com/docs/view-face-events.html for more information about special event handling.

REBOL [
    Title: "Alarmer"
    File: %alarm.r
    Author: oofoe
    Date: 2010-04-28
    Purpose: "Demonstrate non-blocking alarm."
]

alarm-data: none

alarm: func [
    "Set alarm for future time."
    seconds "Seconds from now to ring alarm."
    message [string! unset!] "Message to print on alarm."
] [
    alarm-data: reduce [now/time + seconds  message]
]

ring: func [
    "Action for when alarm comes due."
    message [string! unset!]
] [
    set-face monitor either message [message]["RIIIING!"]
    ; Your sound playing can also go here (my computer doesn't have speakers).
]

periodic: func [
    "Called every second, checks alarms."
    fact action event
] [
    if alarm-data [
        ; Update alarm countdown.
        set-face monitor rejoin [
            "Alarm will ring in " 
            to integer! alarm-data/1 - now/time
            " seconds."
        ]

        ; Check alarm.
        if now/time > alarm-data/1 [
            ring alarm-data/2
            alarm-data: none ; Reset once fired.
        ]
    ]
]


view layout [
    monitor: text 256 "Alarm messages will be shown here."  
        rate 1  feel [engage: :periodic]
    button 256 "re/start countdown" [
        alarm 10 "This is the alarm message."
        set-face monitor "Alarm set."
    ]
]
oofoe
Thanks a lot for this nice piece of code. Will play with it.Would be great if RT implements something more truly multi-tasking without having to use tricks.
Rebol Tutorial
Is it possible to start the alarm automatically on view load instead of clicking on the button ?
Rebol Tutorial
See http://stackoverflow.com/questions/2895458/a-more-elegant-way-to-start-a-multithread-alarm-in-rebol-vid-whats-the-equiva
Rebol Tutorial