Add a modifier structure and rename the ccvalue pair

This commit is contained in:
Paul Fd 2020-04-06 01:19:40 +02:00
parent 0fd1c235de
commit 61d1c568a8
12 changed files with 108 additions and 118 deletions

View file

@ -44,11 +44,11 @@ public:
*/ */
const ValueType& getWithDefault(int index) const noexcept const ValueType& getWithDefault(int index) const noexcept
{ {
auto it = absl::c_lower_bound(container, index, CCValuePairComparator<ValueType>{}); auto it = absl::c_lower_bound(container, index, CCDataComparator<ValueType>{});
if (it == container.end() || it->cc != index) { if (it == container.end() || it->cc != index) {
return defaultValue; return defaultValue;
} else { } else {
return it->value; return it->data;
} }
} }
@ -60,12 +60,12 @@ public:
*/ */
ValueType& operator[](const int& index) noexcept ValueType& operator[](const int& index) noexcept
{ {
auto it = absl::c_lower_bound(container, index, CCValuePairComparator<ValueType>{}); auto it = absl::c_lower_bound(container, index, CCDataComparator<ValueType>{});
if (it == container.end() || it->cc != index) { if (it == container.end() || it->cc != index) {
auto inserted = container.insert(it, { index, defaultValue }); auto inserted = container.insert(it, { index, defaultValue });
return inserted->value; return inserted->data;
} else { } else {
return it->value; return it->data;
} }
} }
@ -85,16 +85,16 @@ public:
*/ */
bool contains(int index) const noexcept bool contains(int index) const noexcept
{ {
return absl::c_binary_search(container, index, CCValuePairComparator<ValueType>{}); return absl::c_binary_search(container, index, CCDataComparator<ValueType>{});
} }
typename std::vector<CCValuePair<ValueType>>::const_iterator begin() const { return container.cbegin(); } typename std::vector<CCData<ValueType>>::const_iterator begin() const { return container.cbegin(); }
typename std::vector<CCValuePair<ValueType>>::const_iterator end() const { return container.cend(); } typename std::vector<CCData<ValueType>>::const_iterator end() const { return container.cend(); }
private: private:
// typename std::vector<std::pair<int, ValueType>>::iterator begin() { return container.begin(); } // typename std::vector<std::pair<int, ValueType>>::iterator begin() { return container.begin(); }
// typename std::vector<std::pair<int, ValueType>>::iterator end() { return container.end(); } // typename std::vector<std::pair<int, ValueType>>::iterator end() { return container.end(); }
const ValueType defaultValue; const ValueType defaultValue;
std::vector<CCValuePair<ValueType>> container; std::vector<CCData<ValueType>> container;
LEAK_DETECTOR(CCMap); LEAK_DETECTOR(CCMap);
}; };
} }

View file

@ -58,7 +58,6 @@ namespace Default
constexpr Range<uint8_t> midi7Range { 0, 127 }; constexpr Range<uint8_t> midi7Range { 0, 127 };
constexpr Range<float> normalizedRange { 0.0f, 1.0f }; constexpr Range<float> normalizedRange { 0.0f, 1.0f };
constexpr Range<float> symmetricNormalizedRange { -1.0, 1.0 }; constexpr Range<float> symmetricNormalizedRange { -1.0, 1.0 };
constexpr float zeroModifier { 0.0f };
// Wavetable oscillator // Wavetable oscillator
constexpr float oscillatorPhase { 0.0 }; constexpr float oscillatorPhase { 0.0 };

View file

@ -50,10 +50,10 @@ namespace sfz {
* @param value * @param value
* @return float * @return float
*/ */
inline float ccSwitchedValue(const MidiState& state, const absl::optional<CCValuePair<float>>& ccSwitch, float value) noexcept inline float ccSwitchedValue(const MidiState& state, const absl::optional<CCData<float>>& ccSwitch, float value) noexcept
{ {
if (ccSwitch) if (ccSwitch)
return value + ccSwitch->value * state.getCCValue(ccSwitch->cc); return value + ccSwitch->data * state.getCCValue(ccSwitch->cc);
else else
return value; return value;
} }
@ -80,13 +80,13 @@ struct EGDescription {
float vel2sustain { Default::vel2sustain }; float vel2sustain { Default::vel2sustain };
int vel2depth { Default::depth }; int vel2depth { Default::depth };
absl::optional<CCValuePair<float>> ccAttack; absl::optional<CCData<float>> ccAttack;
absl::optional<CCValuePair<float>> ccDecay; absl::optional<CCData<float>> ccDecay;
absl::optional<CCValuePair<float>> ccDelay; absl::optional<CCData<float>> ccDelay;
absl::optional<CCValuePair<float>> ccHold; absl::optional<CCData<float>> ccHold;
absl::optional<CCValuePair<float>> ccRelease; absl::optional<CCData<float>> ccRelease;
absl::optional<CCValuePair<float>> ccStart; absl::optional<CCData<float>> ccStart;
absl::optional<CCValuePair<float>> ccSustain; absl::optional<CCData<float>> ccSustain;
/** /**
* @brief Get the attack with possibly a CC modifier and a velocity modifier * @brief Get the attack with possibly a CC modifier and a velocity modifier

View file

@ -29,17 +29,17 @@ void sfz::EQHolder::setup(const EQDescription& description, unsigned numChannels
// Setup the modulated values // Setup the modulated values
lastFrequency = baseFrequency; lastFrequency = baseFrequency;
for (const auto& mod : description.frequencyCC) for (const auto& mod : description.frequencyCC)
lastFrequency += midiState.getCCValue(mod.cc) * mod.value; lastFrequency += midiState.getCCValue(mod.cc) * mod.data;
lastFrequency = Default::eqFrequencyRange.clamp(lastFrequency); lastFrequency = Default::eqFrequencyRange.clamp(lastFrequency);
lastBandwidth = baseBandwidth; lastBandwidth = baseBandwidth;
for (const auto& mod : description.bandwidthCC) for (const auto& mod : description.bandwidthCC)
lastBandwidth += midiState.getCCValue(mod.cc) * mod.value; lastBandwidth += midiState.getCCValue(mod.cc) * mod.data;
lastBandwidth = Default::eqBandwidthRange.clamp(lastBandwidth); lastBandwidth = Default::eqBandwidthRange.clamp(lastBandwidth);
lastGain = baseGain; lastGain = baseGain;
for (const auto& mod : description.gainCC) for (const auto& mod : description.gainCC)
lastGain += midiState.getCCValue(mod.cc) * mod.value; lastGain += midiState.getCCValue(mod.cc) * mod.data;
lastGain = Default::filterGainRange.clamp(lastGain); lastGain = Default::filterGainRange.clamp(lastGain);
// Initialize the EQ // Initialize the EQ
@ -62,17 +62,17 @@ void sfz::EQHolder::process(const float** inputs, float** outputs, unsigned numF
// For now we take the last value // For now we take the last value
lastFrequency = baseFrequency; lastFrequency = baseFrequency;
for (const auto& mod : description->frequencyCC) for (const auto& mod : description->frequencyCC)
lastFrequency += midiState.getCCValue(mod.cc) * mod.value; lastFrequency += midiState.getCCValue(mod.cc) * mod.data;
lastFrequency = Default::eqFrequencyRange.clamp(lastFrequency); lastFrequency = Default::eqFrequencyRange.clamp(lastFrequency);
lastBandwidth = baseBandwidth; lastBandwidth = baseBandwidth;
for (const auto& mod : description->bandwidthCC) for (const auto& mod : description->bandwidthCC)
lastBandwidth += midiState.getCCValue(mod.cc) * mod.value; lastBandwidth += midiState.getCCValue(mod.cc) * mod.data;
lastBandwidth = Default::eqBandwidthRange.clamp(lastBandwidth); lastBandwidth = Default::eqBandwidthRange.clamp(lastBandwidth);
lastGain = baseGain; lastGain = baseGain;
for (const auto& mod : description->gainCC) for (const auto& mod : description->gainCC)
lastGain += midiState.getCCValue(mod.cc) * mod.value; lastGain += midiState.getCCValue(mod.cc) * mod.data;
lastGain = Default::filterGainRange.clamp(lastGain); lastGain = Default::filterGainRange.clamp(lastGain);
if (lastGain == 0.0f) { if (lastGain == 0.0f) {

View file

@ -41,17 +41,17 @@ void sfz::FilterHolder::setup(const FilterDescription& description, unsigned num
// Setup the modulated values // Setup the modulated values
lastCutoff = baseCutoff; lastCutoff = baseCutoff;
for (const auto& mod : description.cutoffCC) for (const auto& mod : description.cutoffCC)
lastCutoff *= centsFactor(midiState.getCCValue(mod.cc) * mod.value); lastCutoff *= centsFactor(midiState.getCCValue(mod.cc) * mod.data);
lastCutoff = Default::filterCutoffRange.clamp(lastCutoff); lastCutoff = Default::filterCutoffRange.clamp(lastCutoff);
lastResonance = baseResonance; lastResonance = baseResonance;
for (const auto& mod : description.resonanceCC) for (const auto& mod : description.resonanceCC)
lastResonance += midiState.getCCValue(mod.cc) * mod.value; lastResonance += midiState.getCCValue(mod.cc) * mod.data;
lastResonance = Default::filterResonanceRange.clamp(lastResonance); lastResonance = Default::filterResonanceRange.clamp(lastResonance);
lastGain = baseGain; lastGain = baseGain;
for (const auto& mod : description.gainCC) for (const auto& mod : description.gainCC)
lastGain += midiState.getCCValue(mod.cc) * mod.value; lastGain += midiState.getCCValue(mod.cc) * mod.data;
lastGain = Default::filterGainRange.clamp(lastGain); lastGain = Default::filterGainRange.clamp(lastGain);
// Initialize the filter // Initialize the filter
@ -71,17 +71,17 @@ void sfz::FilterHolder::process(const float** inputs, float** outputs, unsigned
// TODO: the template deduction could be automatic here? // TODO: the template deduction could be automatic here?
lastCutoff = baseCutoff; lastCutoff = baseCutoff;
for (const auto& mod : description->cutoffCC) for (const auto& mod : description->cutoffCC)
lastCutoff *= centsFactor(midiState.getCCValue(mod.cc) * mod.value); lastCutoff *= centsFactor(midiState.getCCValue(mod.cc) * mod.data);
lastCutoff = Default::filterCutoffRange.clamp(lastCutoff); lastCutoff = Default::filterCutoffRange.clamp(lastCutoff);
lastResonance = baseResonance; lastResonance = baseResonance;
for (const auto& mod : description->resonanceCC) for (const auto& mod : description->resonanceCC)
lastResonance += midiState.getCCValue(mod.cc) * mod.value; lastResonance += midiState.getCCValue(mod.cc) * mod.data;
lastResonance = Default::filterResonanceRange.clamp(lastResonance); lastResonance = Default::filterResonanceRange.clamp(lastResonance);
lastGain = baseGain; lastGain = baseGain;
for (const auto& mod : description->gainCC) for (const auto& mod : description->gainCC)
lastGain += midiState.getCCValue(mod.cc) * mod.value; lastGain += midiState.getCCValue(mod.cc) * mod.data;
lastGain = Default::filterGainRange.clamp(lastGain); lastGain = Default::filterGainRange.clamp(lastGain);
filter.process(inputs, outputs, lastCutoff, lastResonance, lastGain, numFrames); filter.process(inputs, outputs, lastCutoff, lastResonance, lastGain, numFrames);

View file

@ -185,7 +185,7 @@ inline void setRangeStartFromOpcode(const Opcode& opcode, Range<ValueType>& targ
* @param validRange the range of admitted values used to clamp the opcode * @param validRange the range of admitted values used to clamp the opcode
*/ */
template <class ValueType> template <class ValueType>
inline void setCCPairFromOpcode(const Opcode& opcode, absl::optional<CCValuePair<ValueType>>& target, const Range<ValueType>& validRange) inline void setCCPairFromOpcode(const Opcode& opcode, absl::optional<CCData<ValueType>>& target, const Range<ValueType>& validRange)
{ {
auto value = readOpcode(opcode.value, validRange); auto value = readOpcode(opcode.value, validRange);
if (value && Default::ccNumberRange.containsWithEnd(opcode.parameters.back())) if (value && Default::ccNumberRange.containsWithEnd(opcode.parameters.back()))

View file

@ -303,7 +303,7 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
if (opcode.parameters.back() > config::numCCs) if (opcode.parameters.back() > config::numCCs)
return false; return false;
if (auto value = readOpcode(opcode.value, Default::volumeCCRange)) if (auto value = readOpcode(opcode.value, Default::volumeCCRange))
volumeCC[opcode.parameters.back()] = *value; volumeCC[opcode.parameters.back()].value = *value;
break; break;
case hash("amplitude"): case hash("amplitude"):
if (auto value = readOpcode(opcode.value, Default::amplitudeRange)) if (auto value = readOpcode(opcode.value, Default::amplitudeRange))
@ -314,7 +314,7 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
if (opcode.parameters.back() > config::numCCs) if (opcode.parameters.back() > config::numCCs)
return false; return false;
if (auto value = readOpcode(opcode.value, Default::amplitudeRange)) if (auto value = readOpcode(opcode.value, Default::amplitudeRange))
amplitudeCC[opcode.parameters.back()] = normalizePercents(*value); amplitudeCC[opcode.parameters.back()].value = normalizePercents(*value);
break; break;
case hash("pan"): case hash("pan"):
if (auto value = readOpcode(opcode.value, Default::panRange)) if (auto value = readOpcode(opcode.value, Default::panRange))
@ -325,7 +325,7 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
if (opcode.parameters.back() > config::numCCs) if (opcode.parameters.back() > config::numCCs)
return false; return false;
if (auto value = readOpcode(opcode.value, Default::panCCRange)) if (auto value = readOpcode(opcode.value, Default::panCCRange))
panCC[opcode.parameters.back()] = normalizePercents(*value); panCC[opcode.parameters.back()].value = normalizePercents(*value);
break; break;
case hash("position"): case hash("position"):
if (auto value = readOpcode(opcode.value, Default::positionRange)) if (auto value = readOpcode(opcode.value, Default::positionRange))
@ -335,7 +335,7 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
if (opcode.parameters.back() > config::numCCs) if (opcode.parameters.back() > config::numCCs)
return false; return false;
if (auto value = readOpcode(opcode.value, Default::positionCCRange)) if (auto value = readOpcode(opcode.value, Default::positionCCRange))
positionCC[opcode.parameters.back()] = normalizePercents(*value); positionCC[opcode.parameters.back()].value = normalizePercents(*value);
break; break;
case hash("width"): case hash("width"):
if (auto value = readOpcode(opcode.value, Default::widthRange)) if (auto value = readOpcode(opcode.value, Default::widthRange))
@ -345,7 +345,7 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
if (opcode.parameters.back() > config::numCCs) if (opcode.parameters.back() > config::numCCs)
return false; return false;
if (auto value = readOpcode(opcode.value, Default::widthCCRange)) if (auto value = readOpcode(opcode.value, Default::widthCCRange))
widthCC[opcode.parameters.back()] = normalizePercents(*value); widthCC[opcode.parameters.back()].value = normalizePercents(*value);
break; break;
case hash("amp_keycenter"): case hash("amp_keycenter"):
setValueFromOpcode(opcode, ampKeycenter, Default::keyRange); setValueFromOpcode(opcode, ampKeycenter, Default::keyRange);
@ -733,7 +733,7 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
if (opcode.parameters.back() > config::numCCs) if (opcode.parameters.back() > config::numCCs)
return false; return false;
if (auto value = readOpcode(opcode.value, Default::tuneCCRange)) if (auto value = readOpcode(opcode.value, Default::tuneCCRange))
tuneCC[opcode.parameters.back()] = *value; tuneCC[opcode.parameters.back()].value = *value;
break; break;
case hash("bend_up"): case hash("bend_up"):
setValueFromOpcode(opcode, bendUp, Default::bendBoundRange); setValueFromOpcode(opcode, bendUp, Default::bendBoundRange);
@ -1078,15 +1078,15 @@ float sfz::Region::getCrossfadeGain() const noexcept
float gain { 1.0f }; float gain { 1.0f };
// Crossfades due to CC states // Crossfades due to CC states
for (const auto& valuePair : crossfadeCCInRange) { for (const auto& ccData : crossfadeCCInRange) {
const auto ccValue = midiState.getCCValue(valuePair.cc); const auto ccValue = midiState.getCCValue(ccData.cc);
const auto crossfadeRange = valuePair.value; const auto crossfadeRange = ccData.data;
gain *= crossfadeIn(crossfadeRange, ccValue, crossfadeCCCurve); gain *= crossfadeIn(crossfadeRange, ccValue, crossfadeCCCurve);
} }
for (const auto& valuePair : crossfadeCCOutRange) { for (const auto& ccData : crossfadeCCOutRange) {
const auto ccValue = midiState.getCCValue(valuePair.cc); const auto ccValue = midiState.getCCValue(ccData.cc);
const auto crossfadeRange = valuePair.value; const auto crossfadeRange = ccData.data;
gain *= crossfadeOut(crossfadeRange, ccValue, crossfadeCCCurve); gain *= crossfadeOut(crossfadeRange, ccValue, crossfadeCCCurve);
} }

View file

@ -285,11 +285,11 @@ struct Region {
float pan { normalizePercents(Default::pan) }; // pan float pan { normalizePercents(Default::pan) }; // pan
float width { normalizePercents(Default::width) }; // width float width { normalizePercents(Default::width) }; // width
float position { normalizePercents(Default::position) }; // position float position { normalizePercents(Default::position) }; // position
CCMap<float> volumeCC { Default::zeroModifier }; // volume_oncc CCMap<Modifier> volumeCC { {} }; // volume_oncc
CCMap<float> amplitudeCC { Default::zeroModifier }; // amplitude_oncc CCMap<Modifier> amplitudeCC { {} }; // amplitude_oncc
CCMap<float> panCC { Default::zeroModifier }; // pan_oncc CCMap<Modifier> panCC { {} }; // pan_oncc
CCMap<float> widthCC { Default::zeroModifier }; // width_oncc CCMap<Modifier> widthCC { {} }; // width_oncc
CCMap<float> positionCC { Default::zeroModifier }; // position_oncc CCMap<Modifier> positionCC { {} }; // position_oncc
uint8_t ampKeycenter { Default::ampKeycenter }; // amp_keycenter uint8_t ampKeycenter { Default::ampKeycenter }; // amp_keycenter
float ampKeytrack { Default::ampKeytrack }; // amp_keytrack float ampKeytrack { Default::ampKeytrack }; // amp_keytrack
float ampVeltrack { Default::ampVeltrack }; // amp_keytrack float ampVeltrack { Default::ampVeltrack }; // amp_keytrack
@ -317,7 +317,7 @@ struct Region {
int pitchVeltrack { Default::pitchVeltrack }; // pitch_veltrack int pitchVeltrack { Default::pitchVeltrack }; // pitch_veltrack
int transpose { Default::transpose }; // transpose int transpose { Default::transpose }; // transpose
int tune { Default::tune }; // tune int tune { Default::tune }; // tune
CCMap<int> tuneCC { Default::tune }; CCMap<Modifier> tuneCC { {} };
int bendUp { Default::bendUp }; int bendUp { Default::bendUp };
int bendDown { Default::bendDown }; int bendDown { Default::bendDown };
int bendStep { Default::bendStep }; int bendStep { Default::bendStep };

View file

@ -24,44 +24,35 @@ using CCNamePair = std::pair<uint16_t, std::string>;
template <class T> template <class T>
using MidiNoteArray = std::array<T, 128>; using MidiNoteArray = std::array<T, 128>;
template<class ValueType> template<class ValueType>
struct CCValuePair { struct CCData {
int cc; int cc;
ValueType value; ValueType data;
static_assert(config::numCCs - 1 < std::numeric_limits<decltype(cc)>::max());
}; };
template<class ValueType, bool CompareValue = false> struct Modifier {
struct CCValuePairComparator { float value { 0.0f };
bool operator()(const CCValuePair<ValueType>& valuePair, const int& cc) uint8_t curve { 0 };
{ uint8_t steps { 0 };
return (valuePair.cc < cc); uint8_t smooth { 0 };
} static_assert(config::maxCurves - 1 <= std::numeric_limits<decltype(curve)>::max());
bool operator()(const int& cc, const CCValuePair<ValueType>& valuePair)
{
return (cc < valuePair.cc);
}
bool operator()(const CCValuePair<ValueType>& lhs, const CCValuePair<ValueType>& rhs)
{
return (lhs.cc < rhs.cc);
}
}; };
template<class ValueType> template<class ValueType>
struct CCValuePairComparator<ValueType, true> { struct CCDataComparator {
bool operator()(const CCValuePair<ValueType>& valuePair, const ValueType& value) bool operator()(const CCData<ValueType>& ccData, const int& cc)
{ {
return (valuePair.value < value); return (ccData.cc < cc);
} }
bool operator()(const ValueType& value, const CCValuePair<ValueType>& valuePair) bool operator()(const int& cc, const CCData<ValueType>& ccData)
{ {
return (value < valuePair.value); return (cc < ccData.cc);
} }
bool operator()(const CCValuePair<ValueType>& lhs, const CCValuePair<ValueType>& rhs) bool operator()(const CCData<ValueType>& lhs, const CCData<ValueType>& rhs)
{ {
return (lhs.value < rhs.value); return (lhs.cc < rhs.cc);
} }
}; };

View file

@ -265,19 +265,19 @@ void sfz::Voice::amplitudeEnvelope(absl::Span<float> modulationSpan) noexcept
applyGain<float>(baseGain, modulationSpan); applyGain<float>(baseGain, modulationSpan);
for (const auto& mod : region->amplitudeCC) { for (const auto& mod : region->amplitudeCC) {
const auto events = resources.midiState.getCCEvents(mod.cc); const auto events = resources.midiState.getCCEvents(mod.cc);
linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.value; }); linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.data.value; });
applyGain<float>(*tempSpan, modulationSpan); applyGain<float>(*tempSpan, modulationSpan);
} }
// Crossfade envelopes // Crossfade envelopes
for (const auto& mod : region->crossfadeCCInRange) { for (const auto& mod : region->crossfadeCCInRange) {
const auto events = resources.midiState.getCCEvents(mod.cc); const auto events = resources.midiState.getCCEvents(mod.cc);
linearEnvelope(events, *tempSpan, [&](float x) { return crossfadeIn(mod.value, x, xfCurve); }); linearEnvelope(events, *tempSpan, [&](float x) { return crossfadeIn(mod.data, x, xfCurve); });
applyGain<float>(*tempSpan, modulationSpan); applyGain<float>(*tempSpan, modulationSpan);
} }
for (const auto& mod : region->crossfadeCCOutRange) { for (const auto& mod : region->crossfadeCCOutRange) {
const auto events = resources.midiState.getCCEvents(mod.cc); const auto events = resources.midiState.getCCEvents(mod.cc);
linearEnvelope(events, *tempSpan, [&](float x) { return crossfadeOut(mod.value, x, xfCurve); }); linearEnvelope(events, *tempSpan, [&](float x) { return crossfadeOut(mod.data, x, xfCurve); });
applyGain<float>(*tempSpan, modulationSpan); applyGain<float>(*tempSpan, modulationSpan);
} }
@ -285,7 +285,7 @@ void sfz::Voice::amplitudeEnvelope(absl::Span<float> modulationSpan) noexcept
applyGain<float>(db2mag(baseVolumedB), modulationSpan); applyGain<float>(db2mag(baseVolumedB), modulationSpan);
for (const auto& mod : region->volumeCC) { for (const auto& mod : region->volumeCC) {
const auto events = resources.midiState.getCCEvents(mod.cc); const auto events = resources.midiState.getCCEvents(mod.cc);
multiplicativeEnvelope(events, *tempSpan, [&](float x) { return db2mag(x * mod.value); }); multiplicativeEnvelope(events, *tempSpan, [&](float x) { return db2mag(x * mod.data.value); });
applyGain<float>(*tempSpan, modulationSpan); applyGain<float>(*tempSpan, modulationSpan);
} }
} }
@ -338,7 +338,7 @@ void sfz::Voice::panStageMono(AudioSpan<float> buffer) noexcept
fill<float>(*modulationSpan, region->pan); fill<float>(*modulationSpan, region->pan);
for (const auto& mod : region->panCC) { for (const auto& mod : region->panCC) {
const auto events = resources.midiState.getCCEvents(mod.cc); const auto events = resources.midiState.getCCEvents(mod.cc);
linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.value; }); linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.data.value; });
add<float>(*tempSpan, *modulationSpan); add<float>(*tempSpan, *modulationSpan);
} }
pan<float>(*modulationSpan, leftBuffer, rightBuffer); pan<float>(*modulationSpan, leftBuffer, rightBuffer);
@ -361,7 +361,7 @@ void sfz::Voice::panStageStereo(AudioSpan<float> buffer) noexcept
fill<float>(*modulationSpan, region->pan); fill<float>(*modulationSpan, region->pan);
for (const auto& mod : region->panCC) { for (const auto& mod : region->panCC) {
const auto events = resources.midiState.getCCEvents(mod.cc); const auto events = resources.midiState.getCCEvents(mod.cc);
linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.value; }); linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.data.value; });
add<float>(*tempSpan, *modulationSpan); add<float>(*tempSpan, *modulationSpan);
} }
pan<float>(*modulationSpan, leftBuffer, rightBuffer); pan<float>(*modulationSpan, leftBuffer, rightBuffer);
@ -371,7 +371,7 @@ void sfz::Voice::panStageStereo(AudioSpan<float> buffer) noexcept
fill<float>(*modulationSpan, region->width); fill<float>(*modulationSpan, region->width);
for (const auto& mod : region->widthCC) { for (const auto& mod : region->widthCC) {
const auto events = resources.midiState.getCCEvents(mod.cc); const auto events = resources.midiState.getCCEvents(mod.cc);
linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.value; }); linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.data.value; });
add<float>(*tempSpan, *modulationSpan); add<float>(*tempSpan, *modulationSpan);
} }
width<float>(*modulationSpan, leftBuffer, rightBuffer); width<float>(*modulationSpan, leftBuffer, rightBuffer);
@ -380,7 +380,7 @@ void sfz::Voice::panStageStereo(AudioSpan<float> buffer) noexcept
fill<float>(*modulationSpan, region->position); fill<float>(*modulationSpan, region->position);
for (const auto& mod : region->positionCC) { for (const auto& mod : region->positionCC) {
const auto events = resources.midiState.getCCEvents(mod.cc); const auto events = resources.midiState.getCCEvents(mod.cc);
linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.value; }); linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.data.value; });
add<float>(*tempSpan, *modulationSpan); add<float>(*tempSpan, *modulationSpan);
} }
pan<float>(*modulationSpan, leftBuffer, rightBuffer); pan<float>(*modulationSpan, leftBuffer, rightBuffer);
@ -458,7 +458,7 @@ void sfz::Voice::fillWithData(AudioSpan<float> buffer) noexcept
for (const auto& mod : region->tuneCC) { for (const auto& mod : region->tuneCC) {
const auto events = resources.midiState.getCCEvents(mod.cc); const auto events = resources.midiState.getCCEvents(mod.cc);
multiplicativeEnvelope(events, *bends, [&](float x) { return centsFactor(x * mod.value); }); multiplicativeEnvelope(events, *bends, [&](float x) { return centsFactor(x * mod.data.value); });
applyGain<float>(*bends, *jumps); applyGain<float>(*bends, *jumps);
} }
@ -562,7 +562,7 @@ void sfz::Voice::fillWithGenerator(AudioSpan<float> buffer) noexcept
for (const auto& mod : region->tuneCC) { for (const auto& mod : region->tuneCC) {
const auto events = resources.midiState.getCCEvents(mod.cc); const auto events = resources.midiState.getCCEvents(mod.cc);
multiplicativeEnvelope(events, *bends, [&](float x) { return centsFactor(x * mod.value); }); multiplicativeEnvelope(events, *bends, [&](float x) { return centsFactor(x * mod.data.value); });
applyGain<float>(*bends, *frequencies); applyGain<float>(*bends, *frequencies);
} }

View file

@ -351,7 +351,7 @@ TEST_CASE("[Files] wrong (overlapping) replacement for defines")
REQUIRE( synth.getRegionView(1)->keyRange.getEnd() == 57 ); REQUIRE( synth.getRegionView(1)->keyRange.getEnd() == 57 );
REQUIRE(!synth.getRegionView(2)->amplitudeCC.empty()); REQUIRE(!synth.getRegionView(2)->amplitudeCC.empty());
REQUIRE(synth.getRegionView(2)->amplitudeCC.contains(10)); REQUIRE(synth.getRegionView(2)->amplitudeCC.contains(10));
REQUIRE(synth.getRegionView(2)->amplitudeCC.getWithDefault(10) == 0.34f); REQUIRE(synth.getRegionView(2)->amplitudeCC.getWithDefault(10).value == 0.34f);
} }
TEST_CASE("[Files] Specific bug: relative path with backslashes") TEST_CASE("[Files] Specific bug: relative path with backslashes")

View file

@ -470,7 +470,7 @@ TEST_CASE("[Region] Parsing opcodes")
REQUIRE(region.panCC.empty()); REQUIRE(region.panCC.empty());
region.parseOpcode({ "pan_oncc45", "4.2" }); region.parseOpcode({ "pan_oncc45", "4.2" });
REQUIRE(region.panCC.contains(45)); REQUIRE(region.panCC.contains(45));
REQUIRE(region.panCC[45] == 0.042_a); REQUIRE(region.panCC[45].value == 0.042_a);
} }
SECTION("width") SECTION("width")
@ -491,7 +491,7 @@ TEST_CASE("[Region] Parsing opcodes")
REQUIRE(region.widthCC.empty()); REQUIRE(region.widthCC.empty());
region.parseOpcode({ "width_oncc45", "4.2" }); region.parseOpcode({ "width_oncc45", "4.2" });
REQUIRE(region.widthCC.contains(45)); REQUIRE(region.widthCC.contains(45));
REQUIRE(region.widthCC[45] == 0.042_a); REQUIRE(region.widthCC[45].value == 0.042_a);
} }
SECTION("position") SECTION("position")
@ -512,7 +512,7 @@ TEST_CASE("[Region] Parsing opcodes")
REQUIRE(region.positionCC.empty()); REQUIRE(region.positionCC.empty());
region.parseOpcode({ "position_oncc45", "4.2" }); region.parseOpcode({ "position_oncc45", "4.2" });
REQUIRE(region.positionCC.contains(45)); REQUIRE(region.positionCC.contains(45));
REQUIRE(region.positionCC[45] == 0.042_a); REQUIRE(region.positionCC[45].value == 0.042_a);
} }
SECTION("amp_keycenter") SECTION("amp_keycenter")
@ -974,13 +974,13 @@ TEST_CASE("[Region] Parsing opcodes")
REQUIRE(region.amplitudeEG.ccRelease->cc == 5); REQUIRE(region.amplitudeEG.ccRelease->cc == 5);
REQUIRE(region.amplitudeEG.ccStart->cc == 6); REQUIRE(region.amplitudeEG.ccStart->cc == 6);
REQUIRE(region.amplitudeEG.ccSustain->cc == 7); REQUIRE(region.amplitudeEG.ccSustain->cc == 7);
REQUIRE(region.amplitudeEG.ccAttack->value == 1.0f); REQUIRE(region.amplitudeEG.ccAttack->data == 1.0f);
REQUIRE(region.amplitudeEG.ccDecay->value == 2.0f); REQUIRE(region.amplitudeEG.ccDecay->data == 2.0f);
REQUIRE(region.amplitudeEG.ccDelay->value == 3.0f); REQUIRE(region.amplitudeEG.ccDelay->data == 3.0f);
REQUIRE(region.amplitudeEG.ccHold->value == 4.0f); REQUIRE(region.amplitudeEG.ccHold->data == 4.0f);
REQUIRE(region.amplitudeEG.ccRelease->value == 5.0f); REQUIRE(region.amplitudeEG.ccRelease->data == 5.0f);
REQUIRE(region.amplitudeEG.ccStart->value == 6.0f); REQUIRE(region.amplitudeEG.ccStart->data == 6.0f);
REQUIRE(region.amplitudeEG.ccSustain->value == 7.0f); REQUIRE(region.amplitudeEG.ccSustain->data == 7.0f);
// //
region.parseOpcode({ "ampeg_attack_oncc1", "101" }); region.parseOpcode({ "ampeg_attack_oncc1", "101" });
region.parseOpcode({ "ampeg_decay_oncc2", "101" }); region.parseOpcode({ "ampeg_decay_oncc2", "101" });
@ -989,13 +989,13 @@ TEST_CASE("[Region] Parsing opcodes")
region.parseOpcode({ "ampeg_release_oncc5", "101" }); region.parseOpcode({ "ampeg_release_oncc5", "101" });
region.parseOpcode({ "ampeg_start_oncc6", "101" }); region.parseOpcode({ "ampeg_start_oncc6", "101" });
region.parseOpcode({ "ampeg_sustain_oncc7", "101" }); region.parseOpcode({ "ampeg_sustain_oncc7", "101" });
REQUIRE(region.amplitudeEG.ccAttack->value == 100.0f); REQUIRE(region.amplitudeEG.ccAttack->data == 100.0f);
REQUIRE(region.amplitudeEG.ccDecay->value == 100.0f); REQUIRE(region.amplitudeEG.ccDecay->data == 100.0f);
REQUIRE(region.amplitudeEG.ccDelay->value == 100.0f); REQUIRE(region.amplitudeEG.ccDelay->data == 100.0f);
REQUIRE(region.amplitudeEG.ccHold->value == 100.0f); REQUIRE(region.amplitudeEG.ccHold->data == 100.0f);
REQUIRE(region.amplitudeEG.ccRelease->value == 100.0f); REQUIRE(region.amplitudeEG.ccRelease->data == 100.0f);
REQUIRE(region.amplitudeEG.ccStart->value == 100.0f); REQUIRE(region.amplitudeEG.ccStart->data == 100.0f);
REQUIRE(region.amplitudeEG.ccSustain->value == 100.0f); REQUIRE(region.amplitudeEG.ccSustain->data == 100.0f);
// //
region.parseOpcode({ "ampeg_attack_oncc1", "-101" }); region.parseOpcode({ "ampeg_attack_oncc1", "-101" });
region.parseOpcode({ "ampeg_decay_oncc2", "-101" }); region.parseOpcode({ "ampeg_decay_oncc2", "-101" });
@ -1004,13 +1004,13 @@ TEST_CASE("[Region] Parsing opcodes")
region.parseOpcode({ "ampeg_release_oncc5", "-101" }); region.parseOpcode({ "ampeg_release_oncc5", "-101" });
region.parseOpcode({ "ampeg_start_oncc6", "-101" }); region.parseOpcode({ "ampeg_start_oncc6", "-101" });
region.parseOpcode({ "ampeg_sustain_oncc7", "-101" }); region.parseOpcode({ "ampeg_sustain_oncc7", "-101" });
REQUIRE(region.amplitudeEG.ccAttack->value == -100.0f); REQUIRE(region.amplitudeEG.ccAttack->data == -100.0f);
REQUIRE(region.amplitudeEG.ccDecay->value == -100.0f); REQUIRE(region.amplitudeEG.ccDecay->data == -100.0f);
REQUIRE(region.amplitudeEG.ccDelay->value == -100.0f); REQUIRE(region.amplitudeEG.ccDelay->data == -100.0f);
REQUIRE(region.amplitudeEG.ccHold->value == -100.0f); REQUIRE(region.amplitudeEG.ccHold->data == -100.0f);
REQUIRE(region.amplitudeEG.ccRelease->value == -100.0f); REQUIRE(region.amplitudeEG.ccRelease->data == -100.0f);
REQUIRE(region.amplitudeEG.ccStart->value == -100.0f); REQUIRE(region.amplitudeEG.ccStart->data == -100.0f);
REQUIRE(region.amplitudeEG.ccSustain->value == -100.0f); REQUIRE(region.amplitudeEG.ccSustain->data == -100.0f);
} }
SECTION("sustain_sw and sostenuto_sw") SECTION("sustain_sw and sostenuto_sw")
@ -1448,10 +1448,10 @@ TEST_CASE("[Region] Parsing opcodes")
REQUIRE(region.amplitudeCC.empty()); REQUIRE(region.amplitudeCC.empty());
region.parseOpcode({ "amplitude_cc1", "40" }); region.parseOpcode({ "amplitude_cc1", "40" });
REQUIRE(region.amplitudeCC.contains(1)); REQUIRE(region.amplitudeCC.contains(1));
REQUIRE(region.amplitudeCC[1] == 0.40_a); REQUIRE(region.amplitudeCC[1].value == 0.40_a);
region.parseOpcode({ "amplitude_oncc2", "30" }); region.parseOpcode({ "amplitude_oncc2", "30" });
REQUIRE(region.amplitudeCC.contains(2)); REQUIRE(region.amplitudeCC.contains(2));
REQUIRE(region.amplitudeCC[2] == 0.30_a); REQUIRE(region.amplitudeCC[2].value == 0.30_a);
} }
SECTION("volume_oncc/gain_cc") SECTION("volume_oncc/gain_cc")
@ -1459,13 +1459,13 @@ TEST_CASE("[Region] Parsing opcodes")
REQUIRE(region.volumeCC.empty()); REQUIRE(region.volumeCC.empty());
region.parseOpcode({ "gain_cc1", "40" }); region.parseOpcode({ "gain_cc1", "40" });
REQUIRE(region.volumeCC.contains(1)); REQUIRE(region.volumeCC.contains(1));
REQUIRE(region.volumeCC[1] == 40_a); REQUIRE(region.volumeCC[1].value == 40_a);
region.parseOpcode({ "volume_oncc2", "-76" }); region.parseOpcode({ "volume_oncc2", "-76" });
REQUIRE(region.volumeCC.contains(2)); REQUIRE(region.volumeCC.contains(2));
REQUIRE(region.volumeCC[2] == -76.0_a); REQUIRE(region.volumeCC[2].value == -76.0_a);
region.parseOpcode({ "gain_oncc4", "-1" }); region.parseOpcode({ "gain_oncc4", "-1" });
REQUIRE(region.volumeCC.contains(4)); REQUIRE(region.volumeCC.contains(4));
REQUIRE(region.volumeCC[4] == -1.0_a); REQUIRE(region.volumeCC[4].value == -1.0_a);
} }
SECTION("tune_cc/pitch_cc") SECTION("tune_cc/pitch_cc")
@ -1473,13 +1473,13 @@ TEST_CASE("[Region] Parsing opcodes")
REQUIRE(region.tuneCC.empty()); REQUIRE(region.tuneCC.empty());
region.parseOpcode({ "pitch_cc1", "40" }); region.parseOpcode({ "pitch_cc1", "40" });
REQUIRE(region.tuneCC.contains(1)); REQUIRE(region.tuneCC.contains(1));
REQUIRE(region.tuneCC[1] == 40); REQUIRE(region.tuneCC[1].value == 40.0);
region.parseOpcode({ "tune_oncc2", "-76" }); region.parseOpcode({ "tune_oncc2", "-76" });
REQUIRE(region.tuneCC.contains(2)); REQUIRE(region.tuneCC.contains(2));
REQUIRE(region.tuneCC[2] == -76.0); REQUIRE(region.tuneCC[2].value == -76.0);
region.parseOpcode({ "pitch_oncc4", "-1" }); region.parseOpcode({ "pitch_oncc4", "-1" });
REQUIRE(region.tuneCC.contains(4)); REQUIRE(region.tuneCC.contains(4));
REQUIRE(region.tuneCC[4] == -1.0); REQUIRE(region.tuneCC[4].value == -1.0);
} }
} }