Use float internally in the voices

This commit is contained in:
Paul Fd 2020-03-26 00:12:30 +01:00 committed by Paul Ferrand
parent 601126db0d
commit e7686d233e
7 changed files with 47 additions and 44 deletions

View file

@ -43,7 +43,7 @@ namespace config {
constexpr int allNotesOffCC { 123 }; constexpr int allNotesOffCC { 123 };
constexpr int omniOffCC { 124 }; constexpr int omniOffCC { 124 };
constexpr int omniOnCC { 125 }; constexpr int omniOnCC { 125 };
constexpr int halfCCThreshold { 64 }; constexpr float halfCCThreshold { 0.5f };
constexpr int centPerSemitone { 100 }; constexpr int centPerSemitone { 100 };
constexpr float virtuallyZero { 0.00005f }; constexpr float virtuallyZero { 0.00005f };
constexpr float fastReleaseDuration { 0.01f }; constexpr float fastReleaseDuration { 0.01f };

View file

@ -902,6 +902,7 @@ bool sfz::Region::registerCC(int ccNumber, uint8_t ccValue) noexcept
bool sfz::Region::registerCCNormalized(int ccNumber, float ccValue) noexcept bool sfz::Region::registerCCNormalized(int ccNumber, float ccValue) noexcept
{ {
ASSERT(ccValue >= 0.0f && ccValue <= 1.0f);
if (ccConditions.getWithDefault(ccNumber).containsWithEnd(ccValue)) if (ccConditions.getWithDefault(ccNumber).containsWithEnd(ccValue))
ccSwitched.set(ccNumber, true); ccSwitched.set(ccNumber, true);
else else

View file

@ -523,7 +523,7 @@ void multiplyAdd<float, true>(absl::Span<const float> gain, absl::Span<const flo
template <class T, bool SIMD = SIMDConfig::multiplyAdd> template <class T, bool SIMD = SIMDConfig::multiplyAdd>
void multiplyAdd(const T gain, absl::Span<const T> input, absl::Span<T> output) noexcept void multiplyAdd(const T gain, absl::Span<const T> input, absl::Span<T> output) noexcept
{ {
ASSERT(input.size() <= output.size()); // ASSERT(input.size() <= output.size());
auto* in = input.begin(); auto* in = input.begin();
auto* out = output.begin(); auto* out = output.begin();
auto* sentinel = out + std::min(output.size(), input.size()); auto* sentinel = out + std::min(output.size(), input.size());

View file

@ -600,15 +600,15 @@ void sfz::Synth::noteOn(int delay, int noteNumber, uint8_t velocity) noexcept
{ {
ASSERT(noteNumber < 128); ASSERT(noteNumber < 128);
ASSERT(noteNumber >= 0); ASSERT(noteNumber >= 0);
const auto normalizedVelocity = normalizeVelocity(velocity);
ScopedTiming logger { dispatchDuration, ScopedTiming::Operation::addToDuration }; ScopedTiming logger { dispatchDuration, ScopedTiming::Operation::addToDuration };
resources.midiState.noteOnEvent(delay, noteNumber, velocity); resources.midiState.noteOnEventNormalized(delay, noteNumber, normalizedVelocity);
AtomicGuard callbackGuard { inCallback }; AtomicGuard callbackGuard { inCallback };
if (!canEnterCallback) if (!canEnterCallback)
return; return;
noteOnDispatch(delay, noteNumber, velocity); noteOnDispatch(delay, noteNumber, normalizedVelocity);
} }
void sfz::Synth::noteOff(int delay, int noteNumber, uint8_t velocity) noexcept void sfz::Synth::noteOff(int delay, int noteNumber, uint8_t velocity) noexcept
@ -627,7 +627,7 @@ void sfz::Synth::noteOff(int delay, int noteNumber, uint8_t velocity) noexcept
// FIXME: Some keyboards (e.g. Casio PX5S) can send a real note-off velocity. In this case, do we have a // FIXME: Some keyboards (e.g. Casio PX5S) can send a real note-off velocity. In this case, do we have a
// way in sfz to specify that a release trigger should NOT use the note-on velocity? // way in sfz to specify that a release trigger should NOT use the note-on velocity?
// auto replacedVelocity = (velocity == 0 ? sfz::getNoteVelocity(noteNumber) : velocity); // auto replacedVelocity = (velocity == 0 ? sfz::getNoteVelocity(noteNumber) : velocity);
const auto replacedVelocity = resources.midiState.getNoteVelocity(noteNumber); const auto replacedVelocity = resources.midiState.getNoteVelocityNormalized(noteNumber);
for (auto& voice : voices) for (auto& voice : voices)
voice->registerNoteOff(delay, noteNumber, replacedVelocity); voice->registerNoteOff(delay, noteNumber, replacedVelocity);
@ -635,11 +635,11 @@ void sfz::Synth::noteOff(int delay, int noteNumber, uint8_t velocity) noexcept
noteOffDispatch(delay, noteNumber, replacedVelocity); noteOffDispatch(delay, noteNumber, replacedVelocity);
} }
void sfz::Synth::noteOffDispatch(int delay, int noteNumber, uint8_t velocity) noexcept void sfz::Synth::noteOffDispatch(int delay, int noteNumber, float velocity) noexcept
{ {
const auto randValue = randNoteDistribution(Random::randomGenerator); const auto randValue = randNoteDistribution(Random::randomGenerator);
for (auto& region : noteActivationLists[noteNumber]) { for (auto& region : noteActivationLists[noteNumber]) {
if (region->registerNoteOff(noteNumber, velocity, randValue)) { if (region->registerNoteOffNormalized(noteNumber, velocity, randValue)) {
auto voice = findFreeVoice(); auto voice = findFreeVoice();
if (voice == nullptr) if (voice == nullptr)
continue; continue;
@ -649,11 +649,11 @@ void sfz::Synth::noteOffDispatch(int delay, int noteNumber, uint8_t velocity) no
} }
} }
void sfz::Synth::noteOnDispatch(int delay, int noteNumber, uint8_t velocity) noexcept void sfz::Synth::noteOnDispatch(int delay, int noteNumber, float velocity) noexcept
{ {
const auto randValue = randNoteDistribution(Random::randomGenerator); const auto randValue = randNoteDistribution(Random::randomGenerator);
for (auto& region : noteActivationLists[noteNumber]) { for (auto& region : noteActivationLists[noteNumber]) {
if (region->registerNoteOn(noteNumber, velocity, randValue)) { if (region->registerNoteOnNormalized(noteNumber, velocity, randValue)) {
for (auto& voice : voices) { for (auto& voice : voices) {
if (voice->checkOffGroup(delay, region->group)) if (voice->checkOffGroup(delay, region->group))
noteOffDispatch(delay, voice->getTriggerNumber(), voice->getTriggerValue()); noteOffDispatch(delay, voice->getTriggerNumber(), voice->getTriggerValue());
@ -672,9 +672,10 @@ void sfz::Synth::cc(int delay, int ccNumber, uint8_t ccValue) noexcept
{ {
ASSERT(ccNumber < config::numCCs); ASSERT(ccNumber < config::numCCs);
ASSERT(ccNumber >= 0); ASSERT(ccNumber >= 0);
const auto normalizedCC = normalizeCC(ccValue);
ScopedTiming logger { dispatchDuration, ScopedTiming::Operation::addToDuration }; ScopedTiming logger { dispatchDuration, ScopedTiming::Operation::addToDuration };
resources.midiState.ccEvent(delay, ccNumber, ccValue); resources.midiState.ccEventNormalized(delay, ccNumber, normalizedCC);
AtomicGuard callbackGuard { inCallback }; AtomicGuard callbackGuard { inCallback };
if (!canEnterCallback) if (!canEnterCallback)
@ -686,7 +687,7 @@ void sfz::Synth::cc(int delay, int ccNumber, uint8_t ccValue) noexcept
} }
for (auto& voice : voices) for (auto& voice : voices)
voice->registerCC(delay, ccNumber, ccValue); voice->registerCC(delay, ccNumber, normalizedCC);
for (auto& region : ccActivationLists[ccNumber]) { for (auto& region : ccActivationLists[ccNumber]) {
if (region->registerCC(ccNumber, ccValue)) { if (region->registerCC(ccNumber, ccValue)) {
@ -694,7 +695,7 @@ void sfz::Synth::cc(int delay, int ccNumber, uint8_t ccValue) noexcept
if (voice == nullptr) if (voice == nullptr)
continue; continue;
voice->startVoice(region, delay, ccNumber, ccValue, Voice::TriggerType::CC); voice->startVoice(region, delay, ccNumber, normalizedCC, Voice::TriggerType::CC);
} }
} }
} }
@ -952,12 +953,12 @@ void sfz::Synth::resetAllControllers(int delay) noexcept
for (auto& voice : voices) { for (auto& voice : voices) {
voice->registerPitchWheel(delay, 0); voice->registerPitchWheel(delay, 0);
for (unsigned cc = 0; cc < config::numCCs; ++cc) for (unsigned cc = 0; cc < config::numCCs; ++cc)
voice->registerCC(delay, cc, 0); voice->registerCC(delay, cc, 0.0f);
} }
for (auto& region : regions) { for (auto& region : regions) {
for (unsigned cc = 0; cc < config::numCCs; ++cc) for (unsigned cc = 0; cc < config::numCCs; ++cc)
region->registerCC(cc, 0); region->registerCCNormalized(cc, 0.0f);
} }
} }

View file

@ -463,8 +463,8 @@ private:
fs::file_time_type checkModificationTime(); fs::file_time_type checkModificationTime();
void noteOnDispatch(int delay, int noteNumber, uint8_t velocity) noexcept; void noteOnDispatch(int delay, int noteNumber, float velocity) noexcept;
void noteOffDispatch(int delay, int noteNumber, uint8_t velocity) noexcept; void noteOffDispatch(int delay, int noteNumber, float velocity) noexcept;
// Opcode memory; these are used to build regions, as a new region // Opcode memory; these are used to build regions, as a new region
// will integrate opcodes from the group, master and global block // will integrate opcodes from the group, master and global block

View file

@ -24,8 +24,10 @@ sfz::Voice::Voice(sfz::Resources& resources)
waveOscillator.init(sampleRate); waveOscillator.init(sampleRate);
} }
void sfz::Voice::startVoice(Region* region, int delay, int number, uint8_t value, sfz::Voice::TriggerType triggerType) noexcept void sfz::Voice::startVoice(Region* region, int delay, int number, float value, sfz::Voice::TriggerType triggerType) noexcept
{ {
ASSERT(value >= 0.0f && value <= 1.0f);
this->triggerType = triggerType; this->triggerType = triggerType;
triggerNumber = number; triggerNumber = number;
triggerValue = value; triggerValue = value;
@ -71,22 +73,21 @@ void sfz::Voice::startVoice(Region* region, int delay, int number, uint8_t value
} }
speedRatio = static_cast<float>(currentPromise->sampleRate / this->sampleRate); speedRatio = static_cast<float>(currentPromise->sampleRate / this->sampleRate);
} }
pitchRatio = region->getBasePitchVariationNormalized(number, value);
pitchRatio = region->getBasePitchVariation(number, 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->cc)) * region->volumeCC->value; volumedB += resources.midiState.getCCValueNormalized(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();
if (triggerType != TriggerType::CC) if (triggerType != TriggerType::CC)
baseGain *= region->getNoteGain(number, value); baseGain *= region->getNoteGainNormalized(number, value);
float gain { baseGain }; float gain { baseGain };
if (region->amplitudeCC) if (region->amplitudeCC)
gain += normalizeCC(resources.midiState.getCCValue(region->amplitudeCC->cc)) * normalizePercents(region->amplitudeCC->value); gain += resources.midiState.getCCValueNormalized(region->amplitudeCC->cc) * normalizePercents(region->amplitudeCC->value);
amplitudeEnvelope.reset(Default::normalizedRange.clamp(gain)); amplitudeEnvelope.reset(Default::normalizedRange.clamp(gain));
float crossfadeGain { region->getCrossfadeGain() }; float crossfadeGain { region->getCrossfadeGain() };
@ -95,19 +96,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->cc)) * normalizePercents(region->panCC->value); pan += resources.midiState.getCCValueNormalized(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->cc)) * normalizePercents(region->positionCC->value); position += resources.midiState.getCCValueNormalized(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->cc)) * normalizePercents(region->widthCC->value); width += resources.midiState.getCCValueNormalized(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){
@ -123,13 +124,13 @@ void sfz::Voice::startVoice(Region* region, int delay, int number, uint8_t value
const unsigned numChannels = region->isStereo ? 2 : 1; const unsigned numChannels = region->isStereo ? 2 : 1;
for (auto& filter: region->filters) { for (auto& filter: region->filters) {
auto newFilter = resources.filterPool.getFilter(filter, numChannels, number, value); auto newFilter = resources.filterPool.getFilter(filter, numChannels, number, denormalize7Bits<uint8_t>(value));
if (newFilter) if (newFilter)
filters.push_back(newFilter); filters.push_back(newFilter);
} }
for (auto& eq: region->equalizers) { for (auto& eq: region->equalizers) {
auto newEQ = resources.eqPool.getEQ(eq, numChannels, value); auto newEQ = resources.eqPool.getEQ(eq, numChannels, denormalize7Bits<uint8_t>(value));
if (newEQ) if (newEQ)
equalizers.push_back(newEQ); equalizers.push_back(newEQ);
} }
@ -139,7 +140,7 @@ void sfz::Voice::startVoice(Region* region, int delay, int number, uint8_t value
initialDelay = delay + static_cast<int>(region->getDelay() * sampleRate); initialDelay = delay + static_cast<int>(region->getDelay() * sampleRate);
baseFrequency = midiNoteFrequency(number); baseFrequency = midiNoteFrequency(number);
bendStepFactor = centsFactor(region->bendStep); bendStepFactor = centsFactor(region->bendStep);
egEnvelope.reset(*region, resources.midiState, delay, value, sampleRate); egEnvelope.reset(*region, resources.midiState, delay, denormalize7Bits<uint8_t>(value), sampleRate);
} }
bool sfz::Voice::isFree() const noexcept bool sfz::Voice::isFree() const noexcept
@ -159,7 +160,7 @@ void sfz::Voice::release(int delay, bool fastRelease) noexcept
} }
} }
void sfz::Voice::registerNoteOff(int delay, int noteNumber, uint8_t velocity) noexcept void sfz::Voice::registerNoteOff(int delay, int noteNumber, float velocity) noexcept
{ {
UNUSED(velocity); UNUSED(velocity);
if (region == nullptr) if (region == nullptr)
@ -174,12 +175,12 @@ void sfz::Voice::registerNoteOff(int delay, int noteNumber, uint8_t velocity) no
if (region->loopMode == SfzLoopMode::one_shot) if (region->loopMode == SfzLoopMode::one_shot)
return; return;
if (!region->checkSustain || resources.midiState.getCCValue(config::sustainCC) < config::halfCCThreshold) if (!region->checkSustain || resources.midiState.getCCValueNormalized(config::sustainCC) < config::halfCCThreshold)
release(delay); release(delay);
} }
} }
void sfz::Voice::registerCC(int delay, int ccNumber, uint8_t ccValue) noexcept void sfz::Voice::registerCC(int delay, int ccNumber, float ccValue) noexcept
{ {
if (region == nullptr) if (region == nullptr)
return; return;
@ -200,27 +201,27 @@ void sfz::Voice::registerCC(int delay, int ccNumber, uint8_t ccValue) noexcept
delay = max(delay, minEnvelopeDelay); delay = max(delay, minEnvelopeDelay);
if (region->amplitudeCC && ccNumber == region->amplitudeCC->cc) { if (region->amplitudeCC && ccNumber == region->amplitudeCC->cc) {
const float newGain { baseGain + normalizeCC(ccValue) * normalizePercents(region->amplitudeCC->value) }; const float newGain { baseGain + 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->cc) { if (region->volumeCC && ccNumber == region->volumeCC->cc) {
const float newVolumedB { baseVolumedB + normalizeCC(ccValue) * region->volumeCC->value }; const float newVolumedB { baseVolumedB + 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->cc) { if (region->panCC && ccNumber == region->panCC->cc) {
const float newPan { basePan + normalizeCC(ccValue) * normalizePercents(region->panCC->value) }; const float newPan { basePan + 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->cc) { if (region->positionCC && ccNumber == region->positionCC->cc) {
const float newPosition { basePosition + normalizeCC(ccValue) * normalizePercents(region->positionCC->value) }; const float newPosition { basePosition + 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->cc) { if (region->widthCC && ccNumber == region->widthCC->cc) {
const float newWidth { baseWidth + normalizeCC(ccValue) * normalizePercents(region->widthCC->value) }; const float newWidth { baseWidth + ccValue * normalizePercents(region->widthCC->value) };
widthEnvelope.registerEvent(delay, Default::symmetricNormalizedRange.clamp(newWidth)); widthEnvelope.registerEvent(delay, Default::symmetricNormalizedRange.clamp(newWidth));
} }
@ -552,7 +553,7 @@ int sfz::Voice::getTriggerNumber() const noexcept
return triggerNumber; return triggerNumber;
} }
uint8_t sfz::Voice::getTriggerValue() const noexcept float sfz::Voice::getTriggerValue() const noexcept
{ {
return triggerValue; return triggerValue;
} }

View file

@ -81,7 +81,7 @@ public:
* @param value * @param value
* @param triggerType * @param triggerType
*/ */
void startVoice(Region* region, int delay, int number, uint8_t value, TriggerType triggerType) noexcept; void startVoice(Region* region, int delay, int number, float value, TriggerType triggerType) noexcept;
/** /**
* @brief Register a note-off event; this may trigger a release. * @brief Register a note-off event; this may trigger a release.
@ -90,7 +90,7 @@ public:
* @param noteNumber * @param noteNumber
* @param velocity * @param velocity
*/ */
void registerNoteOff(int delay, int noteNumber, uint8_t velocity) noexcept; void registerNoteOff(int delay, int noteNumber, float velocity) noexcept;
/** /**
* @brief Register a CC event; this may trigger a release. If the voice is playing and its * @brief Register a CC event; this may trigger a release. If the voice is playing and its
* region has CC modifiers, it will use this value to compute the CC envelope to apply to the * region has CC modifiers, it will use this value to compute the CC envelope to apply to the
@ -100,7 +100,7 @@ public:
* @param ccNumber * @param ccNumber
* @param ccValue * @param ccValue
*/ */
void registerCC(int delay, int ccNumber, uint8_t ccValue) noexcept; void registerCC(int delay, int ccNumber, float ccValue) noexcept;
/** /**
* @brief Register a pitch wheel event; for now this does nothing * @brief Register a pitch wheel event; for now this does nothing
* *
@ -163,9 +163,9 @@ public:
/** /**
* @brief Get the value that triggered the voice (note velocity or cc value) * @brief Get the value that triggered the voice (note velocity or cc value)
* *
* @return uint8_t * @return float
*/ */
uint8_t getTriggerValue() const noexcept; float getTriggerValue() const noexcept;
/** /**
* @brief Get the type of trigger * @brief Get the type of trigger
* *
@ -261,7 +261,7 @@ private:
TriggerType triggerType; TriggerType triggerType;
int triggerNumber; int triggerNumber;
uint8_t triggerValue; float triggerValue;
absl::optional<int> triggerDelay; absl::optional<int> triggerDelay;
float speedRatio { 1.0 }; float speedRatio { 1.0 };