0
0

Hello,

I've been searching for a solution to my problem for a few days, but i'm a bit lost here (quite new on FMOD).

I'd like to get a system that perform simultaneously following features on an incoming audio stream:
  1. Record incoming stream for later analysis

> For this, basic use of FMOD::Sound record seems to fit perfectly.

  1. Read incoming samples to route them in another thread to do some RT analysis (mean level, stft-based viewer …)

> First difficulty for me … Didn’t find the way to access incoming audio stream data. Maybe dumb … Still looking, but any help would be more than appreciated 😕

  1. Re-route the incoming stream to a given output.

> Didn’t really start to check how to proceed with FMOD for that part. Maybe by the mean of the playback driver ? …

Actually, my application is supposed to be a simple analysis tool in the audio chain. For that, i use Virtual Audio Cables technology, and this application ("inserted" between 2 VAC) should not impact audio stream further than adding a delay (meaning that the 3rd point must be kind of perfect) …

That’s it ! If anyone could help me, mainly on the 2nd point, that would be wonderful 😀

And … If those 3 features can’t be simultaneously implemented on a single (mono) audio stream … Please let me know 😛

Best Regards,

J

  • You must to post comments
0
0

aïe thanks,
it looks like i’m screwed, the delay between what i speek and what i hear is way too long, i can’t work an AEC with an audible delay :(
It’s strange, working at 16k (or 48k) and using a 512 buffer size, the latency between In and out should be of 0.032sec maximum, and the one i hear is easily a 0.5sec…
I used :

[code:2j2kxinq]
while(1)
{
key = getch();
switch (key)
{
case ‘r’ :
case ‘R’ :
{
result = ERRCHECK(FMOD_System_RecordStart(system, recorddriver, sound, looping));
break;
}
.......
}

ERRCHECK(FMOD_System_GetRecordPosition(system, recorddriver, &recordpos));
if ((recordpos>1)&&(init == 0))
{
    init = 1;


    if (looping)
    {
        ERRCHECK(FMOD_Sound_SetMode(sound, FMOD_LOOP_NORMAL));
    }
    else
    {
        ERRCHECK(FMOD_Sound_SetMode(sound, FMOD_LOOP_OFF));
    }


    ERRCHECK(FMOD_System_PlaySound(system, FMOD_CHANNEL_REUSE, sound, 0, &channel));
}

FMOD_System_Update(system);

}

[/code:2j2kxinq]

Is there something i’m doing wrong ? I normally shouldn’t hear a delay, should i ?

  • You must to post comments
0
0

I’m doing something very similar, actually. I suggest you check out doing a custom FMOD DSP. You can record your sound, play it (silently) and then do your analysis in the DSP (which will be called from the FMOD mixer thread). Just be careful that the mixer thread stack isn’t very big (at least on consoles) so you gotta be careful you don’t ‘splode it.

Alternatively, you can just grab the raw PCM data from the FMOD::Sound created by the recording and then do whtever you like with it. There’s actually another thread active now about that part of the API (unlock/getWaveData/read, etc)

  • You must to post comments
0
0

What i think has happened is you’re reading ahead of the record position. So it looks something like this:

Ring buffer:
[code:1knkw1md]
————-> ———————-
|————–W-R———————-|
[/code:1knkw1md]
[i:1knkw1md]Note: The record buffer is bigger than the DSP buffer size, so that’s why it’s more than 32ms[/i:1knkw1md]

If you put a sleep between play and record then the read position will be behind the record position reducing the latency:

Ring buffer:
[code:1knkw1md]
——>
|——R——-W————————|[/code:1knkw1md]

The best-case senario for overall delay is DSP buffersize + sleep time. This will be quite a bit less than 500ms but could be ~100 ms. Let me know how you go.

  • You must to post comments
0
0

Hi,
I’m trying to develop an acoustic echo cancellation system in C.
I’ve the same problem you wrote about : extract/access on the fly the data i’m recording. Did you find a solution ?
Thanks for any help,
Cedric

  • You must to post comments
0
0

Hi Cedric,

I replied in the other thread:
http://52.88.2.202/forum/viewtopic.php?t=12042

Since you’re writing a echo cancellation DSP I would recommend the going for the custom DSP option. Check out the dsp_custom example to see how to write a dsp callback.

  • You must to post comments
0
0

Hi,
thanks for your answers, i just started using fmod so i’m having some troubles :)
Do you know where i can find a tuto in order to use the dsp ?
I tried using the custom dsp example, i replaced the drumloop.wav by a perso.wav (frequency 16k), then in the dsp function, i used a fwrite to save the data in an external file.
Now, if i try to play the new (perso_out.RAW) file with audacity, the frequency became :
– 48k if my fwrite function was after the second loop
– 96k if my fwrite function was in the second loop ;

for (count = 0; count < length; count++)
{
/*
Feel free to unroll this.
/
for (count2 = 0; count2 < outchannels; count2++)
{
temp = inbuffer[(count * inchannels) + count2];
/

This DSP filter just halves the volume!
Input is modified, and sent to output.
/
//printf("\n %f", temp
32000);
//Signal_Out[0] = (short)(temp * 32000);
//fwrite(Signal_Out, sizeof(short), 1, fichier_sortie);
outbuffer[(count * outchannels) + count2] = temp *2;
}
Signal_Out[0] = (short)(temp * 32000);
fwrite(Signal_Out, sizeof(short), 1, fichier_sortie);
}

and i would also like to know where can i modify the length of the input buffer ?
If i have 2 signals (echo cancellation system : 1 from the micro, 1 to the loud speakers) or more, where do we link each signal to specific dsp (in the main function i suppose) ?

Thanks again for your answers, and if you know about a tutorial on fmod i would be very grateful :)

Cédric

ps i saw in previous post http://52.88.2.202/docs/Tutorials, but it appear the link is dead.

  • You must to post comments
0
0

Hi Cédric,

[quote:1190xlhf]I tried using the custom dsp example, i replaced the drumloop.wav by a perso.wav (frequency 16k), then in the dsp function, i used a fwrite to save the data in an external file.
Now, if i try to play the new (perso_out.RAW) file with audacity, the frequency became :
– 48k if my fwrite function was after the second loop
– 96k if my fwrite function was in the second loop ; [/quote:1190xlhf]
When the data enters your DSP unit it has already been resampled to the current mixer sample rate, in this case it is probably 48k. It is also being upmixed to stereo, so where you see it as ’96k’, that is just 48k stereo.

[quote:1190xlhf]i would also like to know where can i modify the length of the input buffer ? [/quote:1190xlhf]
FMOD::System::setDSPBufferSize

[quote:1190xlhf]If i have 2 signals (echo cancellation system : 1 from the micro, 1 to the loud speakers) or more, where do we link each signal to specific dsp (in the main function i suppose) ? [/quote:1190xlhf]
Yes, you can just use Channel::addDSP/ChannelGroup::addDSP to insert your custom DSP units anywhere in the signal path.

  • You must to post comments
0
0

Thanks again for your answers.
Is tere a way to stop the resampling so the incoming data frequency stay to 16k ? because resampling the data means modifying the signal and my AEC works with the correlation/ cross correlation of the inputs signals.

SetDSPBufferSize : when i try to change its length form 1024 to 512, the output sound is corrupted is there something else i must change to balance the process ?

in1 ——->/- DSP -\ —-> out1
in2 ——->\ – – – – / —-> out2

Now, an example of what i need to get could be
out1 = in1 * 2;
out2 = in1/2 + in2;

I need to be able to get access to the data of[u:3e7dbn3h] in1 and in2 in the same DSP at the same time[/u:3e7dbn3h].

As you said earlier, i created a groupA for in1 and a groupB for in2, and added the to the mastergroup.
But inside the custom dsp "mydsp", when i look the inbuffer it looks like in1 and in2 got mixed and i can’t find a way to get in1 and in2 instead of in1+in2.
Here is my actual code, if you can see where my mistake is it would be great.

[code:3e7dbn3h]#include <fmodex/fmod.h>

include <fmodex/fmod_errors.h>

include "wincompat.h"

include <stdio.h>

include <string.h>

FILE *fichier_sortie;
short Signal_Out[1];

void ERRCHECK(FMOD_RESULT result)
{
if (result != FMOD_OK)
{
printf("FMOD error! (%d) %s\n", result, FMOD_ErrorString(result));
exit(-1);
}
}

FMOD_RESULT F_CALLBACK myDSPCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels)
{
unsigned int count, userdata;
int count2;
char name[256];
float temp;
FMOD_DSP *thisdsp = dsp_state->instance;

/*
    This redundant call just shows using the instance parameter of FMOD_DSP_STATE and using it to
    call a DSP information function.
*/
FMOD_DSP_GetInfo(thisdsp, name, 0, 0, 0, 0);
FMOD_DSP_GetUserData(thisdsp, (void **)&amp;userdata);

/*
    This loop assumes inchannels = outchannels, which it will be if the DSP is created with '0'
    as the number of channels in FMOD_DSP_DESCRIPTION.
    Specifying an actual channel count will mean you have to take care of any number of channels coming in,
    but outputting the number of channels specified.  Generally it is best to keep the channel
    count at 0 for maximum compatibility.
*/
printf(&quot;\nlength %d   inchannels  %d  outchannels %d&quot;, length,inchannels,outchannels);
for (count = 0; count &lt; length; count++)
{
    for (count2 = 0; count2 &lt; outchannels; count2++)
    {
        temp = inbuffer[(count * inchannels) + count2];
        printf(&quot;\n %f&quot;, temp*32000);
        outbuffer[(count * outchannels) + count2] = temp *2;
    }
    Signal_Out[0] = (short)(temp * 32000);
    fwrite(Signal_Out, sizeof(short), 1, fichier_sortie);
}

return FMOD_OK;

}

int main(int argc, char *argv[])
{
FMOD_SYSTEM *system = 0;
FMOD_SOUND *sound[2];

FMOD_CHANNEL      *channel[2];
FMOD_DSP          *mydsp = 0;
int                key;
int                driver;
int                exitprocess = 0;
unsigned int       version;

// float pan = 0;
int playingC = 0, playingV = 0;
FMOD_CHANNELGROUP *groupA, *groupB, *masterGroup;

/*
       Opening an output file
*/
if((fichier_sortie=fopen(&quot;Signalsortie.raw&quot;,&quot;w+b&quot;))==NULL)
{
        printf(&quot;\nError! Probleme a l'ouverture du fichier de sortie&quot;);
        exit(-3);
}


/*
    Create a System object and initialize.
*/
ERRCHECK(FMOD_System_Create(&amp;system));
ERRCHECK(FMOD_System_GetVersion(system, &amp;version));
printf(&quot;\nversion : %d&quot;, version);
if (version &lt; FMOD_VERSION)
{
    printf(&quot;Error!  You are using an old version of FMOD %08x.  This program requires %08x\n&quot;, version, FMOD_VERSION);
    return 0;
}

/*
 * Initialize audio card
 * */
ERRCHECK(FMOD_System_SetOutput(system, FMOD_OUTPUTTYPE_ALSA));           //Choix du périphérique ALSA
driver = 0; //  Choix du systeme par défault    (shannon)
ERRCHECK(FMOD_System_SetDriver(system, driver));


/*
 * Here i'm trying unsuccessfully to change the Buffersize of the DSP inputs from 1024 to 512 samples
 * unsuccessfully because the output audio is corrupted
 */
unsigned int fmBufLen;int fmNBuf;
ERRCHECK(FMOD_System_GetDSPBufferSize(system, &amp;fmBufLen, &amp;fmNBuf));
ERRCHECK(FMOD_System_SetDSPBufferSize(system, fmBufLen*2, fmNBuf));


ERRCHECK(FMOD_System_Init(system, 32, FMOD_INIT_NORMAL, NULL));


/*Opening of the sounds*/
ERRCHECK(FMOD_System_CreateSound(system, &quot;Signaltemp.wav&quot;, FMOD_SOFTWARE | FMOD_LOOP_NORMAL, 0, &amp;sound[0]));
ERRCHECK(FMOD_System_CreateSound(system, &quot;Sig08.wav&quot;, FMOD_SOFTWARE | FMOD_2D | FMOD_CREATESTREAM, 0, &amp;sound[1]));


/*
 * DSP - ChannelGroup creation
 */

/*
 *                  / &lt;--- GroupA
 *     masterGroup
 *                  \ &lt;--- GroupB
 */
ERRCHECK(FMOD_System_CreateChannelGroup(system, &quot;Group A&quot;, &amp;groupA));
ERRCHECK(FMOD_System_CreateChannelGroup(system, &quot;Group B&quot;, &amp;groupB));

ERRCHECK(FMOD_System_GetMasterChannelGroup(system, &amp;masterGroup));

ERRCHECK(FMOD_ChannelGroup_AddGroup(masterGroup, groupA));
ERRCHECK(FMOD_ChannelGroup_AddGroup(masterGroup, groupB));



/*
 *                  / &lt;--- GroupA   &lt;--- channel[0] (Signaltemp.wav)
 *     masterGroup
 *                  \ &lt;--- GroupB   &lt;--- channel[1] (Sig08.wav);
 */
ERRCHECK(FMOD_System_PlaySound(system, FMOD_CHANNEL_FREE, sound[0], TRUE, &amp;channel[0]));
ERRCHECK(FMOD_Channel_SetChannelGroup(channel[0], groupA));
ERRCHECK(FMOD_Channel_SetPaused(channel[0], FALSE));

ERRCHECK(FMOD_System_PlaySound(system, FMOD_CHANNEL_FREE, sound[1], TRUE, &amp;channel[1]));
ERRCHECK(FMOD_Channel_SetChannelGroup(channel[1], groupB));
ERRCHECK(FMOD_Channel_SetPaused(channel[1], FALSE));

/*
    Create the DSP effects.
*/
{
    FMOD_DSP_DESCRIPTION  dspdesc;

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

    strcpy(dspdesc.name, &quot;Echo Cancellation Unit (DSP)&quot;);
    dspdesc.channels     = 0;                   // 0 = whatever comes in, else specify.
    dspdesc.read         = myDSPCallback;
    dspdesc.userdata     = (void *)0x12345678;

    ERRCHECK(FMOD_System_CreateDSP(system, &amp;dspdesc, &amp;mydsp));
}

/*
    Inactive by default.
*/
ERRCHECK(FMOD_DSP_SetBypass(mydsp, TRUE));
ERRCHECK(FMOD_System_AddDSP(system, mydsp, 0));
/*
    Main loop.
*/
do
{
    if (kbhit())
    {
        key = getch();

        switch (key)
        {
            case 'f' :
            case 'F' :
            {
                static int active = FALSE;
                ERRCHECK(FMOD_DSP_SetBypass(mydsp, active));
                active = !active;
                break;
            }
            case 'v' :
            case 'V' :
            {
                playingV = !playingV;
                ERRCHECK(FMOD_ChannelGroup_SetMute(groupA, playingV));
                break;
            }

            case 'c' :
            case 'C' :
            {
                playingC = !playingC;
                ERRCHECK(FMOD_ChannelGroup_SetMute(groupB, playingC));
                break;
            }

            case 'q' :
            case 'Q' :
            {
                exitprocess = 1;
            }
        }
    }

    ERRCHECK(FMOD_System_Update(system));

    Sleep(100);
} while ((key != 27) &amp;&amp; (exitprocess ==0));

/*
    Shut down
*/
ERRCHECK(FMOD_Sound_Release(sound[0]));
ERRCHECK(FMOD_Sound_Release(sound[1]));
ERRCHECK(FMOD_DSP_Release(mydsp));
ERRCHECK(FMOD_System_Close(system));
ERRCHECK(FMOD_System_Release(system));
fclose(fichier_sortie);
return 0;

}[/code:3e7dbn3h]

Another question : is it possible to access the data (the ones appearing in the inbuffer of a dsp) from the main function (it would be a solution in order to get in1 an in2 without using a dsp) ?

To finish is there anywhere a "How to use FMOD for dummy" tutorial ?
thanks again,
Cedric

  • You must to post comments
0
0

Hi, some news for those who may have the same problems :)

First i found a way to keep the frequency to 16k instead of the default 48k,
I used :
– FMOD_System_GetSoftwareFormat to get all the parameters
– FMOD_System_SetSoftwareFormat to reset all the parameters, with of course the frequency one to 16k.

This modification solved my second problem, i can now set my buffer size to 512 without corruption/clipping.

I didn’t find how to get 2 signals in one DSP and keeping them as they are (instead of summing them as it look like actually) so i’m going to try this :

MASTER|<———|DSP1|<——-Xin1
– D S P |<———|DSP2|<——-Xin2

where Xin1 goes to the Inbuffer of DSP1 and Xin2 in DSP2’s.
Then i’m going to save those 2 Inbuffers in a global array of float and write in the Outbuffer of DSP1 and 2 to ‘0’.
To finish, i will in MasterDSP work my echo canceller using the 2 saved buffers.
I just hope there will not be a desync between the 3 DSPs or i’m screwed :)

Can anyone confirm me it will always be DSP1, DSP2 and then MasterDSP (supposing i active the DSPs in that order and never deactivate them) ?

Well i do not like the idea of using some global arrays, so if anyone know
– how to keep 2 incoming signals (in the DSP) not mixed
or
-how to get access to my signals on the main (no using of DSP)
it would be awesome :)

[quote:vra95xak] Post subject: Query on the *inbuffer and *outbuffer data structure in DSP

But I didn’t find any documentation on this isuuse in the delivered HTML help file[/quote:vra95xak]Is there an HTML documentation a didn’t find ?

Cédric

  • You must to post comments
0
0

You can store the buffers globally, that should work. The DSP units wont get out of sync because they will each be called once per mix.

[quote:2mxzt5om]- how to keep 2 incoming signals (in the DSP) not mixed[/quote:2mxzt5om]
You can use Channel::setSpeakerLevels to direct the signal to different channels. So if the mixer is running in stereo and you have 2 mono signals you can send one to the right channel and one to the left channel and they wont be mixed.

[quote:2mxzt5om]-how to get access to my signals on the main (no using of DSP) [/quote:2mxzt5om]
You can access the sound data without a DSP by using Sound::lock/unlock. If you take a look at the record to disk example it can show you how to extract the data. This data wont be resampled or up/downmixed at all it will be the raw sound, which is what you want.

[quote:2mxzt5om]Post subject: Query on the *inbuffer and *outbuffer data structure in DSP
But I didn’t find any documentation on this isuuse in the delivered HTML help file
Is there an HTML documentation a didn’t find ? [/quote:2mxzt5om]
Take a look at fmodex.chm:
API Reference/FMOD Ex API reference/Callbacks/FMOD_DSP_READCALLBACK

  • You must to post comments
0
0

Hi,
Thanks for your answers, it really helped!
I’ve one last question (hopefully i will be able to finish this project after that…) :
How can i apply a DSP to the recording input (FMOD_System_RecordStart) ?
Because as i understand it, the RecordStart doesn’t use a channel on which i can apply my DSP.
Thanks,
C.

  • You must to post comments
0
0

[quote:28hmkloi]How can i apply a DSP to the recording input (FMOD_System_RecordStart) ? [/quote:28hmkloi]
That’s not easy. As you noted DSPs can only be applied to channels/channelgroups so you will have to call System::playSound to play that Sound in a Channel.

  • You must to post comments
Showing 12 results
Your Answer

Please first to submit.