Merge pull request #274 from paulfd/voice-cleanup
The synth now resets the voices
This commit is contained in:
commit
9857d7b706
6 changed files with 46 additions and 12 deletions
|
|
@ -40,6 +40,12 @@ void sfz::MidiState::noteOffEvent(int delay, int noteNumber, float velocity) noe
|
|||
|
||||
}
|
||||
|
||||
void sfz::MidiState::allNotesOff(int delay) noexcept
|
||||
{
|
||||
for (int note = 0; note < 128; note++)
|
||||
noteOffEvent(delay, note, 0.0f);
|
||||
}
|
||||
|
||||
void sfz::MidiState::setSampleRate(float sampleRate) noexcept
|
||||
{
|
||||
this->sampleRate = sampleRate;
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ public:
|
|||
/**
|
||||
* @brief Update the state after a note on event
|
||||
*
|
||||
* @param delay
|
||||
* @param noteNumber
|
||||
* @param velocity
|
||||
*/
|
||||
|
|
@ -33,11 +34,22 @@ public:
|
|||
/**
|
||||
* @brief Update the state after a note off event
|
||||
*
|
||||
* @param delay
|
||||
* @param noteNumber
|
||||
* @param velocity
|
||||
*/
|
||||
void noteOffEvent(int delay, int noteNumber, float velocity) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Set all notes off
|
||||
*
|
||||
* @param delay
|
||||
*/
|
||||
void allNotesOff(int delay) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Get the number of active notes
|
||||
*/
|
||||
int getActiveNotes() const noexcept { return activeNotes; }
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -708,6 +708,9 @@ void sfz::Synth::renderBlock(AudioSpan<float> buffer) noexcept
|
|||
callbackBreakdown.amplitude += voice->getLastAmplitudeDuration();
|
||||
callbackBreakdown.filters += voice->getLastFilterDuration();
|
||||
callbackBreakdown.panning += voice->getLastPanningDuration();
|
||||
|
||||
if (voice->toBeCleanedUp())
|
||||
voice->reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -892,6 +895,13 @@ void sfz::Synth::hdcc(int delay, int ccNumber, float normValue) noexcept
|
|||
return;
|
||||
}
|
||||
|
||||
if (ccNumber == config::allNotesOffCC || ccNumber == config::allSoundOffCC) {
|
||||
for (auto& voice : voices)
|
||||
voice->reset();
|
||||
resources.midiState.allNotesOff(delay);
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& voice : voices)
|
||||
voice->registerCC(delay, ccNumber, normValue);
|
||||
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ void sfz::Voice::startVoice(Region* region, int delay, int number, float value,
|
|||
} else {
|
||||
currentPromise = resources.filePool.getFilePromise(region->sampleId);
|
||||
if (currentPromise == nullptr) {
|
||||
reset();
|
||||
switchState(State::cleanMeUp);
|
||||
return;
|
||||
}
|
||||
speedRatio = static_cast<float>(currentPromise->sampleRate / this->sampleRate);
|
||||
|
|
@ -139,7 +139,7 @@ void sfz::Voice::release(int delay, bool fastRelease) noexcept
|
|||
return;
|
||||
|
||||
if (egEnvelope.getRemainingDelay() > delay) {
|
||||
reset();
|
||||
switchState(State::cleanMeUp);
|
||||
} else {
|
||||
egEnvelope.startRelease(delay, fastRelease);
|
||||
}
|
||||
|
|
@ -173,21 +173,16 @@ void sfz::Voice::registerCC(int delay, int ccNumber, float ccValue) noexcept
|
|||
if (region == nullptr)
|
||||
return;
|
||||
|
||||
if (state == State::idle)
|
||||
if (state != State::playing)
|
||||
return;
|
||||
|
||||
if (ccNumber == config::allNotesOffCC || ccNumber == config::allSoundOffCC) {
|
||||
reset();
|
||||
return;
|
||||
}
|
||||
|
||||
if (region->checkSustain && noteIsOff && ccNumber == config::sustainCC && ccValue < config::halfCCThreshold)
|
||||
release(delay);
|
||||
}
|
||||
|
||||
void sfz::Voice::registerPitchWheel(int delay, float pitch) noexcept
|
||||
{
|
||||
if (state == State::idle)
|
||||
if (state != State::playing)
|
||||
return;
|
||||
UNUSED(delay);
|
||||
UNUSED(pitch);
|
||||
|
|
@ -229,6 +224,8 @@ void sfz::Voice::renderBlock(AudioSpan<float> buffer) noexcept
|
|||
ASSERT(static_cast<int>(buffer.getNumFrames()) <= samplesPerBlock);
|
||||
buffer.fill(0.0f);
|
||||
|
||||
ASSERT(region != nullptr);
|
||||
|
||||
const auto delay = min(static_cast<size_t>(initialDelay), buffer.getNumFrames());
|
||||
auto delayed_buffer = buffer.subspan(delay);
|
||||
initialDelay -= static_cast<int>(delay);
|
||||
|
|
@ -252,7 +249,7 @@ void sfz::Voice::renderBlock(AudioSpan<float> buffer) noexcept
|
|||
}
|
||||
|
||||
if (!egEnvelope.isSmoothing())
|
||||
reset();
|
||||
switchState(State::cleanMeUp);
|
||||
|
||||
updateChannelPowers(buffer);
|
||||
|
||||
|
|
@ -683,7 +680,7 @@ float sfz::Voice::getAverageEnvelope() const noexcept
|
|||
|
||||
bool sfz::Voice::releasedOrFree() const noexcept
|
||||
{
|
||||
return state == State::idle || egEnvelope.isReleased();
|
||||
return state != State::playing || egEnvelope.isReleased();
|
||||
}
|
||||
|
||||
uint32_t sfz::Voice::getSourcePosition() const noexcept
|
||||
|
|
|
|||
|
|
@ -53,7 +53,8 @@ public:
|
|||
|
||||
enum class State {
|
||||
idle,
|
||||
playing
|
||||
playing,
|
||||
cleanMeUp,
|
||||
};
|
||||
|
||||
class StateListener {
|
||||
|
|
@ -61,6 +62,11 @@ public:
|
|||
virtual void onVoiceStateChanged(NumericId<Voice> /*id*/, State /*state*/) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Return true if the voice is to be cleaned up (zombie state)
|
||||
*/
|
||||
bool toBeCleanedUp() const { return state == State::cleanMeUp; }
|
||||
|
||||
/**
|
||||
* @brief Sets the listener which is called when the voice state changes.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -152,15 +152,18 @@ TEST_CASE("[Synth] Releasing before the EG started smoothing (initial delay) kil
|
|||
{
|
||||
sfz::Synth synth;
|
||||
synth.setSamplesPerBlock(1024);
|
||||
sfz::AudioBuffer<float> buffer { 2, 1024 };
|
||||
synth.setNumVoices(1);
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/delay_release.sfz");
|
||||
synth.noteOn(0, 60, 63);
|
||||
REQUIRE( !synth.getVoiceView(0)->isFree() );
|
||||
synth.noteOff(100, 60, 63);
|
||||
synth.renderBlock(buffer);
|
||||
REQUIRE( synth.getVoiceView(0)->isFree() );
|
||||
synth.noteOn(200, 60, 63);
|
||||
REQUIRE( !synth.getVoiceView(0)->isFree() );
|
||||
synth.noteOff(1000, 60, 63);
|
||||
synth.renderBlock(buffer);
|
||||
REQUIRE( !synth.getVoiceView(0)->isFree() );
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue