Format
This commit is contained in:
parent
0e89a0b2c6
commit
5d57a5ad24
4 changed files with 388 additions and 246 deletions
|
|
@ -4,89 +4,125 @@
|
|||
|
||||
bool sfz::Region::parseOpcode(const Opcode& opcode)
|
||||
{
|
||||
switch (hash(opcode.opcode))
|
||||
{
|
||||
switch (hash(opcode.opcode)) {
|
||||
// Sound source: sample playback
|
||||
case hash("sample"):
|
||||
sample = absl::StrReplaceAll(trim(opcode.value), {{"\\", "/"}});
|
||||
break;
|
||||
case hash("delay"): setValueFromOpcode(opcode, delay, Default::delayRange); break;
|
||||
case hash("delay_random"): setValueFromOpcode(opcode, delayRandom, Default::delayRange); 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("sample"):
|
||||
sample = absl::StrReplaceAll(trim(opcode.value), { { "\\", "/" } });
|
||||
break;
|
||||
case hash("delay"):
|
||||
setValueFromOpcode(opcode, delay, Default::delayRange);
|
||||
break;
|
||||
case hash("delay_random"):
|
||||
setValueFromOpcode(opcode, delayRandom, Default::delayRange);
|
||||
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("loop_mode"):
|
||||
switch(hash(opcode.value))
|
||||
{
|
||||
case hash("no_loop"):
|
||||
loopMode = SfzLoopMode::no_loop;
|
||||
break;
|
||||
case hash("one_shot"):
|
||||
loopMode = SfzLoopMode::one_shot;
|
||||
break;
|
||||
case hash("loop_continuous"):
|
||||
loopMode = SfzLoopMode::loop_continuous;
|
||||
break;
|
||||
case hash("loop_sustain"):
|
||||
loopMode = SfzLoopMode::loop_sustain;
|
||||
break;
|
||||
default:
|
||||
DBG("Unkown loop mode:" << std::string(opcode.value));
|
||||
switch (hash(opcode.value)) {
|
||||
case hash("no_loop"):
|
||||
loopMode = SfzLoopMode::no_loop;
|
||||
break;
|
||||
case hash("one_shot"):
|
||||
loopMode = SfzLoopMode::one_shot;
|
||||
break;
|
||||
case hash("loop_continuous"):
|
||||
loopMode = SfzLoopMode::loop_continuous;
|
||||
break;
|
||||
case hash("loop_sustain"):
|
||||
loopMode = SfzLoopMode::loop_sustain;
|
||||
break;
|
||||
default:
|
||||
DBG("Unkown loop mode:" << std::string(opcode.value));
|
||||
}
|
||||
break;
|
||||
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("loop_start"): setRangeStartFromOpcode(opcode, loopRange, Default::loopRange); break;
|
||||
case hash("loop_start"):
|
||||
setRangeStartFromOpcode(opcode, loopRange, Default::loopRange);
|
||||
break;
|
||||
|
||||
// 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("off_by"): setValueFromOpcode(opcode, offBy, Default::groupRange); break;
|
||||
case hash("off_by"):
|
||||
setValueFromOpcode(opcode, offBy, Default::groupRange);
|
||||
break;
|
||||
case hash("off_mode"):
|
||||
switch(hash(opcode.value))
|
||||
{
|
||||
case hash("fast"):
|
||||
offMode = SfzOffMode::fast;
|
||||
break;
|
||||
case hash("normal"):
|
||||
offMode = SfzOffMode::normal;
|
||||
break;
|
||||
default:
|
||||
DBG("Unkown off mode:" << std::string(opcode.value));
|
||||
switch (hash(opcode.value)) {
|
||||
case hash("fast"):
|
||||
offMode = SfzOffMode::fast;
|
||||
break;
|
||||
case hash("normal"):
|
||||
offMode = SfzOffMode::normal;
|
||||
break;
|
||||
default:
|
||||
DBG("Unkown off mode:" << std::string(opcode.value));
|
||||
}
|
||||
break;
|
||||
// Region logic: key mapping
|
||||
case hash("lokey"): setRangeStartFromOpcode(opcode, keyRange, Default::keyRange); break;
|
||||
case hash("hikey"): setRangeEndFromOpcode(opcode, keyRange, Default::keyRange); break;
|
||||
case hash("lokey"):
|
||||
setRangeStartFromOpcode(opcode, keyRange, Default::keyRange);
|
||||
break;
|
||||
case hash("hikey"):
|
||||
setRangeEndFromOpcode(opcode, keyRange, Default::keyRange);
|
||||
break;
|
||||
case hash("key"):
|
||||
setRangeStartFromOpcode(opcode, keyRange, Default::keyRange);
|
||||
setRangeEndFromOpcode(opcode, keyRange, Default::keyRange);
|
||||
setValueFromOpcode(opcode, pitchKeycenter, Default::keyRange);
|
||||
break;
|
||||
case hash("lovel"): setRangeStartFromOpcode(opcode, velocityRange, Default::velocityRange); break;
|
||||
case hash("hivel"): setRangeEndFromOpcode(opcode, velocityRange, Default::velocityRange); break;
|
||||
|
||||
case hash("lovel"):
|
||||
setRangeStartFromOpcode(opcode, velocityRange, Default::velocityRange);
|
||||
break;
|
||||
case hash("hivel"):
|
||||
setRangeEndFromOpcode(opcode, velocityRange, Default::velocityRange);
|
||||
break;
|
||||
|
||||
// Region logic: MIDI conditions
|
||||
case hash("lochan"): setRangeStartFromOpcode(opcode, channelRange, Default::channelRange); break;
|
||||
case hash("hichan"): setRangeEndFromOpcode(opcode, channelRange, Default::channelRange); 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)
|
||||
{
|
||||
case hash("lochan"):
|
||||
setRangeStartFromOpcode(opcode, channelRange, Default::channelRange);
|
||||
break;
|
||||
case hash("hichan"):
|
||||
setRangeEndFromOpcode(opcode, channelRange, Default::channelRange);
|
||||
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);
|
||||
}
|
||||
break;
|
||||
case hash("hicc"):
|
||||
if (opcode.parameter)
|
||||
setRangeEndFromOpcode(opcode, ccConditions[*opcode.parameter], Default::ccRange);
|
||||
if (opcode.parameter)
|
||||
setRangeEndFromOpcode(opcode, ccConditions[*opcode.parameter], Default::ccRange);
|
||||
break;
|
||||
case hash("sw_lokey"): setRangeStartFromOpcode(opcode, keyswitchRange, Default::keyRange); break;
|
||||
case hash("sw_hikey"): setRangeEndFromOpcode(opcode, keyswitchRange, Default::keyRange); break;
|
||||
case hash("sw_last"):
|
||||
case hash("sw_lokey"):
|
||||
setRangeStartFromOpcode(opcode, keyswitchRange, Default::keyRange);
|
||||
break;
|
||||
case hash("sw_hikey"):
|
||||
setRangeEndFromOpcode(opcode, keyswitchRange, Default::keyRange);
|
||||
break;
|
||||
case hash("sw_last"):
|
||||
setValueFromOpcode(opcode, keyswitch, Default::keyRange);
|
||||
keySwitched = false;
|
||||
break;
|
||||
|
|
@ -94,105 +130,159 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
|
|||
setValueFromOpcode(opcode, keyswitchDown, Default::keyRange);
|
||||
keySwitched = false;
|
||||
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"):
|
||||
setValueFromOpcode(opcode, previousNote, Default::keyRange);
|
||||
previousKeySwitched = false;
|
||||
break;
|
||||
case hash("sw_vel"):
|
||||
switch(hash(opcode.value))
|
||||
{
|
||||
case hash("current"):
|
||||
velocityOverride = SfzVelocityOverride::current;
|
||||
break;
|
||||
case hash("previous"):
|
||||
velocityOverride = SfzVelocityOverride::previous;
|
||||
break;
|
||||
default:
|
||||
DBG("Unknown velocity mode: " << std::string(opcode.value));
|
||||
switch (hash(opcode.value)) {
|
||||
case hash("current"):
|
||||
velocityOverride = SfzVelocityOverride::current;
|
||||
break;
|
||||
case hash("previous"):
|
||||
velocityOverride = SfzVelocityOverride::previous;
|
||||
break;
|
||||
default:
|
||||
DBG("Unknown velocity mode: " << std::string(opcode.value));
|
||||
}
|
||||
break;
|
||||
// Region logic: internal conditions
|
||||
case hash("lochanaft"): setRangeStartFromOpcode(opcode, aftertouchRange, Default::aftertouchRange); break;
|
||||
case hash("hichanaft"): setRangeEndFromOpcode(opcode, aftertouchRange, Default::aftertouchRange); 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("lochanaft"):
|
||||
setRangeStartFromOpcode(opcode, aftertouchRange, Default::aftertouchRange);
|
||||
break;
|
||||
case hash("hichanaft"):
|
||||
setRangeEndFromOpcode(opcode, aftertouchRange, Default::aftertouchRange);
|
||||
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"):
|
||||
setValueFromOpcode(opcode, sequencePosition, Default::sequenceRange);
|
||||
sequenceSwitched = (opcode.value == "1");
|
||||
break;
|
||||
// Region logic: triggers
|
||||
case hash("trigger"):
|
||||
switch(hash(opcode.value))
|
||||
{
|
||||
case hash("attack"):
|
||||
trigger = SfzTrigger::attack;
|
||||
break;
|
||||
case hash("first"):
|
||||
trigger = SfzTrigger::first;
|
||||
break;
|
||||
case hash("legato"):
|
||||
trigger = SfzTrigger::legato;
|
||||
break;
|
||||
case hash("release"):
|
||||
trigger = SfzTrigger::release;
|
||||
break;
|
||||
case hash("release_key"):
|
||||
trigger = SfzTrigger::release_key;
|
||||
break;
|
||||
default:
|
||||
DBG("Unknown trigger mode: " << std::string(opcode.value));
|
||||
switch (hash(opcode.value)) {
|
||||
case hash("attack"):
|
||||
trigger = SfzTrigger::attack;
|
||||
break;
|
||||
case hash("first"):
|
||||
trigger = SfzTrigger::first;
|
||||
break;
|
||||
case hash("legato"):
|
||||
trigger = SfzTrigger::legato;
|
||||
break;
|
||||
case hash("release"):
|
||||
trigger = SfzTrigger::release;
|
||||
break;
|
||||
case hash("release_key"):
|
||||
trigger = SfzTrigger::release_key;
|
||||
break;
|
||||
default:
|
||||
DBG("Unknown trigger mode: " << std::string(opcode.value));
|
||||
}
|
||||
break;
|
||||
case hash("on_locc"):
|
||||
if (opcode.parameter)
|
||||
setRangeStartFromOpcode(opcode, ccTriggers[*opcode.parameter], Default::ccRange);
|
||||
case hash("on_locc"):
|
||||
if (opcode.parameter)
|
||||
setRangeStartFromOpcode(opcode, ccTriggers[*opcode.parameter], Default::ccRange);
|
||||
break;
|
||||
case hash("on_hicc"):
|
||||
if (opcode.parameter)
|
||||
setRangeEndFromOpcode(opcode, ccTriggers[*opcode.parameter], Default::ccRange);
|
||||
if (opcode.parameter)
|
||||
setRangeEndFromOpcode(opcode, ccTriggers[*opcode.parameter], Default::ccRange);
|
||||
break;
|
||||
|
||||
// Performance parameters: amplifier
|
||||
case hash("volume"): setValueFromOpcode(opcode, volume, Default::volumeRange); break;
|
||||
// case hash("volume_oncc"):
|
||||
// if (opcode.parameter)
|
||||
// setValueFromOpcode(opcode, volumeCCTriggers[*opcode.parameter], Default::volumeCCRange);
|
||||
case hash("volume"):
|
||||
setValueFromOpcode(opcode, volume, Default::volumeRange);
|
||||
break;
|
||||
// case hash("volume_oncc"):
|
||||
// if (opcode.parameter)
|
||||
// setValueFromOpcode(opcode, volumeCCTriggers[*opcode.parameter], Default::volumeCCRange);
|
||||
// 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_oncc"): setCCPairFromOpcode(opcode, amplitudeCC, Default::amplitudeRange); break;
|
||||
case hash("pan"): setValueFromOpcode(opcode, pan, Default::panRange); break;
|
||||
case hash("pan_oncc"): setCCPairFromOpcode(opcode, panCC, Default::panCCRange); break;
|
||||
case hash("position"): 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("amplitude_oncc"):
|
||||
setCCPairFromOpcode(opcode, amplitudeCC, Default::amplitudeRange);
|
||||
break;
|
||||
case hash("pan"):
|
||||
setValueFromOpcode(opcode, pan, Default::panRange);
|
||||
break;
|
||||
case hash("pan_oncc"):
|
||||
setCCPairFromOpcode(opcode, panCC, Default::panCCRange);
|
||||
break;
|
||||
case hash("position"):
|
||||
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_"):
|
||||
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)
|
||||
velocityPoints.emplace_back(*opcode.parameter, *value);
|
||||
}
|
||||
break;
|
||||
case hash("xfin_lokey"): setRangeStartFromOpcode(opcode, crossfadeKeyInRange, Default::keyRange); break;
|
||||
case hash("xfin_hikey"): setRangeEndFromOpcode(opcode, crossfadeKeyInRange, Default::keyRange); break;
|
||||
case hash("xfout_lokey"): 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("xfin_lokey"):
|
||||
setRangeStartFromOpcode(opcode, crossfadeKeyInRange, Default::keyRange);
|
||||
break;
|
||||
case hash("xfin_hikey"):
|
||||
setRangeEndFromOpcode(opcode, crossfadeKeyInRange, Default::keyRange);
|
||||
break;
|
||||
case hash("xfout_lokey"):
|
||||
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"):
|
||||
switch (hash(opcode.value))
|
||||
{
|
||||
switch (hash(opcode.value)) {
|
||||
case hash("power"):
|
||||
crossfadeKeyCurve = SfzCrossfadeCurve::power;
|
||||
break;
|
||||
|
|
@ -204,8 +294,7 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
|
|||
}
|
||||
break;
|
||||
case hash("xf_velcurve"):
|
||||
switch (hash(opcode.value))
|
||||
{
|
||||
switch (hash(opcode.value)) {
|
||||
case hash("power"):
|
||||
crossfadeVelCurve = SfzCrossfadeCurve::power;
|
||||
break;
|
||||
|
|
@ -218,34 +307,86 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
|
|||
break;
|
||||
|
||||
// Performance parameters: pitch
|
||||
case hash("pitch_keycenter"): setValueFromOpcode(opcode, pitchKeycenter, Default::keyRange); break;
|
||||
case hash("pitch_keytrack"): setValueFromOpcode(opcode, pitchKeytrack, Default::pitchKeytrackRange); 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;
|
||||
case hash("pitch_keycenter"):
|
||||
setValueFromOpcode(opcode, pitchKeycenter, Default::keyRange);
|
||||
break;
|
||||
case hash("pitch_keytrack"):
|
||||
setValueFromOpcode(opcode, pitchKeytrack, Default::pitchKeytrackRange);
|
||||
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
|
||||
case hash("ampeg_attack"): setValueFromOpcode(opcode, amplitudeEG.attack, Default::egTimeRange); break;
|
||||
case hash("ampeg_decay"): setValueFromOpcode(opcode, amplitudeEG.decay, Default::egTimeRange); break;
|
||||
case hash("ampeg_delay"): setValueFromOpcode(opcode, amplitudeEG.delay, Default::egTimeRange); break;
|
||||
case hash("ampeg_hold"): setValueFromOpcode(opcode, amplitudeEG.hold, Default::egTimeRange); break;
|
||||
case hash("ampeg_release"): setValueFromOpcode(opcode, amplitudeEG.release, Default::egTimeRange); break;
|
||||
case hash("ampeg_start"): setValueFromOpcode(opcode, amplitudeEG.start, Default::egPercentRange); break;
|
||||
case hash("ampeg_sustain"): 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;
|
||||
case hash("ampeg_attack"):
|
||||
setValueFromOpcode(opcode, amplitudeEG.attack, Default::egTimeRange);
|
||||
break;
|
||||
case hash("ampeg_decay"):
|
||||
setValueFromOpcode(opcode, amplitudeEG.decay, Default::egTimeRange);
|
||||
break;
|
||||
case hash("ampeg_delay"):
|
||||
setValueFromOpcode(opcode, amplitudeEG.delay, Default::egTimeRange);
|
||||
break;
|
||||
case hash("ampeg_hold"):
|
||||
setValueFromOpcode(opcode, amplitudeEG.hold, Default::egTimeRange);
|
||||
break;
|
||||
case hash("ampeg_release"):
|
||||
setValueFromOpcode(opcode, amplitudeEG.release, Default::egTimeRange);
|
||||
break;
|
||||
case hash("ampeg_start"):
|
||||
setValueFromOpcode(opcode, amplitudeEG.start, Default::egPercentRange);
|
||||
break;
|
||||
case hash("ampeg_sustain"):
|
||||
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
|
||||
case hash("ampeg_depth"):
|
||||
case hash("ampeg_vel2depth"):
|
||||
|
|
@ -259,13 +400,7 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
|
|||
|
||||
bool sfz::Region::isSwitchedOn() const noexcept
|
||||
{
|
||||
return keySwitched &&
|
||||
previousKeySwitched &&
|
||||
sequenceSwitched &&
|
||||
pitchSwitched &&
|
||||
bpmSwitched &&
|
||||
aftertouchSwitched &&
|
||||
allCCSwitched;
|
||||
return keySwitched && previousKeySwitched && sequenceSwitched && pitchSwitched && bpmSwitched && aftertouchSwitched && allCCSwitched;
|
||||
}
|
||||
|
||||
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)
|
||||
return false;
|
||||
|
||||
if (keyswitchRange.containsWithEnd(noteNumber))
|
||||
{
|
||||
if (keyswitch)
|
||||
{
|
||||
if (keyswitchRange.containsWithEnd(noteNumber)) {
|
||||
if (keyswitch) {
|
||||
if (*keyswitch == noteNumber)
|
||||
keySwitched = true;
|
||||
else
|
||||
|
|
@ -292,8 +425,7 @@ bool sfz::Region::registerNoteOn(int channel, int noteNumber, uint8_t velocity,
|
|||
}
|
||||
|
||||
const bool keyOk = keyRange.containsWithEnd(noteNumber);
|
||||
if (keyOk)
|
||||
{
|
||||
if (keyOk) {
|
||||
// Update the number of notes playing for the region
|
||||
activeNotesInRange++;
|
||||
|
||||
|
|
@ -308,9 +440,8 @@ bool sfz::Region::registerNoteOn(int channel, int noteNumber, uint8_t velocity,
|
|||
if (trigger == SfzTrigger::release_key || velocityOverride == SfzVelocityOverride::previous)
|
||||
lastNoteVelocities[noteNumber] = velocity;
|
||||
|
||||
if (previousNote)
|
||||
{
|
||||
if ( *previousNote == noteNumber)
|
||||
if (previousNote) {
|
||||
if (*previousNote == noteNumber)
|
||||
previousKeySwitched = true;
|
||||
else
|
||||
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 attackTrigger = (trigger == SfzTrigger::attack);
|
||||
const bool notFirstLegatoNote = (trigger == SfzTrigger::legato && activeNotesInRange > 0);
|
||||
|
||||
|
||||
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)
|
||||
return false;
|
||||
|
||||
if (keyswitchRange.containsWithEnd(noteNumber))
|
||||
{
|
||||
if (keyswitchRange.containsWithEnd(noteNumber)) {
|
||||
if (keyswitchDown && *keyswitchDown == noteNumber)
|
||||
keySwitched = false;
|
||||
|
||||
|
|
@ -355,7 +485,7 @@ bool sfz::Region::registerNoteOff(int channel, int noteNumber, uint8_t velocity
|
|||
|
||||
if (!isSwitchedOn())
|
||||
return false;
|
||||
|
||||
|
||||
const bool randOk = randRange.contains(randValue);
|
||||
const bool releaseTrigger = (trigger == SfzTrigger::release || trigger == SfzTrigger::release_key);
|
||||
return keyOk && chanOk && randOk && releaseTrigger;
|
||||
|
|
@ -370,7 +500,7 @@ bool sfz::Region::registerCC(int channel, int ccNumber, uint8_t ccValue)
|
|||
ccSwitched.set(ccNumber, true);
|
||||
else
|
||||
ccSwitched.set(ccNumber, false);
|
||||
|
||||
|
||||
if (ccSwitched.all())
|
||||
allCCSwitched = true;
|
||||
else
|
||||
|
|
@ -386,7 +516,7 @@ void sfz::Region::registerPitchWheel(int channel, int pitch)
|
|||
{
|
||||
if (!channelRange.containsWithEnd(channel))
|
||||
return;
|
||||
|
||||
|
||||
if (bendRange.containsWithEnd(pitch))
|
||||
pitchSwitched = true;
|
||||
else
|
||||
|
|
@ -397,7 +527,7 @@ void sfz::Region::registerAftertouch(int channel, uint8_t aftertouch)
|
|||
{
|
||||
if (!channelRange.containsWithEnd(channel))
|
||||
return;
|
||||
|
||||
|
||||
if (aftertouchRange.containsWithEnd(aftertouch))
|
||||
aftertouchSwitched = true;
|
||||
else
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
#pragma once
|
||||
#include "Buffer.h"
|
||||
#include "Helpers.h"
|
||||
#include "Globals.h"
|
||||
#include "Helpers.h"
|
||||
|
||||
#include "SIMDHelpers.h"
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
#include <type_traits>
|
||||
#include "SIMDHelpers.h"
|
||||
|
||||
enum class Channel {left, right};
|
||||
enum class Channel { left,
|
||||
right };
|
||||
|
||||
template<class Type, unsigned int Alignment = SIMDConfig::defaultAlignment>
|
||||
class StereoBuffer
|
||||
{
|
||||
template <class Type, unsigned int Alignment = SIMDConfig::defaultAlignment>
|
||||
class StereoBuffer {
|
||||
public:
|
||||
static constexpr int numChannels { 2 };
|
||||
StereoBuffer() = default;
|
||||
|
|
@ -20,13 +20,12 @@ public:
|
|||
{
|
||||
resize(numFrames);
|
||||
}
|
||||
|
||||
bool resize(int numFrames)
|
||||
|
||||
bool resize(int numFrames)
|
||||
{
|
||||
// should have a positive number of frames...
|
||||
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;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -36,13 +35,14 @@ public:
|
|||
|
||||
absl::Span<const Type> getSpan(Channel channel) const
|
||||
{
|
||||
switch(channel)
|
||||
{
|
||||
case Channel::left: return leftBuffer;
|
||||
case Channel::right: return rightBuffer;
|
||||
switch (channel) {
|
||||
case Channel::left:
|
||||
return leftBuffer;
|
||||
case Channel::right:
|
||||
return rightBuffer;
|
||||
// Should not be here by construction...
|
||||
default:
|
||||
ASSERTFALSE;
|
||||
default:
|
||||
ASSERTFALSE;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
|
@ -50,13 +50,14 @@ public:
|
|||
Type& getSample(Channel channel, int sampleIndex) noexcept
|
||||
{
|
||||
ASSERT(sampleIndex >= 0);
|
||||
switch(channel)
|
||||
{
|
||||
case Channel::left: return leftBuffer[sampleIndex];
|
||||
case Channel::right: return rightBuffer[sampleIndex];
|
||||
switch (channel) {
|
||||
case Channel::left:
|
||||
return leftBuffer[sampleIndex];
|
||||
case Channel::right:
|
||||
return rightBuffer[sampleIndex];
|
||||
// Should not be here by construction...
|
||||
default:
|
||||
ASSERTFALSE;
|
||||
default:
|
||||
ASSERTFALSE;
|
||||
return trash;
|
||||
}
|
||||
}
|
||||
|
|
@ -87,21 +88,25 @@ public:
|
|||
|
||||
Type* getChannel(Channel channel) noexcept
|
||||
{
|
||||
switch(channel)
|
||||
{
|
||||
case Channel::left: return leftBuffer.data();
|
||||
case Channel::right: return rightBuffer.data();
|
||||
default: return {};
|
||||
switch (channel) {
|
||||
case Channel::left:
|
||||
return leftBuffer.data();
|
||||
case Channel::right:
|
||||
return rightBuffer.data();
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
Type* begin(Channel channel) noexcept
|
||||
{
|
||||
switch(channel)
|
||||
{
|
||||
case Channel::left: return leftBuffer.data();
|
||||
case Channel::right: return rightBuffer.data();
|
||||
default: return {};
|
||||
switch (channel) {
|
||||
case Channel::left:
|
||||
return leftBuffer.data();
|
||||
case Channel::right:
|
||||
return rightBuffer.data();
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
std::pair<Type*, Type*> getChannels() noexcept { return { leftBuffer.data(), rightBuffer.data() }; }
|
||||
|
|
@ -109,22 +114,26 @@ public:
|
|||
|
||||
Type* end(Channel channel) noexcept
|
||||
{
|
||||
switch(channel)
|
||||
{
|
||||
case Channel::left: return leftBuffer.end();
|
||||
case Channel::right: return rightBuffer.end();
|
||||
default: return {};
|
||||
switch (channel) {
|
||||
case Channel::left:
|
||||
return leftBuffer.end();
|
||||
case Channel::right:
|
||||
return rightBuffer.end();
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
std::pair<Type*, Type*> ends() { return { leftBuffer.end(), rightBuffer.end() }; }
|
||||
|
||||
Type* alignedEnd(Channel channel) noexcept
|
||||
{
|
||||
switch(channel)
|
||||
{
|
||||
case Channel::left: return leftBuffer.alignedEnd();
|
||||
case Channel::right: return rightBuffer.alignedEnd();
|
||||
default: return {};
|
||||
switch (channel) {
|
||||
case Channel::left:
|
||||
return leftBuffer.alignedEnd();
|
||||
case Channel::right:
|
||||
return rightBuffer.alignedEnd();
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
std::pair<Type*, Type*> alignedEnds() { return { leftBuffer.alignedEnd(), rightBuffer.alignedEnd() }; }
|
||||
|
|
|
|||
|
|
@ -1,19 +1,17 @@
|
|||
#pragma once
|
||||
#include "FilePool.h"
|
||||
#include "Parser.h"
|
||||
#include "Region.h"
|
||||
#include "SfzHelpers.h"
|
||||
#include "FilePool.h"
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <optional>
|
||||
#include <random>
|
||||
#include <set>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
namespace sfz
|
||||
{
|
||||
namespace sfz {
|
||||
|
||||
class Synth: public Parser
|
||||
{
|
||||
class Synth : public Parser {
|
||||
public:
|
||||
Synth()
|
||||
{
|
||||
|
|
@ -38,8 +36,7 @@ public:
|
|||
|
||||
void renderBlock(StereoBuffer<float>& buffer)
|
||||
{
|
||||
for (auto& voice: voices)
|
||||
{
|
||||
for (auto& voice : voices) {
|
||||
voice->renderBlock(tempBuffer);
|
||||
buffer.add(tempBuffer);
|
||||
}
|
||||
|
|
@ -48,14 +45,15 @@ public:
|
|||
void noteOn(int delay, int channel, int noteNumber, uint8_t velocity)
|
||||
{
|
||||
auto randValue = getUniform();
|
||||
for (auto& region: regions)
|
||||
{
|
||||
if (region->registerNoteOn(channel, noteNumber, velocity, randValue))
|
||||
{
|
||||
for (auto& voice : voices)
|
||||
voice->registerNoteOn(delay, channel, noteNumber, velocity);
|
||||
|
||||
for (auto& region : regions) {
|
||||
if (region->registerNoteOn(channel, noteNumber, velocity, randValue)) {
|
||||
auto voice = findFreeVoice();
|
||||
if (voice == nullptr)
|
||||
continue;
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
auto randValue = getUniform();
|
||||
for (auto& region: regions)
|
||||
{
|
||||
if (region->registerNoteOff(channel, noteNumber, velocity, randValue))
|
||||
{
|
||||
for (auto& voice : voices) {
|
||||
if (voice->registerNoteOff(delay, channel, noteNumber, velocity)) {
|
||||
// do something
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& region : regions) {
|
||||
if (region->registerNoteOff(channel, noteNumber, velocity, randValue)) {
|
||||
auto voice = findFreeVoice();
|
||||
if (voice == nullptr)
|
||||
continue;
|
||||
|
||||
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:
|
||||
void callback(std::string_view header, std::vector<Opcode> members) final;
|
||||
|
||||
private:
|
||||
Voice* findFreeVoice()
|
||||
{
|
||||
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");
|
||||
return {};
|
||||
}
|
||||
return freeVoice->get();
|
||||
}
|
||||
|
||||
bool hasGlobal { false };
|
||||
bool hasControl { false };
|
||||
int numGroups { 0 };
|
||||
|
|
@ -122,9 +124,10 @@ private:
|
|||
StereoBuffer<float> tempBuffer { config::defaultSamplesPerBlock };
|
||||
int samplesPerBlock { config::defaultSamplesPerBlock };
|
||||
float sampleRate { config::defaultSampleRate };
|
||||
std::random_device rd { };
|
||||
std::random_device rd {};
|
||||
std::mt19937 randomGenerator { rd() };
|
||||
std::uniform_real_distribution<float> randomDistribution { 0, 1 };
|
||||
|
||||
float getUniform()
|
||||
{
|
||||
return randomDistribution(randomGenerator);
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@ public:
|
|||
return (region == nullptr);
|
||||
}
|
||||
|
||||
bool registerNoteOn(int delay, int channel, int noteNumber, uint8_t velocity);
|
||||
void registerNoteOff(int delay, int channel, int noteNumber, uint8_t velocity);
|
||||
void registerNoteOn(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);
|
||||
void registerPitchWheel(int delay, int channel, int pitch);
|
||||
void registerAftertouch(int delay, int channel, uint8_t aftertouch);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue