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:
parent
d10cd27ceb
commit
f70b042da6
8 changed files with 74 additions and 50 deletions
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "LeakDetector.h"
|
#include "LeakDetector.h"
|
||||||
|
#include "SfzHelpers.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <absl/algorithm/container.h>
|
#include <absl/algorithm/container.h>
|
||||||
|
|
||||||
|
|
@ -43,11 +44,11 @@ public:
|
||||||
*/
|
*/
|
||||||
const ValueType& getWithDefault(int index) const noexcept
|
const ValueType& getWithDefault(int index) const noexcept
|
||||||
{
|
{
|
||||||
auto it = absl::c_find_if(container, [&](auto&& pair){ return pair.first == index; });
|
auto it = absl::c_lower_bound(container, index, CompareCC<ValueType>{});
|
||||||
if (it == container.end()) {
|
if (it == container.end() || it->cc != index) {
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
} else {
|
} else {
|
||||||
return it->second;
|
return it->value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -59,13 +60,12 @@ public:
|
||||||
*/
|
*/
|
||||||
ValueType& operator[](const int& index) noexcept
|
ValueType& operator[](const int& index) noexcept
|
||||||
{
|
{
|
||||||
auto it = absl::c_find_if(container, [&](auto&& pair){ return pair.first == index; });
|
auto it = absl::c_lower_bound(container, index, CompareCC<ValueType>{});
|
||||||
if (it == container.end()) {
|
if (it == container.end() || it->cc != index) {
|
||||||
auto newElement = std::make_pair(index, defaultValue);
|
auto inserted = container.insert(it, { index, defaultValue });
|
||||||
auto inserted = container.insert(absl::c_upper_bound(container, newElement, [](auto& lhs, auto& rhs) { return lhs.first < rhs.first; }), newElement);
|
return inserted->value;
|
||||||
return inserted->second;
|
|
||||||
} else {
|
} else {
|
||||||
return it->second;
|
return it->value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -85,15 +85,16 @@ public:
|
||||||
*/
|
*/
|
||||||
bool contains(int index) const noexcept
|
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<CCValuePair<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 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<std::pair<int, ValueType>> container;
|
std::vector<CCValuePair<ValueType>> container;
|
||||||
LEAK_DETECTOR(CCMap);
|
LEAK_DETECTOR(CCMap);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,13 +64,13 @@ struct EGDescription
|
||||||
float vel2sustain { Default::vel2sustain };
|
float vel2sustain { Default::vel2sustain };
|
||||||
int vel2depth { Default::depth };
|
int vel2depth { Default::depth };
|
||||||
|
|
||||||
absl::optional<CCValuePair> ccAttack;
|
absl::optional<CCValuePair<float>> ccAttack;
|
||||||
absl::optional<CCValuePair> ccDecay;
|
absl::optional<CCValuePair<float>> ccDecay;
|
||||||
absl::optional<CCValuePair> ccDelay;
|
absl::optional<CCValuePair<float>> ccDelay;
|
||||||
absl::optional<CCValuePair> ccHold;
|
absl::optional<CCValuePair<float>> ccHold;
|
||||||
absl::optional<CCValuePair> ccRelease;
|
absl::optional<CCValuePair<float>> ccRelease;
|
||||||
absl::optional<CCValuePair> ccStart;
|
absl::optional<CCValuePair<float>> ccStart;
|
||||||
absl::optional<CCValuePair> ccSustain;
|
absl::optional<CCValuePair<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
|
||||||
|
|
|
||||||
|
|
@ -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
|
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) {
|
for (auto& mod: modifiers) {
|
||||||
lambda(value, normalizeCC(getCCValue(mod.first)) * mod.second);
|
lambda(value, normalizeCC(getCCValue(mod.cc)) * mod.value);
|
||||||
}
|
}
|
||||||
return validRange.clamp(value);
|
return validRange.clamp(value);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
* @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>& 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);
|
auto value = readOpcode(opcode.value, validRange);
|
||||||
if (value && Default::ccNumberRange.containsWithEnd(opcode.parameters.back()))
|
if (value && Default::ccNumberRange.containsWithEnd(opcode.parameters.back()))
|
||||||
target = std::make_pair(opcode.parameters.back(), *value);
|
target = { opcode.parameters.back(), *value };
|
||||||
else
|
else
|
||||||
target = {};
|
target = {};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -992,14 +992,14 @@ float sfz::Region::getCrossfadeGain(const sfz::SfzCCArray& ccState) noexcept
|
||||||
|
|
||||||
// Crossfades due to CC states
|
// Crossfades due to CC states
|
||||||
for (const auto& valuePair : crossfadeCCInRange) {
|
for (const auto& valuePair : crossfadeCCInRange) {
|
||||||
const auto ccValue = ccState[valuePair.first];
|
const auto ccValue = ccState[valuePair.cc];
|
||||||
const auto crossfadeRange = valuePair.second;
|
const auto crossfadeRange = valuePair.value;
|
||||||
gain *= crossfadeIn(crossfadeRange, ccValue, crossfadeCCCurve);
|
gain *= crossfadeIn(crossfadeRange, ccValue, crossfadeCCCurve);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& valuePair : crossfadeCCOutRange) {
|
for (const auto& valuePair : crossfadeCCOutRange) {
|
||||||
const auto ccValue = ccState[valuePair.first];
|
const auto ccValue = ccState[valuePair.cc];
|
||||||
const auto crossfadeRange = valuePair.second;
|
const auto crossfadeRange = valuePair.value;
|
||||||
gain *= crossfadeOut(crossfadeRange, ccValue, crossfadeCCCurve);
|
gain *= crossfadeOut(crossfadeRange, ccValue, crossfadeCCCurve);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -264,11 +264,11 @@ struct Region {
|
||||||
float pan { Default::pan }; // pan
|
float pan { Default::pan }; // pan
|
||||||
float width { Default::width }; // width
|
float width { Default::width }; // width
|
||||||
float position { Default::position }; // position
|
float position { Default::position }; // position
|
||||||
absl::optional<CCValuePair> volumeCC; // volume_oncc
|
absl::optional<CCValuePair<float>> volumeCC; // volume_oncc
|
||||||
absl::optional<CCValuePair> amplitudeCC; // amplitude_oncc
|
absl::optional<CCValuePair<float>> amplitudeCC; // amplitude_oncc
|
||||||
absl::optional<CCValuePair> panCC; // pan_oncc
|
absl::optional<CCValuePair<float>> panCC; // pan_oncc
|
||||||
absl::optional<CCValuePair> widthCC; // width_oncc
|
absl::optional<CCValuePair<float>> widthCC; // width_oncc
|
||||||
absl::optional<CCValuePair> positionCC; // position_oncc
|
absl::optional<CCValuePair<float>> 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
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,32 @@ namespace sfz
|
||||||
{
|
{
|
||||||
|
|
||||||
using SfzCCArray = std::array<uint8_t, config::numCCs>;
|
using SfzCCArray = std::array<uint8_t, config::numCCs>;
|
||||||
using CCValuePair = std::pair<uint8_t, float> ;
|
|
||||||
using CCNamePair = std::pair<uint8_t, std::string>;
|
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
|
* @brief Converts cents to a pitch ratio
|
||||||
*
|
*
|
||||||
|
|
@ -94,10 +117,10 @@ constexpr float normalizeBend(float bendValue)
|
||||||
* @param value
|
* @param value
|
||||||
* @return float
|
* @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)
|
if (ccSwitch)
|
||||||
return value + ccSwitch->second * normalizeCC(ccValues[ccSwitch->first]);
|
return value + ccSwitch->value * normalizeCC(ccValues[ccSwitch->cc]);
|
||||||
else
|
else
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ void sfz::Voice::startVoice(Region* region, int delay, int number, uint8_t value
|
||||||
baseVolumedB = region->getBaseVolumedB(number);
|
baseVolumedB = region->getBaseVolumedB(number);
|
||||||
auto volumedB { baseVolumedB };
|
auto volumedB { baseVolumedB };
|
||||||
if (region->volumeCC)
|
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)));
|
volumeEnvelope.reset(db2mag(Default::volumeRange.clamp(volumedB)));
|
||||||
|
|
||||||
baseGain = region->getBaseGain();
|
baseGain = region->getBaseGain();
|
||||||
|
|
@ -56,7 +56,7 @@ void sfz::Voice::startVoice(Region* region, int delay, int number, uint8_t value
|
||||||
|
|
||||||
float gain { baseGain };
|
float gain { baseGain };
|
||||||
if (region->amplitudeCC)
|
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));
|
amplitudeEnvelope.reset(Default::normalizedRange.clamp(gain));
|
||||||
|
|
||||||
float crossfadeGain { region->getCrossfadeGain(resources.midiState.getCCArray()) };
|
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);
|
basePan = normalizePercents(region->pan);
|
||||||
auto pan { basePan };
|
auto pan { basePan };
|
||||||
if (region->panCC)
|
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));
|
panEnvelope.reset(Default::symmetricNormalizedRange.clamp(pan));
|
||||||
|
|
||||||
basePosition = normalizePercents(region->position);
|
basePosition = normalizePercents(region->position);
|
||||||
auto position { basePosition };
|
auto position { basePosition };
|
||||||
if (region->positionCC)
|
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));
|
positionEnvelope.reset(Default::symmetricNormalizedRange.clamp(position));
|
||||||
|
|
||||||
baseWidth = normalizePercents(region->width);
|
baseWidth = normalizePercents(region->width);
|
||||||
auto width { baseWidth };
|
auto width { baseWidth };
|
||||||
if (region->widthCC)
|
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));
|
widthEnvelope.reset(Default::symmetricNormalizedRange.clamp(width));
|
||||||
|
|
||||||
pitchBendEnvelope.setFunction([region](float pitchValue){
|
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...
|
// TODO: this feels like a hack, revisit this along with the smoothed envelopes...
|
||||||
delay = max(delay, minEnvelopeDelay);
|
delay = max(delay, minEnvelopeDelay);
|
||||||
|
|
||||||
if (region->amplitudeCC && ccNumber == region->amplitudeCC->first) {
|
if (region->amplitudeCC && ccNumber == region->amplitudeCC->cc) {
|
||||||
const float newGain { baseGain + normalizeCC(ccValue) * normalizePercents(region->amplitudeCC->second) };
|
const float newGain { baseGain + normalizeCC(ccValue) * normalizePercents(region->amplitudeCC->value) };
|
||||||
amplitudeEnvelope.registerEvent(delay, Default::normalizedRange.clamp(newGain));
|
amplitudeEnvelope.registerEvent(delay, Default::normalizedRange.clamp(newGain));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (region->volumeCC && ccNumber == region->volumeCC->first) {
|
if (region->volumeCC && ccNumber == region->volumeCC->cc) {
|
||||||
const float newVolumedB { baseVolumedB + normalizeCC(ccValue) * region->volumeCC->second };
|
const float newVolumedB { baseVolumedB + normalizeCC(ccValue) * region->volumeCC->value };
|
||||||
volumeEnvelope.registerEvent(delay, db2mag(Default::volumeRange.clamp(newVolumedB)));
|
volumeEnvelope.registerEvent(delay, db2mag(Default::volumeRange.clamp(newVolumedB)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (region->panCC && ccNumber == region->panCC->first) {
|
if (region->panCC && ccNumber == region->panCC->cc) {
|
||||||
const float newPan { basePan + normalizeCC(ccValue) * normalizePercents(region->panCC->second) };
|
const float newPan { basePan + normalizeCC(ccValue) * normalizePercents(region->panCC->value) };
|
||||||
panEnvelope.registerEvent(delay, Default::symmetricNormalizedRange.clamp(newPan));
|
panEnvelope.registerEvent(delay, Default::symmetricNormalizedRange.clamp(newPan));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (region->positionCC && ccNumber == region->positionCC->first) {
|
if (region->positionCC && ccNumber == region->positionCC->cc) {
|
||||||
const float newPosition { basePosition + normalizeCC(ccValue) * normalizePercents(region->positionCC->second) };
|
const float newPosition { basePosition + normalizeCC(ccValue) * normalizePercents(region->positionCC->value) };
|
||||||
positionEnvelope.registerEvent(delay, Default::symmetricNormalizedRange.clamp(newPosition));
|
positionEnvelope.registerEvent(delay, Default::symmetricNormalizedRange.clamp(newPosition));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (region->widthCC && ccNumber == region->widthCC->first) {
|
if (region->widthCC && ccNumber == region->widthCC->cc) {
|
||||||
const float newWidth { baseWidth + normalizeCC(ccValue) * normalizePercents(region->widthCC->second) };
|
const float newWidth { baseWidth + normalizeCC(ccValue) * normalizePercents(region->widthCC->value) };
|
||||||
widthEnvelope.registerEvent(delay, Default::symmetricNormalizedRange.clamp(newWidth));
|
widthEnvelope.registerEvent(delay, Default::symmetricNormalizedRange.clamp(newWidth));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue