Fade out and pause issue

I am trying to work out how to fade out and pause the sound, then unpause it.

I customised the basic ‘3d’ example (for iOS) with this code:

if (Common_BtnPress(BTN_ACTION2))
{
    bool paused;
    channel2->setVolume(1.0);
    channel2->setPaused(false);
    channel2->setDelay(0, 0);
    ERRCHECK(result);
}

if (Common_BtnPress(BTN_MORE))
{
    unsigned long long parentclock;
    channel2->getDSPClock(nullptr, &parentclock);
    unsigned long long fadepoint = parentclock + 44100;
    channel2->addFadePoint(parentclock, 1.0);
    channel2->addFadePoint(fadepoint, 0.0);
    channel2->setDelay(0, fadepoint, false);
}

As you can see, the ‘B’ button unpauses the sound. (I also paused everything to begin with. The ‘E’ button fades out and sets a delay for pausing the sound. Both those actions

On pressing the ‘B’ button again, it doesn’t unpause it.

I read in the documentation

False: When dspclock_end is reached, behaves like ChannelControl::setPaused has been called, a subsequent dspclock_start allows it to resume.

…but I don’t fully understand what it’s asking me to do. I’ve tried lots of combinations of setDelay but it won’t unpause.

Any help would be greatly appreciated.

Some further digging. In order to unpause a sound which has been paused with addFadePoint and setDelay, you have to have another call to both addFadePoint and setDelay, like this.

unsigned long long dspclock;
unsigned long long parentclock;
channel2->getDSPClock(&dspclock, &parentclock);
channel2->addFadePoint(parentclock, 1.0f);
channel2->setDelay(0, 0, false);
channel2->setPaused(false);

However, I am still stuck here because pausing a sound like this:

unsigned long long parentclock;
channel2->getDSPClock(nullptr, &parentclock);
unsigned long long fadepoint = parentclock + 132300;
channel2->addFadePoint(parentclock, 1.0);
channel2->addFadePoint(fadepoint, 0.0);
channel2->setDelay(0, fadepoint, false);

A subsequent call to getPaused (after the fade) returns false (incorrect, as it should have paused with the setDelay call?)

…and a call to isPlaying returns true. So how do we tell when we’ve paused a sound after fading?

I figured it out, but be prepared for a very circuitous answer. This functions just checks if a sound is actively playing on the channel.

We have to check:

  1. if the channel is ‘playing’ (active)
  2. if the sound is paused
  3. if there are any delays set
  4. if there are any future fade points

code

bool isPlaying() {
    // check if the channel is inactive
    bool isplaying = false;
    result = channel->isPlaying(&isplaying);
    if ((result != FMOD_OK) && (result != FMOD_ERR_INVALID_HANDLE)) {
        LOGE("fmod:: Error getting isPlaying status because: %s\n", FMOD_ErrorString(result));
    }
    if (!isplaying) {
        return false;
    }
    
    // check if the sound is paused
    bool paused = true;
    result = channel->getPaused(&paused);
    if (paused) {
        return false;
    }

    // check for scheduled fades
    unsigned long long dspclock_start = 0;
    unsigned long long dspclock_end = 0;
    result = channel->getDelay(&dspclock_start, &dspclock_end, 0);
    if ((result != FMOD_OK) && (result != FMOD_ERR_INVALID_HANDLE)) {
        LOGE("fmod:: Error getting delay because: %s\n", FMOD_ErrorString(result));
    }
    if (dspclock_start > 0 || dspclock_end > 0) {
        // it's set to either play in the future or stop in the future
        // or a fade has been performed
        // if a fade's been performed, there won't be any fade points
        // need to check if there's an active fade
        unsigned int numpoints;
        result = channel->getFadePoints(&numpoints, 0, 0);
        if ((result != FMOD_OK) && (result != FMOD_ERR_INVALID_HANDLE)) {
            LOGE("fmod:: Error getting fade points because: %s\n", FMOD_ErrorString(result));
        }
        if (numpoints) {
            // we're in a fade
            return true;
        }
        return false;
    }
    return true;
}

In the documentation it states for the stopchannels argument that:

False: When dspclock_end is reached, behaves like ChannelControl::setPaused has been called, a subsequent dspclock_start allows it to resume.

However, the word ‘like’ here encapsulates quite a lot of assumptions, and quite a bit of extra code to actually figure out what the state of the channel is. It’s difficult to work out if it’s actually playing sound or not if setDelay and/or addFadePoints has been called.

I hope this may help others in the future when they’re trying to work out if a sound has completed fading, has been paused with setDelay or has been manually paused with setPaused.

ChannelControl::isPlaying is working as intended, calling play on a sound means it is ‘playing’ until it is stopped. Even if it is paused it is still ‘playing’.

A Channel is considered playing after System::playSound or System::playDSP, even if it is paused.

You could also use ChannelControl::getAudibility which goes to zero when delayed and paused and should be one for everything else.

Thanks for the reply, and the tip about getAudibility - that’s helpful.

The issue I had was that the call to setDelay did not pause it. Even though the sound had ‘paused’ when it came to the clock time, calling setPaused(false) did not unpause it. You had to check if there was a delay set using getDelay then unset it using setDelay(0, 0).

Then setVolume did not work, because of the previous fade point. You had to check if there were fade points set using getFadePoints, then remove them and set another fade point at the volume you wanted.

It sounds like getAudibility might circumvent all of this, though! Thanks :slight_smile:

1 Like