FMOD - Dsp Object Panner

Hi everyone,
I am a c ++ developer and use low level api fmod.
I want to make my sound distinguishable whether it is in front of me, behind me or at the top. Ordinary 3d is not enough for me, because it’s ordinary stereo.
I read that the sound can be panned using dsp object paner just as I want, but despite reading the documentation, I can’t make my test program work properly.
May I be very grateful for any help in solving my problem.
Below is the code.

C/C++

#include <iostream>
#include <windows.h>
#include <conio.h>
#include <fmod.hpp>

#define ercheck( r ) if( r != FMOD_OK) std::cout<<"error: " << r;

int main()
{
FMOD_RESULT result;
FMOD::System *system =0;
FMOD::Sound* sound=0;
FMOD::Channel *channel =0;
FMOD::DSP *dsp = 0;


result = FMOD::System_Create(&system);

result =system->setSoftwareFormat(0, FMOD_SPEAKERMODE_7POINT1POINT4, 0); //sets speakers to 7 1
ercheck(result);
result =system->setOutput(FMOD_OUTPUTTYPE_WINSONIC);
ercheck(result);

result = system->init(100, FMOD_INIT_NORMAL | FMOD_INIT_CHANNEL_LOWPASS  | FMOD_INIT_3D_RIGHTHANDED , 0);
result = system->set3DSettings(1.f, 1.f, 0.1f);
ercheck( result );

//create dsp to object paner

result = system->createDSPByType(FMOD_DSP_TYPE_OBJECTPAN, &dsp);
ercheck(result);

//create sound

result = system->createSound( "test.wav",  FMOD_3D, 0, &sound);
ercheck( result );
result = sound->set3DMinMaxDistance( 0.5f , 500);
ercheck( result );

//sound position

FMOD_VECTOR pos_sound = { 500, 110, 490};
FMOD_VECTOR vel_sound = { 0, 0, 0};

//listener

FMOD_VECTOR pos_listener = { 500, 100, 500};
FMOD_VECTOR vel_listener = { 0, 0, 0};
FMOD_VECTOR forward_listener = { 0, 0, -1};
FMOD_VECTOR up_listener = { 0, 1, 0};


bool close = false;
while( !close )
{
	auto key =_getch();
	if(key == 27) //key escape = close program
	close = true;

	Sleep(10);
	result = system->update(); // update to system fmod
	ercheck( result );

/*I don't know how to fill setparameterdata, I read something about this: FMOD_DSP_PARAMETER_3DATTRIBUTES_MULTI
I tried it but it doesn't work */
	dsp->setParameterData(FMOD_DSP_OBJECTPAN_3D_POSITION , 0 , 0); // I do't know how to set this method argument two is type void *


	//listener
	result = system->set3DListenerAttributes(0, &pos_listener, &vel_listener, &forward_listener, &up_listener);
	ercheck( result );

	result = system->playSound( sound, 0, true, &channel);
	ercheck( result );

	result = channel->addDSP(0, dsp); 
	ercheck(result);
	result = channel->set3DAttributes(&pos_sound, &vel_sound);

result = channel->setPaused(false);
}

//shut down

dsp->release();
sound->release();

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


return 0;
}

It looks like you are most of the way there, when using the FMOD Studio API this is handled for you but in the FMOD Core API you must set this DSP parameter explicitly.

FMOD - White Papers | Spatial Audio (object based approach)

In the docs for FMOD_DSP_OBJECTPAN_3D_POSITION it tells you that it requires a data type of FMOD_DSP_PARAMETER_3DATTRIBUTES_MULTI. All the data needs to be updated and passed in any time the sound positioning changes, you will need to manually calculate the relative position of the sound from the listener as one of the parameters of FMOD_DSP_PARAMETER_3DATTRIBUTES_MULTI.

Here is a rough example of how you can provide the information required:

FMOD_DSP_PARAMETER_3DATTRIBUTES_MULTI* multi = {};

{
	//Calculate positioning values
	FMOD_3D_ATTRIBUTES absolute = {};
	absolute.forward	= { 0,0,1 };
	absolute.position	= { 0,1,0 };
	absolute.up			= { 0,1,0 };
	absolute.velocity	= { 0,0,0 };

	FMOD_3D_ATTRIBUTES relative = {};
	relative.forward	= { 0,0,1 };
	relative.position	= { 0,1,0 };
	relative.up			= { 0,1,0 };
	relative.velocity	= { 0,0,0 };

	//Assign values
	multi.numlisteners = 1;
	multi.weight[0] = 1;
	multi.absolute = absolute;
	multi.relative[0] = relative;
}
{
...

    result = dsp->setParameterData(FMOD_DSP_OBJECTPAN_3D_POSITION, (void*)multi, sizeof(multi));
...
}
1 Like

Thank you very much, you helped me a lot.
It would be great if you could answer a few more questions for me.

  • In the code you showed me, I had to correct:
    FMOD_DSP_PARAMETER_3DATTRIBUTES_MULTI * multi = {};
    on
    FMOD_DSP_PARAMETER_3DATTRIBUTES_MULTI multi = {};
    and
    result = dsp-> setParameterData (FMOD_DSP_OBJECTPAN_3D_POSITION, (void *) multi, sizeof (multi));
    on
    result = dsp-> setParameterData (FMOD_DSP_OBJECTPAN_3D_POSITION, (void *) & multi, sizeof (multi));
    now works, i hope i should.
  • Where the sound is played from I control by subtracting the relative position of the listener from the relative position of the sound source, but I do not know how to control the rotation of the listener, e.g. so that the sound that is in front of the listener, after the listener is turned 90 degrees to the right, the sound should sound from the left earphone.
  • is the FMOD_3D flag in the System :: createSound method still needed when I use the object panner and whether in my code the lines:
    result = system-> set3DListenerAttributes (0, & pos_listener, & vel_listener, & forward_listener, & up_listener);
    result = channel-> set3DAttributes (& pos_sound, & vel_sound);
    are still needed, fmod seems to get all the information it needs from the structure FMOD_DSP_PARAMETER_3DATTRIBUTES_MULTI.
  • I noticed that when I place the sound source perfectly to the left of the listener there is no sound in the right earphone, I tried to change it using channel-> set3DSpread (90) but it has no effect.
  • Does 1 dsp always have to correspond to one channel.
    -I did not notice a change in sound when I placed the sound source once above the listener and then below it, I set the y position of the listener to 100 and the y position of the source to 110, should I control something else besides the position?

The sounds info will come from the dsp->setParameterData calls so you won’t need to use channel->set3DAttributes on sounds use the object panner. You will still need to set the listener attributes separately using set3DListenerAttributes.

The rotation of the listener comes from the forward and up vectors of set3DListenerAttributes, make sure that these are being updated and are correct.

Where/what you add a DSP to will determine what it affects. When you call createDSP you are creating an instance of that DSP and each instance cannot be used in multiple places at once. See ChannelControl::addDSP for more.

1 Like

Thank you for your response.
I noticed that in the system (windows 10) I had to run spatial sound in the control panel.
now almost everything works, but I can’t rotate the listener with System :: set3DListenerAttributes, but I can change its position.
Could you please indicate what I am doing wrong?
Below is the code.

C/C++

#include <iostream>
#include <windows.h>
#include <fmod.hpp>

#define ercheck( r ) if( r != FMOD_OK) std::cout<<"error: " << r;

