[Coding] an example of compressor that breaks :-(

edited June 2014 in General
Hello,

So I am trying just to implement a short code from a book ;-)

When I call the Compression function, the LXR stops running :-(
everything is blocked, no possibility to launch the sequencer anymore, no sound, etc.

Any idea where I am doing something wrong in the code?

One of my guess would be the audio buffer (int16_t *buf) that is not returned correctly once the compression funtion is finished ?

Thanks!

main.c
            calcCompressionBlock(buf,size,-20,7,0.1,0.5,1.0);

disto.c
float calcCompressionBlock(int16_t* buf,const uint8_t size, int8_t threshold,uint8_t ratio,float attack_constant,float release_constant,float penv)
{
  int i;
 
  float th, rat;
  float ac, rc;
  float env = penv;
  float indb, dest;
  float inp[size];
  float outp[size];
 
  th = (float) threshold; // in dB FS
  rat = 1.0 - (1.0/(float) ratio); // to calculate gain reduction
  ac = 1.0 / ((float) attack_constant * (float) SR);
  rc = 1.0 / ((float) release_constant * (float) SR);
  //env = 1.0;
 
 
 
  // -32767 + 32767 to -1.0 +1.0
  for(i = 0; i < size; i++){
      inp[i] = buf[i]/32767.0f;
  }
 
  // compression
  //
   for(i = 0; i < size; i++)
   {
    indb = 20.0 * log10(fabs(inp[i]));  // to dB FS
    if (indb > th) {
      dest = (th - indb) * rat; // Gain reduction target
    }
    else {
      dest = 0.0;
    }
    dest = pow(10, dest * 0.05);  // to linear amp
    if (env > dest) { // attack
      env = env + (dest-env)*ac;
    }
    else { // release
      env = env + (dest-env)*rc;
    }
    outp[i] = inp[i]* env;
  }
 
  // -1.0 +1.0 to -32767 + 32767
  for(i = 0; i < size; i++){
      buf[i] = outp[i]*32767;
  }
 
  return env; // the new ENV value that I should catch back and reinject into the next block calculation .. I don't do it yet :-)
 
}

Comments

  • Two ideas:
    • Stack overflow because you are allocating inp & outp on the stack (float inp[size] which I think is only allowed in C99)
    • Division by 0, not sure how arm handles that (probably can be configured)

  • Thanks :-)
    arg. you are going to say my quesiton is stupid but which ANSI C are we compiling if not C99 ?
    sorry again for this dummy question :-)
  • By the way if I just do a function with inside:

    for(i = 0; i < size; i++){
          inp[i] = buf[i]/32767.0f;
      }
     // -1.0 +1.0 to -32767 + 32767
      for(i = 0; i < size; i++){
          buf[i] = outp[i]*32767;
      }
     
    the sound is OKAY.

  • I'm not sure what the default C is these days since gcc isn't strictly anything until you tell it. But I think that method of stack-allocating an array doesn't work everywhere, so it may break. But you don't really need inp/outp anyway from the looks of things.

    That last snippet probably shouldn't work, since it assigns buf[i] from outp[i] without setting outp[i] (or it just got lost in copypasta).

    Are there any compiler warnings? Maybe log10 or pow are just reaaally slow (or not found at all?)
  • oki, thanks for this hinys, I will come back to you with more info. I am leaving for some days ;-) Talk to you at my return :-)))
  • what values have you set here?

      rat = 1.0 - (1.0/(float) ratio); // to calculate gain reduction
      ac = 1.0 / ((float) attack_constant * (float) SR);
      rc = 1.0 / ((float) release_constant * (float) SR);

    if either 'ratio', 'attack_constant', 'release_constant' or 'SR' == 0 the code will crash.
  • Lots of chance for divide by zero.

    If you initialize env as 0 and the time constants are too long it will be silent.  I think env should be initialized as 1.0.

  • Also there are a lot of log pow and fabs calls that you could avoid.  That will reduce the cpu load.  I don't think you need the extra buffers either.

    //linear threshold in signed 16 bit so we can do fewer calls to log
    int16_t  in_abs;
    int16_t th_linear = (int16_t)(32767.0f * pow(10.0f, (float)threshold * 0.05f));
    float temp_db ;
    for (i = 0; i < size; i++)
    {
    in_abs = abs(buf[i]);//abs is faster than fabs so do abs on signed 16 value
    if (in_abs>th_linear)
    {
    in_abs = th_linear - in_abs;
    temp_db =  log10((float)in_abs) - 4.515436681142f; //log(A/B)=log(A)-log(B)
    // * 20 above then * 0.05 below cancel out.
    dest = pow(10.0f, temp_db * rat); //convert to linear scalar
    }
    else
    {
    dest = 1.0f;
    }
    if (env > dest) 
    { // attack
    env = env + (dest-env)*ac;
    }
    else 
    { // release
    env = env + (dest-env)*rc;
    }
    buf[i] = (int16_t)((float)buf[i] * env);
    }
    return env;
  • Actually that wont be much quicker.  You might try replacing the log and pow with lookup tables.
  • fabs should be 1 cycle for m4, and IIRC there's no integer abs instruction so it's probably comes out about the same. But as you say it will be pretty negligable since log10 and pow will be the bottleneck by orders of magnitude...

    LUT might work, even if you have to interpolate between entries. Not sure if there's an approximation to use that will yield a similar effect (tanh?) and that can be quickly calculated. As long as there's no division which hurts at 14 cycles :)
  • Interesting.  I was thinking from an old fashioned x86 perspective.  The M4 floating point stuff looks good.  

    There is a tricky log approximation here..


  • Hello everyone,
    sorry for my silence, I am a bit busy with work and concert :-) I will play the LXR on the 21st of june in Grenoble, France :-) 23 PM :-) main tekno scene !!!!  Parc paul mistral :-)

    next week, I will check back my code and chase the divide by sero issue :-)
    Meanwhile, I am using the LXR and my code and noticed a bug (when you do RND and save the results, the KIT is not saved with the new random sound, strange ! ). I need to correct this before going back to coding effects.
    talk to you soon :-)
  • Hey egnouf please make a little video or something and tell us how the lxr sound on a big system! ;)
  • hello!
    So I was at the main scene in Grenoble for Electro Music (very good hour - 11PM till 12PM)... many people and BIG system sound :-)

    The LXR sounds just excellent, it was adding PERCUSSIVE sounds to the main composition we played with my friend (a lot of toms, hit hat and I over used the ROLL function !). I used a lot the SRR function (sample rate reduction) but I want to improve the one delivered with the LXR as it lacks of harmonics (I have a idea for this .. adding a sine to the SRR function.. well).

    I like the LXR because it adds on top of other sounds its own caracter !
    it is much more significant that with a elektron (I have one) drum machine... Also I like that the LXR program and machine is robust, it last one hour without any bugs, etc. it is small, nice, easy to use, I love it!

    I will publish one minute of video soon :-)
    regards.
  • Thats great. Can't wait to see the video!
  • Beaware that the video will not reproduce a good quality sound but I will try to explain when you hear the LXR ;-)
  • I still have to hear the LXR on a big PA.
    so far I just know it from my cheap fostex monitors :-/
Sign In or Register to comment.