Search code examples
macosaudiofmod

FMOD Ex dropping sounds, eventually going silent


I'm attempting to port an old open-source FMOD 3 game (Candy Crisis) to the latest version of FMOD Ex 4 on OS X. Its sound needs are very simple—it plays WAVs, sometimes changing their frequency or speaker mix, and also plays MOD tracker music, sometimes changing the speed. I'm finding that the game works fine at first, but over the course of a few minutes, it starts truncating sounds early, then the music loses channels and eventually stops, then over time all sound ceases. I can cause the problem to reproduce more quickly if I lower the number of channels available to FMOD.

I can get the truncated/missing sounds issue to occur even if I never play a music file, but music definitely seems to make things worse. I have also tried commenting out the code which adjusts the sound frequency and speaker mix, and that was not the issue.

I am calling update() every frame.

Here's the entirety of my interactions with FMOD to play WAVs:

void InitSound( void )
{
    FMOD_RESULT   result = FMOD::System_Create(&g_fmod);
    FMOD_ERRCHECK(result);

    unsigned int  version;
    result = g_fmod->getVersion(&version);
    FMOD_ERRCHECK(result);

    if (version < FMOD_VERSION)
    {
        printf("Error!  You are using an old version of FMOD %08x.  This program requires %08x\n", version, FMOD_VERSION);
        abort();
    }

    result = g_fmod->init(8 /* was originally 64, but 8 repros the issue faster */, FMOD_INIT_NORMAL, 0);
    FMOD_ERRCHECK(result);

    for (int index=0; index<kNumSounds; index++)
    {
        result = g_fmod->createSound(QuickResourceName("snd", index+128, ".wav"), FMOD_DEFAULT, 0, &s_sound[index]);
        FMOD_ERRCHECK(result);
    }
}


void PlayMono( short which )
{
    if (soundOn)
    {
        FMOD_RESULT       result = g_fmod->playSound(FMOD_CHANNEL_FREE, s_sound[which], false, NULL);
        FMOD_ERRCHECK(result);
    }
}

void PlayStereoFrequency( short player, short which, short freq )
{
    if (soundOn)
    {
        FMOD::Channel*    channel = NULL;
        FMOD_RESULT       result = g_fmod->playSound(FMOD_CHANNEL_FREE, s_sound[which], true, &channel);
        FMOD_ERRCHECK(result);

        result = channel->setSpeakerMix(player, 1.0f - player, 0, 0, 0, 0, 0, 0);
        FMOD_ERRCHECK(result);

        float channelFrequency;
        result = s_sound[which]->getDefaults(&channelFrequency, NULL, NULL, NULL);
        FMOD_ERRCHECK(result);

        result = channel->setFrequency((channelFrequency * (16 + freq)) / 16);
        FMOD_ERRCHECK(result);

        result = channel->setPaused(false);
        FMOD_ERRCHECK(result);
    }
}

void UpdateSound()
{
    g_fmod->update();
}

And here's how I play MODs.

void ChooseMusic( short which )
{
    if( musicSelection >= 0 && musicSelection <= k_songs )  
    {
        s_musicChannel->stop();
        s_musicChannel = NULL;

        s_musicModule->release();
        s_musicModule = NULL;

        musicSelection = -1;
    }

    if (which >= 0 && which <= k_songs)
    {
        FMOD_RESULT result = g_fmod->createSound(QuickResourceName("mod", which+128, ""), FMOD_DEFAULT, 0, &s_musicModule);
        FMOD_ERRCHECK(result);

        result = g_fmod->playSound(FMOD_CHANNEL_FREE, s_musicModule, true, &s_musicChannel);
        FMOD_ERRCHECK(result);

        EnableMusic(musicOn);
        s_musicModule->setLoopCount(-1);
        s_musicChannel->setPaused(false);

        musicSelection = which;
        s_musicPaused  = 0;
    }
}

If someone wants to experiment with this, let me know and I'll upload the project somewhere. My gut feeling is that FMOD is busted but I'd love to be proven wrong.


Solution

  • Every time I play the following WAV, FMOD loses one channel permanently. I am able to reproduce this channel-losing behavior in the "playsound" example if I replace the existing jaguar.wav with my file.

    https://drive.google.com/file/d/0B1eDRY8sV_a9SXMyNktXbWZOYWs/view?usp=sharing

    I contacted Firelight and got this response. Apparently WAVs can include a looping command! I had no idea.

    Hello John,

    I've taken a look at the two files you have provided. Both files end with a 2 sample infinite loop region.

    FMOD 4 (and FMOD 5 for that matter) will see the loop region in the file and automatically enable FMOD_LOOP_NORMAL if you haven't specified any loop mode. Assuming you want one-shot behavior just pass in FMOD_LOOP_OFF when you create the sound.

    Kind regards, Mathew Block | Senior Platform Engineer

    Technically this behavior contradicts the documented behavior of FMOD_DEFAULT (which is specified to imply FMOD_LOOP_OFF) so they are planning to improve the documentation here.