Simple Tremolo?


#1

Hey I’ve been getting used to JUCE for coding audio plug ins specifically, i’ve done most of the basics at this point IE gain, delay, EQ filtering. I’m now trying to get my head around a basic tremolo effect so that i can start making variable delays for choruses, flangers etc. but I can’t quite get the thing to work.

Heres the main process block : \

float phase = 0.0;                             //start point for wave
float freq = *Freq;                           //gain var
float PI_double = 2 * float_Pi;              //2 * PI
float incr = freq * PI_double / SampleR;    //var to increment the wave
float w = PI_double / SampleR;
float mod;                                //variable to store the modulation
float depth = *Depth / 200;              //depth gotten from the depth param
float offset = 1 - depth;               //offset (caps the depth below 1.
float nsamp = buffer.getNumSamples();  //number of samps in buffer
  //get write pointers for L and R channels
float* channelDataL = buffer.getWritePointer (0);
float* channelDataR = buffer.getWritePointer (1);
      for (int i = 0; i < nsamp; ++i ){
       //calculate modulation
        mod = offset + depth * sin(w * phase);
   
      //output the samples * by the modulation
       channelDataL[i] *=  mod;
       channelDataR[i]  *=  mod;
   
       phase += incr;
   
   //wrap the phase var
     if (phase >= PI_double)
     phase -= PI_double;
        
    }}

as you can see it only uses 2 parameters one for frequency and one for depth of the effect, in short, I get sound output from the host after running it through the plug but the actual modulation of the sound isn’t there IE no ‘wobwobwob’ tremolo effects to be heard. Anyway, I’m fully out of ideas and I can only assume i’m doing something stupid in the generating of the sine wave somewhere?

any ideas ?


#2

please fix the formatting of the coded part.


#3

Do you mean so that it looks like it does now ?


#4

You need to be using float/double literals for your constants, not ints. IE

float depth = *Depth / 200;

should be

float depth = *depth / 200.0;

Also probably not a big deal for this plugin, but in general you want to avoid make trig function calls every sample period. For modulation effects, you should try creating an oscillator class and use it to generate a new sample every period. That way you can easily change the oscillator shape from sine to square to triangle or whatever. You should also avoid having to redo all those calculations every buffer cycle, if they only need to happen when a parameter changes. Not to mention the way it’s set up now, the “depth” parameter is fixed to the value at the beginning of every buffer, and you should account for it changing during a buffer period to get sample-accurate automation.


#5

I figured that sin call would be fairly inefficient, I was planning on making an OSC class at some point but wanted to get the tremolo working first, i figured that bit of code above would actually work to some extent but now that you mention it though it might have just made sense to implement it from a class right off the bat…maybe i’ll give that a go !


#6

erm, that is no improvement. If Depth is a float*, then the original was correct. If one operand of the division is a float, the result will be a float. It would be only a problem, if both were integers. In that case the result would be an integer division casted to a float, i.e. truncated.

Your “corrected” version would dereference a float? Maybe this is a construct, I am not aware of, but I think it won’t compile.

If you were talking about performance, go the whole nine yards and write

float depth = *Depth / 200.0f;

Otherwise the literal is created as double and then casted into a float, afaik (assuming that Depth is a float pointer from the parameter). But no big deal for the optimiser, I guess :wink:


#7

The “phase” variable is apparently declared as a local variable and initialized to 0.0 in the processing function, which won’t work. It should be a member variable instead.


#8

really? why would that be? it’s only used in that main process block and not anywhere else so surely it should only be in that block? it’s not a variable to hold a parameter value or anything either…


#9

It’s reset back to zero every time when the audio processing function is called. But you want the phase variable to retain its state between the calls, right?


#10

That makes so much sense. aha, i’ll try it out later on !


#11

Just made this change, works exactly the way i wanted it to now, thank a bunch!