This commit is contained in:
paulfd 2019-08-23 15:46:02 +02:00
parent 0e89a0b2c6
commit 5d57a5ad24
4 changed files with 388 additions and 246 deletions

View file

@ -4,89 +4,125 @@
bool sfz::Region::parseOpcode(const Opcode& opcode) bool sfz::Region::parseOpcode(const Opcode& opcode)
{ {
switch (hash(opcode.opcode)) switch (hash(opcode.opcode)) {
{
// Sound source: sample playback // Sound source: sample playback
case hash("sample"): case hash("sample"):
sample = absl::StrReplaceAll(trim(opcode.value), {{"\\", "/"}}); sample = absl::StrReplaceAll(trim(opcode.value), { { "\\", "/" } });
break; break;
case hash("delay"): setValueFromOpcode(opcode, delay, Default::delayRange); break; case hash("delay"):
case hash("delay_random"): setValueFromOpcode(opcode, delayRandom, Default::delayRange); break; setValueFromOpcode(opcode, delay, Default::delayRange);
case hash("offset"): setValueFromOpcode(opcode, offset, Default::offsetRange); break; break;
case hash("offset_random"): setValueFromOpcode(opcode, offsetRandom, Default::offsetRange); break; case hash("delay_random"):
case hash("end"): setValueFromOpcode(opcode, sampleEnd, Default::sampleEndRange); break; setValueFromOpcode(opcode, delayRandom, Default::delayRange);
case hash("count"): setValueFromOpcode(opcode, sampleCount, Default::sampleCountRange); break; break;
case hash("offset"):
setValueFromOpcode(opcode, offset, Default::offsetRange);
break;
case hash("offset_random"):
setValueFromOpcode(opcode, offsetRandom, Default::offsetRange);
break;
case hash("end"):
setValueFromOpcode(opcode, sampleEnd, Default::sampleEndRange);
break;
case hash("count"):
setValueFromOpcode(opcode, sampleCount, Default::sampleCountRange);
break;
case hash("loopmode"): case hash("loopmode"):
case hash("loop_mode"): case hash("loop_mode"):
switch(hash(opcode.value)) switch (hash(opcode.value)) {
{ case hash("no_loop"):
case hash("no_loop"): loopMode = SfzLoopMode::no_loop;
loopMode = SfzLoopMode::no_loop; break;
break; case hash("one_shot"):
case hash("one_shot"): loopMode = SfzLoopMode::one_shot;
loopMode = SfzLoopMode::one_shot; break;
break; case hash("loop_continuous"):
case hash("loop_continuous"): loopMode = SfzLoopMode::loop_continuous;
loopMode = SfzLoopMode::loop_continuous; break;
break; case hash("loop_sustain"):
case hash("loop_sustain"): loopMode = SfzLoopMode::loop_sustain;
loopMode = SfzLoopMode::loop_sustain; break;
break; default:
default: DBG("Unkown loop mode:" << std::string(opcode.value));
DBG("Unkown loop mode:" << std::string(opcode.value));
} }
break; break;
case hash("loopend"): case hash("loopend"):
case hash("loop_end"): setRangeEndFromOpcode(opcode, loopRange, Default::loopRange); break; case hash("loop_end"):
setRangeEndFromOpcode(opcode, loopRange, Default::loopRange);
break;
case hash("loopstart"): case hash("loopstart"):
case hash("loop_start"): setRangeStartFromOpcode(opcode, loopRange, Default::loopRange); break; case hash("loop_start"):
setRangeStartFromOpcode(opcode, loopRange, Default::loopRange);
break;
// Instrument settings: voice lifecycle // Instrument settings: voice lifecycle
case hash("group"): setValueFromOpcode(opcode, group, Default::groupRange); break; case hash("group"):
setValueFromOpcode(opcode, group, Default::groupRange);
break;
case hash("offby"): case hash("offby"):
case hash("off_by"): setValueFromOpcode(opcode, offBy, Default::groupRange); break; case hash("off_by"):
setValueFromOpcode(opcode, offBy, Default::groupRange);
break;
case hash("off_mode"): case hash("off_mode"):
switch(hash(opcode.value)) switch (hash(opcode.value)) {
{ case hash("fast"):
case hash("fast"): offMode = SfzOffMode::fast;
offMode = SfzOffMode::fast; break;
break; case hash("normal"):
case hash("normal"): offMode = SfzOffMode::normal;
offMode = SfzOffMode::normal; break;
break; default:
default: DBG("Unkown off mode:" << std::string(opcode.value));
DBG("Unkown off mode:" << std::string(opcode.value));
} }
break; break;
// Region logic: key mapping // Region logic: key mapping
case hash("lokey"): setRangeStartFromOpcode(opcode, keyRange, Default::keyRange); break; case hash("lokey"):
case hash("hikey"): setRangeEndFromOpcode(opcode, keyRange, Default::keyRange); break; setRangeStartFromOpcode(opcode, keyRange, Default::keyRange);
break;
case hash("hikey"):
setRangeEndFromOpcode(opcode, keyRange, Default::keyRange);
break;
case hash("key"): case hash("key"):
setRangeStartFromOpcode(opcode, keyRange, Default::keyRange); setRangeStartFromOpcode(opcode, keyRange, Default::keyRange);
setRangeEndFromOpcode(opcode, keyRange, Default::keyRange); setRangeEndFromOpcode(opcode, keyRange, Default::keyRange);
setValueFromOpcode(opcode, pitchKeycenter, Default::keyRange); setValueFromOpcode(opcode, pitchKeycenter, Default::keyRange);
break; break;
case hash("lovel"): setRangeStartFromOpcode(opcode, velocityRange, Default::velocityRange); break; case hash("lovel"):
case hash("hivel"): setRangeEndFromOpcode(opcode, velocityRange, Default::velocityRange); break; setRangeStartFromOpcode(opcode, velocityRange, Default::velocityRange);
break;
case hash("hivel"):
setRangeEndFromOpcode(opcode, velocityRange, Default::velocityRange);
break;
// Region logic: MIDI conditions // Region logic: MIDI conditions
case hash("lochan"): setRangeStartFromOpcode(opcode, channelRange, Default::channelRange); break; case hash("lochan"):
case hash("hichan"): setRangeEndFromOpcode(opcode, channelRange, Default::channelRange); break; setRangeStartFromOpcode(opcode, channelRange, Default::channelRange);
case hash("lobend"): setRangeStartFromOpcode(opcode, bendRange, Default::bendRange); break; break;
case hash("hibend"): setRangeEndFromOpcode(opcode, bendRange, Default::bendRange); break; case hash("hichan"):
case hash("locc"): setRangeEndFromOpcode(opcode, channelRange, Default::channelRange);
if (opcode.parameter) break;
{ case hash("lobend"):
setRangeStartFromOpcode(opcode, bendRange, Default::bendRange);
break;
case hash("hibend"):
setRangeEndFromOpcode(opcode, bendRange, Default::bendRange);
break;
case hash("locc"):
if (opcode.parameter) {
setRangeStartFromOpcode(opcode, ccConditions[*opcode.parameter], Default::ccRange); setRangeStartFromOpcode(opcode, ccConditions[*opcode.parameter], Default::ccRange);
} }
break; break;
case hash("hicc"): case hash("hicc"):
if (opcode.parameter) if (opcode.parameter)
setRangeEndFromOpcode(opcode, ccConditions[*opcode.parameter], Default::ccRange); setRangeEndFromOpcode(opcode, ccConditions[*opcode.parameter], Default::ccRange);
break; break;
case hash("sw_lokey"): setRangeStartFromOpcode(opcode, keyswitchRange, Default::keyRange); break; case hash("sw_lokey"):
case hash("sw_hikey"): setRangeEndFromOpcode(opcode, keyswitchRange, Default::keyRange); break; setRangeStartFromOpcode(opcode, keyswitchRange, Default::keyRange);
case hash("sw_last"): break;
case hash("sw_hikey"):
setRangeEndFromOpcode(opcode, keyswitchRange, Default::keyRange);
break;
case hash("sw_last"):
setValueFromOpcode(opcode, keyswitch, Default::keyRange); setValueFromOpcode(opcode, keyswitch, Default::keyRange);
keySwitched = false; keySwitched = false;
break; break;
@ -94,105 +130,159 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
setValueFromOpcode(opcode, keyswitchDown, Default::keyRange); setValueFromOpcode(opcode, keyswitchDown, Default::keyRange);
keySwitched = false; keySwitched = false;
break; break;
case hash("sw_up"): setValueFromOpcode(opcode, keyswitchUp, Default::keyRange); break; case hash("sw_up"):
setValueFromOpcode(opcode, keyswitchUp, Default::keyRange);
break;
case hash("sw_previous"): case hash("sw_previous"):
setValueFromOpcode(opcode, previousNote, Default::keyRange); setValueFromOpcode(opcode, previousNote, Default::keyRange);
previousKeySwitched = false; previousKeySwitched = false;
break; break;
case hash("sw_vel"): case hash("sw_vel"):
switch(hash(opcode.value)) switch (hash(opcode.value)) {
{ case hash("current"):
case hash("current"): velocityOverride = SfzVelocityOverride::current;
velocityOverride = SfzVelocityOverride::current; break;
break; case hash("previous"):
case hash("previous"): velocityOverride = SfzVelocityOverride::previous;
velocityOverride = SfzVelocityOverride::previous; break;
break; default:
default: DBG("Unknown velocity mode: " << std::string(opcode.value));
DBG("Unknown velocity mode: " << std::string(opcode.value));
} }
break; break;
// Region logic: internal conditions // Region logic: internal conditions
case hash("lochanaft"): setRangeStartFromOpcode(opcode, aftertouchRange, Default::aftertouchRange); break; case hash("lochanaft"):
case hash("hichanaft"): setRangeEndFromOpcode(opcode, aftertouchRange, Default::aftertouchRange); break; setRangeStartFromOpcode(opcode, aftertouchRange, Default::aftertouchRange);
case hash("lobpm"): setRangeStartFromOpcode(opcode, bpmRange, Default::bpmRange); break; break;
case hash("hibpm"): setRangeEndFromOpcode(opcode, bpmRange, Default::bpmRange); break; case hash("hichanaft"):
case hash("lorand"): setRangeStartFromOpcode(opcode, randRange, Default::randRange); break; setRangeEndFromOpcode(opcode, aftertouchRange, Default::aftertouchRange);
case hash("hirand"): setRangeEndFromOpcode(opcode, randRange, Default::randRange); break; break;
case hash("seq_length"): setValueFromOpcode(opcode, sequenceLength, Default::sequenceRange); break; case hash("lobpm"):
setRangeStartFromOpcode(opcode, bpmRange, Default::bpmRange);
break;
case hash("hibpm"):
setRangeEndFromOpcode(opcode, bpmRange, Default::bpmRange);
break;
case hash("lorand"):
setRangeStartFromOpcode(opcode, randRange, Default::randRange);
break;
case hash("hirand"):
setRangeEndFromOpcode(opcode, randRange, Default::randRange);
break;
case hash("seq_length"):
setValueFromOpcode(opcode, sequenceLength, Default::sequenceRange);
break;
case hash("seq_position"): case hash("seq_position"):
setValueFromOpcode(opcode, sequencePosition, Default::sequenceRange); setValueFromOpcode(opcode, sequencePosition, Default::sequenceRange);
sequenceSwitched = (opcode.value == "1"); sequenceSwitched = (opcode.value == "1");
break; break;
// Region logic: triggers // Region logic: triggers
case hash("trigger"): case hash("trigger"):
switch(hash(opcode.value)) switch (hash(opcode.value)) {
{ case hash("attack"):
case hash("attack"): trigger = SfzTrigger::attack;
trigger = SfzTrigger::attack; break;
break; case hash("first"):
case hash("first"): trigger = SfzTrigger::first;
trigger = SfzTrigger::first; break;
break; case hash("legato"):
case hash("legato"): trigger = SfzTrigger::legato;
trigger = SfzTrigger::legato; break;
break; case hash("release"):
case hash("release"): trigger = SfzTrigger::release;
trigger = SfzTrigger::release; break;
break; case hash("release_key"):
case hash("release_key"): trigger = SfzTrigger::release_key;
trigger = SfzTrigger::release_key; break;
break; default:
default: DBG("Unknown trigger mode: " << std::string(opcode.value));
DBG("Unknown trigger mode: " << std::string(opcode.value));
} }
break; break;
case hash("on_locc"): case hash("on_locc"):
if (opcode.parameter) if (opcode.parameter)
setRangeStartFromOpcode(opcode, ccTriggers[*opcode.parameter], Default::ccRange); setRangeStartFromOpcode(opcode, ccTriggers[*opcode.parameter], Default::ccRange);
break; break;
case hash("on_hicc"): case hash("on_hicc"):
if (opcode.parameter) if (opcode.parameter)
setRangeEndFromOpcode(opcode, ccTriggers[*opcode.parameter], Default::ccRange); setRangeEndFromOpcode(opcode, ccTriggers[*opcode.parameter], Default::ccRange);
break; break;
// Performance parameters: amplifier // Performance parameters: amplifier
case hash("volume"): setValueFromOpcode(opcode, volume, Default::volumeRange); break; case hash("volume"):
// case hash("volume_oncc"): setValueFromOpcode(opcode, volume, Default::volumeRange);
// if (opcode.parameter) break;
// setValueFromOpcode(opcode, volumeCCTriggers[*opcode.parameter], Default::volumeCCRange); // case hash("volume_oncc"):
// if (opcode.parameter)
// setValueFromOpcode(opcode, volumeCCTriggers[*opcode.parameter], Default::volumeCCRange);
// break; // break;
case hash("amplitude"): setValueFromOpcode(opcode, amplitude, Default::amplitudeRange); break; case hash("amplitude"):
setValueFromOpcode(opcode, amplitude, Default::amplitudeRange);
break;
case hash("amplitude_cc"): case hash("amplitude_cc"):
case hash("amplitude_oncc"): setCCPairFromOpcode(opcode, amplitudeCC, Default::amplitudeRange); break; case hash("amplitude_oncc"):
case hash("pan"): setValueFromOpcode(opcode, pan, Default::panRange); break; setCCPairFromOpcode(opcode, amplitudeCC, Default::amplitudeRange);
case hash("pan_oncc"): setCCPairFromOpcode(opcode, panCC, Default::panCCRange); break; break;
case hash("position"): setValueFromOpcode(opcode, position, Default::positionRange); break; case hash("pan"):
case hash("position_oncc"): setCCPairFromOpcode(opcode, positionCC, Default::positionCCRange); break; setValueFromOpcode(opcode, pan, Default::panRange);
case hash("width"): setValueFromOpcode(opcode, width, Default::widthRange); break; break;
case hash("width_oncc"): setCCPairFromOpcode(opcode, widthCC, Default::widthCCRange); break; case hash("pan_oncc"):
case hash("amp_keycenter"): setValueFromOpcode(opcode, ampKeycenter, Default::keyRange); break; setCCPairFromOpcode(opcode, panCC, Default::panCCRange);
case hash("amp_keytrack"): setValueFromOpcode(opcode, ampKeytrack, Default::ampKeytrackRange); break; break;
case hash("amp_veltrack"): setValueFromOpcode(opcode, ampVeltrack, Default::ampVeltrackRange); break; case hash("position"):
case hash("amp_random"): setValueFromOpcode(opcode, ampRandom, Default::ampRandomRange); break; setValueFromOpcode(opcode, position, Default::positionRange);
break;
case hash("position_oncc"):
setCCPairFromOpcode(opcode, positionCC, Default::positionCCRange);
break;
case hash("width"):
setValueFromOpcode(opcode, width, Default::widthRange);
break;
case hash("width_oncc"):
setCCPairFromOpcode(opcode, widthCC, Default::widthCCRange);
break;
case hash("amp_keycenter"):
setValueFromOpcode(opcode, ampKeycenter, Default::keyRange);
break;
case hash("amp_keytrack"):
setValueFromOpcode(opcode, ampKeytrack, Default::ampKeytrackRange);
break;
case hash("amp_veltrack"):
setValueFromOpcode(opcode, ampVeltrack, Default::ampVeltrackRange);
break;
case hash("amp_random"):
setValueFromOpcode(opcode, ampRandom, Default::ampRandomRange);
break;
case hash("amp_velcurve_"): case hash("amp_velcurve_"):
if (opcode.parameter && Default::ccRange.containsWithEnd(*opcode.parameter)) if (opcode.parameter && Default::ccRange.containsWithEnd(*opcode.parameter)) {
{
if (auto value = readOpcode(opcode.value, Default::ampVelcurveRange); value) if (auto value = readOpcode(opcode.value, Default::ampVelcurveRange); value)
velocityPoints.emplace_back(*opcode.parameter, *value); velocityPoints.emplace_back(*opcode.parameter, *value);
} }
break; break;
case hash("xfin_lokey"): setRangeStartFromOpcode(opcode, crossfadeKeyInRange, Default::keyRange); break; case hash("xfin_lokey"):
case hash("xfin_hikey"): setRangeEndFromOpcode(opcode, crossfadeKeyInRange, Default::keyRange); break; setRangeStartFromOpcode(opcode, crossfadeKeyInRange, Default::keyRange);
case hash("xfout_lokey"): setRangeStartFromOpcode(opcode, crossfadeKeyOutRange, Default::keyRange); break; break;
case hash("xfout_hikey"): setRangeEndFromOpcode(opcode, crossfadeKeyOutRange, Default::keyRange); break; case hash("xfin_hikey"):
case hash("xfin_lovel"): setRangeStartFromOpcode(opcode, crossfadeVelInRange, Default::velocityRange); break; setRangeEndFromOpcode(opcode, crossfadeKeyInRange, Default::keyRange);
case hash("xfin_hivel"): setRangeEndFromOpcode(opcode, crossfadeVelInRange, Default::velocityRange); break; break;
case hash("xfout_lovel"): setRangeStartFromOpcode(opcode, crossfadeVelOutRange, Default::velocityRange); break; case hash("xfout_lokey"):
case hash("xfout_hivel"): setRangeEndFromOpcode(opcode, crossfadeVelOutRange, Default::velocityRange); break; setRangeStartFromOpcode(opcode, crossfadeKeyOutRange, Default::keyRange);
break;
case hash("xfout_hikey"):
setRangeEndFromOpcode(opcode, crossfadeKeyOutRange, Default::keyRange);
break;
case hash("xfin_lovel"):
setRangeStartFromOpcode(opcode, crossfadeVelInRange, Default::velocityRange);
break;
case hash("xfin_hivel"):
setRangeEndFromOpcode(opcode, crossfadeVelInRange, Default::velocityRange);
break;
case hash("xfout_lovel"):
setRangeStartFromOpcode(opcode, crossfadeVelOutRange, Default::velocityRange);
break;
case hash("xfout_hivel"):
setRangeEndFromOpcode(opcode, crossfadeVelOutRange, Default::velocityRange);
break;
case hash("xf_keycurve"): case hash("xf_keycurve"):
switch (hash(opcode.value)) switch (hash(opcode.value)) {
{
case hash("power"): case hash("power"):
crossfadeKeyCurve = SfzCrossfadeCurve::power; crossfadeKeyCurve = SfzCrossfadeCurve::power;
break; break;
@ -204,8 +294,7 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
} }
break; break;
case hash("xf_velcurve"): case hash("xf_velcurve"):
switch (hash(opcode.value)) switch (hash(opcode.value)) {
{
case hash("power"): case hash("power"):
crossfadeVelCurve = SfzCrossfadeCurve::power; crossfadeVelCurve = SfzCrossfadeCurve::power;
break; break;
@ -218,34 +307,86 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
break; break;
// Performance parameters: pitch // Performance parameters: pitch
case hash("pitch_keycenter"): setValueFromOpcode(opcode, pitchKeycenter, Default::keyRange); break; case hash("pitch_keycenter"):
case hash("pitch_keytrack"): setValueFromOpcode(opcode, pitchKeytrack, Default::pitchKeytrackRange); break; setValueFromOpcode(opcode, pitchKeycenter, Default::keyRange);
case hash("pitch_veltrack"): setValueFromOpcode(opcode, pitchVeltrack, Default::pitchVeltrackRange); break; break;
case hash("pitch_random"): setValueFromOpcode(opcode, pitchRandom, Default::pitchRandomRange); break; case hash("pitch_keytrack"):
case hash("transpose"): setValueFromOpcode(opcode, transpose, Default::transposeRange); break; setValueFromOpcode(opcode, pitchKeytrack, Default::pitchKeytrackRange);
case hash("tune"): setValueFromOpcode(opcode, tune, Default::tuneRange); break; break;
case hash("pitch_veltrack"):
setValueFromOpcode(opcode, pitchVeltrack, Default::pitchVeltrackRange);
break;
case hash("pitch_random"):
setValueFromOpcode(opcode, pitchRandom, Default::pitchRandomRange);
break;
case hash("transpose"):
setValueFromOpcode(opcode, transpose, Default::transposeRange);
break;
case hash("tune"):
setValueFromOpcode(opcode, tune, Default::tuneRange);
break;
// Amplitude Envelope // Amplitude Envelope
case hash("ampeg_attack"): setValueFromOpcode(opcode, amplitudeEG.attack, Default::egTimeRange); break; case hash("ampeg_attack"):
case hash("ampeg_decay"): setValueFromOpcode(opcode, amplitudeEG.decay, Default::egTimeRange); break; setValueFromOpcode(opcode, amplitudeEG.attack, Default::egTimeRange);
case hash("ampeg_delay"): setValueFromOpcode(opcode, amplitudeEG.delay, Default::egTimeRange); break; break;
case hash("ampeg_hold"): setValueFromOpcode(opcode, amplitudeEG.hold, Default::egTimeRange); break; case hash("ampeg_decay"):
case hash("ampeg_release"): setValueFromOpcode(opcode, amplitudeEG.release, Default::egTimeRange); break; setValueFromOpcode(opcode, amplitudeEG.decay, Default::egTimeRange);
case hash("ampeg_start"): setValueFromOpcode(opcode, amplitudeEG.start, Default::egPercentRange); break; break;
case hash("ampeg_sustain"): setValueFromOpcode(opcode, amplitudeEG.sustain, Default::egPercentRange); break; case hash("ampeg_delay"):
case hash("ampeg_vel2attack"): setValueFromOpcode(opcode, amplitudeEG.vel2attack, Default::egOnCCTimeRange); break; setValueFromOpcode(opcode, amplitudeEG.delay, Default::egTimeRange);
case hash("ampeg_vel2decay"): setValueFromOpcode(opcode, amplitudeEG.vel2decay, Default::egOnCCTimeRange); break; break;
case hash("ampeg_vel2delay"): setValueFromOpcode(opcode, amplitudeEG.vel2delay, Default::egOnCCTimeRange); break; case hash("ampeg_hold"):
case hash("ampeg_vel2hold"): setValueFromOpcode(opcode, amplitudeEG.vel2hold, Default::egOnCCTimeRange); break; setValueFromOpcode(opcode, amplitudeEG.hold, Default::egTimeRange);
case hash("ampeg_vel2release"): setValueFromOpcode(opcode, amplitudeEG.vel2release, Default::egOnCCTimeRange); break; break;
case hash("ampeg_vel2sustain"): setValueFromOpcode(opcode, amplitudeEG.vel2sustain, Default::egOnCCPercentRange); break; case hash("ampeg_release"):
case hash("ampeg_attack_oncc"): setCCPairFromOpcode(opcode, amplitudeEG.ccAttack, Default::egOnCCTimeRange); break; setValueFromOpcode(opcode, amplitudeEG.release, Default::egTimeRange);
case hash("ampeg_decay_oncc"): setCCPairFromOpcode(opcode, amplitudeEG.ccDecay, Default::egOnCCTimeRange); break; break;
case hash("ampeg_delay_oncc"): setCCPairFromOpcode(opcode, amplitudeEG.ccDelay, Default::egOnCCTimeRange); break; case hash("ampeg_start"):
case hash("ampeg_hold_oncc"): setCCPairFromOpcode(opcode, amplitudeEG.ccHold, Default::egOnCCTimeRange); break; setValueFromOpcode(opcode, amplitudeEG.start, Default::egPercentRange);
case hash("ampeg_release_oncc"): setCCPairFromOpcode(opcode, amplitudeEG.ccRelease, Default::egOnCCTimeRange); break; break;
case hash("ampeg_start_oncc"): setCCPairFromOpcode(opcode, amplitudeEG.ccStart, Default::egOnCCPercentRange); break; case hash("ampeg_sustain"):
case hash("ampeg_sustain_oncc"): setCCPairFromOpcode(opcode, amplitudeEG.ccSustain, Default::egOnCCPercentRange); break; setValueFromOpcode(opcode, amplitudeEG.sustain, Default::egPercentRange);
break;
case hash("ampeg_vel2attack"):
setValueFromOpcode(opcode, amplitudeEG.vel2attack, Default::egOnCCTimeRange);
break;
case hash("ampeg_vel2decay"):
setValueFromOpcode(opcode, amplitudeEG.vel2decay, Default::egOnCCTimeRange);
break;
case hash("ampeg_vel2delay"):
setValueFromOpcode(opcode, amplitudeEG.vel2delay, Default::egOnCCTimeRange);
break;
case hash("ampeg_vel2hold"):
setValueFromOpcode(opcode, amplitudeEG.vel2hold, Default::egOnCCTimeRange);
break;
case hash("ampeg_vel2release"):
setValueFromOpcode(opcode, amplitudeEG.vel2release, Default::egOnCCTimeRange);
break;
case hash("ampeg_vel2sustain"):
setValueFromOpcode(opcode, amplitudeEG.vel2sustain, Default::egOnCCPercentRange);
break;
case hash("ampeg_attack_oncc"):
setCCPairFromOpcode(opcode, amplitudeEG.ccAttack, Default::egOnCCTimeRange);
break;
case hash("ampeg_decay_oncc"):
setCCPairFromOpcode(opcode, amplitudeEG.ccDecay, Default::egOnCCTimeRange);
break;
case hash("ampeg_delay_oncc"):
setCCPairFromOpcode(opcode, amplitudeEG.ccDelay, Default::egOnCCTimeRange);
break;
case hash("ampeg_hold_oncc"):
setCCPairFromOpcode(opcode, amplitudeEG.ccHold, Default::egOnCCTimeRange);
break;
case hash("ampeg_release_oncc"):
setCCPairFromOpcode(opcode, amplitudeEG.ccRelease, Default::egOnCCTimeRange);
break;
case hash("ampeg_start_oncc"):
setCCPairFromOpcode(opcode, amplitudeEG.ccStart, Default::egOnCCPercentRange);
break;
case hash("ampeg_sustain_oncc"):
setCCPairFromOpcode(opcode, amplitudeEG.ccSustain, Default::egOnCCPercentRange);
break;
// Ignored opcodes // Ignored opcodes
case hash("ampeg_depth"): case hash("ampeg_depth"):
case hash("ampeg_vel2depth"): case hash("ampeg_vel2depth"):
@ -259,13 +400,7 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
bool sfz::Region::isSwitchedOn() const noexcept bool sfz::Region::isSwitchedOn() const noexcept
{ {
return keySwitched && return keySwitched && previousKeySwitched && sequenceSwitched && pitchSwitched && bpmSwitched && aftertouchSwitched && allCCSwitched;
previousKeySwitched &&
sequenceSwitched &&
pitchSwitched &&
bpmSwitched &&
aftertouchSwitched &&
allCCSwitched;
} }
bool sfz::Region::registerNoteOn(int channel, int noteNumber, uint8_t velocity, float randValue) bool sfz::Region::registerNoteOn(int channel, int noteNumber, uint8_t velocity, float randValue)
@ -274,10 +409,8 @@ bool sfz::Region::registerNoteOn(int channel, int noteNumber, uint8_t velocity,
if (!chanOk) if (!chanOk)
return false; return false;
if (keyswitchRange.containsWithEnd(noteNumber)) if (keyswitchRange.containsWithEnd(noteNumber)) {
{ if (keyswitch) {
if (keyswitch)
{
if (*keyswitch == noteNumber) if (*keyswitch == noteNumber)
keySwitched = true; keySwitched = true;
else else
@ -292,8 +425,7 @@ bool sfz::Region::registerNoteOn(int channel, int noteNumber, uint8_t velocity,
} }
const bool keyOk = keyRange.containsWithEnd(noteNumber); const bool keyOk = keyRange.containsWithEnd(noteNumber);
if (keyOk) if (keyOk) {
{
// Update the number of notes playing for the region // Update the number of notes playing for the region
activeNotesInRange++; activeNotesInRange++;
@ -308,9 +440,8 @@ bool sfz::Region::registerNoteOn(int channel, int noteNumber, uint8_t velocity,
if (trigger == SfzTrigger::release_key || velocityOverride == SfzVelocityOverride::previous) if (trigger == SfzTrigger::release_key || velocityOverride == SfzVelocityOverride::previous)
lastNoteVelocities[noteNumber] = velocity; lastNoteVelocities[noteNumber] = velocity;
if (previousNote) if (previousNote) {
{ if (*previousNote == noteNumber)
if ( *previousNote == noteNumber)
previousKeySwitched = true; previousKeySwitched = true;
else else
previousKeySwitched = false; previousKeySwitched = false;
@ -328,7 +459,7 @@ bool sfz::Region::registerNoteOn(int channel, int noteNumber, uint8_t velocity,
const bool firstLegatoNote = (trigger == SfzTrigger::first && activeNotesInRange == 0); const bool firstLegatoNote = (trigger == SfzTrigger::first && activeNotesInRange == 0);
const bool attackTrigger = (trigger == SfzTrigger::attack); const bool attackTrigger = (trigger == SfzTrigger::attack);
const bool notFirstLegatoNote = (trigger == SfzTrigger::legato && activeNotesInRange > 0); const bool notFirstLegatoNote = (trigger == SfzTrigger::legato && activeNotesInRange > 0);
return keyOk && velOk && chanOk && randOk && (attackTrigger || firstLegatoNote || notFirstLegatoNote); return keyOk && velOk && chanOk && randOk && (attackTrigger || firstLegatoNote || notFirstLegatoNote);
} }
@ -338,8 +469,7 @@ bool sfz::Region::registerNoteOff(int channel, int noteNumber, uint8_t velocity
if (!chanOk) if (!chanOk)
return false; return false;
if (keyswitchRange.containsWithEnd(noteNumber)) if (keyswitchRange.containsWithEnd(noteNumber)) {
{
if (keyswitchDown && *keyswitchDown == noteNumber) if (keyswitchDown && *keyswitchDown == noteNumber)
keySwitched = false; keySwitched = false;
@ -355,7 +485,7 @@ bool sfz::Region::registerNoteOff(int channel, int noteNumber, uint8_t velocity
if (!isSwitchedOn()) if (!isSwitchedOn())
return false; return false;
const bool randOk = randRange.contains(randValue); const bool randOk = randRange.contains(randValue);
const bool releaseTrigger = (trigger == SfzTrigger::release || trigger == SfzTrigger::release_key); const bool releaseTrigger = (trigger == SfzTrigger::release || trigger == SfzTrigger::release_key);
return keyOk && chanOk && randOk && releaseTrigger; return keyOk && chanOk && randOk && releaseTrigger;
@ -370,7 +500,7 @@ bool sfz::Region::registerCC(int channel, int ccNumber, uint8_t ccValue)
ccSwitched.set(ccNumber, true); ccSwitched.set(ccNumber, true);
else else
ccSwitched.set(ccNumber, false); ccSwitched.set(ccNumber, false);
if (ccSwitched.all()) if (ccSwitched.all())
allCCSwitched = true; allCCSwitched = true;
else else
@ -386,7 +516,7 @@ void sfz::Region::registerPitchWheel(int channel, int pitch)
{ {
if (!channelRange.containsWithEnd(channel)) if (!channelRange.containsWithEnd(channel))
return; return;
if (bendRange.containsWithEnd(pitch)) if (bendRange.containsWithEnd(pitch))
pitchSwitched = true; pitchSwitched = true;
else else
@ -397,7 +527,7 @@ void sfz::Region::registerAftertouch(int channel, uint8_t aftertouch)
{ {
if (!channelRange.containsWithEnd(channel)) if (!channelRange.containsWithEnd(channel))
return; return;
if (aftertouchRange.containsWithEnd(aftertouch)) if (aftertouchRange.containsWithEnd(aftertouch))
aftertouchSwitched = true; aftertouchSwitched = true;
else else

View file

@ -1,18 +1,18 @@
#pragma once #pragma once
#include "Buffer.h" #include "Buffer.h"
#include "Helpers.h"
#include "Globals.h" #include "Globals.h"
#include "Helpers.h"
#include "SIMDHelpers.h"
#include <array> #include <array>
#include <iostream> #include <iostream>
#include <type_traits> #include <type_traits>
#include "SIMDHelpers.h"
enum class Channel {left, right}; enum class Channel { left,
right };
template<class Type, unsigned int Alignment = SIMDConfig::defaultAlignment> template <class Type, unsigned int Alignment = SIMDConfig::defaultAlignment>
class StereoBuffer class StereoBuffer {
{
public: public:
static constexpr int numChannels { 2 }; static constexpr int numChannels { 2 };
StereoBuffer() = default; StereoBuffer() = default;
@ -20,13 +20,12 @@ public:
{ {
resize(numFrames); resize(numFrames);
} }
bool resize(int numFrames) bool resize(int numFrames)
{ {
// should have a positive number of frames... // should have a positive number of frames...
ASSERT(numFrames >= 0); ASSERT(numFrames >= 0);
if (leftBuffer.resize(static_cast<size_t>(numFrames)) && rightBuffer.resize(static_cast<size_t>(numFrames))) if (leftBuffer.resize(static_cast<size_t>(numFrames)) && rightBuffer.resize(static_cast<size_t>(numFrames))) {
{
this->numFrames = numFrames; this->numFrames = numFrames;
return true; return true;
} }
@ -36,13 +35,14 @@ public:
absl::Span<const Type> getSpan(Channel channel) const absl::Span<const Type> getSpan(Channel channel) const
{ {
switch(channel) switch (channel) {
{ case Channel::left:
case Channel::left: return leftBuffer; return leftBuffer;
case Channel::right: return rightBuffer; case Channel::right:
return rightBuffer;
// Should not be here by construction... // Should not be here by construction...
default: default:
ASSERTFALSE; ASSERTFALSE;
return {}; return {};
} }
} }
@ -50,13 +50,14 @@ public:
Type& getSample(Channel channel, int sampleIndex) noexcept Type& getSample(Channel channel, int sampleIndex) noexcept
{ {
ASSERT(sampleIndex >= 0); ASSERT(sampleIndex >= 0);
switch(channel) switch (channel) {
{ case Channel::left:
case Channel::left: return leftBuffer[sampleIndex]; return leftBuffer[sampleIndex];
case Channel::right: return rightBuffer[sampleIndex]; case Channel::right:
return rightBuffer[sampleIndex];
// Should not be here by construction... // Should not be here by construction...
default: default:
ASSERTFALSE; ASSERTFALSE;
return trash; return trash;
} }
} }
@ -87,21 +88,25 @@ public:
Type* getChannel(Channel channel) noexcept Type* getChannel(Channel channel) noexcept
{ {
switch(channel) switch (channel) {
{ case Channel::left:
case Channel::left: return leftBuffer.data(); return leftBuffer.data();
case Channel::right: return rightBuffer.data(); case Channel::right:
default: return {}; return rightBuffer.data();
default:
return {};
} }
} }
Type* begin(Channel channel) noexcept Type* begin(Channel channel) noexcept
{ {
switch(channel) switch (channel) {
{ case Channel::left:
case Channel::left: return leftBuffer.data(); return leftBuffer.data();
case Channel::right: return rightBuffer.data(); case Channel::right:
default: return {}; return rightBuffer.data();
default:
return {};
} }
} }
std::pair<Type*, Type*> getChannels() noexcept { return { leftBuffer.data(), rightBuffer.data() }; } std::pair<Type*, Type*> getChannels() noexcept { return { leftBuffer.data(), rightBuffer.data() }; }
@ -109,22 +114,26 @@ public:
Type* end(Channel channel) noexcept Type* end(Channel channel) noexcept
{ {
switch(channel) switch (channel) {
{ case Channel::left:
case Channel::left: return leftBuffer.end(); return leftBuffer.end();
case Channel::right: return rightBuffer.end(); case Channel::right:
default: return {}; return rightBuffer.end();
default:
return {};
} }
} }
std::pair<Type*, Type*> ends() { return { leftBuffer.end(), rightBuffer.end() }; } std::pair<Type*, Type*> ends() { return { leftBuffer.end(), rightBuffer.end() }; }
Type* alignedEnd(Channel channel) noexcept Type* alignedEnd(Channel channel) noexcept
{ {
switch(channel) switch (channel) {
{ case Channel::left:
case Channel::left: return leftBuffer.alignedEnd(); return leftBuffer.alignedEnd();
case Channel::right: return rightBuffer.alignedEnd(); case Channel::right:
default: return {}; return rightBuffer.alignedEnd();
default:
return {};
} }
} }
std::pair<Type*, Type*> alignedEnds() { return { leftBuffer.alignedEnd(), rightBuffer.alignedEnd() }; } std::pair<Type*, Type*> alignedEnds() { return { leftBuffer.alignedEnd(), rightBuffer.alignedEnd() }; }

View file

@ -1,19 +1,17 @@
#pragma once #pragma once
#include "FilePool.h"
#include "Parser.h" #include "Parser.h"
#include "Region.h" #include "Region.h"
#include "SfzHelpers.h" #include "SfzHelpers.h"
#include "FilePool.h"
#include <vector>
#include <set>
#include <optional> #include <optional>
#include <random> #include <random>
#include <set>
#include <string_view> #include <string_view>
#include <vector>
namespace sfz namespace sfz {
{
class Synth: public Parser class Synth : public Parser {
{
public: public:
Synth() Synth()
{ {
@ -38,8 +36,7 @@ public:
void renderBlock(StereoBuffer<float>& buffer) void renderBlock(StereoBuffer<float>& buffer)
{ {
for (auto& voice: voices) for (auto& voice : voices) {
{
voice->renderBlock(tempBuffer); voice->renderBlock(tempBuffer);
buffer.add(tempBuffer); buffer.add(tempBuffer);
} }
@ -48,14 +45,15 @@ public:
void noteOn(int delay, int channel, int noteNumber, uint8_t velocity) void noteOn(int delay, int channel, int noteNumber, uint8_t velocity)
{ {
auto randValue = getUniform(); auto randValue = getUniform();
for (auto& region: regions) for (auto& voice : voices)
{ voice->registerNoteOn(delay, channel, noteNumber, velocity);
if (region->registerNoteOn(channel, noteNumber, velocity, randValue))
{ for (auto& region : regions) {
if (region->registerNoteOn(channel, noteNumber, velocity, randValue)) {
auto voice = findFreeVoice(); auto voice = findFreeVoice();
if (voice == nullptr) if (voice == nullptr)
continue; continue;
voice->startVoice(region.get(), channel, noteNumber, velocity, Voice::TriggerType::NoteOn); voice->startVoice(region.get(), channel, noteNumber, velocity, Voice::TriggerType::NoteOn);
} }
} }
@ -64,15 +62,18 @@ public:
void noteOff(int delay, int channel, int noteNumber, uint8_t velocity) void noteOff(int delay, int channel, int noteNumber, uint8_t velocity)
{ {
auto randValue = getUniform(); auto randValue = getUniform();
for (auto& region: regions) for (auto& voice : voices) {
{ if (voice->registerNoteOff(delay, channel, noteNumber, velocity)) {
if (region->registerNoteOff(channel, noteNumber, velocity, randValue)) // do something
{ }
}
for (auto& region : regions) {
if (region->registerNoteOff(channel, noteNumber, velocity, randValue)) {
auto voice = findFreeVoice(); auto voice = findFreeVoice();
if (voice == nullptr) if (voice == nullptr)
continue; continue;
voice->startVoice(region.get(), channel, noteNumber, velocity, Voice::TriggerType::NoteOff);
voice->startVoice(region.get(), channel, noteNumber, velocity, Voice::TriggerType::NoteOff); voice->startVoice(region.get(), channel, noteNumber, velocity, Voice::TriggerType::NoteOff);
} }
} }
@ -84,17 +85,18 @@ public:
protected: protected:
void callback(std::string_view header, std::vector<Opcode> members) final; void callback(std::string_view header, std::vector<Opcode> members) final;
private: private:
Voice* findFreeVoice() Voice* findFreeVoice()
{ {
auto freeVoice = absl::c_find_if(voices, [](const auto& voice) { return voice->isFree(); }); auto freeVoice = absl::c_find_if(voices, [](const auto& voice) { return voice->isFree(); });
if (freeVoice == voices.end()) if (freeVoice == voices.end()) {
{
DBG("Voices are overloaded, can't start a new note"); DBG("Voices are overloaded, can't start a new note");
return {}; return {};
} }
return freeVoice->get(); return freeVoice->get();
} }
bool hasGlobal { false }; bool hasGlobal { false };
bool hasControl { false }; bool hasControl { false };
int numGroups { 0 }; int numGroups { 0 };
@ -122,9 +124,10 @@ private:
StereoBuffer<float> tempBuffer { config::defaultSamplesPerBlock }; StereoBuffer<float> tempBuffer { config::defaultSamplesPerBlock };
int samplesPerBlock { config::defaultSamplesPerBlock }; int samplesPerBlock { config::defaultSamplesPerBlock };
float sampleRate { config::defaultSampleRate }; float sampleRate { config::defaultSampleRate };
std::random_device rd { }; std::random_device rd {};
std::mt19937 randomGenerator { rd() }; std::mt19937 randomGenerator { rd() };
std::uniform_real_distribution<float> randomDistribution { 0, 1 }; std::uniform_real_distribution<float> randomDistribution { 0, 1 };
float getUniform() float getUniform()
{ {
return randomDistribution(randomGenerator); return randomDistribution(randomGenerator);

View file

@ -32,8 +32,8 @@ public:
return (region == nullptr); return (region == nullptr);
} }
bool registerNoteOn(int delay, int channel, int noteNumber, uint8_t velocity); void registerNoteOn(int delay, int channel, int noteNumber, uint8_t velocity);
void registerNoteOff(int delay, int channel, int noteNumber, uint8_t velocity); bool registerNoteOff(int delay, int channel, int noteNumber, uint8_t velocity);
bool registerCC(int delay, int channel, int ccNumber, uint8_t ccValue); bool registerCC(int delay, int channel, int ccNumber, uint8_t ccValue);
void registerPitchWheel(int delay, int channel, int pitch); void registerPitchWheel(int delay, int channel, int pitch);
void registerAftertouch(int delay, int channel, uint8_t aftertouch); void registerAftertouch(int delay, int channel, uint8_t aftertouch);