| 420 | } |
| 421 | |
| 422 | void GranularSynth::handleGrainAddRemove(int blockSize) { |
| 423 | if (mParameters.ui.specComplete) { |
| 424 | // Add one grain per active note |
| 425 | for (GrainNote* gNote : mActiveNotes) { |
| 426 | for (size_t i = 0; i < gNote->grainTriggers.size(); ++i) { |
| 427 | if (gNote->grainTriggers[i] <= 0) { |
| 428 | mParamGenerator = mParameters.note.notes[gNote->pitchClass]->generators[i].get(); |
| 429 | mParamCandidate = mParameters.note.notes[gNote->pitchClass]->getCandidate(i); |
| 430 | mGain = juce::Decibels::decibelsToGain(mParameters.getFloatParam(mParamGenerator, ParamCommon::Type::GAIN, true)); |
| 431 | mGrainRate = mParameters.getFloatParam(mParamGenerator, ParamCommon::Type::GRAIN_RATE, true); |
| 432 | mGrainDuration = mParameters.getFloatParam(mParamGenerator, ParamCommon::Type::GRAIN_DURATION, true); |
| 433 | mGrainSync = mParameters.getBoolParam(mParamGenerator, ParamCommon::Type::GRAIN_SYNC); |
| 434 | mPitchAdjust = mParameters.getFloatParam(mParamGenerator, ParamCommon::Type::PITCH_ADJUST, true); |
| 435 | mPitchSpray = mParameters.getFloatParam(mParamGenerator, ParamCommon::Type::PITCH_SPRAY, true); |
| 436 | mPosAdjust = mParameters.getFloatParam(mParamGenerator, ParamCommon::Type::POS_ADJUST, true); |
| 437 | mPosSpray = mParameters.getFloatParam(mParamGenerator, ParamCommon::Type::POS_SPRAY, true); |
| 438 | mPanAdjust = mParameters.getFloatParam(mParamGenerator, ParamCommon::Type::PAN_ADJUST, true); |
| 439 | mPanSpray = mParameters.getFloatParam(mParamGenerator, ParamCommon::Type::PAN_SPRAY, true); |
| 440 | mShape = mParameters.getFloatParam(mParamGenerator, ParamCommon::Type::GRAIN_SHAPE, true); |
| 441 | mTilt = mParameters.getFloatParam(mParamGenerator, ParamCommon::Type::GRAIN_TILT, true); |
| 442 | mReverse = mParameters.getBoolParam(mParamGenerator, ParamCommon::Type::REVERSE); |
| 443 | mOctaveAdjust = mParameters.getIntParam(mParamGenerator, ParamCommon::Type::OCTAVE_ADJUST); |
| 444 | |
| 445 | if (mGrainSync) { |
| 446 | mDiv = std::pow(2, juce::roundToInt(ParamRanges::SYNC_DIV_MAX * (1.0f - ParamRanges::GRAIN_DURATION.convertTo0to1(mGrainDuration)))); |
| 447 | // Find synced duration using bpm |
| 448 | mDurSec = mBarsPerSec / mDiv; |
| 449 | } else { |
| 450 | mDurSec = mGrainDuration; |
| 451 | } |
| 452 | // Skip adding new grain if not enabled or full of grains |
| 453 | if (mParamCandidate != nullptr && mParameters.note.notes[gNote->pitchClass]->shouldPlayGenerator(i)) { |
| 454 | jassert(mParamCandidate->pbRate > 0.1f); |
| 455 | // Get the next available grain from the pool (if there is one) |
| 456 | Grain* grain = mGrainPool.getNextAvailableGrain(); |
| 457 | if (grain != nullptr) { |
| 458 | mDurSamples = mSampleRate * mDurSec * (1.0f / mParamCandidate->pbRate); |
| 459 | /* Position calculation */ |
| 460 | mPosSprayOffset = juce::jmap(mRandom.nextFloat(), ParamRanges::POSITION_SPRAY.start, mPosSpray) * mSampleRate; |
| 461 | if (mRandom.nextFloat() > 0.5f) mPosSprayOffset = -mPosSprayOffset; |
| 462 | mPosOffset = mPosAdjust * mDurSamples + mPosSprayOffset; |
| 463 | mPosSamples = mParamCandidate->posRatio * mAudioBuffer.getNumSamples() + mPosOffset; |
| 464 | |
| 465 | /* Pan offset */ |
| 466 | mPanSprayOffset = mRandom.nextFloat() * mPanSpray; |
| 467 | if (mRandom.nextFloat() > 0.5f) mPanSprayOffset = -mPanSprayOffset; |
| 468 | mPanOffset = juce::jlimit(ParamRanges::PAN_ADJUST.start, ParamRanges::PAN_ADJUST.end, mPanAdjust + mPanSprayOffset); |
| 469 | |
| 470 | /* Pitch calculation */ |
| 471 | mPitchSprayOffset = juce::jmap(mRandom.nextFloat(), 0.0f, mPitchSpray); |
| 472 | if (mRandom.nextFloat() > 0.5f) mPitchSprayOffset = -mPitchSprayOffset; |
| 473 | mPitchBendOffset = std::pow(Utils::TIMESTRETCH_RATIO, mCurPitchBendSemitones) - 1; |
| 474 | mPbRate = mParamCandidate->pbRate + mPitchAdjust + mPitchSprayOffset + mPitchBendOffset; |
| 475 | if (mReverse) { |
| 476 | mPbRate = -mPbRate; // Flip playback rate if going in reverse |
| 477 | mPosSamples += mDurSamples; // Start at the end |
| 478 | } |
| 479 | /* Octave correction (centered around 0) */ |
nothing calls this directly
no test coverage detected