int main()
{
FMOD_RESULT result;
FMOD::System *system =0;
FMOD::Sound* sound=0;
FMOD::Channel *channel =0;

FMOD::DSP *dsp = 0;

result = FMOD::System_Create(&system);
result =system->setSoftwareFormat(0, FMOD_SPEAKERMODE_7POINT1POINT4, 0); //sets speakers to 7 1
ercheck(result);
result =system->setOutput(FMOD_OUTPUTTYPE_WINSONIC);
ercheck(result);

result = system->init(100, FMOD_INIT_NORMAL , 0);
result = system->set3DSettings(1.f, 1.f, 0.1f);
ercheck( result );

//create dsp to object paner

result = system->createDSPByType(FMOD_DSP_TYPE_OBJECTPAN, &dsp);
ercheck(result);

//create sound

result = system->createSound( "test.wav",  FMOD_3D | FMOD_LOOP_NORMAL , 0, &sound);
ercheck( result );
result = sound->set3DMinMaxDistance( 0.5f , 500);
ercheck( result );

//sound position

FMOD_VECTOR pos_sound = { 510, 100, 500};
FMOD_VECTOR vel_sound = { 0, 0, 0};

//listener

FMOD_VECTOR pos_listener = { 500, 100, 500};
FMOD_VECTOR vel_listener = { 0, 0, 0};
FMOD_VECTOR forward_listener = { 1, 0, 0};
FMOD_VECTOR up_listener = { 0, 1, 0};

//play sound

	result = system->playSound( sound, 0, true, &channel);
	ercheck( result );
	result = channel->addDSP(0, dsp);
	ercheck(result);

result = channel->setPaused(false);

FMOD_DSP_PARAMETER_3DATTRIBUTES_MULTI multi = {};
	FMOD_3D_ATTRIBUTES absolute = {};
	FMOD_3D_ATTRIBUTES relative = {};
bool close = false;
while( !close )
{



absolute.forward	= { 0,0,1 };
	absolute.position	= pos_sound;
	absolute.up			= { 0,1,0 };
	absolute.velocity	= { 0,0,0 };


	relative.forward = { 0,0,1 };

	relative.position.x = pos_sound.x -pos_listener.x;
	relative.position.y = pos_sound.y -pos_listener.y;
	relative.position.z = pos_sound.z -pos_listener.z;
	relative.up			= { 0,1,0 };
	relative.velocity	= { 0,0,0 };

	multi.numlisteners = 1;
	multi.weight[0] = 1;
	multi.absolute = absolute;
	multi.relative[0] = relative;

result = dsp->setParameterData(FMOD_DSP_OBJECTPAN_3D_POSITION, (void*)&multi, sizeof(multi));

	//listener

forward_listener.x = 1; //does not rotate
result = system->set3DListenerAttributes(0, &relative.position, &vel_listener, &forward_listener, &up_listener); //works fine but does not rotate the listener
//result = system->set3DListenerAttributes( 0, &pos_listener, &vel_listener, &forward_listener, &up_listener); //no sound is heard
	ercheck( result );


//	result = channel->set3DAttributes(&pos_sound, &vel_sound);
	//Sleep(10);
	
	result = system->update(); // update to system fmod
	ercheck(result);


}//while

//shut down

dsp->release();
sound->release();

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

return 0;
}

Just for clarity, I’m guessing you have tried using different vectors for the forward_listener and pos_sound? The position of the sound and the listener is currently the same and the listener forward only gets set once.

In my example, the sound is placed at the position:
FMOD_VECTOR pos_sound = {510, 100, 500};
and the listener at position:
FMOD_VECTOR pos_listener = {500, 100, 500};
this means the sound is to the right of the listener.
If the listener would have the front vector set to:
FMOD_VECTOR forward_listener = {0, 0, 1};
this sound would be heard from the right speaker.
However, I rotate the listener 90 degrees clockwise
FMOD_VECTOR forward_listener = {1, 0, 0};
so the sound should be heard equally from both speakers.
Everything works like this when I turn off dsp object panner and run standard 3d, but if I run dsp object panner, the sound is still audible in the right speaker, and should be heard in front of the listener.
When I set
system-> set3DListenerAttributes (0, & pos_listener, & vel_listener, & forward_listener, & up_listener);
and dsp object panner is on, I don’t hear anything, but when I set
system-> set3DListenerAttributes (0, & relative.position, & vel_listener, & forward_listener, & up_listener);
it can be heard from the right, but probably too quiet.

  • I don’t know what you mean when you say the position of the listener and the sound are the same.
  • I tried to change each of the vectors in different ways absolute.forward, relative.forward and forward_listener unfortunately to no avail.

My apologies, I have actually lead you on the wrong path.

set3DListenerAttributes is not required when using FMOD_DSP_PARAMETER_3DATTRIBUTES_MULTI to drive a DSP, all the information comes from that struct.

We actually have a section in our docs about this very topic, Driving the Spatializer, that also provides all the math that Studio handles internally.

1 Like