Change CCValuePair type alias and use it in CCMap

Also use lower bound and binary search in the
CCMap vector
This commit is contained in:
Paul Fd 2020-03-07 12:35:48 +01:00
parent d10cd27ceb
commit f70b042da6
8 changed files with 74 additions and 50 deletions

View file

@ -6,6 +6,7 @@
#pragma once
#include "LeakDetector.h"
#include "SfzHelpers.h"
#include <vector>
#include <absl/algorithm/container.h>
@ -43,11 +44,11 @@ public:
*/
const ValueType& getWithDefault(int index) const noexcept
{
auto it = absl::c_find_if(container, [&](auto&& pair){ return pair.first == index; });
if (it == container.end()) {
auto it = absl::c_lower_bound(container, index, CompareCC<ValueType>{});
if (it == container.end() || it->cc != index) {
return defaultValue;
} else {
return it->second;
return it->value;
}
}
@ -59,13 +60,12 @@ public:
*/
ValueType& operator[](const int& index) noexcept
{
auto it = absl::c_find_if(container, [&](auto&& pair){ return pair.first == index; });
if (it == container.end()) {
auto newElement = std::make_pair(index, defaultValue);
auto inserted = container.insert(absl::c_upper_bound(container, newElement, [](auto& lhs, auto& rhs) { return lhs.first < rhs.first; }), newElement);
return inserted->second;
auto it = absl::c_lower_bound(container, index, CompareCC<ValueType>{});
if (it == container.end() || it->cc != index) {
auto inserted = container.insert(it, { index, defaultValue });
return inserted->value;
} else {
return it->second;
return it->value;
}
}
@ -85,15 +85,16 @@ public:
*/
bool contains(int index) const noexcept
{
return absl::c_find_if(container, [&](auto&& pair){ return pair.first == index; }) != container.end();
return absl::c_binary_search(container, index, CompareCC<ValueType>{});
}
typename std::vector<std::pair<int, ValueType>>::const_iterator begin() const { return container.cbegin(); }
typename std::vector<std::pair<int, ValueType>>::const_iterator end() const { return container.cend(); }
typename std::vector<CCValuePair<ValueType>>::const_iterator begin() const { return container.cbegin(); }
typename std::vector<CCValuePair<ValueType>>::const_iterator end() const { return container.cend(); }
private:
// typename std::vector<std::pair<int, ValueType>>::iterator begin() { return container.begin(); }
// typename std::vector<std::pair<int, ValueType>>::iterator end() { return container.end(); }
const ValueType defaultValue;
std::vector<std::pair<int, ValueType>> container;
std::vector<CCValuePair<ValueType>> container;
LEAK_DETECTOR(CCMap);
};
}

View file

@ -64,13 +64,13 @@ struct EGDescription
float vel2sustain { Default::vel2sustain };
int vel2depth { Default::depth };
absl::optional<CCValuePair> ccAttack;
absl::optional<CCValuePair> ccDecay;
absl::optional<CCValuePair> ccDelay;
absl::optional<CCValuePair> ccHold;
absl::optional<CCValuePair> ccRelease;
absl::optional<CCValuePair> ccStart;
absl::optional<CCValuePair> ccSustain;
absl::optional<CCValuePair<float>> ccAttack;
absl::optional<CCValuePair<float>> ccDecay;
absl::optional<CCValuePair<float>> ccDelay;
absl::optional<CCValuePair<float>> ccHold;
absl::optional<CCValuePair<float>> ccRelease;
absl::optional<CCValuePair<float>> ccStart;
absl::optional<CCValuePair<float>> ccSustain;
/**
* @brief Get the attack with possibly a CC modifier and a velocity modifier

View file

@ -120,7 +120,7 @@ public:
T modulate(T value, const CCMap<U>& modifiers, const Range<T>& validRange, const modFunction<T, U>& lambda = addToBase<T>) const noexcept
{
for (auto& mod: modifiers) {
lambda(value, normalizeCC(getCCValue(mod.first)) * mod.second);
lambda(value, normalizeCC(getCCValue(mod.cc)) * mod.value);
}
return validRange.clamp(value);
}

View file

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

View file

@ -992,14 +992,14 @@ float sfz::Region::getCrossfadeGain(const sfz::SfzCCArray& ccState) noexcept
// Crossfades due to CC states
for (const auto& valuePair : crossfadeCCInRange) {
const auto ccValue = ccState[valuePair.first];
const auto crossfadeRange = valuePair.second;
const auto ccValue = ccState[valuePair.cc];
const auto crossfadeRange = valuePair.value;
gain *= crossfadeIn(crossfadeRange, ccValue, crossfadeCCCurve);
}
for (const auto& valuePair : crossfadeCCOutRange) {
const auto ccValue = ccState[valuePair.first];
const auto crossfadeRange = valuePair.second;
const auto ccValue = ccState[valuePair.cc];
const auto crossfadeRange = valuePair.value;
gain *= crossfadeOut(crossfadeRange, ccValue, crossfadeCCCurve);
}

View file

@ -264,11 +264,11 @@ struct Region {
float pan { Default::pan }; // pan
float width { Default::width }; // width
float position { Default::position }; // position
absl::optional<CCValuePair> volumeCC; // volume_oncc
absl::optional<CCValuePair> amplitudeCC; // amplitude_oncc
absl::optional<CCValuePair> panCC; // pan_oncc
absl::optional<CCValuePair> widthCC; // width_oncc
absl::optional<CCValuePair> positionCC; // position_oncc
absl::optional<CCValuePair<float>> volumeCC; // volume_oncc
absl::optional<CCValuePair<float>> amplitudeCC; // amplitude_oncc
absl::optional<CCValuePair<float>> panCC; // pan_oncc
absl::optional<CCValuePair<float>> widthCC; // width_oncc
absl::optional<CCValuePair<float>> positionCC; // position_oncc
uint8_t ampKeycenter { Default::ampKeycenter }; // amp_keycenter
float ampKeytrack { Default::ampKeytrack }; // amp_keytrack
float ampVeltrack { Default::ampVeltrack }; // amp_keytrack

View file

@ -16,9 +16,32 @@ namespace sfz
{
using SfzCCArray = std::array<uint8_t, config::numCCs>;
using CCValuePair = std::pair<uint8_t, float> ;
using CCNamePair = std::pair<uint8_t, std::string>;
template<class ValueType>
struct CCValuePair {
int cc;
ValueType value;
};
template<class ValueType>
struct CompareCC {
bool operator()(const CCValuePair<ValueType>& valuePair, const int& cc)
{
return (valuePair.cc < cc);
}
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);
}
};
/**
* @brief Converts cents to a pitch ratio
*
@ -94,10 +117,10 @@ constexpr float normalizeBend(float bendValue)
* @param value
* @return float
*/
inline float ccSwitchedValue(const SfzCCArray& ccValues, const absl::optional<CCValuePair>& ccSwitch, float value) noexcept
inline float ccSwitchedValue(const SfzCCArray& ccValues, const absl::optional<CCValuePair<float>>& ccSwitch, float value) noexcept
{
if (ccSwitch)
return value + ccSwitch->second * normalizeCC(ccValues[ccSwitch->first]);
return value + ccSwitch->value * normalizeCC(ccValues[ccSwitch->cc]);
else
return value;
}

View file

