aboutsummaryrefslogtreecommitdiff
path: root/dfx-library/lfo.cpp
blob: 58a58c3b9f3e98cc966bed68cf586b22e6c38cc4 (plain)
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#ifndef __lfo
#include "lfo.h"
#endif

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>


//------------------------------------------------------------------------
LFO::LFO()
{
	sineTable = new float[NUM_LFO_POINTS];
	triangleTable = new float[NUM_LFO_POINTS];
	squareTable = new float[NUM_LFO_POINTS];
	sawTable = new float[NUM_LFO_POINTS];
	reverseSawTable = new float[NUM_LFO_POINTS];
	thornTable = new float[NUM_LFO_POINTS];

	fillLFOtables();
	table = sineTable;	// just to have it pointing to something at least

	srand((unsigned int)time(NULL));	// sets a seed value for rand() from the system clock

	reset();
}

//------------------------------------------------------------------------
LFO::~LFO()
{
	if (sineTable)
		delete[] sineTable;
	if (triangleTable)
		delete[] triangleTable;
	if (squareTable)
		delete[] squareTable;
	if (sawTable)
		delete[] sawTable;
	if (reverseSawTable)
		delete[] reverseSawTable;
	if (thornTable)
		delete[] thornTable;
}

//------------------------------------------------------------------------
void LFO::reset()
{
	position = 0.0f;
	stepSize = 1.0f;	// just to avoid anything really screwy
	oldRandomNumber = (float)rand() / (float)RAND_MAX;
	randomNumber = (float)rand() / (float)RAND_MAX;
	smoothSamples = 0;
	granularityCounter = 0;
}

//-----------------------------------------------------------------------------------------
// this function creates tables for mapping out the sine, triangle, & saw LFO shapes

void LFO::fillLFOtables()
{
  long i, n;


	// fill the sine waveform table (oscillates from 0 to 1 & back to 0)
	for (i = 0; (i < NUM_LFO_POINTS); i++)
		sineTable[i] = (sinf( ( ((float)i/(float)NUM_LFO_POINTS)-0.25f ) * 2.0f * PI ) + 1.0f) * 0.5f;

	// fill the triangle waveform table
	// ramp from 0 to 1 for the first half
	for (i = 0; (i < NUM_LFO_POINTS/2); i++)
		triangleTable[i] = (float)i / (float)(NUM_LFO_POINTS/2);
	// & ramp from 1 to 0 for the second half
	for (n = 0; (i < NUM_LFO_POINTS); n++)
	{
		triangleTable[i] = 1.0f - ((float)n / (float)(NUM_LFO_POINTS/2));
		i++;
	}

	// fill the square waveform table
	// stay at 1 for the first half
	for (i = 0; (i < NUM_LFO_POINTS/2); i++)
		squareTable[i] = 1.0f;
	// & 0 for the second half
	for (n = 0; (i < NUM_LFO_POINTS); n++)
	{
		squareTable[i] = 0.0f;
		i++;
	}

	// fill the sawtooth waveform table (ramps from 0 to 1)
	for (i = 0; (i < NUM_LFO_POINTS); i++)
		sawTable[i] = (float)i / (float)(NUM_LFO_POINTS-1);

	// fill the reverse sawtooth waveform table (ramps from 1 to 0)
	for (i = 0; (i < NUM_LFO_POINTS); i++)
		reverseSawTable[i] = (float)(NUM_LFO_POINTS-i-1) / (float)(NUM_LFO_POINTS-1);

	// fill the thorn waveform table
	// exponentially slope up from 0 to 1 for the first half
	for (i = 0; (i < NUM_LFO_POINTS/2); i++)
		thornTable[i] = powf( ((float)i / (float)(NUM_LFO_POINTS/2)), 2.0f );
	// & exponentially slope down from 1 to 0 for the second half
	for (n = 0; (i < NUM_LFO_POINTS); n++)
	{
		thornTable[i] = powf( (1.0f - ((float)n / (float)(NUM_LFO_POINTS/2))), 2.0f );
		i++;
	}
}


//--------------------------------------------------------------------------------------
void LFO::getShapeName(char *nameString)
{
	switch (LFOshapeScaled(fShape))
	{
		case kSineLFO                : strcpy(nameString, "sine");					break;
		case kTriangleLFO            : strcpy(nameString, "triangle");				break;
		case kSquareLFO              : strcpy(nameString, "square");				break;
		case kSawLFO                 : strcpy(nameString, "sawtooth");				break;
		case kReverseSawLFO          : strcpy(nameString, "reverse sawtooth");		break;
		case kThornLFO               : strcpy(nameString, "thorn");					break;
		case kRandomLFO              : strcpy(nameString, "random");				break;
		case kRandomInterpolatingLFO : strcpy(nameString, "random interpolating");	break;
		default :																	break;
	}
}


//--------------------------------------------------------------------------------------
// this function points the LFO table pointers to the correct waveform tables

void LFO::pickTheLFOwaveform()
{
	switch (LFOshapeScaled(fShape))
	{
		case kSineLFO :
			table = sineTable;
			break;
		case kTriangleLFO :
			table = triangleTable;
			break;
		case kSquareLFO :
			table = squareTable;
			break;
		case kSawLFO :
			table = sawTable;
			break;
		case kReverseSawLFO :
			table = reverseSawTable;
			break;
		case kThornLFO :
			table = thornTable;
			break;
		default :
			table = sineTable;
			break;
	}
}

//--------------------------------------------------------------------------------------
// calculates the position within an LFO's cycle needed to sync to the song's beat

void LFO::syncToTheBeat(long samplesToBar)
{
  float countdown, cyclesize;

	// calculate how many samples long the LFO cycle is
	cyclesize = NUM_LFO_POINTS_FLOAT / stepSize;
	// calculate many more samples it will take for this cycle to coincide with the beat
	countdown = fmodf( (float)samplesToBar,  cyclesize);
	// & convert that into the correct LFO position according to its table step size
	position = (cyclesize - countdown) * stepSize;
	// wrap around the new position if it is beyond the end of the LFO table
	if (position >= NUM_LFO_POINTS_FLOAT)
		position = fmodf(position, NUM_LFO_POINTS_FLOAT);
}