Flex envelope dynamic update

This commit is contained in:
Paul Fd 2021-06-27 12:13:44 +02:00
parent 83be87c449
commit e79e5cf04d
8 changed files with 48 additions and 15 deletions

View file

@ -70,7 +70,8 @@ namespace config {
constexpr float powerFollowerReleaseTime { 200e-3f };
constexpr uint16_t numCCs { 512 };
constexpr int maxCurves { 256 };
constexpr int chunkSize { 1024 };
constexpr int fileChunkSize { 1024 };
constexpr int processChunkSize { 16 };
constexpr unsigned int defaultAlignment { 16 };
constexpr int filtersInPool { maxVoices * 2 };
constexpr int excessFileFrames { 64 };

View file

@ -101,7 +101,7 @@ void streamFromFile(sfz::AudioReader& reader, sfz::FileAudioBuffer& output, std:
{
const auto numFrames = static_cast<size_t>(reader.frames());
const auto numChannels = reader.channels();
const auto chunkSize = static_cast<size_t>(sfz::config::chunkSize);
const auto chunkSize = static_cast<size_t>(sfz::config::fileChunkSize);
output.reset();
output.addChannels(reader.channels());

View file

@ -86,19 +86,19 @@ void FlexEGs::clearUnusedCurves()
}
///
float FlexEGPoint::getTime(const MidiState& state) const noexcept
float FlexEGPoint::getTime(const MidiState& state, int delay) const noexcept
{
float returnedValue { time };
for (const CCData<float>& mod : ccTime)
returnedValue += state.getCCValue(mod.cc) * mod.data;
returnedValue += state.getCCValueAt(mod.cc, delay) * mod.data;
return returnedValue;
}
float FlexEGPoint::getLevel(const MidiState& state) const noexcept
float FlexEGPoint::getLevel(const MidiState& state, int delay) const noexcept
{
float returnedValue { level };
for (const CCData<float>& mod : ccLevel)
returnedValue += state.getCCValue(mod.cc) * mod.data;
returnedValue += state.getCCValueAt(mod.cc, delay) * mod.data;
return returnedValue;
}

View file

@ -26,8 +26,8 @@ struct FlexEGPoint {
CCMap<float> ccTime;
CCMap<float> ccLevel;
float getTime(const MidiState& state) const noexcept;
float getLevel(const MidiState& state) const noexcept;
float getTime(const MidiState& state, int delay = 0) const noexcept;
float getLevel(const MidiState& state, int delay = 0) const noexcept;
void setShape(float shape);
float shape() const noexcept { return shape_; }

View file

@ -57,7 +57,7 @@ struct FlexEnvelope::Impl {
void process(absl::Span<float> out);
bool advanceToStage(unsigned stageNumber);
bool advanceToNextStage();
void updateCurrentTimeAndLevel();
void updateCurrentTimeAndLevel(int delay = 0);
};
FlexEnvelope::FlexEnvelope(Resources &resources)
@ -155,7 +155,19 @@ bool FlexEnvelope::isFinished() const noexcept
void FlexEnvelope::process(absl::Span<float> out)
{
Impl& impl = *impl_;
impl.process(out);
if (impl.desc_->dynamic) {
int processed = 0;
int remaining = static_cast<int>(out.size());
while(remaining > 0) {
impl.updateCurrentTimeAndLevel(processed);
int chunkSize = min(config::processChunkSize, remaining);
impl.process(out.subspan(processed, chunkSize));
processed += chunkSize;
remaining -= chunkSize;
}
} else {
impl.process(out);
}
}
void FlexEnvelope::Impl::process(absl::Span<float> out)
@ -271,7 +283,7 @@ bool FlexEnvelope::Impl::advanceToNextStage()
return advanceToStage(currentStageNumber_ + 1);
}
void FlexEnvelope::Impl::updateCurrentTimeAndLevel()
void FlexEnvelope::Impl::updateCurrentTimeAndLevel(int delay)
{
const FlexEGDescription& desc = *desc_;
if (currentStageNumber_ >= desc.points.size())
@ -279,8 +291,8 @@ void FlexEnvelope::Impl::updateCurrentTimeAndLevel()
const FlexEGPoint& point = desc.points[currentStageNumber_];
const MidiState& midiState = resources_->getMidiState();
stageTargetLevel_ = point.getLevel(midiState);
stageTime_ = point.getTime(midiState);
stageTargetLevel_ = point.getLevel(midiState, delay);
stageTime_ = point.getTime(midiState, delay);
}
} // namespace sfz

View file

@ -202,6 +202,17 @@ float sfz::MidiState::getCCValue(int ccNumber) const noexcept
return ccEvents[ccNumber].back().value;
}
float sfz::MidiState::getCCValueAt(int ccNumber, int delay) const noexcept
{
ASSERT(ccNumber >= 0 && ccNumber < config::numCCs);
const auto ccEvent = absl::c_lower_bound(
ccEvents[ccNumber], delay, MidiEventDelayComparator {});
if (ccEvent != ccEvents[ccNumber].end())
return ccEvent->value;
else
return ccEvents[ccNumber].back().value;
}
void sfz::MidiState::reset() noexcept
{
for (auto& velocity: lastNoteVelocities)

View file

@ -167,13 +167,22 @@ public:
bool isNotePressed(int noteNumber) const noexcept { return noteStates[noteNumber]; }
/**
* @brief Get the CC value for CC number
* @brief Get the last CC value for CC number
*
* @param ccNumber
* @return float
*/
float getCCValue(int ccNumber) const noexcept;
/**
* @brief Get the CC value for CC number
*
* @param ccNumber
* @param delay
* @return float
*/
float getCCValueAt(int ccNumber, int delay) const noexcept;
/**
* @brief Reset the midi state (does not impact the last note on time)
*

View file

@ -39,7 +39,7 @@ public:
* @param factor
* @param chunkSize
*/
Oversampler(Oversampling factor = Oversampling::x1, size_t chunkSize = config::chunkSize);
Oversampler(Oversampling factor = Oversampling::x1, size_t chunkSize = config::fileChunkSize);
/**
* @brief Stream the oversampling of an input AudioBuffer into an output
* one, possibly signaling the caller along the way of the number of