It can be applied or not per operator. The output of the LFO must be calculated once per sample and if selected, it is added to the logarithmic amplitude of the operator before the exponential lookup.
I present two algorithms that acheive the desired results. The first algorithm looks more complicated, but tests suggest to me that it's more efficient, and I think it more closely reflects the way the silicon is actually built. That's purely educated speculation on my part. The second algorithm is somewhat cleaner in lines but runs about 10% more slowly for me.
- Code: Select all
#define DAM 1
unsigned char lfoStepper = 0;
unsigned char lfoAmCounter = 0;
unsigned char lfoDir = 0;
unsigned char lfoAm;
void runLfoAm(void)
{
lfoStepper++;
if (!(lfoStepper & 0x3f))
{
if (lfoDir)
if (lfoAmCounter)
lfoAmCounter--;
else
{
lfoAmCounter++;
lfoDir = 0;
}
else
if (lfoAmCounter == 105)
{
lfoAmCounter--;
lfoDir = 1;
}
else
lfoAmCounter++;
}
if (DAM)
lfoAm = (lfoAmCounter >> 2) << 3;
else
lfoAm = (lfoAmCounter >> 4) << 3;
}
- Code: Select all
#define DAM 1
unsigned short int lfoAmCounter1 = 0;
unsigned char lfoDir1 = 0;
unsigned char lfoAm1;
void runLfoAm(void)
{
if (lfoDir)
if (lfoAmCounter <= 32)
lfoDir = 0;
else
lfoAmCounter--;
else
if (lfoAmCounter >= 6751)
lfoDir = 1;
else
lfoAmCounter++;
if (DAM)
lfoAm = (lfoAmCounter >> 8) << 3;
else
lfoAm = (lfoAmCounter >> 10) << 3;
}
In each case, the value of runLfoAm() is called once per sample, and then the value of lfoAm is available to modulate the amplitude of an operator.