-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathbufferOverrideProcess.cpp
More file actions
286 lines (257 loc) · 12.2 KB
/
Copy pathbufferOverrideProcess.cpp
File metadata and controls
286 lines (257 loc) · 12.2 KB
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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
/*------------------- by Marc Poirier ][ March 2001 -------------------*/
#ifndef __bufferOverride
#include "bufferOverride.hpp"
#endif
//-----------------------------------------------------------------------------
void BufferOverride::updateBuffer(long samplePos)
{
bool doSmoothing = true; // but in some situations, we shouldn't
bool barSync = false; // true if we need to sync up with the next bar start
float divisorLFOvalue, bufferLFOvalue; // the current output values of the LFOs
long prevForcedBufferSize; // the previous forced buffer size
// take care of MIDI
heedBufferOverrideEvents(samplePos);
readPos = 0; // reset for starting a new minibuffer
prevMinibufferSize = minibufferSize;
prevForcedBufferSize = currentForcedBufferSize;
//--------------------------PROCESS THE LFOs----------------------------
// update the LFOs' positions to the current position
divisorLFO->updatePosition(prevMinibufferSize);
bufferLFO->updatePosition(prevMinibufferSize);
// Then get the current output values of the LFOs, which also updates their positions once more.
// Scale the 0.0 - 1.0 LFO output values to 0.0 - 2.0 (oscillating around 1.0).
divisorLFOvalue = processLFOzero2two(divisorLFO);
bufferLFOvalue = 2.0f - processLFOzero2two(bufferLFO); // inverting it makes more pitch sense
// & then update the stepSize for each LFO, in case the LFO parameters have changed
if (onOffTest(divisorLFO->fTempoSync))
divisorLFO->stepSize = currentTempoBPS * (tempoRateTable->getScalar(divisorLFO->fRate)) * numLFOpointsDivSR;
else
divisorLFO->stepSize = LFOrateScaled(divisorLFO->fRate) * numLFOpointsDivSR;
if (onOffTest(bufferLFO->fTempoSync))
bufferLFO->stepSize = currentTempoBPS * (tempoRateTable->getScalar(bufferLFO->fRate)) * numLFOpointsDivSR;
else
bufferLFO->stepSize = LFOrateScaled(bufferLFO->fRate) * numLFOpointsDivSR;
//---------------------------CALCULATE FORCED BUFFER SIZE----------------------------
// check if it's the end of this forced buffer
if (writePos >= currentForcedBufferSize) {
writePos = 0; // start up a new forced buffer
// check on the previous forced & minibuffers; don't smooth if the last forced buffer wasn't divided
if (prevMinibufferSize >= currentForcedBufferSize)
doSmoothing = false;
else
doSmoothing = true;
// now update the the size of the current force buffer
if ( onOffTest(fBufferTempoSync) && // the user wants to do tempo sync / beat division rate
(currentTempoBPS > 0.0f) ) { // avoid division by zero
currentForcedBufferSize = (long) ( SAMPLERATE / (currentTempoBPS * tempoRateTable->getScalar(fBuffer)) );
// set this true so that we make sure to do the measure syncronisation later on
if (needResync)
barSync = true;
} else
currentForcedBufferSize = forcedBufferSizeSamples(fBuffer);
// apply the buffer LFO to the forced buffer size
currentForcedBufferSize = (long) ((float)currentForcedBufferSize * bufferLFOvalue);
// really low tempos & tempo rate values can cause huge forced buffer sizes,
// so prevent going outside of the allocated buffer space
if (currentForcedBufferSize > SUPER_MAX_BUFFER)
currentForcedBufferSize = SUPER_MAX_BUFFER;
if (currentForcedBufferSize < 2)
currentForcedBufferSize = 2;
// untrue this so that we don't do the measure sync calculations again unnecessarily
needResync = false;
}
//-----------------------CALCULATE THE DIVISOR-------------------------
currentBufferDivisor = bufferDivisorScaled(fDivisor);
// apply the divisor LFO to the divisor value if there's an "active" divisor (i.e. 2 or greater)
if (currentBufferDivisor >= 2.0f) {
currentBufferDivisor *= divisorLFOvalue;
// now it's possible that the LFO could make the divisor less than 2,
// which will essentially turn the effect off, so we stop the modulation at 2
if (currentBufferDivisor < 2.0f)
currentBufferDivisor = 2.0f;
}
//-----------------------CALCULATE THE MINIBUFFER SIZE-------------------------
// this is not a new forced buffer starting up
if (writePos > 0) {
// if it's allowed, update the minibuffer size midway through this forced buffer
if (onOffTest(fBufferInterrupt))
minibufferSize = (long) ( (float)currentForcedBufferSize / currentBufferDivisor );
// if it's the last minibuffer, then fill up the forced buffer to the end
// by extending this last minibuffer to fill up the end of the forced buffer
long remainingForcedBuffer = currentForcedBufferSize - writePos;
if ( (minibufferSize*2) >= remainingForcedBuffer )
minibufferSize = remainingForcedBuffer;
}
// this is a new forced buffer just beginning, act accordingly, do bar sync if necessary
else {
long samplesToBar;
if (barSync) {
samplesToBar = samplesToNextBar(timeInfo);
// do beat sync for each LFO if it ought to be done
if (onOffTest(divisorLFO->fTempoSync))
divisorLFO->syncToTheBeat(samplesToBar);
if (onOffTest(bufferLFO->fTempoSync))
bufferLFO->syncToTheBeat(samplesToBar);
}
// because there isn't really any division (given my implementation) when the divisor is < 2
if (currentBufferDivisor < 2.0f) {
if (barSync)
minibufferSize = currentForcedBufferSize = samplesToBar % currentForcedBufferSize;
else
minibufferSize = currentForcedBufferSize;
} else {
minibufferSize = (long) ( (float)currentForcedBufferSize / currentBufferDivisor );
if (barSync) {
// calculate how long this forced buffer needs to be
long countdown = samplesToBar % currentForcedBufferSize;
// update the forced buffer size & number of minibuffers so that
// the forced buffers sync up with the musical measures of the song
if ( countdown < (minibufferSize*2) ) // extend the buffer if it would be too short...
currentForcedBufferSize += countdown;
else // ...otherwise chop it down to the length of the extra bit needed to sync with the next measure
currentForcedBufferSize = countdown;
}
}
}
//-----------------------CALCULATE SMOOTHING DURATION-------------------------
// no smoothing if the previous forced buffer wasn't divided
if (!doSmoothing)
smoothcount = smoothDur = 0;
else {
smoothDur = (long) (fSmooth * (float)minibufferSize);
long maxSmoothDur;
// if we're just starting a new forced buffer,
// then the samples beyond the end of the previous one are not valid
if (writePos <= 0)
maxSmoothDur = prevForcedBufferSize - prevMinibufferSize;
// otherwise just make sure that we don't go outside of the allocated arrays
else
maxSmoothDur = SUPER_MAX_BUFFER - prevMinibufferSize;
if (smoothDur > maxSmoothDur)
smoothDur = maxSmoothDur;
smoothcount = smoothDur;
smoothStep = 1.0f / (float)(smoothDur+1); // the gain increment for each smoothing step
// sqrtFadeIn = sqrtf(smoothStep);
// sqrtFadeOut = sqrtf(1.0f - smoothStep);
// smoothFract = smoothStep;
fadeOutGain = cosf(PI/(float)(4*smoothDur));
fadeInGain = sinf(PI/(float)(4*smoothDur));
realFadePart = (fadeOutGain * fadeOutGain) - (fadeInGain * fadeInGain); // cosf(3.141592/2/n)
imaginaryFadePart = 2.0f * fadeOutGain * fadeInGain; // sinf(3.141592/2/n)
}
}
//---------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------
void BufferOverride::d_run(float **inputs, float **outputs, uint32_t sampleFrames)
{
//-------------------------SAFETY CHECK----------------------
// there must have not been available memory or something (like WaveLab goofing up),
// so try to allocate buffers now
if ( (buffer1 == NULL)
#ifdef BUFFEROVERRIDE_STEREO
|| (buffer2 == NULL)
#endif
)
createAudioBuffers();
// if the creation failed, then abort audio processing
if (buffer1 == NULL)
return;
#ifdef BUFFEROVERRIDE_STEREO
if (buffer2 == NULL)
return;
#endif
//-------------------------INITIALIZATIONS----------------------
// this is a handy value to have during LFO calculations & wasteful to recalculate at every sample
numLFOpointsDivSR = NUM_LFO_POINTS_FLOAT / SAMPLERATE;
divisorLFO->pickTheLFOwaveform();
bufferLFO->pickTheLFOwaveform();
// calculate this scaler value to minimize calculations later during processOutput()
// float inputGain = 1.0f - fDryWetMix;
// float outputGain = fDryWetMix;
float inputGain = sqrtf(1.0f - fDryWetMix);
float outputGain = sqrtf(fDryWetMix);
//-----------------------TEMPO STUFF---------------------------
// figure out the current tempo if we're doing tempo sync
if ( onOffTest(fBufferTempoSync) ||
(onOffTest(divisorLFO->fTempoSync) || onOffTest(bufferLFO->fTempoSync)) ) {
// calculate the tempo at the current processing buffer
if ( (fTempo > 0.0f) || (hostCanDoTempo != 1) ) { // get the tempo from the user parameter
currentTempoBPS = tempoScaled(fTempo) / 60.0f;
needResync = false; // we don't want it true if we're not syncing to host tempo
} else { // get the tempo from the host
timeInfo = getTimeInfo(kBeatSyncTimeInfoFlags);
if (timeInfo) {
if (kVstTempoValid & timeInfo->flags)
currentTempoBPS = (float)timeInfo->tempo / 60.0f;
else
currentTempoBPS = tempoScaled(fTempo) / 60.0f;
// currentTempoBPS = ((float)tempoAt(reportCurrentPosition())) / 600000.0f;
// but zero & negative tempos are bad, so get the user tempo value instead if that happens
if (currentTempoBPS <= 0.0f)
currentTempoBPS = tempoScaled(fTempo) / 60.0f;
//
// check if audio playback has just restarted & reset buffer stuff if it has (for measure sync)
if (timeInfo->flags & kVstTransportChanged) {
needResync = true;
currentForcedBufferSize = 1;
writePos = 1;
minibufferSize = 1;
prevMinibufferSize = 0;
smoothcount = smoothDur = 0;
}
} else { // do the same stuff as above if the timeInfo gets a null pointer
currentTempoBPS = tempoScaled(fTempo) / 60.0f;
needResync = false; // we don't want it true if we're not syncing to host tempo
}
}
}
//-----------------------AUDIO STUFF---------------------------
// here we begin the audio output loop, which has two checkpoints at the beginning
for (long samplecount = 0; (samplecount < sampleFrames); samplecount++) {
// check if it's the end of this minibuffer
if (readPos >= minibufferSize)
updateBuffer(samplecount);
// store the latest input samples into the buffers
buffer1[writePos] = inputs[0][samplecount];
#ifdef BUFFEROVERRIDE_STEREO
buffer2[writePos] = inputs[1][samplecount];
#endif
// get the current output without any smoothing
float out1 = buffer1[readPos];
#ifdef BUFFEROVERRIDE_STEREO
float out2 = buffer2[readPos];
#endif
// and if smoothing is taking place, get the smoothed audio output
if (smoothcount > 0) {
// crossfade between the current input & its corresponding overlap sample
// out1 *= 1.0f - (smoothStep * (float)smoothcount); // current
// out1 += buffer1[readPos+prevMinibufferSize] * smoothStep*(float)smoothcount; // + previous
// float smoothfract = smoothStep * (float)smoothcount;
// float newgain = sqrt(1.0f - smoothfract);
// float oldgain = sqrt(smoothfract);
// out1 = (out1 * newgain) + (buffer1[readPos+prevMinibufferSize] * oldgain);
// out1 = (out1 * sqrtFadeIn) + (buffer1[readPos+prevMinibufferSize] * sqrtFadeOut);
out1 = (out1 * fadeInGain) + (buffer1[readPos+prevMinibufferSize] * fadeOutGain);
#ifdef BUFFEROVERRIDE_STEREO
// out2 *= 1.0f - (smoothStep * (float)smoothcount); // current
// out2 += buffer2[readPos+prevMinibufferSize] * smoothStep*(float)smoothcount; // + previous
// out2 = (out2 * newgain) + (buffer2[readPos+prevMinibufferSize] * oldgain);
// out2 = (out2 * sqrtFadeIn) + (buffer2[readPos+prevMinibufferSize] * sqrtFadeOut);
out2 = (out2 * fadeInGain) + (buffer2[readPos+prevMinibufferSize] * fadeOutGain);
#endif
smoothcount--;
// smoothFract += smoothStep;
// sqrtFadeIn = 0.5f * (sqrtFadeIn + (smoothFract / sqrtFadeIn));
// sqrtFadeOut = 0.5f * (sqrtFadeOut + ((1.0f-smoothFract) / sqrtFadeOut));
fadeInGain = (fadeOutGain * imaginaryFadePart) + (fadeInGain * realFadePart);
fadeOutGain = (realFadePart * fadeOutGain) - (imaginaryFadePart * fadeInGain);
}
outputs[0][samplecount] += (out1 * outputGain) + (inputs[0][samplecount] * inputGain);
#ifdef BUFFEROVERRIDE_STEREO
outputs[1][samplecount] += (out2 * outputGain) + (inputs[1][samplecount] * inputGain);
#endif
// increment the position trackers
readPos++;
writePos++;
}
}