annotate examples/10-Instruments/d-box/OscillatorBank.cpp @ 490:b6b532e88a5c prerelease

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