Remove CCArray, and store floats internally
This commit is contained in:
parent
f8801e78e4
commit
9373f31945
11 changed files with 209 additions and 151 deletions
|
|
@ -18,15 +18,14 @@ void ADSREnvelope<Type>::reset(const Region& region, const MidiState& state, int
|
||||||
return static_cast<int>(timeInSeconds * sampleRate);
|
return static_cast<int>(timeInSeconds * sampleRate);
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto ccArray = state.getCCArray();
|
this->delay = delay + secondsToSamples(region.amplitudeEG.getDelay(state, velocity));
|
||||||
this->delay = delay + secondsToSamples(region.amplitudeEG.getDelay(ccArray, velocity));
|
this->attack = secondsToSamples(region.amplitudeEG.getAttack(state, velocity));
|
||||||
this->attack = secondsToSamples(region.amplitudeEG.getAttack(ccArray, velocity));
|
this->decay = secondsToSamples(region.amplitudeEG.getDecay(state, velocity));
|
||||||
this->decay = secondsToSamples(region.amplitudeEG.getDecay(ccArray, velocity));
|
this->release = secondsToSamples(region.amplitudeEG.getRelease(state, velocity));
|
||||||
this->release = secondsToSamples(region.amplitudeEG.getRelease(ccArray, velocity));
|
this->hold = secondsToSamples(region.amplitudeEG.getHold(state, velocity));
|
||||||
this->hold = secondsToSamples(region.amplitudeEG.getHold(ccArray, velocity));
|
|
||||||
this->peak = 1.0;
|
this->peak = 1.0;
|
||||||
this->sustain = normalizePercents(region.amplitudeEG.getSustain(ccArray, velocity));
|
this->sustain = normalizePercents(region.amplitudeEG.getSustain(state, velocity));
|
||||||
this->start = this->peak * normalizePercents(region.amplitudeEG.getStart(ccArray, velocity));
|
this->start = this->peak * normalizePercents(region.amplitudeEG.getStart(state, velocity));
|
||||||
|
|
||||||
releaseDelay = 0;
|
releaseDelay = 0;
|
||||||
shouldRelease = false;
|
shouldRelease = false;
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@
|
||||||
#include "Macros.h"
|
#include "Macros.h"
|
||||||
#include "LeakDetector.h"
|
#include "LeakDetector.h"
|
||||||
#include "SfzHelpers.h"
|
#include "SfzHelpers.h"
|
||||||
|
#include "MidiState.h"
|
||||||
#include <absl/types/optional.h>
|
#include <absl/types/optional.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -42,6 +43,23 @@ namespace sfz
|
||||||
* TODO: should be updated for SFZ v2
|
* TODO: should be updated for SFZ v2
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief If a cc switch exists for the value, returns the value with the CC modifier, otherwise returns the value alone.
|
||||||
|
*
|
||||||
|
* @param ccValues
|
||||||
|
* @param ccSwitch
|
||||||
|
* @param value
|
||||||
|
* @return float
|
||||||
|
*/
|
||||||
|
inline float ccSwitchedValue(const MidiState& state, const absl::optional<CCValuePair<float>>& ccSwitch, float value) noexcept
|
||||||
|
{
|
||||||
|
if (ccSwitch)
|
||||||
|
return value + ccSwitch->value * normalizeCC(state.getCCValue(ccSwitch->cc));
|
||||||
|
else
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
struct EGDescription
|
struct EGDescription
|
||||||
{
|
{
|
||||||
EGDescription() = default;
|
EGDescription() = default;
|
||||||
|
|
@ -76,80 +94,80 @@ struct EGDescription
|
||||||
/**
|
/**
|
||||||
* @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
|
||||||
*
|
*
|
||||||
* @param ccValues
|
* @param state
|
||||||
* @param velocity
|
* @param velocity
|
||||||
* @return float
|
* @return float
|
||||||
*/
|
*/
|
||||||
float getAttack(const SfzCCArray &ccValues, uint8_t velocity) const noexcept
|
float getAttack(const MidiState &state, uint8_t velocity) const noexcept
|
||||||
{
|
{
|
||||||
return Default::egTimeRange.clamp(ccSwitchedValue(ccValues, ccAttack, attack) + normalizeVelocity(velocity)*vel2attack);
|
return Default::egTimeRange.clamp(ccSwitchedValue(state, ccAttack, attack) + normalizeVelocity(velocity)*vel2attack);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @brief Get the decay with possibly a CC modifier and a velocity modifier
|
* @brief Get the decay with possibly a CC modifier and a velocity modifier
|
||||||
*
|
*
|
||||||
* @param ccValues
|
* @param state
|
||||||
* @param velocity
|
* @param velocity
|
||||||
* @return float
|
* @return float
|
||||||
*/
|
*/
|
||||||
float getDecay(const SfzCCArray &ccValues, uint8_t velocity) const noexcept
|
float getDecay(const MidiState &state, uint8_t velocity) const noexcept
|
||||||
{
|
{
|
||||||
return Default::egTimeRange.clamp(ccSwitchedValue(ccValues, ccDecay, decay) + normalizeVelocity(velocity)*vel2decay);
|
return Default::egTimeRange.clamp(ccSwitchedValue(state, ccDecay, decay) + normalizeVelocity(velocity)*vel2decay);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @brief Get the delay with possibly a CC modifier and a velocity modifier
|
* @brief Get the delay with possibly a CC modifier and a velocity modifier
|
||||||
*
|
*
|
||||||
* @param ccValues
|
* @param state
|
||||||
* @param velocity
|
* @param velocity
|
||||||
* @return float
|
* @return float
|
||||||
*/
|
*/
|
||||||
float getDelay(const SfzCCArray &ccValues, uint8_t velocity) const noexcept
|
float getDelay(const MidiState &state, uint8_t velocity) const noexcept
|
||||||
{
|
{
|
||||||
return Default::egTimeRange.clamp(ccSwitchedValue(ccValues, ccDelay, delay) + normalizeVelocity(velocity)*vel2delay);
|
return Default::egTimeRange.clamp(ccSwitchedValue(state, ccDelay, delay) + normalizeVelocity(velocity)*vel2delay);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @brief Get the holding duration with possibly a CC modifier and a velocity modifier
|
* @brief Get the holding duration with possibly a CC modifier and a velocity modifier
|
||||||
*
|
*
|
||||||
* @param ccValues
|
* @param state
|
||||||
* @param velocity
|
* @param velocity
|
||||||
* @return float
|
* @return float
|
||||||
*/
|
*/
|
||||||
float getHold(const SfzCCArray &ccValues, uint8_t velocity) const noexcept
|
float getHold(const MidiState &state, uint8_t velocity) const noexcept
|
||||||
{
|
{
|
||||||
return Default::egTimeRange.clamp(ccSwitchedValue(ccValues, ccHold, hold) + normalizeVelocity(velocity)*vel2hold);
|
return Default::egTimeRange.clamp(ccSwitchedValue(state, ccHold, hold) + normalizeVelocity(velocity)*vel2hold);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @brief Get the release duration with possibly a CC modifier and a velocity modifier
|
* @brief Get the release duration with possibly a CC modifier and a velocity modifier
|
||||||
*
|
*
|
||||||
* @param ccValues
|
* @param state
|
||||||
* @param velocity
|
* @param velocity
|
||||||
* @return float
|
* @return float
|
||||||
*/
|
*/
|
||||||
float getRelease(const SfzCCArray &ccValues, uint8_t velocity) const noexcept
|
float getRelease(const MidiState &state, uint8_t velocity) const noexcept
|
||||||
{
|
{
|
||||||
return Default::egTimeRange.clamp(ccSwitchedValue(ccValues, ccRelease, release) + normalizeVelocity(velocity)*vel2release);
|
return Default::egTimeRange.clamp(ccSwitchedValue(state, ccRelease, release) + normalizeVelocity(velocity)*vel2release);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @brief Get the starting level with possibly a CC modifier and a velocity modifier
|
* @brief Get the starting level with possibly a CC modifier and a velocity modifier
|
||||||
*
|
*
|
||||||
* @param ccValues
|
* @param state
|
||||||
* @param velocity
|
* @param velocity
|
||||||
* @return float
|
* @return float
|
||||||
*/
|
*/
|
||||||
float getStart(const SfzCCArray &ccValues, uint8_t velocity) const noexcept
|
float getStart(const MidiState &state, uint8_t velocity) const noexcept
|
||||||
{
|
{
|
||||||
UNUSED(velocity);
|
UNUSED(velocity);
|
||||||
return Default::egPercentRange.clamp(ccSwitchedValue(ccValues, ccStart, start));
|
return Default::egPercentRange.clamp(ccSwitchedValue(state, ccStart, start));
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @brief Get the sustain level with possibly a CC modifier and a velocity modifier
|
* @brief Get the sustain level with possibly a CC modifier and a velocity modifier
|
||||||
*
|
*
|
||||||
* @param ccValues
|
* @param state
|
||||||
* @param velocity
|
* @param velocity
|
||||||
* @return float
|
* @return float
|
||||||
*/
|
*/
|
||||||
float getSustain(const SfzCCArray &ccValues, uint8_t velocity) const noexcept
|
float getSustain(const MidiState &state, uint8_t velocity) const noexcept
|
||||||
{
|
{
|
||||||
return Default::egPercentRange.clamp(ccSwitchedValue(ccValues, ccSustain, sustain) + normalizeVelocity(velocity)*vel2sustain);
|
return Default::egPercentRange.clamp(ccSwitchedValue(state, ccSustain, sustain) + normalizeVelocity(velocity)*vel2sustain);
|
||||||
}
|
}
|
||||||
LEAK_DETECTOR(EGDescription);
|
LEAK_DETECTOR(EGDescription);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,19 @@ sfz::MidiState::MidiState()
|
||||||
}
|
}
|
||||||
|
|
||||||
void sfz::MidiState::noteOnEvent(int delay, int noteNumber, uint8_t velocity) noexcept
|
void sfz::MidiState::noteOnEvent(int delay, int noteNumber, uint8_t velocity) noexcept
|
||||||
|
{
|
||||||
|
noteOnEventNormalized(delay, noteNumber, normalizeVelocity(velocity));
|
||||||
|
}
|
||||||
|
|
||||||
|
void sfz::MidiState::noteOffEvent(int delay, int noteNumber, uint8_t velocity) noexcept
|
||||||
|
{
|
||||||
|
noteOffEventNormalized(delay, noteNumber, normalizeVelocity(velocity));
|
||||||
|
}
|
||||||
|
|
||||||
|
void sfz::MidiState::noteOnEventNormalized(int delay, int noteNumber, float velocity) noexcept
|
||||||
{
|
{
|
||||||
ASSERT(noteNumber >= 0 && noteNumber <= 127);
|
ASSERT(noteNumber >= 0 && noteNumber <= 127);
|
||||||
ASSERT(velocity >= 0 && velocity <= 127);
|
ASSERT(velocity >= 0 && velocity <= 1.0);
|
||||||
|
|
||||||
if (noteNumber >= 0 && noteNumber < 128) {
|
if (noteNumber >= 0 && noteNumber < 128) {
|
||||||
lastNoteVelocities[noteNumber] = velocity;
|
lastNoteVelocities[noteNumber] = velocity;
|
||||||
|
|
@ -26,10 +36,10 @@ void sfz::MidiState::noteOnEvent(int delay, int noteNumber, uint8_t velocity) no
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sfz::MidiState::noteOffEvent(int delay, int noteNumber, uint8_t velocity) noexcept
|
void sfz::MidiState::noteOffEventNormalized(int delay, int noteNumber, float velocity) noexcept
|
||||||
{
|
{
|
||||||
ASSERT(noteNumber >= 0 && noteNumber <= 127);
|
ASSERT(noteNumber >= 0 && noteNumber <= 127);
|
||||||
ASSERT(velocity >= 0 && velocity <= 127);
|
ASSERT(velocity >= 0.0 && velocity <= 1.0);
|
||||||
UNUSED(velocity);
|
UNUSED(velocity);
|
||||||
if (noteNumber >= 0 && noteNumber < 128) {
|
if (noteNumber >= 0 && noteNumber < 128) {
|
||||||
if (activeNotes > 0)
|
if (activeNotes > 0)
|
||||||
|
|
@ -52,12 +62,18 @@ float sfz::MidiState::getNoteDuration(int noteNumber) const
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t sfz::MidiState::getNoteVelocity(int noteNumber) const noexcept
|
uint8_t sfz::MidiState::getNoteVelocity(int noteNumber) const noexcept
|
||||||
|
{
|
||||||
|
return denormalizeVelocity(getNoteVelocityNormalized(noteNumber));
|
||||||
|
}
|
||||||
|
|
||||||
|
float sfz::MidiState::getNoteVelocityNormalized(int noteNumber) const noexcept
|
||||||
{
|
{
|
||||||
ASSERT(noteNumber >= 0 && noteNumber <= 127);
|
ASSERT(noteNumber >= 0 && noteNumber <= 127);
|
||||||
|
|
||||||
return lastNoteVelocities[noteNumber];
|
return lastNoteVelocities[noteNumber];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void sfz::MidiState::pitchBendEvent(int delay, int pitchBendValue) noexcept
|
void sfz::MidiState::pitchBendEvent(int delay, int pitchBendValue) noexcept
|
||||||
{
|
{
|
||||||
ASSERT(pitchBendValue >= -8192 && pitchBendValue <= 8192);
|
ASSERT(pitchBendValue >= -8192 && pitchBendValue <= 8192);
|
||||||
|
|
@ -72,24 +88,28 @@ int sfz::MidiState::getPitchBend() const noexcept
|
||||||
|
|
||||||
void sfz::MidiState::ccEvent(int delay, int ccNumber, uint8_t ccValue) noexcept
|
void sfz::MidiState::ccEvent(int delay, int ccNumber, uint8_t ccValue) noexcept
|
||||||
{
|
{
|
||||||
ASSERT(ccNumber >= 0 && ccNumber < config::numCCs);
|
ccEventNormalized(delay, ccNumber, normalizeCC(ccValue));
|
||||||
ASSERT(ccValue >= 0 && ccValue <= 127);
|
|
||||||
|
|
||||||
cc[ccNumber] = ccValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t sfz::MidiState::getCCValue(int ccNumber) const noexcept
|
uint8_t sfz::MidiState::getCCValue(int ccNumber) const noexcept
|
||||||
|
{
|
||||||
|
return denormalizeCC(getCCValueNormalized(ccNumber));
|
||||||
|
}
|
||||||
|
|
||||||
|
void sfz::MidiState::ccEventNormalized(int delay, int ccNumber, float ccValue) noexcept
|
||||||
|
{
|
||||||
|
ASSERT(ccValue >= 0.0 && ccValue <= 1.0);
|
||||||
|
|
||||||
|
cc[ccNumber] = ccValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float sfz::MidiState::getCCValueNormalized(int ccNumber) const noexcept
|
||||||
{
|
{
|
||||||
ASSERT(ccNumber >= 0 && ccNumber < config::numCCs);
|
ASSERT(ccNumber >= 0 && ccNumber < config::numCCs);
|
||||||
|
|
||||||
return cc[ccNumber];
|
return cc[ccNumber];
|
||||||
}
|
}
|
||||||
|
|
||||||
const sfz::SfzCCArray& sfz::MidiState::getCCArray() const noexcept
|
|
||||||
{
|
|
||||||
return cc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void sfz::MidiState::reset(int delay) noexcept
|
void sfz::MidiState::reset(int delay) noexcept
|
||||||
{
|
{
|
||||||
for (auto& velocity: lastNoteVelocities)
|
for (auto& velocity: lastNoteVelocities)
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include "SfzHelpers.h"
|
|
||||||
#include "CCMap.h"
|
#include "CCMap.h"
|
||||||
#include "Range.h"
|
#include "Range.h"
|
||||||
|
|
||||||
|
|
@ -31,6 +30,14 @@ public:
|
||||||
*/
|
*/
|
||||||
void noteOnEvent(int delay, int noteNumber, uint8_t velocity) noexcept;
|
void noteOnEvent(int delay, int noteNumber, uint8_t velocity) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Update the state after a note on event
|
||||||
|
*
|
||||||
|
* @param noteNumber
|
||||||
|
* @param velocity
|
||||||
|
*/
|
||||||
|
void noteOnEventNormalized(int delay, int noteNumber, float velocity) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Update the state after a note off event
|
* @brief Update the state after a note off event
|
||||||
*
|
*
|
||||||
|
|
@ -39,6 +46,14 @@ public:
|
||||||
*/
|
*/
|
||||||
void noteOffEvent(int delay, int noteNumber, uint8_t velocity) noexcept;
|
void noteOffEvent(int delay, int noteNumber, uint8_t velocity) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Update the state after a note off event
|
||||||
|
*
|
||||||
|
* @param noteNumber
|
||||||
|
* @param velocity
|
||||||
|
*/
|
||||||
|
void noteOffEventNormalized(int delay, int noteNumber, float velocity) noexcept;
|
||||||
|
|
||||||
int getActiveNotes() const noexcept { return activeNotes; }
|
int getActiveNotes() const noexcept { return activeNotes; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -57,6 +72,14 @@ public:
|
||||||
*/
|
*/
|
||||||
uint8_t getNoteVelocity(int noteNumber) const noexcept;
|
uint8_t getNoteVelocity(int noteNumber) const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the note on velocity for a given note
|
||||||
|
*
|
||||||
|
* @param noteNumber
|
||||||
|
* @return float
|
||||||
|
*/
|
||||||
|
float getNoteVelocityNormalized(int noteNumber) const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Register a pitch bend event
|
* @brief Register a pitch bend event
|
||||||
*
|
*
|
||||||
|
|
@ -79,6 +102,14 @@ public:
|
||||||
*/
|
*/
|
||||||
void ccEvent(int delay, int ccNumber, uint8_t ccValue) noexcept;
|
void ccEvent(int delay, int ccNumber, uint8_t ccValue) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Register a CC event
|
||||||
|
*
|
||||||
|
* @param ccNumber
|
||||||
|
* @param ccValue
|
||||||
|
*/
|
||||||
|
void ccEventNormalized(int delay, int ccNumber, float ccValue) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the CC value for CC number
|
* @brief Get the CC value for CC number
|
||||||
*
|
*
|
||||||
|
|
@ -88,11 +119,12 @@ public:
|
||||||
uint8_t getCCValue(int ccNumber) const noexcept;
|
uint8_t getCCValue(int ccNumber) const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the full CC status
|
* @brief Get the CC value for CC number
|
||||||
*
|
*
|
||||||
* @return const SfzCCArray&
|
* @param ccNumber
|
||||||
|
* @return float
|
||||||
*/
|
*/
|
||||||
const SfzCCArray& getCCArray() const noexcept;
|
float getCCValueNormalized(int ccNumber) const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Reset the midi state (does not impact the last note on time)
|
* @brief Reset the midi state (does not impact the last note on time)
|
||||||
|
|
@ -140,12 +172,12 @@ private:
|
||||||
* depressed notes.
|
* depressed notes.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
MidiNoteArray<uint8_t> lastNoteVelocities;
|
MidiNoteArray<float> lastNoteVelocities;
|
||||||
/**
|
/**
|
||||||
* @brief Current known values for the CCs.
|
* @brief Current known values for the CCs.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
SfzCCArray cc;
|
std::array<float, config::numCCs> cc;
|
||||||
/**
|
/**
|
||||||
* Pitch bend status
|
* Pitch bend status
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -1009,19 +1009,19 @@ float sfz::Region::getNoteGain(int noteNumber, uint8_t velocity) const noexcept
|
||||||
return baseGain;
|
return baseGain;
|
||||||
}
|
}
|
||||||
|
|
||||||
float sfz::Region::getCrossfadeGain(const sfz::SfzCCArray& ccState) const noexcept
|
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& valuePair : crossfadeCCInRange) {
|
||||||
const auto ccValue = ccState[valuePair.cc];
|
const auto ccValue = midiState.getCCValue(valuePair.cc);
|
||||||
const auto crossfadeRange = valuePair.value;
|
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.cc];
|
const auto ccValue = midiState.getCCValue(valuePair.cc);
|
||||||
const auto crossfadeRange = valuePair.value;
|
const auto crossfadeRange = valuePair.value;
|
||||||
gain *= crossfadeOut(crossfadeRange, ccValue, crossfadeCCCurve);
|
gain *= crossfadeOut(crossfadeRange, ccValue, crossfadeCCCurve);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -152,7 +152,7 @@ struct Region {
|
||||||
* @param ccState
|
* @param ccState
|
||||||
* @return float
|
* @return float
|
||||||
*/
|
*/
|
||||||
float getCrossfadeGain(const SfzCCArray& ccState) const noexcept;
|
float getCrossfadeGain() const noexcept;
|
||||||
/**
|
/**
|
||||||
* @brief Get the base volume of the region depending on which note has been
|
* @brief Get the base volume of the region depending on which note has been
|
||||||
* pressed to trigger the region.
|
* pressed to trigger the region.
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@
|
||||||
namespace sfz
|
namespace sfz
|
||||||
{
|
{
|
||||||
|
|
||||||
using SfzCCArray = std::array<uint8_t, config::numCCs>;
|
|
||||||
using CCNamePair = std::pair<uint16_t, std::string>;
|
using CCNamePair = std::pair<uint16_t, std::string>;
|
||||||
|
|
||||||
template<class ValueType>
|
template<class ValueType>
|
||||||
|
|
@ -83,6 +82,16 @@ constexpr T denormalize7Bits(float value)
|
||||||
return static_cast<T>(value * 127.0f);
|
return static_cast<T>(value * 127.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr uint8_t denormalizeCC(float value)
|
||||||
|
{
|
||||||
|
return denormalize7Bits<uint8_t>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr uint8_t denormalizeVelocity(float value)
|
||||||
|
{
|
||||||
|
return denormalize7Bits<uint8_t>(value);
|
||||||
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
constexpr float normalize7Bits(T value)
|
constexpr float normalize7Bits(T value)
|
||||||
{
|
{
|
||||||
|
|
@ -141,22 +150,6 @@ constexpr float normalizeBend(float bendValue)
|
||||||
return min(max(bendValue, -8191.0f), 8191.0f) / 8191.0f;
|
return min(max(bendValue, -8191.0f), 8191.0f) / 8191.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief If a cc switch exists for the value, returns the value with the CC modifier, otherwise returns the value alone.
|
|
||||||
*
|
|
||||||
* @param ccValues
|
|
||||||
* @param ccSwitch
|
|
||||||
* @param value
|
|
||||||
* @return float
|
|
||||||
*/
|
|
||||||
inline float ccSwitchedValue(const SfzCCArray& ccValues, const absl::optional<CCValuePair<float>>& ccSwitch, float value) noexcept
|
|
||||||
{
|
|
||||||
if (ccSwitch)
|
|
||||||
return value + ccSwitch->value * normalizeCC(ccValues[ccSwitch->cc]);
|
|
||||||
else
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Convert a note in string to its equivalent midi note number
|
* @brief Convert a note in string to its equivalent midi note number
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ void sfz::Voice::startVoice(Region* region, int delay, int number, uint8_t value
|
||||||
gain += normalizeCC(resources.midiState.getCCValue(region->amplitudeCC->cc)) * normalizePercents(region->amplitudeCC->value);
|
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() };
|
||||||
crossfadeEnvelope.reset(Default::normalizedRange.clamp(crossfadeGain));
|
crossfadeEnvelope.reset(Default::normalizedRange.clamp(crossfadeGain));
|
||||||
|
|
||||||
basePan = normalizePercents(region->pan);
|
basePan = normalizePercents(region->pan);
|
||||||
|
|
@ -225,7 +225,7 @@ void sfz::Voice::registerCC(int delay, int ccNumber, uint8_t ccValue) noexcept
|
||||||
}
|
}
|
||||||
|
|
||||||
if (region->crossfadeCCInRange.contains(ccNumber) || region->crossfadeCCOutRange.contains(ccNumber)) {
|
if (region->crossfadeCCInRange.contains(ccNumber) || region->crossfadeCCOutRange.contains(ccNumber)) {
|
||||||
const float crossfadeGain = region->getCrossfadeGain(resources.midiState.getCCArray());
|
const float crossfadeGain = region->getCrossfadeGain();
|
||||||
crossfadeEnvelope.registerEvent(delay, Default::normalizedRange.clamp(crossfadeGain));
|
crossfadeEnvelope.registerEvent(delay, Default::normalizedRange.clamp(crossfadeGain));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,108 +12,108 @@ using namespace Catch::literals;
|
||||||
TEST_CASE("[EGDescription] Attack range")
|
TEST_CASE("[EGDescription] Attack range")
|
||||||
{
|
{
|
||||||
sfz::EGDescription eg;
|
sfz::EGDescription eg;
|
||||||
sfz::SfzCCArray ccArray { 0 };
|
sfz::MidiState state;
|
||||||
eg.attack = 1;
|
eg.attack = 1;
|
||||||
eg.vel2attack = -1.27f;
|
eg.vel2attack = -1.27f;
|
||||||
eg.ccAttack = { 63, 1.27f };
|
eg.ccAttack = { 63, 1.27f };
|
||||||
REQUIRE( eg.getAttack(ccArray, 0) == 1.0f );
|
REQUIRE( eg.getAttack(state, 0) == 1.0f );
|
||||||
REQUIRE( eg.getAttack(ccArray, 127) == 0.0f );
|
REQUIRE( eg.getAttack(state, 127) == 0.0f );
|
||||||
ccArray[63] = 127;
|
state.ccEvent(0, 63, 127);
|
||||||
REQUIRE( eg.getAttack(ccArray, 127) == 1.0f );
|
REQUIRE( eg.getAttack(state, 127) == 1.0f );
|
||||||
REQUIRE( eg.getAttack(ccArray, 0) == 2.27f );
|
REQUIRE( eg.getAttack(state, 0) == 2.27f );
|
||||||
eg.ccAttack = { 63, 127.0f };
|
eg.ccAttack = { 63, 127.0f };
|
||||||
REQUIRE( eg.getAttack(ccArray, 0) == 100.0f );
|
REQUIRE( eg.getAttack(state, 0) == 100.0f );
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("[EGDescription] Delay range")
|
TEST_CASE("[EGDescription] Delay range")
|
||||||
{
|
{
|
||||||
sfz::EGDescription eg;
|
sfz::EGDescription eg;
|
||||||
sfz::SfzCCArray ccArray { 0 };
|
sfz::MidiState state;
|
||||||
eg.delay = 1;
|
eg.delay = 1;
|
||||||
eg.vel2delay = -1.27f;
|
eg.vel2delay = -1.27f;
|
||||||
eg.ccDelay = { 63, 1.27f };
|
eg.ccDelay = { 63, 1.27f };
|
||||||
REQUIRE( eg.getDelay(ccArray, 0) == 1.0f );
|
REQUIRE( eg.getDelay(state, 0) == 1.0f );
|
||||||
REQUIRE( eg.getDelay(ccArray, 127) == 0.0f );
|
REQUIRE( eg.getDelay(state, 127) == 0.0f );
|
||||||
ccArray[63] = 127;
|
state.ccEvent(0, 63, 127);
|
||||||
REQUIRE( eg.getDelay(ccArray, 127) == 1.0f );
|
REQUIRE( eg.getDelay(state, 127) == 1.0f );
|
||||||
REQUIRE( eg.getDelay(ccArray, 0) == 2.27f );
|
REQUIRE( eg.getDelay(state, 0) == 2.27f );
|
||||||
eg.ccDelay = { 63, 127.0f };
|
eg.ccDelay = { 63, 127.0f };
|
||||||
REQUIRE( eg.getDelay(ccArray, 0) == 100.0f );
|
REQUIRE( eg.getDelay(state, 0) == 100.0f );
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("[EGDescription] Decay range")
|
TEST_CASE("[EGDescription] Decay range")
|
||||||
{
|
{
|
||||||
sfz::EGDescription eg;
|
sfz::EGDescription eg;
|
||||||
sfz::SfzCCArray ccArray { 0 };
|
sfz::MidiState state;
|
||||||
eg.decay = 1.0f;
|
eg.decay = 1.0f;
|
||||||
eg.vel2decay = -1.27f;
|
eg.vel2decay = -1.27f;
|
||||||
eg.ccDecay = { 63, 1.27f };
|
eg.ccDecay = { 63, 1.27f };
|
||||||
REQUIRE( eg.getDecay(ccArray, 0) == 1.0f );
|
REQUIRE( eg.getDecay(state, 0) == 1.0f );
|
||||||
REQUIRE( eg.getDecay(ccArray, 127) == 0.0f );
|
REQUIRE( eg.getDecay(state, 127) == 0.0f );
|
||||||
ccArray[63] = 127;
|
state.ccEvent(0, 63, 127);
|
||||||
REQUIRE( eg.getDecay(ccArray, 127) == 1.0f );
|
REQUIRE( eg.getDecay(state, 127) == 1.0f );
|
||||||
REQUIRE( eg.getDecay(ccArray, 0) == 2.27f );
|
REQUIRE( eg.getDecay(state, 0) == 2.27f );
|
||||||
eg.ccDecay = { 63, 127.0f };
|
eg.ccDecay = { 63, 127.0f };
|
||||||
REQUIRE( eg.getDecay(ccArray, 0) == 100.0f );
|
REQUIRE( eg.getDecay(state, 0) == 100.0f );
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("[EGDescription] Release range")
|
TEST_CASE("[EGDescription] Release range")
|
||||||
{
|
{
|
||||||
sfz::EGDescription eg;
|
sfz::EGDescription eg;
|
||||||
sfz::SfzCCArray ccArray { 0 };
|
sfz::MidiState state;
|
||||||
eg.release = 1;
|
eg.release = 1;
|
||||||
eg.vel2release = -1.27f;
|
eg.vel2release = -1.27f;
|
||||||
eg.ccRelease = { 63, 1.27f };
|
eg.ccRelease = { 63, 1.27f };
|
||||||
REQUIRE( eg.getRelease(ccArray, 0) == 1.0f );
|
REQUIRE( eg.getRelease(state, 0) == 1.0f );
|
||||||
REQUIRE( eg.getRelease(ccArray, 127) == 0.0f );
|
REQUIRE( eg.getRelease(state, 127) == 0.0f );
|
||||||
ccArray[63] = 127;
|
state.ccEvent(0, 63, 127);
|
||||||
REQUIRE( eg.getRelease(ccArray, 127) == 1.0f );
|
REQUIRE( eg.getRelease(state, 127) == 1.0f );
|
||||||
REQUIRE( eg.getRelease(ccArray, 0) == 2.27f );
|
REQUIRE( eg.getRelease(state, 0) == 2.27f );
|
||||||
eg.ccRelease = { 63, 127.0f };
|
eg.ccRelease = { 63, 127.0f };
|
||||||
REQUIRE( eg.getRelease(ccArray, 0) == 100.0f );
|
REQUIRE( eg.getRelease(state, 0) == 100.0f );
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("[EGDescription] Hold range")
|
TEST_CASE("[EGDescription] Hold range")
|
||||||
{
|
{
|
||||||
sfz::EGDescription eg;
|
sfz::EGDescription eg;
|
||||||
sfz::SfzCCArray ccArray { 0 };
|
sfz::MidiState state;
|
||||||
eg.hold = 1;
|
eg.hold = 1;
|
||||||
eg.vel2hold = -1.27f;
|
eg.vel2hold = -1.27f;
|
||||||
eg.ccHold = { 63, 1.27f };
|
eg.ccHold = { 63, 1.27f };
|
||||||
REQUIRE( eg.getHold(ccArray, 0) == 1.0f );
|
REQUIRE( eg.getHold(state, 0) == 1.0f );
|
||||||
REQUIRE( eg.getHold(ccArray, 127) == 0.0f );
|
REQUIRE( eg.getHold(state, 127) == 0.0f );
|
||||||
ccArray[63] = 127;
|
state.ccEvent(0, 63, 127);
|
||||||
REQUIRE( eg.getHold(ccArray, 127) == 1.0f );
|
REQUIRE( eg.getHold(state, 127) == 1.0f );
|
||||||
REQUIRE( eg.getHold(ccArray, 0) == 2.27f );
|
REQUIRE( eg.getHold(state, 0) == 2.27f );
|
||||||
eg.ccHold = { 63, 127.0f };
|
eg.ccHold = { 63, 127.0f };
|
||||||
REQUIRE( eg.getHold(ccArray, 0) == 100.0f );
|
REQUIRE( eg.getHold(state, 0) == 100.0f );
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("[EGDescription] Sustain level")
|
TEST_CASE("[EGDescription] Sustain level")
|
||||||
{
|
{
|
||||||
sfz::EGDescription eg;
|
sfz::EGDescription eg;
|
||||||
sfz::SfzCCArray ccArray { 0 };
|
sfz::MidiState state;
|
||||||
eg.sustain = 50;
|
eg.sustain = 50;
|
||||||
eg.vel2sustain = -100;
|
eg.vel2sustain = -100;
|
||||||
eg.ccSustain = { 63, 100.0f };
|
eg.ccSustain = { 63, 100.0f };
|
||||||
REQUIRE( eg.getSustain(ccArray, 0) == 50.0f );
|
REQUIRE( eg.getSustain(state, 0) == 50.0f );
|
||||||
REQUIRE( eg.getSustain(ccArray, 127) == 0.0f );
|
REQUIRE( eg.getSustain(state, 127) == 0.0f );
|
||||||
ccArray[63] = 127;
|
state.ccEvent(0, 63, 127);
|
||||||
REQUIRE( eg.getSustain(ccArray, 127) == 50.0f );
|
REQUIRE( eg.getSustain(state, 127) == 50.0f );
|
||||||
eg.ccSustain = { 63, 200.0f };
|
eg.ccSustain = { 63, 200.0f };
|
||||||
REQUIRE( eg.getSustain(ccArray, 0) == 100.0f );
|
REQUIRE( eg.getSustain(state, 0) == 100.0f );
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("[EGDescription] Start level")
|
TEST_CASE("[EGDescription] Start level")
|
||||||
{
|
{
|
||||||
sfz::EGDescription eg;
|
sfz::EGDescription eg;
|
||||||
sfz::SfzCCArray ccArray { 0 };
|
sfz::MidiState state;
|
||||||
eg.start = 0;
|
eg.start = 0;
|
||||||
eg.ccStart = { 63, 127.0f };
|
eg.ccStart = { 63, 127.0f };
|
||||||
REQUIRE( eg.getStart(ccArray, 0) == 0.0f );
|
REQUIRE( eg.getStart(state, 0) == 0.0f );
|
||||||
REQUIRE( eg.getStart(ccArray, 127) == 0.0f );
|
REQUIRE( eg.getStart(state, 127) == 0.0f );
|
||||||
ccArray[63] = 127;
|
state.ccEvent(0, 63, 127);
|
||||||
REQUIRE( eg.getStart(ccArray, 0) == 100.0f );
|
REQUIRE( eg.getStart(state, 0) == 100.0f );
|
||||||
eg.ccStart = { 63, -127.0f };
|
eg.ccStart = { 63, -127.0f };
|
||||||
REQUIRE( eg.getStart(ccArray, 0) == 0.0f );
|
REQUIRE( eg.getStart(state, 0) == 0.0f );
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,21 +18,18 @@ using namespace Catch::literals;
|
||||||
TEST_CASE("[MidiState] Initial values")
|
TEST_CASE("[MidiState] Initial values")
|
||||||
{
|
{
|
||||||
sfz::MidiState state;
|
sfz::MidiState state;
|
||||||
for (auto& cc: state.getCCArray())
|
for (unsigned cc = 0; cc < sfz::config::numCCs; cc++)
|
||||||
REQUIRE( cc == 0 );
|
REQUIRE( state.getCCValue(cc) == 0 );
|
||||||
REQUIRE( state.getPitchBend() == 0 );
|
REQUIRE( state.getPitchBend() == 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("[MidiState] Set and get CCs")
|
TEST_CASE("[MidiState] Set and get CCs")
|
||||||
{
|
{
|
||||||
sfz::MidiState state;
|
sfz::MidiState state;
|
||||||
const auto& cc = state.getCCArray();
|
|
||||||
state.ccEvent(0, 24, 23);
|
state.ccEvent(0, 24, 23);
|
||||||
state.ccEvent(0, 123, 124);
|
state.ccEvent(0, 123, 124);
|
||||||
REQUIRE(state.getCCValue(24) == 23);
|
REQUIRE(state.getCCValue(24) == 23);
|
||||||
REQUIRE(cc[24] == 23);
|
|
||||||
REQUIRE(state.getCCValue(123) == 124);
|
REQUIRE(state.getCCValue(123) == 124);
|
||||||
REQUIRE(cc[123] == 124);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("[MidiState] Set and get pitch bends")
|
TEST_CASE("[MidiState] Set and get pitch bends")
|
||||||
|
|
@ -68,6 +65,5 @@ TEST_CASE("[MidiState] Set and get note velocities")
|
||||||
TEST_CASE("[MidiState] Extended CCs")
|
TEST_CASE("[MidiState] Extended CCs")
|
||||||
{
|
{
|
||||||
sfz::MidiState state;
|
sfz::MidiState state;
|
||||||
REQUIRE(state.getCCArray().size() >= 142);
|
|
||||||
state.ccEvent(0, 142, 64); // should not trap
|
state.ccEvent(0, 142, 64); // should not trap
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -166,13 +166,13 @@ TEST_CASE("[Region] Crossfade in on CC")
|
||||||
region.parseOpcode({ "xfin_locc24", "20" });
|
region.parseOpcode({ "xfin_locc24", "20" });
|
||||||
region.parseOpcode({ "xfin_hicc24", "24" });
|
region.parseOpcode({ "xfin_hicc24", "24" });
|
||||||
region.parseOpcode({ "amp_veltrack", "0" });
|
region.parseOpcode({ "amp_veltrack", "0" });
|
||||||
midiState.ccEvent(0, 24, 19); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.0_a );
|
midiState.ccEvent(0, 24, 19); REQUIRE( region.getCrossfadeGain() == 0.0_a );
|
||||||
midiState.ccEvent(0, 24, 20); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.0_a );
|
midiState.ccEvent(0, 24, 20); REQUIRE( region.getCrossfadeGain() == 0.0_a );
|
||||||
midiState.ccEvent(0, 24, 21); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.5_a );
|
midiState.ccEvent(0, 24, 21); REQUIRE( region.getCrossfadeGain() == 0.5_a );
|
||||||
midiState.ccEvent(0, 24, 22); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.70711_a );
|
midiState.ccEvent(0, 24, 22); REQUIRE( region.getCrossfadeGain() == 0.70711_a );
|
||||||
midiState.ccEvent(0, 24, 23); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.86603_a );
|
midiState.ccEvent(0, 24, 23); REQUIRE( region.getCrossfadeGain() == 0.86603_a );
|
||||||
midiState.ccEvent(0, 24, 24); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 1.0_a );
|
midiState.ccEvent(0, 24, 24); REQUIRE( region.getCrossfadeGain() == 1.0_a );
|
||||||
midiState.ccEvent(0, 24, 25); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 1.0_a );
|
midiState.ccEvent(0, 24, 25); REQUIRE( region.getCrossfadeGain() == 1.0_a );
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("[Region] Crossfade in on CC - gain")
|
TEST_CASE("[Region] Crossfade in on CC - gain")
|
||||||
|
|
@ -184,13 +184,13 @@ TEST_CASE("[Region] Crossfade in on CC - gain")
|
||||||
region.parseOpcode({ "xfin_hicc24", "24" });
|
region.parseOpcode({ "xfin_hicc24", "24" });
|
||||||
region.parseOpcode({ "amp_veltrack", "0" });
|
region.parseOpcode({ "amp_veltrack", "0" });
|
||||||
region.parseOpcode({ "xf_cccurve", "gain" });
|
region.parseOpcode({ "xf_cccurve", "gain" });
|
||||||
midiState.ccEvent(0, 24, 19); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.0_a );
|
midiState.ccEvent(0, 24, 19); REQUIRE( region.getCrossfadeGain() == 0.0_a );
|
||||||
midiState.ccEvent(0, 24, 20); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.0_a );
|
midiState.ccEvent(0, 24, 20); REQUIRE( region.getCrossfadeGain() == 0.0_a );
|
||||||
midiState.ccEvent(0, 24, 21); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.25_a );
|
midiState.ccEvent(0, 24, 21); REQUIRE( region.getCrossfadeGain() == 0.25_a );
|
||||||
midiState.ccEvent(0, 24, 22); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.5_a );
|
midiState.ccEvent(0, 24, 22); REQUIRE( region.getCrossfadeGain() == 0.5_a );
|
||||||
midiState.ccEvent(0, 24, 23); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.75_a );
|
midiState.ccEvent(0, 24, 23); REQUIRE( region.getCrossfadeGain() == 0.75_a );
|
||||||
midiState.ccEvent(0, 24, 24); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 1.0_a );
|
midiState.ccEvent(0, 24, 24); REQUIRE( region.getCrossfadeGain() == 1.0_a );
|
||||||
midiState.ccEvent(0, 24, 25); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 1.0_a );
|
midiState.ccEvent(0, 24, 25); REQUIRE( region.getCrossfadeGain() == 1.0_a );
|
||||||
}
|
}
|
||||||
TEST_CASE("[Region] Crossfade out on CC")
|
TEST_CASE("[Region] Crossfade out on CC")
|
||||||
{
|
{
|
||||||
|
|
@ -200,13 +200,13 @@ TEST_CASE("[Region] Crossfade out on CC")
|
||||||
region.parseOpcode({ "xfout_locc24", "20" });
|
region.parseOpcode({ "xfout_locc24", "20" });
|
||||||
region.parseOpcode({ "xfout_hicc24", "24" });
|
region.parseOpcode({ "xfout_hicc24", "24" });
|
||||||
region.parseOpcode({ "amp_veltrack", "0" });
|
region.parseOpcode({ "amp_veltrack", "0" });
|
||||||
midiState.ccEvent(0, 24, 19); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 1.0_a );
|
midiState.ccEvent(0, 24, 19); REQUIRE( region.getCrossfadeGain() == 1.0_a );
|
||||||
midiState.ccEvent(0, 24, 20); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 1.0_a );
|
midiState.ccEvent(0, 24, 20); REQUIRE( region.getCrossfadeGain() == 1.0_a );
|
||||||
midiState.ccEvent(0, 24, 21); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.86603_a );
|
midiState.ccEvent(0, 24, 21); REQUIRE( region.getCrossfadeGain() == 0.86603_a );
|
||||||
midiState.ccEvent(0, 24, 22); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.70711_a );
|
midiState.ccEvent(0, 24, 22); REQUIRE( region.getCrossfadeGain() == 0.70711_a );
|
||||||
midiState.ccEvent(0, 24, 23); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.5_a );
|
midiState.ccEvent(0, 24, 23); REQUIRE( region.getCrossfadeGain() == 0.5_a );
|
||||||
midiState.ccEvent(0, 24, 24); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.0_a );
|
midiState.ccEvent(0, 24, 24); REQUIRE( region.getCrossfadeGain() == 0.0_a );
|
||||||
midiState.ccEvent(0, 24, 25); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.0_a );
|
midiState.ccEvent(0, 24, 25); REQUIRE( region.getCrossfadeGain() == 0.0_a );
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("[Region] Crossfade out on CC - gain")
|
TEST_CASE("[Region] Crossfade out on CC - gain")
|
||||||
|
|
@ -218,13 +218,13 @@ TEST_CASE("[Region] Crossfade out on CC - gain")
|
||||||
region.parseOpcode({ "xfout_hicc24", "24" });
|
region.parseOpcode({ "xfout_hicc24", "24" });
|
||||||
region.parseOpcode({ "amp_veltrack", "0" });
|
region.parseOpcode({ "amp_veltrack", "0" });
|
||||||
region.parseOpcode({ "xf_cccurve", "gain" });
|
region.parseOpcode({ "xf_cccurve", "gain" });
|
||||||
midiState.ccEvent(0, 24, 19); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 1.0_a );
|
midiState.ccEvent(0, 24, 19); REQUIRE( region.getCrossfadeGain() == 1.0_a );
|
||||||
midiState.ccEvent(0, 24, 20); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 1.0_a );
|
midiState.ccEvent(0, 24, 20); REQUIRE( region.getCrossfadeGain() == 1.0_a );
|
||||||
midiState.ccEvent(0, 24, 21); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.75_a );
|
midiState.ccEvent(0, 24, 21); REQUIRE( region.getCrossfadeGain() == 0.75_a );
|
||||||
midiState.ccEvent(0, 24, 22); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.5_a );
|
midiState.ccEvent(0, 24, 22); REQUIRE( region.getCrossfadeGain() == 0.5_a );
|
||||||
midiState.ccEvent(0, 24, 23); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.25_a );
|
midiState.ccEvent(0, 24, 23); REQUIRE( region.getCrossfadeGain() == 0.25_a );
|
||||||
midiState.ccEvent(0, 24, 24); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.0_a );
|
midiState.ccEvent(0, 24, 24); REQUIRE( region.getCrossfadeGain() == 0.0_a );
|
||||||
midiState.ccEvent(0, 24, 25); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.0_a );
|
midiState.ccEvent(0, 24, 25); REQUIRE( region.getCrossfadeGain() == 0.0_a );
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("[Region] Velocity bug for extreme values - veltrack at 0")
|
TEST_CASE("[Region] Velocity bug for extreme values - veltrack at 0")
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue