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 float powerFollowerReleaseTime { 200e-3f };
|
||||||
constexpr uint16_t numCCs { 512 };
|
constexpr uint16_t numCCs { 512 };
|
||||||
constexpr int maxCurves { 256 };
|
constexpr int maxCurves { 256 };
|
||||||
constexpr int chunkSize { 1024 };
|
constexpr int fileChunkSize { 1024 };
|
||||||
|
constexpr int processChunkSize { 16 };
|
||||||
constexpr unsigned int defaultAlignment { 16 };
|
constexpr unsigned int defaultAlignment { 16 };
|
||||||
constexpr int filtersInPool { maxVoices * 2 };
|
constexpr int filtersInPool { maxVoices * 2 };
|
||||||
constexpr int excessFileFrames { 64 };
|
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 numFrames = static_cast<size_t>(reader.frames());
|
||||||
const auto numChannels = reader.channels();
|
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.reset();
|
||||||
output.addChannels(reader.channels());
|
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 };
|
float returnedValue { time };
|
||||||
for (const CCData<float>& mod : ccTime)
|
for (const CCData<float>& mod : ccTime)
|
||||||
returnedValue += state.getCCValue(mod.cc) * mod.data;
|
returnedValue += state.getCCValueAt(mod.cc, delay) * mod.data;
|
||||||
return returnedValue;
|
return returnedValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
float FlexEGPoint::getLevel(const MidiState& state) const noexcept
|
float FlexEGPoint::getLevel(const MidiState& state, int delay) const noexcept
|
||||||
{
|
{
|
||||||
float returnedValue { level };
|
float returnedValue { level };
|
||||||
for (const CCData<float>& mod : ccLevel)
|
for (const CCData<float>& mod : ccLevel)
|
||||||
returnedValue += state.getCCValue(mod.cc) * mod.data;
|
returnedValue += state.getCCValueAt(mod.cc, delay) * mod.data;
|
||||||
return returnedValue;
|
return returnedValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,8 @@ struct FlexEGPoint {
|
||||||
CCMap<float> ccTime;
|
CCMap<float> ccTime;
|
||||||
CCMap<float> ccLevel;
|
CCMap<float> ccLevel;
|
||||||
|
|
||||||
float getTime(const MidiState& state) const noexcept;
|
float getTime(const MidiState& state, int delay = 0) const noexcept;
|
||||||
float getLevel(const MidiState& state) const noexcept;
|
float getLevel(const MidiState& state, int delay = 0) const noexcept;
|
||||||
|
|
||||||
void setShape(float shape);
|
void setShape(float shape);
|
||||||
float shape() const noexcept { return shape_; }
|
float shape() const noexcept { return shape_; }
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ struct FlexEnvelope::Impl {
|
||||||
void process(absl::Span<float> out);
|
void process(absl::Span<float> out);
|
||||||
bool advanceToStage(unsigned stageNumber);
|
bool advanceToStage(unsigned stageNumber);
|
||||||
bool advanceToNextStage();
|
bool advanceToNextStage();
|
||||||
void updateCurrentTimeAndLevel();
|
void updateCurrentTimeAndLevel(int delay = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
FlexEnvelope::FlexEnvelope(Resources &resources)
|
FlexEnvelope::FlexEnvelope(Resources &resources)
|
||||||
|
|
@ -155,7 +155,19 @@ bool FlexEnvelope::isFinished() const noexcept
|
||||||
void FlexEnvelope::process(absl::Span<float> out)
|
void FlexEnvelope::process(absl::Span<float> out)
|
||||||
{
|
{
|
||||||
Impl& impl = *impl_;
|
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)
|
void FlexEnvelope::Impl::process(absl::Span<float> out)
|
||||||
|
|
@ -271,7 +283,7 @@ bool FlexEnvelope::Impl::advanceToNextStage()
|
||||||
return advanceToStage(currentStageNumber_ + 1);
|
return advanceToStage(currentStageNumber_ + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlexEnvelope::Impl::updateCurrentTimeAndLevel()
|
void FlexEnvelope::Impl::updateCurrentTimeAndLevel(int delay)
|
||||||
{
|
{
|
||||||
const FlexEGDescription& desc = *desc_;
|
const FlexEGDescription& desc = *desc_;
|
||||||
if (currentStageNumber_ >= desc.points.size())
|
if (currentStageNumber_ >= desc.points.size())
|
||||||
|
|
@ -279,8 +291,8 @@ void FlexEnvelope::Impl::updateCurrentTimeAndLevel()
|
||||||
|
|
||||||
const FlexEGPoint& point = desc.points[currentStageNumber_];
|
const FlexEGPoint& point = desc.points[currentStageNumber_];
|
||||||
const MidiState& midiState = resources_->getMidiState();
|
const MidiState& midiState = resources_->getMidiState();
|
||||||
stageTargetLevel_ = point.getLevel(midiState);
|
stageTargetLevel_ = point.getLevel(midiState, delay);
|
||||||
stageTime_ = point.getTime(midiState);
|
stageTime_ = point.getTime(midiState, delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace sfz
|
} // namespace sfz
|
||||||
|
|
|
||||||
|
|
@ -202,6 +202,17 @@ float sfz::MidiState::getCCValue(int ccNumber) const noexcept
|
||||||
return ccEvents[ccNumber].back().value;
|
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
|
void sfz::MidiState::reset() noexcept
|
||||||
{
|
{
|
||||||
for (auto& velocity: lastNoteVelocities)
|
for (auto& velocity: lastNoteVelocities)
|
||||||
|
|
|
||||||
|
|
@ -167,13 +167,22 @@ public:
|
||||||
bool isNotePressed(int noteNumber) const noexcept { return noteStates[noteNumber]; }
|
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
|
* @param ccNumber
|
||||||
* @return float
|
* @return float
|
||||||
*/
|
*/
|
||||||
float getCCValue(int ccNumber) const noexcept;
|
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)
|
* @brief Reset the midi state (does not impact the last note on time)
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ public:
|
||||||
* @param factor
|
* @param factor
|
||||||
* @param chunkSize
|
* @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
|
* @brief Stream the oversampling of an input AudioBuffer into an output
|
||||||
* one, possibly signaling the caller along the way of the number of
|
* one, possibly signaling the caller along the way of the number of
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue