comparison examples/d-box/OscillatorBank.cpp @ 300:dbeed520b014 prerelease

Renamed projects to examples
author Giulio Moro <giuliomoro@yahoo.it>
date Fri, 27 May 2016 13:58:20 +0100
parents projects/d-box/OscillatorBank.cpp@8a575ba3ab52
children
comparison
equal deleted inserted replaced
297:a3d83ebdf49b 300:dbeed520b014
1 /*
2 * OscillatorBank.cpp
3 *
4 * Created on: May 23, 2014
5 * Author: Victor Zappi and Andrew McPherson
6 */
7
8
9 /*
10 * There is a problem with name consistency between this class and the Parser class in spear_parser files.
11 * There, a "frame" is each of the time values where partials are sampled, while a "hop" is the actual jump between frames [calculated in samples]
12 * Here, "hop" is used with the meaning of "frame", while "frame" became the local frame of a partial
13 *
14 * example
15 *
16 * frames: 0 1 2
17 * p0 p0_0 p0_1
18 * p1 p1_0 p1_1 p1_2
19 * p2 p2_0 p2_1
20 *
21 * In this case:
22 * in Parser there are 2 hops, 3 total frames and the 3 partials have respectively 2, 3 and 2 local frames
23 *
24 * here there are 3 total hops [the concept of jumps is discarded, cos not in use] and the 3 partials have respectively 2, 3 and 2 frames
25 *
26 * This must be fixed
27 */
28
29 // TODO: fix hop-frame name consistency
30
31
32 #include <stdlib.h>
33
34 #include "OscillatorBank.h"
35
36 OscillatorBank::OscillatorBank() {
37 loaded = false;
38 }
39
40 OscillatorBank::OscillatorBank(string filename, int hopsize, int samplerate) {
41 loaded = false;
42 loadFile(filename.c_str(), hopsize, samplerate);
43 }
44
45 OscillatorBank::OscillatorBank(char *filename, int hopsize, int samplerate) {
46 loaded = false;
47 loadFile(filename, hopsize, samplerate);
48 }
49
50 OscillatorBank::~OscillatorBank() {
51 free(oscillatorPhases);
52 free(oscillatorNextNormFreq);
53 free(oscillatorNextAmp);
54 free(oscillatorNormFrequencies);
55 free(oscillatorAmplitudes);
56 free(oscillatorNormFreqDerivatives);
57 free(oscillatorAmplitudeDerivatives);
58 free(phaseCopies);
59 free(nextNormFreqCopies);
60 free(nextAmpCopies);
61
62 delete[] oscStatNormFrequenciesMean;
63 delete[] oscStatNumHops;
64 delete[] lookupTable;
65 delete[] indicesMapping;
66 delete[] freqFixedDeltas;
67 delete[] ampFixedDeltas;
68 delete[] nyquistCut;
69 }
70
71 bool OscillatorBank::initBank(int oversamp) {
72 if (!loaded)
73 return false;
74
75 //---prepare look-up table
76 lookupTableSize = 1024;
77 lookupTable = new float[lookupTableSize + 1];
78 for (int n = 0; n < (lookupTableSize + 1); n++)
79 lookupTable[n] = sin(2.0 * M_PI * (float) n / (float) lookupTableSize);
80 frequencyScaler = (float) lookupTableSize / rate;
81 nyqNorm = rate / 2 * frequencyScaler;
82
83 if (oversamp < 1)
84 oversamp = 1;
85
86 //---prepare oscillators
87 partials = &(parser.partials); // pointer to paser's partials
88 partialsHopSize = parser.getHopSize();
89 lastHop = partials->getHopNum(); // last bank hop is equal to last partial frame, which is equal to partial hop num
90 overSampling = oversamp;
91 hopSize = partialsHopSize / overSampling; // if oversampling, osc bank hop num > partials hop num
92 hopSizeReminder = partialsHopSize % overSampling;
93 oscBankHopSize = hopSize;
94 numOfPartials = partials->getPartialNum();
95 numOfOscillators = partials->getMaxActivePartialNum(); // get the maximum number of active partials at the same time
96
97 // set to next multiple of 4 [NEON]
98 numOfOscillators = (numOfOscillators + 3) & ~0x3; // to be sure we can add up to 3 fake oscillators
99
100 int err;
101 //---allocate buffers
102 // alligned buffers [NEON]
103 err = posix_memalign((void**) &oscillatorPhases, 16,
104 numOfOscillators * sizeof(float));
105 err += posix_memalign((void**) &oscillatorNextNormFreq, 16,
106 numOfOscillators * sizeof(float));
107 err += posix_memalign((void**) &oscillatorNextAmp, 16,
108 numOfOscillators * sizeof(float));
109 err += posix_memalign((void**) &oscillatorNormFrequencies, 16,
110 numOfOscillators * sizeof(float));
111 err += posix_memalign((void**) &oscillatorAmplitudes, 16,
112 numOfOscillators * sizeof(float));
113 err += posix_memalign((void**) &oscillatorNormFreqDerivatives, 16,
114 numOfOscillators * sizeof(float));
115 err += posix_memalign((void**) &oscillatorAmplitudeDerivatives, 16,
116 numOfOscillators * sizeof(float));
117 err += posix_memalign((void**) &phaseCopies, 16,
118 numOfOscillators * sizeof(float));
119 err += posix_memalign((void**) &nextNormFreqCopies, 16,
120 numOfOscillators * sizeof(float));
121 err += posix_memalign((void**) &nextAmpCopies, 16,
122 numOfOscillators * sizeof(float));
123
124 // regular ones
125 oscStatNormFrequenciesMean = new float[numOfPartials];
126 oscStatNumHops = new float[numOfPartials];
127 indicesMapping = new int[numOfPartials];
128 freqFixedDeltas = new float[numOfPartials];
129 ampFixedDeltas = new float[numOfPartials];
130 nyquistCut = new bool[numOfPartials];
131
132 if (err > 0) {
133 dbox_printf("Failed memory allocations %@#!\n");
134 return false;
135 }
136
137 // copy stats [they do not change]
138 for (int n = 0; n < numOfPartials; n++) {
139 oscStatNormFrequenciesMean[n] = partials->partialFreqMean[n]
140 * frequencyScaler;
141 oscStatNumHops[n] = partials->partialNumFrames[n]; // in Parser and Partials "frames" are what we call here "hops" [see comment at top of file]
142 }
143
144 // deafult values
145 actPartNum = 0;
146 loopStartHop = 0;
147 loopEndHop = (parser.partials.getHopNum() - 2) * overSampling;
148 ampTh = 0.0001;
149 hopNumTh = 0;
150 pitchMultiplier = 1;
151 freqMovement = 1;
152 filterNum = 0;
153 note = false;
154 speed = 1;
155 nextSpeed = -1;
156 maxSpeed = 10;
157 minSpeed = 0.1;
158 jumpHop = -1;
159
160 // filter
161 filterMaxF = 22000;
162 filterAmpMinF = 10 * frequencyScaler;
163 filterAmpMaxF = 5000 * frequencyScaler;
164 filterAmpMul = 10.0;
165
166 // adsr
167 minAttackTime = .0001;
168 deltaAttackTime = 2.;
169 minReleaseTime = 1;
170 deltaReleaseTime = 2.5;
171
172 adsr.setAttackRate(minAttackTime * rate);
173 adsr.setDecayRate(.0001 * rate);
174 adsr.setSustainLevel(1);
175 adsr.setReleaseRate(minReleaseTime * rate);
176
177 state = bank_stopped;
178 return true;
179 }
180
181 void OscillatorBank::resetOscillators() {
182 currentHop = -1;
183 loopDir = 1;
184 loopDirShift = 0;
185 fill(nyquistCut, nyquistCut + numOfPartials, false);
186 prevAdsrVal = 0;
187 prevAmpTh = ampTh;
188 prevHopNumTh = hopNumTh;
189 prevPitchMultiplier = pitchMultiplier;
190 prevFreqMovement = freqMovement;
191 prevFilterNum = filterNum;
192 memcpy(prevFilterFreqs, filterFreqs, filterNum * sizeof(float));
193 memcpy(prevFilterQ, filterQ, filterNum * sizeof(float));
194
195 int activePNum = partials->activePartialNum[0];
196 unsigned int *activeP = partials->activePartials[0];
197 for (int i = 0; i < activePNum; i++) {
198 freqFixedDeltas[activeP[i]] = partials->partialFreqDelta[activeP[i]][0]
199 / overSampling;
200 ampFixedDeltas[activeP[i]] = partials->partialAmpDelta[activeP[i]][0]
201 / overSampling;
202 }
203 // attack!
204 adsr.gate(1);
205 note = true;
206
207 nextHop();
208
209 state = bank_playing;
210 }
211
212 void OscillatorBank::nextHop() {
213 hopSize = oscBankHopSize;
214
215 // copy phases, next freqs and next amps from previous frame
216 memcpy(phaseCopies, oscillatorPhases, actPartNum * sizeof(float));
217 memcpy(nextNormFreqCopies, oscillatorNextNormFreq,
218 actPartNum * sizeof(float));
219 memcpy(nextAmpCopies, oscillatorNextAmp, actPartNum * sizeof(float));
220
221 // next frame is forward or backwards, cos we could be in the loop
222 currentHop += loopDir;
223
224 checkDirection();
225
226 // if((currentHop/overSampling)%100 == 0)
227 // dbox_printf("currentHop %d, direction: %d\n", currentHop/overSampling, loopDir);
228
229 // if needs jump, end here this method, cos jumpToHop() will do tee rest
230 if (checkJump() == 0)
231 return;
232 // otherwise, if jump is not needed or fails, continue regular stuff
233
234 if (nextEnvState() != 0)
235 return; // release has ended!
236
237 checkSpeed();
238
239 // now let's decide how to calculate next hop
240 if (!checkOversampling())
241 nextOscBankHop();
242 else
243 nextPartialHop();
244 }
245
246 void OscillatorBank::nextOscBankHop() {
247 int parIndex, localHop;
248 float parDamp = 1;
249 int currentPartialHop = (currentHop / overSampling) + loopDirShift;
250
251 // if going backwards in the loop, get previous frame active partials...
252 actPartNum = partials->activePartialNum[currentPartialHop - loopDirShift];
253 actPart = partials->activePartials[currentPartialHop - loopDirShift];
254 //cout << "actPartNum: " << actPartNum << endl;
255
256 envState = adsr.getState(); // to determine what state we will be in next hop [attack, decay, sustain, release]
257
258 int parCnt = 0;
259 int currentHopReminder = currentHop % overSampling;
260 // steps to reach next bank hop from previous partial hop
261 int steps = currentHopReminder + 1;
262 if (loopDir < 0)
263 steps = overSampling - currentHopReminder + 1;
264
265 for (int i = 0; i < actPartNum; i++) {
266 // find partial and frame
267 parIndex = actPart[i];
268 //localHop = partials->localPartialFrames[currentPartialHop][parIndex];
269 localHop = currentPartialHop - partials->partialStartFrame[parIndex]; // in Parser and Partials "frames" are what we call here "hops". These particular ones are local frames [see comment at top of file]
270
271 //float delta = partials->partialFrequencies[parIndex][localHop+loopDir] - partials->partialFrequencies[parIndex][localHop];
272
273 // if this partial was over nyquist on previous hop...
274 if (nyquistCut[parIndex]) {
275 // ...restart from safe values
276 oscillatorPhases[parCnt] = 0;
277 //TODO add freqmove dependency
278 oscillatorNextNormFreq[parCnt] =
279 (partials->partialFrequencies[parIndex][localHop]
280 + freqFixedDeltas[parIndex] * (steps - 1))
281 * frequencyScaler * prevPitchMultiplier;
282 oscillatorNextAmp[parCnt] = 0;
283 } else if (loopDir == 1) // otherwise recover phase, target freq and target amp from previous frame
284 {
285 if ((localHop != 0) || (currentHopReminder != 0)) {
286 oscillatorPhases[parCnt] =
287 phaseCopies[indicesMapping[parIndex]];
288 oscillatorNextNormFreq[parCnt] =
289 nextNormFreqCopies[indicesMapping[parIndex]];
290 oscillatorNextAmp[parCnt] =
291 nextAmpCopies[indicesMapping[parIndex]];
292 } else // first oscillator hop [both for bank and partial], so no previous data are available
293 {
294 oscillatorPhases[parCnt] = 0;
295 //TODO add freqmove dependency
296 oscillatorNextNormFreq[parCnt] =
297 partials->partialFrequencies[parIndex][localHop]
298 * frequencyScaler * prevPitchMultiplier;
299 parDamp = calculateParDamping(parIndex, prevHopNumTh,
300 prevAdsrVal, oscillatorNextNormFreq[parCnt],
301 prevFilterNum, prevFilterFreqs, prevFilterQ);
302 oscillatorNextAmp[parCnt] =
303 partials->partialAmplitudes[parIndex][localHop]
304 * parDamp;
305 if(oscillatorNextAmp[parCnt] > 1)
306 oscillatorNextAmp[parCnt] = 1;
307 freqFixedDeltas[parIndex] =
308 partials->partialFreqDelta[parIndex][localHop + loopDir]
309 * loopDir / overSampling;
310 ampFixedDeltas[parIndex] =
311 partials->partialAmpDelta[parIndex][localHop + loopDir]
312 * loopDir / overSampling;
313 }
314 } else {
315 oscillatorPhases[parCnt] = phaseCopies[indicesMapping[parIndex]];
316 oscillatorNextNormFreq[parCnt] =
317 nextNormFreqCopies[indicesMapping[parIndex]];
318 oscillatorNextAmp[parCnt] = nextAmpCopies[indicesMapping[parIndex]];
319 }
320
321 // remove aliasing, skipping partial over nyquist freq
322 if (oscillatorNextNormFreq[parCnt] > nyqNorm) {
323 nyquistCut[parIndex] = true;
324 continue;
325 }
326 nyquistCut[parIndex] = false;
327
328 // first set up freq, cos filter affects amplitude damping according to freq content
329 oscillatorNormFrequencies[parCnt] = oscillatorNextNormFreq[parCnt]; // to fix any possible drifts
330 // save next values, current for next round
331 oscillatorNextNormFreq[parCnt] = (freqMovement
332 * (partials->partialFrequencies[parIndex][localHop]
333 + freqFixedDeltas[parIndex] * steps) * frequencyScaler
334 + (1 - freqMovement) * oscStatNormFrequenciesMean[parIndex])
335 * pitchMultiplier;
336 // derivatives are (next hop value*next damping) - (current hop value*current damping) ---> next hop must be available, in both directions, because of control on active partials
337 oscillatorNormFreqDerivatives[parCnt] = (oscillatorNextNormFreq[parCnt]
338 - oscillatorNormFrequencies[parCnt]) / hopCounter;
339 // this second weird passage handles dissonance control, morphing between regular and mean frequencies
340 oscillatorNormFreqDerivatives[parCnt] = freqMovement
341 * oscillatorNormFreqDerivatives[parCnt]
342 + (1 - freqMovement)
343 * ((oscStatNormFrequenciesMean[parIndex]
344 * pitchMultiplier)
345 - oscillatorNormFrequencies[parCnt])
346 / hopCounter;
347
348 parDamp = calculateParDamping(parIndex, hopNumTh, adsrVal,
349 oscillatorNextNormFreq[parCnt], filterNum, filterFreqs, filterQ);
350
351 // now amplitudes
352 oscillatorAmplitudes[parCnt] = oscillatorNextAmp[parCnt]; // to fix any possible drifts
353 // save next values, current for next round
354 //delta = partials->partialAmplitudes[parIndex][localHop+loopDir] - partials->partialAmplitudes[parIndex][localHop];
355 oscillatorNextAmp[parCnt] =
356 (partials->partialAmplitudes[parIndex][localHop]
357 + ampFixedDeltas[parIndex] * steps) * parDamp;
358 if(oscillatorNextAmp[parCnt] > 1)
359 oscillatorNextAmp[parCnt] = 1;
360 if ((loopDir == -1) && (localHop = 1) && (currentHopReminder == 1))
361 oscillatorNextAmp[parCnt] = 0;
362 // derivatives are (next hop value*next damping) - (current hop value*current damping) ---> next hop must be available, in both directions, because of control on active partials
363 oscillatorAmplitudeDerivatives[parCnt] = (oscillatorNextAmp[parCnt]
364 - oscillatorAmplitudes[parCnt]) / hopCounter;
365
366 // finally update current mapping between oscillators and partials
367 indicesMapping[parIndex] = parCnt;
368 parCnt++;
369 }
370 actPartNum = parCnt;
371 // [NEON] if not multiple of 4...
372 if (actPartNum % 4 != 0)
373 addFakeOsc();
374 }
375
376 void OscillatorBank::nextPartialHop() {
377 unsigned int parIndex, localHop;
378 float parDamp = 1;
379 int currentPartialHop = currentHop / overSampling;
380
381 // if going backwards in the loop, get previous frame active partials...
382 actPartNum = partials->activePartialNum[currentPartialHop - loopDirShift];
383 actPart = partials->activePartials[currentPartialHop - loopDirShift];
384
385 envState = adsr.getState(); // to determine what state we will be in next hop [attack, decay, sustain, release]
386
387 int parCnt = 0;
388 int steps = overSampling - 1; // steps to reach next hop [partial or bank] from previous partial hop
389
390 for (int i = 0; i < actPartNum; i++) {
391 // find partial and frame
392 parIndex = actPart[i];
393 //localHop = partials->localPartialFrames[currentPartialHop][parIndex];
394 localHop = currentPartialHop - partials->partialStartFrame[parIndex]; // in Parser and Partials "frames" are what we call here "hops". These particular ones are local frames [see comment at top of file]
395
396 // if this partial was over nyquist on previous hop...
397 if (nyquistCut[parIndex]) {
398 // ...restart from safe values
399 oscillatorPhases[parCnt] = 0;
400 //TODO add freqmove dependency
401 oscillatorNextNormFreq[parCnt] =
402 (partials->partialFrequencies[parIndex][localHop]
403 + freqFixedDeltas[parIndex] * steps
404 * (1 - loopDirShift)) * frequencyScaler
405 * prevPitchMultiplier;
406 oscillatorNextAmp[parCnt] = 0;
407 } else if (loopDir == 1) // otherwise recover phase, target freq and target amp from previous frame
408 {
409 if ((localHop != 0) || (overSampling > 1)) {
410 oscillatorPhases[parCnt] =
411 phaseCopies[indicesMapping[parIndex]];
412 oscillatorNextNormFreq[parCnt] =
413 nextNormFreqCopies[indicesMapping[parIndex]];
414 oscillatorNextAmp[parCnt] =
415 nextAmpCopies[indicesMapping[parIndex]];
416 } else // first oscillator hop [both for bank and partial], so no previous data are available
417 {
418 oscillatorPhases[parCnt] = 0;
419 //TODO add freqmove dependency
420 oscillatorNextNormFreq[parCnt] =
421 partials->partialFrequencies[parIndex][localHop]
422 * frequencyScaler * prevPitchMultiplier;
423 parDamp = calculateParDamping(parIndex, prevHopNumTh,
424 prevAdsrVal, oscillatorNextNormFreq[parCnt],
425 prevFilterNum, prevFilterFreqs, prevFilterQ);
426 oscillatorNextAmp[parCnt] =
427 partials->partialAmplitudes[parIndex][localHop]
428 * parDamp;
429 if(oscillatorNextAmp[parCnt] > 1)
430 oscillatorNextAmp[parCnt] = 1;
431 freqFixedDeltas[parIndex] =
432 partials->partialFreqDelta[parIndex][localHop + loopDir]
433 * loopDir / overSampling;
434 ampFixedDeltas[parIndex] =
435 partials->partialAmpDelta[parIndex][localHop + loopDir]
436 * loopDir / overSampling;
437 }
438 } else {
439 if (localHop != partials->partialNumFrames[parIndex] - 1) {
440 oscillatorPhases[parCnt] =
441 phaseCopies[indicesMapping[parIndex]];
442 oscillatorNextNormFreq[parCnt] =
443 nextNormFreqCopies[indicesMapping[parIndex]];
444 oscillatorNextAmp[parCnt] =
445 nextAmpCopies[indicesMapping[parIndex]];
446 } else // first oscillator hop [going backwards - both for bank and partial] , so no previous data are available
447 {
448 oscillatorPhases[parCnt] = 0;
449 //TODO add freqmove dependency
450 oscillatorNextNormFreq[parCnt] =
451 partials->partialFrequencies[parIndex][localHop]
452 * frequencyScaler * prevPitchMultiplier;
453 parDamp = calculateParDamping(parIndex, prevHopNumTh,
454 prevAdsrVal, oscillatorNextNormFreq[parCnt],
455 prevFilterNum, prevFilterFreqs, prevFilterQ);
456 oscillatorNextAmp[parCnt] =
457 partials->partialAmplitudes[parIndex][localHop]
458 * parDamp;
459 if(oscillatorNextAmp[parCnt] > 1)
460 oscillatorNextAmp[parCnt] = 1;
461 freqFixedDeltas[parIndex] =
462 partials->partialFreqDelta[parIndex][localHop + loopDir]
463 * loopDir / overSampling;
464 ampFixedDeltas[parIndex] =
465 partials->partialAmpDelta[parIndex][localHop + loopDir]
466 * loopDir / overSampling;
467 }
468 }
469 // remove aliasing, skipping partial over nyquist freq
470 if (oscillatorNextNormFreq[parCnt] > nyqNorm) {
471 //cout << nyqNorm << endl;
472 nyquistCut[parIndex] = true;
473 continue;
474 }
475 nyquistCut[parIndex] = false;
476
477 // first set up freq, cos filter affects amplitude damping according to freq content
478 oscillatorNormFrequencies[parCnt] = oscillatorNextNormFreq[parCnt]; // to fix any possible drifts
479 // save next values, current for next round
480 oscillatorNextNormFreq[parCnt] = (freqMovement
481 * (partials->partialFrequencies[parIndex][localHop + loopDir]
482 - freqFixedDeltas[parIndex] * steps * loopDirShift)
483 * frequencyScaler
484 + (1 - freqMovement) * oscStatNormFrequenciesMean[parIndex])
485 * pitchMultiplier;
486 // derivatives are (next hop value*next damping) - (current hop value*current damping) ---> next hop must be available, in both directions, because of control on active partials
487 oscillatorNormFreqDerivatives[parCnt] = (oscillatorNextNormFreq[parCnt]
488 - oscillatorNormFrequencies[parCnt]) / hopCounter;
489 // this second weird passage handles dissonance control, morphing between regular and mean frequencies
490 oscillatorNormFreqDerivatives[parCnt] = freqMovement
491 * oscillatorNormFreqDerivatives[parCnt]
492 + (1 - freqMovement)
493 * ((oscStatNormFrequenciesMean[parIndex]
494 * pitchMultiplier)
495 - oscillatorNormFrequencies[parCnt])
496 / hopCounter;
497
498 parDamp = calculateParDamping(parIndex, hopNumTh, adsrVal,
499 oscillatorNextNormFreq[parCnt], filterNum, filterFreqs, filterQ);
500
501 // now amplitudes
502 oscillatorAmplitudes[parCnt] = oscillatorNextAmp[parCnt]; // to fix any possible drifts
503 // save next values, current for next round
504 //delta = partials->partialAmplitudes[parIndex][localHop+loopDir] - partials->partialAmplitudes[parIndex][localHop];
505 oscillatorNextAmp[parCnt] =
506 (partials->partialAmplitudes[parIndex][localHop + loopDir]
507 - (ampFixedDeltas[parIndex]) * steps * loopDirShift)
508 * parDamp;
509 if(oscillatorNextAmp[parCnt] > 1)
510 oscillatorNextAmp[parCnt] = 1;
511
512 // to avoid bursts when transients are played backwards
513 if ((loopDir == -1) && (localHop - 1 == 0) && (overSampling == 1)) {
514 oscillatorNextAmp[parCnt] = 0;
515 }
516 // derivatives are (next hop value*next damping) - (current hop value*current damping) ---> next hop must be available, in both directions, because of control on active partials
517 oscillatorAmplitudeDerivatives[parCnt] = (oscillatorNextAmp[parCnt]
518 - oscillatorAmplitudes[parCnt]) / hopCounter;
519
520 // if next is not going to loop boundaries, get next deltas [same direction]
521 if ((((currentPartialHop + loopDir) * overSampling != loopEndHop)
522 || (loopDir == -1))
523 && (((currentPartialHop + loopDir) * overSampling + loopDir
524 != loopStartHop) || (loopDir == 1))) {
525 freqFixedDeltas[parIndex] =
526 partials->partialFreqDelta[parIndex][localHop + loopDir]
527 * loopDir / overSampling;
528 ampFixedDeltas[parIndex] =
529 partials->partialAmpDelta[parIndex][localHop + loopDir]
530 * loopDir / overSampling;
531 } else // .. otherwise, keep deltas but change sign [co swe change direction]
532 {
533 freqFixedDeltas[parIndex] = -freqFixedDeltas[parIndex];
534 ampFixedDeltas[parIndex] = -ampFixedDeltas[parIndex];
535 }
536
537 // finally update current mapping between oscillators and partials
538 indicesMapping[parIndex] = parCnt;
539 parCnt++;
540 }
541 actPartNum = parCnt;
542 // [NEON] if not multiple of 4...
543 if (actPartNum % 4 != 0)
544 addFakeOsc();
545
546 updatePrevControls();
547 }
548
549 void OscillatorBank::addFakeOsc() {
550 // ...calculate difference
551 int newPartNum = (actPartNum + 3) & ~0x3;
552 // ...add fake oscillators until total num is multiple of 4
553 for (int i = actPartNum; i < newPartNum; i++) {
554 oscillatorAmplitudes[i] = 0;
555 oscillatorNormFrequencies[i] = 0;
556 oscillatorAmplitudeDerivatives[i] = 0;
557 oscillatorNormFreqDerivatives[i] = 0;
558 oscillatorPhases[i] = 0;
559 }
560 // ...and update num of active partials
561 actPartNum = newPartNum;
562 }
563
564 void OscillatorBank::play(float vel) {
565 // set attack and release params according to velocity
566 //adsr.setAttackRate((minAttackTime + ((1 - vel) * deltaAttackTime)) * rate);
567 adsr.setAttackRate(minAttackTime * rate);
568 //adsr.setReleaseRate((minReleaseTime + (1 - vel) * deltaReleaseTime) * rate);
569 adsr.setReleaseRate(minReleaseTime * rate);
570
571 // set timbre
572 hopNumTh = log((1 - vel) + 1) / log(2) * 20000;
573
574 state = bank_toreset;
575 }
576
577 //---------------------------------------------------------------------------------------------------------------------------
578 // private methods
579 //---------------------------------------------------------------------------------------------------------------------------
580
581 bool OscillatorBank::loader(char *filename, int hopsize, int samplerate) {
582 rate = samplerate;
583 loaded = parser.parseFile(filename, hopsize, samplerate);
584 return loaded;
585 }
586
587 int OscillatorBank::jumpToHop() {
588 int jumpGap = abs(jumpHop - currentHop / overSampling); // gaps in partial reference
589
590 // can't jump to self dude
591 if (jumpGap == 0)
592 return 1;
593
594 // direction is in general maintained with jump
595 if (jumpHop == 0)
596 setDirection(1);
597 else if (jumpHop == lastHop)
598 setDirection(-1);
599
600 dbox_printf("\tJump from %d to %d\n", currentHop / overSampling, jumpHop);
601 dbox_printf("\tdirection %d\n", loopDir);
602
603 currentHop = jumpHop * overSampling;
604
605 if (nextEnvState() != 0)
606 return 0; // release has ended!
607
608 checkSpeed();
609
610 int parIndex, localHop, targetHop;
611 float parDamp = 1;
612 int currentPartialHop = currentHop / overSampling;
613 int targetPartialHop = jumpHop;
614
615 actPartNum = partials->activePartialNum[currentPartialHop];
616 actPart = partials->activePartials[currentPartialHop];
617 int targetActParNum = partials->activePartialNum[targetPartialHop];
618 unsigned int *targetActPar = partials->activePartials[targetPartialHop];
619
620 envState = adsr.getState(); // to determine what state we will be in next hop [attack, decay, sustain, release]
621
622 int parCnt = 0;
623 int currentHopReminder = currentHop % overSampling;
624
625 // steps to walk where i am [bank of partial hop] from previous partial hop
626 int steps = currentHopReminder * (overSampling != 1); // no oversampling 0, oversampling and going ff currentHopReminder
627
628 for (int i = 0; i < actPartNum; i++) {
629 // find partial and frame
630 parIndex = actPart[i];
631 //localHop = partials->localPartialFrames[currentPartialHop][parIndex];
632 localHop = currentPartialHop - partials->partialStartFrame[parIndex]; // in Parser and Partials "frames" are what we call here "hops". These particular ones are local frames [see comment at top of file]
633
634 // if this partial was over nyquist on previous hop...
635 if (nyquistCut[parIndex]) {
636 // ...restart from safe values
637 oscillatorPhases[parCnt] = 0;
638 //TODO add freqmove dependency
639 oscillatorNextNormFreq[parCnt] =
640 (partials->partialFrequencies[parIndex][localHop]
641 + freqFixedDeltas[parIndex] * steps * loopDir)
642 * frequencyScaler * prevPitchMultiplier;
643 oscillatorNextAmp[parCnt] = 0;
644 } else if (loopDir == 1) {// otherwise recover phase, target freq and target amp from previous frame
645 if ((localHop != 0)
646 || ((overSampling > 1) && (currentHopReminder != 0))) {
647 oscillatorPhases[parCnt] =
648 phaseCopies[indicesMapping[parIndex]];
649 oscillatorNextNormFreq[parCnt] =
650 nextNormFreqCopies[indicesMapping[parIndex]];
651 oscillatorNextAmp[parCnt] =
652 nextAmpCopies[indicesMapping[parIndex]];
653 } else { // first oscillator hop [both for bank and partial], so no previous data are available
654 oscillatorPhases[parCnt] = 0;
655 //TODO add freqmove dependency
656 oscillatorNextNormFreq[parCnt] =
657 partials->partialFrequencies[parIndex][localHop]
658 * frequencyScaler * prevPitchMultiplier;
659 parDamp = calculateParDamping(parIndex, prevHopNumTh,
660 prevAdsrVal, oscillatorNextNormFreq[parCnt],
661 prevFilterNum, prevFilterFreqs, prevFilterQ);
662 oscillatorNextAmp[parCnt] =
663 partials->partialAmplitudes[parIndex][localHop]
664 * parDamp;
665 if(oscillatorNextAmp[parCnt] > 1)
666 oscillatorNextAmp[parCnt] = 1;
667 }
668 } else {
669 if (( (unsigned)localHop != partials->partialNumFrames[parIndex] - 1)
670 || ((overSampling > 1) && (currentHopReminder != 0))) {
671 oscillatorPhases[parCnt] =
672 phaseCopies[indicesMapping[parIndex]];
673 oscillatorNextNormFreq[parCnt] =
674 nextNormFreqCopies[indicesMapping[parIndex]];
675 oscillatorNextAmp[parCnt] =
676 nextAmpCopies[indicesMapping[parIndex]];
677 } else // first oscillator hop [going backwards - both for bank and partial] , so no previous data are available, so retrieve where i am
678 {
679 oscillatorPhases[parCnt] = 0;
680 //TODO add freqmove dependency
681 oscillatorNextNormFreq[parCnt] =
682 partials->partialFrequencies[parIndex][localHop]
683 * frequencyScaler * prevPitchMultiplier;
684 parDamp = calculateParDamping(parIndex, prevHopNumTh,
685 prevAdsrVal, oscillatorNextNormFreq[parCnt],
686 prevFilterNum, prevFilterFreqs, prevFilterQ);
687 oscillatorNextAmp[parCnt] =
688 partials->partialAmplitudes[parIndex][localHop]
689 * parDamp;
690 if(oscillatorNextAmp[parCnt] > 1)
691 oscillatorNextAmp[parCnt] = 1;
692 }
693 }
694 // remove aliasing, skipping partial over nyquist freq
695 if (oscillatorNextNormFreq[parCnt] > nyqNorm) {
696 //cout << nyqNorm << endl;
697 nyquistCut[parIndex] = true;
698 continue;
699 }
700 nyquistCut[parIndex] = false;
701
702 // check what happens of this partial at target hop
703 float targetFreqVal, targetAmpVal;
704 //targetHop = partials->localPartialFrames[targetPartialHop][parIndex];
705 targetHop = targetPartialHop - partials->partialStartFrame[parIndex];
706
707 if (targetHop == -1)
708 targetFreqVal = targetAmpVal = 0;
709 else {
710 targetFreqVal = partials->partialFrequencies[parIndex][targetHop]
711 * frequencyScaler; // pitch shift will be multiplied later!!!
712 targetAmpVal = partials->partialFrequencies[parIndex][targetHop]; // parDamp will be multiplied later!!!
713 }
714
715 // first set up freq, cos filter affects amplitude damping according to freq content
716 oscillatorNormFrequencies[parCnt] = oscillatorNextNormFreq[parCnt]; // to fix any possible drifts
717 // save next values, current for next round
718 oscillatorNextNormFreq[parCnt] = (freqMovement * targetFreqVal
719 + (1 - freqMovement) * oscStatNormFrequenciesMean[parIndex])
720 * pitchMultiplier;
721 // derivatives are (next hop value*next damping) - (current hop value*current damping) ---> next hop must be available, in both directions, because of control on active partials
722 oscillatorNormFreqDerivatives[parCnt] = (oscillatorNextNormFreq[parCnt]
723 - oscillatorNormFrequencies[parCnt]) / hopCounter;
724 // this second weird passage handles dissonance control, morphing between regular and mean frequencies
725 oscillatorNormFreqDerivatives[parCnt] = freqMovement
726 * oscillatorNormFreqDerivatives[parCnt]
727 + (1 - freqMovement)
728 * ((oscStatNormFrequenciesMean[parIndex]
729 * pitchMultiplier)
730 - oscillatorNormFrequencies[parCnt])
731 / hopCounter;
732
733 parDamp = calculateParDamping(parIndex, hopNumTh, adsrVal,
734 oscillatorNextNormFreq[parCnt], filterNum, filterFreqs, filterQ);
735
736 // now amplitudes
737 oscillatorAmplitudes[parCnt] = oscillatorNextAmp[parCnt]; // to fix any possible drifts
738 // save next values, current for next round
739 oscillatorNextAmp[parCnt] = targetAmpVal * parDamp;
740 if(oscillatorNextAmp[parCnt] > 1)
741 oscillatorNextAmp[parCnt] = 1;
742 // to avoid bursts when transients are played backwards
743 if ((loopDir == -1) && (targetHop == 0)
744 && ((overSampling == 1) || (currentHopReminder == 0))) {
745 oscillatorNextAmp[parCnt] = 0;
746 }
747 // derivatives are (next hop value*next damping) - (current hop value*current damping) ---> next hop must be available, in both directions, because of control on active partials
748 oscillatorAmplitudeDerivatives[parCnt] = (oscillatorNextAmp[parCnt]
749 - oscillatorAmplitudes[parCnt]) / hopCounter;
750
751 //if partial does not die at target, calculate deltas according to direction
752 if (targetHop != -1) {
753 freqFixedDeltas[parIndex] =
754 partials->partialFreqDelta[parIndex][targetHop] * loopDir
755 / overSampling;
756 ampFixedDeltas[parIndex] =
757 partials->partialAmpDelta[parIndex][targetHop] * loopDir
758 / overSampling;
759 }
760
761 // finally update current mapping between oscillators and partials
762 indicesMapping[parIndex] = parCnt;
763 parCnt++;
764 }
765 actPartNum = parCnt;
766
767 // now add the ones that start at target hop!
768 for (int i = 0; i < targetActParNum; i++) {
769 // find partial and frame
770 parIndex = targetActPar[i];
771 //targetHop = partials->localPartialFrames[targetPartialHop][parIndex];
772 targetHop = targetPartialHop - partials->partialStartFrame[parIndex]; // in Parser and Partials "frames" are what we call here "hops". These particular ones are local frames [see comment at top of file]
773
774 // check if this partials was already active before the jump
775 //localHop = partials->localPartialFrames[currentPartialHop][parIndex];
776 localHop = currentPartialHop - partials->partialStartFrame[parIndex];
777
778 // if yes, skip it
779 if (localHop != -1)
780 continue;
781
782 // otherwise add it to active bunch and calcucalte values
783
784 // first set up freq, cos filter affects amplitude damping according to freq content
785 oscillatorNormFrequencies[parCnt] = 0;
786 // save next values, current for next round
787 oscillatorNextNormFreq[parCnt] = (freqMovement
788 * partials->partialFrequencies[parIndex][targetHop]
789 * frequencyScaler
790 + (1 - freqMovement) * oscStatNormFrequenciesMean[parIndex])
791 * pitchMultiplier;
792 // derivatives are (next hop value*next damping) - (current hop value*current damping) ---> next hop must be available, in both directions, because of control on active partials
793 oscillatorNormFreqDerivatives[parCnt] = (oscillatorNextNormFreq[parCnt]
794 - oscillatorNormFrequencies[parCnt]) / hopCounter;
795 // this second weird passage handles dissonance control, morphing between regular and mean frequencies
796 oscillatorNormFreqDerivatives[parCnt] = freqMovement
797 * oscillatorNormFreqDerivatives[parCnt]
798 + (1 - freqMovement)
799 * ((oscStatNormFrequenciesMean[parIndex]
800 * pitchMultiplier)
801 - oscillatorNormFrequencies[parCnt])
802 / hopCounter;
803
804 parDamp = calculateParDamping(parIndex, hopNumTh, adsrVal,
805 oscillatorNextNormFreq[parCnt], filterNum, filterFreqs, filterQ);
806
807 // now amplitudes
808 oscillatorAmplitudes[parCnt] = 0;
809 // save next values, current for next round
810 oscillatorNextAmp[parCnt] =
811 partials->partialFrequencies[parIndex][targetHop] * parDamp;
812 if(oscillatorNextAmp[parCnt] > 1)
813 oscillatorNextAmp[parCnt] = 1;
814 // derivatives are (next hop value*next damping) - (current hop value*current damping) ---> next hop must be available, in both directions, because of control on active partials
815 oscillatorAmplitudeDerivatives[parCnt] = (oscillatorNextAmp[parCnt]
816 - oscillatorAmplitudes[parCnt]) / hopCounter;
817
818 //calculate deltas according to direction
819 freqFixedDeltas[parIndex] =
820 partials->partialFreqDelta[parIndex][targetHop] * loopDir
821 / overSampling;
822 ampFixedDeltas[parIndex] =
823 partials->partialAmpDelta[parIndex][targetHop] * loopDir
824 / overSampling;
825
826 // finally update current mapping between oscillators and partials
827 indicesMapping[parIndex] = parCnt;
828 parCnt++;
829
830 }
831 // [NEON] if not multiple of 4...
832 if (actPartNum % 4 != 0)
833 addFakeOsc();
834
835 updatePrevControls();
836
837 jumpHop = -1;
838
839 return 0;
840 }
841
842 int OscillatorBank::nextEnvState() {
843 /*
844 envState = Attack.getState(); // to determine what state we are in [attack, decay, sustain, release]
845
846 // osc bank is playing the tail and the tail ends...
847 if( (state == bank_playing)&&(envState == env_idle) )
848 {
849 state = bank_stopped; // ...stop bank
850 return 1; // and return immediately
851 }
852 else if( (envState == env_attack) || (envState == env_decay) )
853 {
854 // run envelopes until next frame
855 dampWeight = Attack.process(hopSize);
856 }
857 else if(envState == env_release)
858 {
859 // run envelopes until next frame
860 dampWeight = Attack.process(hopSize);
861 releaseDamp = Release.process(hopSize);
862 }*/
863
864 envState = adsr.getState();
865 // osc bank is playing the tail and the tail ends...
866 if ((state == bank_playing) && (envState == env_idle)) {
867 state = bank_stopped; // ...stop bank
868 adsrVal = 0;
869 return 1; // and return immediately
870 } else
871 adsrVal = adsr.process(hopSize);
872
873 return 0;
874 }
875
876 void OscillatorBank::checkDirection() {
877 // end of the loop or end of file
878 if (((currentHop >= loopEndHop) && (loopDir == 1))
879 || ((currentHop >= lastHop) && (loopDir == 1))) {
880 // move backwards
881 setDirection(-1);
882 //dbox_printf("backward from %d\n", loopEndHop);
883 } else if (((currentHop <= loopStartHop) && (loopDir == -1))
884 || ((currentHop <= 0) && (loopDir == -1))) // start of the loop or start of file
885 {
886 // move forward
887 setDirection(1);
888 //dbox_printf("forward from %d\n", loopStartHop);
889 }
890 }
891
892 void OscillatorBank::checkSpeed() {
893 // speed control [alike on highways, LOL]
894 if (nextSpeed > 0) {
895 nextSpeed = (nextSpeed < maxSpeed) ? nextSpeed : maxSpeed;
896 nextSpeed = (nextSpeed > minSpeed) ? nextSpeed : minSpeed;
897 speed = nextSpeed;
898 nextSpeed = -1;
899 }
900 hopCounter = hopSize / speed;
901 }
902
903 int OscillatorBank::checkJump() {
904 //check if has to jump somewhere
905 if (jumpHop > -1) {
906 // needs to jump!
907 if (jumpToHop() == 0)
908 return 0;
909 }
910 return 1; // no jump
911 }
912
913 bool OscillatorBank::checkOversampling() {
914 //TODO fix this, but need andrew to fix oversampling multiple of period size
915 // if partialsHopSize is not a multiple of oversampling, change hop size to periodically match next partial hop
916 if (hopSizeReminder > 0) {
917 // if next osc bank hop overtakes next partial hop...
918 if ((currentHop + loopDir) * hopSize > partialsHopSize) {
919 hopSize = hopSizeReminder; // ...shrink osc bank hop size to match partial hop
920 return true; // and set next hop as matching with next partial hop
921 }
922 } else if (((currentHop + (1 - loopDirShift)) % overSampling) == 0) // if next osc bank hop matches next partial hop
923 return true; // ...mark next hop as partial hop
924
925 return false; // ,otherwise mark next hop as osc bank hop
926 }
927
928 void OscillatorBank::updatePrevControls() {
929 prevAdsrVal = adsrVal;
930 prevAmpTh = ampTh;
931 prevHopNumTh = hopNumTh;
932 prevPitchMultiplier = pitchMultiplier;
933 prevFreqMovement = freqMovement;
934 prevFilterNum = filterNum;
935 memcpy(prevFilterFreqs, filterFreqs, filterNum * sizeof(float));
936 memcpy(prevFilterQ, filterQ, filterNum * sizeof(float));
937 }
938
939 float OscillatorBank::calculateParDamping(int parIndex, int hopNTh,
940 float adsrVl, float nextFreq, int filNum, float *filFreq, float *filQ) {
941 float parDamp = 1;
942
943 // timbre
944 parDamp = ((float) (oscStatNumHops[parIndex] + 1)) / (hopNTh + 1);
945 parDamp = (parDamp > 1) ? 1 : parDamp;
946 parDamp = adsrVl * parDamp;
947
948 //filters
949
950 float filterWeights[MAX_TOUCHES];
951 float filterDamp[MAX_TOUCHES];
952 float filDist;
953 float filterWeightsAcc;
954 float filDmp;
955 float filAmp;
956
957 // band reject notch filter
958 // float dist, dmp;
959 // for(int k=0; k<filterNum; k++)
960 // {
961 // dist = fabs(oscillatorNextNormFreq[parCnt]-filterFreqs[k]);
962 // if(dist<=filterQ[k])
963 // {
964 // dmp = dist/filterQ[k];
965 // parDamp *= dmp*dmp*dmp;
966 // }
967 // }
968
969
970 // each filter is a band pass notch filter
971
972 // if at least one is active
973 if (filNum > 0) {
974 // reset values
975 filDist = 0;
976 filterWeightsAcc = 0;
977 filDmp = 0;
978 filAmp = 0;
979 // for each filter
980 for (int k = 0; k < filNum; k++) {
981 // here are a couple of kludges to boost sound output of hi freq filters
982
983 // damping effect of filter increases with distance, but decreases with filter frequency [kludge]
984 float mul = ((filterMaxF-nextFreq)/filterMaxF) * 0.9 + 0.1 ;
985 //filDist = fabs(nextFreq - filFreq[k])*( ((exp(a*4)-1)/EXP_DENOM) * 0.9 + 0.1 );
986 filDist = fabs(nextFreq - filFreq[k])*mul;
987
988 // these to merge all filters contributions according to distance
989 filterWeights[k] = filterMaxF - filDist;
990 filterWeightsAcc += filterWeights[k];
991 // freqs very close to filter center are slightly amplified
992 // the size of this amp area and the effect of amplification increase with frequency [kludge]
993 if (filDist
994 < filterAmpMinF
995 + (filterAmpMaxF*(1-mul) - filterAmpMinF) * (1 - filQ[k]) )
996 filAmp = filQ[k] * filterAmpMul*(1-mul);
997 else
998 filAmp = 0;
999 // actual damping
1000 filDmp = 1 / (filDist * filQ[k]);
1001 filDmp = (filDmp > 1) ? 1 : filDmp;
1002 // sum damp+amplification
1003 filterDamp[k] = filDmp + filAmp;
1004 }
1005 // do weighted mean to merge all filters contributions
1006 filDmp = 0;
1007 for (int k = 0; k < filNum; k++)
1008 filDmp += filterDamp[k] * filterWeights[k];
1009 filDmp /= filterWeightsAcc;
1010 // apply
1011 parDamp *= filDmp;
1012 }
1013
1014
1015 return parDamp;
1016 }