Compute loop information at the start of the voice The check for actual looping is still done in the render method, to see if we do have enough samples

This commit is contained in:
Paul Ferrand 2020-10-05 13:48:21 +02:00 committed by Jean Pierre Cimalando
parent 9f698aea4c
commit 8f3be5ca3c
2 changed files with 60 additions and 22 deletions

View file

@ -99,6 +99,7 @@ void sfz::Voice::startVoice(Region* region, int delay, const TriggerEvent& event
switchState(State::cleanMeUp);
return;
}
updateLoopInformation();
speedRatio = static_cast<float>(currentPromise->sampleRate / this->sampleRate);
}
@ -558,26 +559,11 @@ void sfz::Voice::fillWithData(AudioSpan<float> buffer) noexcept
}
// calculate loop characteristics
bool isLooping = false;
int loopStart = 0;
int loopEnd = 0;
int loopSize = 0;
int loopXfadeSize = 0;
int loopXfOutStart = 0;
int loopXfInStart = 0; // Note: beware in case of negative index
const bool isLooping = region->shouldLoop()
&& (static_cast<size_t>(loop.end) < source.getNumFrames());
SpanHolder<absl::Span<float>> xfadeTemp[2];
SpanHolder<absl::Span<int>> xfadeIndexTemp[1];
if (region->shouldLoop()) {
loopEnd = region->loopEnd(currentPromise->oversamplingFactor);
isLooping = static_cast<size_t>(loopEnd) < source.getNumFrames();
}
if (isLooping) {
loopStart = static_cast<int>(region->loopStart(currentPromise->oversamplingFactor));
loopSize = loopEnd + 1 - loopStart;
loopXfadeSize = static_cast<int>(
lroundPositive(region->loopCrossfade * static_cast<int>(currentPromise->oversamplingFactor) * currentPromise->sampleRate));
loopXfOutStart = loopEnd + 1 - loopXfadeSize;
loopXfInStart = loopStart - loopXfadeSize;
for (auto& buf : xfadeTemp) {
buf = resources.bufferPool.getBuffer(numSamples);
if (!buf)
@ -642,12 +628,12 @@ void sfz::Voice::fillWithData(AudioSpan<float> buffer) noexcept
int index = (*indices)[i];
// wrap indices post loop-entry around the loop segment
int wrappedIndex = (index <= loopEnd) ? index :
(loopStart + (index - loopStart) % loopSize);
int wrappedIndex = (index <= loop.end) ? index :
(loop.start + (index - loop.start) % loop.size);
(*indices)[i] = wrappedIndex;
// identify the partition this index is in
bool xfading = wrappedIndex >= loopStart && wrappedIndex >= loopXfOutStart;
bool xfading = wrappedIndex >= loop.start && wrappedIndex >= loop.xfOutStart;
int partitionType = xfading ? kPartitionLoopXfade : kPartitionNormal;
// if looping or entering a different type, start a new partition
bool start = i == 0 || wrappedIndex < oldIndex || partitionType != oldPartitionType;
@ -712,7 +698,7 @@ void sfz::Voice::fillWithData(AudioSpan<float> buffer) noexcept
// compute crossfade positions
for (unsigned i = 0; i < ptSize; ++i) {
float pos = ptIndices[i] + ptCoeffs[i];
xfCurvePos[i] = (pos - loopXfOutStart) / loopXfadeSize;
xfCurvePos[i] = (pos - loop.xfOutStart) / loop.xfSize;
}
//----------------------------------------------------------------//
@ -752,7 +738,7 @@ void sfz::Voice::fillWithData(AudioSpan<float> buffer) noexcept
// compute indices of the crossfade input segment
absl::Span<int> xfInIndices = xfadeIndexTemp[0]->first(ptSize);
absl::c_copy(ptIndices, xfInIndices.begin());
subtract1(loopXfOutStart - loopXfInStart, xfInIndices);
subtract1(loop.xfOutStart - loop.xfInStart, xfInIndices);
// disregard the segment whose indices have been pushed
// into the negatives, take these virtually as zeroes.
@ -1067,6 +1053,8 @@ void sfz::Voice::reset() noexcept
floatPositionOffset = 0.0f;
noteIsOff = false;
resetLoopInformation();
powerFollower.clear();
for (auto& filter : filters)
@ -1078,6 +1066,37 @@ void sfz::Voice::reset() noexcept
removeVoiceFromRing();
}
void sfz::Voice::resetLoopInformation() noexcept
{
loop.start = 0;
loop.end = 0;
loop.size = 0;
loop.xfSize = 0;
loop.xfOutStart = 0;
loop.xfInStart = 0;
}
void sfz::Voice::updateLoopInformation() noexcept
{
if (!region || !currentPromise)
return;
if (!region->shouldLoop())
return;
const auto factor = currentPromise->oversamplingFactor;
const auto rate = currentPromise->sampleRate;
loop.end = static_cast<int>(region->loopEnd(factor));
loop.start = static_cast<int>(region->loopStart(factor));
loop.size = loop.end + 1 - loop.start;
loop.xfSize = static_cast<int>(
lroundPositive(region->loopCrossfade * static_cast<int>(factor) * rate)
);
loop.xfOutStart = loop.end + 1 - loop.xfSize;
loop.xfInStart = loop.start - loop.xfSize;
}
void sfz::Voice::setNextSisterVoice(Voice* voice) noexcept
{
// Should never be null

View file

@ -496,6 +496,25 @@ private:
int sourcePosition { 0 };
int initialDelay { 0 };
int age { 0 };
struct {
int start { 0 };
int end { 0 };
int size { 0 };
int xfSize { 0 };
int xfOutStart { 0 };
int xfInStart { 0 };
} loop;
/**
* @brief Reset the loop information
*
*/
void resetLoopInformation() noexcept;
/**
* @brief Read the loop information data from the region.
* This requires that the region and promise is properly set.
*
*/
void updateLoopInformation() noexcept;
FilePromisePtr currentPromise { nullptr };