Refactor the opcode handling for LFO and EG
This commit is contained in:
parent
1e3b85827e
commit
97c9411f8d
4 changed files with 444 additions and 542 deletions
|
|
@ -53,6 +53,28 @@ static absl::string_view extractBackInteger(absl::string_view opcodeName)
|
|||
return opcodeName.substr(i);
|
||||
}
|
||||
|
||||
std::string Opcode::getLetterOnlyName() const
|
||||
{
|
||||
absl::string_view name { this->name };
|
||||
|
||||
std::string letterOnlyName;
|
||||
letterOnlyName.reserve(name.size());
|
||||
|
||||
bool charWasDigit = false;
|
||||
for (unsigned char c : name) {
|
||||
bool charIsDigit = absl::ascii_isdigit(c);
|
||||
|
||||
if (!charIsDigit)
|
||||
letterOnlyName.push_back(c);
|
||||
else if (!charWasDigit)
|
||||
letterOnlyName.push_back('&');
|
||||
|
||||
charWasDigit = charIsDigit;
|
||||
}
|
||||
|
||||
return letterOnlyName;
|
||||
}
|
||||
|
||||
std::string Opcode::getDerivedName(OpcodeCategory newCategory, unsigned number) const
|
||||
{
|
||||
std::string derivedName(name);
|
||||
|
|
|
|||
|
|
@ -82,6 +82,12 @@ struct Opcode {
|
|||
*/
|
||||
Opcode cleanUp(OpcodeScope scope) const;
|
||||
|
||||
/**
|
||||
* @brief Calculate a letter-only name, replacing any digit sequence with
|
||||
* in the opcode name with a single ampersand character.
|
||||
*/
|
||||
std::string getLetterOnlyName() const;
|
||||
|
||||
/*
|
||||
* @brief Get the derived opcode name to convert it to another category.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include "modulations/ModId.h"
|
||||
#include "absl/strings/str_replace.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/match.h"
|
||||
#include "absl/algorithm/container.h"
|
||||
#include <random>
|
||||
#include <cassert>
|
||||
|
|
@ -45,32 +46,18 @@ sfz::Region::Region(int regionNumber, const MidiState& midiState, absl::string_v
|
|||
amplitudeEG.release = Default::egRelease;
|
||||
}
|
||||
|
||||
// Helper for ccN processing
|
||||
#define case_any_ccN(x) \
|
||||
case hash(x "_oncc&"): \
|
||||
case hash(x "_curvecc&"): \
|
||||
case hash(x "_stepcc&"): \
|
||||
case hash(x "_smoothcc&")
|
||||
|
||||
bool sfz::Region::parseOpcode(const Opcode& rawOpcode)
|
||||
{
|
||||
const Opcode opcode = rawOpcode.cleanUp(kOpcodeScopeRegion);
|
||||
|
||||
switch (opcode.lettersOnlyHash) {
|
||||
// Helper for ccN processing
|
||||
#define case_any_ccN(x) \
|
||||
case hash(x "_oncc&"): \
|
||||
case hash(x "_curvecc&"): \
|
||||
case hash(x "_stepcc&"): \
|
||||
case hash(x "_smoothcc&")
|
||||
|
||||
#define LFO_EG_filter_EQ_target(sourceKey, targetKey, spec) \
|
||||
{ \
|
||||
const auto number = opcode.parameters.front(); \
|
||||
if (number == 0) \
|
||||
return false; \
|
||||
\
|
||||
const auto index = opcode.parameters.size() == 2 ? opcode.parameters.back() - 1 : 0; \
|
||||
if (!extendIfNecessary(filters, index + 1, Default::numFilters)) \
|
||||
return false; \
|
||||
\
|
||||
const ModKey source = ModKey::createNXYZ(sourceKey, id, number - 1); \
|
||||
const ModKey target = ModKey::createNXYZ(targetKey, id, index); \
|
||||
getOrCreateConnection(source, target).sourceDepth = opcode.read(spec); \
|
||||
}
|
||||
|
||||
// Sound source: sample playback
|
||||
case hash("sample"):
|
||||
|
|
@ -747,523 +734,6 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode)
|
|||
bendSmooth = opcode.read(Default::smoothCC);
|
||||
break;
|
||||
|
||||
// Modulation: LFO
|
||||
case hash("lfo&_freq"):
|
||||
{
|
||||
const auto lfoNumber = opcode.parameters.front();
|
||||
if (lfoNumber == 0)
|
||||
return false;
|
||||
if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs))
|
||||
return false;
|
||||
lfos[lfoNumber - 1].freq = opcode.read(Default::lfoFreq);
|
||||
}
|
||||
break;
|
||||
case_any_ccN("lfo&_freq"):
|
||||
{
|
||||
const auto lfoNumber = opcode.parameters.front();
|
||||
if (lfoNumber == 0)
|
||||
return false;
|
||||
if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs))
|
||||
return false;
|
||||
processGenericCc(opcode, Default::lfoFreqMod, ModKey::createNXYZ(ModId::LFOFrequency, id, lfoNumber - 1));
|
||||
}
|
||||
break;
|
||||
case hash("lfo&_beats"):
|
||||
{
|
||||
const auto lfoNumber = opcode.parameters.front();
|
||||
if (lfoNumber == 0)
|
||||
return false;
|
||||
if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs))
|
||||
return false;
|
||||
lfos[lfoNumber - 1].beats = opcode.read(Default::lfoBeats);
|
||||
}
|
||||
break;
|
||||
case_any_ccN("lfo&_beats"):
|
||||
{
|
||||
const auto lfoNumber = opcode.parameters.front();
|
||||
if (lfoNumber == 0)
|
||||
return false;
|
||||
if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs))
|
||||
return false;
|
||||
processGenericCc(opcode, Default::lfoBeatsMod, ModKey::createNXYZ(ModId::LFOBeats, id, lfoNumber - 1));
|
||||
}
|
||||
break;
|
||||
case hash("lfo&_phase"):
|
||||
{
|
||||
const auto lfoNumber = opcode.parameters.front();
|
||||
if (lfoNumber == 0)
|
||||
return false;
|
||||
if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs))
|
||||
return false;
|
||||
lfos[lfoNumber - 1].phase0 = opcode.read(Default::lfoPhase);
|
||||
}
|
||||
break;
|
||||
case hash("lfo&_delay"):
|
||||
{
|
||||
const auto lfoNumber = opcode.parameters.front();
|
||||
if (lfoNumber == 0)
|
||||
return false;
|
||||
if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs))
|
||||
return false;
|
||||
lfos[lfoNumber - 1].delay = opcode.read(Default::lfoDelay);
|
||||
}
|
||||
break;
|
||||
case hash("lfo&_fade"):
|
||||
{
|
||||
const auto lfoNumber = opcode.parameters.front();
|
||||
if (lfoNumber == 0)
|
||||
return false;
|
||||
if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs))
|
||||
return false;
|
||||
lfos[lfoNumber - 1].fade = opcode.read(Default::lfoFade);
|
||||
}
|
||||
break;
|
||||
case hash("lfo&_count"):
|
||||
{
|
||||
const auto lfoNumber = opcode.parameters.front();
|
||||
if (lfoNumber == 0)
|
||||
return false;
|
||||
if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs))
|
||||
return false;
|
||||
lfos[lfoNumber - 1].count = opcode.read(Default::lfoCount);
|
||||
}
|
||||
break;
|
||||
case hash("lfo&_steps"):
|
||||
{
|
||||
const auto lfoNumber = opcode.parameters.front();
|
||||
if (lfoNumber == 0)
|
||||
return false;
|
||||
if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs))
|
||||
return false;
|
||||
if (!lfos[lfoNumber - 1].seq)
|
||||
lfos[lfoNumber - 1].seq = LFODescription::StepSequence();
|
||||
lfos[lfoNumber - 1].seq->steps.resize(opcode.read(Default::lfoSteps));
|
||||
}
|
||||
break;
|
||||
case hash("lfo&_step&"):
|
||||
{
|
||||
const auto lfoNumber = opcode.parameters.front();
|
||||
const auto stepNumber = opcode.parameters[1];
|
||||
if (lfoNumber == 0 || stepNumber == 0 || stepNumber > config::maxLFOSteps)
|
||||
return false;
|
||||
if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs))
|
||||
return false;
|
||||
if (!lfos[lfoNumber - 1].seq)
|
||||
lfos[lfoNumber - 1].seq = LFODescription::StepSequence();
|
||||
if (!extendIfNecessary(lfos[lfoNumber - 1].seq->steps, stepNumber, Default::numLFOSteps))
|
||||
return false;
|
||||
lfos[lfoNumber - 1].seq->steps[stepNumber - 1] = opcode.read(Default::lfoStepX);
|
||||
}
|
||||
break;
|
||||
case hash("lfo&_wave&"): // also lfo&_wave
|
||||
{
|
||||
const auto lfoNumber = opcode.parameters.front();
|
||||
const auto subNumber = opcode.parameters[1];
|
||||
if (lfoNumber == 0 || subNumber == 0 || subNumber > config::maxLFOSubs)
|
||||
return false;
|
||||
if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs))
|
||||
return false;
|
||||
if (!extendIfNecessary(lfos[lfoNumber - 1].sub, subNumber, Default::numLFOSubs))
|
||||
return false;
|
||||
lfos[lfoNumber - 1].sub[subNumber - 1].wave = opcode.read(Default::lfoWave);
|
||||
}
|
||||
break;
|
||||
case hash("lfo&_offset&"): // also lfo&_offset
|
||||
{
|
||||
const auto lfoNumber = opcode.parameters.front();
|
||||
const auto subNumber = opcode.parameters[1];
|
||||
if (lfoNumber == 0 || subNumber == 0 || subNumber > config::maxLFOSubs)
|
||||
return false;
|
||||
if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs))
|
||||
return false;
|
||||
if (!extendIfNecessary(lfos[lfoNumber - 1].sub, subNumber, Default::numLFOSubs))
|
||||
return false;
|
||||
lfos[lfoNumber - 1].sub[subNumber - 1].offset = opcode.read(Default::lfoOffset);
|
||||
}
|
||||
break;
|
||||
case hash("lfo&_ratio&"): // also lfo&_ratio
|
||||
{
|
||||
const auto lfoNumber = opcode.parameters.front();
|
||||
const auto subNumber = opcode.parameters[1];
|
||||
if (lfoNumber == 0 || subNumber == 0 || subNumber > config::maxLFOSubs)
|
||||
return false;
|
||||
if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs))
|
||||
return false;
|
||||
if (!extendIfNecessary(lfos[lfoNumber - 1].sub, subNumber, Default::numLFOSubs))
|
||||
return false;
|
||||
lfos[lfoNumber - 1].sub[subNumber - 1].ratio = opcode.read(Default::lfoRatio);
|
||||
}
|
||||
break;
|
||||
case hash("lfo&_scale&"): // also lfo&_scale
|
||||
{
|
||||
const auto lfoNumber = opcode.parameters.front();
|
||||
const auto subNumber = opcode.parameters[1];
|
||||
if (lfoNumber == 0 || subNumber == 0 || subNumber > config::maxLFOSubs)
|
||||
return false;
|
||||
if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs))
|
||||
return false;
|
||||
if (!extendIfNecessary(lfos[lfoNumber - 1].sub, subNumber, Default::numLFOSubs))
|
||||
return false;
|
||||
lfos[lfoNumber - 1].sub[subNumber - 1].scale = opcode.read(Default::lfoScale);
|
||||
}
|
||||
break;
|
||||
|
||||
// Modulation: LFO (targets)
|
||||
case hash("lfo&_amplitude"):
|
||||
{
|
||||
const auto lfoNumber = opcode.parameters.front();
|
||||
if (lfoNumber == 0)
|
||||
return false;
|
||||
const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1);
|
||||
const ModKey target = ModKey::createNXYZ(ModId::Amplitude, id);
|
||||
getOrCreateConnection(source, target).sourceDepth =
|
||||
opcode.read(Default::amplitudeMod);
|
||||
}
|
||||
break;
|
||||
case hash("lfo&_pan"):
|
||||
{
|
||||
const auto lfoNumber = opcode.parameters.front();
|
||||
if (lfoNumber == 0)
|
||||
return false;
|
||||
const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1);
|
||||
const ModKey target = ModKey::createNXYZ(ModId::Pan, id);
|
||||
getOrCreateConnection(source, target).sourceDepth =
|
||||
opcode.read(Default::panMod);
|
||||
}
|
||||
break;
|
||||
case hash("lfo&_width"):
|
||||
{
|
||||
const auto lfoNumber = opcode.parameters.front();
|
||||
if (lfoNumber == 0)
|
||||
return false;
|
||||
const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1);
|
||||
const ModKey target = ModKey::createNXYZ(ModId::Width, id);
|
||||
getOrCreateConnection(source, target).sourceDepth =
|
||||
opcode.read(Default::widthMod);
|
||||
}
|
||||
break;
|
||||
case hash("lfo&_position"): // sfizz extension
|
||||
{
|
||||
const auto lfoNumber = opcode.parameters.front();
|
||||
if (lfoNumber == 0)
|
||||
return false;
|
||||
const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1);
|
||||
const ModKey target = ModKey::createNXYZ(ModId::Position, id);
|
||||
getOrCreateConnection(source, target).sourceDepth =
|
||||
opcode.read(Default::positionMod);
|
||||
}
|
||||
break;
|
||||
case hash("lfo&_pitch"):
|
||||
{
|
||||
const auto lfoNumber = opcode.parameters.front();
|
||||
if (lfoNumber == 0)
|
||||
return false;
|
||||
const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1);
|
||||
const ModKey target = ModKey::createNXYZ(ModId::Pitch, id);
|
||||
getOrCreateConnection(source, target).sourceDepth =
|
||||
opcode.read(Default::pitchMod);
|
||||
}
|
||||
break;
|
||||
case hash("lfo&_volume"):
|
||||
{
|
||||
const auto lfoNumber = opcode.parameters.front();
|
||||
if (lfoNumber == 0)
|
||||
return false;
|
||||
const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1);
|
||||
const ModKey target = ModKey::createNXYZ(ModId::Volume, id);
|
||||
getOrCreateConnection(source, target).sourceDepth =
|
||||
opcode.read(Default::volumeMod);
|
||||
}
|
||||
break;
|
||||
case hash("lfo&_cutoff&"):
|
||||
LFO_EG_filter_EQ_target(ModId::LFO, ModId::FilCutoff, Default::filterCutoffMod);
|
||||
break;
|
||||
case hash("lfo&_resonance&"):
|
||||
LFO_EG_filter_EQ_target(ModId::LFO, ModId::FilResonance, Default::filterResonanceMod);
|
||||
break;
|
||||
case hash("lfo&_fil&gain"):
|
||||
LFO_EG_filter_EQ_target(ModId::LFO, ModId::FilGain, Default::filterGainMod);
|
||||
break;
|
||||
case hash("lfo&_eq&gain"):
|
||||
LFO_EG_filter_EQ_target(ModId::LFO, ModId::EqGain, Default::eqGainMod);
|
||||
break;
|
||||
case hash("lfo&_eq&freq"):
|
||||
LFO_EG_filter_EQ_target(ModId::LFO, ModId::EqFrequency, Default::eqFrequencyMod);
|
||||
break;
|
||||
case hash("lfo&_eq&bw"):
|
||||
LFO_EG_filter_EQ_target(ModId::LFO, ModId::EqBandwidth, Default::eqBandwidthMod);
|
||||
break;
|
||||
|
||||
// Modulation: Flex EG (targets)
|
||||
case hash("eg&_amplitude"):
|
||||
{
|
||||
const auto egNumber = opcode.parameters.front();
|
||||
if (egNumber == 0)
|
||||
return false;
|
||||
const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1);
|
||||
const ModKey target = ModKey::createNXYZ(ModId::Amplitude, id);
|
||||
getOrCreateConnection(source, target).sourceDepth =
|
||||
opcode.read(Default::amplitudeMod);
|
||||
}
|
||||
break;
|
||||
case hash("eg&_pan"):
|
||||
{
|
||||
const auto egNumber = opcode.parameters.front();
|
||||
if (egNumber == 0)
|
||||
return false;
|
||||
const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1);
|
||||
const ModKey target = ModKey::createNXYZ(ModId::Pan, id);
|
||||
getOrCreateConnection(source, target).sourceDepth =
|
||||
opcode.read(Default::panMod);
|
||||
}
|
||||
break;
|
||||
case hash("eg&_width"):
|
||||
{
|
||||
const auto egNumber = opcode.parameters.front();
|
||||
if (egNumber == 0)
|
||||
return false;
|
||||
const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1);
|
||||
const ModKey target = ModKey::createNXYZ(ModId::Width, id);
|
||||
getOrCreateConnection(source, target).sourceDepth =
|
||||
opcode.read(Default::widthMod);
|
||||
}
|
||||
break;
|
||||
case hash("eg&_position"): // sfizz extension
|
||||
{
|
||||
const auto egNumber = opcode.parameters.front();
|
||||
if (egNumber == 0)
|
||||
return false;
|
||||
const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1);
|
||||
const ModKey target = ModKey::createNXYZ(ModId::Position, id);
|
||||
getOrCreateConnection(source, target).sourceDepth =
|
||||
opcode.read(Default::positionMod);
|
||||
}
|
||||
break;
|
||||
case hash("eg&_pitch"):
|
||||
{
|
||||
const auto egNumber = opcode.parameters.front();
|
||||
if (egNumber == 0)
|
||||
return false;
|
||||
const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1);
|
||||
const ModKey target = ModKey::createNXYZ(ModId::Pitch, id);
|
||||
getOrCreateConnection(source, target).sourceDepth =
|
||||
opcode.read(Default::pitchMod);
|
||||
}
|
||||
break;
|
||||
case hash("eg&_volume"):
|
||||
{
|
||||
const auto egNumber = opcode.parameters.front();
|
||||
if (egNumber == 0)
|
||||
return false;
|
||||
const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1);
|
||||
const ModKey target = ModKey::createNXYZ(ModId::Volume, id);
|
||||
getOrCreateConnection(source, target).sourceDepth =
|
||||
opcode.read(Default::volumeMod);
|
||||
}
|
||||
break;
|
||||
case hash("eg&_cutoff&"):
|
||||
LFO_EG_filter_EQ_target(ModId::Envelope, ModId::FilCutoff, Default::filterCutoffMod);
|
||||
break;
|
||||
case hash("eg&_resonance&"):
|
||||
LFO_EG_filter_EQ_target(ModId::Envelope, ModId::FilResonance, Default::filterResonanceMod);
|
||||
break;
|
||||
case hash("eg&_fil&gain"):
|
||||
LFO_EG_filter_EQ_target(ModId::Envelope, ModId::FilGain, Default::filterGainMod);
|
||||
break;
|
||||
case hash("eg&_eq&gain"):
|
||||
LFO_EG_filter_EQ_target(ModId::Envelope, ModId::EqGain, Default::eqGainMod);
|
||||
break;
|
||||
case hash("eg&_eq&freq"):
|
||||
LFO_EG_filter_EQ_target(ModId::Envelope, ModId::EqFrequency, Default::eqFrequencyMod);
|
||||
break;
|
||||
case hash("eg&_eq&bw"):
|
||||
LFO_EG_filter_EQ_target(ModId::Envelope, ModId::EqBandwidth, Default::eqBandwidthMod);
|
||||
break;
|
||||
|
||||
case hash("eg&_ampeg"):
|
||||
{
|
||||
const auto egNumber = opcode.parameters.front();
|
||||
if (egNumber == 0)
|
||||
return false;
|
||||
if (!extendIfNecessary(flexEGs, egNumber, Default::numFlexEGs))
|
||||
return false;
|
||||
auto ampeg = opcode.read(Default::flexEGAmpeg);
|
||||
FlexEGDescription& desc = flexEGs[egNumber - 1];
|
||||
if (desc.ampeg != ampeg) {
|
||||
desc.ampeg = ampeg;
|
||||
flexAmpEG = absl::nullopt;
|
||||
for (size_t i = 0, n = flexEGs.size(); i < n && !flexAmpEG; ++i) {
|
||||
if (flexEGs[i].ampeg)
|
||||
flexAmpEG = static_cast<uint8_t>(i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Amplitude Envelope
|
||||
case hash("ampeg_attack"):
|
||||
case hash("ampeg_decay"):
|
||||
case hash("ampeg_delay"):
|
||||
case hash("ampeg_hold"):
|
||||
case hash("ampeg_release"):
|
||||
case hash("ampeg_start"):
|
||||
case hash("ampeg_sustain"):
|
||||
case hash("ampeg_veltoattack"): // also ampeg_vel2attack
|
||||
case hash("ampeg_veltodecay"): // also ampeg_vel2decay
|
||||
case hash("ampeg_veltodelay"): // also ampeg_vel2delay
|
||||
case hash("ampeg_veltohold"): // also ampeg_vel2hold
|
||||
case hash("ampeg_veltorelease"): // also ampeg_vel2release
|
||||
case hash("ampeg_veltosustain"): // also ampeg_vel2sustain
|
||||
case hash("ampeg_attack_oncc&"): // also ampeg_attackcc&
|
||||
case hash("ampeg_decay_oncc&"): // also ampeg_decaycc&
|
||||
case hash("ampeg_delay_oncc&"): // also ampeg_delaycc&
|
||||
case hash("ampeg_hold_oncc&"): // also ampeg_holdcc&
|
||||
case hash("ampeg_release_oncc&"): // also ampeg_releasecc&
|
||||
case hash("ampeg_start_oncc&"): // also ampeg_startcc&
|
||||
case hash("ampeg_sustain_oncc&"): // also ampeg_sustaincc&
|
||||
parseEGOpcode(opcode, amplitudeEG);
|
||||
break;
|
||||
|
||||
case hash("pitcheg_attack"):
|
||||
case hash("pitcheg_decay"):
|
||||
case hash("pitcheg_delay"):
|
||||
case hash("pitcheg_hold"):
|
||||
case hash("pitcheg_release"):
|
||||
case hash("pitcheg_start"):
|
||||
case hash("pitcheg_sustain"):
|
||||
case hash("pitcheg_veltoattack"): // also pitcheg_vel2attack
|
||||
case hash("pitcheg_veltodecay"): // also pitcheg_vel2decay
|
||||
case hash("pitcheg_veltodelay"): // also pitcheg_vel2delay
|
||||
case hash("pitcheg_veltohold"): // also pitcheg_vel2hold
|
||||
case hash("pitcheg_veltorelease"): // also pitcheg_vel2release
|
||||
case hash("pitcheg_veltosustain"): // also pitcheg_vel2sustain
|
||||
case hash("pitcheg_attack_oncc&"): // also pitcheg_attackcc&
|
||||
case hash("pitcheg_decay_oncc&"): // also pitcheg_decaycc&
|
||||
case hash("pitcheg_delay_oncc&"): // also pitcheg_delaycc&
|
||||
case hash("pitcheg_hold_oncc&"): // also pitcheg_holdcc&
|
||||
case hash("pitcheg_release_oncc&"): // also pitcheg_releasecc&
|
||||
case hash("pitcheg_start_oncc&"): // also pitcheg_startcc&
|
||||
case hash("pitcheg_sustain_oncc&"): // also pitcheg_sustaincc&
|
||||
if (parseEGOpcode(opcode, pitchEG))
|
||||
getOrCreateConnection(
|
||||
ModKey::createNXYZ(ModId::PitchEG, id),
|
||||
ModKey::createNXYZ(ModId::Pitch, id));
|
||||
break;
|
||||
|
||||
case hash("fileg_attack"):
|
||||
case hash("fileg_decay"):
|
||||
case hash("fileg_delay"):
|
||||
case hash("fileg_hold"):
|
||||
case hash("fileg_release"):
|
||||
case hash("fileg_start"):
|
||||
case hash("fileg_sustain"):
|
||||
case hash("fileg_veltoattack"): // also fileg_vel2attack
|
||||
case hash("fileg_veltodecay"): // also fileg_vel2decay
|
||||
case hash("fileg_veltodelay"): // also fileg_vel2delay
|
||||
case hash("fileg_veltohold"): // also fileg_vel2hold
|
||||
case hash("fileg_veltorelease"): // also fileg_vel2release
|
||||
case hash("fileg_veltosustain"): // also fileg_vel2sustain
|
||||
case hash("fileg_attack_oncc&"): // also fileg_attackcc&
|
||||
case hash("fileg_decay_oncc&"): // also fileg_decaycc&
|
||||
case hash("fileg_delay_oncc&"): // also fileg_delaycc&
|
||||
case hash("fileg_hold_oncc&"): // also fileg_holdcc&
|
||||
case hash("fileg_release_oncc&"): // also fileg_releasecc&
|
||||
case hash("fileg_start_oncc&"): // also fileg_startcc&
|
||||
case hash("fileg_sustain_oncc&"): // also fileg_sustaincc&
|
||||
if (parseEGOpcode(opcode, filterEG))
|
||||
getOrCreateConnection(
|
||||
ModKey::createNXYZ(ModId::FilEG, id),
|
||||
ModKey::createNXYZ(ModId::FilCutoff, id));
|
||||
break;
|
||||
|
||||
case hash("pitcheg_depth"):
|
||||
getOrCreateConnection(
|
||||
ModKey::createNXYZ(ModId::PitchEG, id),
|
||||
ModKey::createNXYZ(ModId::Pitch, id)).sourceDepth = opcode.read(Default::egDepth);
|
||||
break;
|
||||
case hash("fileg_depth"):
|
||||
getOrCreateConnection(
|
||||
ModKey::createNXYZ(ModId::FilEG, id),
|
||||
ModKey::createNXYZ(ModId::FilCutoff, id)).sourceDepth = opcode.read(Default::egDepth);
|
||||
break;
|
||||
|
||||
case hash("pitcheg_veltodepth"): // also pitcheg_vel2depth
|
||||
getOrCreateConnection(
|
||||
ModKey::createNXYZ(ModId::PitchEG, id),
|
||||
ModKey::createNXYZ(ModId::Pitch, id)).velToDepth = opcode.read(Default::egVel2Depth);
|
||||
break;
|
||||
case hash("fileg_veltodepth"): // also fileg_vel2depth
|
||||
getOrCreateConnection(
|
||||
ModKey::createNXYZ(ModId::FilEG, id),
|
||||
ModKey::createNXYZ(ModId::FilCutoff, id)).velToDepth = opcode.read(Default::egVel2Depth);
|
||||
break;
|
||||
|
||||
// Flex envelopes
|
||||
case hash("eg&_dynamic"):
|
||||
{
|
||||
const auto egNumber = opcode.parameters.front();
|
||||
if (egNumber == 0)
|
||||
return false;
|
||||
if (!extendIfNecessary(flexEGs, egNumber, Default::numFlexEGs))
|
||||
return false;
|
||||
auto& eg = flexEGs[egNumber - 1];
|
||||
eg.dynamic = opcode.read(Default::flexEGDynamic);
|
||||
}
|
||||
break;
|
||||
case hash("eg&_sustain"):
|
||||
{
|
||||
const auto egNumber = opcode.parameters.front();
|
||||
if (egNumber == 0)
|
||||
return false;
|
||||
if (!extendIfNecessary(flexEGs, egNumber, Default::numFlexEGs))
|
||||
return false;
|
||||
auto& eg = flexEGs[egNumber - 1];
|
||||
eg.sustain = opcode.read(Default::flexEGSustain);
|
||||
}
|
||||
break;
|
||||
case hash("eg&_time&"):
|
||||
{
|
||||
const auto egNumber = opcode.parameters.front();
|
||||
if (egNumber == 0)
|
||||
return false;
|
||||
if (!extendIfNecessary(flexEGs, egNumber, Default::numFlexEGs))
|
||||
return false;
|
||||
auto& eg = flexEGs[egNumber - 1];
|
||||
const auto pointNumber = opcode.parameters[1];
|
||||
if (!extendIfNecessary(eg.points, pointNumber + 1, Default::numFlexEGPoints))
|
||||
return false;
|
||||
eg.points[pointNumber].time = opcode.read(Default::flexEGPointTime);
|
||||
}
|
||||
break;
|
||||
case hash("eg&_level&"):
|
||||
{
|
||||
const auto egNumber = opcode.parameters.front();
|
||||
if (egNumber == 0)
|
||||
return false;
|
||||
if (!extendIfNecessary(flexEGs, egNumber, Default::numFlexEGs))
|
||||
return false;
|
||||
auto& eg = flexEGs[egNumber - 1];
|
||||
const auto pointNumber = opcode.parameters[1];
|
||||
if (!extendIfNecessary(eg.points, pointNumber + 1, Default::numFlexEGPoints))
|
||||
return false;
|
||||
eg.points[pointNumber].level = opcode.read(Default::flexEGPointLevel);
|
||||
}
|
||||
break;
|
||||
case hash("eg&_shape&"):
|
||||
{
|
||||
const auto egNumber = opcode.parameters.front();
|
||||
if (egNumber == 0)
|
||||
return false;
|
||||
if (!extendIfNecessary(flexEGs, egNumber, Default::numFlexEGs))
|
||||
return false;
|
||||
auto& eg = flexEGs[egNumber - 1];
|
||||
const auto pointNumber = opcode.parameters[1];
|
||||
if (!extendIfNecessary(eg.points, pointNumber + 1, Default::numFlexEGPoints))
|
||||
return false;
|
||||
eg.points[pointNumber].setShape(opcode.read(Default::flexEGPointShape));
|
||||
}
|
||||
break;
|
||||
|
||||
case hash("effect&"):
|
||||
{
|
||||
const auto effectNumber = opcode.parameters.back();
|
||||
|
|
@ -1284,11 +754,49 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode)
|
|||
case hash("ampeg_depth"):
|
||||
case hash("ampeg_veltodepth"): // also ampeg_vel2depth
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
|
||||
#undef case_any_ccN
|
||||
#undef LFO_EG_filter_EQ_target
|
||||
default: {
|
||||
// Amplitude Envelope
|
||||
if (absl::StartsWith(opcode.name, "ampeg_")) {
|
||||
if (parseEGOpcode(opcode, amplitudeEG))
|
||||
return true;
|
||||
}
|
||||
// Pitch Envelope
|
||||
if (absl::StartsWith(opcode.name, "pitcheg_")) {
|
||||
if (parseEGOpcode(opcode, pitchEG)) {
|
||||
getOrCreateConnection(
|
||||
ModKey::createNXYZ(ModId::PitchEG, id),
|
||||
ModKey::createNXYZ(ModId::Pitch, id));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Filter Envelope
|
||||
if (absl::StartsWith(opcode.name, "fileg_")) {
|
||||
if (parseEGOpcode(opcode, filterEG)) {
|
||||
getOrCreateConnection(
|
||||
ModKey::createNXYZ(ModId::FilEG, id),
|
||||
ModKey::createNXYZ(ModId::FilCutoff, id));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
const std::string letterOnlyName = opcode.getLetterOnlyName();
|
||||
|
||||
// Modulation: LFO
|
||||
if (absl::StartsWith(letterOnlyName, "lfo&_")) {
|
||||
if (parseLFOOpcodeV2(opcode))
|
||||
return true;
|
||||
}
|
||||
// Modulation: Flex EG
|
||||
if (absl::StartsWith(letterOnlyName, "eg&_")) {
|
||||
if (parseEGOpcodeV2(opcode))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -1390,6 +898,29 @@ bool sfz::Region::parseEGOpcode(const Opcode& opcode, EGDescription& eg)
|
|||
eg.ccSustain[opcode.parameters.back()] = opcode.read(Default::egPercentMod);
|
||||
|
||||
break;
|
||||
|
||||
case hash("pitcheg_depth"):
|
||||
getOrCreateConnection(
|
||||
ModKey::createNXYZ(ModId::PitchEG, id),
|
||||
ModKey::createNXYZ(ModId::Pitch, id)).sourceDepth = opcode.read(Default::egDepth);
|
||||
break;
|
||||
case hash("fileg_depth"):
|
||||
getOrCreateConnection(
|
||||
ModKey::createNXYZ(ModId::FilEG, id),
|
||||
ModKey::createNXYZ(ModId::FilCutoff, id)).sourceDepth = opcode.read(Default::egDepth);
|
||||
break;
|
||||
|
||||
case hash("pitcheg_veltodepth"): // also pitcheg_vel2depth
|
||||
getOrCreateConnection(
|
||||
ModKey::createNXYZ(ModId::PitchEG, id),
|
||||
ModKey::createNXYZ(ModId::Pitch, id)).velToDepth = opcode.read(Default::egVel2Depth);
|
||||
break;
|
||||
case hash("fileg_veltodepth"): // also fileg_vel2depth
|
||||
getOrCreateConnection(
|
||||
ModKey::createNXYZ(ModId::FilEG, id),
|
||||
ModKey::createNXYZ(ModId::FilCutoff, id)).velToDepth = opcode.read(Default::egVel2Depth);
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1412,6 +943,333 @@ bool sfz::Region::parseEGOpcode(const Opcode& opcode, absl::optional<EGDescripti
|
|||
return parsed;
|
||||
}
|
||||
|
||||
bool sfz::Region::parseLFOOpcodeV2(const Opcode& opcode)
|
||||
{
|
||||
const unsigned lfoNumber1Based = opcode.parameters.front();
|
||||
|
||||
if (lfoNumber1Based <= 0)
|
||||
return false;
|
||||
if (!extendIfNecessary(lfos, lfoNumber1Based, Default::numLFOs))
|
||||
return false;
|
||||
|
||||
const unsigned lfoNumber = lfoNumber1Based - 1;
|
||||
LFODescription& lfo = lfos[lfoNumber];
|
||||
|
||||
//
|
||||
auto getOrCreateLFOStep = [&opcode, &lfo]() -> float* {
|
||||
const unsigned stepNumber1Based = opcode.parameters[1];
|
||||
if (stepNumber1Based <= 0 || stepNumber1Based > config::maxLFOSteps)
|
||||
return nullptr;
|
||||
if (!lfo.seq)
|
||||
lfo.seq = LFODescription::StepSequence();
|
||||
if (!extendIfNecessary(lfo.seq->steps, stepNumber1Based, Default::numLFOSteps))
|
||||
return nullptr;
|
||||
return &lfo.seq->steps[stepNumber1Based - 1];
|
||||
};
|
||||
auto getOrCreateLFOSub = [&opcode, &lfo]() -> LFODescription::Sub* {
|
||||
const unsigned subNumber1Based = opcode.parameters[1];
|
||||
if (subNumber1Based <= 0 || subNumber1Based > config::maxLFOSubs)
|
||||
return nullptr;
|
||||
if (!extendIfNecessary(lfo.sub, subNumber1Based, Default::numLFOSubs))
|
||||
return nullptr;
|
||||
return &lfo.sub[subNumber1Based - 1];
|
||||
};
|
||||
auto LFO_EG_filter_EQ_target = [this, &opcode, lfoNumber](ModId sourceId, ModId targetId, const OpcodeSpec<float>& spec) -> bool {
|
||||
const unsigned index = opcode.parameters.size() == 2 ? opcode.parameters.back() - 1 : 0;
|
||||
if (!extendIfNecessary(filters, index + 1, Default::numFilters))
|
||||
return false;
|
||||
const ModKey source = ModKey::createNXYZ(sourceId, id, lfoNumber);
|
||||
const ModKey target = ModKey::createNXYZ(targetId, id, index);
|
||||
getOrCreateConnection(source, target).sourceDepth = opcode.read(spec);
|
||||
return true;
|
||||
};
|
||||
|
||||
//
|
||||
switch (opcode.lettersOnlyHash) {
|
||||
|
||||
// Modulation: LFO
|
||||
case hash("lfo&_freq"):
|
||||
lfo.freq = opcode.read(Default::lfoFreq);
|
||||
break;
|
||||
case_any_ccN("lfo&_freq"):
|
||||
processGenericCc(opcode, Default::lfoFreqMod, ModKey::createNXYZ(ModId::LFOFrequency, id, lfoNumber));
|
||||
break;
|
||||
case hash("lfo&_beats"):
|
||||
lfo.beats = opcode.read(Default::lfoBeats);
|
||||
break;
|
||||
case_any_ccN("lfo&_beats"):
|
||||
processGenericCc(opcode, Default::lfoBeatsMod, ModKey::createNXYZ(ModId::LFOBeats, id, lfoNumber));
|
||||
break;
|
||||
case hash("lfo&_phase"):
|
||||
lfo.phase0 = opcode.read(Default::lfoPhase);
|
||||
break;
|
||||
case hash("lfo&_delay"):
|
||||
lfo.delay = opcode.read(Default::lfoDelay);
|
||||
break;
|
||||
case hash("lfo&_fade"):
|
||||
lfo.fade = opcode.read(Default::lfoFade);
|
||||
break;
|
||||
case hash("lfo&_count"):
|
||||
lfo.count = opcode.read(Default::lfoCount);
|
||||
break;
|
||||
case hash("lfo&_steps"):
|
||||
if (!lfo.seq)
|
||||
lfo.seq = LFODescription::StepSequence();
|
||||
lfo.seq->steps.resize(opcode.read(Default::lfoSteps));
|
||||
break;
|
||||
case hash("lfo&_step&"):
|
||||
if (float* step = getOrCreateLFOStep())
|
||||
*step = opcode.read(Default::lfoStepX);
|
||||
else
|
||||
return false;
|
||||
break;
|
||||
case hash("lfo&_wave&"): // also lfo&_wave
|
||||
if (LFODescription::Sub* sub = getOrCreateLFOSub())
|
||||
sub->wave = opcode.read(Default::lfoWave);
|
||||
else
|
||||
return false;
|
||||
break;
|
||||
case hash("lfo&_offset&"): // also lfo&_offset
|
||||
if (LFODescription::Sub* sub = getOrCreateLFOSub())
|
||||
sub->offset = opcode.read(Default::lfoOffset);
|
||||
else
|
||||
return false;
|
||||
break;
|
||||
case hash("lfo&_ratio&"): // also lfo&_ratio
|
||||
if (LFODescription::Sub* sub = getOrCreateLFOSub())
|
||||
sub->ratio = opcode.read(Default::lfoRatio);
|
||||
else
|
||||
return false;
|
||||
break;
|
||||
case hash("lfo&_scale&"): // also lfo&_scale
|
||||
if (LFODescription::Sub* sub = getOrCreateLFOSub())
|
||||
sub->scale = opcode.read(Default::lfoScale);
|
||||
else
|
||||
return false;
|
||||
break;
|
||||
|
||||
// Modulation: LFO (targets)
|
||||
case hash("lfo&_amplitude"):
|
||||
{
|
||||
const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber);
|
||||
const ModKey target = ModKey::createNXYZ(ModId::Amplitude, id);
|
||||
getOrCreateConnection(source, target).sourceDepth =
|
||||
opcode.read(Default::amplitudeMod);
|
||||
}
|
||||
break;
|
||||
case hash("lfo&_pan"):
|
||||
{
|
||||
const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber);
|
||||
const ModKey target = ModKey::createNXYZ(ModId::Pan, id);
|
||||
getOrCreateConnection(source, target).sourceDepth =
|
||||
opcode.read(Default::panMod);
|
||||
}
|
||||
break;
|
||||
case hash("lfo&_width"):
|
||||
{
|
||||
const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber);
|
||||
const ModKey target = ModKey::createNXYZ(ModId::Width, id);
|
||||
getOrCreateConnection(source, target).sourceDepth =
|
||||
opcode.read(Default::widthMod);
|
||||
}
|
||||
break;
|
||||
case hash("lfo&_position"): // sfizz extension
|
||||
{
|
||||
const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber);
|
||||
const ModKey target = ModKey::createNXYZ(ModId::Position, id);
|
||||
getOrCreateConnection(source, target).sourceDepth =
|
||||
opcode.read(Default::positionMod);
|
||||
}
|
||||
break;
|
||||
case hash("lfo&_pitch"):
|
||||
{
|
||||
const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber);
|
||||
const ModKey target = ModKey::createNXYZ(ModId::Pitch, id);
|
||||
getOrCreateConnection(source, target).sourceDepth =
|
||||
opcode.read(Default::pitchMod);
|
||||
}
|
||||
break;
|
||||
case hash("lfo&_volume"):
|
||||
{
|
||||
const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber);
|
||||
const ModKey target = ModKey::createNXYZ(ModId::Volume, id);
|
||||
getOrCreateConnection(source, target).sourceDepth =
|
||||
opcode.read(Default::volumeMod);
|
||||
}
|
||||
break;
|
||||
|
||||
case hash("lfo&_cutoff&"):
|
||||
LFO_EG_filter_EQ_target(ModId::LFO, ModId::FilCutoff, Default::filterCutoffMod);
|
||||
break;
|
||||
case hash("lfo&_resonance&"):
|
||||
LFO_EG_filter_EQ_target(ModId::LFO, ModId::FilResonance, Default::filterResonanceMod);
|
||||
break;
|
||||
case hash("lfo&_fil&gain"):
|
||||
LFO_EG_filter_EQ_target(ModId::LFO, ModId::FilGain, Default::filterGainMod);
|
||||
break;
|
||||
case hash("lfo&_eq&gain"):
|
||||
LFO_EG_filter_EQ_target(ModId::LFO, ModId::EqGain, Default::eqGainMod);
|
||||
break;
|
||||
case hash("lfo&_eq&freq"):
|
||||
LFO_EG_filter_EQ_target(ModId::LFO, ModId::EqFrequency, Default::eqFrequencyMod);
|
||||
break;
|
||||
case hash("lfo&_eq&bw"):
|
||||
LFO_EG_filter_EQ_target(ModId::LFO, ModId::EqBandwidth, Default::eqBandwidthMod);
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sfz::Region::parseEGOpcodeV2(const Opcode& opcode)
|
||||
{
|
||||
const unsigned egNumber1Based = opcode.parameters.front();
|
||||
if (egNumber1Based <= 0)
|
||||
return false;
|
||||
if (!extendIfNecessary(flexEGs, egNumber1Based, Default::numFlexEGs))
|
||||
return false;
|
||||
|
||||
const unsigned egNumber = egNumber1Based - 1;
|
||||
FlexEGDescription& eg = flexEGs[egNumber];
|
||||
|
||||
//
|
||||
auto getOrCreateEGPoint = [&opcode, &eg]() -> FlexEGPoint* {
|
||||
const auto pointNumber = opcode.parameters[1];
|
||||
if (!extendIfNecessary(eg.points, pointNumber + 1, Default::numFlexEGPoints))
|
||||
return nullptr;
|
||||
return &eg.points[pointNumber];
|
||||
};
|
||||
auto LFO_EG_filter_EQ_target = [this, &opcode, egNumber](ModId sourceId, ModId targetId, const OpcodeSpec<float>& spec) -> bool {
|
||||
const unsigned index = opcode.parameters.size() == 2 ? opcode.parameters.back() - 1 : 0;
|
||||
if (!extendIfNecessary(filters, index + 1, Default::numFilters))
|
||||
return false;
|
||||
const ModKey source = ModKey::createNXYZ(sourceId, id, egNumber);
|
||||
const ModKey target = ModKey::createNXYZ(targetId, id, index);
|
||||
getOrCreateConnection(source, target).sourceDepth = opcode.read(spec);
|
||||
return true;
|
||||
};
|
||||
|
||||
//
|
||||
switch (opcode.lettersOnlyHash) {
|
||||
|
||||
// Flex envelopes
|
||||
case hash("eg&_dynamic"):
|
||||
eg.dynamic = opcode.read(Default::flexEGDynamic);
|
||||
break;
|
||||
case hash("eg&_sustain"):
|
||||
eg.sustain = opcode.read(Default::flexEGSustain);
|
||||
break;
|
||||
case hash("eg&_time&"):
|
||||
if (FlexEGPoint* point = getOrCreateEGPoint())
|
||||
point->time = opcode.read(Default::flexEGPointTime);
|
||||
else
|
||||
return false;
|
||||
break;
|
||||
case hash("eg&_level&"):
|
||||
if (FlexEGPoint* point = getOrCreateEGPoint())
|
||||
point->level = opcode.read(Default::flexEGPointLevel);
|
||||
else
|
||||
return false;
|
||||
break;
|
||||
case hash("eg&_shape&"):
|
||||
if (FlexEGPoint* point = getOrCreateEGPoint())
|
||||
point->setShape(opcode.read(Default::flexEGPointShape));
|
||||
else
|
||||
return false;
|
||||
break;
|
||||
|
||||
// Modulation: Flex EG (targets)
|
||||
case hash("eg&_amplitude"):
|
||||
{
|
||||
const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber);
|
||||
const ModKey target = ModKey::createNXYZ(ModId::Amplitude, id);
|
||||
getOrCreateConnection(source, target).sourceDepth =
|
||||
opcode.read(Default::amplitudeMod);
|
||||
}
|
||||
break;
|
||||
case hash("eg&_pan"):
|
||||
{
|
||||
const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber);
|
||||
const ModKey target = ModKey::createNXYZ(ModId::Pan, id);
|
||||
getOrCreateConnection(source, target).sourceDepth =
|
||||
opcode.read(Default::panMod);
|
||||
}
|
||||
break;
|
||||
case hash("eg&_width"):
|
||||
{
|
||||
const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber);
|
||||
const ModKey target = ModKey::createNXYZ(ModId::Width, id);
|
||||
getOrCreateConnection(source, target).sourceDepth =
|
||||
opcode.read(Default::widthMod);
|
||||
}
|
||||
break;
|
||||
case hash("eg&_position"): // sfizz extension
|
||||
{
|
||||
const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber);
|
||||
const ModKey target = ModKey::createNXYZ(ModId::Position, id);
|
||||
getOrCreateConnection(source, target).sourceDepth =
|
||||
opcode.read(Default::positionMod);
|
||||
}
|
||||
break;
|
||||
case hash("eg&_pitch"):
|
||||
{
|
||||
const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber);
|
||||
const ModKey target = ModKey::createNXYZ(ModId::Pitch, id);
|
||||
getOrCreateConnection(source, target).sourceDepth =
|
||||
opcode.read(Default::pitchMod);
|
||||
}
|
||||
break;
|
||||
case hash("eg&_volume"):
|
||||
{
|
||||
const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber);
|
||||
const ModKey target = ModKey::createNXYZ(ModId::Volume, id);
|
||||
getOrCreateConnection(source, target).sourceDepth =
|
||||
opcode.read(Default::volumeMod);
|
||||
}
|
||||
break;
|
||||
case hash("eg&_cutoff&"):
|
||||
LFO_EG_filter_EQ_target(ModId::Envelope, ModId::FilCutoff, Default::filterCutoffMod);
|
||||
break;
|
||||
case hash("eg&_resonance&"):
|
||||
LFO_EG_filter_EQ_target(ModId::Envelope, ModId::FilResonance, Default::filterResonanceMod);
|
||||
break;
|
||||
case hash("eg&_fil&gain"):
|
||||
LFO_EG_filter_EQ_target(ModId::Envelope, ModId::FilGain, Default::filterGainMod);
|
||||
break;
|
||||
case hash("eg&_eq&gain"):
|
||||
LFO_EG_filter_EQ_target(ModId::Envelope, ModId::EqGain, Default::eqGainMod);
|
||||
break;
|
||||
case hash("eg&_eq&freq"):
|
||||
LFO_EG_filter_EQ_target(ModId::Envelope, ModId::EqFrequency, Default::eqFrequencyMod);
|
||||
break;
|
||||
case hash("eg&_eq&bw"):
|
||||
LFO_EG_filter_EQ_target(ModId::Envelope, ModId::EqBandwidth, Default::eqBandwidthMod);
|
||||
break;
|
||||
|
||||
case hash("eg&_ampeg"):
|
||||
{
|
||||
auto ampeg = opcode.read(Default::flexEGAmpeg);
|
||||
if (eg.ampeg != ampeg) {
|
||||
eg.ampeg = ampeg;
|
||||
flexAmpEG = absl::nullopt;
|
||||
for (size_t i = 0, n = flexEGs.size(); i < n && !flexAmpEG; ++i) {
|
||||
if (flexEGs[i].ampeg)
|
||||
flexAmpEG = static_cast<uint8_t>(i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sfz::Region::processGenericCc(const Opcode& opcode, OpcodeSpec<float> spec, const ModKey& target)
|
||||
{
|
||||
if (!opcode.isAnyCcN())
|
||||
|
|
|
|||
|
|
@ -266,6 +266,22 @@ struct Region {
|
|||
* @return false
|
||||
*/
|
||||
bool parseEGOpcode(const Opcode& opcode, absl::optional<EGDescription>& eg);
|
||||
/**
|
||||
* @brief Parse a opcode which is specific to a particular SFZv2 LFO: lfoN.
|
||||
*
|
||||
* @param opcode
|
||||
* @return true if the opcode was properly read and stored.
|
||||
* @return false
|
||||
*/
|
||||
bool parseLFOOpcodeV2(const Opcode& opcode);
|
||||
/**
|
||||
* @brief Parse a opcode which is specific to a particular SFZv2 EG: egN.
|
||||
*
|
||||
* @param opcode
|
||||
* @return true if the opcode was properly read and stored.
|
||||
* @return false
|
||||
*/
|
||||
bool parseEGOpcodeV2(const Opcode& opcode);
|
||||
/**
|
||||
* @brief Process a generic CC opcode, and fill the modulation parameters.
|
||||
*
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue