diff --git a/src/deluge/io/midi/learned_midi.h b/src/deluge/io/midi/learned_midi.h index 7be02086de..db4acaedc0 100644 --- a/src/deluge/io/midi/learned_midi.h +++ b/src/deluge/io/midi/learned_midi.h @@ -32,15 +32,15 @@ class LearnedMIDI { LearnedMIDI(); void clear(); - inline bool equalsCable(MIDICable* newCable) { + constexpr bool equalsCable(MIDICable* newCable) const { return (!MIDIDeviceManager::differentiatingInputsByDevice || !cable || newCable == cable); } - inline bool equalsChannelOrZone(MIDICable* newCable, int32_t newChannelOrZone) { + constexpr bool equalsChannelOrZone(MIDICable* newCable, int32_t newChannelOrZone) const { return (newChannelOrZone == channelOrZone && equalsCable(newCable)); } - inline bool equalsNoteOrCC(MIDICable* newCable, int32_t newChannel, int32_t newNoteOrCC) { + constexpr bool equalsNoteOrCC(MIDICable* newCable, int32_t newChannel, int32_t newNoteOrCC) const { return (newNoteOrCC == noteOrCC && equalsChannelOrZone(newCable, newChannel)); } diff --git a/src/deluge/model/global_effectable/global_effectable.h b/src/deluge/model/global_effectable/global_effectable.h index 695691417c..cb9fd6ff7e 100644 --- a/src/deluge/model/global_effectable/global_effectable.h +++ b/src/deluge/model/global_effectable/global_effectable.h @@ -19,9 +19,7 @@ #include "definitions_cxx.hpp" #include "dsp/filter/filter_set.h" -#include "gui/l10n/l10n.h" #include "model/mod_controllable/mod_controllable_audio.h" -#include "util/containers.h" using namespace deluge; class Serializer; diff --git a/src/deluge/model/mod_controllable/mod_controllable.cpp b/src/deluge/model/mod_controllable/mod_controllable.cpp index fd7554da0d..6329588843 100644 --- a/src/deluge/model/mod_controllable/mod_controllable.cpp +++ b/src/deluge/model/mod_controllable/mod_controllable.cpp @@ -20,9 +20,6 @@ #include "model/timeline_counter.h" #include "modulation/automation/auto_param.h" -ModControllable::ModControllable() { -} - // modelStack->autoParam will be NULL in this rare case!! int32_t ModControllable::getKnobPosForNonExistentParam(int32_t whichModEncoder, ModelStackWithAutoParam* modelStack) { return -64; @@ -40,7 +37,7 @@ ModelStackWithAutoParam* ModControllable::getParamFromModEncoder(int32_t whichMo return (ModelStackWithAutoParam*)modelStack; } -ModelStackWithAutoParam* ModControllable::getParamFromMIDIKnob(MIDIKnob* knob, +ModelStackWithAutoParam* ModControllable::getParamFromMIDIKnob(MIDIKnob& knob, ModelStackWithThreeMainThings* modelStack) { setTheAutoParamToNull(modelStack); diff --git a/src/deluge/model/mod_controllable/mod_controllable.h b/src/deluge/model/mod_controllable/mod_controllable.h index 5b1ceb5fab..2bf7a85569 100644 --- a/src/deluge/model/mod_controllable/mod_controllable.h +++ b/src/deluge/model/mod_controllable/mod_controllable.h @@ -39,7 +39,7 @@ class ModelStackWithSoundFlags; /// interface to the rest of the system when displaying information about the underlying modulation state. class ModControllable { public: - ModControllable(); + ModControllable() = default; virtual bool modEncoderButtonAction(uint8_t whichModEncoder, bool on, ModelStackWithThreeMainThings* modelStack) { return false; } // Returns whether Instrument was changed @@ -47,10 +47,11 @@ class ModControllable { virtual ModelStackWithAutoParam* getParamFromModEncoder(int32_t whichModEncoder, ModelStackWithThreeMainThings* modelStack, bool allowCreation = true); // Check that autoParam isn't NULL, after calling this. - virtual ModelStackWithAutoParam* getParamFromMIDIKnob( - MIDIKnob* knob, - ModelStackWithThreeMainThings* modelStack); // Check that autoParam isn't NULL, after calling this - virtual uint8_t* getModKnobMode(); // Return NULL if different modes not supported + + /// Check that autoParam isn't NULL, after calling this + virtual ModelStackWithAutoParam* getParamFromMIDIKnob(MIDIKnob& knob, ModelStackWithThreeMainThings* modelStack); + + virtual uint8_t* getModKnobMode(); // Return NULL if different modes not supported virtual bool isKit() { return false; } virtual bool isSong() { return false; } virtual bool isEditingComp() { return false; } diff --git a/src/deluge/model/mod_controllable/mod_controllable_audio.cpp b/src/deluge/model/mod_controllable/mod_controllable_audio.cpp index 249151f2a8..0da993b341 100644 --- a/src/deluge/model/mod_controllable/mod_controllable_audio.cpp +++ b/src/deluge/model/mod_controllable/mod_controllable_audio.cpp @@ -36,10 +36,12 @@ #include "model/clip/instrument_clip.h" #include "model/note/note_row.h" #include "model/song/song.h" +#include "modulation/knob.h" #include "modulation/params/param_set.h" #include "processing/engines/audio_engine.h" #include "processing/sound/sound.h" #include "storage/storage_manager.h" +#include namespace params = deluge::modulation::params; @@ -94,7 +96,7 @@ void ModControllableAudio::cloneFrom(ModControllableAudio* other) { trebleFreq = other->trebleFreq; filterRoute = other->filterRoute; sidechain.cloneFrom(&other->sidechain); - midiKnobArray.cloneFrom(&other->midiKnobArray); // Could fail if no RAM... not too big a concern + midi_knobs = other->midi_knobs; // Could fail if no RAM... not too big a concern delay = other->delay; stutterConfig = other->stutterConfig; } @@ -406,32 +408,31 @@ void ModControllableAudio::writeTagsToFile(Serializer& writer) { writer.closeTag(); // MIDI knobs - if (midiKnobArray.getNumElements()) { + if (midi_knobs.size() > 0) { writer.writeArrayStart("midiKnobs"); - for (int32_t k = 0; k < midiKnobArray.getNumElements(); k++) { - MIDIKnob* knob = midiKnobArray.getElement(k); + for (MIDIKnob& knob : midi_knobs) { writer.writeOpeningTagBeginning("midiKnob", true); - knob->midiInput.writeAttributesToFile( + knob.midiInput.writeAttributesToFile( writer, MIDI_MESSAGE_CC); // Writes channel and CC, but not device - we do that below. - writer.writeAttribute("relative", knob->relative); - writer.writeAttribute("controlsParam", params::paramNameForFile(unpatchedParamKind_, - knob->paramDescriptor.getJustTheParam())); - if (!knob->paramDescriptor.isJustAParam()) { // TODO: this only applies to Sounds + writer.writeAttribute("relative", knob.relative); + writer.writeAttribute( + "controlsParam", params::paramNameForFile(unpatchedParamKind_, knob.paramDescriptor.getJustTheParam())); + if (!knob.paramDescriptor.isJustAParam()) { // TODO: this only applies to Sounds writer.writeAttribute("patchAmountFromSource", - sourceToString(knob->paramDescriptor.getTopLevelSource())); + sourceToString(knob.paramDescriptor.getTopLevelSource())); - if (knob->paramDescriptor.hasSecondSource()) { + if (knob.paramDescriptor.hasSecondSource()) { writer.writeAttribute("patchAmountFromSecondSource", - sourceToString(knob->paramDescriptor.getSecondSourceFromTop())); + sourceToString(knob.paramDescriptor.getSecondSourceFromTop())); } } // Because we manually called LearnedMIDI::writeAttributesToFile() above, we have to give the MIDIDevice its // own tag, cos that can't be written as just an attribute. - if (knob->midiInput.cable) { + if (knob.midiInput.cable != nullptr) { writer.writeOpeningTagEnd(); - knob->midiInput.cable->writeReferenceToFile(writer); + knob.midiInput.cable->writeReferenceToFile(writer); writer.writeClosingTag("midiKnob", true, true); } else { @@ -803,22 +804,26 @@ Error ModControllableAudio::readTagFromFile(Deserializer& reader, char const* ta reader.match('}'); // close box. if (p != params::GLOBAL_NONE && p != params::PLACEHOLDER_RANGE) { - MIDIKnob* newKnob = midiKnobArray.insertKnobAtEnd(); - if (newKnob) { - newKnob->midiInput.cable = cable; - newKnob->midiInput.channelOrZone = channel; - newKnob->midiInput.noteOrCC = ccNumber; - newKnob->relative = relative; + try { + MIDIKnob& new_knob = midi_knobs.emplace_back(); + new_knob.midiInput.cable = cable; + new_knob.midiInput.channelOrZone = channel; + new_knob.midiInput.noteOrCC = ccNumber; + new_knob.relative = relative; if (s == PatchSource::NOT_AVAILABLE) { - newKnob->paramDescriptor.setToHaveParamOnly(p); + new_knob.paramDescriptor.setToHaveParamOnly(p); } else if (s2 == PatchSource::NOT_AVAILABLE) { - newKnob->paramDescriptor.setToHaveParamAndSource(p, s); + new_knob.paramDescriptor.setToHaveParamAndSource(p, s); } else { - newKnob->paramDescriptor.setToHaveParamAndTwoSources(p, s, s2); + new_knob.paramDescriptor.setToHaveParamAndTwoSources(p, s, s2); } + } catch (...) { + // If we run out of memory, we just ignore the knob + // TODO(@stellar-ari): This is bad practice, we should handle this better, but it + // currently follows the previous implementation } } } @@ -835,16 +840,16 @@ Error ModControllableAudio::readTagFromFile(Deserializer& reader, char const* ta return Error::NONE; } -ModelStackWithAutoParam* ModControllableAudio::getParamFromMIDIKnob(MIDIKnob* knob, +ModelStackWithAutoParam* ModControllableAudio::getParamFromMIDIKnob(MIDIKnob& knob, ModelStackWithThreeMainThings* modelStack) { ParamCollectionSummary* summary = modelStack->paramManager->getUnpatchedParamSetSummary(); ParamCollection* paramCollection = summary->paramCollection; - int32_t paramId = knob->paramDescriptor.getJustTheParam() - params::UNPATCHED_START; + int32_t param_id = knob.paramDescriptor.getJustTheParam() - params::UNPATCHED_START; ModelStackWithParamId* modelStackWithParamId = - modelStack->addParamCollectionAndId(paramCollection, summary, paramId); + modelStack->addParamCollectionAndId(paramCollection, summary, param_id); ModelStackWithAutoParam* modelStackWithAutoParam = paramCollection->getAutoParamFromId(modelStackWithParamId); @@ -892,17 +897,16 @@ bool ModControllableAudio::offerReceivedCCToLearnedParamsForClip(MIDICable& cabl bool messageUsed = false; // For each MIDI knob... - for (int32_t k = 0; k < midiKnobArray.getNumElements(); k++) { - MIDIKnob* knob = midiKnobArray.getElement(k); + for (MIDIKnob& knob : midi_knobs) { // If this is the knob... - if (knob->midiInput.equalsNoteOrCC(&cable, channel, ccNumber)) { + if (knob.midiInput.equalsNoteOrCC(&cable, channel, ccNumber)) { messageUsed = true; // See if this message is evidence that the knob is not "relative" if (value >= 16 && value < 112) { - knob->relative = false; + knob.relative = false; } int32_t modPos = 0; @@ -948,7 +952,8 @@ bool ModControllableAudio::offerReceivedCCToLearnedParamsForClip(MIDICable& cabl modelStackWithParam->paramCollection->paramValueToKnobPos(currentValue, modelStackWithParam); // calculate new knob position based on value received and deluge current value - newKnobPos = MidiTakeover::calculateKnobPos(knobPos, value, knob, false, CC_NUMBER_NONE, isStepEditing); + newKnobPos = + MidiTakeover::calculateKnobPos(knobPos, value, &knob, false, CC_NUMBER_NONE, isStepEditing); // is the cc being received for the same value as the current knob pos? If so, do nothing if (newKnobPos == knobPos) { @@ -989,17 +994,16 @@ bool ModControllableAudio::offerReceivedCCToLearnedParamsForSong( bool messageUsed = false; // For each MIDI knob... - for (int32_t k = 0; k < midiKnobArray.getNumElements(); k++) { - MIDIKnob* knob = midiKnobArray.getElement(k); + for (MIDIKnob& knob : midi_knobs) { // If this is the knob... - if (knob->midiInput.equalsNoteOrCC(&cable, channel, ccNumber)) { + if (knob.midiInput.equalsNoteOrCC(&cable, channel, ccNumber)) { messageUsed = true; // See if this message is evidence that the knob is not "relative" if (value >= 16 && value < 112) { - knob->relative = false; + knob.relative = false; } int32_t modPos = 0; @@ -1038,7 +1042,8 @@ bool ModControllableAudio::offerReceivedCCToLearnedParamsForSong( modelStackWithParam->paramCollection->paramValueToKnobPos(currentValue, modelStackWithParam); // calculate new knob position based on value received and deluge current value - newKnobPos = MidiTakeover::calculateKnobPos(knobPos, value, knob, false, CC_NUMBER_NONE, isStepEditing); + newKnobPos = + MidiTakeover::calculateKnobPos(knobPos, value, &knob, false, CC_NUMBER_NONE, isStepEditing); // is the cc being received for the same value as the current knob pos? If so, do nothing if (newKnobPos == knobPos) { @@ -1083,12 +1088,11 @@ bool ModControllableAudio::offerReceivedPitchBendToLearnedParams(MIDICable& cabl bool messageUsed = false; // For each MIDI knob... - for (int32_t k = 0; k < midiKnobArray.getNumElements(); k++) { - MIDIKnob* knob = midiKnobArray.getElement(k); + for (MIDIKnob& knob : midi_knobs) { // If this is the knob... - if (knob->midiInput.equalsNoteOrCC(&cable, channel, - 128)) { // I've got 128 representing pitch bend here... why again? + if (knob.midiInput.equalsNoteOrCC(&cable, channel, + 128)) { // I've got 128 representing pitch bend here... why again? messageUsed = true; @@ -1342,83 +1346,45 @@ bool ModControllableAudio::setModFXType(ModFXType newType) { // Returns false if fail due to insufficient RAM. bool ModControllableAudio::learnKnob(MIDICable* cable, ParamDescriptor paramDescriptor, uint8_t whichKnob, uint8_t modKnobMode, uint8_t midiChannel, Song* song) { - - bool overwroteExistingKnob = false; - // If a mod knob if (midiChannel >= 16) { return false; - - // TODO: make function not virtual after this changed - - /* - // If that knob was patched to something else... - overwroteExistingKnob = (modKnobs[modKnobMode][whichKnob].s != s || modKnobs[modKnobMode][whichKnob].p != p); - - modKnobs[modKnobMode][whichKnob].s = s; - modKnobs[modKnobMode][whichKnob].p = p; - */ } - // If a MIDI knob - else { - - MIDIKnob* knob; - - // Was this MIDI knob already set to control this thing? - for (int32_t k = 0; k < midiKnobArray.getNumElements(); k++) { - knob = midiKnobArray.getElement(k); - if (knob->midiInput.equalsNoteOrCC(cable, midiChannel, whichKnob) - && paramDescriptor == knob->paramDescriptor) { - // overwroteExistingKnob = (midiKnobs[k].s != s || midiKnobs[k].p != p); - goto midiKnobFound; - } - } + // Was there a MIDI knob already set to control this thing? + auto result = std::ranges::find_if(midi_knobs, [&](const MIDIKnob& knob) -> bool { + return knob.midiInput.equalsNoteOrCC(cable, midiChannel, whichKnob) && paramDescriptor == knob.paramDescriptor; + }); - // Or if we're here, it doesn't already exist, so find an unused MIDIKnob - knob = midiKnobArray.insertKnobAtEnd(); - if (!knob) { - return false; - } + try { + MIDIKnob& knob = result != midi_knobs.end() + ? *result // If it already exists, use that one + : midi_knobs.emplace_back(); // If it doesn't exist, create a new one + knob.midiInput.noteOrCC = whichKnob; + knob.midiInput.channelOrZone = midiChannel; + knob.midiInput.cable = cable; + knob.paramDescriptor = paramDescriptor; + knob.relative = (whichKnob != 128); // Guess that it's relative, unless this is a pitch-bend "knob" + return true; -midiKnobFound: - knob->midiInput.noteOrCC = whichKnob; - knob->midiInput.channelOrZone = midiChannel; - knob->midiInput.cable = cable; - knob->paramDescriptor = paramDescriptor; - knob->relative = (whichKnob != 128); // Guess that it's relative, unless this is a pitch-bend "knob" - } - - if (overwroteExistingKnob) { - ensureInaccessibleParamPresetValuesWithoutKnobsAreZero(song); + } catch (...) { + return false; } - - return true; } // Returns whether anything was found to unlearn bool ModControllableAudio::unlearnKnobs(ParamDescriptor paramDescriptor, Song* song) { - bool anythingFound = false; - // I've deactivated the unlearning of mod knobs, mainly because, if you want to unlearn a MIDI knob, you might not // want to also deactivate a mod knob to the same param at the same time + size_t erased = std::erase_if(midi_knobs, [&](const MIDIKnob& knob) -> bool { + return knob.paramDescriptor == paramDescriptor; //< + }); - for (int32_t k = 0; k < midiKnobArray.getNumElements();) { - MIDIKnob* knob = midiKnobArray.getElement(k); - if (knob->paramDescriptor == paramDescriptor) { - anythingFound = true; - midiKnobArray.deleteAtIndex(k); - } - else { - k++; - } - } - - if (anythingFound) { + if (erased > 0) { ensureInaccessibleParamPresetValuesWithoutKnobsAreZero(song); } - return anythingFound; + return erased > 0; } void ModControllableAudio::displayFilterSettings(bool on, FilterType currentFilterType) { diff --git a/src/deluge/model/mod_controllable/mod_controllable_audio.h b/src/deluge/model/mod_controllable/mod_controllable_audio.h index 89311f2602..52e2168d5a 100644 --- a/src/deluge/model/mod_controllable/mod_controllable_audio.h +++ b/src/deluge/model/mod_controllable/mod_controllable_audio.h @@ -27,6 +27,7 @@ #include "model/mod_controllable/ModFXProcessor.h" #include "model/mod_controllable/filters/filter_config.h" #include "model/mod_controllable/mod_controllable.h" +#include "modulation/knob.h" #include "modulation/lfo.h" #include "modulation/midi/midi_knob_array.h" #include "modulation/params/param_descriptor.h" @@ -87,7 +88,7 @@ class ModControllableAudio : public ModControllable { bool isSRREnabled(ParamManager* paramManager); bool hasBassAdjusted(ParamManager* paramManager); bool hasTrebleAdjusted(ParamManager* paramManager); - ModelStackWithAutoParam* getParamFromMIDIKnob(MIDIKnob* knob, ModelStackWithThreeMainThings* modelStack) override; + ModelStackWithAutoParam* getParamFromMIDIKnob(MIDIKnob& knob, ModelStackWithThreeMainThings* modelStack) override; // EQ int32_t bassFreq{}; // These two should eventually not be variables like this @@ -122,7 +123,7 @@ class ModControllableAudio : public ModControllable { SideChain sidechain; // Song doesn't use this, despite extending this class - MidiKnobArray midiKnobArray; + deluge::fast_vector midi_knobs; int32_t postReverbVolumeLastTime{}; protected: diff --git a/src/deluge/model/song/song.cpp b/src/deluge/model/song/song.cpp index aa40bd456b..5ce5dd0fd9 100644 --- a/src/deluge/model/song/song.cpp +++ b/src/deluge/model/song/song.cpp @@ -3338,15 +3338,14 @@ void Song::replaceInstrument(Instrument* oldOutput, Instrument* newOutput, bool // - you midi learn a controller to that clip's params // - you then go to change the preset for that clip // - you expect that you can continue controlling the same params for the new preset - ModControllableAudio* oldModControllableAudio = (ModControllableAudio*)oldOutput->toModControllable(); - if (oldModControllableAudio) { - int32_t numKnobs = oldModControllableAudio->midiKnobArray.getNumElements(); - if (numKnobs) { - ModControllableAudio* newModControllableAudio = - (ModControllableAudio*)newOutput->toModControllable(); - newModControllableAudio->midiKnobArray.cloneFrom(&oldModControllableAudio->midiKnobArray); - oldModControllableAudio->midiKnobArray.deleteAtIndex(0, numKnobs); - oldModControllableAudio->ensureInaccessibleParamPresetValuesWithoutKnobsAreZero(this); + auto* old_mca = static_cast(oldOutput->toModControllable()); + if (old_mca != nullptr) { + size_t num_knobs = old_mca->midi_knobs.size(); + if (num_knobs > 0) { + auto& new_mca = static_cast(*newOutput->toModControllable()); + new_mca.midi_knobs.clear(); + std::swap(new_mca.midi_knobs, old_mca->midi_knobs); + old_mca->ensureInaccessibleParamPresetValuesWithoutKnobsAreZero(this); } } } diff --git a/src/deluge/modulation/knob.h b/src/deluge/modulation/knob.h index bfb0447d64..fb99973987 100644 --- a/src/deluge/modulation/knob.h +++ b/src/deluge/modulation/knob.h @@ -23,7 +23,7 @@ class Knob { public: - Knob() {} + Knob() = default; virtual bool isRelative() = 0; virtual bool is14Bit() = 0; @@ -33,7 +33,7 @@ class Knob { class MIDIKnob : public Knob { public: - MIDIKnob() {} + MIDIKnob() = default; bool isRelative() override { return relative; } bool is14Bit() override { return (midiInput.noteOrCC == 128); } bool topValueIs127() override { return (midiInput.noteOrCC < 128 && !relative); } diff --git a/src/deluge/processing/sound/sound.cpp b/src/deluge/processing/sound/sound.cpp index b652eec516..682a9ace67 100644 --- a/src/deluge/processing/sound/sound.cpp +++ b/src/deluge/processing/sound/sound.cpp @@ -930,19 +930,19 @@ Error Sound::readTagFromFileOrError(Deserializer& reader, char const* tagName, P if (p != params::GLOBAL_NONE && p != params::PLACEHOLDER_RANGE) { // Discard any unlikely "range" ones from before V3.2.0, // for complex reasons - ModKnob* newKnob = &modKnobs[k][w]; + ModKnob& new_knob = modKnobs[k][w]; if (s == PatchSource::NOT_AVAILABLE) { - newKnob->paramDescriptor.setToHaveParamOnly(p); + new_knob.paramDescriptor.setToHaveParamOnly(p); } else if (s2 == PatchSource::NOT_AVAILABLE) { - newKnob->paramDescriptor.setToHaveParamAndSource(p, s); + new_knob.paramDescriptor.setToHaveParamAndSource(p, s); } else { - newKnob->paramDescriptor.setToHaveParamAndTwoSources(p, s, s2); + new_knob.paramDescriptor.setToHaveParamAndTwoSources(p, s, s2); } - ensureKnobReferencesCorrectVolume(newKnob); + ensureKnobReferencesCorrectVolume(new_knob); } } @@ -1469,19 +1469,19 @@ Error Sound::readTagFromFileOrError(Deserializer& reader, char const* tagName, P } // Exists for the purpose of potentially correcting an incorrect file as it's loaded -void Sound::ensureKnobReferencesCorrectVolume(Knob* knob) { - int32_t p = knob->paramDescriptor.getJustTheParam(); +void Sound::ensureKnobReferencesCorrectVolume(Knob& knob) { + int32_t p = knob.paramDescriptor.getJustTheParam(); if (p == params::GLOBAL_VOLUME_POST_REVERB_SEND || p == params::GLOBAL_VOLUME_POST_FX || p == params::LOCAL_VOLUME) { - if (knob->paramDescriptor.isJustAParam()) { - knob->paramDescriptor.setToHaveParamOnly(params::GLOBAL_VOLUME_POST_FX); + if (knob.paramDescriptor.isJustAParam()) { + knob.paramDescriptor.setToHaveParamOnly(params::GLOBAL_VOLUME_POST_FX); } - else if (knob->paramDescriptor.getTopLevelSource() == PatchSource::SIDECHAIN) { - knob->paramDescriptor.changeParam(params::GLOBAL_VOLUME_POST_REVERB_SEND); + else if (knob.paramDescriptor.getTopLevelSource() == PatchSource::SIDECHAIN) { + knob.paramDescriptor.changeParam(params::GLOBAL_VOLUME_POST_REVERB_SEND); } else { - knob->paramDescriptor.changeParam(params::LOCAL_VOLUME); + knob.paramDescriptor.changeParam(params::LOCAL_VOLUME); } } } @@ -3150,15 +3150,14 @@ void Sound::ensureParamPresetValueWithoutKnobIsZero(ModelStackWithAutoParam* mod } } - for (int32_t k = 0; k < midiKnobArray.getNumElements(); k++) { - MIDIKnob* knob = midiKnobArray.getElement(k); - if (knob->paramDescriptor.isSetToParamWithNoSource(modelStack->paramId)) { - return; - } - } + bool any_assigned = std::ranges::any_of(midi_knobs, [&](const MIDIKnob& knob) { + return knob.paramDescriptor.isSetToParamWithNoSource(modelStack->paramId); + }); - // If we're here, no knobs were assigned to this param, so make it 0 - modelStack->autoParam->setCurrentValueWithNoReversionOrRecording(modelStack, 0); + // No knobs were assigned to this param, so make it 0 + if (!any_assigned) { + modelStack->autoParam->setCurrentValueWithNoReversionOrRecording(modelStack, 0); + } } void Sound::ensureParamPresetValueWithoutKnobIsZeroWithMinimalDetails(ParamManager* paramManager, int32_t p) { @@ -3178,15 +3177,14 @@ void Sound::ensureParamPresetValueWithoutKnobIsZeroWithMinimalDetails(ParamManag } } - for (int32_t k = 0; k < midiKnobArray.getNumElements(); k++) { - MIDIKnob* knob = midiKnobArray.getElement(k); - if (knob->paramDescriptor.isSetToParamWithNoSource(p)) { - return; - } - } + bool any_assigned = std::ranges::any_of(midi_knobs, [&](const MIDIKnob& knob) { + return knob.paramDescriptor.isSetToParamWithNoSource(p); //< + }); - // If we're here, no knobs were assigned to this param, so make it 0 - param->setCurrentValueBasicForSetup(0); + // No knobs were assigned to this param, so make it 0 + if (!any_assigned) { + param->setCurrentValueBasicForSetup(0); + } } void Sound::doneReadingFromFile() { @@ -3501,8 +3499,7 @@ Error Sound::readFromFile(Deserializer& reader, ModelStackWithModControllable* m doneReadingFromFile(); // Ensure all MIDI knobs reference correct volume... - for (int32_t k = 0; k < midiKnobArray.getNumElements(); k++) { - MIDIKnob* knob = midiKnobArray.getElement(k); + for (MIDIKnob& knob : midi_knobs) { ensureKnobReferencesCorrectVolume(knob); } @@ -5178,14 +5175,14 @@ bool Sound::renderingVoicesInStereo(ModelStackWithSoundFlags* modelStack) { return false; } -ModelStackWithAutoParam* Sound::getParamFromMIDIKnob(MIDIKnob* knob, ModelStackWithThreeMainThings* modelStack) { +ModelStackWithAutoParam* Sound::getParamFromMIDIKnob(MIDIKnob& knob, ModelStackWithThreeMainThings* modelStack) { ParamCollectionSummary* summary; int32_t paramId; - if (knob->paramDescriptor.isJustAParam()) { + if (knob.paramDescriptor.isJustAParam()) { - int32_t p = knob->paramDescriptor.getJustTheParam(); + int32_t p = knob.paramDescriptor.getJustTheParam(); // Unpatched parameter if (p >= params::UNPATCHED_START) { @@ -5202,7 +5199,7 @@ ModelStackWithAutoParam* Sound::getParamFromMIDIKnob(MIDIKnob* knob, ModelStackW // Patch cable strength else { summary = modelStack->paramManager->getPatchCableSetSummary(); - paramId = knob->paramDescriptor.data; + paramId = knob.paramDescriptor.data; } ModelStackWithParamId* modelStackWithParamId = diff --git a/src/deluge/processing/sound/sound.h b/src/deluge/processing/sound/sound.h index 559c513425..17d316ae02 100644 --- a/src/deluge/processing/sound/sound.h +++ b/src/deluge/processing/sound/sound.h @@ -281,7 +281,7 @@ class Sound : public ModControllableAudio { void deleteMultiRange(int32_t s, int32_t r); void prepareForHibernation(); void wontBeRenderedForAWhile() override; - ModelStackWithAutoParam* getParamFromMIDIKnob(MIDIKnob* knob, ModelStackWithThreeMainThings* modelStack) final; + ModelStackWithAutoParam* getParamFromMIDIKnob(MIDIKnob& knob, ModelStackWithThreeMainThings* modelStack) final; virtual ArpeggiatorBase* getArp() = 0; void possiblySetupDefaultExpressionPatching(ParamManager* paramManager); @@ -302,7 +302,7 @@ class Sound : public ModControllableAudio { void setupUnisonDetuners(ModelStackWithSoundFlags* modelStack); void setupUnisonStereoSpread(); void calculateEffectiveVolume(); - void ensureKnobReferencesCorrectVolume(Knob* knob); + void ensureKnobReferencesCorrectVolume(Knob& knob); Error readTagFromFileOrError(Deserializer& reader, char const* tagName, ParamManagerForTimeline* paramManager, int32_t readAutomationUpToPos, ArpeggiatorSettings* arpSettings, Song* song);