2
\$\begingroup\$

After reading documentation and tutorials about fmod I still have a question about frequency ranges.

I've found how to get a frequency range using low and high pass DSP at the same time on the main channel, but I can't find how to get several ranges at the same time. For example I want, for a specific phase of my game, to hear range 400 to 600Hz and 1000 to 2000hz of the same sound. I tried to create a channel by range, but it doesn't seem to work (or maybe I do something wrong). How can I do that ?

Thank you

\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

High pass and low pass filters are usually shelves, that is if you apply a low pass filter at a given frequency then you're losing frequencies about that cutoff frequency and can't get them back.

In order to get more than one limited range of frequencies, the most straightforward way is to use EQ.

One of the FMOD dsp types of DSP is FMOD_DSP_TYPE_PARAMEQ. For each frequency band you want to affect, create one FMOD_DSP_TYPE_PARAMEQ unit object and set the parameters appropriately. With EQ, you can't directly affect the range. Instead, you set a center frequency and the bandwidth or Q (more about EQ here: http://tweakheadz.com/EQ_and_the_Limits_of_Audio.html).

FMOD_DSP_TYPE_PARAMEQ

Enumeration

typedef enum { FMOD_DSP_PARAMEQ_CENTER,
FMOD_DSP_PARAMEQ_BANDWIDTH, FMOD_DSP_PARAMEQ_GAIN } FMOD_DSP_PARAMEQ; Values

FMOD_DSP_PARAMEQ_CENTER Frequency center. 20.0 to 22000.0. Default = 8000.0.

FMOD_DSP_PARAMEQ_BANDWIDTH Octave range around the center frequency to filter. 0.2 to 5.0. Default = 1.0.

FMOD_DSP_PARAMEQ_GAIN Frequency Gain. 0.05 to 3.0. Default = 1.0.

Remarks

Parametric EQ is a bandpass filter that attenuates or amplifies a selected frequency and its neighbouring frequencies.

To create a multi-band EQ create multiple FMOD_DSP_TYPE_PARAMEQ units and set each unit to different frequencies, for example 1000hz, 2000hz, 4000hz, 8000hz, 16000hz with a range of 1 octave each.

Here's a quick example (assuming you initialized FMOD and omitting error checking for brevity):

FMOD::DSP* dspObj;

systemPtr->createDSPByType(FMOD_DSPTYPE_PARAMEQ, &dspObj);
dspObj->setParameter(FMOD_DSP_PARAMEQ_CENTER, 500);
dspObj->setParameter(FMOD_DSP_PARAMEQ_BANDWIDTH, 0.2);
dspObj->setParameter(FMOD_DSP_PARAMEQ_GAIN, 3.0);
FMOD::DSPConnection* eq1Connection;
systemPtr->addDSP(dspObj, &eq1Connection);

systemPtr->createDSPByType(FMOD_DSPTYPE_PARAMEQ, &dspObj);
dspObj->setParameter(FMOD_DSP_PARAMEQ_CENTER, 1500);
dspObj->setParameter(FMOD_DSP_PARAMEQ_BANDWIDTH, 5.0);
dspObj->setParameter(FMOD_DSP_PARAMEQ_GAIN, 3.0);
FMOD::DSPConnection* eq2Connection;
systemPtr->addDSP(dspObj, &eq2Connection);

In DAW-land, you could route the audio from your source channel to two new aux channels and apply separate sets of high and low pass filters to achieve something sort of like this. However, I don't believe FMOD supports that kind of routing and it might raise performance concerns. Also, taking into account resonance the final mix using this approach could sound very strange.

Also, FMOD has the capacity to load some VSTs. If you're just exploring the API and not trying to implement FMOD for a full-on game, look at http://kvraudio.com and see if you can find some VSTs to do what you're trying to achieve.

I also don't know if it's possible to cut everything except for multiple frequency band sin FMOD. This is similar to the use case for a comb filter, but if you're doing this much synthesis you may be better off working on the sample level and implementing your own DSP effects by adding callbacks into a FMOD_DSP_DESCRIPTION structure.

\$\endgroup\$
2
  • \$\begingroup\$ Thank you for that quick answer (and for your very interesting links). I will try PARAMEQ DSP (even if it implies I have to learn the definition of an octave :) I'm pretty noob even in musical culture). Thanks again. \$\endgroup\$
    – lvictorino
    Nov 8, 2011 at 6:52
  • \$\begingroup\$ Hi, I tried your answer it seems to work, but I found a more gentle way to do it for my need, using High / Low Pass. Thanks again for your answer. \$\endgroup\$
    – lvictorino
    Nov 14, 2011 at 13:47
0
\$\begingroup\$

Somewhere (on the fmod forums) someone suggested me to use low / high pass DSPs. The trick is to split signal into branches in order to only keep frequency range needed on a specific branch (a branch will handle 400 to 500Hz, an other only 1000 to 2000Hz... and so on).

If I want to isolate only 400Hz to 600Hz and 5000Hz to 10000Hz from a sound, the goal is to have something like that :

                         o -- HighPass -- LowPass -- o (400Hz to 600Hz)
                        /                             \
main channel output--- o                               o --- main channel input
                        \                             /
                         o -- HighPass -- LowPass -- o (5KHz to 10KHz)

Now let's code it (the code below presumes that you already have all your fmod stuff initialized) :

// Creates the sound we want to play
FMOD::Sound *sound;
result = system->createSound("science.mp3", FMOD_DEFAULT, 0, &sound);

// Declares the channels and DSP we will use
FMOD::Channel *pChan; // main channel
FMOD::ChannelGroup *pChanGrp; // channel group where we will split our signal
FMOD::DSP *pDSPhigh1; //HighPass1
FMOD::DSP *pDSPlow1; //LowPass1
FMOD::DSP *pDSPhigh2;  //HighPass2
FMOD::DSP *pDSPlow2; //LowPass2

FMOD::DSP *pDSPChanHead;
FMOD::DSP *pDSPChanGrpHead;

// let's play our sound and set our main channel pointer
system->playSound(FMOD_CHANNEL_FREE, sound, false, &pChan);

// creates the channel group and gets the head DSP pointer
result = system->createChannelGroup( "my_chan_grp", &pChanGrp );
result = pChanGrp->getDSPHead(&pDSPChanGrpHead);

// now let's create our first low pass DSP
result = system->createDSPByType( FMOD_DSP_TYPE_LOWPASS, &pDSPlow1 );
result = pDSPlow1->setParameter( FMOD_DSP_LOWPASS_CUTOFF, 600.f ); // we want the cutoff at 600Hz
result = pDSPChanGrpHead->addInput(pDSPlow1, 0); // connecting to channel group head

// now let's do the same with our second low pass DSP
result = system->createDSPByType( FMOD_DSP_TYPE_LOWPASS, &pDSPlow2 );
result = pDSPlow2->setParameter( FMOD_DSP_LOWPASS_CUTOFF, 10000.f ); // we want the cutoff at 10000Hz
result = pDSPChanGrpHead->addInput(pDSPlow2, 0); // connects to group head 

// Now we need to create high pass DSP
result = system->createDSPByType( FMOD_DSP_TYPE_HIGHPASS, &pDSPhigh1 );
result = pDSPhigh1->setParameter( FMOD_DSP_HIGHPASS_CUTOFF, 400.f ); // we want the cutoff at 400Hz
result = pDSPlow1->addInput(pDSPhigh1, 0); // connects HighPass1 to LowPass1

result = system->createDSPByType( FMOD_DSP_TYPE_HIGHPASS, &pDSPhigh2 );
result = pDSPhigh2->setParameter( FMOD_DSP_HIGHPASS_CUTOFF, 5000.f );
result = pDSPlow2->addInput(pDSPhigh2, 0); // connects HighPass2 to LowPass2

// now we have to get the DSP Head pointer of the main channel and disconnect all existing DSP in order to avoid having our sound still playing without any modification
result = pChan->getDSPHead(&pDSPChanHead);
pDSPChanHead->disconnectAll(false, true);
// and finally connect channel DSP head to HighPass1 and HighPass2
result = pDSPhigh1->addInput(pDSPChanHead, 0);  
result = pDSPhigh2->addInput(pDSPChanHead, 0); 

// don't forget to activate your new DSP
pDSPhigh1->setActive(true);
pDSPhigh2->setActive(true);
pDSPlow1->setActive(true);
pDSPlow2->setActive(true);

I hope this will help someone.

\$\endgroup\$
2
  • \$\begingroup\$ This is a valid solution, and I had thought about including it, but you're now using twice as many DSP units. Not a big deal at all for a reasonable number of sounds, but it's still something to consider. If you want to get more into audio programming, I recommend checking this book out: amazon.com/Audio-Programming-Book-Richard-Boulanger/dp/… The first couple chapters are a bit slow since they're C tutorials, but it has a lot of great digestable info. \$\endgroup\$ Nov 15, 2011 at 0:17
  • \$\begingroup\$ Thanks for the advice. I was looking for a good audio programming book and it seems to be exactly what I need. As you can imagine the code above is just a sample code I made in order to see how fmod works, I am just a 'regular' game dev curious about audio programming, that's why it may seem a little bit "dirtier" than your proposal using FMOD_DSPTYPE_PARAMEQ. \$\endgroup\$
    – lvictorino
    Nov 15, 2011 at 9:32

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .