Advance the generator when not used

This commit is contained in:
Jean Pierre Cimalando 2020-07-27 19:14:30 +02:00
parent 6bb4b7c83e
commit 97702e4308
4 changed files with 65 additions and 2 deletions

View file

@ -723,6 +723,7 @@ void sfz::Synth::renderBlock(AudioSpan<float> buffer) noexcept
}
ModMatrix& mm = resources.modMatrix;
mm.beginCycle(numFrames);
activeVoices = 0;
{ // Main render block
@ -731,8 +732,6 @@ void sfz::Synth::renderBlock(AudioSpan<float> buffer) noexcept
tempMixSpan->fill(0.0f);
resources.filePool.cleanupPromises();
mm.beginCycle(numFrames);
// Ramp out whatever is in the buffer at this point; should only be killed voice data
linearRamp<float>(*rampSpan, 1.0f, -1.0f / static_cast<float>(numFrames));
for (size_t i = 0, n = effectBuses.size(); i < n; ++i) {
@ -754,6 +753,8 @@ void sfz::Synth::renderBlock(AudioSpan<float> buffer) noexcept
callbackBreakdown.filters += voice->getLastFilterDuration();
callbackBreakdown.panning += voice->getLastPanningDuration();
mm.endVoice();
if (voice->toBeCleanedUp())
voice->reset();
}
@ -781,6 +782,9 @@ void sfz::Synth::renderBlock(AudioSpan<float> buffer) noexcept
// Apply the master volume
buffer.applyGain(db2mag(volume));
// Perform any remaining modulators
mm.endCycle();
{ // Clear events and advance midi time
ScopedTiming logger { dispatchDuration, ScopedTiming::Operation::addToDuration };
resources.midiState.advanceTime(buffer.getNumFrames());

View file

@ -47,6 +47,20 @@ public:
* @param buffer output buffer
*/
virtual void generate(const ModKey& sourceKey, NumericId<Voice> voiceNum, absl::Span<float> buffer) = 0;
/**
* @brief Advance the generator by a number of frames
* This is called instead of `generate` in case the output is discarded.
* It can be overriden with a faster implementation if wanted.
*
* @param sourceKey source key
* @param voiceNum voice number if the generator is per-voice, otherwise undefined
* @param buffer writable spare buffer, contents will be discarded
*/
virtual void generateDiscarded(const ModKey& sourceKey, NumericId<Voice> voiceNum, absl::Span<float> buffer)
{
generate(sourceKey, voiceNum, buffer);
}
};
} // namespace sfz

View file

@ -224,6 +224,22 @@ void ModMatrix::beginCycle(unsigned numFrames)
target.bufferReady = false;
}
void ModMatrix::endCycle()
{
Impl& impl = *impl_;
const uint32_t numFrames = impl.numFrames_;
for (Impl::Source &source : impl.sources_) {
if (!source.bufferReady) {
int flags = source.key.flags();
if (flags & kModIsPerCycle) {
absl::Span<float> buffer(source.buffer.data(), numFrames);
source.gen->generateDiscarded(source.key, {}, buffer);
}
}
}
}
void ModMatrix::beginVoice(NumericId<Voice> voiceId)
{
Impl& impl = *impl_;
@ -242,6 +258,23 @@ void ModMatrix::beginVoice(NumericId<Voice> voiceId)
}
}
void ModMatrix::endVoice()
{
Impl& impl = *impl_;
const uint32_t numFrames = impl.numFrames_;
const NumericId<Voice> voiceId = impl.voiceId_;
for (Impl::Source &source : impl.sources_) {
if (!source.bufferReady) {
int flags = source.key.flags();
if (flags & kModIsPerVoice) {
absl::Span<float> buffer(source.buffer.data(), numFrames);
source.gen->generateDiscarded(source.key, voiceId, buffer);
}
}
}
}
float* ModMatrix::getModulation(TargetId targetId)
{
if (!validTarget(targetId))

View file

@ -113,6 +113,12 @@ public:
*/
void beginCycle(unsigned numFrames);
/**
* @brief End modulation processing for the entire cycle.
* This performs a dummy run of any unused modulations.
*/
void endCycle();
/**
* @brief Start modulation processing for a given voice.
* This clears all the buffers which are per-voice.
@ -121,6 +127,12 @@ public:
*/
void beginVoice(NumericId<Voice> voiceId);
/**
* @brief End modulation processing for a given voice.
* This performs a dummy run of any unused modulations which are per-cycle.
*/
void endVoice();
/**
* @brief Get the modulation buffer for the given target.
* If the target does not exist, the result is null.