1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
|
/*------------------- by Marc Poirier ][ January 2002 ------------------*/
#ifndef __lfo
#define __lfo
#include <math.h>
#include <stdlib.h>
#include "dfxmisc.h"
#include "TempoRateTable.h"
//-------------------------------------------------------------------------------------
// these are the 8 LFO waveforms:
enum
{
kSineLFO,
kTriangleLFO,
kSquareLFO,
kSawLFO,
kReverseSawLFO,
kThornLFO,
kRandomLFO,
kRandomInterpolatingLFO,
numLFOshapes
};
//-------------------------------------------------------------------------------------
// constants & macros
#define LFOshapeScaled(A) (paramSteppedScaled((A), numLFOshapes))
#define LFOshapeUnscaled(A) (paramSteppedUnscaled((A), numLFOshapes))
#define NUM_LFO_POINTS 512
const float NUM_LFO_POINTS_FLOAT = (float)NUM_LFO_POINTS; // to reduce casting later on
const float LFO_TABLE_STEP = 1.0f / (float)NUM_LFO_POINTS; // to reduce division & encourage multiplication
const long SQUARE_HALF_POINT = NUM_LFO_POINTS / 2; // the point in the table when the square waveform drops to zero
#define LFO_SMOOTH_DUR 48
const float LFO_SMOOTH_STEP = 1.0f / (float)LFO_SMOOTH_DUR;
// this scales the return of processLFO() from 0.0 - 1.0 output to 0.0 - 2.0 (oscillating around 1.0)
#define processLFOzero2two(A) ( ((A)->processLFO() * 2.0f) - (A)->fDepth + 1.0f );
//-----------------------------------------------------------------------------
class LFO
{
public:
LFO();
~LFO();
void reset();
void fillLFOtables();
void pickTheLFOwaveform();
void getShapeName(char *nameString);
void syncToTheBeat(long samplesToBar);
// the LFO waveform tables
float *sineTable, *triangleTable, *squareTable, *sawTable, *reverseSawTable, *thornTable;
// the following are intended to be used as 0.0 - 1.0 VST parameter values:
float fOnOff; // parameter value for turning the LFO on or off
float fTempoSync; // parameter value for toggling tempo sync
float fRate; // parameter value for LFO rate (in Hz)
float fTempoRate; // parameter value for LFO rate (in cycles per beat)
float fDepth; // parameter value LFO depth
float fShape; // parameter value for LFO shape
bool onOff; // in case it's easier to have a bool version of fOnOff
float position; // this tracks the position in the LFO table
float stepSize; // size of the steps through the LFO table
float *table; // pointer to the LFO table
float randomNumber; // this stores random values for the random LFO waveforms
float oldRandomNumber; // this stores previous random values for the random interpolating LFO waveform
float cycleRate; // the rate in Hz of the LFO (only used for first layer LFOs)
long smoothSamples; // a counter for the position during a smoothing fade
long granularityCounter; // a counter for implementing LFO processing on a block basis
long granularity; // the number of samples to wait before processing
//--------------------------------------------------------------------------------------
// This function wraps around the LFO table position when it passes the cycle end.
// It also sets up the smoothing counter if a discontiguous LFO waveform is being used.
void updatePosition(long numSteps = 1)
{
// increment the LFO position tracker
position += (stepSize * (float)numSteps);
if (position >= NUM_LFO_POINTS_FLOAT)
{
// wrap around the position tracker if it has made it past the end of the LFO table
position = fmodf(position, NUM_LFO_POINTS_FLOAT);
// get new random LFO values, too
oldRandomNumber = randomNumber;
randomNumber = (float)rand() / (float)RAND_MAX;
// set up the sample smoothing if a discontiguous waveform's cycle just ended
switch (LFOshapeScaled(fShape))
{
case kSquareLFO :
case kSawLFO :
case kReverseSawLFO :
case kRandomLFO :
smoothSamples = LFO_SMOOTH_DUR;
default:
break;
}
}
// special check for the square waveform - it also needs smoothing at the half point
else if (LFOshapeScaled(fShape) == kSquareLFO)
{
// check to see if it has just passed the halfway point
if ( ((long)position >= SQUARE_HALF_POINT) &&
((long)(position - stepSize) < SQUARE_HALF_POINT) )
smoothSamples = LFO_SMOOTH_DUR;
}
}
//--------------------------------------------------------------------------------------
// this function gets the current 0.0 - 1.0 output value of the LFO & increments its position
float processLFO()
{
float randiScalar, outValue;
int shape = LFOshapeScaled(fShape);
if (shape == kRandomInterpolatingLFO)
{
// calculate how far into this LFO cycle we are so far, scaled from 0.0 to 1.0
randiScalar = position * LFO_TABLE_STEP;
// interpolate between the previous random number & the new one
outValue = (randomNumber * randiScalar) + (oldRandomNumber * (1.0f-randiScalar));
}
//
else if (shape == kRandomLFO)
outValue = randomNumber;
//
else
outValue = table[(long)position];
return (outValue * fDepth);
}
};
#endif
|