Added the pan envelope

This commit is contained in:
paulfd 2019-09-07 14:03:44 +02:00
parent c1d2384e09
commit 83fbfc1fcb
6 changed files with 47 additions and 11 deletions

View file

@ -41,7 +41,6 @@ public:
void clear();
void reset(Type value = 0.0);
void getBlock(absl::Span<Type> output);
private:
std::function<Type(Type)> function { [](Type input) { return input; } };
static_assert(std::is_arithmetic<Type>::value);

View file

@ -712,7 +712,7 @@ float sfz::Region::getNoteGain(int noteNumber, uint8_t velocity) noexcept
return baseGain;
}
float sfz::Region::getCCGain(const sfz::CCValueArray& ccState) noexcept
float sfz::Region::getCrossfadeGain(const sfz::CCValueArray& ccState) noexcept
{
float gain { 1.0f };

View file

@ -56,7 +56,7 @@ struct Region {
bool isStereo() const noexcept;
float getBasePitchVariation(int noteNumber, uint8_t velocity) noexcept;
float getNoteGain(int noteNumber, uint8_t velocity) noexcept;
float getCCGain(const CCValueArray& ccState) noexcept;
float getCrossfadeGain(const CCValueArray& ccState) noexcept;
float getBaseGain() noexcept;
float velocityGain(uint8_t velocity) const noexcept;
uint32_t getOffset() noexcept;

View file

@ -53,6 +53,12 @@ inline constexpr float normalizePercents(T percentValue)
return std::min(std::max(static_cast<float>(percentValue), 0.0f), 100.0f) / 100.0f;
}
template<class T>
inline constexpr float normalizeNegativePercents(T percentValue)
{
return std::min(std::max(static_cast<float>(percentValue), -100.0f), 100.0f) / 100.0f;
}
inline float ccSwitchedValue(const CCValueArray& ccValues, const std::optional<CCValuePair>& ccSwitch, float value) noexcept
{
if (ccSwitch)

View file

@ -22,6 +22,7 @@
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "Voice.h"
#include "AudioSpan.h"
#include "Defaults.h"
#include "SIMDHelpers.h"
#include "SfzHelpers.h"
@ -50,15 +51,24 @@ void sfz::Voice::startVoice(Region* region, int delay, int channel, int number,
state = State::playing;
speedRatio = static_cast<float>(region->sampleRate / this->sampleRate);
pitchRatio = region->getBasePitchVariation(number, value);
baseGain = region->getBaseGain();
if (triggerType != TriggerType::CC)
baseGain *= region->getNoteGain(number, value);
baseGain *= region->getCCGain(ccState);
baseGain *= region->getCrossfadeGain(ccState);
if (region->amplitudeCC)
baseGain *= normalizeCC(ccState[region->amplitudeCC->first]) * normalizePercents(region->amplitudeCC->second);
amplitudeEnvelope.reset(baseGain);
basePan = normalizeNegativePercents(region->pan);
auto pan = basePan;
if (region->panCC)
pan += normalizeCC(ccState[region->amplitudeCC->first]) * normalizeNegativePercents(region->amplitudeCC->second);
panEnvelope.reset(pan);
DBG("Base Panning: " << pan);
sourcePosition = region->getOffset();
floatPosition = static_cast<float>(sourcePosition);
initialDelay = delay + region->getDelay();
baseFrequency = midiNoteFrequency(number) * pitchRatio;
prepareEGEnvelope(delay, value);
@ -129,6 +139,11 @@ void sfz::Voice::registerCC(int delay, int channel [[maybe_unused]], int ccNumbe
const float newGain { normalizeCC(ccValue) * normalizePercents(region->amplitudeCC->second) * baseGain };
amplitudeEnvelope.registerEvent(delay, newGain);
}
if (region->panCC && ccNumber == region->panCC->first) {
const float newPan { basePan + normalizeCC(ccValue) * normalizeNegativePercents(region->amplitudeCC->second)};
panEnvelope.registerEvent(delay, newPan);
}
}
void sfz::Voice::registerPitchWheel(int delay [[maybe_unused]], int channel [[maybe_unused]], int pitch [[maybe_unused]]) noexcept
@ -190,15 +205,31 @@ void sfz::Voice::processMono(AudioSpan<float> buffer) noexcept
auto leftBuffer = buffer.getSpan(0);
auto rightBuffer = buffer.getSpan(1);
auto envelopeSpan = tempSpan1.first(numSamples);
amplitudeEnvelope.getBlock(envelopeSpan);
::applyGain<float>(envelopeSpan, leftBuffer);
auto span1 = tempSpan1.first(numSamples);
auto span2 = tempSpan2.first(numSamples);
egEnvelope.getBlock(envelopeSpan);
::applyGain<float>(envelopeSpan, leftBuffer);
// Amplitude envelope
amplitudeEnvelope.getBlock(span1);
::applyGain<float>(span1, leftBuffer);
// AmpEG envelope
egEnvelope.getBlock(span1);
::applyGain<float>(span1, leftBuffer);
// Prepare for stereo output
::copy<float>(leftBuffer, rightBuffer);
panEnvelope.getBlock(span1);
// We assume that the pan envelope is already normalized between -1 and 1
::fill<float>(span2, 1.0f);
::add<float>(span1, span2);
::applyGain<float>(piFour<float>, span2);
::cos<float>(span2, span1);
::sin<float>(span2, span2);
::applyGain<float>(span1, leftBuffer);
::applyGain<float>(span2, rightBuffer);
}
void sfz::Voice::processStereo(AudioSpan<float> buffer) noexcept
{
const auto numSamples = buffer.getNumFrames();

View file

@ -90,6 +90,7 @@ private:
float speedRatio { 1.0 };
float pitchRatio { 1.0 };
float baseGain { 1.0 };
float basePan { 0.0 };
float baseFrequency { 440.0 };
float phase { 0.0f };
@ -113,8 +114,7 @@ private:
const CCValueArray& ccState;
ADSREnvelope<float> egEnvelope;
LinearEnvelope<float> amplitudeEnvelope;
LinearEnvelope<float> leftPanEnvelope;
LinearEnvelope<float> rightPanEnvelope;
LinearEnvelope<float> panEnvelope;
LEAK_DETECTOR(Voice);
};