Use modifiers for panning/width

This commit is contained in:
Paul Ferrand 2020-03-29 19:22:19 +02:00
parent d59d29c72b
commit 97234177a1
5 changed files with 37 additions and 51 deletions

View file

@ -54,9 +54,10 @@ namespace Default
constexpr SfzLoopMode loopMode { SfzLoopMode::no_loop };
constexpr Range<uint32_t> loopRange { 0, std::numeric_limits<uint32_t>::max() };
// Global ranges
// common defaults
constexpr Range<uint8_t> midi7Range { 0, 127 };
constexpr Range<float> normalizedRange { 0.0f, 1.0f };
constexpr float zeroModifier { 0.0f };
// Wavetable oscillator
constexpr float oscillatorPhase { 0.0 };

View file

@ -305,22 +305,34 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
amplitudeCC[opcode.parameters.back()] = normalizePercents(*value);
break;
case hash("pan"):
setValueFromOpcode(opcode, pan, Default::panRange);
if (auto value = readOpcode(opcode.value, Default::panRange))
pan = normalizePercents(*value);
break;
case hash("pan_oncc&"):
setCCPairFromOpcode(opcode, panCC, Default::panCCRange);
if (opcode.parameters.back() > config::numCCs)
return false;
if (auto value = readOpcode(opcode.value, Default::panCCRange))
panCC[opcode.parameters.back()] = normalizePercents(*value);
break;
case hash("position"):
setValueFromOpcode(opcode, position, Default::positionRange);
if (auto value = readOpcode(opcode.value, Default::positionRange))
position = normalizePercents(*value);
break;
case hash("position_oncc&"):
setCCPairFromOpcode(opcode, positionCC, Default::positionCCRange);
if (opcode.parameters.back() > config::numCCs)
return false;
if (auto value = readOpcode(opcode.value, Default::positionCCRange))
positionCC[opcode.parameters.back()] = normalizePercents(*value);
break;
case hash("width"):
setValueFromOpcode(opcode, width, Default::widthRange);
if (auto value = readOpcode(opcode.value, Default::widthRange))
width = normalizePercents(*value);
break;
case hash("width_oncc&"):
setCCPairFromOpcode(opcode, widthCC, Default::widthCCRange);
if (opcode.parameters.back() > config::numCCs)
return false;
if (auto value = readOpcode(opcode.value, Default::widthCCRange))
widthCC[opcode.parameters.back()] = normalizePercents(*value);
break;
case hash("amp_keycenter"):
setValueFromOpcode(opcode, ampKeycenter, Default::keyRange);

View file

@ -277,10 +277,10 @@ struct Region {
float width { Default::width }; // width
float position { Default::position }; // position
absl::optional<CCValuePair<float>> volumeCC; // volume_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
CCMap<float> amplitudeCC { Default::zeroModifier }; // amplitude_oncc
CCMap<float> panCC { Default::zeroModifier }; // pan_oncc
CCMap<float> widthCC { Default::zeroModifier }; // width_oncc
CCMap<float> positionCC { Default::zeroModifier }; // position_oncc
uint8_t ampKeycenter { Default::ampKeycenter }; // amp_keycenter
float ampKeytrack { Default::ampKeytrack }; // amp_keytrack
float ampVeltrack { Default::ampVeltrack }; // amp_keytrack

View file

@ -85,24 +85,6 @@ void sfz::Voice::startVoice(Region* region, int delay, int number, float value,
if (triggerType != TriggerType::CC)
baseGain *= region->getNoteGain(number, value);
basePan = normalizePercents(region->pan);
auto pan = basePan;
if (region->panCC)
pan += resources.midiState.getCCValue(region->panCC->cc) * normalizePercents(region->panCC->value);
panEnvelope.reset(Default::symmetricNormalizedRange.clamp(pan));
basePosition = normalizePercents(region->position);
auto position = basePosition;
if (region->positionCC)
position += resources.midiState.getCCValue(region->positionCC->cc) * normalizePercents(region->positionCC->value);
positionEnvelope.reset(Default::symmetricNormalizedRange.clamp(position));
baseWidth = normalizePercents(region->width);
auto width = baseWidth;
if (region->widthCC)
width += resources.midiState.getCCValue(region->widthCC->cc) * normalizePercents(region->widthCC->value);
widthEnvelope.reset(Default::symmetricNormalizedRange.clamp(width));
pitchBendEnvelope.setFunction([region](float pitchValue){
const auto normalizedBend = normalizeBend(pitchValue);
const auto bendInCents = normalizedBend > 0.0f ? normalizedBend * static_cast<float>(region->bendUp) : -normalizedBend * static_cast<float>(region->bendDown);
@ -199,21 +181,6 @@ void sfz::Voice::registerCC(int delay, int ccNumber, float ccValue) noexcept
const float newVolumedB { baseVolumedB + ccValue * region->volumeCC->value };
volumeEnvelope.registerEvent(delay, db2mag(Default::volumeRange.clamp(newVolumedB)));
}
if (region->panCC && ccNumber == region->panCC->cc) {
const float newPan { basePan + ccValue * normalizePercents(region->panCC->value) };
panEnvelope.registerEvent(delay, Default::symmetricNormalizedRange.clamp(newPan));
}
if (region->positionCC && ccNumber == region->positionCC->cc) {
const float newPosition { basePosition + ccValue * normalizePercents(region->positionCC->value) };
positionEnvelope.registerEvent(delay, Default::symmetricNormalizedRange.clamp(newPosition));
}
if (region->widthCC && ccNumber == region->widthCC->cc) {
const float newWidth { baseWidth + ccValue * normalizePercents(region->widthCC->value) };
widthEnvelope.registerEvent(delay, Default::symmetricNormalizedRange.clamp(newWidth));
}
}
void sfz::Voice::registerPitchWheel(int delay, int pitch) noexcept
@ -378,7 +345,9 @@ void sfz::Voice::processMono(AudioSpan<float> buffer) noexcept
copy<float>(leftBuffer, rightBuffer);
// Apply panning
panEnvelope.getBlock(modulationSpan);
fill<float>(modulationSpan, 0.0f);
getLinearEnvelope<float>(region->panCC, resources.midiState, modulationSpan, [](float modifier, float value) { return value * modifier; });
add<float>(region->pan, modulationSpan);
pan<float>(modulationSpan, leftBuffer, rightBuffer);
}
}
@ -431,13 +400,20 @@ void sfz::Voice::processStereo(AudioSpan<float> buffer) noexcept
ScopedTiming logger { panningDuration };
// Apply panning
panEnvelope.getBlock(modulationSpan);
fill<float>(modulationSpan, 0.0f);
getLinearEnvelope<float>(region->panCC, resources.midiState, modulationSpan, [](float modifier, float value) { return value * modifier; });
add<float>(region->pan, modulationSpan);
pan<float>(modulationSpan, leftBuffer, rightBuffer);
// Apply the width/position process
widthEnvelope.getBlock(modulationSpan);
fill<float>(modulationSpan, 0.0f);
getLinearEnvelope<float>(region->widthCC, resources.midiState, modulationSpan, [](float modifier, float value) { return value * modifier; });
add<float>(region->width, modulationSpan);
width<float>(modulationSpan, leftBuffer, rightBuffer);
positionEnvelope.getBlock(modulationSpan);
fill<float>(modulationSpan, 0.0f);
getLinearEnvelope<float>(region->positionCC, resources.midiState, modulationSpan, [](float modifier, float value) { return value * modifier; });
add<float>(region->position, modulationSpan);
pan<float>(modulationSpan, leftBuffer, rightBuffer);
}

View file

@ -268,9 +268,6 @@ private:
float pitchRatio { 1.0 };
float baseVolumedB{ 0.0 };
float baseGain { 1.0 };
float basePan { 0.0 };
float basePosition { 0.0 };
float baseWidth { 0.0 };
float baseFrequency { 440.0 };
float phase { 0.0f };