Crossfade with S-shape curve
This commit is contained in:
parent
453d489d4a
commit
893d0361c2
2 changed files with 39 additions and 5 deletions
|
|
@ -34,6 +34,9 @@ sfz::Voice::Voice(int voiceNumber, sfz::Resources& resources)
|
||||||
|
|
||||||
gainSmoother.setSmoothing(config::gainSmoothing, sampleRate);
|
gainSmoother.setSmoothing(config::gainSmoothing, sampleRate);
|
||||||
xfadeSmoother.setSmoothing(config::xfadeSmoothing, sampleRate);
|
xfadeSmoother.setSmoothing(config::xfadeSmoothing, sampleRate);
|
||||||
|
|
||||||
|
// prepare curves
|
||||||
|
getSCurve();
|
||||||
}
|
}
|
||||||
|
|
||||||
sfz::Voice::~Voice()
|
sfz::Voice::~Voice()
|
||||||
|
|
@ -626,7 +629,9 @@ void sfz::Voice::fillWithData(AudioSpan<float> buffer) noexcept
|
||||||
}
|
}
|
||||||
|
|
||||||
// loop crossfade settings
|
// loop crossfade settings
|
||||||
constexpr bool loopXfadeUseCurves = false; // 0: linear, 1: use curves 5 & 6
|
constexpr int loopXfadeUseCurves = 2; // 0: linear
|
||||||
|
// 1: use curves 5 & 6
|
||||||
|
// 2: use S-shaped curve
|
||||||
|
|
||||||
// index preprocessing for loops
|
// index preprocessing for loops
|
||||||
if (isLooping) {
|
if (isLooping) {
|
||||||
|
|
@ -715,12 +720,17 @@ void sfz::Voice::fillWithData(AudioSpan<float> buffer) noexcept
|
||||||
{
|
{
|
||||||
// compute out curve
|
// compute out curve
|
||||||
absl::Span<float> xfCurve = xfadeTemp[1]->first(ptSize);
|
absl::Span<float> xfCurve = xfadeTemp[1]->first(ptSize);
|
||||||
IF_CONSTEXPR (loopXfadeUseCurves) {
|
IF_CONSTEXPR (loopXfadeUseCurves == 2) {
|
||||||
|
const Curve& xfIn = getSCurve();
|
||||||
|
for (unsigned i = 0; i < ptSize; ++i)
|
||||||
|
xfCurve[i] = xfIn.evalNormalized(1.0f - xfCoeff[i]);
|
||||||
|
}
|
||||||
|
else IF_CONSTEXPR (loopXfadeUseCurves == 1) {
|
||||||
const Curve& xfOut = resources.curves.getCurve(6);
|
const Curve& xfOut = resources.curves.getCurve(6);
|
||||||
for (unsigned i = 0; i < ptSize; ++i)
|
for (unsigned i = 0; i < ptSize; ++i)
|
||||||
xfCurve[i] = xfOut.evalNormalized(xfCoeff[i]);
|
xfCurve[i] = xfOut.evalNormalized(xfCoeff[i]);
|
||||||
}
|
}
|
||||||
else {
|
else IF_CONSTEXPR (loopXfadeUseCurves == 0) {
|
||||||
// TODO(jpc) vectorize this
|
// TODO(jpc) vectorize this
|
||||||
for (unsigned i = 0; i < ptSize; ++i)
|
for (unsigned i = 0; i < ptSize; ++i)
|
||||||
xfCurve[i] = clamp(1.0f - xfCoeff[i], 0.0f, 1.0f);
|
xfCurve[i] = clamp(1.0f - xfCoeff[i], 0.0f, 1.0f);
|
||||||
|
|
@ -763,12 +773,17 @@ void sfz::Voice::fillWithData(AudioSpan<float> buffer) noexcept
|
||||||
|
|
||||||
// compute in curve
|
// compute in curve
|
||||||
absl::Span<float> xfCurve = xfadeTemp[1]->first(applySize);
|
absl::Span<float> xfCurve = xfadeTemp[1]->first(applySize);
|
||||||
IF_CONSTEXPR (loopXfadeUseCurves) {
|
IF_CONSTEXPR (loopXfadeUseCurves == 2) {
|
||||||
|
const Curve& xfIn = getSCurve();
|
||||||
|
for (unsigned i = 0; i < applySize; ++i)
|
||||||
|
xfCurve[i] = xfIn.evalNormalized(xfInCoeff[i]);
|
||||||
|
}
|
||||||
|
else IF_CONSTEXPR (loopXfadeUseCurves == 1) {
|
||||||
const Curve& xfIn = resources.curves.getCurve(5);
|
const Curve& xfIn = resources.curves.getCurve(5);
|
||||||
for (unsigned i = 0; i < applySize; ++i)
|
for (unsigned i = 0; i < applySize; ++i)
|
||||||
xfCurve[i] = xfIn.evalNormalized(xfInCoeff[i]);
|
xfCurve[i] = xfIn.evalNormalized(xfInCoeff[i]);
|
||||||
}
|
}
|
||||||
else {
|
else IF_CONSTEXPR (loopXfadeUseCurves == 0) {
|
||||||
// TODO(jpc) vectorize this
|
// TODO(jpc) vectorize this
|
||||||
for (unsigned i = 0; i < applySize; ++i)
|
for (unsigned i = 0; i < applySize; ++i)
|
||||||
xfCurve[i] = clamp(xfInCoeff[i], 0.0f, 1.0f);
|
xfCurve[i] = clamp(xfInCoeff[i], 0.0f, 1.0f);
|
||||||
|
|
@ -865,6 +880,20 @@ void sfz::Voice::fillInterpolatedWithQuality(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const sfz::Curve& sfz::Voice::getSCurve()
|
||||||
|
{
|
||||||
|
static const Curve curve = []() -> Curve {
|
||||||
|
constexpr unsigned N = Curve::NumValues;
|
||||||
|
float values[N];
|
||||||
|
for (unsigned i = 0; i < N; ++i) {
|
||||||
|
double x = i / static_cast<double>(N - 1);
|
||||||
|
values[i] = (1.0 - std::cos(M_PI * x)) * 0.5;
|
||||||
|
}
|
||||||
|
return Curve::buildFromPoints(values);
|
||||||
|
}();
|
||||||
|
return curve;
|
||||||
|
}
|
||||||
|
|
||||||
void sfz::Voice::fillWithGenerator(AudioSpan<float> buffer) noexcept
|
void sfz::Voice::fillWithGenerator(AudioSpan<float> buffer) noexcept
|
||||||
{
|
{
|
||||||
const auto leftSpan = buffer.getSpan(0);
|
const auto leftSpan = buffer.getSpan(0);
|
||||||
|
|
|
||||||
|
|
@ -396,6 +396,11 @@ private:
|
||||||
absl::Span<const int> indices, absl::Span<const float> coeffs,
|
absl::Span<const int> indices, absl::Span<const float> coeffs,
|
||||||
absl::Span<const float> addingGains, int quality);
|
absl::Span<const float> addingGains, int quality);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get a S-shaped curve that is applicable to loop crossfading.
|
||||||
|
*/
|
||||||
|
static const Curve& getSCurve();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Compute the amplitude envelope, applied as a gain to a mono
|
* @brief Compute the amplitude envelope, applied as a gain to a mono
|
||||||
* or stereo buffer
|
* or stereo buffer
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue