1

I am making a morse code app and I want to play the sounds one after another but I can't seem to get it to work. They are all playing at the same time so I can only here the last one. This is what I have so far.

This is my delay function.

func delay(delay:Double, closure:()->()) {
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW,Int64(delay * Double(NSEC_PER_SEC))),dispatch_get_main_queue(), closure)
}

This is my iteration loop

for i in morseArray
    {
        println("delayTime: \(delayTime)")
        if i == "."
        {
            delay(delayTime++, closure: { () -> () in
                self.dotSound.play()
            })
        }
        else if i == "-"
        {
            delay(delayTime++, closure: { () -> () in
                self.dashSound.play()
            })
        }
    }
Vadim Kotov
  • 7,103
  • 8
  • 44
  • 57
spogatetz
  • 11
  • 2
  • 3
    "This is my delay function" Actually it's _my_ `delay` function: http://stackoverflow.com/a/24318861/341994 But you are welcome to use it! :)))))) – matt May 19 '15 at 18:01
  • 1
    @matt, it might be a case of "convergent evolution." I created a delay function that does exactly what this one/yours does. The syntax of mine was a tad different, but this is trivial enough that I bet others have done this as well. It's an obvious use of GCD in Swift. – Duncan C May 19 '15 at 19:05
  • 1
    @DuncanC His is word-for-word identical to mine, _including the name of the function and the name of the parameter_. What are the chances? An octopus has an eye and an insect has an eye, but they are not identical and they do not both refer to them as "eye". – matt May 19 '15 at 19:06

1 Answers1

2

This is never going to work in a simple for-loop, because each play command takes time (it is time-consuming asynchronous). You thus cannot and must not "wait" for a sound to finish. Your increasing delays are not a viable solution, as you've discovered. You are going to need a much more sophisticated strategy for lining up your dot and dash sounds so that everything happens in order.

One very simple approach would be to use AVQueuePlayer, which does exactly that: it lets you line up a series of sound files to play, and then plays them in series.

A more elaborate solution, which is what I use in my "99 Bottles" app, would involve taking advantage of the delegate message emitted by an AVAudioPlayer when it finishes. Instead of looping, you respond to each "I'm finished" message by playing the next sound. So, you'd keep the list of sounds in an array, and each "I'm finished" delegate method would pull the first sound off the front of the array and play it.

matt
  • 447,615
  • 74
  • 748
  • 977