Changing panning formula

Hello, what is the recommended way to go to change how panning works?

We’d like to make it so that a sound that is positioned 45º degrees from the speaker to the right is panned 100% to the right speaker. Meaning no sound from the left speaker in that scenario. Note that we are not asking about 3DSpread, this is something else.

Setting 3dLevel to 0 to disable spatialization, then using setPan() is not a good solution as the pan wouldn’t adapt as the listener orientation changes.

Thanks in advance.

You could try reducing the ‘Sound Size’ on the panner dsp using : DSP::setParameterFloat &
FMOD_DSP_PAN_3D_SOUND_SIZE.

Thanks for the reply Cameron.

I couldn’t get it to work, but I’m probably not using this correctly, apologies if this is covered in the documentation but I didn’t find anything like this mentioned. What I’m trying is creating a DSP of type Pan and then adding to the channel of each new sound that I play.

// function to attach dps
void _attach_pan_dps(FMOD::Channel *channel){ //LEAK!!!! just for testing
    if (!channel || !_system) return;
    FMOD_RESULT result;

    FMOD::DSP *new_dsp = NULL;
    LOG_ERROR(_system->createDSPByType(FMOD_DSP_TYPE_PAN, &new_dsp));
    if (new_dsp){
        LOG_ERROR(channel->addDSP(FMOD_CHANNELCONTROL_DSP_HEAD, new_dsp));
        new_dsp->setParameterFloat(FMOD_DSP_PAN_3D_SOUND_SIZE, 10000000);
    }
}


// code to play sound and attach dps
FMOD::Channel *channel = NULL;
LOG_ERROR(_system->playSound(sound, _effects_channel, true, &channel));
if (channel) _attach_pan_dps(channel);

Am I supposed to do this? Or am I supposed to retrieve a panner dsp that is already put in place by fmod? Thanks in advance!

Edit: I also tried negative values since you suggested to reduce it, still no effect.

Apologies, sound size may not give you the end result you need.

The easiest way to customize the panning is in FMOD Studio.

Here are the steps I used:

  • Automate the panners Surround Direction and Surround Extent.
  • Add the built in parameter ‘Direction’ to the event.
  • Create the curve that suits your needs on the Surround Direction, this allows you to specify the panning at various positions around the listener.
  • Controlling the extent will allow you to add as little or as much spread as you like.

To do something like this in code is possible, although it would not be an easy task, but using Studio makes it much easier to visualize as well.

Cameron, thanks a lot for the reply but we are using the API and we need to keep using API. Would you mind explaining the steps? I take it it involves setting FMOD_DSP_PAN_2D_EXTENT? Also keep in mind we would like this to work with any sound automatically, it sounded from your reply that you were suggesting specifying the panning direction for every sound but obviously we cannot do this in our shooter game.

Thanks in advance.

Hi noknees.
The point of the hand drawn graph above is that you are after a non standard pan bias. This is easily set up in a graphical editor like FMOD Studio.
If you are using the core API, then you are going to have to write your own code to warp the pan in a non standard fashion.

The curve in the screenshot is not a perfect sine wave segment, it has flat spots which means it will hover more in the left or the right instead of panning to the middle. This is what we assumed you were after. " make it so that a sound that is positioned 45º degrees from the speaker to the right is panned 100% to the right speaker". If this is a 3d sound then what happens when it needs to switch from right to left?

The extent/direction parameters of the panner just give you the ‘spread’ and angle of the pan.
You can get a similar effect (ie extent) just by using Channel::set3DPanSpread. It is symmetrical and doesn’t bias to the left or right in any way.
It just stops the pan from pinpointing a particular speaker, and spreads it around the arc by the number of degrees you specify.

If you just want to pan a sound left or right with no bleed, make it 2d and use setPan(-1) or setPan(1)

If you are using the core API, then you are going to have to write your own code to warp the pan in a non standard fashion.

That sounds good. How would I go about doing this? How do I setup a non-standard pan-bias? Does it involve writing a custom DSP? That is perfectly fine. And do we have other options?

make it so that a sound that is positioned 45º degrees from the speaker to the right is panned 100% to the right speaker". If this is a 3d sound then what happens when it needs to switch from right to left?

I don’t understand that question though, we just want what you sensibly described as a “non-standard pan-bias” above, for example:

(0º is on front, 90º right, -90º left, approximate illustrative values given)
-90º => 100/0
-70º => 100/0
-45º => 100/0
-40º => 90/0
-22º => 66/33
0º => 50/50
22º => 33/66
40º => 10/90
45º => 0/100
70º => 0/100
90º => 0/100

If the sound switches then it would just need a different panning according to our bias. Also remember I said in the first answer that I understand what “3D spread” in fmod is and that we are not asking about 3d spread:

Note that we are not asking about 3DSpread, this is something else.

We really appreciate the help and thanks again for your patience!

Bit off-topic, but I want to drop my 2 cents, I understand there might not be a lot of projects using the core API, and so you may want to direct people to your Studio product, but we are one of those projects that really need it, and I hope you don’t get rid of the API product in the future, having a stable audio layer that is thread-safe is still very useful, even if we don’t end up using any of your “mixing” features. I can get into details about our use-case privately when I contact you before release.

Hi,
we’re not trying to obscure the core API, in fact we made it more prominent recently and gave it its own page at https://www.fmod.com/core . The core is an important product for things like embedded systems and other developers who want to write their own multimedia playback systems.

We also support ‘programmer sounds’ in studio. These are low level callbacks for people who want to play sounds in studio events that arent normal (ie a shoutcast stream, or manually loading their own bank for dialog etc).

For your pan setup, it is basically what I assumed, so I was on the right track.
The graph I drew (via cameron’s screenshot) does exactly what you said, it whips from right to left quickly near the 0 degree mark, and hovers left or right for the rest of the time.

Because I drew it in an editor, I could hand create the curve.
If you are using your own code, you will have to generate your own curve and pan the sounds yourself.

You will have to use a dot product with the (normalized) difference vectors between the listener and the sound, and the listener orientation vector. That will translate into a -1 to +1 value that you can pass to setPan()

You might be able to get the skew you want by scaling the vectors away from being normalized, or passing the result of a dot product through a square root function .

ie pan = 1-sqrt(1-pan) https://www.wolframalpha.com/input/?i=1-sqrt(1-x) )
or an even heavier bias
1-sqrt(sqrt(1-pan)) https://www.wolframalpha.com/input/?i=1-sqrt(sqrt(1-x))

Hi Brett! We are very thankful of the level of support that we are getting over this, and it’s great to know that you are placing such focus into this segment.

I was asking more about the technical details of what you would recommend to do. For example, a way that I see is to implement a custom DSP, then implement the panning operations in its read callback, then create a new instance of said DSP for every new sound and attach it to its channel on the tail. Am I on the right track?

I do appreciate the insight on panning math, however, a few more things to try!

Thanks again.

hi,
The idea is that you can just do the math mentioned above, and call Channel::setPan yourself instead of set3DAttributes

Alternatively, just warp (rotate around the listener) the 3d vectors you pass to set3DAttributes to make them bias to the right or left more.

Hello Brett

Right at the start of the thread in the first post I also stated:

Setting 3dLevel to 0 to disable spatialization, then using setPan() is not a good solution as the pan wouldn’t adapt as the listener orientation changes.

Are you suggesting that I iterate every sound that is being played every frame, and then setPan() accordingly? I dismissed that route because it seemed not very efficient, but perhaps is the way to go if you are suggesting that setPan() has very little impact. Furthermore, the updates in panning would happen at a different frequency, they would happen at the graphics timestep. Or are you just suggesting that I just set the panning once and then if the listener changes orientation while the sound is playing the panning doesn’t adapt, I’m afraid that is not acceptable in our scenario.

The best way I can see to make this work is to create a custom DSP, what do you think?

Thanks!

Hi,
Yes I meant do the math yourself, it is not inefficient to do so, just more programming work. It would work with the listener orientation, because you provide it to fmod and already know what the orientation is.

A DSP would be even more work, as you’d have to do the same math, then mix/process the PCM data into the right multichannel panned signal.

System::update is where the 3d calculations happen in fmod , so doing them yourself on the main thread or letting fmod do it is exactly same in regards to dsp/game frame timing.

The other option I said in my last email, is let fmod do the work as normal, but warp the 3d positions of your sounds before they get passed into fmod. This is probably the least work imo.

The other option I said in my last email, is let fmod do the work as normal, but warp the 3d positions of your sounds before they get passed into fmod. This is probably the least work imo.

The reason this kind of solution was never an option is that the panning really needs to be updated in real-time, the player may, and often will, change orientations before a sound has finished playing.

System::update is where the 3d calculations happen in fmod , so doing them yourself on the main thread or letting fmod do it is exactly same in regards to dsp/game frame timing.

Ah, this is very useful information. I think I’ll go with your suggestion, then, using ChannelGroup::getChannel and ChannelGroup::getNumChannels to iterate all the channels and use setPan() on them. Thanks!