0
0

I’m trying to get a system going where I have 4 channels of audio which feed into a custom dsp where they are combined together and 2 output channels are created. The way they are combined together depends on another input to the dsp which I feed in through the userdata pointer.

Firstly theres a fair chance that this is impossible and thats why I am running into problems. If it is then some confirmation of this from you gurus would be appreciated so I can move on to try and find some other way to do this.

As it stands I have the backbone of the thing is set up as follows.

[code:1hdawygf]

result = system->createSound("W_singing.wav",  FMOD_SOFTWARE | FMOD_LOOP_NORMAL, 0, &sound[0]); ERRCHECK(result);
result = system->createSound("X_singing.wav",  FMOD_SOFTWARE | FMOD_LOOP_NORMAL, 0, &sound[1]); ERRCHECK(result);
result = system->createSound("Y_singing.wav",  FMOD_SOFTWARE | FMOD_LOOP_NORMAL, 0, &sound[2]); ERRCHECK(result);
result = system->createSound("Z_singing.wav",  FMOD_SOFTWARE | FMOD_LOOP_NORMAL, 0, &sound[3]); ERRCHECK(result);

/////////////////////////////////////////////////////////////////////////////


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


result = system->playSound(FMOD_CHANNEL_FREE, sound[0], false, &channel[0]);  ERRCHECK(result);
ERRCHECK(result = channel[0]->setSpeakerMix(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
result = system->playSound(FMOD_CHANNEL_FREE, sound[1], false, &channel[1]);  ERRCHECK(result);
ERRCHECK(result = channel[1]->setSpeakerMix(0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); 
result = system->playSound(FMOD_CHANNEL_FREE, sound[2], false, &channel[2]);  ERRCHECK(result);
ERRCHECK(result = channel[2]->setSpeakerMix(0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); 
result = system->playSound(FMOD_CHANNEL_FREE, sound[3], false, &channel[3]);  ERRCHECK(result);
ERRCHECK(result = channel[3]->setSpeakerMix(0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f)); 

result = channel[0]->setChannelGroup(groupA); ERRCHECK(result);
result = channel[1]->setChannelGroup(groupA); ERRCHECK(result);
result = channel[2]->setChannelGroup(groupA); ERRCHECK(result);
result = channel[3]->setChannelGroup(groupA); ERRCHECK(result);


// Create the custom DSP 
{ 
    FMOD_DSP_DESCRIPTION  dspdesc; 
    memset(&dspdesc, 0, sizeof(FMOD_DSP_DESCRIPTION)); 
    strcpy(dspdesc.name, "L"); 
    dspdesc.channels     = 2;                
    dspdesc.read         = myDSPCallback; 
dspdesc.userdata = (void *)Luserdata;
    result = system->createDSP(&dspdesc, &mydsp); 
    ERRCHECK(result); 
} 
result = system->setDSPBufferSize(buffsize,4);

mydsp->setActive(true);  

//Tell the dsp which channel to act on
result = groupA->addDSP(mydsp, 0); ERRCHECK(result);

[/code:1hdawygf]

Now when I stop the debugger in the custom dsp callback and examine everything I find the following are as they should be.

inchannels=4
outchannels=2
The data I am passing through the userdata pointer is as expected also.

However when I examine inbuffer I find that there is only data in every fourth element of the array, so for some reason only one channel of the data in the channelgroup is being passed through.

Any thoughts as to how I can rectify this…or am I just mad to try and do this in the first place…?

  • You must to post comments
0
0

I’m open to absolutely any suggestions on this! I’m a bit stuck tbh.

I’ve included more code including the main loop of the program. Perhaps I’m adding the dsp in the wrong place or something?

[code:ao2hk27p] //Declare everything
FMOD::System *system;
FMOD::Sound *sound[4] ;
FMOD::Channel *channel[4]; channel[0] = 0; channel[1] = 0; channel[2] = 0; channel[3] = 0;
FMOD::DSP *mydsp;
FMOD::ChannelGroup *groupA;
FMOD_RESULT result;
unsigned int version;
//void *buff = 0;
int length = 0;
int channelsplaying = 0;
FMOD_CREATESOUNDEXINFO exinfo;

/////////////////////////////////////////////////////////////////////////////////
InputServer input;
boost::thread inputThread(input);
/////////////////////////////////////////////////////////////////////////////////
float AngleValue_az=0,AngleValue_el=0;//,AngleValue_az_old=0;

float               overlapbufferL[hrir_leng-1];
float               overlapbufferR[hrir_leng-1];

for (int i=0;i<hrir_leng-1;i++){
    overlapbufferL[i]=0; overlapbufferR[i]=0;

}
//Initialise the array of pointers to arrays of userdata to be passed to the DSP callbacks
float               *Luserdata[4]; Luserdata[0] = new float[1]; Luserdata[1] = new float[1]; Luserdata[2] = new float[1]; Luserdata[3] = new float[1];

Luserdata[0]=&AngleValue_az;
Luserdata[1]=&AngleValue_el;
Luserdata[2]=overlapbufferL;
Luserdata[3]=overlapbufferR; 


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


/* 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);
    exit(0);
}
result = system->setDSPBufferSize(buffsize,4);  //change dsp buffer length. default is 1024
ERRCHECK(result);

result =system->setSoftwareFormat(44100, FMOD_SOUND_FORMAT_PCM16, 4, 6,  FMOD_DSP_RESAMPLER_LINEAR); ERRCHECK(result);
//result = system->setSoftwareFormat(44100,  FMOD_SOUND_FORMAT_PCM16, 4, 10, FMOD_DSP_RESAMPLER_LINEAR);ERRCHECK(result);
result = system->init(32, FMOD_INIT_NORMAL, 0); ERRCHECK(result);

///////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////

result = system->createSound("W_singing.wav",  FMOD_SOFTWARE | FMOD_LOOP_NORMAL, 0, &sound[0]); ERRCHECK(result);
result = system->createSound("X_singing.wav",  FMOD_SOFTWARE | FMOD_LOOP_NORMAL, 0, &sound[1]); ERRCHECK(result);
result = system->createSound("Y_singing.wav",  FMOD_SOFTWARE | FMOD_LOOP_NORMAL, 0, &sound[2]); ERRCHECK(result);
result = system->createSound("Z_singing.wav",  FMOD_SOFTWARE | FMOD_LOOP_NORMAL, 0, &sound[3]); ERRCHECK(result);

////////////////////////////////////////////////////////////////////////////////////////////

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

result = system->playSound(FMOD_CHANNEL_FREE, sound[0], false, &channel[0]);  ERRCHECK(result);
ERRCHECK(result = channel[0]->setSpeakerMix(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); 
result = system->playSound(FMOD_CHANNEL_FREE, sound[1], false, &channel[1]);  ERRCHECK(result);
ERRCHECK(result = channel[1]->setSpeakerMix(0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); 
result = system->playSound(FMOD_CHANNEL_FREE, sound[2], false, &channel[2]);  ERRCHECK(result);
ERRCHECK(result = channel[2]->setSpeakerMix(0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); 
result = system->playSound(FMOD_CHANNEL_FREE, sound[3], false, &channel[3]);  ERRCHECK(result);
ERRCHECK(result = channel[3]->setSpeakerMix(0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f)); 

result = channel[0]->setChannelGroup(groupA); ERRCHECK(result);
result = channel[1]->setChannelGroup(groupA); ERRCHECK(result);
result = channel[2]->setChannelGroup(groupA); ERRCHECK(result);
result = channel[3]->setChannelGroup(groupA); ERRCHECK(result);

int   numchannels;
result = groupA->getNumChannels(&numchannels);ERRCHECK(result);
cout<<"num of channel in group = "<<numchannels<<endl;

{ 
    FMOD_DSP_DESCRIPTION  dspdesc; 
    memset(&dspdesc, 0, sizeof(FMOD_DSP_DESCRIPTION)); 
    strcpy(dspdesc.name, "L"); 
    dspdesc.channels     = 2;                
    dspdesc.read         = myDSPCallback; 
    dspdesc.userdata = (void *)Luserdata;
    result = system->createDSP(&dspdesc, &mydsp); 
    ERRCHECK(result); 
} 
result = system->setDSPBufferSize(buffsize,4);

//Loop////////////////////////////////////////////////////////////////////////////


handle = ISD_OpenTracker( (Hwnd)NULL, 0, TRUE, TRUE ); 
if( handle < 1 ){
    printf( "Failed to detect InterSense tracking device\n" );
}

result = groupA->addDSP(mydsp, 0); ERRCHECK(result);
//mydsp->setActive(true); 
while (1)
{
    if (!waiting_line.empty() ) {
        if (waiting_line.front() == "q") {  //quit!
            std::cout << "bye!" << std::endl;
            break;
        }else {
            waiting_line.pop();
            std::cout << "unrecognised command.\n>> " << std::flush;
        }

    }

    ///////////////////////////////////////////////////////////////////

    ISD_GetTrackingData( handle, &data );
    ISD_GetCommInfo( handle, &tracker );

    AngleValue_az=data.Station[0].Euler[0];
    AngleValue_el=data.Station[0].Euler[1];
    Luserdata[0]=&AngleValue_az;
    Luserdata[1]=&AngleValue_el;

    mydsp->setActive(true);
    system->update();
    // Prevent CPU overload in our simple loop.
    const int frame_period_ms = 30;
    Sleep(frame_period_ms); 
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////


// release resources
ISD_CloseTracker( handle );
////////////////////////////////
result = sound[0]->release();
ERRCHECK(result);
result = sound[1]->release();
ERRCHECK(result);
result = sound[2]->release();
ERRCHECK(result);
result = sound[3]->release();
ERRCHECK(result);
result = mydsp->release();
ERRCHECK(result);
result = system->close();
ERRCHECK(result);
result = system->release();
ERRCHECK(result);

}
[/code:ao2hk27p]

  • You must to post comments
0
0

Hi Claire,

Did you ever find a solution to this? I’ve been implementing similar ambisonics functionality with FMOD in the last week and I seem to have it working. The only difference it’s outputting to physical speakers and not doing a HRTF convolution (yet). It can handle a max of 8 speakers. It seems to be limited to that number because it’s a standard speaker set up in the FMOD speaker modes (7POINT1).

I encountered exactly the same problem you mentioned, data only coming in on one channel of the inbuffer for the custom DSP. After a lot of debugging I’ve found that this occurs when using FMOD_SPEAKERMODE_RAW. This speaker mode doesn’t seem to be easily compatible with multichannel custom DSP callbacks.

So in your code as posted the call to SetSoftwareFormat automatically sets the speaker mode to FMOD_SPEAKERMODE_RAW.

This means that SetSpeakerMix no longer works. So from what I can tell all the sounds are being summed together on to one input channel in the DSP.

I think a possible solution is to set the speaker mode to FMOD_SPEAKERMODE_QUAD and remove the call to SetSoftwareFormat. This should allow you to manage the inputs into the custom DSP properly i.e. one per channel.

If you pad the 4 channel output with zeros you should be able to route the HRTF response to the headphones and get the same effect as a stereo output.

Do any of the FMOD gods have any ideas on any of this?

Cheers,
Paul

  • You must to post comments
0
0

Hi there!

I think I ended up giving up on it and loading the 4 channels into global memory where I could get at them from the custom dsp callback. This is obviously incredibly bad coding practice though!! I was just looking to get something rough up and going with short pieces of audio.

This meant that I was using the custom dsp unit more as an oscillator type source than anything else with no input channel and one output channel. I had to create 2, one for each ear. I passed a few bits of info through the userdata pointer (location, L/R ear etc).

The FMOD_SPEAKERMODE_QUAD idea sounds like a good one though. I’m going to have to come back to this stuff soon so I’ll definately try it out.

There must be a reasonably neat way of doing it. I presumed I was missing something fairly fundamental tbh.
Maybe the FMOD gods will enlighten us with their wisdom…!!
It would really be a great feature of FMOD if this kind of spatial audio setup could be implemented relatively easily.

  • You must to post comments
Showing 3 results
Your Answer

Please first to submit.