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
|
void sfz::MidiState::setSampleRate(float sampleRate) noexcept
|
||||||
{
|
{
|
||||||
this->sampleRate = sampleRate;
|
this->sampleRate = sampleRate;
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* @brief Update the state after a note on event
|
* @brief Update the state after a note on event
|
||||||
*
|
*
|
||||||
|
* @param delay
|
||||||
* @param noteNumber
|
* @param noteNumber
|
||||||
* @param velocity
|
* @param velocity
|
||||||
*/
|
*/
|
||||||
|
|
@ -33,11 +34,22 @@ public:
|
||||||
/**
|
/**
|
||||||
* @brief Update the state after a note off event
|
* @brief Update the state after a note off event
|
||||||
*
|
*
|
||||||
|
* @param delay
|
||||||
* @param noteNumber
|
* @param noteNumber
|
||||||
* @param velocity
|
* @param velocity
|
||||||
*/
|
*/
|
||||||
void noteOffEvent(int delay, int noteNumber, float velocity) noexcept;
|
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; }
|
int getActiveNotes() const noexcept { return activeNotes; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -708,6 +708,9 @@ void sfz::Synth::renderBlock(AudioSpan<float> buffer) noexcept
|
||||||
callbackBreakdown.amplitude += voice->getLastAmplitudeDuration();
|
callbackBreakdown.amplitude += voice->getLastAmplitudeDuration();
|
||||||
callbackBreakdown.filters += voice->getLastFilterDuration();
|
callbackBreakdown.filters += voice->getLastFilterDuration();
|
||||||
callbackBreakdown.panning += voice->getLastPanningDuration();
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ccNumber == config::allNotesOffCC || ccNumber == config::allSoundOffCC) {
|
||||||
|
for (auto& voice : voices)
|
||||||
|
voice->reset();
|
||||||
|
resources.midiState.allNotesOff(delay);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (auto& voice : voices)
|
for (auto& voice : voices)
|
||||||
voice->registerCC(delay, ccNumber, normValue);
|
voice->registerCC(delay, ccNumber, normValue);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ void sfz::Voice::startVoice(Region* region, int delay, int number, float value,
|
||||||
} else {
|
} else {
|
||||||
currentPromise = resources.filePool.getFilePromise(region->sampleId);
|
currentPromise = resources.filePool.getFilePromise(region->sampleId);
|
||||||
if (currentPromise == nullptr) {
|
if (currentPromise == nullptr) {
|
||||||
reset();
|
switchState(State::cleanMeUp);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
speedRatio = static_cast<float>(currentPromise->sampleRate / this->sampleRate);
|
speedRatio = static_cast<float>(currentPromise->sampleRate / this->sampleRate);
|
||||||
|
|
@ -139,7 +139,7 @@ void sfz::Voice::release(int delay, bool fastRelease) noexcept
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (egEnvelope.getRemainingDelay() > delay) {
|
if (egEnvelope.getRemainingDelay() > delay) {
|
||||||
reset();
|
switchState(State::cleanMeUp);
|
||||||
} else {
|
} else {
|
||||||
egEnvelope.startRelease(delay, fastRelease);
|
egEnvelope.startRelease(delay, fastRelease);
|
||||||
}
|
}
|
||||||
|
|
@ -173,21 +173,16 @@ void sfz::Voice::registerCC(int delay, int ccNumber, float ccValue) noexcept
|
||||||
if (region == nullptr)
|
if (region == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (state == State::idle)
|
if (state != State::playing)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (ccNumber == config::allNotesOffCC || ccNumber == config::allSoundOffCC) {
|
|
||||||
reset();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (region->checkSustain && noteIsOff && ccNumber == config::sustainCC && ccValue < config::halfCCThreshold)
|
if (region->checkSustain && noteIsOff && ccNumber == config::sustainCC && ccValue < config::halfCCThreshold)
|
||||||
release(delay);
|
release(delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sfz::Voice::registerPitchWheel(int delay, float pitch) noexcept
|
void sfz::Voice::registerPitchWheel(int delay, float pitch) noexcept
|
||||||
{
|
{
|
||||||
if (state == State::idle)
|
if (state != State::playing)
|
||||||
return;
|
return;
|
||||||
UNUSED(delay);
|
UNUSED(delay);
|
||||||
UNUSED(pitch);
|
UNUSED(pitch);
|
||||||
|
|
@ -229,6 +224,8 @@ void sfz::Voice::renderBlock(AudioSpan<float> buffer) noexcept
|
||||||
ASSERT(static_cast<int>(buffer.getNumFrames()) <= samplesPerBlock);
|
ASSERT(static_cast<int>(buffer.getNumFrames()) <= samplesPerBlock);
|
||||||
buffer.fill(0.0f);
|
buffer.fill(0.0f);
|
||||||
|
|
||||||
|
ASSERT(region != nullptr);
|
||||||
|
|
||||||
const auto delay = min(static_cast<size_t>(initialDelay), buffer.getNumFrames());
|
const auto delay = min(static_cast<size_t>(initialDelay), buffer.getNumFrames());
|
||||||
auto delayed_buffer = buffer.subspan(delay);
|
auto delayed_buffer = buffer.subspan(delay);
|
||||||
initialDelay -= static_cast<int>(delay);
|
initialDelay -= static_cast<int>(delay);
|
||||||
|
|
@ -252,7 +249,7 @@ void sfz::Voice::renderBlock(AudioSpan<float> buffer) noexcept
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!egEnvelope.isSmoothing())
|
if (!egEnvelope.isSmoothing())
|
||||||
reset();
|
switchState(State::cleanMeUp);
|
||||||
|
|
||||||
updateChannelPowers(buffer);
|
updateChannelPowers(buffer);
|
||||||
|
|
||||||
|
|
@ -683,7 +680,7 @@ float sfz::Voice::getAverageEnvelope() const noexcept
|
||||||
|
|
||||||
bool sfz::Voice::releasedOrFree() 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
|
uint32_t sfz::Voice::getSourcePosition() const noexcept
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,8 @@ public:
|
||||||
|
|
||||||
enum class State {
|
enum class State {
|
||||||
idle,
|
idle,
|
||||||
playing
|
playing,
|
||||||
|
cleanMeUp,
|
||||||
};
|
};
|
||||||
|
|
||||||
class StateListener {
|
class StateListener {
|
||||||
|
|
@ -61,6 +62,11 @@ public:
|
||||||
virtual void onVoiceStateChanged(NumericId<Voice> /*id*/, State /*state*/) {}
|
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.
|
* @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;
|
sfz::Synth synth;
|
||||||
synth.setSamplesPerBlock(1024);
|
synth.setSamplesPerBlock(1024);
|
||||||
|
sfz::AudioBuffer<float> buffer { 2, 1024 };
|
||||||
synth.setNumVoices(1);
|
synth.setNumVoices(1);
|
||||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/delay_release.sfz");
|
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/delay_release.sfz");
|
||||||
synth.noteOn(0, 60, 63);
|
synth.noteOn(0, 60, 63);
|
||||||
REQUIRE( !synth.getVoiceView(0)->isFree() );
|
REQUIRE( !synth.getVoiceView(0)->isFree() );
|
||||||
synth.noteOff(100, 60, 63);
|
synth.noteOff(100, 60, 63);
|
||||||
|
synth.renderBlock(buffer);
|
||||||
REQUIRE( synth.getVoiceView(0)->isFree() );
|
REQUIRE( synth.getVoiceView(0)->isFree() );
|
||||||
synth.noteOn(200, 60, 63);
|
synth.noteOn(200, 60, 63);
|
||||||
REQUIRE( !synth.getVoiceView(0)->isFree() );
|
REQUIRE( !synth.getVoiceView(0)->isFree() );
|
||||||
synth.noteOff(1000, 60, 63);
|
synth.noteOff(1000, 60, 63);
|
||||||
|
synth.renderBlock(buffer);
|
||||||
REQUIRE( !synth.getVoiceView(0)->isFree() );
|
REQUIRE( !synth.getVoiceView(0)->isFree() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue