From 1bc0fde111fe8d8ef8a377b560adab6b7ecd9594 Mon Sep 17 00:00:00 2001 From: Hayden Setlik Date: Sun, 11 Apr 2021 19:08:11 -0600 Subject: [PATCH] switched control flow to private members updated once per buffer --- Source/DAHDSR.cpp | 26 +++++++-------- Source/DAHDSR.h | 42 +++++++++++++++++++++--- Source/FmVoice.cpp | 63 ++++++++++++++++++++++-------------- Source/FmVoice.h | 47 +++++++++++++++------------ Source/LfoProcessor.cpp | 33 +++++++++++++------ Source/LfoProcessor.h | 21 +++++++++++- Source/OperatorProcessor.cpp | 6 ++-- Source/OperatorProcessor.h | 44 ++++++++++++++++++++----- Source/PluginProcessor.cpp | 6 +++- 9 files changed, 204 insertions(+), 84 deletions(-) diff --git a/Source/DAHDSR.cpp b/Source/DAHDSR.cpp index 6a4301a..092c5a9 100644 --- a/Source/DAHDSR.cpp +++ b/Source/DAHDSR.cpp @@ -16,16 +16,16 @@ float DAHDSR::process(float input) { case delayPhase: { - if(ParamStatic::opDelayTime[index] > 0) + if(valueOf(delayId) > 0) { if(samplesIntoPhase == 0) - samplesInPhase = phaseSafe(floor(ParamStatic::opDelayTime[index].get() * (sampleRate / 1000))); + samplesInPhase = phaseSafe(floor(delayTime * (sampleRate / 1000))); samplesIntoPhase += 1; if(samplesIntoPhase >= samplesInPhase) { currentPhase = attackPhase; samplesIntoPhase = 0; - samplesInPhase = phaseSafe(floor(ParamStatic::opAttackTime[index].get() * (sampleRate / 1000))); + samplesInPhase = phaseSafe(floor(attackTime * (sampleRate / 1000))); factor = exp((log(1.0f) - log(minLevel)) /samplesInPhase); } output = 0.0f; @@ -33,7 +33,7 @@ float DAHDSR::process(float input) else { currentPhase = attackPhase; - samplesInPhase = phaseSafe(floor(ParamStatic::opAttackTime[index].get() * (sampleRate / 1000))); + samplesInPhase = phaseSafe(floor(attackTime * (sampleRate / 1000))); factor = exp((log(1.0f) - log(minLevel)) /samplesInPhase); samplesIntoPhase = 0; } @@ -49,30 +49,30 @@ float DAHDSR::process(float input) { currentPhase = holdPhase; samplesIntoPhase = 0; - samplesInPhase = ParamStatic::opHoldTime[index].get() * (sampleRate / 1000); + samplesInPhase = valueOf(holdId) * (sampleRate / 1000); } break; } case holdPhase: { - if(ParamStatic::opHoldTime[index].get() != 0) + if(holdTime != 0) { samplesIntoPhase += 1; if(samplesIntoPhase > samplesInPhase) { currentPhase = decayPhase; samplesIntoPhase = 0; - samplesInPhase = phaseSafe(ParamStatic::opDecayTime[index].get() * (sampleRate / 1000)); - factor = exp((log(ParamStatic::opSustainLevel[index].get()) - log(1.0f)) /samplesInPhase); + samplesInPhase = phaseSafe(decayTime * (sampleRate / 1000)); + factor = exp((log(sustainLevel) - log(1.0f)) /samplesInPhase); } output = 1.0f; - } + } else { currentPhase = decayPhase; samplesIntoPhase = 0; - samplesInPhase = phaseSafe(ParamStatic::opDecayTime[index].get() * (sampleRate / 1000)); - factor = exp((log(ParamStatic::opSustainLevel[index].get()) - log(1.0f)) /samplesInPhase);; + samplesInPhase = phaseSafe(decayTime * (sampleRate / 1000)); + factor = exp((log(sustainLevel) - log(1.0f)) /samplesInPhase);; } break; } @@ -84,13 +84,13 @@ float DAHDSR::process(float input) { currentPhase = sustainPhase; samplesIntoPhase = 0; - output = ParamStatic::opSustainLevel[index].get(); + output = sustainLevel; } break; } case sustainPhase: { - output = ParamStatic::opSustainLevel[index].get(); + output = sustainLevel; break; } case releasePhase: diff --git a/Source/DAHDSR.h b/Source/DAHDSR.h index a6fc0e7..17a4e25 100644 --- a/Source/DAHDSR.h +++ b/Source/DAHDSR.h @@ -26,28 +26,49 @@ class DAHDSR releasePhase, noteOff }; + juce::AudioProcessorValueTreeState* tree; //functions - DAHDSR(int ind) : factor(1.0f), sampleRate(44100), index(ind) + DAHDSR(int ind, juce::AudioProcessorValueTreeState* t) : tree(t), factor(1.0f), sampleRate(44100), index(ind) { trigger = false; samplesIntoPhase = 0; currentPhase = noteOff; + auto iStr = juce::String(ind); + delayId = "delayParam" + iStr; + attackId = "attackParam" + iStr; + holdId = "holdParam" + iStr; + decayId = "decayParam" + iStr; + sustainId = "sustainParam" + iStr; + releaseId = "releaseParam" + iStr; } ~DAHDSR() {} void triggerOn() { trigger = true; - samplesInPhase = floor(ParamStatic::opDelayTime[index].get() * (sampleRate / 1000)); + samplesInPhase = floor(delayTime * (sampleRate / 1000)); samplesIntoPhase = 0; currentPhase = delayPhase; } + float valueOf(juce::String& str) + { + return *tree->getRawParameterValue(str); + } + void updateParams() + { + delayTime = valueOf(delayId); + attackTime = valueOf(attackId); + holdTime = valueOf(holdId); + decayTime = valueOf(decayId); + sustainLevel = valueOf(sustainId); + releaseTime = valueOf(releaseId); + } void triggerOff() { trigger = false; currentPhase = releasePhase; samplesIntoPhase = 0; - samplesInPhase = ParamStatic::opReleaseTime[index].get() * (sampleRate / 1000); - factor = exp((log(minLevel) - log(ParamStatic::opSustainLevel[index].get())) /samplesInPhase); + samplesInPhase = releaseTime * (sampleRate / 1000); + factor = exp((log(minLevel) - log(sustainLevel)) /samplesInPhase); } void setSampleRate(double value) {sampleRate = value;} float process(float input); @@ -70,4 +91,17 @@ class DAHDSR double sampleRate; int index; bool trigger; + juce::String delayId; + juce::String attackId; + juce::String holdId; + juce::String decayId; + juce::String sustainId; + juce::String releaseId; +private: + float delayTime = 0.0f; + float attackTime = 20.0f; + float holdTime = 0.0f; + float decayTime = 100.0f; + float sustainLevel = 0.6f; + float releaseTime = 40.0f; }; diff --git a/Source/FmVoice.cpp b/Source/FmVoice.cpp index 1899954..47f0778 100644 --- a/Source/FmVoice.cpp +++ b/Source/FmVoice.cpp @@ -12,34 +12,44 @@ -FmVoice::FmVoice(int numOperators, int index) : voiceIndex(index), operatorCount(numOperators), fundamental(1.0f) +FmVoice::FmVoice(int numOperators, int index, juce::AudioProcessorValueTreeState* t) : tree(t), voiceIndex(index), operatorCount(numOperators), fundamental(1.0f) { lfoMax = std::numeric_limits::min(); lfoMin = std::numeric_limits::max(); numJumps = 0; - for(int i = 0; i < numOperators; ++i) + for(int o = 0; o < numOperators; ++o) { - operators.add(new Operator(i, voiceIndex)); - std::vector ints; - for(int n = 0; n < numOperators; ++n) + operators.add(new Operator(o, voiceIndex, tree)); + auto oStr = juce::String(o); + opAudibleIds[o] = "audibleParam" + oStr; + for(int i = 0; i < numOperators; ++i) { - int newVal = 0; - ints.push_back(newVal); + auto iStr = juce::String(i); + opRoutingIds[o][i] = oStr + "to" + iStr + "Param"; } - routingParams.push_back(ints); } for(int n = 0; n < totalLfos; ++n) { - lfoBank.add(new LfoProcessor(n)); + lfoBank.add(new LfoProcessor(n, tree)); + } + +} +void FmVoice::updateParams() +{ + for(op1Index = 0; op1Index < TOTAL_OPERATORS; ++op1Index) + { + operators[op1Index]->updateParams(); + opAudible[op1Index] = getValue(opAudibleIds[op1Index]); + if(op1Index < TOTAL_LFOS) + lfoBank[op1Index]->updateParams(); + for(op2Index = 0; op2Index < TOTAL_OPERATORS; ++op2Index) + { + opRouting[op1Index][op2Index] = (int)getValue(opRoutingIds[op1Index][op2Index]); + } } } -float lastSample = 0.0f; -int numBuffers = 0; -int op1Index = 0; -int op2Index = 0; void FmVoice::renderNextBlock(juce::AudioBuffer &outputBuffer, int startSample, int numSamples) { - ParamStatic::workingFundamental = fundamental; for(int i = startSample; i < (startSample + numSamples); ++i) { for(int lfo = 0; lfo < 4; ++ lfo) @@ -57,12 +67,12 @@ void FmVoice::renderNextBlock(juce::AudioBuffer &outputBuffer, int startS op2Index = 0; for(Operator* d : operators) { - if(ParamStatic::opRouting[op1Index][op2Index].get()) + if(opRouting[op1Index][op2Index]) { d->modOffset += o->lastOutputSample;} ++op2Index; } opSample = o->sample(fundamental); - if(ParamStatic::opAudible[o->getIndex()].get()) + if(opAudible[o->getIndex()]) { opSum += opSample; sumL += o->lastOutputL; @@ -72,10 +82,9 @@ void FmVoice::renderNextBlock(juce::AudioBuffer &outputBuffer, int startS ++op1Index; } outputBuffer.addSample(0, i, sumL); - if(outputBuffer.getNumChannels() > 0) - outputBuffer.addSample(1, i, sumR); + outputBuffer.addSample(1, i, sumR); - if(fabs(opSum - lastOpSample) > 0.3f) + if(fabs(opSum - lastOpSample) > 0.2f) ++numJumps; lastOpSample = opSum; } @@ -84,14 +93,20 @@ void FmVoice::applyLfo(int index) { LfoProcessor* thisLfo = lfoBank[index]; lfoValue = thisLfo->getSampleValue(); - if(ParamStatic::lfoTarget[index] > 0) + /* + if(lfoValue < lfoMin) + lfoMin = lfoValue; + if(lfoValue > lfoMax) + lfoMax = lfoValue; + */ + if(thisLfo->target > 0) { - if(ParamStatic::lfoTarget[index].get() % 2 != 0) - ParamStatic::opAmplitudeMod[(ParamStatic::lfoTarget[index].get() / 2)] = ((1.0f + lfoValue) / 2.0f); + if(thisLfo->target % 2 != 0) + operators[(thisLfo->target / 2)]->setAM((1.0f + lfoValue) / 2.0f); else { - auto targetOp = ParamStatic::lfoTarget[index].get() / 2; - operators[targetOp - 1]->modulateRatio(lfoValue, ParamStatic::lfoRatioMode[index].get()); + auto targetOp = thisLfo->target / 2; + operators[targetOp - 1]->modulateRatio(lfoValue, thisLfo->ratioModType); } } } diff --git a/Source/FmVoice.h b/Source/FmVoice.h index b4c3173..76c8a61 100644 --- a/Source/FmVoice.h +++ b/Source/FmVoice.h @@ -28,7 +28,8 @@ class FmSound : public juce::SynthesiserSound class FmVoice : public juce::SynthesiserVoice { public: - FmVoice(int numOperators, int index); + juce::AudioProcessorValueTreeState* tree; + FmVoice(int numOperators, int index, juce::AudioProcessorValueTreeState* t); ~FmVoice() { printf("Voice #: %d -- %d total jumps\n", voiceIndex, numJumps); @@ -70,22 +71,6 @@ class FmVoice : public juce::SynthesiserVoice if(velocity == 0) clearCurrentNote(); } - void updateLfoTarget(std::atomic* value, int lfo) - { - lfoBank[lfo]->currentTarget = *value; - } - void updateLfoRate(std::atomic* value, int lfo) - { - lfoBank[lfo]->currentRate = *value; - } - void updateLfoWave(std::atomic* value, int lfo) - { - lfoBank[lfo]->currentWaveType = *value; - } - void updateLfoLevel(std::atomic* value, int lfo) - { - lfoBank[lfo]->currentLevel = *value; - } void applyLfo(int index); void setRoutingFromGrid(juce::AudioProcessorValueTreeState* pTree, std::vector> grid); void setSampleRate(double newRate) @@ -109,8 +94,12 @@ class FmVoice : public juce::SynthesiserVoice { setSampleRate(newRate); } + float getValue(juce::String str) + { + return *tree->getRawParameterValue(str); + } + void updateParams(); int voiceIndex; - std::vector> routingParams; int numJumps; int operatorCount; float fundamental; @@ -125,21 +114,28 @@ class FmVoice : public juce::SynthesiserVoice float lfoValue; float lfoMax; float lfoMin; +private: + int op1Index, op2Index; + juce::String opRoutingIds[TOTAL_OPERATORS][TOTAL_OPERATORS]; + juce::String opAudibleIds[TOTAL_OPERATORS]; + int opRouting[TOTAL_OPERATORS][TOTAL_OPERATORS]; + int opAudible[TOTAL_OPERATORS]; }; class FmSynth : public juce::Synthesiser { public: - FmSynth(int operators, int lfos, int numVoices) : juce::Synthesiser(), numOperators(operators), numLfos(lfos) + juce::AudioProcessorValueTreeState* tree; + FmSynth(int operators, int lfos, int nVoices, juce::AudioProcessorValueTreeState* t) : juce::Synthesiser(), tree(t), numOperators(operators), numLfos(lfos), numVoices(nVoices) { for(int i = 0; i < numVoices; ++i) { - addVoice(new FmVoice(numOperators, i)); + addVoice(new FmVoice(numOperators, i, tree)); } addSound(new FmSound()); } - FmVoice* getFmVoice(int i) + FmVoice* getFmVoice(int& i) { return dynamic_cast(voices.getUnchecked(i)); } @@ -147,7 +143,16 @@ class FmSynth : public juce::Synthesiser { return &voices; } + void updateParams() + { + for(idx = 0; idx < numVoices; ++idx) + { + getFmVoice(idx)->updateParams(); + } + } private: + int idx; int numOperators; int numLfos; + int numVoices; }; diff --git a/Source/LfoProcessor.cpp b/Source/LfoProcessor.cpp index 0bbf153..bba6d8d 100644 --- a/Source/LfoProcessor.cpp +++ b/Source/LfoProcessor.cpp @@ -9,41 +9,56 @@ */ #include "LfoProcessor.h" -LfoProcessor::LfoProcessor(int index) : lfoIndex(index) +LfoProcessor::LfoProcessor(int index, juce::AudioProcessorValueTreeState* t) : tree(t), lfoIndex(index) { - + auto iStr = juce::String(index); + rateId = "lfoRateParam" + iStr; + levelId = "lfoLevelParam" + iStr; + targetId = "lfoTargetParam" + iStr; + waveId = "lfoWaveParam" + iStr; + ratioModId = "lfoRatioModeParam" + iStr; + //updateParams(); } float LfoProcessor::getSampleValue() { - switch(ParamStatic::lfoWave[lfoIndex].get()) + switch(wave) { case 0: { - lastValue = ((lfo_osc.sinebuf(ParamStatic::lfoRate[lfoIndex].get()) * 0.5f) + 0.5f); + lastValue = ((lfo_osc.sinebuf(rate) * 0.5f) + 0.5f); break; } case 1: { - lastValue = ((lfo_osc.triangle(ParamStatic::lfoRate[lfoIndex].get()) * 0.5f) + 0.5f); + lastValue = ((lfo_osc.triangle(rate) * 0.5f) + 0.5f); break; } case 2: { - lastValue = ((lfo_osc.square(ParamStatic::lfoRate[lfoIndex].get()) * 0.5f) + 0.5f); + lastValue = ((lfo_osc.square(rate) * 0.5f) + 0.5f); break; } case 3: { - lastValue = ((lfo_osc.saw(ParamStatic::lfoRate[lfoIndex].get()) / 2.0f) + 0.5f); + lastValue = ((lfo_osc.saw(rate) / 2.0f) + 0.5f); break; } case 4: { - int msCycle = floor(1000 / (ParamStatic::lfoRate[lfoIndex].get() + 0.0001)); + int msCycle = floor(1000 / (rate + 0.0001)); lastValue = randOsc.sample(msCycle); break; } } - return lastValue * ParamStatic::lfoLevel[lfoIndex].get(); + return lastValue * level; }; + +void LfoProcessor::updateParams() +{ + rate = getValue(rateId); + level = getValue(levelId); + target = (int)getValue(targetId); + wave = (int)getValue(waveId); + ratioModType = (int)getValue(ratioModId); +} diff --git a/Source/LfoProcessor.h b/Source/LfoProcessor.h index e739b31..ad41b9c 100644 --- a/Source/LfoProcessor.h +++ b/Source/LfoProcessor.h @@ -13,6 +13,7 @@ #include "maximilian.h" #include "SampleAndHoldOscillator.h" #include "ParameterStructure.h" +#include "WavetableProcessor.h" //const to set the synth's total availible number of LFOs /* GUIDE TO TARGET NUMBERS Operator : Parameter : id @@ -45,9 +46,15 @@ const int totalLfos = 4; class LfoProcessor { public: + juce::AudioProcessorValueTreeState* tree; //functions - LfoProcessor(int index); + LfoProcessor(int index, juce::AudioProcessorValueTreeState* t); ~LfoProcessor() {} + void updateParams(); + float getValue(juce::String str) + { + return *tree->getRawParameterValue(str); + } float getSampleValue(); //data int currentTarget; @@ -56,8 +63,20 @@ class LfoProcessor float currentLevel; int getIndex() {return lfoIndex;} float lastValue; + float rate; + float level; + int target; + int wave; + int ratioModType; private: + juce::String rateId; + juce::String levelId; + juce::String targetId; + juce::String waveId; + juce::String ratioModId; maxiOsc lfo_osc; RandomOscillator randOsc; int lfoIndex; + + }; diff --git a/Source/OperatorProcessor.cpp b/Source/OperatorProcessor.cpp index 4ca4ff9..78f402e 100644 --- a/Source/OperatorProcessor.cpp +++ b/Source/OperatorProcessor.cpp @@ -12,8 +12,8 @@ float Operator::sample(float fundamental) { - rawSample = wtOsc.getSample((fundamental * ParamStatic::opRatio[index].get()) + (modOffset * ParamStatic::opModIndex[index].get())); - lastOutputSample = envelope.process(rawSample) * ( 1.0f - ParamStatic::opAmplitudeMod[index].get()); + rawSample = wtOsc.getSample((fundamental * ratio) + (modOffset * modIndex)); + lastOutputSample = envelope.process(rawSample) * ( 1.0f - amplitudeMod); updatePan(); return lastOutputSample; } @@ -47,5 +47,5 @@ void Operator::modulateRatio(float value, int mode) break; } } - ParamStatic::opRatio[index] = ratio + modValue; + ratio = ratio + modValue; } diff --git a/Source/OperatorProcessor.h b/Source/OperatorProcessor.h index c6ec86f..6dc97b3 100644 --- a/Source/OperatorProcessor.h +++ b/Source/OperatorProcessor.h @@ -18,16 +18,35 @@ class Operator { public: - Operator(int opIndex, int voiceIndex) : lastOutputSample(0.0f), envelope(opIndex), voice(voiceIndex), ratio(1.0f), index(opIndex) + juce::AudioProcessorValueTreeState* tree; + Operator(int opIndex, int voiceIndex, juce::AudioProcessorValueTreeState* t) : tree(t), lastOutputSample(0.0f), envelope(opIndex, tree), voice(voiceIndex), ratio(1.0f), index(opIndex) { minRatio = std::numeric_limits::max(); maxRatio = std::numeric_limits::min(); + auto iStr = juce::String(opIndex); + panId = "panParam" + iStr; + levelId = "levelParam" + iStr; + ratioId = "ratioParam" + iStr; + modIndexId = "indexParam" + iStr; + } ~Operator() { //printf("Minimum ratio: %f\n", minRatio); //printf("Maximum ratio: %f\n", maxRatio); } + float getValue(juce::String str) + { + return *tree->getRawParameterValue(str); + } + void updateParams() + { + envelope.updateParams(); + pan = getValue(panId); + level = getValue(levelId); + ratio = getValue(ratioId); + modIndex = getValue(modIndexId); + } int getIndex() { return index; @@ -52,12 +71,16 @@ class Operator } void updatePan() { - panValue = (ParamStatic::opPanValue[index].get() + 1.0f) / 2.0f; + panValue = (pan + 1.0f) / 2.0f; gainR = panValue; gainL = 1.0f - panValue; lastOutputL = lastOutputSample * gainL; lastOutputR = lastOutputSample * gainR; } + void setAM(float value) + { + amplitudeMod = value; + } float sample(float fundamental); float lastOutputSample; float gainL; @@ -71,14 +94,19 @@ class Operator float rawSample; float panValue; private: - float ratio; - float modIndex; - float level; int index; SineTableOscillator wtOsc; - const int ratioId = (3 * index) + 2; - const int modIndexId = (3 * index) + 3; - const int levelId = (3 * index) + 4; float minRatio; float maxRatio; + juce::String panId; + juce::String modIndexId; + juce::String levelId; + juce::String ratioId; + juce::String amplitudeId; + float pan; + float ratio; + float modIndex; + float level; + float amplitudeMod; + }; diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index 8b838e7..cf89348 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -121,7 +121,7 @@ HexFmAudioProcessor::HexFmAudioProcessor() #endif .withOutput ("Output", juce::AudioChannelSet::stereo(), true) #endif - ), tree(*this, nullptr, "synthParams", createLayout(numOperators)), synth(6, 4, 6) + ), tree(*this, nullptr, "synthParams", createLayout(numOperators)), synth(6, 4, 6, &tree) #endif { for(int i = 0; i < 4; ++i) @@ -270,6 +270,7 @@ bool HexFmAudioProcessor::isBusesLayoutSupported (const BusesLayout& layouts) co void HexFmAudioProcessor::processBlock (juce::AudioBuffer& buffer, juce::MidiBuffer& midiMessages) { + /* ParamStatic::setRouting(&tree, routingIds); for(lfoIndex = 0; lfoIndex < TOTAL_LFOS; ++lfoIndex) @@ -295,7 +296,10 @@ void HexFmAudioProcessor::processBlock (juce::AudioBuffer& buffer, juce:: ParamStatic::opSustainLevel[opIndex].setFrom(tree.getRawParameterValue(sustainIds[opIndex])); ParamStatic::opReleaseTime[opIndex].setFrom(tree.getRawParameterValue(releaseIds[opIndex])); } + */ + buffer.clear(); + synth.updateParams(); synth.renderNextBlock(buffer, midiMessages, 0, buffer.getNumSamples()); }