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