diff --git a/benchmarks/BM_meanSquared.cpp b/benchmarks/BM_meanSquared.cpp index 0b1c159e..34c29a8f 100644 --- a/benchmarks/BM_meanSquared.cpp +++ b/benchmarks/BM_meanSquared.cpp @@ -34,7 +34,7 @@ BENCHMARK_DEFINE_F(MeanSquaredArray, Scalar) (benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::sumSquares, false); auto result = sfz::meanSquared(input); benchmark::DoNotOptimize(result); } @@ -44,7 +44,7 @@ BENCHMARK_DEFINE_F(MeanSquaredArray, SIMD) (benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::sumSquares, true); auto result = sfz::meanSquared(input); benchmark::DoNotOptimize(result); } @@ -54,7 +54,7 @@ BENCHMARK_DEFINE_F(MeanSquaredArray, Scalar_Unaligned) (benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::sumSquares, false); auto result = sfz::meanSquared(absl::MakeSpan(input).subspan(1)); benchmark::DoNotOptimize(result); } @@ -64,7 +64,7 @@ BENCHMARK_DEFINE_F(MeanSquaredArray, SIMD_Unaligned) (benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::sumSquares, true); auto result = sfz::meanSquared(absl::MakeSpan(input).subspan(1)); benchmark::DoNotOptimize(result); } diff --git a/benchmarks/BM_powerFollower.cpp b/benchmarks/BM_powerFollower.cpp new file mode 100644 index 00000000..6444e0e6 --- /dev/null +++ b/benchmarks/BM_powerFollower.cpp @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "PowerFollower.h" +#include "AudioBuffer.h" +#include "Config.h" +#include +#include + +class PowerFollowerFixture : public benchmark::Fixture { +public: + PowerFollowerFixture() + { + inputSignal_ = sfz::AudioBuffer(2, numFrames); + auto leftSignal = inputSignal_.getSpan(0); + auto rightSignal = inputSignal_.getSpan(1); + float phase = 0; + for (size_t i = 0; i < numFrames; ++i) { + constexpr float k2pi = 2.0 * M_PI; + leftSignal[i] = std::sin(k2pi * phase); + rightSignal[i] = std::cos(k2pi * phase); + phase += 440.0f / sfz::config::defaultSampleRate; + phase -= static_cast(phase); + } + } + + void SetUp(const ::benchmark::State& state) + { + auto blockSize = static_cast(state.range(0)); + follower_.setSampleRate(sfz::config::defaultSampleRate); + follower_.setSamplesPerBlock(blockSize); + follower_.clear(); + + // + refFollower_.init(sfz::config::defaultSampleRate); + refFollower_.clear(); + } + + void TearDown(const ::benchmark::State& /* state */) + { + } + + static constexpr size_t numFrames = 65536; + sfz::PowerFollower follower_; + sfz::AudioBuffer inputSignal_; + + // + struct ReferenceFollower { + /* + import("stdfaust.lib"); + process = (_, _) : + : an.amp_follower_ud(att, rel) with { att = 5e-3; rel = 200e-3; }; + */ + + void init(float sampleRate) + { + fConst0 = std::min(192000.0f, std::max(1.0f, float(sampleRate))); + fConst1 = std::exp((0.0f - (200.0f / fConst0))); + fConst2 = (1.0f - fConst1); + fConst3 = std::exp((0.0f - (5.0f / fConst0))); + fConst4 = (1.0f - fConst3); + } + void clear() + { + for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { + fRec1[l0] = 0.0f; + } + for (int l1 = 0; (l1 < 2); l1 = (l1 + 1)) { + fRec0[l1] = 0.0f; + } + } + float process(float input0, float input1) + { + float fTemp0 = std::fabs((float(input0) + float(input1))); + fRec1[0] = std::max(fTemp0, ((fConst3 * fRec1[1]) + (fConst4 * fTemp0))); + fRec0[0] = ((fConst1 * fRec0[1]) + (fConst2 * fRec1[0])); + float output = fRec0[0]; + fRec1[1] = fRec1[0]; + fRec0[1] = fRec0[0]; + return output; + } + + float fConst0; + float fConst1; + float fConst2; + float fConst3; + float fConst4; + float fRec1[2]; + float fRec0[2]; + }; + ReferenceFollower refFollower_; +}; + +constexpr size_t PowerFollowerFixture::numFrames; + +BENCHMARK_DEFINE_F(PowerFollowerFixture, ReferenceFollower) (benchmark::State& state) +{ + sfz::AudioSpan inputSignal(inputSignal_); + auto input0 = inputSignal.getConstSpan(0); + auto input1 = inputSignal.getConstSpan(1); + + for (auto _ : state) { + auto& follower = refFollower_; + float output = 0; + for (size_t i = 0, n = inputSignal.getNumFrames(); i < n; ++i) + output = follower.process(input0[i], input1[i]); + benchmark::DoNotOptimize(output); + } +} + +BENCHMARK_DEFINE_F(PowerFollowerFixture, Follower) (benchmark::State& state) +{ + sfz::AudioSpan inputSignal(inputSignal_); + for (auto _ : state) { + auto& follower = follower_; + auto blockSize = static_cast(state.range(0)); + for (size_t i = 0; i < numFrames; i += blockSize) + follower.process(inputSignal.subspan(i, blockSize)); + } +} + +BENCHMARK_REGISTER_F(PowerFollowerFixture, ReferenceFollower)->Range(1, 1); +BENCHMARK_REGISTER_F(PowerFollowerFixture, Follower)->RangeMultiplier(2)->Range(1 << 5, 1 << 12); diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 71fd0b14..4efb3d82 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -66,6 +66,8 @@ sfizz_add_benchmark(bm_logger BM_logger.cpp) target_link_libraries(bm_logger PRIVATE sfizz::sfizz) sfizz_add_benchmark(bm_smoothers BM_smoothers.cpp) target_link_libraries(bm_smoothers PRIVATE sfizz::sfizz) +sfizz_add_benchmark(bm_powerFollower BM_powerFollower.cpp) +target_link_libraries(bm_powerFollower PRIVATE sfizz::sfizz) if (TARGET sfizz-samplerate) sfizz_add_benchmark(bm_resample BM_resample.cpp ${BENCHMARK_SIMD_SOURCES}) diff --git a/dpf.mk b/dpf.mk index 5507e79b..2ee507e8 100644 --- a/dpf.mk +++ b/dpf.mk @@ -103,6 +103,7 @@ SFIZZ_SOURCES = \ src/sfizz/Parser.cpp \ src/sfizz/parser/Parser.cpp \ src/sfizz/parser/ParserPrivate.cpp \ + src/sfizz/PowerFollower.cpp \ src/sfizz/Region.cpp \ src/sfizz/RTSemaphore.cpp \ src/sfizz/ScopedFTZ.cpp \ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e97af140..ed19f1b6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -81,6 +81,7 @@ set (SFIZZ_HEADERS sfizz/Oversampler.h sfizz/Panning.h sfizz/PolyphonyGroup.h + sfizz/PowerFollower.h sfizz/railsback/2-1.h sfizz/railsback/4-1.h sfizz/railsback/4-2.h @@ -138,6 +139,7 @@ set (SFIZZ_SOURCES sfizz/Effects.cpp sfizz/LFO.cpp sfizz/LFODescription.cpp + sfizz/PowerFollower.cpp sfizz/modulations/ModId.cpp sfizz/modulations/ModKey.cpp sfizz/modulations/ModKeyHash.cpp diff --git a/src/sfizz/Config.h b/src/sfizz/Config.h index 2956dae6..e56548fc 100644 --- a/src/sfizz/Config.h +++ b/src/sfizz/Config.h @@ -57,7 +57,9 @@ namespace config { constexpr Oversampling defaultOversamplingFactor { Oversampling::x1 }; constexpr float A440 { 440.0 }; constexpr size_t powerHistoryLength { 16 }; - constexpr float filteredEnvelopeCutoff { 5 }; + constexpr size_t powerFollowerStep { 512 }; + constexpr float powerFollowerAttackTime { 5e-3f }; + constexpr float powerFollowerReleaseTime { 200e-3f }; constexpr uint16_t numCCs { 512 }; constexpr int maxCurves { 256 }; constexpr int chunkSize { 1024 }; @@ -72,10 +74,10 @@ namespace config { */ constexpr float stealingAgeCoeff { 0.5f }; /** - * @brief The threshold for envelope stealing. - * In percentage of the sum of all envelopes. + * @brief The threshold for power stealing. + * In percentage of the sum of all powers. */ - constexpr float stealingEnvelopeCoeff { 0.5f }; + constexpr float stealingPowerCoeff { 0.5f }; constexpr int filtersPerVoice { 2 }; constexpr int eqsPerVoice { 3 }; constexpr int oscillatorsPerVoice { 9 }; diff --git a/src/sfizz/PowerFollower.cpp b/src/sfizz/PowerFollower.cpp new file mode 100644 index 00000000..f2eb05e5 --- /dev/null +++ b/src/sfizz/PowerFollower.cpp @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "PowerFollower.h" +#include "Defaults.h" +#include "SIMDHelpers.h" +#include + +namespace sfz { + +PowerFollower::PowerFollower() + : sampleRate_(config::defaultSampleRate), + samplesPerBlock_(config::defaultSamplesPerBlock), + tempBuffer_(new float[config::defaultSamplesPerBlock]) +{ + updateTrackingFactor(); +} + +void PowerFollower::setSampleRate(float sampleRate) noexcept +{ + if (sampleRate_ != sampleRate) { + sampleRate_ = sampleRate; + updateTrackingFactor(); + } +} + +void PowerFollower::setSamplesPerBlock(unsigned samplesPerBlock) +{ + if (samplesPerBlock_ != samplesPerBlock) { + tempBuffer_.reset(new float[samplesPerBlock]); + samplesPerBlock_ = samplesPerBlock; + } +} + +void PowerFollower::process(AudioSpan buffer) noexcept +{ + size_t numFrames = buffer.getNumFrames(); + if (numFrames == 0) + return; + + /// + constexpr size_t step = config::powerFollowerStep; + float currentPower = currentPower_; + float currentSum = currentSum_; + size_t currentCount = currentCount_; + + const float attackFactor = attackTrackingFactor_; + const float releaseFactor = releaseTrackingFactor_; + + /// + size_t index = 0; + while (index < numFrames) { + size_t blockSize = std::min(step - currentCount, numFrames - index); + absl::Span tempBuffer(tempBuffer_.get(), blockSize); + + copy(buffer.getConstSpan(0).subspan(index, blockSize), tempBuffer); + for (unsigned i = 1, n = buffer.getNumChannels(); i < n; ++i) + add(buffer.getConstSpan(i).subspan(index, blockSize), tempBuffer); + + currentSum += sumSquares(tempBuffer); + currentCount += blockSize; + + if (currentCount == step) { + const float meanPower = currentSum / step; + currentPower = max( + currentPower * attackFactor + meanPower * (1 - attackFactor), + currentPower * releaseFactor + meanPower * (1 - releaseFactor)); + currentSum = 0; + currentCount = 0; + } + + index += blockSize; + } + + /// + currentPower_ = currentPower; + currentSum_ = currentSum; + currentCount_ = currentCount; +} + +void PowerFollower::clear() noexcept +{ + currentPower_ = 0; + currentSum_ = 0; + currentCount_ = 0; +} + +void PowerFollower::updateTrackingFactor() noexcept +{ + // Protect the envelope follower against blowups + attackTrackingFactor_ = std::exp(-1.0f / ((config::powerFollowerAttackTime / config::powerFollowerStep) * sampleRate_)); + releaseTrackingFactor_ = std::exp(-1.0f / ((config::powerFollowerReleaseTime / config::powerFollowerStep) * sampleRate_)); +} + +} // namespace sfz diff --git a/src/sfizz/PowerFollower.h b/src/sfizz/PowerFollower.h new file mode 100644 index 00000000..1febd9f1 --- /dev/null +++ b/src/sfizz/PowerFollower.h @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include "AudioSpan.h" +#include + +namespace sfz { + +class PowerFollower { +public: + PowerFollower(); + void setSampleRate(float sampleRate) noexcept; + void setSamplesPerBlock(unsigned samplesPerBlock); + void process(AudioSpan buffer) noexcept; + void clear() noexcept; + float getAveragePower() const noexcept { return currentPower_; } + +private: + void updateTrackingFactor() noexcept; + +private: + float sampleRate_ {}; + unsigned samplesPerBlock_ {}; + + std::unique_ptr tempBuffer_; + + float attackTrackingFactor_ {}; + float releaseTrackingFactor_ {}; + + float currentPower_ {}; + float currentSum_ = 0; + size_t currentCount_ = 0; +}; + +} // namespace sfz diff --git a/src/sfizz/SIMDHelpers.cpp b/src/sfizz/SIMDHelpers.cpp index c86cecf8..c0287772 100644 --- a/src/sfizz/SIMDHelpers.cpp +++ b/src/sfizz/SIMDHelpers.cpp @@ -39,7 +39,7 @@ struct SIMDDispatch { decltype(&cumsumScalar) cumsum = &cumsumScalar; decltype(&diffScalar) diff = &diffScalar; decltype(&meanScalar) mean = &meanScalar; - decltype(&meanSquaredScalar) meanSquared = &meanSquaredScalar; + decltype(&sumSquaresScalar) sumSquares = &sumSquaresScalar; decltype(&clampAllScalar) clampAll = &clampAllScalar; decltype(&allWithinScalar) allWithin = &allWithinScalar; @@ -85,7 +85,7 @@ void SIMDDispatch::setStatus(SIMDOps op, bool enable) SIMD_OP(cumsum) SIMD_OP(diff) SIMD_OP(mean) - SIMD_OP(meanSquared) + SIMD_OP(sumSquares) SIMD_OP(clampAll) SIMD_OP(allWithin) } @@ -122,7 +122,7 @@ void SIMDDispatch::setStatus(SIMDOps op, bool enable) SIMD_OP(cumsum) SIMD_OP(diff) SIMD_OP(mean) - SIMD_OP(meanSquared) + SIMD_OP(sumSquares) SIMD_OP(clampAll) SIMD_OP(allWithin) } @@ -163,7 +163,7 @@ void SIMDDispatch::resetStatus() setStatus(SIMDOps::diff, false); setStatus(SIMDOps::sfzInterpolationCast, true); setStatus(SIMDOps::mean, false); - setStatus(SIMDOps::meanSquared, false); + setStatus(SIMDOps::sumSquares, false); setStatus(SIMDOps::upsampling, true); setStatus(SIMDOps::clampAll, false); setStatus(SIMDOps::allWithin, true); @@ -292,9 +292,9 @@ float mean(const float* vector, unsigned size) noexcept } template <> -float meanSquared(const float* vector, unsigned size) noexcept +float sumSquares(const float* vector, unsigned size) noexcept { - return simdDispatch().meanSquared(vector, size); + return simdDispatch().sumSquares(vector, size); } template <> diff --git a/src/sfizz/SIMDHelpers.h b/src/sfizz/SIMDHelpers.h index c0a27c09..ae34f732 100644 --- a/src/sfizz/SIMDHelpers.h +++ b/src/sfizz/SIMDHelpers.h @@ -57,7 +57,7 @@ enum class SIMDOps { diff, sfzInterpolationCast, mean, - meanSquared, + sumSquares, upsampling, clampAll, allWithin, @@ -515,7 +515,7 @@ T mean(absl::Span vector) noexcept } /** - * @brief Computes the mean squared of a span + * @brief Computes the sum of squares of a span * * @tparam T the underlying type * @tparam SIMD use the SIMD version or the scalar version @@ -523,13 +523,33 @@ T mean(absl::Span vector) noexcept * @return T */ template -T meanSquared(const T* vector, unsigned size) noexcept +T sumSquares(const T* vector, unsigned size) noexcept { - meanSquaredScalar(vector, size); + return sumSquaresScalar(vector, size); } template <> -float meanSquared(const float* vector, unsigned size) noexcept; +float sumSquares(const float* vector, unsigned size) noexcept; + +template +T sumSquares(absl::Span vector) noexcept +{ + return sumSquares(vector.data(), vector.size()); +} + +/** + * @brief Computes the mean squared of a span + * + * @tparam T the underlying type + * @param vector + * @return T + */ +template +T meanSquared(const T* vector, unsigned size) noexcept +{ + T sum = sumSquares(vector, size); + return sum / size; +} template T meanSquared(absl::Span vector) noexcept diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index 1b644066..a6fdf375 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -30,9 +30,6 @@ sfz::Voice::Voice(int voiceNumber, sfz::Resources& resources) gainSmoother.setSmoothing(config::gainSmoothing, sampleRate); xfadeSmoother.setSmoothing(config::xfadeSmoothing, sampleRate); - - for (auto & filter : channelEnvelopeFilters) - filter.setGain(vaGain(config::filteredEnvelopeCutoff, sampleRate)); } sfz::Voice::~Voice() @@ -252,20 +249,19 @@ void sfz::Voice::setSampleRate(float sampleRate) noexcept gainSmoother.setSmoothing(config::gainSmoothing, sampleRate); xfadeSmoother.setSmoothing(config::xfadeSmoothing, sampleRate); - for (auto & filter : channelEnvelopeFilters) - filter.setGain(vaGain(config::filteredEnvelopeCutoff, sampleRate)); - for (WavetableOscillator& osc : waveOscillators) osc.init(sampleRate); for (auto& lfo : lfos) lfo->setSampleRate(sampleRate); + + powerFollower.setSampleRate(sampleRate); } void sfz::Voice::setSamplesPerBlock(int samplesPerBlock) noexcept { this->samplesPerBlock = samplesPerBlock; - this->minEnvelopeDelay = samplesPerBlock / 2; + powerFollower.setSamplesPerBlock(samplesPerBlock); } void sfz::Voice::renderBlock(AudioSpan buffer) noexcept @@ -301,7 +297,7 @@ void sfz::Voice::renderBlock(AudioSpan buffer) noexcept if (!egEnvelope.isSmoothing()) switchState(State::cleanMeUp); - updateChannelPowers(buffer); + powerFollower.process(buffer); age += buffer.getNumFrames(); if (triggerDelay) { @@ -739,11 +735,7 @@ void sfz::Voice::reset() noexcept floatPositionOffset = 0.0f; noteIsOff = false; - for (auto& f : channelEnvelopeFilters) - f.reset(); - - for (auto& p : smoothedChannelEnvelopes) - p = 0.0f; + powerFollower.clear(); filters.clear(); equalizers.clear(); @@ -773,9 +765,9 @@ void sfz::Voice::removeVoiceFromRing() noexcept nextSisterVoice = this; } -float sfz::Voice::getAverageEnvelope() const noexcept +float sfz::Voice::getAveragePower() const noexcept { - return max(smoothedChannelEnvelopes[0], smoothedChannelEnvelopes[1]); + return powerFollower.getAveragePower(); } bool sfz::Voice::releasedOrFree() const noexcept @@ -870,22 +862,6 @@ void sfz::Voice::setupOscillatorUnison() #endif } -void sfz::Voice::updateChannelPowers(AudioSpan buffer) -{ - assert(smoothedChannelEnvelopes.size() == channelEnvelopeFilters.size()); - assert(buffer.getNumChannels() <= channelEnvelopeFilters.size()); - if (buffer.getNumFrames() == 0) - return; - - for (unsigned i = 0; i < smoothedChannelEnvelopes.size(); ++i) { - const auto input = buffer.getConstSpan(i); - for (unsigned s = 0; s < buffer.getNumFrames(); ++s) - smoothedChannelEnvelopes[i] = - channelEnvelopeFilters[i].tickLowpass(std::abs(input[s])); - } -} - - void sfz::Voice::switchState(State s) { if (s != state) { diff --git a/src/sfizz/Voice.h b/src/sfizz/Voice.h index 5b72e799..0aec391e 100644 --- a/src/sfizz/Voice.h +++ b/src/sfizz/Voice.h @@ -15,6 +15,7 @@ #include "AudioSpan.h" #include "LeakDetector.h" #include "OnePoleFilter.h" +#include "PowerFollower.h" #include "NumericId.h" #include "absl/types/span.h" #include @@ -261,7 +262,7 @@ public: * * @return float */ - float getAverageEnvelope() const noexcept; + float getAveragePower() const noexcept; /** * @brief Get the position of the voice in the source, in samples * @@ -450,7 +451,6 @@ private: FilePromisePtr currentPromise { nullptr }; int samplesPerBlock { config::defaultSamplesPerBlock }; - int minEnvelopeDelay { config::defaultSamplesPerBlock / 2 }; float sampleRate { config::defaultSampleRate }; Resources& resources; @@ -486,10 +486,8 @@ private: Smoother xfadeSmoother; void resetSmoothers() noexcept; - std::array, 2> channelEnvelopeFilters; - std::array smoothedChannelEnvelopes; + PowerFollower powerFollower; - HistoricalBuffer powerHistory { config::powerHistoryLength }; LEAK_DETECTOR(Voice); }; diff --git a/src/sfizz/VoiceStealing.cpp b/src/sfizz/VoiceStealing.cpp index 49e1b2d0..0fa4f1a7 100644 --- a/src/sfizz/VoiceStealing.cpp +++ b/src/sfizz/VoiceStealing.cpp @@ -13,13 +13,13 @@ sfz::Voice* sfz::VoiceStealing::steal(absl::Span voices) noexcept // Start of the voice stealing algorithm absl::c_stable_sort(voices, voiceOrdering); - const auto sumEnvelope = absl::c_accumulate(voices, 0.0f, [](float sum, const Voice* v) { - return sum + v->getAverageEnvelope(); + const auto sumPower = absl::c_accumulate(voices, 0.0f, [](float sum, const Voice* v) { + return sum + v->getAveragePower(); }); - // We are checking the envelope to try and kill voices with relative low contribution + // We are checking the power to try and kill voices with relative low contribution // to the output compared to the rest. - const auto envThreshold = sumEnvelope - / static_cast(voices.size()) * config::stealingEnvelopeCoeff; + const auto powerThreshold = sumPower + / static_cast(voices.size()) * config::stealingPowerCoeff; // We are checking the age so that voices have the time to build up attack // This is not perfect because pad-type voices will take a long time to output // their sound, but it's reasonable for sounds with a quick attack and longer @@ -37,12 +37,12 @@ sfz::Voice* sfz::VoiceStealing::steal(absl::Span voices) noexcept break; } - float maxEnvelope { 0.0f }; + float maxPower { 0.0f }; SisterVoiceRing::applyToRing(ref, [&](Voice* v) { - maxEnvelope = max(maxEnvelope, v->getAverageEnvelope()); + maxPower = max(maxPower, v->getAveragePower()); }); - if (maxEnvelope < envThreshold) { + if (maxPower < powerThreshold) { returnedVoice = ref; break; } diff --git a/src/sfizz/simd/HelpersSSE.cpp b/src/sfizz/simd/HelpersSSE.cpp index 3ae8b984..d17288e7 100644 --- a/src/sfizz/simd/HelpersSSE.cpp +++ b/src/sfizz/simd/HelpersSSE.cpp @@ -370,7 +370,7 @@ float meanSSE(const float* vector, unsigned size) noexcept return result / static_cast(size); } -float meanSquaredSSE(const float* vector, unsigned size) noexcept +float sumSquaresSSE(const float* vector, unsigned size) noexcept { const auto sentinel = vector + size; @@ -404,7 +404,7 @@ float meanSquaredSSE(const float* vector, unsigned size) noexcept vector++; } - return result / static_cast(size); + return result; } void cumsumSSE(const float* input, float* output, unsigned size) noexcept diff --git a/src/sfizz/simd/HelpersSSE.h b/src/sfizz/simd/HelpersSSE.h index cff28650..5046d914 100644 --- a/src/sfizz/simd/HelpersSSE.h +++ b/src/sfizz/simd/HelpersSSE.h @@ -22,7 +22,7 @@ void subtractSSE(const float* input, float* output, unsigned size) noexcept; void subtract1SSE(float value, float* output, unsigned size) noexcept; void copySSE(const float* input, float* output, unsigned size) noexcept; float meanSSE(const float* vector, unsigned size) noexcept; -float meanSquaredSSE(const float* vector, unsigned size) noexcept; +float sumSquaresSSE(const float* vector, unsigned size) noexcept; void cumsumSSE(const float* input, float* output, unsigned size) noexcept; void diffSSE(const float* input, float* output, unsigned size) noexcept; void clampAllSSE(float* input, float low, float high, unsigned size) noexcept; diff --git a/src/sfizz/simd/HelpersScalar.h b/src/sfizz/simd/HelpersScalar.h index d5ac1162..871a9ff6 100644 --- a/src/sfizz/simd/HelpersScalar.h +++ b/src/sfizz/simd/HelpersScalar.h @@ -142,7 +142,7 @@ T meanScalar(const T* vector, unsigned size) noexcept } template -T meanSquaredScalar(const T* vector, unsigned size) noexcept +T sumSquaresScalar(const T* vector, unsigned size) noexcept { T result{ 0.0 }; if (size == 0) @@ -154,7 +154,7 @@ T meanSquaredScalar(const T* vector, unsigned size) noexcept vector++; } - return result / static_cast(size); + return result; } template diff --git a/tests/SIMDHelpersT.cpp b/tests/SIMDHelpersT.cpp index 805bb0f9..f0ef8277 100644 --- a/tests/SIMDHelpersT.cpp +++ b/tests/SIMDHelpersT.cpp @@ -690,9 +690,9 @@ TEST_CASE("[Helpers] Mean (SIMD vs scalar)") TEST_CASE("[Helpers] Mean Squared") { std::array input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f }; - sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::sumSquares, false); REQUIRE(sfz::meanSquared(input) == 38.5f); - sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::sumSquares, true); REQUIRE(sfz::meanSquared(input) == 38.5f); } @@ -700,9 +700,9 @@ TEST_CASE("[Helpers] Mean Squared (SIMD vs scalar)") { std::vector input(medBufferSize); absl::c_iota(input, 0.0f); - sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::sumSquares, false); auto scalarResult = sfz::meanSquared(input); - sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::sumSquares, true); auto simdResult = sfz::meanSquared(input); REQUIRE( scalarResult == Approx(simdResult).margin(1e-3) ); }