views:

33

answers:

3

Hi. What is the best way to handle this situation on an iPhone device: My program ramps the pitch of a sound between two values. A button pressed calls a method that has a while loop that does the ramping in small increments. It will take some time to finish. In the meantime the user has pressed another button calling the same method. Now I want the loop in the first call to stop and the second to start from the current state. Here is the something like what the method should look like:

-(void)changePitchSample: (float) newPitch{
float oldPitch=channel.pitch;
if (oldPitch>newPitch) {
    while (channel.pitch>newPitch) {
        channel.pitch = channel.pitch-0.001;
    }
}
else if (oldPitch<newPitch) {
    while (channel.pitch<newPitch) {
        channel.pitch = channel.pitch+0.001;
    }
}

}

Now how to best handle the situation where the method is called again? Do I need some kind of mulitthreading? I do not need two processes going at the same time, so it seems there must be some easier solution that I cannot find (being new to this language).

Any help greatly appreciated!

+1  A: 

You cannot do this like that. While your loop is running no events will be processed. So if the user pushes the button again nothing will happen before your loop is finished. Also like this you can’t control the speed of your ramp. I’d suggest using a NSTimer. In your changePitchSample: method you store the new pitch somewhere (don’t overwrite the old one) and start a timer that fires once. When the timer fires you increment your pitch and if it is less than the new pitch you restart the timer.

Sven
Thanks. I read somewhere that NSTimer had a resolution of 100ms or so, but I did not test it myself yet (it might well be wrong). That kind of resolution would of course not be able to make a smooth ramp.
materialvision
You’re right, Apples documentation says something about 50-100 ms. The exact resolution depends also on what else is happening in your run loop. I’d try the timer and see if it is good enough. Otherwise you probably have to use another thread.
Sven
Yes, that kind of timing interval will not work with pitch, since it needs to be very smooth. So I will then need to look into threading still. . .
materialvision
+1  A: 

Don't use a while loop; it blocks everything else. Use a timer and a state machine. The timer can call the state machine at the rate at which you want things to change. The state machine can look at the last ramp value and the time of the last button hit (or even an array of UI event times) and decide whether and how much to ramp the volume during the next time step (logic is often just a pile of if and select/case statements if the control algorithm isn't amenable to a nice table). Then the state machine can call the object or routine that handles the actual sound level.

hotpaw2
Thanks but as you can see in the discussion on the other answer above about NSTimer, it does not have large enough resolution to work with pitch (which would result in very audible steps). I would probably need to run the state machine in a separate thread or something like that.
materialvision
+1  A: 

Have a look at NSOperation and the Concurrency Programming Guide. You can first start you operation the increase the pitch and also store the operation object. On the second call you can call [operation cancel] to stop the last operation. Start a second operation to i.e. decrease the pitch and also store the new object.

Btw: What you are doing right now is very bad since you "block the main thread". Calculations that take some time should not be directly executed. You should probably also have a look at NSTimer to make your code independent of the processor speed.

Felix
Thanks I will look into NSOperation, but I will probably still need some kind of multithreading as you can see from the other answers regarding NSTimer not being fast enough.
materialvision
@materialvision: If you need threading, NSOperation is the easiest way to do it.
Chuck
@materialvision: NSOperation *is* a way to do multithreading. The operation queue spawns a new thread for each operation that is on it.
JeremyP