Move the modifiers in the midistate
This commit is contained in:
parent
507ddc8e01
commit
3ceee27c0a
6 changed files with 125 additions and 269 deletions
|
|
@ -28,9 +28,12 @@ void sfz::EQHolder::setup(const EQDescription& description, unsigned numChannels
|
|||
baseGain = description.gain + velocity * description.vel2gain;
|
||||
|
||||
// Setup the modulated values
|
||||
lastFrequency = midiState.modulate(baseFrequency, description.frequencyCC, Default::eqFrequencyRange);
|
||||
lastBandwidth = midiState.modulate(baseBandwidth, description.bandwidthCC, Default::eqBandwidthRange);
|
||||
lastGain = midiState.modulate(baseGain, description.gainCC, Default::eqGainRange);
|
||||
lastFrequency = baseFrequency + midiState.fastAdditiveModifiers(description.frequencyCC);
|
||||
lastFrequency = Default::eqFrequencyRange.clamp(lastFrequency);
|
||||
lastBandwidth = baseBandwidth + midiState.fastAdditiveModifiers(description.bandwidthCC);
|
||||
lastBandwidth = Default::eqBandwidthRange.clamp(lastBandwidth);
|
||||
lastGain = baseGain + midiState.fastAdditiveModifiers(description.gainCC);
|
||||
lastGain = Default::eqGainRange.clamp(lastGain);
|
||||
|
||||
// Initialize the EQ
|
||||
eq.prepare(lastFrequency, lastBandwidth, lastGain);
|
||||
|
|
@ -50,9 +53,12 @@ void sfz::EQHolder::process(const float** inputs, float** outputs, unsigned numF
|
|||
|
||||
// TODO: Once the midistate envelopes are done, add modulation in there!
|
||||
// For now we take the last value
|
||||
lastFrequency = midiState.modulate(baseFrequency, description->frequencyCC, Default::eqFrequencyRange);
|
||||
lastBandwidth = midiState.modulate(baseBandwidth, description->bandwidthCC, Default::eqBandwidthRange);
|
||||
lastGain = midiState.modulate(baseGain, description->gainCC, Default::eqGainRange);
|
||||
lastFrequency = baseFrequency + midiState.fastAdditiveModifiers(description->frequencyCC);
|
||||
lastFrequency = Default::eqFrequencyRange.clamp(lastFrequency);
|
||||
lastBandwidth = baseBandwidth + midiState.fastAdditiveModifiers(description->bandwidthCC);
|
||||
lastBandwidth = Default::eqBandwidthRange.clamp(lastBandwidth);
|
||||
lastGain = baseGain + midiState.fastAdditiveModifiers(description->gainCC);
|
||||
lastGain = Default::eqGainRange.clamp(lastGain);
|
||||
|
||||
if (lastGain == 0.0f) {
|
||||
justCopy();
|
||||
|
|
|
|||
|
|
@ -40,9 +40,12 @@ void sfz::FilterHolder::setup(const FilterDescription& description, unsigned num
|
|||
baseResonance = description.resonance;
|
||||
|
||||
// Setup the modulated values
|
||||
lastCutoff = midiState.modulate<float, int>(baseCutoff, description.cutoffCC, Default::filterCutoffRange, multiplyByCents);
|
||||
lastResonance = midiState.modulate(baseResonance, description.resonanceCC, Default::filterResonanceRange);
|
||||
lastGain = midiState.modulate(baseGain, description.gainCC, Default::filterGainRange);
|
||||
lastCutoff = baseCutoff * midiState.fastMultiplicativeModifiers(description.cutoffCC, multiplyByCentsModifier);
|
||||
lastCutoff = Default::filterCutoffRange.clamp(lastCutoff);
|
||||
lastResonance = baseResonance + midiState.fastAdditiveModifiers(description.resonanceCC);
|
||||
lastResonance = Default::filterResonanceRange.clamp(lastResonance);
|
||||
lastGain = baseGain + midiState.fastAdditiveModifiers(description.gainCC);
|
||||
lastGain = Default::filterGainRange.clamp(lastGain);
|
||||
|
||||
// Initialize the filter
|
||||
filter.prepare(lastCutoff, lastResonance, lastGain);
|
||||
|
|
@ -59,9 +62,14 @@ void sfz::FilterHolder::process(const float** inputs, float** outputs, unsigned
|
|||
// TODO: Once the midistate envelopes are done, add modulation in there!
|
||||
// For now we take the last value
|
||||
// TODO: the template deduction could be automatic here?
|
||||
lastCutoff = midiState.modulate<float, int>(baseCutoff, description->cutoffCC, Default::filterCutoffRange, multiplyByCents);
|
||||
lastResonance = midiState.modulate(baseResonance, description->resonanceCC, Default::filterResonanceRange);
|
||||
baseGain = midiState.modulate(baseGain, description->gainCC, Default::filterGainRange);
|
||||
lastCutoff = baseCutoff * midiState.fastMultiplicativeModifiers(description->cutoffCC, [](const int& modifier, float value) -> float {
|
||||
return value * centsFactor(modifier);
|
||||
});
|
||||
lastCutoff = Default::filterCutoffRange.clamp(lastCutoff);
|
||||
lastResonance = baseResonance + midiState.fastAdditiveModifiers(description->resonanceCC);
|
||||
lastResonance = Default::filterResonanceRange.clamp(lastResonance);
|
||||
lastGain = baseGain + midiState.fastAdditiveModifiers(description->gainCC);
|
||||
lastGain = Default::filterGainRange.clamp(lastGain);
|
||||
|
||||
filter.process(inputs, outputs, lastCutoff, lastResonance, lastGain, numFrames);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@
|
|||
#include <array>
|
||||
#include "CCMap.h"
|
||||
#include "Range.h"
|
||||
#include "absl/types/span.h"
|
||||
#include "SIMDHelpers.h"
|
||||
|
||||
namespace sfz
|
||||
{
|
||||
|
|
@ -132,18 +134,68 @@ public:
|
|||
* @param lambda the function to apply for each modifier
|
||||
* @return T
|
||||
*/
|
||||
template<class T, class U>
|
||||
T modulate(T value, const CCMap<U>& modifiers, const Range<T>& validRange, const modFunction<T, U>& lambda = addToBase<T>) const noexcept
|
||||
template<class T, class F = decltype(gainModifier<T>)>
|
||||
float fastAdditiveModifiers(const CCMap<T>& modifiers, F&& lambda = gainModifier<T>) const noexcept
|
||||
{
|
||||
float returnedValue { 0.0f };
|
||||
for (auto& mod: modifiers) {
|
||||
lambda(value, getCCValue(mod.cc) * mod.value);
|
||||
returnedValue += lambda(getCCValue(mod.cc), mod.value);
|
||||
}
|
||||
return validRange.clamp(value);
|
||||
return returnedValue;
|
||||
}
|
||||
|
||||
template<class T, class F = decltype(gainModifier<T>)>
|
||||
float fastMultiplicativeModifiers(const CCMap<T>& modifiers, F&& lambda = gainModifier<T>) const noexcept
|
||||
{
|
||||
float returnedValue { 1.0f };
|
||||
for (auto& mod: modifiers) {
|
||||
returnedValue *= lambda(getCCValue(mod.cc), mod.value);
|
||||
}
|
||||
return returnedValue;
|
||||
}
|
||||
|
||||
template<class T, class F = decltype(gainModifier<T>)>
|
||||
void additiveModifiers(const CCMap<T>& modifiers, absl::Span<float> output, absl::Span<float> temp, F&& lambda = gainModifier<T>)
|
||||
{
|
||||
fill<float>(output, 0.0f);
|
||||
for (auto& mod : modifiers) {
|
||||
linearEnvelope(mod, temp, lambda);
|
||||
add<float>(temp, output);
|
||||
}
|
||||
}
|
||||
|
||||
template<class T, class F = decltype(gainModifier<T>)>
|
||||
void multiplicativeModifiers(const CCMap<T>& modifiers, absl::Span<float> output, absl::Span<float> temp, F&& lambda = gainModifier<T>)
|
||||
{
|
||||
for (auto& mod : modifiers) {
|
||||
linearEnvelope(mod, temp, lambda);
|
||||
applyGain<float>(temp, output);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const EventVector& getEvents(int ccIdx) const noexcept;
|
||||
|
||||
private:
|
||||
|
||||
template<class T, class F>
|
||||
void linearEnvelope(T&& modifier, absl::Span<float> envelope, F&& lambda) const
|
||||
{
|
||||
const auto eventList = getEvents(modifier.cc);
|
||||
ASSERT(eventList.size() > 0);
|
||||
ASSERT(eventList[0].delay == 0);
|
||||
|
||||
auto lastValue = lambda(modifier.value, eventList[0].value);
|
||||
auto lastDelay = eventList[0].delay;
|
||||
for (unsigned i = 1; i < eventList.size(); ++ i) {
|
||||
const auto event = eventList[i];
|
||||
const auto length = event.delay - lastDelay;
|
||||
const auto step = (lambda(modifier.value, event.value) - lastValue)/ length;
|
||||
lastValue = linearRamp<float>(envelope.subspan(lastDelay, length), lastValue, step);
|
||||
lastDelay += length;
|
||||
}
|
||||
fill<float>(envelope.subspan(lastDelay), lastValue);
|
||||
}
|
||||
int activeNotes { 0 };
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -274,26 +274,6 @@ bool findDefine(absl::string_view line, absl::string_view& variable, absl::strin
|
|||
*/
|
||||
bool findInclude(absl::string_view line, std::string& path);
|
||||
|
||||
/**
|
||||
* @brief Defines a function that modulates a base value with another one
|
||||
*
|
||||
* @tparam T
|
||||
*/
|
||||
template<class T, class U>
|
||||
using modFunction = std::function<void(T&, U)>;
|
||||
|
||||
/**
|
||||
* @brief Modulation helper that adds the modifier to the base value
|
||||
*
|
||||
* @tparam T
|
||||
* @param base the base value
|
||||
* @param modifier the modifier value
|
||||
*/
|
||||
template<class T>
|
||||
inline CXX14_CONSTEXPR void addToBase(T& base, T modifier)
|
||||
{
|
||||
base += modifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief multiply a value by a factor, in cents. To be used for pitch variations.
|
||||
|
|
@ -301,9 +281,15 @@ inline CXX14_CONSTEXPR void addToBase(T& base, T modifier)
|
|||
* @param base
|
||||
* @param modifier
|
||||
*/
|
||||
inline CXX14_CONSTEXPR void multiplyByCents(float& base, int modifier)
|
||||
inline CXX14_CONSTEXPR float multiplyByCentsModifier(int modifier, float base)
|
||||
{
|
||||
base *= centsFactor(modifier);
|
||||
return base * centsFactor(modifier);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline CXX14_CONSTEXPR float gainModifier(T modifier, float value)
|
||||
{
|
||||
return value * modifier;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -252,221 +252,6 @@ void sfz::Voice::renderBlock(AudioSpan<float> buffer) noexcept
|
|||
this->triggerDelay = absl::nullopt;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void getLinearEnvelope(const sfz::CCMap<T>& ccMods, const sfz::MidiState& state, absl::Span<float> output, absl::Span<float> temp, std::function<float(const T&, float)> function)
|
||||
{
|
||||
for (auto& mod : ccMods) {
|
||||
const auto eventList = state.getEvents(mod.cc);
|
||||
ASSERT(eventList.size() > 0);
|
||||
ASSERT(eventList[0].delay == 0);
|
||||
|
||||
auto lastValue = function(mod.value, eventList[0].value);
|
||||
auto lastDelay = eventList[0].delay;
|
||||
for (unsigned i = 1; i < eventList.size(); ++ i) {
|
||||
const auto event = eventList[i];
|
||||
const auto length = event.delay - lastDelay;
|
||||
const auto step = (function(mod.value, event.value) - lastValue)/ length;
|
||||
lastValue = sfz::linearRamp<float>(temp.subspan(lastDelay, length), lastValue, step);
|
||||
lastDelay += length;
|
||||
}
|
||||
sfz::fill<float>(temp.subspan(lastDelay), lastValue);
|
||||
sfz::applyGain<float>(temp, output);
|
||||
}
|
||||
}
|
||||
|
||||
void sfz::Voice::amplitudeModulation(absl::Span<float> modulationSpan) noexcept
|
||||
{
|
||||
fill<float>(modulationSpan, 1.0f);
|
||||
if (!region)
|
||||
return;
|
||||
|
||||
const auto numSamples = modulationSpan.size();
|
||||
auto tempBuffer = resources.bufferPool.getBuffer(numSamples);
|
||||
if (!tempBuffer)
|
||||
return;
|
||||
auto tempSpan = absl::MakeSpan(*tempBuffer).first(numSamples);
|
||||
|
||||
for (auto& mod : region->amplitudeCC) {
|
||||
const auto eventList = resources.midiState.getEvents(mod.cc);
|
||||
ASSERT(eventList.size() > 0);
|
||||
ASSERT(eventList[0].delay == 0);
|
||||
|
||||
auto lastValue = mod.value * eventList[0].value;
|
||||
auto lastDelay = eventList[0].delay;
|
||||
for (unsigned i = 1; i < eventList.size(); ++ i) {
|
||||
const auto event = eventList[i];
|
||||
const auto length = event.delay - lastDelay;
|
||||
const auto step = (Default::amplitudeRange.clamp(mod.value * event.value) - lastValue)/ length;
|
||||
lastValue = linearRamp<float>(tempSpan.subspan(lastDelay, length), lastValue, step);
|
||||
lastDelay += length;
|
||||
}
|
||||
fill<float>(tempSpan.subspan(lastDelay), lastValue);
|
||||
applyGain<float>(tempSpan, modulationSpan);
|
||||
}
|
||||
applyGain<float>(baseGain, modulationSpan);
|
||||
}
|
||||
|
||||
void sfz::Voice::crossfadeModulation(absl::Span<float> modulationSpan) noexcept
|
||||
{
|
||||
fill<float>(modulationSpan, 1.0f);
|
||||
if (!region)
|
||||
return;
|
||||
|
||||
const auto numSamples = modulationSpan.size();
|
||||
auto tempBuffer = resources.bufferPool.getBuffer(numSamples);
|
||||
if (!tempBuffer)
|
||||
return;
|
||||
auto tempSpan = absl::MakeSpan(*tempBuffer).first(numSamples);
|
||||
|
||||
for (auto& mod : region->crossfadeCCInRange) {
|
||||
const auto eventList = resources.midiState.getEvents(mod.cc);
|
||||
ASSERT(eventList.size() > 0);
|
||||
ASSERT(eventList[0].delay == 0);
|
||||
|
||||
auto lastValue = crossfadeIn(mod.value, eventList[0].value, region->crossfadeCCCurve);
|
||||
auto lastDelay = eventList[0].delay;
|
||||
for (unsigned i = 1; i < eventList.size(); ++ i) {
|
||||
const auto event = eventList[i];
|
||||
const auto length = event.delay - lastDelay;
|
||||
const auto step = (crossfadeIn(mod.value, event.value, region->crossfadeCCCurve) - lastValue)/ length;
|
||||
lastValue = linearRamp<float>(tempSpan.subspan(lastDelay, length), lastValue, step);
|
||||
lastDelay += length;
|
||||
}
|
||||
fill<float>(tempSpan.subspan(lastDelay), lastValue);
|
||||
applyGain<float>(tempSpan, modulationSpan);
|
||||
}
|
||||
|
||||
for (auto& mod : region->crossfadeCCOutRange) {
|
||||
const auto eventList = resources.midiState.getEvents(mod.cc);
|
||||
ASSERT(eventList.size() > 0);
|
||||
ASSERT(eventList[0].delay == 0);
|
||||
|
||||
auto lastValue = crossfadeOut(mod.value, eventList[0].value, region->crossfadeCCCurve);
|
||||
auto lastDelay = eventList[0].delay;
|
||||
for (unsigned i = 1; i < eventList.size(); ++ i) {
|
||||
const auto event = eventList[i];
|
||||
const auto length = event.delay - lastDelay;
|
||||
const auto step = (crossfadeOut(mod.value, event.value, region->crossfadeCCCurve) - lastValue)/ length;
|
||||
lastValue = linearRamp<float>(tempSpan.subspan(lastDelay, length), lastValue, step);
|
||||
lastDelay += length;
|
||||
}
|
||||
fill<float>(tempSpan.subspan(lastDelay), lastValue);
|
||||
applyGain<float>(tempSpan, modulationSpan);
|
||||
}
|
||||
}
|
||||
|
||||
void sfz::Voice::panningModulation(absl::Span<float> modulationSpan) noexcept
|
||||
{
|
||||
if (!region)
|
||||
return;
|
||||
|
||||
if (region->panCC.empty()) {
|
||||
fill<float>(modulationSpan, region->pan);
|
||||
return;
|
||||
}
|
||||
|
||||
fill<float>(modulationSpan, 1.0f);
|
||||
const auto numSamples = modulationSpan.size();
|
||||
auto tempBuffer = resources.bufferPool.getBuffer(numSamples);
|
||||
if (!tempBuffer)
|
||||
return;
|
||||
auto tempSpan = absl::MakeSpan(*tempBuffer).first(numSamples);
|
||||
|
||||
for (auto& mod : region->panCC) {
|
||||
const auto eventList = resources.midiState.getEvents(mod.cc);
|
||||
ASSERT(eventList.size() > 0);
|
||||
ASSERT(eventList[0].delay == 0);
|
||||
|
||||
auto lastValue = mod.value * eventList[0].value;
|
||||
auto lastDelay = eventList[0].delay;
|
||||
for (unsigned i = 1; i < eventList.size(); ++ i) {
|
||||
const auto event = eventList[i];
|
||||
const auto length = event.delay - lastDelay;
|
||||
const auto step = (Default::panRange.clamp(mod.value * event.value) - lastValue)/ length;
|
||||
lastValue = linearRamp<float>(tempSpan.subspan(lastDelay, length), lastValue, step);
|
||||
lastDelay += length;
|
||||
}
|
||||
fill<float>(tempSpan.subspan(lastDelay), lastValue);
|
||||
applyGain<float>(tempSpan, modulationSpan);
|
||||
}
|
||||
|
||||
add<float>(region->pan, modulationSpan);
|
||||
}
|
||||
|
||||
void sfz::Voice::widthModulation(absl::Span<float> modulationSpan) noexcept
|
||||
{
|
||||
if (!region)
|
||||
return;
|
||||
|
||||
if (region->widthCC.empty()) {
|
||||
fill<float>(modulationSpan, region->width);
|
||||
return;
|
||||
}
|
||||
|
||||
fill<float>(modulationSpan, 1.0f);
|
||||
const auto numSamples = modulationSpan.size();
|
||||
auto tempBuffer = resources.bufferPool.getBuffer(numSamples);
|
||||
if (!tempBuffer)
|
||||
return;
|
||||
auto tempSpan = absl::MakeSpan(*tempBuffer).first(numSamples);
|
||||
|
||||
for (auto& mod : region->widthCC) {
|
||||
const auto eventList = resources.midiState.getEvents(mod.cc);
|
||||
ASSERT(eventList.size() > 0);
|
||||
ASSERT(eventList[0].delay == 0);
|
||||
|
||||
auto lastValue = mod.value * eventList[0].value;
|
||||
auto lastDelay = eventList[0].delay;
|
||||
for (unsigned i = 1; i < eventList.size(); ++ i) {
|
||||
const auto event = eventList[i];
|
||||
const auto length = event.delay - lastDelay;
|
||||
const auto step = (Default::widthRange.clamp(mod.value * event.value) - lastValue)/ length;
|
||||
lastValue = linearRamp<float>(tempSpan.subspan(lastDelay, length), lastValue, step);
|
||||
lastDelay += length;
|
||||
}
|
||||
fill<float>(tempSpan.subspan(lastDelay), lastValue);
|
||||
applyGain<float>(tempSpan, modulationSpan);
|
||||
}
|
||||
add<float>(region->width, modulationSpan);
|
||||
}
|
||||
|
||||
void sfz::Voice::positionModulation(absl::Span<float> modulationSpan) noexcept
|
||||
{
|
||||
if (!region)
|
||||
return;
|
||||
|
||||
if (region->positionCC.empty()) {
|
||||
fill<float>(modulationSpan, region->position);
|
||||
return;
|
||||
}
|
||||
|
||||
fill<float>(modulationSpan, 1.0f);
|
||||
const auto numSamples = modulationSpan.size();
|
||||
auto tempBuffer = resources.bufferPool.getBuffer(numSamples);
|
||||
if (!tempBuffer)
|
||||
return;
|
||||
auto tempSpan = absl::MakeSpan(*tempBuffer).first(numSamples);
|
||||
|
||||
for (auto& mod : region->positionCC) {
|
||||
const auto eventList = resources.midiState.getEvents(mod.cc);
|
||||
ASSERT(eventList.size() > 0);
|
||||
ASSERT(eventList[0].delay == 0);
|
||||
|
||||
auto lastValue = mod.value * eventList[0].value;
|
||||
auto lastDelay = eventList[0].delay;
|
||||
for (unsigned i = 1; i < eventList.size(); ++ i) {
|
||||
const auto event = eventList[i];
|
||||
const auto length = event.delay - lastDelay;
|
||||
const auto step = (Default::positionRange.clamp(mod.value * event.value) - lastValue)/ length;
|
||||
lastValue = linearRamp<float>(tempSpan.subspan(lastDelay, length), lastValue, step);
|
||||
lastDelay += length;
|
||||
}
|
||||
fill<float>(tempSpan.subspan(lastDelay), lastValue);
|
||||
applyGain<float>(tempSpan, modulationSpan);
|
||||
}
|
||||
add<float>(region->position, modulationSpan);
|
||||
}
|
||||
|
||||
void sfz::Voice::processMono(AudioSpan<float> buffer) noexcept
|
||||
{
|
||||
const auto numSamples = buffer.getNumFrames();
|
||||
|
|
@ -474,21 +259,29 @@ void sfz::Voice::processMono(AudioSpan<float> buffer) noexcept
|
|||
auto rightBuffer = buffer.getSpan(1);
|
||||
|
||||
auto modulationBuffer = resources.bufferPool.getBuffer(numSamples);
|
||||
if (!modulationBuffer)
|
||||
auto tempBuffer = resources.bufferPool.getBuffer(numSamples);
|
||||
if (!modulationBuffer || !tempBuffer)
|
||||
return;
|
||||
auto modulationSpan = absl::MakeSpan(*modulationBuffer).first(numSamples);
|
||||
auto tempSpan = absl::MakeSpan(*tempBuffer).first(numSamples);
|
||||
using namespace std::placeholders;
|
||||
const auto xfinBind = std::bind(crossfadeIn<float, float>, _1, _2, region->crossfadeCCCurve);
|
||||
const auto xfoutBind = std::bind(crossfadeIn<float, float>, _1, _2, region->crossfadeCCCurve);
|
||||
|
||||
{ // Amplitude processing
|
||||
ScopedTiming logger { amplitudeDuration };
|
||||
|
||||
// Amplitude envelope
|
||||
amplitudeModulation(modulationSpan);
|
||||
fill<float>(modulationSpan, baseGain);
|
||||
resources.midiState.multiplicativeModifiers(region->amplitudeCC, modulationSpan, tempSpan);
|
||||
DBG("Final gain: " << modulationSpan.back());
|
||||
applyGain<float>(modulationSpan, leftBuffer);
|
||||
|
||||
// Crossfade envelopes
|
||||
// crossfadeEnvelope.getBlock(modulationSpan);
|
||||
crossfadeModulation(modulationSpan);
|
||||
fill<float>(modulationSpan, 1.0f);
|
||||
resources.midiState.multiplicativeModifiers(region->crossfadeCCInRange, modulationSpan, tempSpan, xfinBind);
|
||||
resources.midiState.multiplicativeModifiers(region->crossfadeCCOutRange, modulationSpan, tempSpan, xfoutBind);
|
||||
DBG("XF: " << modulationSpan.back());
|
||||
applyGain<float>(modulationSpan, leftBuffer);
|
||||
|
||||
|
|
@ -522,7 +315,8 @@ void sfz::Voice::processMono(AudioSpan<float> buffer) noexcept
|
|||
copy<float>(leftBuffer, rightBuffer);
|
||||
|
||||
// Apply panning
|
||||
panningModulation(modulationSpan);
|
||||
fill<float>(modulationSpan, region->pan);
|
||||
resources.midiState.additiveModifiers(region->panCC, modulationSpan, tempSpan);
|
||||
DBG("Pan: " << modulationSpan.back());
|
||||
pan<float>(modulationSpan, leftBuffer, rightBuffer);
|
||||
}
|
||||
|
|
@ -535,19 +329,29 @@ void sfz::Voice::processStereo(AudioSpan<float> buffer) noexcept
|
|||
auto rightBuffer = buffer.getSpan(1);
|
||||
|
||||
auto modulationBuffer = resources.bufferPool.getBuffer(numSamples);
|
||||
if (!modulationBuffer)
|
||||
auto tempBuffer = resources.bufferPool.getBuffer(numSamples);
|
||||
if (!modulationBuffer || !tempBuffer)
|
||||
return;
|
||||
auto modulationSpan = absl::MakeSpan(*modulationBuffer).first(numSamples);
|
||||
auto tempSpan = absl::MakeSpan(*tempBuffer).first(numSamples);
|
||||
|
||||
using namespace std::placeholders;
|
||||
const auto xfinBind = std::bind(crossfadeIn<float, float>, _1, _2, region->crossfadeCCCurve);
|
||||
const auto xfoutBind = std::bind(crossfadeIn<float, float>, _1, _2, region->crossfadeCCCurve);
|
||||
|
||||
{ // Amplitude processing
|
||||
ScopedTiming logger { amplitudeDuration };
|
||||
|
||||
// Amplitude envelope
|
||||
amplitudeModulation(modulationSpan);
|
||||
fill<float>(modulationSpan, baseGain);
|
||||
resources.midiState.multiplicativeModifiers(region->amplitudeCC, modulationSpan, tempSpan);
|
||||
DBG("Final gain: " << modulationSpan.back());
|
||||
buffer.applyGain(modulationSpan);
|
||||
|
||||
// Crossfade envelopes
|
||||
crossfadeModulation(modulationSpan);
|
||||
fill<float>(modulationSpan, 1.0f);
|
||||
resources.midiState.multiplicativeModifiers(region->crossfadeCCInRange, modulationSpan, tempSpan, xfinBind);
|
||||
resources.midiState.multiplicativeModifiers(region->crossfadeCCOutRange, modulationSpan, tempSpan, xfoutBind);
|
||||
buffer.applyGain(modulationSpan);
|
||||
|
||||
// Volume envelope
|
||||
|
|
@ -563,14 +367,20 @@ void sfz::Voice::processStereo(AudioSpan<float> buffer) noexcept
|
|||
ScopedTiming logger { panningDuration };
|
||||
|
||||
// Apply panning
|
||||
panningModulation(modulationSpan);
|
||||
// panningModulation(modulationSpan);
|
||||
fill<float>(modulationSpan, region->pan);
|
||||
resources.midiState.additiveModifiers(region->panCC, modulationSpan, tempSpan);
|
||||
pan<float>(modulationSpan, leftBuffer, rightBuffer);
|
||||
|
||||
// Apply the width/position process
|
||||
widthModulation(modulationSpan);
|
||||
// widthModulation(modulationSpan);
|
||||
fill<float>(modulationSpan, region->width);
|
||||
resources.midiState.additiveModifiers(region->widthCC, modulationSpan, tempSpan);
|
||||
width<float>(modulationSpan, leftBuffer, rightBuffer);
|
||||
|
||||
positionModulation(modulationSpan);
|
||||
// positionModulation(modulationSpan);
|
||||
fill<float>(modulationSpan, region->position);
|
||||
resources.midiState.additiveModifiers(region->positionCC, modulationSpan, tempSpan);
|
||||
pan<float>(modulationSpan, leftBuffer, rightBuffer);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -251,12 +251,6 @@ private:
|
|||
*/
|
||||
void processStereo(AudioSpan<float> buffer) noexcept;
|
||||
|
||||
void amplitudeModulation(absl::Span<float> modulationSpan) noexcept;
|
||||
void crossfadeModulation(absl::Span<float> modulationSpan) noexcept;
|
||||
void panningModulation(absl::Span<float> modulationSpan) noexcept;
|
||||
void widthModulation(absl::Span<float> modulationSpan) noexcept;
|
||||
void positionModulation(absl::Span<float> modulationSpan) noexcept;
|
||||
|
||||
Region* region { nullptr };
|
||||
|
||||
enum class State {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue