Use the full modifier on amplitude and crossfades
This commit is contained in:
parent
394512183a
commit
d59d29c72b
1 changed files with 40 additions and 24 deletions
|
|
@ -85,9 +85,6 @@ void sfz::Voice::startVoice(Region* region, int delay, int number, float value,
|
||||||
if (triggerType != TriggerType::CC)
|
if (triggerType != TriggerType::CC)
|
||||||
baseGain *= region->getNoteGain(number, value);
|
baseGain *= region->getNoteGain(number, value);
|
||||||
|
|
||||||
float crossfadeGain { region->getCrossfadeGain() };
|
|
||||||
crossfadeEnvelope.reset(Default::normalizedRange.clamp(crossfadeGain));
|
|
||||||
|
|
||||||
basePan = normalizePercents(region->pan);
|
basePan = normalizePercents(region->pan);
|
||||||
auto pan = basePan;
|
auto pan = basePan;
|
||||||
if (region->panCC)
|
if (region->panCC)
|
||||||
|
|
@ -217,11 +214,6 @@ void sfz::Voice::registerCC(int delay, int ccNumber, float ccValue) noexcept
|
||||||
const float newWidth { baseWidth + 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));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (region->crossfadeCCInRange.contains(ccNumber) || region->crossfadeCCOutRange.contains(ccNumber)) {
|
|
||||||
const float crossfadeGain = region->getCrossfadeGain();
|
|
||||||
crossfadeEnvelope.registerEvent(delay, Default::normalizedRange.clamp(crossfadeGain));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sfz::Voice::registerPitchWheel(int delay, int pitch) noexcept
|
void sfz::Voice::registerPitchWheel(int delay, int pitch) noexcept
|
||||||
|
|
@ -294,26 +286,23 @@ void sfz::Voice::renderBlock(AudioSpan<float> buffer) noexcept
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
void getLinearEnvelope(const sfz::CCMap<T>& ccMods, const sfz::MidiState& state, absl::Span<float> output, absl::Span<float> temp)
|
void getLinearEnvelope(const sfz::CCMap<T>& ccMods, const sfz::MidiState& state, absl::Span<float> temp, std::function<float(const T&, float)> function)
|
||||||
{
|
{
|
||||||
ASSERT(output.size() <= temp.size());
|
|
||||||
for (auto& mod : ccMods) {
|
for (auto& mod : ccMods) {
|
||||||
const auto eventList = state.getEvents(mod.cc);
|
const auto eventList = state.getEvents(mod.cc);
|
||||||
const auto modifier = static_cast<float>(mod.value);
|
|
||||||
ASSERT(eventList.size() > 0);
|
ASSERT(eventList.size() > 0);
|
||||||
ASSERT(eventList[0].delay == 0);
|
ASSERT(eventList[0].delay == 0);
|
||||||
|
|
||||||
auto lastValue = eventList[0].value;
|
auto lastValue = function(mod.value, eventList[0].value);
|
||||||
auto lastDelay = eventList[0].delay;
|
auto lastDelay = eventList[0].delay;
|
||||||
for (unsigned i = 1; i < eventList.size(); ++ i) {
|
for (unsigned i = 1; i < eventList.size(); ++ i) {
|
||||||
const auto event = eventList[i];
|
const auto event = eventList[i];
|
||||||
const auto length = event.delay - lastDelay;
|
const auto length = event.delay - lastDelay;
|
||||||
const auto step = (event.value - lastValue) * modifier / length;
|
const auto step = (function(mod.value, event.value) - lastValue)/ length;
|
||||||
lastValue = sfz::linearRamp<T>(temp.subspan(lastDelay, length), lastValue, step);
|
lastValue = sfz::linearRamp<float>(temp.subspan(lastDelay, length), lastValue, step);
|
||||||
lastDelay += length;
|
lastDelay += length;
|
||||||
}
|
}
|
||||||
sfz::fill<T>(temp.subspan(lastDelay), lastValue * modifier);
|
sfz::fill<float>(temp.subspan(lastDelay), lastValue);
|
||||||
sfz::add<T>(temp, output);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -334,13 +323,30 @@ void sfz::Voice::processMono(AudioSpan<float> buffer) noexcept
|
||||||
ScopedTiming logger { amplitudeDuration };
|
ScopedTiming logger { amplitudeDuration };
|
||||||
|
|
||||||
// Amplitude envelope
|
// Amplitude envelope
|
||||||
fill<float>(modulationSpan, baseGain);
|
fill<float>(modulationSpan, 0.0f);
|
||||||
getLinearEnvelope(region->amplitudeCC, resources.midiState, modulationSpan, tempSpan);
|
getLinearEnvelope<float>(region->amplitudeCC, resources.midiState, modulationSpan, [](const float& modifier, float value){
|
||||||
|
return value * modifier;
|
||||||
|
});
|
||||||
|
DBG("Amplitude curve back: " << modulationSpan.back());
|
||||||
|
add<float>(baseGain, modulationSpan);
|
||||||
|
DBG("FInal gain: " << modulationSpan.back());
|
||||||
applyGain<float>(modulationSpan, leftBuffer);
|
applyGain<float>(modulationSpan, leftBuffer);
|
||||||
|
|
||||||
// Crossfade envelope
|
// Crossfade envelopes
|
||||||
crossfadeEnvelope.getBlock(modulationSpan);
|
// crossfadeEnvelope.getBlock(modulationSpan);
|
||||||
|
fill<float>(modulationSpan, 1.0f);
|
||||||
|
getLinearEnvelope<Range<float>>(region->crossfadeCCInRange, resources.midiState, modulationSpan, [this](const Range<float>& range, float value){
|
||||||
|
return crossfadeIn(range, value, region->crossfadeCCCurve);
|
||||||
|
});
|
||||||
applyGain<float>(modulationSpan, leftBuffer);
|
applyGain<float>(modulationSpan, leftBuffer);
|
||||||
|
DBG("XFin: " << modulationSpan.back());
|
||||||
|
|
||||||
|
fill<float>(modulationSpan, 1.0f);
|
||||||
|
getLinearEnvelope<Range<float>>(region->crossfadeCCOutRange, resources.midiState, modulationSpan, [this](const Range<float>& range, float value){
|
||||||
|
return crossfadeOut(range, value, region->crossfadeCCCurve);
|
||||||
|
});
|
||||||
|
applyGain<float>(modulationSpan, leftBuffer);
|
||||||
|
DBG("XFout: " << modulationSpan.back());
|
||||||
|
|
||||||
// Volume envelope
|
// Volume envelope
|
||||||
volumeEnvelope.getBlock(modulationSpan);
|
volumeEnvelope.getBlock(modulationSpan);
|
||||||
|
|
@ -394,12 +400,22 @@ void sfz::Voice::processStereo(AudioSpan<float> buffer) noexcept
|
||||||
ScopedTiming logger { amplitudeDuration };
|
ScopedTiming logger { amplitudeDuration };
|
||||||
|
|
||||||
// Amplitude envelope
|
// Amplitude envelope
|
||||||
fill<float>(modulationSpan, baseGain);
|
fill<float>(modulationSpan, 0.0f);
|
||||||
getLinearEnvelope(region->amplitudeCC, resources.midiState, modulationSpan, tempSpan);
|
getLinearEnvelope<float>(region->amplitudeCC, resources.midiState, modulationSpan, [](float modifier, float value) { return value * modifier; });
|
||||||
|
add<float>(baseGain, modulationSpan);
|
||||||
buffer.applyGain(modulationSpan);
|
buffer.applyGain(modulationSpan);
|
||||||
|
|
||||||
// Crossfade envelope
|
// Crossfade envelopes
|
||||||
crossfadeEnvelope.getBlock(modulationSpan);
|
fill<float>(modulationSpan, 1.0f);
|
||||||
|
getLinearEnvelope<Range<float>>(region->crossfadeCCInRange, resources.midiState, modulationSpan, [this](const Range<float>& range, float value){
|
||||||
|
return crossfadeIn(range, value, region->crossfadeCCCurve);
|
||||||
|
});
|
||||||
|
buffer.applyGain(modulationSpan);
|
||||||
|
|
||||||
|
fill<float>(modulationSpan, 1.0f);
|
||||||
|
getLinearEnvelope<Range<float>>(region->crossfadeCCOutRange, resources.midiState, modulationSpan, [this](const Range<float>& range, float value){
|
||||||
|
return crossfadeOut(range, value, region->crossfadeCCCurve);
|
||||||
|
});
|
||||||
buffer.applyGain(modulationSpan);
|
buffer.applyGain(modulationSpan);
|
||||||
|
|
||||||
// Volume envelope
|
// Volume envelope
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue