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);
|
||||
xfadeSmoother.setSmoothing(config::xfadeSmoothing, sampleRate);
|
||||
|
||||
// prepare curves
|
||||
getSCurve();
|
||||
}
|
||||
|
||||
sfz::Voice::~Voice()
|
||||
|
|
@ -626,7 +629,9 @@ void sfz::Voice::fillWithData(AudioSpan<float> buffer) noexcept
|
|||
}
|
||||
|
||||
// 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
|
||||
if (isLooping) {
|
||||
|
|
@ -715,12 +720,17 @@ void sfz::Voice::fillWithData(AudioSpan<float> buffer) noexcept
|
|||
{
|
||||
// compute out curve
|
||||
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);
|
||||
for (unsigned i = 0; i < ptSize; ++i)
|
||||
xfCurve[i] = xfOut.evalNormalized(xfCoeff[i]);
|
||||
}
|
||||
else {
|
||||
else IF_CONSTEXPR (loopXfadeUseCurves == 0) {
|
||||
// TODO(jpc) vectorize this
|
||||
for (unsigned i = 0; i < ptSize; ++i)
|
||||
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
|
||||
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);
|
||||
for (unsigned i = 0; i < applySize; ++i)
|
||||
xfCurve[i] = xfIn.evalNormalized(xfInCoeff[i]);
|
||||
}
|
||||
else {
|
||||
else IF_CONSTEXPR (loopXfadeUseCurves == 0) {
|
||||
// TODO(jpc) vectorize this
|
||||
for (unsigned i = 0; i < applySize; ++i)
|
||||
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
|
||||
{
|
||||
const auto leftSpan = buffer.getSpan(0);
|
||||
|
|
|
|||
|
|
@ -396,6 +396,11 @@ private:
|
|||
absl::Span<const int> indices, absl::Span<const float> coeffs,
|
||||
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
|
||||
* or stereo buffer
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue