Kernel BLEP for aliasing reduction


#1

Hi,
I’m trying to implement a BLEP oscillator but i’m not sure how to generate a correct kernel.
I’ve tried the following:

int num_zero_crossings = 1;
int oversampling = 2048;
long n = num_zero_crossings * oversampling * 2 + 1;
double blep_table[n];

double sum = 0;
double val = 0;
for (int i = 0; i < n; i++){
   double t = (double) (i) / (double) (n - 1);
   val = Sinc(num_zero_crossings + 2 * t * num_zero_crossings);
   val *= 0.42 - 0.5 * cos(2.0 * PI * t) + 0.08 * cos(4.0 * PI * t); //Apply blackmann
   sum += val;                                                       // To integrate 
   blep_table[i] = sum;
}

for (int i = 0; i < n; i++){
   blep_table[i] = blep_table[i] / sum; // normalize
   if (i > n / 2 - 1) {                  // subtract unit step
      blep_table[i] -= 1;
   }
   blep_table[i] *= 2;
}

with:

static inline double Sinc(double x){
   double pix;
   if(x == 0){
      return 1;
   }
   else{
      pix = PI * x;
      return sin(pix) / pix;
   }
}

But I feel like I’m doing something wrong. Could someone comment on this ?
Thanks for your help,
Best regards, Louis


#2

The mistake in your code is that you totally discard the negative half of the sinc function. I think you meant something like this instead:

val = Sinc(-num_zero_crossings + 2 * t * num_zero_crossings);

Then the other mistake is to use BLEP instead of minBLEP (more practical to use because the response is completely causal). And then to use minBLEP instead of polyBLEP :slight_smile:


#3

Hi pichenettes,
Thanks for your answer. Yes I meant:

val = Sinc(-num_zero_crossings + 2 * t * num_zero_crossings);

I did a mistake when I wrote it here.
Yes i’m aware about polyblep but the idea is to apply more than 2 points correction. Is it possible with polyblep ?
Concerning minblep, I’ve heard that this method introduce more problem than it solves and that linear BLEP worth the effort. I should also mentionne I want to implement hard sync.

About the BLEP kernel is the window applied at the right moment (before integration) ?
Thanks again for your help !


#4

I’ve run your code with this modification and the output seemed correct. What’s your problem exactly?


#5

When I try to use it:

void lfo_perform64(t_lfo *x, t_object *dsp64, double **ins, long numins, double **outs, long numouts, long sampleframes, long flags, void *userparam){
   double *in = ins[0];
   double *out = outs[0];

   double next_sample = x->last_sample;

   while (sampleframes --){
      double this_sample = next_sample;
      next_sample = 0;
      double phase_inc = *in++ / x->samplerate;
      x->phase += phase_inc;
      if (x->phase >= 1){
         x->phase -= 1;
         double t = x->phase / phase_inc;
         next_sample -= DoBlep2(x, t); 
         this_sample -= DoBlep1(x, t);
      }
   next_sample += (x->phase * 2) - 1;
   *out++ = this_sample;
   }
   x->last_sample = next_sample;
}

with

static inline double DoBlep1(t_lfo *x, double t){
   double blep_table_center = x->blep_table_size / 2.0 - 1;
   double index = t * blep_table_center;
   return LinInterpo(x->blep_table, index);
}

and

static inline double DoBlep2(t_lfo *x, double t){
   double blep_table_center = x->blep_table_size / 2.0 - 1;
   double index = (1 + t) * blep_table_center;
   return LinInterpo(x->blep_table, index);
}

The interpolation is:

static inline double LinInterpo(double *buffer, double index){
   long x0 = (long)index;
   if (x0 != index ){
      long x1 = x0 + 1;
      return buffer[x0] + ((buffer[x1] - buffer[x0])) * (index - x0);
   }
   else{
      return buffer[x0];
   }
}

When I Replace DoBlep1 and DoBlep2 by:

static inline double DoPolyBlep1(double t){
   t -= 1;
   return t*t + t+t + 1.0;
}

and

static inline double DoPolyBlep2(double t){
   return t+t - t*t - 1.0;
}

Everything works as expected (no noise appearing).

The aliasing reduction is okay but sometime I got some noise appearing in my freq analyser.
I suspected the kernel because when I replace the DoBlep1 and Doblep2 by approximation (polyblep) there is no problem !
But maybe I should go with minblep or 4 point polyblep if it’s possible ?
What do you think about minblep ? Did it really introduce more problems ? Or is it as simple as using a more complex kernel and then forgot about lookahead ?
Thanks again for your help !


#6

Your code looks strange… When x->phase exceeds 1.0, it should be wrapped in the [0, 1[ range.


#7

yes, sorry an other mistake … I edited my last post


#8

It would help if you posted directly your project - the actual code you’re trying to run. After all, there could be a bug in LinInterpo… and we’re not going very far if all the mistakes I detect are copy/paste error from your code to the other.

An oddity: in DoBlep1, you do t = 1 - tand then use (1 - t)when computing the index. So t is not changed at all?


#9

Hey pichnettes,
You’re right, I didn’t see the oddity. I Edited my code adding the interpolation part. I also add the polyblep function I use to compare with the BLEP. I didn’t post all the project because it’s a max msp external, so I thought it won’t be good for clarity but I will if you think it’s needed.
Thanks again for your help, I really appreciate this !