8 Replies Latest reply: Jul 21, 2010 6:50 AM by nate12345
nate12345 Level 2 Level 2 (495 points)
Hi, All.

I've got an AppleScript Objective C program that I'd like to have do two things at once. For example, when a button is clicked, speak a sentence, and do some math (example below). The easiest thing would be to just give it two sent actions, the handlers that I want it to run, but nope, can't do that.
I tried using one handler within another, but it still waits for the first to finish before moving on to the second, like this:

on secondTask()
set x to 1
repeat 5
set x to x + 1
end repeat
end secondTask

on btnClicked_(sender)
secondTask()
say "Hello, you've just clicked a button. We're doing some math right now."
end butnClicked_


When I use this, the tasks get done, but one at a time.
Is there any way to get it to do two things in parallel?

Thanks!
-Nate

MacBook 2.4 ghz 4GB RAM, Mac OS X (10.6.4), MB June 2008, Nano 3G + 5G, AEBS 2008, Logitech 5.1, LaCie 2Big + Rugged, CS4 DP
  • 1. Re: ASObjC: Do Two Things at Once
    red_menace Level 6 Level 6 (14,610 points)
    There are a variety of ways to do things at the same time (see the Concurrency Programming Guide), but if you are just wanting to start saying some text and then do something else, you can use NSSpeechSynthesizer instead of *Standard Additions* to speak the text. For example, add and connect a NSSpeechSynthesizer class in *Interface Builder*, then use it's startSpeakingString method to start saying your text before moving on to the next task.
  • 2. Re: ASObjC: Do Two Things at Once
    Hiroto Level 5 Level 5 (5,015 points)
    Hello

    You may also use say(1) with 'do shell script'. Like this :

    (* NOT TESTED *)
    on secondTask()
    set x to 1
    repeat 5 times
    set x to x + 1
    end repeat
    end secondTask

    on btnClicked_(sender)
    say "Hello, you've just clicked a button. We're doing some math right now."
    secondTask()
    display dialog (result as string)
    end btnClicked_

    on say t
    do shell script "say " & t's quoted form & " >/dev/null 2>&1 &"
    end say


    Regards,
    H
  • 3. Re: ASObjC: Do Two Things at Once
    hhas Level 2 Level 2 (190 points)
    red_menace wrote:
    There are a variety of ways to do things at the same time (see the Concurrency Programming Guide),


    Bear in mind that AppleScript's thread safety is extremely coarse (one thread per AppleScript component instance), which adds all sorts of complexities and limitations if you try to go that route. (I think OSAKit will let you create multiple component instances, but you'll need to know quite a bit about threading and OSA, and even then I can't say it'll work for sure.) Asynchronous APIs or multi-process are the best approaches, IMO.
  • 4. Re: ASObjC: Do Two Things at Once
    nate12345 Level 2 Level 2 (495 points)
    Thanks, everyone!

    So, my understanding is that simultaneous scripts aren't really possible in this environment. I'll use the speech synth object, which looks like it, for the most part, let me do what I'm looking for.

    Thanks!
  • 5. Re: ASObjC: Do Two Things at Once
    nate12345 Level 2 Level 2 (495 points)
    OK, so, I started using your method, but realized that the only connection I could make with the NSSpeechSynthesizer object to the application was as delegate.

    Is that what you mean when you say to connect it?
    If not, what should I do otherwise?
    If so, how can I get from there to something like synthObject's startSpeakingString_(toSay)?

    Thanks!
  • 6. Re: ASObjC: Do Two Things at Once
    red_menace Level 6 Level 6 (14,610 points)
    NSSpeechSynthesizer's initWithVoice method doesn't appear to actually create the object (I probably read/used it wrong, although the task uses the term "create"), so I just created one from Interface Builder. From IB, open the Classes tab of the Library palette and select NSSpeechSynthesizer - this adds the object. From there, you can connect the object to your AppDelegate's synthObject property as usual, e.g.
    property synthObject: missing value
    --
    synthObject's startSpeakingString_(toSay)
  • 7. Re: ASObjC: Do Two Things at Once
    Hiroto Level 5 Level 5 (5,015 points)
    Hello

    If I understand it correctly, something like the following snippet would work :

    --SNIPPET
    (* not tested *)
    tell current application's class "NSSpeechSynthesizer"
    set synth to its alloc()'s initWithVoice_(missing value) -- default voice
    end tell

    synth's startSpeakingString_("Humpty Dumpty sat on a wall,
    Humpty Dumpty had a great fall.
    All the king's horses and all the king's men
    Couldn't put Humpty together again.")

    tell current application to display dialog "Now speaking..." buttons {"Stop"}

    --if synth's isSpeaking() then synth's stopSpeaking()
    synth's stopSpeaking()
    synth's release()
    --END OF SNIPPET


    And if the above works, actual script in ASObjC would look something like this :

    --SCRIPT (outline)
    (* not tested *)
    property NSSpeechSynthesizer : class "NSSpeechSynthesizer"

    script myAppDelegate
    property parent : class "NSObject"
    property myButton : missing value
    property synth : {}

    on buttonClicked_(sender)
    synth's startSpeakingString_("Hello")
    end buttonClicked_

    on awakeFromNib()
    set synth to NSSpeechSynthesizer's alloc()'s initWithVoice_(missing value) -- default voice
    end awakeFromNib

    on applicationWillFinishLaunching_(aNotification)
    end applicationWillFinishLaunching_

    on applicationShouldTerminate_(sender)
    --synth's stopSpeaking() -- not sure this is necessary
    synth's release()
    return current application's NSTerminateNow
    end applicationShouldTerminate_
    end script
    --END OF SCRIPT

    *When you alloc() something, make sure you release() it.

    Regards,
    H
  • 8. Re: ASObjC: Do Two Things at Once
    nate12345 Level 2 Level 2 (495 points)
    Great, thanks!

    Those both seem to work.

    I'm going to use a combination of the two: Red_Menace's IB connections, and Hiroto's initWithVoice.

    Thanks again!