Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fade an NSSound object

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.

like image 670
Stuart Grimshaw Avatar asked Nov 06 '22 22:11

Stuart Grimshaw


2 Answers

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 :-)

like image 153
Stuart Grimshaw Avatar answered Nov 15 '22 12:11

Stuart Grimshaw


I would use NSTimer to avoid blocking the main thread.

like image 28
Marc Charbonneau Avatar answered Nov 15 '22 13:11

Marc Charbonneau