annotate projects/d-box/OscillatorBank.cpp @ 223:ec9425f728bc mergingClockSync

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