0
0

we are thinking about doing a custom voice chat system, where multiple clients are connected to channels (like GLOBAL, TEAM1, TEAM2, etc…), where each client can hear one or more channels. each channel would be one sound object on server.
so we have a few questions:

1) can we use a user created sound (streaming) on server side, with multiple channels (one per client), which will be fed from client network streams (ie: client 1 feeds channel 1, client 2 channel 2, etc…)? if so, how can one properly feed the channel buffers to sound stream buffer, i mean do we just offset the location (based on format) and write there?

2) can we "mix" the above sound on demand, so that we get an output buffer with a single channel. can we do this without the main fmod update loop (mixer thread, etc…)? this buffer would then be compressed and sent back to clients as a playback buffer.

3) is there a "saner" way to do this? :)

  • You must to post comments
0
0

For lowest latency, you should be using System::createDSP and pulling in data via that callback. It will be for example 1024 samples at a time on pc. (though you can set that).

You could use System::playDSP to play these on their own channels, or you could even connect them all into a submix dsp unit so that they run through 1 fmod channel.
This technique would probably get you what you wanted regarding the mix into a buffer, because your submix dsp unit could also have a read callback that just captures the mixed result.

  • You must to post comments
0
0

as an example with the submix dsp thing, this is what my test app does

The submix target
[code:rrv3jop2]
{
FMOD_DSP_DESCRIPTION dspdesc;

    memset(&dspdesc, 0, sizeof(FMOD_DSP_DESCRIPTION));

    strcpy(dspdesc.name, "UNIT A");
    dspdesc.channels     = 0;                   // 0 = whatever comes in, else specify.
    dspdesc.read         = testcallbackA;
    dspdesc.setposition  = 0;
    dspdesc.userdata     = (void *)0x12345678;

    result = gSystem->createDSP(&dspdesc, &dspA);
    ERRCHECK(result);
}

[/code:rrv3jop2]

some sinewaves
[code:rrv3jop2]
{
result = gSystem->createDSPByType(FMOD_DSP_TYPE_OSCILLATOR, &dspsine1);
ERRCHECK(result);

    result = dspsine1->setParameter(FMOD_DSP_OSCILLATOR_RATE, 261.63f);
    result = dspsine1->setParameter(FMOD_DSP_OSCILLATOR_TYPE, OSCILLATOR_TYPE);
}
{
    result = gSystem->createDSPByType(FMOD_DSP_TYPE_OSCILLATOR, &dspsine2);
    ERRCHECK(result);

    result = dspsine2->setParameter(FMOD_DSP_OSCILLATOR_RATE, 329.63f);
    result = dspsine2->setParameter(FMOD_DSP_OSCILLATOR_TYPE, OSCILLATOR_TYPE);
}
{
    result = gSystem->createDSPByType(FMOD_DSP_TYPE_OSCILLATOR, &dspsine3);
    ERRCHECK(result);

    result = dspsine3->setParameter(FMOD_DSP_OSCILLATOR_RATE, 392.00);
    result = dspsine3->setParameter(FMOD_DSP_OSCILLATOR_TYPE, OSCILLATOR_TYPE);
}

result = dspsine1->setActive(true);
result = dspsine2->setActive(true);
result = dspsine3->setActive(true);

[/code:rrv3jop2]

add the sinewaves to the submix
[code:rrv3jop2]
result = dspA->addInput(dspsine1, 0);
ERRCHECK(result);

result = dspA->addInput(dspsine2, 0);
ERRCHECK(result);

result = dspA->addInput(dspsine3, 0);
ERRCHECK(result);

[/code:rrv3jop2]

play the submix
[code:rrv3jop2]
result = gSystem->playDSP(FMOD_CHANNEL_FREE, dspA, false, &gChannel[currentchannel]);
[/code:rrv3jop2]

here’s an example of what dspA’s callback does, at the moment it just scales the volume of the signal down.

[code:rrv3jop2]
FMOD_RESULT F_CALLBACK testcallbackA(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels)
{
unsigned int count;
char name[256];
FMOD::DSP *thisdsp = (FMOD::DSP *)dsp_state->instance;

thisdsp->getInfo(name, 0, 0, 0, 0);

if (inchannels == outchannels)
{
    for (count = 0; count < length * inchannels; count++)
    {
        outbuffer[count] = inbuffer[count] * 0.3f;
    }
}
else if (outchannels > inchannels)
{
    for (count = 0; count < length; count++)
    {
        int count2;

        for (count2 = 0; count2 < outchannels; count2++)
        {
            if (count2 == 0)
            {
                outbuffer[count * outchannels + count2] = inbuffer[(count * inchannels) + 0] * 0.4f;
            }
            else
            {
                outbuffer[count * outchannels + count2] = 0;
            }
        }
    }
}
else
{
    for (count = 0; count < length; count++)
    {
        int count2;

        for (count2 = 0; count2 < inchannels; count2++)
        {
            outbuffer[count * outchannels + 0] += (inbuffer[(count * inchannels) + count2] * (1.0f / (float)inchannels));
        }
        outbuffer[count * outchannels + 0] *= 0.4f;
    }
}

return FMOD_OK;

}
[/code:rrv3jop2]

  • You must to post comments
0
0

nice, thank you!

3D position is basically based per channel, correct?

  • You must to post comments
Showing 3 results
Your Answer

Please first to submit.