Tentative replacement of the amplitude envelope
This commit is contained in:
parent
612265ebb5
commit
42fa89ab5a
4 changed files with 37 additions and 17 deletions
|
|
@ -299,7 +299,10 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
|
|||
break;
|
||||
case hash("amplitude_cc&"): // fallthrough
|
||||
case hash("amplitude_oncc&"):
|
||||
setCCPairFromOpcode(opcode, amplitudeCC, Default::amplitudeRange);
|
||||
if (opcode.parameters.back() > config::numCCs)
|
||||
return false;
|
||||
if (auto value = readOpcode(opcode.value, Default::amplitudeRange))
|
||||
amplitudeCC[opcode.parameters.back()] = *value;
|
||||
break;
|
||||
case hash("pan"):
|
||||
setValueFromOpcode(opcode, pan, Default::panRange);
|
||||
|
|
|
|||
|
|
@ -277,7 +277,7 @@ struct Region {
|
|||
float width { Default::width }; // width
|
||||
float position { Default::position }; // position
|
||||
absl::optional<CCValuePair<float>> volumeCC; // volume_oncc
|
||||
absl::optional<CCValuePair<float>> amplitudeCC; // amplitude_oncc
|
||||
CCMap<float> amplitudeCC { Default::amplitude }; // amplitude_oncc
|
||||
absl::optional<CCValuePair<float>> panCC; // pan_oncc
|
||||
absl::optional<CCValuePair<float>> widthCC; // width_oncc
|
||||
absl::optional<CCValuePair<float>> positionCC; // position_oncc
|
||||
|
|
|
|||
|
|
@ -85,11 +85,6 @@ void sfz::Voice::startVoice(Region* region, int delay, int number, float value,
|
|||
if (triggerType != TriggerType::CC)
|
||||
baseGain *= region->getNoteGain(number, value);
|
||||
|
||||
float gain { baseGain };
|
||||
if (region->amplitudeCC)
|
||||
gain += resources.midiState.getCCValue(region->amplitudeCC->cc) * normalizePercents(region->amplitudeCC->value);
|
||||
amplitudeEnvelope.reset(Default::normalizedRange.clamp(gain));
|
||||
|
||||
float crossfadeGain { region->getCrossfadeGain() };
|
||||
crossfadeEnvelope.reset(Default::normalizedRange.clamp(crossfadeGain));
|
||||
|
||||
|
|
@ -203,11 +198,6 @@ void sfz::Voice::registerCC(int delay, int ccNumber, float ccValue) noexcept
|
|||
// TODO: this feels like a hack, revisit this along with the smoothed envelopes...
|
||||
delay = max(delay, minEnvelopeDelay);
|
||||
|
||||
if (region->amplitudeCC && ccNumber == region->amplitudeCC->cc) {
|
||||
const float newGain { baseGain + ccValue * normalizePercents(region->amplitudeCC->value) };
|
||||
amplitudeEnvelope.registerEvent(delay, Default::normalizedRange.clamp(newGain));
|
||||
}
|
||||
|
||||
if (region->volumeCC && ccNumber == region->volumeCC->cc) {
|
||||
const float newVolumedB { baseVolumedB + ccValue * region->volumeCC->value };
|
||||
volumeEnvelope.registerEvent(delay, db2mag(Default::volumeRange.clamp(newVolumedB)));
|
||||
|
|
@ -311,6 +301,31 @@ 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)
|
||||
{
|
||||
ASSERT(output.size() <= temp.size());
|
||||
sfz::fill<T>(output, T{0.0});
|
||||
for (auto& mod : ccMods) {
|
||||
const auto eventList = state.getEvents(mod.cc);
|
||||
const auto modifier = static_cast<float>(mod.value);
|
||||
ASSERT(eventList.size() > 0);
|
||||
ASSERT(eventList[0].delay == 0);
|
||||
|
||||
auto lastValue = 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 = (event.value - lastValue) * modifier / length;
|
||||
lastValue = sfz::linearRamp<T>(temp.subspan(lastDelay, length), lastValue, step);
|
||||
lastDelay += length;
|
||||
}
|
||||
sfz::fill<T>(temp.subspan(lastDelay), lastValue * modifier);
|
||||
sfz::add<T>(temp, output);
|
||||
}
|
||||
}
|
||||
|
||||
void sfz::Voice::processMono(AudioSpan<float> buffer) noexcept
|
||||
{
|
||||
const auto numSamples = buffer.getNumFrames();
|
||||
|
|
@ -318,12 +333,13 @@ void sfz::Voice::processMono(AudioSpan<float> buffer) noexcept
|
|||
auto rightBuffer = buffer.getSpan(1);
|
||||
|
||||
auto modulationSpan = tempSpan1.first(numSamples);
|
||||
auto tempSpan = tempSpan2.first(numSamples);
|
||||
|
||||
{ // Amplitude processing
|
||||
ScopedTiming logger { amplitudeDuration };
|
||||
|
||||
// Amplitude envelope
|
||||
amplitudeEnvelope.getBlock(modulationSpan);
|
||||
getLinearEnvelope(region->amplitudeCC, resources.midiState, modulationSpan, tempSpan);
|
||||
applyGain<float>(modulationSpan, leftBuffer);
|
||||
|
||||
// Crossfade envelope
|
||||
|
|
@ -369,6 +385,7 @@ void sfz::Voice::processStereo(AudioSpan<float> buffer) noexcept
|
|||
{
|
||||
const auto numSamples = buffer.getNumFrames();
|
||||
auto modulationSpan = tempSpan1.first(numSamples);
|
||||
auto tempSpan = tempSpan2.first(numSamples);
|
||||
auto leftBuffer = buffer.getSpan(0);
|
||||
auto rightBuffer = buffer.getSpan(1);
|
||||
|
||||
|
|
@ -376,7 +393,7 @@ void sfz::Voice::processStereo(AudioSpan<float> buffer) noexcept
|
|||
ScopedTiming logger { amplitudeDuration };
|
||||
|
||||
// Amplitude envelope
|
||||
amplitudeEnvelope.getBlock(modulationSpan);
|
||||
getLinearEnvelope(region->amplitudeCC, resources.midiState, modulationSpan, tempSpan);
|
||||
buffer.applyGain(modulationSpan);
|
||||
|
||||
// Crossfade envelope
|
||||
|
|
|
|||
|
|
@ -309,9 +309,9 @@ TEST_CASE("[Files] wrong (overlapping) replacement for defines")
|
|||
REQUIRE( synth.getRegionView(0)->keyRange.getEnd() == 52 );
|
||||
REQUIRE( synth.getRegionView(1)->keyRange.getStart() == 57 );
|
||||
REQUIRE( synth.getRegionView(1)->keyRange.getEnd() == 57 );
|
||||
REQUIRE( synth.getRegionView(2)->amplitudeCC );
|
||||
REQUIRE( synth.getRegionView(2)->amplitudeCC->cc == 10 );
|
||||
REQUIRE( synth.getRegionView(2)->amplitudeCC->value == 34.0f );
|
||||
REQUIRE( !synth.getRegionView(2)->amplitudeCC.empty() );
|
||||
REQUIRE( synth.getRegionView(2)->amplitudeCC.contains(10) );
|
||||
REQUIRE( synth.getRegionView(2)->amplitudeCC.getWithDefault(10) == 34.0f );
|
||||
}
|
||||
|
||||
TEST_CASE("[Files] Specific bug: relative path with backslashes")
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue