views:

419

answers:

3

I've written a cheap & cheerful sound board in for my Mac, and I play the various sounds with NSSound like this:

-(void)play:(NSSound *)soundEffect:(BOOL)stopIfPlaying {
    BOOL wasPlaying = FALSE;

    if([nowPlaying isPlaying])  {
        [nowPlaying stop];
        wasPlaying = TRUE;
    }   

    if(soundEffect != nowPlaying)
    {
        [soundEffect play];
        nowPlaying = soundEffect;
    } else if(soundEffect == nowPlaying && ![nowPlaying isPlaying] && !wasPlaying) {
        [nowPlaying play];
    }
}

Rather than just stop it dead, I'd like it to fade out over a couple of seconds or so.

A: 

Something like this perhaps? You probably want a more linear dropoff, but the basic idea is make a loop and sleep the period of time till the next update.

if([nowPlaying isPlaying])  {
    for(int i = 1; i < 100; ++i)
    {
        [nowPlaying setVolume: (1.0 / i)];
        Sleep(20);
    }
    [nowPlaying stop];
    wasPlaying = TRUE;
}
Chris Blackwell
I just tried this Chris, the Sleep function put the whole laptop to sleep, which made me chuckle.sleep works fine, except the parameter it takes in seconds rather than milliseconds.
Stuart Grimshaw
Curses on you errant shift key!
Chris Blackwell
A: 

This is the final version of the method:

-(void)play:(NSSound *)soundEffect:(BOOL)stopIfPlaying {
    BOOL wasPlaying = FALSE;

    if([nowPlaying isPlaying]) {
     struct timespec ts;
     ts.tv_sec = 0;
     ts.tv_nsec = 25000000;

     // If the sound effect is the same, fade it out.
     if(soundEffect == nowPlaying)
     {
      for(int i = 1; i < 30; ++i)
      {
       [nowPlaying setVolume: (1.0 / i )];
       nanosleep(&ts, &ts);
      }   
     }

     [nowPlaying stop];
     [nowPlaying setVolume:1];
     wasPlaying = TRUE;
    } 

    if(soundEffect != nowPlaying)
    {
     [soundEffect play];
     nowPlaying = soundEffect;
    } else if(soundEffect == nowPlaying && ![nowPlaying isPlaying] && !wasPlaying) {
     [nowPlaying play];
    }
}

So it only fades out if I pass the same sound in (ie, click the same button), also, I went for nanosleep rather than sleep, as that on has a granularity of 1 second.

I struggled for a while trying to work out why my 200 millisecond delay didn't seem to have any effect, but then 200 NANOseconds isn't really that long is it :-)

Stuart Grimshaw
+1  A: 

I would use NSTimer to avoid blocking the main thread.

Marc Charbonneau