Skip to content

Commit

Permalink
Move the stateful region value computations in a separate file
Browse files Browse the repository at this point in the history
  • Loading branch information
paulfd committed Jul 4, 2021
1 parent 5527282 commit 66ec8c4
Show file tree
Hide file tree
Showing 10 changed files with 476 additions and 379 deletions.
1 change: 1 addition & 0 deletions common.mk
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ SFIZZ_SOURCES = \
src/sfizz/PowerFollower.cpp \
src/sfizz/Region.cpp \
src/sfizz/RegionSet.cpp \
src/sfizz/RegionStateful.cpp \
src/sfizz/Resources.cpp \
src/sfizz/RTSemaphore.cpp \
src/sfizz/ScopedFTZ.cpp \
Expand Down
1 change: 1 addition & 0 deletions scripts/run_clang_tidy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ clang-tidy \
src/sfizz/Panning.cpp \
src/sfizz/sfizz.cpp \
src/sfizz/Region.cpp \
src/sfizz/RegionStateful.cpp \
src/sfizz/SIMDHelpers.cpp \
src/sfizz/simd/HelpersSSE.cpp \
src/sfizz/simd/HelpersAVX.cpp \
Expand Down
2 changes: 2 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ set(SFIZZ_HEADERS
sfizz/railsback/4-1.h
sfizz/railsback/4-2.h
sfizz/Region.h
sfizz/RegionStateful.h
sfizz/RegionSet.h
sfizz/Resources.h
sfizz/RTSemaphore.h
Expand Down Expand Up @@ -131,6 +132,7 @@ set(SFIZZ_SOURCES
sfizz/AudioReader.cpp
sfizz/FilterPool.cpp
sfizz/EQPool.cpp
sfizz/RegionStateful.cpp
sfizz/Region.cpp
sfizz/Voice.cpp
sfizz/ScopedFTZ.cpp
Expand Down
123 changes: 0 additions & 123 deletions src/sfizz/Region.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,11 @@

#include "Region.h"
#include "Opcode.h"
#include "MidiState.h"
#include "MathHelpers.h"
#include "utility/SwapAndPop.h"
#include "utility/StringViewHelpers.h"
#include "utility/Macros.h"
#include "utility/Debug.h"
#include "ModifierHelpers.h"
#include "modulations/ModId.h"
#include "absl/strings/str_replace.h"
#include "absl/strings/str_cat.h"
Expand Down Expand Up @@ -1739,18 +1737,6 @@ float sfz::Region::getBasePitchVariation(float noteNumber, float velocity) const
return centsFactor(pitchVariationInCents);
}

float sfz::Region::getBaseVolumedB(const MidiState& midiState, int noteNumber) const noexcept
{
fast_real_distribution<float> volumeDistribution { 0.0f, ampRandom };
auto baseVolumedB = volume + volumeDistribution(Random::randomGenerator);
baseVolumedB += globalVolume;
baseVolumedB += masterVolume;
baseVolumedB += groupVolume;
if (trigger == Trigger::release || trigger == Trigger::release_key)
baseVolumedB -= rtDecay * midiState.getNoteDuration(noteNumber);
return baseVolumedB;
}

float sfz::Region::getBaseGain() const noexcept
{
float baseGain = amplitude;
Expand All @@ -1774,115 +1760,6 @@ float sfz::Region::getPhase() const noexcept
return phase;
}

uint64_t sfz::Region::getOffset(const MidiState& midiState) const noexcept
{
std::uniform_int_distribution<int64_t> offsetDistribution { 0, offsetRandom };
uint64_t finalOffset = offset + offsetDistribution(Random::randomGenerator);
for (const auto& mod: offsetCC)
finalOffset += static_cast<uint64_t>(mod.data * midiState.getCCValue(mod.cc));
return Default::offset.bounds.clamp(finalOffset);
}

float sfz::Region::getDelay(const MidiState& midiState) const noexcept
{
fast_real_distribution<float> delayDistribution { 0, delayRandom };
float finalDelay { delay };
finalDelay += delayDistribution(Random::randomGenerator);
for (const auto& mod: delayCC)
finalDelay += mod.data * midiState.getCCValue(mod.cc);

return Default::delay.bounds.clamp(finalDelay);
}

uint32_t sfz::Region::getSampleEnd(MidiState& midiState) const noexcept
{
int64_t end = sampleEnd;
for (const auto& mod: endCC)
end += static_cast<int64_t>(mod.data * midiState.getCCValue(mod.cc));

end = clamp(end, int64_t { 0 }, sampleEnd);
return static_cast<uint32_t>(end);
}

uint32_t sfz::Region::loopStart(MidiState& midiState) const noexcept
{
auto start = loopRange.getStart();
for (const auto& mod: loopStartCC)
start += static_cast<int64_t>(mod.data * midiState.getCCValue(mod.cc));

start = clamp(start, int64_t { 0 }, sampleEnd);
return static_cast<uint32_t>(start);
}

uint32_t sfz::Region::loopEnd(MidiState& midiState) const noexcept
{
auto end = loopRange.getEnd();
for (const auto& mod: loopEndCC)
end += static_cast<int64_t>(mod.data * midiState.getCCValue(mod.cc));

end = clamp(end, int64_t { 0 }, sampleEnd);
return static_cast<uint32_t>(end);
}

float sfz::Region::getNoteGain(int noteNumber, float velocity) const noexcept
{
ASSERT(velocity >= 0.0f && velocity <= 1.0f);

float baseGain { 1.0f };

// Amplitude key tracking
baseGain *= db2mag(ampKeytrack * static_cast<float>(noteNumber - ampKeycenter));

// Crossfades related to the note number
baseGain *= crossfadeIn(crossfadeKeyInRange, noteNumber, crossfadeKeyCurve);
baseGain *= crossfadeOut(crossfadeKeyOutRange, noteNumber, crossfadeKeyCurve);

// Amplitude velocity tracking
baseGain *= velocityCurve(velocity);

// Crossfades related to velocity
baseGain *= crossfadeIn(crossfadeVelInRange, velocity, crossfadeVelCurve);
baseGain *= crossfadeOut(crossfadeVelOutRange, velocity, crossfadeVelCurve);

return baseGain;
}

float sfz::Region::getCrossfadeGain(const MidiState& midiState) const noexcept
{
float gain { 1.0f };

// Crossfades due to CC states
for (const auto& ccData : crossfadeCCInRange) {
const auto ccValue = midiState.getCCValue(ccData.cc);
const auto crossfadeRange = ccData.data;
gain *= crossfadeIn(crossfadeRange, ccValue, crossfadeCCCurve);
}

for (const auto& ccData : crossfadeCCOutRange) {
const auto ccValue = midiState.getCCValue(ccData.cc);
const auto crossfadeRange = ccData.data;
gain *= crossfadeOut(crossfadeRange, ccValue, crossfadeCCCurve);
}

return gain;
}

float sfz::Region::velocityCurve(float velocity) const noexcept
{
ASSERT(velocity >= 0.0f && velocity <= 1.0f);

float gain;
if (velCurve)
gain = velCurve->evalNormalized(velocity);
else
gain = velocity * velocity;

gain = std::fabs(ampVeltrack) * (1.0f - gain);
gain = (ampVeltrack < 0) ? gain : (1.0f - gain);

return gain;
}

void sfz::Region::offsetAllKeys(int offset) noexcept
{
// Offset key range
Expand Down
56 changes: 0 additions & 56 deletions src/sfizz/Region.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,32 +108,6 @@ struct Region {
* @return float
*/
float getBasePitchVariation(float noteNumber, float velocity) const noexcept;
/**
* @brief Get the note-related gain of the region depending on which note has been
* pressed and at which velocity.
*
* @param noteNumber
* @param velocity
* @return float
*/
float getNoteGain(int noteNumber, float velocity) const noexcept;
/**
* @brief Get the additional crossfade gain of the region depending on the
* CC values
*
* @param midiState
* @return float
*/
float getCrossfadeGain(const MidiState& midiState) const noexcept;
/**
* @brief Get the base volume of the region depending on which note has been
* pressed to trigger the region.
*
* @param midiState
* @param noteNumber
* @return float
*/
float getBaseVolumedB(const MidiState& midiState, int noteNumber) const noexcept;
/**
* @brief Get the base gain of the region.
*
Expand All @@ -146,12 +120,6 @@ struct Region {
* @return float
*/
float getPhase() const noexcept;
/**
* @brief Computes the gain value related to the velocity of the note
*
* @return float
*/
float velocityCurve(float velocity) const noexcept;
/**
* @brief Get the detuning in cents for a given bend value between -1 and 1
*
Expand All @@ -160,27 +128,6 @@ struct Region {
*/
float getBendInCents(float bend) const noexcept;

/**
* @brief Get the region offset in samples
*
* @param midiState
* @return uint32_t
*/
uint64_t getOffset(const MidiState& midiState) const noexcept;
/**
* @brief Get the region delay in seconds
*
* @param midiState
* @return float
*/
float getDelay(const MidiState& midiState) const noexcept;
/**
* @brief Get the index of the sample end, either natural end or forced
* loop.
*
* @return uint32_t
*/
uint32_t getSampleEnd(MidiState& midiState) const noexcept;
/**
* @brief Parse a new opcode into the region to fill in the proper parameters.
* This must be called multiple times for each opcode applying to this region.
Expand Down Expand Up @@ -260,9 +207,6 @@ struct Region {

void offsetAllKeys(int offset) noexcept;

uint32_t loopStart(MidiState& midiState) const noexcept;
uint32_t loopEnd(MidiState& midiState) const noexcept;

/**
* @brief Get the gain this region contributes into the input of the Nth
* effect bus
Expand Down
134 changes: 134 additions & 0 deletions src/sfizz/RegionStateful.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// SPDX-License-Identifier: BSD-2-Clause

// This code is part of the sfizz library and is licensed under a BSD 2-clause
// license. You should have receive a LICENSE.md file along with the code.
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz

#include "RegionStateful.h"
#include "ModifierHelpers.h"

namespace sfz {

float getBaseVolumedB(const Region& region, const MidiState& midiState, int noteNumber) noexcept
{
fast_real_distribution<float> volumeDistribution { 0.0f, region.ampRandom };
auto baseVolumedB = region.volume + volumeDistribution(Random::randomGenerator);
baseVolumedB += region.globalVolume;
baseVolumedB += region.masterVolume;
baseVolumedB += region.groupVolume;
if (region.trigger == Trigger::release || region.trigger == Trigger::release_key)
baseVolumedB -= region.rtDecay * midiState.getNoteDuration(noteNumber);
return baseVolumedB;
}


uint64_t getOffset(const Region& region, const MidiState& midiState) noexcept
{
std::uniform_int_distribution<int64_t> offsetDistribution { 0, region.offsetRandom };
uint64_t finalOffset = region.offset + offsetDistribution(Random::randomGenerator);
for (const auto& mod: region.offsetCC)
finalOffset += static_cast<uint64_t>(mod.data * midiState.getCCValue(mod.cc));
return Default::offset.bounds.clamp(finalOffset);
}

float getDelay(const Region& region, const MidiState& midiState) noexcept
{
fast_real_distribution<float> delayDistribution { 0, region.delayRandom };
float finalDelay { region.delay };
finalDelay += delayDistribution(Random::randomGenerator);
for (const auto& mod: region.delayCC)
finalDelay += mod.data * midiState.getCCValue(mod.cc);

return Default::delay.bounds.clamp(finalDelay);
}

uint32_t getSampleEnd(const Region& region, MidiState& midiState) noexcept
{
int64_t end = region.sampleEnd;
for (const auto& mod: region.endCC)
end += static_cast<int64_t>(mod.data * midiState.getCCValue(mod.cc));

end = clamp(end, int64_t { 0 }, region.sampleEnd);
return static_cast<uint32_t>(end);
}

uint32_t loopStart(const Region& region, MidiState& midiState) noexcept
{
auto start = region.loopRange.getStart();
for (const auto& mod: region.loopStartCC)
start += static_cast<int64_t>(mod.data * midiState.getCCValue(mod.cc));

start = clamp(start, int64_t { 0 }, region.sampleEnd);
return static_cast<uint32_t>(start);
}

uint32_t loopEnd(const Region& region, MidiState& midiState) noexcept
{
auto end = region.loopRange.getEnd();
for (const auto& mod: region.loopEndCC)
end += static_cast<int64_t>(mod.data * midiState.getCCValue(mod.cc));

end = clamp(end, int64_t { 0 }, region.sampleEnd);
return static_cast<uint32_t>(end);
}

float getNoteGain(const Region& region, int noteNumber, float velocity, const MidiState& midiState, const CurveSet& curveSet) noexcept
{
ASSERT(velocity >= 0.0f && velocity <= 1.0f);

float baseGain { 1.0f };

// Amplitude key tracking
baseGain *= db2mag(region.ampKeytrack * static_cast<float>(noteNumber - region.ampKeycenter));

// Crossfades related to the note number
baseGain *= crossfadeIn(region.crossfadeKeyInRange, noteNumber, region.crossfadeKeyCurve);
baseGain *= crossfadeOut(region.crossfadeKeyOutRange, noteNumber, region.crossfadeKeyCurve);

// Amplitude velocity tracking
baseGain *= velocityCurve(region, velocity, midiState, curveSet);

// Crossfades related to velocity
baseGain *= crossfadeIn(region.crossfadeVelInRange, velocity, region.crossfadeVelCurve);
baseGain *= crossfadeOut(region.crossfadeVelOutRange, velocity, region.crossfadeVelCurve);

return baseGain;
}

float getCrossfadeGain(const Region& region, const MidiState& midiState) noexcept
{
float gain { 1.0f };

// Crossfades due to CC states
for (const auto& ccData : region.crossfadeCCInRange) {
const auto ccValue = midiState.getCCValue(ccData.cc);
const auto crossfadeRange = ccData.data;
gain *= crossfadeIn(crossfadeRange, ccValue, region.crossfadeCCCurve);
}

for (const auto& ccData : region.crossfadeCCOutRange) {
const auto ccValue = midiState.getCCValue(ccData.cc);
const auto crossfadeRange = ccData.data;
gain *= crossfadeOut(crossfadeRange, ccValue, region.crossfadeCCCurve);
}

return gain;
}

float velocityCurve(const Region& region, float velocity, const MidiState& midiState, const CurveSet& curveSet) noexcept
{
ASSERT(velocity >= 0.0f && velocity <= 1.0f);

float gain;
if (region.velCurve)
gain = region.velCurve->evalNormalized(velocity);
else
gain = velocity * velocity;

gain = std::fabs(region.ampVeltrack) * (1.0f - gain);
gain = (region.ampVeltrack < 0) ? gain : (1.0f - gain);

return gain;
}

}
Loading

0 comments on commit 66ec8c4

Please sign in to comment.