@ -47,7 +47,7 @@ void sfz::Voice::startVoice(Region* region, int delay, int number, uint8_t value
baseVolumedB = region->getBaseVolumedB(number);
auto volumedB { baseVolumedB };
if (region->volumeCC)
volumedB += normalizeCC(resources.midiState.getCCValue(region->volumeCC->first)) * region->volumeCC->second;
volumedB += normalizeCC(resources.midiState.getCCValue(region->volumeCC->cc)) * region->volumeCC->value;
volumeEnvelope.reset(db2mag(Default::volumeRange.clamp(volumedB)));
baseGain = region->getBaseGain();
@ -56,7 +56,7 @@ void sfz::Voice::startVoice(Region* region, int delay, int number, uint8_t value
float gain { baseGain };
if (region->amplitudeCC)
gain += normalizeCC(resources.midiState.getCCValue(region->amplitudeCC->first)) * normalizePercents(region->amplitudeCC->second);
gain += normalizeCC(resources.midiState.getCCValue(region->amplitudeCC->cc)) * normalizePercents(region->amplitudeCC->value);
amplitudeEnvelope.reset(Default::normalizedRange.clamp(gain));
float crossfadeGain { region->getCrossfadeGain(resources.midiState.getCCArray()) };
@ -65,19 +65,19 @@ void sfz::Voice::startVoice(Region* region, int delay, int number, uint8_t value
basePan = normalizePercents(region->pan);
auto pan { basePan };
if (region->panCC)
pan += normalizeCC(resources.midiState.getCCValue(region->panCC->first)) * normalizePercents(region->panCC->second);
pan += normalizeCC(resources.midiState.getCCValue(region->panCC->cc)) * normalizePercents(region->panCC->value);
panEnvelope.reset(Default::symmetricNormalizedRange.clamp(pan));
basePosition = normalizePercents(region->position);
auto position { basePosition };
if (region->positionCC)
position += normalizeCC(resources.midiState.getCCValue(region->positionCC->first)) * normalizePercents(region->positionCC->second);
position += normalizeCC(resources.midiState.getCCValue(region->positionCC->cc)) * normalizePercents(region->positionCC->value);
positionEnvelope.reset(Default::symmetricNormalizedRange.clamp(position));
baseWidth = normalizePercents(region->width);
auto width { baseWidth };
if (region->widthCC)
width += normalizeCC(resources.midiState.getCCValue(region->widthCC->first)) * normalizePercents(region->widthCC->second);
width += normalizeCC(resources.midiState.getCCValue(region->widthCC->cc)) * normalizePercents(region->widthCC->value);
widthEnvelope.reset(Default::symmetricNormalizedRange.clamp(width));
pitchBendEnvelope.setFunction([region](float pitchValue){
@ -168,28 +168,28 @@ void sfz::Voice::registerCC(int delay, int ccNumber, uint8_t ccValue) noexcept
// TODO: this feels like a hack, revisit this along with the smoothed envelopes...
delay = max(delay, minEnvelopeDelay);
if (region->amplitudeCC && ccNumber == region->amplitudeCC->first) {
const float newGain { baseGain + normalizeCC(ccValue) * normalizePercents(region->amplitudeCC->second) };
if (region->amplitudeCC && ccNumber == region->amplitudeCC->cc) {
const float newGain { baseGain + normalizeCC(ccValue) * normalizePercents(region->amplitudeCC->value) };
amplitudeEnvelope.registerEvent(delay, Default::normalizedRange.clamp(newGain));
}
if (region->volumeCC && ccNumber == region->volumeCC->first) {
const float newVolumedB { baseVolumedB + normalizeCC(ccValue) * region->volumeCC->second };
if (region->volumeCC && ccNumber == region->volumeCC->cc) {
const float newVolumedB { baseVolumedB + normalizeCC(ccValue) * region->volumeCC->value };
volumeEnvelope.registerEvent(delay, db2mag(Default::volumeRange.clamp(newVolumedB)));
}
if (region->panCC && ccNumber == region->panCC->first) {
const float newPan { basePan + normalizeCC(ccValue) * normalizePercents(region->panCC->second) };
if (region->panCC && ccNumber == region->panCC->cc) {
const float newPan { basePan + normalizeCC(ccValue) * normalizePercents(region->panCC->value) };
panEnvelope.registerEvent(delay, Default::symmetricNormalizedRange.clamp(newPan));
}
if (region->positionCC && ccNumber == region->positionCC->first) {
const float newPosition { basePosition + normalizeCC(ccValue) * normalizePercents(region->positionCC->second) };
if (region->positionCC && ccNumber == region->positionCC->cc) {
const float newPosition { basePosition + normalizeCC(ccValue) * normalizePercents(region->positionCC->value) };
positionEnvelope.registerEvent(delay, Default::symmetricNormalizedRange.clamp(newPosition));
}
if (region->widthCC && ccNumber == region->widthCC->first) {
const float newWidth { baseWidth + normalizeCC(ccValue) * normalizePercents(region->widthCC->second) };
if (region->widthCC && ccNumber == region->widthCC->cc) {
const float newWidth { baseWidth + normalizeCC(ccValue) * normalizePercents(region->widthCC->value) };
widthEnvelope.registerEvent(delay, Default::symmetricNormalizedRange.clamp(newWidth));
}