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 SfzLoopMode loopMode { SfzLoopMode::no_loop };
constexpr Range<uint32_t> loopRange { 0, std::numeric_limits<uint32_t>::max() }; 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<uint8_t> midi7Range { 0, 127 };
constexpr Range<float> normalizedRange { 0.0f, 1.0f }; constexpr Range<float> normalizedRange { 0.0f, 1.0f };
constexpr float zeroModifier { 0.0f };
// Wavetable oscillator // Wavetable oscillator
constexpr float oscillatorPhase { 0.0 }; constexpr float oscillatorPhase { 0.0 };

View file

@ -305,22 +305,34 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
amplitudeCC[opcode.parameters.back()] = normalizePercents(*value); amplitudeCC[opcode.parameters.back()] = normalizePercents(*value);
break; break;
case hash("pan"): case hash("pan"):
setValueFromOpcode(opcode, pan, Default::panRange); if (auto value = readOpcode(opcode.value, Default::panRange))
pan = normalizePercents(*value);
break; break;
case hash("pan_oncc&"): 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; break;
case hash("position"): case hash("position"):
setValueFromOpcode(opcode, position, Default::positionRange); if (auto value = readOpcode(opcode.value, Default::positionRange))
position = normalizePercents(*value);
break; break;
case hash("position_oncc&"): 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; break;
case hash("width"): case hash("width"):
setValueFromOpcode(opcode, width, Default::widthRange); if (auto value = readOpcode(opcode.value, Default::widthRange))
width = normalizePercents(*value);
break; break;
case hash("width_oncc&"): 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; break;
case hash("amp_keycenter"): case hash("amp_keycenter"):
setValueFromOpcode(opcode, ampKeycenter, Default::keyRange); setValueFromOpcode(opcode, ampKeycenter, Default::keyRange);

View file

@ -277,10 +277,10 @@ 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
CCMap<float> amplitudeCC { Default::amplitude }; // amplitude_oncc CCMap<float> amplitudeCC { Default::zeroModifier }; // amplitude_oncc
absl::optional<CCValuePair<float>> panCC; // pan_oncc CCMap<float> panCC { Default::zeroModifier }; // pan_oncc
absl::optional<CCValuePair<float>> widthCC; // width_oncc CCMap<float> widthCC { Default::zeroModifier }; // width_oncc
absl::optional<CCValuePair<float>> positionCC; // position_oncc CCMap<float> positionCC { Default::zeroModifier }; // position_oncc
uint8_t ampKeycenter { Default::ampKeycenter }; // amp_keycenter uint8_t ampKeycenter { Default::ampKeycenter }; // amp_keycenter
float ampKeytrack { Default::ampKeytrack }; // amp_keytrack float ampKeytrack { Default::ampKeytrack }; // amp_keytrack
float ampVeltrack { Default::ampVeltrack }; // 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) if (triggerType != TriggerType::CC)
baseGain *= region->getNoteGain(number, value); 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){ pitchBendEnvelope.setFunction([region](float pitchValue){
const auto normalizedBend = normalizeBend(pitchValue); const auto normalizedBend = normalizeBend(pitchValue);
const auto bendInCents = normalizedBend > 0.0f ? normalizedBend * static_cast<float>(region->bendUp) : -normalizedBend * static_cast<float>(region->bendDown); 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 }; const float newVolumedB { baseVolumedB + ccValue * region->volumeCC->value };
volumeEnvelope.registerEvent(delay, db2mag(Default::volumeRange.clamp(newVolumedB))); 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 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); copy<float>(leftBuffer, rightBuffer);
// Apply panning // 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); pan<float>(modulationSpan, leftBuffer, rightBuffer);
} }
} }
@ -431,13 +400,20 @@ void sfz::Voice::processStereo(AudioSpan<float> buffer) noexcept
ScopedTiming logger { panningDuration }; ScopedTiming logger { panningDuration };
// Apply panning // 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); pan<float>(modulationSpan, leftBuffer, rightBuffer);
// Apply the width/position process // 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); 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); pan<float>(modulationSpan, leftBuffer, rightBuffer);
} }

View file

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