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
|
||||
#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);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 = {};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue