Flex envelope dynamic update
This commit is contained in:
parent
83be87c449
commit
e79e5cf04d
8 changed files with 48 additions and 15 deletions
|
|
@ -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 };
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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_; }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue