annotate projects/d-box/OscillatorBank.cpp @ 39:638bc1ae2500 staging

Improved readibility of the DIGITAL code in the PRU, using register names instead of aliases and expanding some of the macros, removing unused macros. Binaries were not modified
author Giulio Moro <giuliomoro@yahoo.it>
date Wed, 13 May 2015 12:18:10 +0100
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 }