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;
|
break;
|
||||||
case hash("amplitude_cc&"): // fallthrough
|
case hash("amplitude_cc&"): // fallthrough
|
||||||
case hash("amplitude_oncc&"):
|
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;
|
break;
|
||||||
case hash("pan"):
|
case hash("pan"):
|
||||||
setValueFromOpcode(opcode, pan, Default::panRange);
|
setValueFromOpcode(opcode, pan, Default::panRange);
|
||||||
|
|
|
||||||
|
|
@ -277,7 +277,7 @@ struct Region {
|
||||||
float width { Default::width }; // width
|
float width { Default::width }; // width
|
||||||
float position { Default::position }; // position
|
float position { Default::position }; // position
|
||||||
absl::optional<CCValuePair<float>> volumeCC; // volume_oncc
|
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>> panCC; // pan_oncc
|
||||||
absl::optional<CCValuePair<float>> widthCC; // width_oncc
|
absl::optional<CCValuePair<float>> widthCC; // width_oncc
|
||||||
absl::optional<CCValuePair<float>> positionCC; // position_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)
|
if (triggerType != TriggerType::CC)
|
||||||
baseGain *= region->getNoteGain(number, value);
|
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() };
|
float crossfadeGain { region->getCrossfadeGain() };
|
||||||
crossfadeEnvelope.reset(Default::normalizedRange.clamp(crossfadeGain));
|
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...
|
// TODO: this feels like a hack, revisit this along with the smoothed envelopes...
|
||||||
delay = max(delay, minEnvelopeDelay);
|
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) {
|
if (region->volumeCC && ccNumber == region->volumeCC->cc) {
|
||||||
const float newVolumedB { baseVolumedB + 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)));
|
||||||
|
|
@ -311,6 +301,31 @@ void sfz::Voice::renderBlock(AudioSpan<float> buffer) noexcept
|
||||||
this->triggerDelay = absl::nullopt;
|
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
|
void sfz::Voice::processMono(AudioSpan<float> buffer) noexcept
|
||||||
{
|
{
|
||||||
const auto numSamples = buffer.getNumFrames();
|
const auto numSamples = buffer.getNumFrames();
|
||||||
|
|
@ -318,12 +333,13 @@ void sfz::Voice::processMono(AudioSpan<float> buffer) noexcept
|
||||||
auto rightBuffer = buffer.getSpan(1);
|
auto rightBuffer = buffer.getSpan(1);
|
||||||
|
|
||||||
auto modulationSpan = tempSpan1.first(numSamples);
|
auto modulationSpan = tempSpan1.first(numSamples);
|
||||||
|
auto tempSpan = tempSpan2.first(numSamples);
|
||||||
|
|
||||||
{ // Amplitude processing
|
{ // Amplitude processing
|
||||||
ScopedTiming logger { amplitudeDuration };
|
ScopedTiming logger { amplitudeDuration };
|
||||||
|
|
||||||
// Amplitude envelope
|
// Amplitude envelope
|
||||||
amplitudeEnvelope.getBlock(modulationSpan);
|
getLinearEnvelope(region->amplitudeCC, resources.midiState, modulationSpan, tempSpan);
|
||||||
applyGain<float>(modulationSpan, leftBuffer);
|
applyGain<float>(modulationSpan, leftBuffer);
|
||||||
|
|
||||||
// Crossfade envelope
|
// Crossfade envelope
|
||||||
|
|
@ -369,6 +385,7 @@ void sfz::Voice::processStereo(AudioSpan<float> buffer) noexcept
|
||||||
{
|
{
|
||||||
const auto numSamples = buffer.getNumFrames();
|
const auto numSamples = buffer.getNumFrames();
|
||||||
auto modulationSpan = tempSpan1.first(numSamples);
|
auto modulationSpan = tempSpan1.first(numSamples);
|
||||||
|
auto tempSpan = tempSpan2.first(numSamples);
|
||||||
auto leftBuffer = buffer.getSpan(0);
|
auto leftBuffer = buffer.getSpan(0);
|
||||||
auto rightBuffer = buffer.getSpan(1);
|
auto rightBuffer = buffer.getSpan(1);
|
||||||
|
|
||||||
|
|
@ -376,7 +393,7 @@ void sfz::Voice::processStereo(AudioSpan<float> buffer) noexcept
|
||||||
ScopedTiming logger { amplitudeDuration };
|
ScopedTiming logger { amplitudeDuration };
|
||||||
|
|
||||||
// Amplitude envelope
|
// Amplitude envelope
|
||||||
amplitudeEnvelope.getBlock(modulationSpan);
|
getLinearEnvelope(region->amplitudeCC, resources.midiState, modulationSpan, tempSpan);
|
||||||
buffer.applyGain(modulationSpan);
|
buffer.applyGain(modulationSpan);
|
||||||
|
|
||||||
// Crossfade envelope
|
// Crossfade envelope
|
||||||
|
|
|
||||||
|
|
@ -309,9 +309,9 @@ TEST_CASE("[Files] wrong (overlapping) replacement for defines")
|
||||||
REQUIRE( synth.getRegionView(0)->keyRange.getEnd() == 52 );
|
REQUIRE( synth.getRegionView(0)->keyRange.getEnd() == 52 );
|
||||||
REQUIRE( synth.getRegionView(1)->keyRange.getStart() == 57 );
|
REQUIRE( synth.getRegionView(1)->keyRange.getStart() == 57 );
|
||||||
REQUIRE( synth.getRegionView(1)->keyRange.getEnd() == 57 );
|
REQUIRE( synth.getRegionView(1)->keyRange.getEnd() == 57 );
|
||||||
REQUIRE( synth.getRegionView(2)->amplitudeCC );
|
REQUIRE( !synth.getRegionView(2)->amplitudeCC.empty() );
|
||||||
REQUIRE( synth.getRegionView(2)->amplitudeCC->cc == 10 );
|
REQUIRE( synth.getRegionView(2)->amplitudeCC.contains(10) );
|
||||||
REQUIRE( synth.getRegionView(2)->amplitudeCC->value == 34.0f );
|
REQUIRE( synth.getRegionView(2)->amplitudeCC.getWithDefault(10) == 34.0f );
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("[Files] Specific bug: relative path with backslashes")
|
TEST_CASE("[Files] Specific bug: relative path with backslashes")
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue