Handle the volume cc modifiers like the rest

This commit is contained in:
Paul Ferrand 2020-03-31 00:33:06 +02:00
parent bc60b19c4b
commit bd85a97db3
3 changed files with 19 additions and 29 deletions

View file

@ -294,7 +294,10 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
case hash("gain_cc&"):
case hash("gain_oncc&"): // fallthrough
case hash("volume_oncc&"):
setCCPairFromOpcode(opcode, volumeCC, Default::volumeCCRange);
if (opcode.parameters.back() > config::numCCs)
return false;
if (auto value = readOpcode(opcode.value, Default::volumeCCRange))
volumeCC[opcode.parameters.back()] = *value;
break;
case hash("amplitude"):
if (auto value = readOpcode(opcode.value, Default::amplitudeRange))

View file

@ -276,7 +276,7 @@ struct Region {
float pan { normalizePercents(Default::pan) }; // pan
float width { normalizePercents(Default::width) }; // width
float position { normalizePercents(Default::position) }; // position
absl::optional<CCValuePair<float>> volumeCC; // volume_oncc
CCMap<float> volumeCC { Default::zeroModifier }; // volume_oncc
CCMap<float> amplitudeCC { Default::zeroModifier }; // amplitude_oncc
CCMap<float> panCC { Default::zeroModifier }; // pan_oncc
CCMap<float> widthCC { Default::zeroModifier }; // width_oncc

View file

@ -74,23 +74,11 @@ void sfz::Voice::startVoice(Region* region, int delay, int number, float value,
speedRatio = static_cast<float>(currentPromise->sampleRate / this->sampleRate);
}
pitchRatio = region->getBasePitchVariation(number, value);
baseVolumedB = region->getBaseVolumedB(number);
auto volumedB = baseVolumedB;
if (region->volumeCC)
volumedB += resources.midiState.getCCValue(region->volumeCC->cc) * region->volumeCC->value;
volumeEnvelope.reset(db2mag(Default::volumeRange.clamp(volumedB)));
baseGain = region->getBaseGain();
if (triggerType != TriggerType::CC)
baseGain *= region->getNoteGain(number, value);
pitchBendEnvelope.setFunction([region](float bend){
const auto bendInCents = bend > 0.0f ? bend * static_cast<float>(region->bendUp) : -bend * static_cast<float>(region->bendDown);
return centsFactor(bendInCents);
});
pitchBendEnvelope.reset(resources.midiState.getPitchBend());
// Check that we can handle the number of filters; filters should be cleared here
ASSERT((filters.capacity() - filters.size()) >= region->filters.size());
ASSERT((equalizers.capacity() - equalizers.size()) >= region->equalizers.size());
@ -171,23 +159,14 @@ void sfz::Voice::registerCC(int delay, int ccNumber, float ccValue) noexcept
if (region->checkSustain && noteIsOff && ccNumber == config::sustainCC && ccValue < config::halfCCThreshold)
release(delay);
// Add a minimum delay for smoothing the envelopes
// TODO: this feels like a hack, revisit this along with the smoothed envelopes...
delay = max(delay, minEnvelopeDelay);
if (region->volumeCC && ccNumber == region->volumeCC->cc) {
const float newVolumedB { baseVolumedB + ccValue * region->volumeCC->value };
volumeEnvelope.registerEvent(delay, db2mag(Default::volumeRange.clamp(newVolumedB)));
}
}
void sfz::Voice::registerPitchWheel(int delay, float pitch) noexcept
{
if (state == State::idle)
return;
pitchBendEnvelope.registerEvent(delay, pitch);
UNUSED(delay);
UNUSED(pitch);
}
void sfz::Voice::registerAftertouch(int delay, uint8_t aftertouch) noexcept
@ -293,7 +272,12 @@ void sfz::Voice::ampStageMono(AudioSpan<float> buffer) noexcept
applyGain<float>(*modulationSpan, leftBuffer);
// Volume envelope
volumeEnvelope.getBlock(*modulationSpan);
fill<float>(*modulationSpan, db2mag(baseVolumedB));
for (auto& mod : region->volumeCC) {
const auto events = resources.midiState.getCCEvents(mod.cc);
multiplicativeEnvelope(events, *tempSpan, [&](float x) { return db2mag(x * mod.value); });
applyGain<float>(*tempSpan, *modulationSpan);
}
applyGain<float>(*modulationSpan, leftBuffer);
// AmpEG envelope
@ -330,17 +314,20 @@ void sfz::Voice::ampStageStereo(AudioSpan<float> buffer) noexcept
linearEnvelope(events, *tempSpan, [&](float x) { return crossfadeIn(mod.value, x, xfCurve); });
applyGain<float>(*tempSpan, *modulationSpan);
}
for (auto& mod : region->crossfadeCCOutRange) {
const auto events = resources.midiState.getCCEvents(mod.cc);
linearEnvelope(events, *tempSpan, [&](float x) { return crossfadeOut(mod.value, x, xfCurve); });
applyGain<float>(*tempSpan, *modulationSpan);
}
buffer.applyGain(*modulationSpan);
// Volume envelope
volumeEnvelope.getBlock(*modulationSpan);
fill<float>(*modulationSpan, db2mag(baseVolumedB));
for (auto& mod : region->volumeCC) {
const auto events = resources.midiState.getCCEvents(mod.cc);
multiplicativeEnvelope(events, *tempSpan, [&](float x) { return db2mag(x * mod.value); });
applyGain<float>(*tempSpan, *modulationSpan);
}
buffer.applyGain(*modulationSpan);
// AmpEG envelope