Author Topic: Formant Filter  (Read 13331 times)

matrix12x

  • Team Member
  • ***
  • Posts: 200
    • View Profile
Formant Filter
« on: October 25, 2014, 03:03:42 PM »

I was wondering if anyone has tried implementing a formant filter yet, something akin to the one on musicdsp.org
http://www.musicdsp.org/showArchiveComment.php?ArchiveID=110


I was going to hack my way through this later this month and was wondering if there is anything I should keep an eye out for?

Xavier

  • Administrator
  • Hero Member
  • *
  • Posts: 2259
    • View Profile
Re: Formant Filter
« Reply #1 on: October 26, 2014, 09:15:58 PM »

Yes i saw this one.
It was much too CPU intensive to integrate the official engine.

But i would love to hear how it sounds.
Let us know if you have it working...


matrix12x

  • Team Member
  • ***
  • Posts: 200
    • View Profile
Re: Formant Filter
« Reply #2 on: October 27, 2014, 04:05:14 AM »
So I tried it and......
The coefficient for the A vowel is kind of harsh. Which can be cool.

It is ridiculously CPU intensive. When the Formant filter is selected, the encoders don't scan quite right, completely missing steps, for example the third parameter to control gain.

And if I implement one of the encoders to change the formant it crashes.

I am going to look for a less CPU intensive approach. I wonder how one would optimize the music dap version?

Xavier

  • Administrator
  • Hero Member
  • *
  • Posts: 2259
    • View Profile
Re: Formant Filter
« Reply #3 on: October 27, 2014, 10:12:21 AM »
I am going to look for a less CPU intensive approach. I wonder how one would optimize the music dap version?

In the loop don't use any member variable.
Create local variables for anything you update in the loop.
And Copy them i the member variables after the loop.

The goal is to have all writable variable in CPU registers.

pld

  • Team member
  • *
  • Posts: 41
    • View Profile
Re: Formant Filter
« Reply #4 on: October 30, 2014, 02:00:58 PM »
Are 'double' calculations emulated in software, instead of using the hardware FPU? That would certainly kill performance...
However the comments seem to indicate that using float makes the filter unstable :-\



Xavier

  • Administrator
  • Hero Member
  • *
  • Posts: 2259
    • View Profile
Re: Formant Filter
« Reply #5 on: October 31, 2014, 10:22:11 PM »
I just gave a quick try on one channel but could not get any sound out of these coefs :

Code: [Select]

    case FILTER_FORMANT:
    {
        int vowelnum = params.effect.param1  * 4.0d;
        float *sp = this->sampleBlock;

        float formantMemoryLeft0 = formantMemoryLeft[0];
        float formantMemoryLeft1 = formantMemoryLeft[1];
        float formantMemoryLeft2 = formantMemoryLeft[2];
        float formantMemoryLeft3 = formantMemoryLeft[3];
        float formantMemoryLeft4 = formantMemoryLeft[4];
        float formantMemoryLeft5 = formantMemoryLeft[5];
        float formantMemoryLeft6 = formantMemoryLeft[6];
        float formantMemoryLeft7 = formantMemoryLeft[7];
        float formantMemoryLeft8 = formantMemoryLeft[8];
        float formantMemoryLeft9 = formantMemoryLeft[9];


        for (int k=0 ; k < BLOCK_SIZE ; k++) {

            //---------------------------------------------------------------------------------
            *sp = (float) ( coeff[vowelnum][0] * (*sp)  +
            coeff[vowelnum][1] * formantMemoryLeft0 +
            coeff[vowelnum][2] *formantMemoryLeft1 +
            coeff[vowelnum][3] *formantMemoryLeft2 +
            coeff[vowelnum][4] *formantMemoryLeft3 +
            coeff[vowelnum][5] *formantMemoryLeft4 +
            coeff[vowelnum][6] *formantMemoryLeft5 +
            coeff[vowelnum][7] *formantMemoryLeft6 +
            coeff[vowelnum][8] *formantMemoryLeft7 +
            coeff[vowelnum][9] *formantMemoryLeft8 +
            coeff[vowelnum][10] *formantMemoryLeft9 );

            formantMemoryLeft9= formantMemoryLeft8;
            formantMemoryLeft8= formantMemoryLeft7;
            formantMemoryLeft7= formantMemoryLeft6;
            formantMemoryLeft6= formantMemoryLeft5;
            formantMemoryLeft5= formantMemoryLeft4;
            formantMemoryLeft4= formantMemoryLeft3;
            formantMemoryLeft3= formantMemoryLeft2;
            formantMemoryLeft2= formantMemoryLeft1;
            formantMemoryLeft1= formantMemoryLeft0;
            formantMemoryLeft0= (*sp);

            *sp++ = (*sp) * mixerGain;
            *sp++ = (*sp) * mixerGain;


        }
        formantMemoryLeft[0] = formantMemoryLeft0;
        formantMemoryLeft[1] = formantMemoryLeft1;
        formantMemoryLeft[2] = formantMemoryLeft2;
        formantMemoryLeft[3] = formantMemoryLeft3;
        formantMemoryLeft[4] = formantMemoryLeft4;
        formantMemoryLeft[5] = formantMemoryLeft5;
        formantMemoryLeft[6] = formantMemoryLeft6;
        formantMemoryLeft[7] = formantMemoryLeft7;
        formantMemoryLeft[8] = formantMemoryLeft8;
        formantMemoryLeft[9] = formantMemoryLeft9;

    }
    break;

If anyone see something wrong... let me know.
If not, i assume the 32bits FPU of the STM32F4 is not precise enough for this operation.

I would not bereally surprise when i look at the coef[] which goes from 8.11044e-06 to 181.6233289...
The first one must be rounded to 0.

Xavier

matrix12x

  • Team Member
  • ***
  • Posts: 200
    • View Profile
Re: Formant Filter
« Reply #6 on: November 01, 2014, 12:56:49 AM »
Hi Xavier,

According to one of the comments on musicdsp.org, I changed the first coefficient to 3.11044e-06 from 8.11044e-06. Although I think you are correct about it being rounded to zero.

I also put the coefficients in the case, as well as the:    
static double memory[10]={0,0,0,0,0,0,0,0,0,0};

Also, I did this exactly as was in the original:
      memory[9]= memory[8];
      memory[8]= memory[7];
      memory[7]= memory[6];
      memory[6]= memory[5];
      memory[5]= memory[4];
      memory[4]= memory[3];
      memory[3]= memory[2];
      memory[2]= memory[1];   
      memory[1]= memory[0];
      memory[0]=(double) localV;
then a:
                localv0L = localV;

I am not sure it is the correct sound I get, but I definitely get sound.

matrix12x

  • Team Member
  • ***
  • Posts: 200
    • View Profile
Re: Formant Filter
« Reply #7 on: November 01, 2014, 06:50:33 PM »
I am wondering if a better approach would be 3 parallel band pass filters?
or is that too cpu intensive?

Xavier

  • Administrator
  • Hero Member
  • *
  • Posts: 2259
    • View Profile
Re: Formant Filter
« Reply #8 on: November 02, 2014, 06:37:22 PM »

Thanks, a assume it cannot work at all with floats (32 bits) as i did.
I haven't tried with double (64 bits)... which will be much slower on the preenfm2 because 64 bits is not natively suported by the ARM FPU.

Keep in mind that intel/amd FPU use 80 bits for intermediate result, so that's can be a usefull/hearable difference in that kind of calcul.

Have 3 parallels band pass is an idea... Did any one make that before for firmant filtering ? I don't know.
It will be less intessive than the formant filter we talk about.
The problem is to control preciselly  the wideness and the amplitude of the formant.

Xavier

matrix12x

  • Team Member
  • ***
  • Posts: 200
    • View Profile
Re: Formant Filter
« Reply #9 on: November 02, 2014, 07:49:56 PM »
Sound on Sound has an article on this in the analog realm. http://www.soundonsound.com/sos/mar01/articles/synthsec.asp

and provides a table with the center frequencies for different formants for a man:

VOWEL SOUND AS IN... F1 F2 F3
"ee" leap 270 2300 3000
"oo" loop 300 870 2250
"i" lip 400 2000 2550
"e" let 530 1850 2500
"u" lug 640 1200 2400
"a" lap 660 1700 2400

Then they go on to discuss amplitude and the width or Q of the band pass filters. They state that the bandwidth for the filters for a man's formants are around 100Hz wide and a woman's are slightly wider.

I have seen something like this with the Freq of one or more of these BPFs ever so slightly modulated by a LFO.

matrix12x

  • Team Member
  • ***
  • Posts: 200
    • View Profile
Re: Formant Filter
« Reply #10 on: November 02, 2014, 09:09:01 PM »
In the Csound manual I found a table:
http://csound.github.io/docs/manual/MiscFormants.html

It lists frequencies, band widths and gain/loss for each band. Although it looks like 5 BPFs are used there.


Xavier

  • Administrator
  • Hero Member
  • *
  • Posts: 2259
    • View Profile
Re: Formant Filter
« Reply #11 on: November 03, 2014, 11:21:50 PM »
Very Interesting URL, thanks for sharing  :)

matrix12x

  • Team Member
  • ***
  • Posts: 200
    • View Profile
Re: Formant Filter
« Reply #12 on: November 06, 2014, 04:37:13 AM »
So what I am thinking of trying, when I get a free min or two, is taking the BPF you already implemented, making a formant filter comprised of 5 copies ran in parallel, setting their Q (bw=f/Q) and freq according to an array of values from those tables. Using the encoder to set he formant/vowel.

Would this be processor intensive?


Xavier

  • Administrator
  • Hero Member
  • *
  • Posts: 2259
    • View Profile
Re: Formant Filter
« Reply #13 on: November 06, 2014, 10:10:00 AM »
Would this be processor intensive?

Yes. But as far as you limit the polyphony or use simple algorithms (3 or 4 operators) it should be OK.