multiplicativeEnvelope free function for pitch
This commit is contained in:
parent
9e3f496f9e
commit
088da9df65
4 changed files with 44 additions and 23 deletions
|
|
@ -157,10 +157,15 @@ void sfz::MidiState::resetAllControllers(int delay) noexcept
|
||||||
pitchBendEvent(delay, 0.0f);
|
pitchBendEvent(delay, 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
const sfz::EventVector& sfz::MidiState::getEvents(int ccIdx) const noexcept
|
const sfz::EventVector& sfz::MidiState::getCCEvents(int ccIdx) const noexcept
|
||||||
{
|
{
|
||||||
if (ccIdx < 0 || ccIdx > config::numCCs)
|
if (ccIdx < 0 || ccIdx > config::numCCs)
|
||||||
return nullEvent;
|
return nullEvent;
|
||||||
|
|
||||||
return cc[ccIdx];
|
return cc[ccIdx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const sfz::EventVector& sfz::MidiState::getPitchEvents() const noexcept
|
||||||
|
{
|
||||||
|
return pitchEvents;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,8 @@ public:
|
||||||
*/
|
*/
|
||||||
void resetAllControllers(int delay) noexcept;
|
void resetAllControllers(int delay) noexcept;
|
||||||
|
|
||||||
const EventVector& getEvents(int ccIdx) const noexcept;
|
const EventVector& getCCEvents(int ccIdx) const noexcept;
|
||||||
|
const EventVector& getPitchEvents() const noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -373,7 +373,7 @@ void multiplicativeEnvelope(const EventVector& events, absl::Span<float> envelop
|
||||||
const auto event = events[i];
|
const auto event = events[i];
|
||||||
const auto length = event.delay - lastDelay;
|
const auto length = event.delay - lastDelay;
|
||||||
const auto nextValue = lambda(event.value);
|
const auto nextValue = lambda(event.value);
|
||||||
const auto step = std::exp((std::log(nextValue) - std::log(currentValue)) / length);
|
const auto step = std::exp((std::log(nextValue) - std::log(lastValue)) / length);
|
||||||
multiplicativeRamp<float>(envelope.subspan(lastDelay, length), lastValue, step);
|
multiplicativeRamp<float>(envelope.subspan(lastDelay, length), lastValue, step);
|
||||||
lastValue = nextValue;
|
lastValue = nextValue;
|
||||||
lastDelay += length;
|
lastDelay += length;
|
||||||
|
|
|
||||||
|
|
@ -187,7 +187,7 @@ void sfz::Voice::registerPitchWheel(int delay, float pitch) noexcept
|
||||||
if (state == State::idle)
|
if (state == State::idle)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pitchBendEnvelope.registerEvent(delay, pitch * 8191.0f);
|
pitchBendEnvelope.registerEvent(delay, pitch);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sfz::Voice::registerAftertouch(int delay, uint8_t aftertouch) noexcept
|
void sfz::Voice::registerAftertouch(int delay, uint8_t aftertouch) noexcept
|
||||||
|
|
@ -272,7 +272,7 @@ void sfz::Voice::ampStageMono(AudioSpan<float> buffer) noexcept
|
||||||
// Amplitude envelope
|
// Amplitude envelope
|
||||||
fill<float>(*modulationSpan, baseGain);
|
fill<float>(*modulationSpan, baseGain);
|
||||||
for (auto& mod : region->amplitudeCC) {
|
for (auto& mod : region->amplitudeCC) {
|
||||||
const auto events = resources.midiState.getEvents(mod.cc);
|
const auto events = resources.midiState.getCCEvents(mod.cc);
|
||||||
linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.value; });
|
linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.value; });
|
||||||
applyGain<float>(*tempSpan, *modulationSpan);
|
applyGain<float>(*tempSpan, *modulationSpan);
|
||||||
}
|
}
|
||||||
|
|
@ -281,12 +281,12 @@ void sfz::Voice::ampStageMono(AudioSpan<float> buffer) noexcept
|
||||||
// Crossfade envelopes
|
// Crossfade envelopes
|
||||||
fill<float>(*modulationSpan, 1.0f);
|
fill<float>(*modulationSpan, 1.0f);
|
||||||
for (auto& mod : region->crossfadeCCInRange) {
|
for (auto& mod : region->crossfadeCCInRange) {
|
||||||
const auto events = resources.midiState.getEvents(mod.cc);
|
const auto events = resources.midiState.getCCEvents(mod.cc);
|
||||||
linearEnvelope(events, *tempSpan, [&](float x) { return crossfadeIn(mod.value, x, xfCurve); });
|
linearEnvelope(events, *tempSpan, [&](float x) { return crossfadeIn(mod.value, x, xfCurve); });
|
||||||
applyGain<float>(*tempSpan, *modulationSpan);
|
applyGain<float>(*tempSpan, *modulationSpan);
|
||||||
}
|
}
|
||||||
for (auto& mod : region->crossfadeCCOutRange) {
|
for (auto& mod : region->crossfadeCCOutRange) {
|
||||||
const auto events = resources.midiState.getEvents(mod.cc);
|
const auto events = resources.midiState.getCCEvents(mod.cc);
|
||||||
linearEnvelope(events, *tempSpan, [&](float x) { return crossfadeOut(mod.value, x, xfCurve); });
|
linearEnvelope(events, *tempSpan, [&](float x) { return crossfadeOut(mod.value, x, xfCurve); });
|
||||||
applyGain<float>(*tempSpan, *modulationSpan);
|
applyGain<float>(*tempSpan, *modulationSpan);
|
||||||
}
|
}
|
||||||
|
|
@ -317,25 +317,26 @@ void sfz::Voice::ampStageStereo(AudioSpan<float> buffer) noexcept
|
||||||
// Amplitude envelope
|
// Amplitude envelope
|
||||||
fill<float>(*modulationSpan, baseGain);
|
fill<float>(*modulationSpan, baseGain);
|
||||||
for (auto& mod : region->amplitudeCC) {
|
for (auto& mod : region->amplitudeCC) {
|
||||||
const auto events = resources.midiState.getEvents(mod.cc);
|
const auto events = resources.midiState.getCCEvents(mod.cc);
|
||||||
linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.value; });
|
linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.value; });
|
||||||
applyGain<float>(*tempSpan, *modulationSpan);
|
applyGain<float>(*tempSpan, *modulationSpan);
|
||||||
}
|
}
|
||||||
buffer.applyGain(*modulationSpan);
|
buffer.applyGain(*modulationSpan);
|
||||||
|
|
||||||
|
|
||||||
// Crossfade envelopes
|
// Crossfade envelopes
|
||||||
fill<float>(*modulationSpan, 1.0f);
|
fill<float>(*modulationSpan, 1.0f);
|
||||||
for (auto& mod : region->crossfadeCCInRange) {
|
for (auto& mod : region->crossfadeCCInRange) {
|
||||||
const auto events = resources.midiState.getEvents(mod.cc);
|
const auto events = resources.midiState.getCCEvents(mod.cc);
|
||||||
linearEnvelope(events, *tempSpan, [&](float x) { return crossfadeIn(mod.value, x, xfCurve); });
|
linearEnvelope(events, *tempSpan, [&](float x) { return crossfadeIn(mod.value, x, xfCurve); });
|
||||||
applyGain<float>(*tempSpan, *modulationSpan);
|
applyGain<float>(*tempSpan, *modulationSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& mod : region->crossfadeCCOutRange) {
|
for (auto& mod : region->crossfadeCCOutRange) {
|
||||||
const auto events = resources.midiState.getEvents(mod.cc);
|
const auto events = resources.midiState.getCCEvents(mod.cc);
|
||||||
linearEnvelope(events, *tempSpan, [&](float x) { return crossfadeOut(mod.value, x, xfCurve); });
|
linearEnvelope(events, *tempSpan, [&](float x) { return crossfadeOut(mod.value, x, xfCurve); });
|
||||||
applyGain<float>(*tempSpan, *modulationSpan);
|
applyGain<float>(*tempSpan, *modulationSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.applyGain(*modulationSpan);
|
buffer.applyGain(*modulationSpan);
|
||||||
|
|
||||||
// Volume envelope
|
// Volume envelope
|
||||||
|
|
@ -366,7 +367,7 @@ void sfz::Voice::panStageMono(AudioSpan<float> buffer) noexcept
|
||||||
// Apply panning
|
// Apply panning
|
||||||
fill<float>(*modulationSpan, region->pan);
|
fill<float>(*modulationSpan, region->pan);
|
||||||
for (auto& mod : region->panCC) {
|
for (auto& mod : region->panCC) {
|
||||||
const auto events = resources.midiState.getEvents(mod.cc);
|
const auto events = resources.midiState.getCCEvents(mod.cc);
|
||||||
linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.value; });
|
linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.value; });
|
||||||
add<float>(*tempSpan, *modulationSpan);
|
add<float>(*tempSpan, *modulationSpan);
|
||||||
}
|
}
|
||||||
|
|
@ -389,7 +390,7 @@ void sfz::Voice::panStageStereo(AudioSpan<float> buffer) noexcept
|
||||||
// panningModulation(*modulationSpan);
|
// panningModulation(*modulationSpan);
|
||||||
fill<float>(*modulationSpan, region->pan);
|
fill<float>(*modulationSpan, region->pan);
|
||||||
for (auto& mod : region->panCC) {
|
for (auto& mod : region->panCC) {
|
||||||
const auto events = resources.midiState.getEvents(mod.cc);
|
const auto events = resources.midiState.getCCEvents(mod.cc);
|
||||||
linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.value; });
|
linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.value; });
|
||||||
add<float>(*tempSpan, *modulationSpan);
|
add<float>(*tempSpan, *modulationSpan);
|
||||||
}
|
}
|
||||||
|
|
@ -399,7 +400,7 @@ void sfz::Voice::panStageStereo(AudioSpan<float> buffer) noexcept
|
||||||
// widthModulation(*modulationSpan);
|
// widthModulation(*modulationSpan);
|
||||||
fill<float>(*modulationSpan, region->width);
|
fill<float>(*modulationSpan, region->width);
|
||||||
for (auto& mod : region->widthCC) {
|
for (auto& mod : region->widthCC) {
|
||||||
const auto events = resources.midiState.getEvents(mod.cc);
|
const auto events = resources.midiState.getCCEvents(mod.cc);
|
||||||
linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.value; });
|
linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.value; });
|
||||||
add<float>(*tempSpan, *modulationSpan);
|
add<float>(*tempSpan, *modulationSpan);
|
||||||
}
|
}
|
||||||
|
|
@ -408,7 +409,7 @@ void sfz::Voice::panStageStereo(AudioSpan<float> buffer) noexcept
|
||||||
// positionModulation(*modulationSpan);
|
// positionModulation(*modulationSpan);
|
||||||
fill<float>(*modulationSpan, region->position);
|
fill<float>(*modulationSpan, region->position);
|
||||||
for (auto& mod : region->positionCC) {
|
for (auto& mod : region->positionCC) {
|
||||||
const auto events = resources.midiState.getEvents(mod.cc);
|
const auto events = resources.midiState.getCCEvents(mod.cc);
|
||||||
linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.value; });
|
linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.value; });
|
||||||
add<float>(*tempSpan, *modulationSpan);
|
add<float>(*tempSpan, *modulationSpan);
|
||||||
}
|
}
|
||||||
|
|
@ -472,10 +473,17 @@ void sfz::Voice::fillWithData(AudioSpan<float> buffer) noexcept
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fill<float>(*jumps, pitchRatio * speedRatio);
|
fill<float>(*jumps, pitchRatio * speedRatio);
|
||||||
if (region->bendStep > 1)
|
// if (region->bendStep > 1)
|
||||||
pitchBendEnvelope.getQuantizedBlock(*bends, bendStepFactor);
|
// pitchBendEnvelope.getQuantizedBlock(*bends, bendStepFactor);
|
||||||
else
|
// else
|
||||||
pitchBendEnvelope.getBlock(*bends);
|
// pitchBendEnvelope.getBlock(*bends);
|
||||||
|
const auto events = resources.midiState.getPitchEvents();
|
||||||
|
const auto bendLambda = [this](float bend){
|
||||||
|
const auto bendInCents = bend > 0.0f ? bend * static_cast<float>(region->bendUp) : -bend * static_cast<float>(region->bendDown);
|
||||||
|
return centsFactor(bendInCents);
|
||||||
|
};
|
||||||
|
multiplicativeEnvelope(events, *bends, bendLambda);
|
||||||
|
DBG("Bend: " << bends->back());
|
||||||
|
|
||||||
applyGain<float>(*bends, *jumps);
|
applyGain<float>(*bends, *jumps);
|
||||||
jumps->front() += floatPositionOffset;
|
jumps->front() += floatPositionOffset;
|
||||||
|
|
@ -558,11 +566,18 @@ void sfz::Voice::fillWithGenerator(AudioSpan<float> buffer) noexcept
|
||||||
float keycenterFrequency = midiNoteFrequency(region->pitchKeycenter);
|
float keycenterFrequency = midiNoteFrequency(region->pitchKeycenter);
|
||||||
fill<float>(*frequencies, pitchRatio * keycenterFrequency);
|
fill<float>(*frequencies, pitchRatio * keycenterFrequency);
|
||||||
|
|
||||||
if (region->bendStep > 1)
|
const auto events = resources.midiState.getPitchEvents();
|
||||||
pitchBendEnvelope.getQuantizedBlock(*bends, bendStepFactor);
|
const auto bendLambda = [this](float bend){
|
||||||
else
|
const auto bendInCents = bend > 0.0f ? bend * static_cast<float>(region->bendUp) : -bend * static_cast<float>(region->bendDown);
|
||||||
pitchBendEnvelope.getBlock(*bends);
|
return centsFactor(bendInCents);
|
||||||
|
};
|
||||||
|
// if (region->bendStep > 1)
|
||||||
|
// pitchBendEnvelope.getQuantizedBlock(*bends, bendStepFactor);
|
||||||
|
// else
|
||||||
|
// pitchBendEnvelope.getBlock(*bends);
|
||||||
|
|
||||||
|
multiplicativeEnvelope(events, *bends, bendLambda);
|
||||||
|
DBG("Bend: " << bends->back());
|
||||||
applyGain<float>(*bends, *frequencies);
|
applyGain<float>(*bends, *frequencies);
|
||||||
|
|
||||||
waveOscillator.processModulated(frequencies->data(), leftSpan.data(), buffer.getNumFrames());
|
waveOscillator.processModulated(frequencies->data(), leftSpan.data(), buffer.getNumFrames());
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue