Esempio n. 1
0
int main(int argc, char *argv[])
{
    FMOD::System       *system;
    FMOD::Sound        *sound[6];
    FMOD::Channel      *channel[6];
    FMOD::ChannelGroup *groupA, *groupB, *masterGroup;
    FMOD_RESULT         result;
    int                 key, count;
    unsigned int        version;

    /*
        Create a System object and initialize.
    */
    result = FMOD::System_Create(&system);
    ERRCHECK(result);

    result = system->getVersion(&version);
    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);
        return 0;
    }

    result = system->init(32, FMOD_INIT_NORMAL, 0);
    ERRCHECK(result);

    result = system->createSound("../media/drumloop.wav", FMOD_LOOP_NORMAL, 0, &sound[0]);
    ERRCHECK(result);
    result = system->createSound("../media/jaguar.wav", FMOD_LOOP_NORMAL, 0, &sound[1]);
    ERRCHECK(result);
    result = system->createSound("../media/swish.wav", FMOD_LOOP_NORMAL, 0, &sound[2]);
    ERRCHECK(result);
    result = system->createSound("../media/c.ogg", FMOD_LOOP_NORMAL, 0, &sound[3]);
    ERRCHECK(result);
    result = system->createSound("../media/d.ogg", FMOD_LOOP_NORMAL, 0, &sound[4]);
    ERRCHECK(result);
    result = system->createSound("../media/e.ogg", FMOD_LOOP_NORMAL, 0, &sound[5]);
    ERRCHECK(result);

    result = system->createChannelGroup("Group A", &groupA);
    ERRCHECK(result);

    result = system->createChannelGroup("Group B", &groupB);
    ERRCHECK(result);

    result = system->getMasterChannelGroup(&masterGroup);
    ERRCHECK(result);

    printf("=======================================================================\n");
    printf("ChannelGroups Example.  Copyright (c) Firelight Technologies 2004-2014.\n");
    printf("=======================================================================\n");
    printf("\n");
    printf("Group A : drumloop.wav, jaguar.wav, swish.wav\n");
    printf("Group B : c.ogg, d.ogg, e.ogg\n");
    printf("\n");
    printf("Press 'A' to mute/unmute group A\n");
    printf("Press 'B' to mute/unmute group B\n");
    printf("Press 'C' to mute/unmute group A and B (master group)\n");
    printf("Press 'Esc' to quit\n");
    printf("\n");

    /*
        Instead of being independent, set the group A and B to be children of the master group.
    */
    result = masterGroup->addGroup(groupA);
    ERRCHECK(result);

    result = masterGroup->addGroup(groupB);
    ERRCHECK(result);

    /*
        Start all the sounds!
    */
    for (count = 0; count < 6; count++)
    {
        result = system->playSound(FMOD_CHANNEL_FREE, sound[count], true, &channel[count]);
        ERRCHECK(result);
        if (count < 3)
        {
            result = channel[count]->setChannelGroup(groupA);
        }
        else
        {
            result = channel[count]->setChannelGroup(groupB);
        }
        ERRCHECK(result);
        result = channel[count]->setPaused(false);
        ERRCHECK(result);
    }   

    /*
        Change the volume of each group, just because we can!  (And makes it less noise).
    */
    result = groupA->setVolume(0.5f);
    ERRCHECK(result);
    result = groupB->setVolume(0.5f);
    ERRCHECK(result);

    /*
        Main loop.
    */
    do
    {
        if (kbhit())
        {
            key = getch();

            switch (key)
            {
                case 'a' : 
                case 'A' : 
                {
                    static bool mute = true;

                    groupA->setMute(mute);

                    mute = !mute;
                    break;
                }
                case 'b' : 
                case 'B' : 
                {
                    static bool mute = true;

                    groupB->setMute(mute);

                    mute = !mute;
                    break;
                }
                case 'c' : 
                case 'C' : 
                {
                    static bool mute = true;

                    masterGroup->setMute(mute);

                    mute = !mute;
                    break;
                }
            }
        }

        system->update();

        {
            int  channelsplaying = 0;

            system->getChannelsPlaying(&channelsplaying);

            printf("Channels Playing %2d\r", channelsplaying);
        }

        Sleep(10);

    } while (key != 27);

    printf("\n");

    /*
        A little fade out. (over 2 seconds)
    */
    printf("Goodbye!\n");
    {
        float pitch = 1.0f;
        float vol = 1.0f;

        for (count = 0; count < 200; count++)
        {
            masterGroup->setPitch(pitch);
            masterGroup->setVolume(vol);

            vol   -= (1.0f / 200.0f);
            pitch -= (0.5f / 200.0f);

            Sleep(10);
        }
    }

    /*
        Shut down
    */
    for (count = 0; count < 6; count++)
    {
        result = sound[count]->release();
        ERRCHECK(result);
    }

    result = groupA->release();
    ERRCHECK(result);
    result = groupB->release();
    ERRCHECK(result);

    result = system->close();
    ERRCHECK(result);
    result = system->release();
    ERRCHECK(result);

    return 0;
}
Esempio n. 2
0
int FMOD_Main()
{
    FMOD::System           *system;
    FMOD::Sound            *sound[3];
    FMOD::Channel          *channel = 0;
    FMOD::ChannelGroup     *channelgroup = 0;
    FMOD_RESULT             result;
    unsigned int            version, dsp_block_len, count;
    int                     outputrate = 0;
    void                   *extradriverdata = 0;
    
    Common_Init(&extradriverdata);

    /*
        Create a System object and initialize.
    */
    result = FMOD::System_Create(&system);
    ERRCHECK(result);

    result = system->getVersion(&version);
    ERRCHECK(result);

    if (version < FMOD_VERSION)
    {
        Common_Fatal("FMOD lib version %08x doesn't match header version %08x", version, FMOD_VERSION);
    }
    
    result = system->init(100, FMOD_INIT_NORMAL, extradriverdata);
    ERRCHECK(result);

    /*
        Get information needed later for scheduling.  The mixer block size, and the output rate of the mixer.
    */
    result = system->getDSPBufferSize(&dsp_block_len, 0);
    ERRCHECK(result);

    result = system->getSoftwareFormat(&outputrate, 0, 0);
    ERRCHECK(result);

    /*
        Load 3 sounds - these are just sine wave tones at different frequencies.  C, D and E on the musical scale.
    */
    result = system->createSound(Common_MediaPath("c.ogg"), FMOD_DEFAULT, 0, &sound[NOTE_C]);
    ERRCHECK(result);
    result = system->createSound(Common_MediaPath("d.ogg"), FMOD_DEFAULT, 0, &sound[NOTE_D]);
    ERRCHECK(result);
    result = system->createSound(Common_MediaPath("e.ogg"), FMOD_DEFAULT, 0, &sound[NOTE_E]);
    ERRCHECK(result);

    /* 
        Create a channelgroup that the channels will play on.  We can use this channelgroup as our clock reference. 
        It also means we can pause and pitch bend the channelgroup, without affecting the offsets of the delays, because the channelgroup clock
        which the channels feed off, will be pausing and speeding up/slowing down and still keeping the children in sync.
    */
    result = system->createChannelGroup("Parent", &channelgroup);
    ERRCHECK(result);

    unsigned int numsounds = sizeof(note) / sizeof(note[0]);

    /*
        Play all the sounds at once! Space them apart with set delay though so that they sound like they play in order.
    */
    for (count = 0; count < numsounds; count++)
    {
        static unsigned long long clock_start = 0;
        unsigned int slen;
        FMOD::Sound *s = sound[note[count]];                            /* Pick a note from our tune. */

        result = system->playSound(s, channelgroup, true, &channel);    /* Play the sound on the channelgroup we want to use as the parent clock reference (for setDelay further down) */
        ERRCHECK(result);

        if (!clock_start)
        {
            result = channel->getDSPClock(0, &clock_start);
            ERRCHECK(result);

            clock_start += (dsp_block_len * 2);                         /* Start the sound into the future, by 2 mixer blocks worth. */
                                                                        /* Should be enough to avoid the mixer catching up and hitting the clock value before we've finished setting up everything. */
                                                                        /* Alternatively the channelgroup we're basing the clock on could be paused to stop it ticking. */
        }
        else
        {
            float freq;

            result = s->getLength(&slen, FMOD_TIMEUNIT_PCM);            /* Get the length of the sound in samples. */
            ERRCHECK(result);

            result = s->getDefaults(&freq, 0);                          /* Get the default frequency that the sound was recorded at. */
            ERRCHECK(result);

            slen = (unsigned int)((float)slen / freq * outputrate);     /* Convert the length of the sound to 'output samples' for the output timeline. */
            
            clock_start += slen;                                        /* Place the sound clock start time to this value after the last one. */
        }

        result = channel->setDelay(clock_start, 0, false);              /* Schedule the channel to start in the future at the newly calculated channelgroup clock value. */
        ERRCHECK(result);

        result = channel->setPaused(false);                             /* Unpause the sound.  Note that you won't hear the sounds, they are scheduled into the future. */
        ERRCHECK(result);
    }

    /*
        Main loop.
    */
    do
    {
        Common_Update();

        if (Common_BtnPress(BTN_ACTION1))                               /* Pausing the channelgroup as the clock parent, will pause any scheduled sounds from continuing */
        {                                                               /* If you paused the channel, this would not stop the clock it is delayed against from ticking,  */
            bool paused;                                                /* and you'd have to recalculate the delay for the channel into the future again before it was unpaused. */
            result = channelgroup->getPaused(&paused);
            ERRCHECK(result);
            result = channelgroup->setPaused(!paused);
            ERRCHECK(result);
        }
        if (Common_BtnPress(BTN_ACTION2)) 
        {                                 
            for (count = 0; count < 50; count++)
            {
                float pitch;
                result = channelgroup->getPitch(&pitch);
                ERRCHECK(result);
                pitch += 0.01f;
                result = channelgroup->setPitch(pitch);
                ERRCHECK(result);

                result = system->update();
                ERRCHECK(result);

                Common_Sleep(10);
            }
        }
        if (Common_BtnPress(BTN_ACTION3)) 
        {                                 
            for (count = 0; count < 50; count++)
            {
                float pitch;
                result = channelgroup->getPitch(&pitch);
                ERRCHECK(result);

                if (pitch > 0.1f)
                {
                    pitch -= 0.01f;
                }
                result = channelgroup->setPitch(pitch);
                ERRCHECK(result);
                
                result = system->update();
                ERRCHECK(result);

                Common_Sleep(10);
            }
        }

        result = system->update();
        ERRCHECK(result);

        /*
            Print some information
        */
        {
            bool    playing = false;
            bool    paused = false;
            int     chansplaying;

            if (channelgroup)
            {
                result = channelgroup->isPlaying(&playing);
                if ((result != FMOD_OK) && (result != FMOD_ERR_INVALID_HANDLE))
                {
                    ERRCHECK(result);
                }

                result = channelgroup->getPaused(&paused);
                if ((result != FMOD_OK) && (result != FMOD_ERR_INVALID_HANDLE))
                {
                    ERRCHECK(result);
                }
            }

            result = system->getChannelsPlaying(&chansplaying);
            ERRCHECK(result);

            Common_Draw("==================================================");
            Common_Draw("Gapless Playback example.");
            Common_Draw("Copyright (c) Firelight Technologies 2004-2014.");
            Common_Draw("==================================================");
            Common_Draw("");
            Common_Draw("Press %s to toggle pause", Common_BtnStr(BTN_ACTION1));
            Common_Draw("Press %s to increase pitch", Common_BtnStr(BTN_ACTION2));
            Common_Draw("Press %s to decrease pitch", Common_BtnStr(BTN_ACTION3));
            Common_Draw("Press %s to quit", Common_BtnStr(BTN_QUIT));
            Common_Draw("");
            Common_Draw("Channels Playing %d : %s", chansplaying, paused ? "Paused " : playing ? "Playing" : "Stopped");
        }

        Common_Sleep(50);
    } while (!Common_BtnPress(BTN_QUIT));

    /*
        Shut down
    */
    result = sound[NOTE_C]->release();
    ERRCHECK(result);
    result = sound[NOTE_D]->release();
    ERRCHECK(result);
    result = sound[NOTE_E]->release();
    ERRCHECK(result);

    result = system->close();
    ERRCHECK(result);
    result = system->release();
    ERRCHECK(result);

    Common_Close();

    return 0;
}
int FMOD_Main()
{
    FMOD::System       *system;
    FMOD::Sound        *sound[6];
    FMOD::Channel      *channel[6];
    FMOD::ChannelGroup *groupA, *groupB, *masterGroup;
    FMOD_RESULT         result;
    int                 count;
    unsigned int        version;
    void               *extradriverdata = 0;

    Common_Init(&extradriverdata);

    /*
        Create a System object and initialize.
    */
    result = FMOD::System_Create(&system);
    ERRCHECK(result);

    result = system->getVersion(&version);
    ERRCHECK(result);

    if (version < FMOD_VERSION)
    {
        Common_Fatal("FMOD lib version %08x doesn't match header version %08x", version, FMOD_VERSION);
    }

    result = system->init(32, FMOD_INIT_NORMAL, extradriverdata);
    ERRCHECK(result);

    result = system->createSound(Common_MediaPath("drumloop.wav"), FMOD_LOOP_NORMAL, 0, &sound[0]);
    ERRCHECK(result);
    result = system->createSound(Common_MediaPath("jaguar.wav"), FMOD_LOOP_NORMAL, 0, &sound[1]);
    ERRCHECK(result);
    result = system->createSound(Common_MediaPath("swish.wav"), FMOD_LOOP_NORMAL, 0, &sound[2]);
    ERRCHECK(result);
    result = system->createSound(Common_MediaPath("c.ogg"), FMOD_LOOP_NORMAL, 0, &sound[3]);
    ERRCHECK(result);
    result = system->createSound(Common_MediaPath("d.ogg"), FMOD_LOOP_NORMAL, 0, &sound[4]);
    ERRCHECK(result);
    result = system->createSound(Common_MediaPath("e.ogg"), FMOD_LOOP_NORMAL, 0, &sound[5]);
    ERRCHECK(result);

    result = system->createChannelGroup("Group A", &groupA);
    ERRCHECK(result);
    result = system->createChannelGroup("Group B", &groupB);
    ERRCHECK(result);

    result = system->getMasterChannelGroup(&masterGroup);
    ERRCHECK(result);

    /*
        Instead of being independent, set the group A and B to be children of the master group.
    */
    result = masterGroup->addGroup(groupA);
    ERRCHECK(result);

    result = masterGroup->addGroup(groupB);
    ERRCHECK(result);

    /*
        Start all the sounds.
    */
    for (count = 0; count < 6; count++)
    {
        result = system->playSound(sound[count], 0, true, &channel[count]);
        ERRCHECK(result);
        
        result = channel[count]->setChannelGroup((count < 3) ? groupA : groupB);
        ERRCHECK(result);
        
        result = channel[count]->setPaused(false);
        ERRCHECK(result);
    }   

    /*
        Change the volume of each group, just because we can! (reduce overall noise).
    */
    result = groupA->setVolume(0.5f);
    ERRCHECK(result);
    result = groupB->setVolume(0.5f);
    ERRCHECK(result);

    /*
        Main loop.
    */
    do
    {
        Common_Update();

        if (Common_BtnPress(BTN_ACTION1))
        {
            bool mute = true;
            groupA->getMute(&mute);
            groupA->setMute(!mute);
        }

        if (Common_BtnPress(BTN_ACTION2))
        {
            bool mute = true;
            groupB->getMute(&mute);
            groupB->setMute(!mute);
        }

        if (Common_BtnPress(BTN_ACTION3))
        {
            bool mute = true;
            masterGroup->getMute(&mute);
            masterGroup->setMute(!mute);
        }

        result = system->update();
        ERRCHECK(result);

        {
            int channelsplaying = 0;

            result = system->getChannelsPlaying(&channelsplaying);
            ERRCHECK(result);

            Common_Draw("==================================================");
            Common_Draw("Channel Groups Example.");
            Common_Draw("Copyright (c) Firelight Technologies 2004-2014.");
            Common_Draw("==================================================");
            Common_Draw("");
            Common_Draw("Group A : drumloop.wav, jaguar.wav, swish.wav");
            Common_Draw("Group B : c.ogg, d.ogg, e.ogg");
            Common_Draw("");
            Common_Draw("Press %s to mute/unmute group A", Common_BtnStr(BTN_ACTION1));
            Common_Draw("Press %s to mute/unmute group B", Common_BtnStr(BTN_ACTION2));
            Common_Draw("Press %s to mute/unmute master group", Common_BtnStr(BTN_ACTION3));
            Common_Draw("Press %s to quit", Common_BtnStr(BTN_QUIT));
            Common_Draw("");
            Common_Draw("Channels playing %d", channelsplaying);
        }

        Common_Sleep(50);
    } while (!Common_BtnPress(BTN_QUIT));


    /*
        A little fade out over 2 seconds.
    */
    {
        float pitch = 1.0f;
        float vol = 1.0f;

        for (count = 0; count < 200; count++)
        {
            masterGroup->setPitch(pitch);
            masterGroup->setVolume(vol);

            vol   -= (1.0f / 200.0f);
            pitch -= (0.5f / 200.0f);

            Common_Sleep(10);
        }
    }

    /*
        Shut down.
    */
    for (count = 0; count < 6; count++)
    {
        result = sound[count]->release();
        ERRCHECK(result);
    }

    result = groupA->release();
    ERRCHECK(result);
    result = groupB->release();
    ERRCHECK(result);

    result = system->close();
    ERRCHECK(result);
    result = system->release();
    ERRCHECK(result);

    Common_Close();

    return 0;
}
int FMOD_Main()
{
    void *extradriverdata = 0;    
    Common_Init(&extradriverdata);

    /*
        Create a System object and initialize
    */
    FMOD_RESULT result;
    FMOD::System* system;
    result = FMOD::System_Create(&system);
    ERRCHECK(result);

    unsigned int version;
    result = system->getVersion(&version);
    ERRCHECK(result);

    if (version < FMOD_VERSION)
    {
        Common_Fatal("FMOD lib version %08x doesn't match header version %08x", version, FMOD_VERSION);
    }
    
    result = system->init(32, FMOD_INIT_NORMAL, extradriverdata);
    ERRCHECK(result);
        

    /*
        Create a new channel group to hold the convolution DSP unit
    */
    FMOD::ChannelGroup* reverbGroup;
    result = system->createChannelGroup("reverb", &reverbGroup);
    ERRCHECK(result);

    
    /*
        Create a new channel group to hold all the channels and process the dry path
    */
    FMOD::ChannelGroup* mainGroup;
    result = system->createChannelGroup("main", &mainGroup);
    ERRCHECK(result);

    /*
        Create the convultion DSP unit and set it as the tail of the channel group
    */
    FMOD::DSP* reverbUnit;    
    result = system->createDSPByType(FMOD_DSP_TYPE_CONVOLUTIONREVERB, &reverbUnit);
    ERRCHECK(result);
    result = reverbGroup->addDSP(FMOD_CHANNELCONTROL_DSP_TAIL, reverbUnit);
    ERRCHECK(result);

    /*
        Open the impulse response wav file, but use FMOD_OPENONLY as we want
        to read the data into a seperate buffer
    */
    FMOD::Sound* irSound;
    result = system->createSound(Common_MediaPath("standrews.wav"), FMOD_DEFAULT | FMOD_OPENONLY, NULL, &irSound);
    ERRCHECK(result);

    /*
        Retrieve the sound information for the Impulse Response input file
    */
    FMOD_SOUND_FORMAT irSoundFormat;
    FMOD_SOUND_TYPE irSoundType;
    int irSoundBits, irSoundChannels;
    result = irSound->getFormat(&irSoundType, &irSoundFormat, &irSoundChannels, &irSoundBits);
    ERRCHECK(result);
    unsigned int irSoundLength;
    result = irSound->getLength(&irSoundLength, FMOD_TIMEUNIT_PCM);
    ERRCHECK(result);

    
    if (irSoundFormat != FMOD_SOUND_FORMAT_PCM16)
    {
        /*
            For simplicity of the example, if the impulse response is the wrong format just display an error
        */        
        Common_Fatal("Impulse Response file is the wrong audio format");
    }

    /*
        The reverb unit expects a block of data containing a single 16 bit int containing
        the number of channels in the impulse response, followed by PCM 16 data
    */
    unsigned int irDataLength = sizeof(short) * (irSoundLength * irSoundChannels + 1);
    short* irData = (short*)malloc(irDataLength);
    irData[0] = irSoundChannels;
    unsigned int irDataRead;
    result = irSound->readData(&irData[1], irDataLength - sizeof(short), &irDataRead);
    ERRCHECK(result);
    result = reverbUnit->setParameterData(FMOD_DSP_CONVOLUTION_REVERB_PARAM_IR, irData, irDataLength);
    ERRCHECK(result);

    /*
        Don't pass any dry signal from the reverb unit, instead take the dry part
        of the mix from the main signal path
    */
    result = reverbUnit->setParameterFloat(FMOD_DSP_CONVOLUTION_REVERB_PARAM_DRY, -80.0f);    
    ERRCHECK(result);

    /*
        We can now free our copy of the IR data and release the sound object, the reverb unit 
        has created it's internal data
    */
    free(irData);
    result = irSound->release();
    ERRCHECK(result);
    
    /*
        Load up and play a sample clip recorded in an anechoic chamber
    */
    FMOD::Sound* sound;
    system->createSound(Common_MediaPath("singing.wav"), FMOD_3D | FMOD_LOOP_NORMAL, NULL, &sound);
    ERRCHECK(result);

    FMOD::Channel* channel;
    system->playSound(sound, mainGroup, true, &channel);
    ERRCHECK(result);
    
    /*
        Create a send connection between the channel head and the reverb unit
    */
    FMOD::DSP* channelHead;
    channel->getDSP(FMOD_CHANNELCONTROL_DSP_HEAD, &channelHead);
    ERRCHECK(result);
    FMOD::DSPConnection* reverbConnection;
    result = reverbUnit->addInput(channelHead, &reverbConnection, FMOD_DSPCONNECTION_TYPE_SEND);
    ERRCHECK(result);

    result = channel->setPaused(false);
    ERRCHECK(result);


    float wetVolume = 1.0;
    float dryVolume = 1.0;

    /*
        Main loop
    */
    do
    {
        Common_Update();

        if (Common_BtnPress(BTN_LEFT))
        {
            wetVolume = (wetVolume <= 0.0f) ? wetVolume : wetVolume - 0.05;
        }
        if (Common_BtnPress(BTN_RIGHT))
        {
            wetVolume = (wetVolume >= 1.0f) ? wetVolume : wetVolume + 0.05f;
        }        
        if (Common_BtnPress(BTN_DOWN))
        {
            dryVolume = (dryVolume <= 0.0f) ? dryVolume : dryVolume - 0.05f;
        }
        if (Common_BtnPress(BTN_UP))
        {
            dryVolume = (dryVolume >= 1.0f) ? dryVolume : dryVolume + 0.05f;
        }
        

        result = system->update();
        ERRCHECK(result);

        result = reverbConnection->setMix(wetVolume);
        ERRCHECK(result);
        result = mainGroup->setVolume(dryVolume);
        ERRCHECK(result);


        Common_Draw("==================================================");
        Common_Draw("Convolution Example.");
        Common_Draw("Copyright (c) Firelight Technologies 2004-2015.");
        Common_Draw("==================================================");
        Common_Draw("Press %s and %s to change dry mix", Common_BtnStr(BTN_UP), Common_BtnStr(BTN_DOWN));
        Common_Draw("Press %s and %s to change wet mix", Common_BtnStr(BTN_LEFT), Common_BtnStr(BTN_RIGHT));
        Common_Draw("wet mix [%.2f] dry mix [%.2f]", wetVolume, dryVolume);
        Common_Draw("Press %s to quit", Common_BtnStr(BTN_QUIT));
        Common_Draw("");

        Common_Sleep(50);
    } while (!Common_BtnPress(BTN_QUIT));

    /*
        Shut down
    */
    result = sound->release();
    ERRCHECK(result);
    result = mainGroup->release();
    ERRCHECK(result);
    result = reverbGroup->removeDSP(reverbUnit);
    ERRCHECK(result);
    result = reverbUnit->disconnectAll(true, true);
    ERRCHECK(result);
    result = reverbUnit->release();
    ERRCHECK(result);
    result = reverbGroup->release();
    ERRCHECK(result);
    result = system->close();
    ERRCHECK(result);
    result = system->release();
    ERRCHECK(result);

    Common_Close();

    return 0;
}
Esempio n. 5
0
int main(int argc, char *argv[])
{
    FMOD::System       *system;
    FMOD::Sound        *sound[5];
    FMOD::Channel      *channel[5];
    FMOD::ChannelGroup *groupA, *groupB, *masterGroup;
    FMOD::DSP          *dspreverb, *dspflange, *dsplowpass;
    FMOD_RESULT         result;
    int                 key, count;
    unsigned int        version;

    /*
        Create a System object and initialize.
    */
    result = FMOD::System_Create(&system);
    ERRCHECK(result);

    result = system->getVersion(&version);
    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);
        return 0;
    }

    result = system->init(32, FMOD_INIT_NORMAL, 0);
    ERRCHECK(result);

    result = system->createSound("../media/drumloop.wav", FMOD_SOFTWARE | FMOD_LOOP_NORMAL, 0, &sound[0]);
    ERRCHECK(result);
    result = system->createSound("../media/jaguar.wav", FMOD_SOFTWARE | FMOD_LOOP_NORMAL, 0, &sound[1]);
    ERRCHECK(result);
    result = system->createSound("../media/c.ogg", FMOD_SOFTWARE | FMOD_LOOP_NORMAL, 0, &sound[2]);
    ERRCHECK(result);
    result = system->createSound("../media/d.ogg", FMOD_SOFTWARE | FMOD_LOOP_NORMAL, 0, &sound[3]);
    ERRCHECK(result);
    result = system->createSound("../media/e.ogg", FMOD_SOFTWARE | FMOD_LOOP_NORMAL, 0, &sound[4]);
    ERRCHECK(result);

    result = system->createChannelGroup("Group A", &groupA);
    ERRCHECK(result);

    result = system->createChannelGroup("Group B", &groupB);
    ERRCHECK(result);

    result = system->getMasterChannelGroup(&masterGroup);
    ERRCHECK(result);

    result = masterGroup->addGroup(groupA);
    ERRCHECK(result);

    result = masterGroup->addGroup(groupB);
    ERRCHECK(result);

    printf("======================================================================\n");
    printf("Sub-mixing example.  Copyright (c) Firelight Technologies 2004-2014.\n");
    printf("======================================================================\n");
    printf("                                                       (drumloop.wav) \n");
    printf("                                                      /               \n");
    printf("                                              (groupA)                \n");
    printf("                                     (reverb)/        \\               \n");
    printf("                                    /                  (jaguar.wav)   \n");
    printf("(soundcard)--(lowpass)--(mastergroup)                                  \n");
    printf("                                    \\                  (c.ogg)        \n");
    printf("                                     (flange)         /                \n");
    printf("                                             \\(groupB)--(d.ogg)       \n");
    printf("                                                      \\               \n");
    printf("                                                       (e.ogg)        \n");
    printf("Press 'A' to mute/unmute group A\n");
    printf("Press 'B' to mute/unmute group B\n");
    printf("\n");
    printf("Press 'R' to place reverb on group A\n");
    printf("Press 'F' to place flange on group B\n");
    printf("Press 'L' to place lowpass on master group (everything)\n");
    printf("Press 'Esc' to quit\n");
    printf("\n");

    /*
        Start all the sounds!
    */
    for (count = 0; count < 5; count++)
    {
        result = system->playSound(FMOD_CHANNEL_FREE, sound[count], true, &channel[count]);
        ERRCHECK(result);
        if (count < 2)
        {
            result = channel[count]->setChannelGroup(groupA);
        }
        else
        {
            result = channel[count]->setChannelGroup(groupB);
        }
        ERRCHECK(result);
        result = channel[count]->setPaused(false);
        ERRCHECK(result);
    }

    /*
        Create the DSP effects we want to apply to our submixes.
    */
    result = system->createDSPByType(FMOD_DSP_TYPE_SFXREVERB, &dspreverb);
    ERRCHECK(result);

    result = system->createDSPByType(FMOD_DSP_TYPE_FLANGE, &dspflange);
    ERRCHECK(result);
    result = dspflange->setParameter(FMOD_DSP_FLANGE_RATE, 1.0f);
    ERRCHECK(result);

    result = system->createDSPByType(FMOD_DSP_TYPE_LOWPASS, &dsplowpass);
    ERRCHECK(result);
    result = dsplowpass->setParameter(FMOD_DSP_LOWPASS_CUTOFF, 500.0f);
    ERRCHECK(result);

    /*
        Main loop.
    */
    do
    {
        if (kbhit())
        {
            key = getch();

            switch (key)
            {
            case 'a' :
            case 'A' :
            {
                static bool mute = true;

                groupA->setMute(mute);

                mute = !mute;
                break;
            }
            case 'b' :
            case 'B' :
            {
                static bool mute = true;

                groupB->setMute(mute);

                mute = !mute;
                break;
            }
            case 'r' :
            case 'R' :
            {
                static bool reverb = true;

                if (reverb)
                {
                    groupA->addDSP(dspreverb, 0);
                }
                else
                {
                    dspreverb->remove();
                }

                reverb = !reverb;
                break;
            }
            case 'f' :
            case 'F' :
            {
                static bool flange = true;

                if (flange)
                {
                    groupB->addDSP(dspflange, 0);
                }
                else
                {
                    dspflange->remove();
                }

                flange = !flange;
                break;
            }
            case 'l' :
            case 'L' :
            {
                static bool lowpass = true;

                if (lowpass)
                {
                    masterGroup->addDSP(dsplowpass, 0);
                }
                else
                {
                    dsplowpass->remove();
                }

                lowpass = !lowpass;
                break;
            }
            }
        }

        system->update();

        {
            int  channelsplaying = 0;

            system->getChannelsPlaying(&channelsplaying);

            printf("Channels Playing %2d\r", channelsplaying);
        }

        fflush(stdout);
        Sleep(10);

    } while (key != 27);

    printf("\n");

    /*
        Shut down
    */
    for (count = 0; count < 5; count++)
    {
        result = sound[count]->release();
        ERRCHECK(result);
    }

    result = dspreverb->release();
    ERRCHECK(result);
    result = dspflange->release();
    ERRCHECK(result);
    result = dsplowpass->release();
    ERRCHECK(result);

    result = groupA->release();
    ERRCHECK(result);
    result = groupB->release();
    ERRCHECK(result);

    result = system->close();
    ERRCHECK(result);
    result = system->release();
    ERRCHECK(result);

    return 0;
}