Implement the LFOs v1
This commit is contained in:
parent
ef1a548d98
commit
7f2daa24e7
10 changed files with 245 additions and 8 deletions
|
|
@ -101,6 +101,9 @@ extern const OpcodeSpec<float> pitchMod { 0.0f, Range<float>(-2400.0f, 2400.0f),
|
||||||
extern const OpcodeSpec<float> bendUp { 200.0f, Range<float>(-12000.0f, 12000.0f), 0 };
|
extern const OpcodeSpec<float> bendUp { 200.0f, Range<float>(-12000.0f, 12000.0f), 0 };
|
||||||
extern const OpcodeSpec<float> bendDown { -200.0f, Range<float>(-12000.0f, 12000.0f), 0 };
|
extern const OpcodeSpec<float> bendDown { -200.0f, Range<float>(-12000.0f, 12000.0f), 0 };
|
||||||
extern const OpcodeSpec<float> bendStep { 1.0f, Range<float>(1.0f, 1200.0f), 0 };
|
extern const OpcodeSpec<float> bendStep { 1.0f, Range<float>(1.0f, 1200.0f), 0 };
|
||||||
|
extern const OpcodeSpec<float> ampLFODepth { 0.0f, Range<float>(-10.0f, 10.0f), 0 };
|
||||||
|
extern const OpcodeSpec<float> pitchLFODepth { 0.0f, Range<float>(-1200.0f, 1200.0f), 0 };
|
||||||
|
extern const OpcodeSpec<float> filLFODepth { 0.0f, Range<float>(-1200.0f, 1200.0f), 0 };
|
||||||
extern const OpcodeSpec<float> lfoFreq { 0.0f, Range<float>(0.0f, 100.0f), 0 };
|
extern const OpcodeSpec<float> lfoFreq { 0.0f, Range<float>(0.0f, 100.0f), 0 };
|
||||||
extern const OpcodeSpec<float> lfoFreqMod { 0.0f, Range<float>(-100.0f, 100.0f), 0 };
|
extern const OpcodeSpec<float> lfoFreqMod { 0.0f, Range<float>(-100.0f, 100.0f), 0 };
|
||||||
extern const OpcodeSpec<float> lfoBeats { 0.0f, Range<float>(0.0f, 1000.0f), 0 };
|
extern const OpcodeSpec<float> lfoBeats { 0.0f, Range<float>(0.0f, 1000.0f), 0 };
|
||||||
|
|
|
||||||
|
|
@ -209,6 +209,9 @@ namespace Default
|
||||||
extern const OpcodeSpec<float> bendUp;
|
extern const OpcodeSpec<float> bendUp;
|
||||||
extern const OpcodeSpec<float> bendDown;
|
extern const OpcodeSpec<float> bendDown;
|
||||||
extern const OpcodeSpec<float> bendStep;
|
extern const OpcodeSpec<float> bendStep;
|
||||||
|
extern const OpcodeSpec<float> ampLFODepth;
|
||||||
|
extern const OpcodeSpec<float> pitchLFODepth;
|
||||||
|
extern const OpcodeSpec<float> filLFODepth;
|
||||||
extern const OpcodeSpec<float> lfoFreq;
|
extern const OpcodeSpec<float> lfoFreq;
|
||||||
extern const OpcodeSpec<float> lfoFreqMod;
|
extern const OpcodeSpec<float> lfoFreqMod;
|
||||||
extern const OpcodeSpec<float> lfoBeats;
|
extern const OpcodeSpec<float> lfoBeats;
|
||||||
|
|
|
||||||
|
|
@ -780,6 +780,34 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Amplitude LFO
|
||||||
|
if (absl::StartsWith(opcode.name, "amplfo_")) {
|
||||||
|
if (parseLFOOpcode(opcode, amplitudeLFO)) {
|
||||||
|
getOrCreateConnection(
|
||||||
|
ModKey::createNXYZ(ModId::AmpLFO, id),
|
||||||
|
ModKey::createNXYZ(ModId::Volume, id));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Pitch LFO
|
||||||
|
if (absl::StartsWith(opcode.name, "pitchlfo_")) {
|
||||||
|
if (parseLFOOpcode(opcode, pitchLFO)) {
|
||||||
|
getOrCreateConnection(
|
||||||
|
ModKey::createNXYZ(ModId::PitchLFO, id),
|
||||||
|
ModKey::createNXYZ(ModId::Pitch, id));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Filter LFO
|
||||||
|
if (absl::StartsWith(opcode.name, "fillfo_")) {
|
||||||
|
if (parseLFOOpcode(opcode, filterLFO)) {
|
||||||
|
getOrCreateConnection(
|
||||||
|
ModKey::createNXYZ(ModId::FilLFO, id),
|
||||||
|
ModKey::createNXYZ(ModId::FilCutoff, id));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
const std::string letterOnlyName = opcode.getLetterOnlyName();
|
const std::string letterOnlyName = opcode.getLetterOnlyName();
|
||||||
|
|
||||||
|
|
@ -802,6 +830,109 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool sfz::Region::parseLFOOpcode(const Opcode& opcode, LFODescription& lfo)
|
||||||
|
{
|
||||||
|
#define case_any_lfo(param) \
|
||||||
|
case hash("amplfo_" param): \
|
||||||
|
case hash("pitchlfo_" param): \
|
||||||
|
case hash("fillfo_" param) \
|
||||||
|
|
||||||
|
#define case_any_lfo_any_ccN(param) \
|
||||||
|
case_any_ccN("amplfo_" param): \
|
||||||
|
case_any_ccN("pitchlfo_" param): \
|
||||||
|
case_any_ccN("fillfo_" param) \
|
||||||
|
|
||||||
|
//
|
||||||
|
ModKey sourceKey;
|
||||||
|
ModKey targetKey;
|
||||||
|
OpcodeSpec<float> depthSpec;
|
||||||
|
|
||||||
|
if (absl::StartsWith(opcode.name, "amplfo_")) {
|
||||||
|
sourceKey = ModKey::createNXYZ(ModId::AmpLFO, id);
|
||||||
|
targetKey = ModKey::createNXYZ(ModId::Volume, id);
|
||||||
|
lfo.freqKey = ModKey::createNXYZ(ModId::AmpLFOFrequency, id);
|
||||||
|
depthSpec = Default::ampLFODepth;
|
||||||
|
}
|
||||||
|
else if (absl::StartsWith(opcode.name, "pitchlfo_")) {
|
||||||
|
sourceKey = ModKey::createNXYZ(ModId::PitchLFO, id);
|
||||||
|
targetKey = ModKey::createNXYZ(ModId::Pitch, id);
|
||||||
|
lfo.freqKey = ModKey::createNXYZ(ModId::PitchLFOFrequency, id);
|
||||||
|
depthSpec = Default::pitchLFODepth;
|
||||||
|
}
|
||||||
|
else if (absl::StartsWith(opcode.name, "fillfo_")) {
|
||||||
|
sourceKey = ModKey::createNXYZ(ModId::FilLFO, id);
|
||||||
|
targetKey = ModKey::createNXYZ(ModId::FilCutoff, id);
|
||||||
|
lfo.freqKey = ModKey::createNXYZ(ModId::FilLFOFrequency, id);
|
||||||
|
depthSpec = Default::filLFODepth;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ASSERTFALSE;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
switch (opcode.lettersOnlyHash) {
|
||||||
|
|
||||||
|
case_any_lfo("delay"):
|
||||||
|
lfo.delay = opcode.read(Default::lfoDelay);
|
||||||
|
break;
|
||||||
|
case_any_lfo("depth"):
|
||||||
|
getOrCreateConnection(sourceKey, targetKey).sourceDepth = opcode.read(depthSpec);
|
||||||
|
break;
|
||||||
|
case_any_lfo_any_ccN("depth"): // also depthcc&
|
||||||
|
// TODO(jpc) LFO v1
|
||||||
|
break;
|
||||||
|
case_any_lfo("depthchanaft"):
|
||||||
|
// TODO(jpc) LFO v1
|
||||||
|
break;
|
||||||
|
case_any_lfo("depthpolyaft"):
|
||||||
|
// TODO(jpc) LFO v1
|
||||||
|
break;
|
||||||
|
case_any_lfo("fade"):
|
||||||
|
lfo.fade = opcode.read(Default::lfoFade);
|
||||||
|
break;
|
||||||
|
case_any_lfo("freq"):
|
||||||
|
lfo.freq = opcode.read(Default::lfoFreq);
|
||||||
|
break;
|
||||||
|
case_any_lfo_any_ccN("freq"): // also freqcc&
|
||||||
|
processGenericCc(opcode, Default::lfoFreqMod, lfo.freqKey);
|
||||||
|
break;
|
||||||
|
case_any_lfo("freqchanaft"):
|
||||||
|
// TODO(jpc) LFO v1
|
||||||
|
break;
|
||||||
|
case_any_lfo("freqpolyaft"):
|
||||||
|
// TODO(jpc) LFO v1
|
||||||
|
break;
|
||||||
|
|
||||||
|
// sfizz extension
|
||||||
|
case_any_lfo("wave"):
|
||||||
|
lfo.sub[0].wave = opcode.read(Default::lfoWave);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef case_any_lfo
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sfz::Region::parseLFOOpcode(const Opcode& opcode, absl::optional<LFODescription>& lfo)
|
||||||
|
{
|
||||||
|
bool create = lfo == absl::nullopt;
|
||||||
|
if (create) {
|
||||||
|
lfo = LFODescription();
|
||||||
|
lfo->sub[0].wave = LFOWave::Sine; // the LFO v1 default
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parsed = parseLFOOpcode(opcode, *lfo);
|
||||||
|
if (!parsed && create)
|
||||||
|
lfo = absl::nullopt;
|
||||||
|
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
bool sfz::Region::parseEGOpcode(const Opcode& opcode, EGDescription& eg)
|
bool sfz::Region::parseEGOpcode(const Opcode& opcode, EGDescription& eg)
|
||||||
{
|
{
|
||||||
#define case_any_eg(param) \
|
#define case_any_eg(param) \
|
||||||
|
|
|
||||||
|
|
@ -246,6 +246,26 @@ struct Region {
|
||||||
* @return false
|
* @return false
|
||||||
*/
|
*/
|
||||||
bool parseOpcode(const Opcode& opcode);
|
bool parseOpcode(const Opcode& opcode);
|
||||||
|
/**
|
||||||
|
* @brief Parse a opcode which is specific to a particular SFZv1 LFO:
|
||||||
|
* amplfo, pitchlfo, fillfo.
|
||||||
|
*
|
||||||
|
* @param opcode
|
||||||
|
* @param lfo
|
||||||
|
* @return true if the opcode was properly read and stored.
|
||||||
|
* @return false
|
||||||
|
*/
|
||||||
|
bool parseLFOOpcode(const Opcode& opcode, LFODescription& lfo);
|
||||||
|
/**
|
||||||
|
* @brief Parse a opcode which is specific to a particular SFZv1 LFO:
|
||||||
|
* amplfo, pitchlfo, fillfo.
|
||||||
|
*
|
||||||
|
* @param opcode
|
||||||
|
* @param lfo
|
||||||
|
* @return true if the opcode was properly read and stored.
|
||||||
|
* @return false
|
||||||
|
*/
|
||||||
|
bool parseLFOOpcode(const Opcode& opcode, absl::optional<LFODescription>& lfo);
|
||||||
/**
|
/**
|
||||||
* @brief Parse a opcode which is specific to a particular SFZv1 EG:
|
* @brief Parse a opcode which is specific to a particular SFZv1 EG:
|
||||||
* ampeg, pitcheg, fileg.
|
* ampeg, pitcheg, fileg.
|
||||||
|
|
@ -457,6 +477,9 @@ struct Region {
|
||||||
|
|
||||||
// LFOs
|
// LFOs
|
||||||
std::vector<LFODescription> lfos;
|
std::vector<LFODescription> lfos;
|
||||||
|
absl::optional<LFODescription> amplitudeLFO;
|
||||||
|
absl::optional<LFODescription> pitchLFO;
|
||||||
|
absl::optional<LFODescription> filterLFO;
|
||||||
|
|
||||||
bool hasStereoSample { false };
|
bool hasStereoSample { false };
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -551,6 +551,9 @@ void Synth::Impl::finalizeSfzLoad()
|
||||||
size_t maxFlexEGs { 0 };
|
size_t maxFlexEGs { 0 };
|
||||||
bool havePitchEG { false };
|
bool havePitchEG { false };
|
||||||
bool haveFilterEG { false };
|
bool haveFilterEG { false };
|
||||||
|
bool haveAmplitudeLFO { false };
|
||||||
|
bool havePitchLFO { false };
|
||||||
|
bool haveFilterLFO { false };
|
||||||
|
|
||||||
FlexEGs::clearUnusedCurves();
|
FlexEGs::clearUnusedCurves();
|
||||||
|
|
||||||
|
|
@ -683,6 +686,9 @@ void Synth::Impl::finalizeSfzLoad()
|
||||||
maxFlexEGs = max(maxFlexEGs, region->flexEGs.size());
|
maxFlexEGs = max(maxFlexEGs, region->flexEGs.size());
|
||||||
havePitchEG = havePitchEG || region->pitchEG != absl::nullopt;
|
havePitchEG = havePitchEG || region->pitchEG != absl::nullopt;
|
||||||
haveFilterEG = haveFilterEG || region->filterEG != absl::nullopt;
|
haveFilterEG = haveFilterEG || region->filterEG != absl::nullopt;
|
||||||
|
haveAmplitudeLFO = haveAmplitudeLFO || region->amplitudeLFO != absl::nullopt;
|
||||||
|
havePitchLFO = havePitchLFO || region->pitchLFO != absl::nullopt;
|
||||||
|
haveFilterLFO = haveFilterLFO || region->filterLFO != absl::nullopt;
|
||||||
|
|
||||||
++currentRegionIndex;
|
++currentRegionIndex;
|
||||||
}
|
}
|
||||||
|
|
@ -731,6 +737,9 @@ void Synth::Impl::finalizeSfzLoad()
|
||||||
settingsPerVoice_.maxFlexEGs = maxFlexEGs;
|
settingsPerVoice_.maxFlexEGs = maxFlexEGs;
|
||||||
settingsPerVoice_.havePitchEG = havePitchEG;
|
settingsPerVoice_.havePitchEG = havePitchEG;
|
||||||
settingsPerVoice_.haveFilterEG = haveFilterEG;
|
settingsPerVoice_.haveFilterEG = haveFilterEG;
|
||||||
|
settingsPerVoice_.haveAmplitudeLFO = haveAmplitudeLFO;
|
||||||
|
settingsPerVoice_.havePitchLFO = havePitchLFO;
|
||||||
|
settingsPerVoice_.haveFilterLFO = haveFilterLFO;
|
||||||
|
|
||||||
applySettingsPerVoice();
|
applySettingsPerVoice();
|
||||||
|
|
||||||
|
|
@ -1579,6 +1588,9 @@ void Synth::Impl::applySettingsPerVoice()
|
||||||
voice.setMaxFlexEGsPerVoice(settingsPerVoice_.maxFlexEGs);
|
voice.setMaxFlexEGsPerVoice(settingsPerVoice_.maxFlexEGs);
|
||||||
voice.setPitchEGEnabledPerVoice(settingsPerVoice_.havePitchEG);
|
voice.setPitchEGEnabledPerVoice(settingsPerVoice_.havePitchEG);
|
||||||
voice.setFilterEGEnabledPerVoice(settingsPerVoice_.haveFilterEG);
|
voice.setFilterEGEnabledPerVoice(settingsPerVoice_.haveFilterEG);
|
||||||
|
voice.setAmplitudeLFOEnabledPerVoice(settingsPerVoice_.haveAmplitudeLFO);
|
||||||
|
voice.setPitchLFOEnabledPerVoice(settingsPerVoice_.havePitchLFO);
|
||||||
|
voice.setFilterLFOEnabledPerVoice(settingsPerVoice_.haveFilterLFO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1605,6 +1617,9 @@ void Synth::Impl::setupModMatrix()
|
||||||
case ModId::Controller:
|
case ModId::Controller:
|
||||||
gen = genController_.get();
|
gen = genController_.get();
|
||||||
break;
|
break;
|
||||||
|
case ModId::AmpLFO:
|
||||||
|
case ModId::PitchLFO:
|
||||||
|
case ModId::FilLFO:
|
||||||
case ModId::LFO:
|
case ModId::LFO:
|
||||||
gen = genLFO_.get();
|
gen = genLFO_.get();
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -283,6 +283,9 @@ struct Synth::Impl final: public Parser::Listener {
|
||||||
size_t maxFlexEGs { 0 };
|
size_t maxFlexEGs { 0 };
|
||||||
bool havePitchEG { false };
|
bool havePitchEG { false };
|
||||||
bool haveFilterEG { false };
|
bool haveFilterEG { false };
|
||||||
|
bool haveAmplitudeLFO { false };
|
||||||
|
bool havePitchLFO { false };
|
||||||
|
bool haveFilterLFO { false };
|
||||||
} settingsPerVoice_;
|
} settingsPerVoice_;
|
||||||
|
|
||||||
Duration dispatchDuration_ { 0 };
|
Duration dispatchDuration_ { 0 };
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,12 @@ int ModIds::flags(ModId id) noexcept
|
||||||
return kModIsPerVoice|kModIsAdditive;
|
return kModIsPerVoice|kModIsAdditive;
|
||||||
case ModId::OscillatorModDepth:
|
case ModId::OscillatorModDepth:
|
||||||
return kModIsPerVoice|kModIsPercentMultiplicative;
|
return kModIsPerVoice|kModIsPercentMultiplicative;
|
||||||
|
case ModId::AmpLFOFrequency:
|
||||||
|
return kModIsPerVoice|kModIsAdditive;
|
||||||
|
case ModId::PitchLFOFrequency:
|
||||||
|
return kModIsPerVoice|kModIsAdditive;
|
||||||
|
case ModId::FilLFOFrequency:
|
||||||
|
return kModIsPerVoice|kModIsAdditive;
|
||||||
case ModId::LFOFrequency:
|
case ModId::LFOFrequency:
|
||||||
return kModIsPerVoice|kModIsAdditive;
|
return kModIsPerVoice|kModIsAdditive;
|
||||||
case ModId::LFOBeats:
|
case ModId::LFOBeats:
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,9 @@ enum class ModId : int {
|
||||||
EqBandwidth,
|
EqBandwidth,
|
||||||
OscillatorDetune,
|
OscillatorDetune,
|
||||||
OscillatorModDepth,
|
OscillatorModDepth,
|
||||||
|
AmpLFOFrequency,
|
||||||
|
PitchLFOFrequency,
|
||||||
|
FilLFOFrequency,
|
||||||
LFOFrequency,
|
LFOFrequency,
|
||||||
LFOBeats,
|
LFOBeats,
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -144,6 +144,12 @@ std::string ModKey::toString() const
|
||||||
return absl::StrCat("OscillatorDetune {", region_.number(), ", N=", 1 + params_.N, "}");
|
return absl::StrCat("OscillatorDetune {", region_.number(), ", N=", 1 + params_.N, "}");
|
||||||
case ModId::OscillatorModDepth:
|
case ModId::OscillatorModDepth:
|
||||||
return absl::StrCat("OscillatorModDepth {", region_.number(), ", N=", 1 + params_.N, "}");
|
return absl::StrCat("OscillatorModDepth {", region_.number(), ", N=", 1 + params_.N, "}");
|
||||||
|
case ModId::AmpLFOFrequency:
|
||||||
|
return absl::StrCat("AmplitudeLFOFrequency {", region_.number(), "}");
|
||||||
|
case ModId::PitchLFOFrequency:
|
||||||
|
return absl::StrCat("PitchLFOFrequency {", region_.number(), "}");
|
||||||
|
case ModId::FilLFOFrequency:
|
||||||
|
return absl::StrCat("FilterLFOFrequency {", region_.number(), "}");
|
||||||
case ModId::LFOFrequency:
|
case ModId::LFOFrequency:
|
||||||
return absl::StrCat("LFOFrequency {", region_.number(), ", N=", 1 + params_.N, "}");
|
return absl::StrCat("LFOFrequency {", region_.number(), ", N=", 1 + params_.N, "}");
|
||||||
case ModId::LFOBeats:
|
case ModId::LFOBeats:
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,6 @@ LFOSource::LFOSource(VoiceManager& manager)
|
||||||
|
|
||||||
void LFOSource::init(const ModKey& sourceKey, NumericId<Voice> voiceId, unsigned delay)
|
void LFOSource::init(const ModKey& sourceKey, NumericId<Voice> voiceId, unsigned delay)
|
||||||
{
|
{
|
||||||
unsigned lfoIndex = sourceKey.parameters().N;
|
|
||||||
|
|
||||||
Voice* voice = voiceManager_.getVoiceById(voiceId);
|
Voice* voice = voiceManager_.getVoiceById(voiceId);
|
||||||
if (!voice) {
|
if (!voice) {
|
||||||
ASSERTFALSE;
|
ASSERTFALSE;
|
||||||
|
|
@ -30,13 +28,39 @@ void LFOSource::init(const ModKey& sourceKey, NumericId<Voice> voiceId, unsigned
|
||||||
}
|
}
|
||||||
|
|
||||||
const Region* region = voice->getRegion();
|
const Region* region = voice->getRegion();
|
||||||
if (lfoIndex >= region->lfos.size()) {
|
LFO* lfo = nullptr;
|
||||||
|
const LFODescription* desc = nullptr;
|
||||||
|
|
||||||
|
switch (sourceKey.id()) {
|
||||||
|
case ModId::AmpLFO:
|
||||||
|
lfo = voice->getAmplitudeLFO();
|
||||||
|
desc = &*region->amplitudeLFO;
|
||||||
|
break;
|
||||||
|
case ModId::PitchLFO:
|
||||||
|
lfo = voice->getPitchLFO();
|
||||||
|
desc = &*region->pitchLFO;
|
||||||
|
break;
|
||||||
|
case ModId::FilLFO:
|
||||||
|
lfo = voice->getFilterLFO();
|
||||||
|
desc = &*region->filterLFO;
|
||||||
|
break;
|
||||||
|
case ModId::LFO:
|
||||||
|
{
|
||||||
|
unsigned lfoIndex = sourceKey.parameters().N;
|
||||||
|
if (lfoIndex >= region->lfos.size()) {
|
||||||
|
ASSERTFALSE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lfo = voice->getLFO(lfoIndex);
|
||||||
|
desc = ®ion->lfos[lfoIndex];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
ASSERTFALSE;
|
ASSERTFALSE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LFO* lfo = voice->getLFO(lfoIndex);
|
lfo->configure(desc);
|
||||||
lfo->configure(®ion->lfos[lfoIndex]);
|
|
||||||
lfo->start(delay);
|
lfo->start(delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -52,13 +76,33 @@ void LFOSource::generate(const ModKey& sourceKey, NumericId<Voice> voiceId, absl
|
||||||
}
|
}
|
||||||
|
|
||||||
const Region* region = voice->getRegion();
|
const Region* region = voice->getRegion();
|
||||||
if (lfoIndex >= region->lfos.size()) {
|
LFO* lfo = nullptr;
|
||||||
|
|
||||||
|
switch (sourceKey.id()) {
|
||||||
|
case ModId::AmpLFO:
|
||||||
|
lfo = voice->getAmplitudeLFO();
|
||||||
|
break;
|
||||||
|
case ModId::PitchLFO:
|
||||||
|
lfo = voice->getPitchLFO();
|
||||||
|
break;
|
||||||
|
case ModId::FilLFO:
|
||||||
|
lfo = voice->getFilterLFO();
|
||||||
|
break;
|
||||||
|
case ModId::LFO:
|
||||||
|
{
|
||||||
|
if (lfoIndex >= region->lfos.size()) {
|
||||||
|
ASSERTFALSE;
|
||||||
|
fill(buffer, 0.0f);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lfo = voice->getLFO(lfoIndex);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
ASSERTFALSE;
|
ASSERTFALSE;
|
||||||
fill(buffer, 0.0f);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LFO* lfo = voice->getLFO(lfoIndex);
|
|
||||||
lfo->process(buffer);
|
lfo->process(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue