diff --git a/src/sfizz/ModifierHelpers.h b/src/sfizz/ModifierHelpers.h index f853b136..5ea57c02 100644 --- a/src/sfizz/ModifierHelpers.h +++ b/src/sfizz/ModifierHelpers.h @@ -1,3 +1,9 @@ +// 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 "Range.h" @@ -55,6 +61,14 @@ float crossfadeOut(const sfz::Range& crossfadeRange, U value, SfzCrossfadeCur return 1.0f; } +/** + * @brief Compute a linear envelope based on events, with a lambda applied to the event values + * + * @tparam F + * @param events + * @param envelope + * @param lambda + */ template void linearEnvelope(const EventVector& events, absl::Span envelope, F&& lambda) { @@ -76,6 +90,15 @@ void linearEnvelope(const EventVector& events, absl::Span envelope, F&& l fill(envelope.subspan(lastDelay), lastValue); } +/** + * @brief Compute a quantized linear envelope based on events, with a lambda applied to the event values + * + * @tparam F + * @param events + * @param envelope + * @param lambda + * @param step + */ template void linearEnvelope(const EventVector& events, absl::Span envelope, F&& lambda, float step) { @@ -116,6 +139,15 @@ void linearEnvelope(const EventVector& events, absl::Span envelope, F&& l fill(envelope.subspan(lastDelay), lastValue); } + +/** + * @brief Compute a multiplicative envelope based on events, with a lambda applied to the event values + * + * @tparam F + * @param events + * @param envelope + * @param lambda + */ template void multiplicativeEnvelope(const EventVector& events, absl::Span envelope, F&& lambda) { @@ -139,6 +171,16 @@ void multiplicativeEnvelope(const EventVector& events, absl::Span envelop fill(envelope.subspan(lastDelay), lastValue); } +/** + * @brief Compute a quantized multiplicative envelope based on events, with a lambda applied to the event values + * + * @tparam F + * @tparam Round is true if the quantization rounds rather than truncs the elements + * @param events + * @param envelope + * @param lambda + * @param step + */ template void multiplicativeEnvelope(const EventVector& events, absl::Span envelope, F&& lambda, float step) { @@ -186,18 +228,46 @@ void multiplicativeEnvelope(const EventVector& events, absl::Span envelop fill(envelope.subspan(lastDelay), lastValue); } +/** + * @brief Alias for a multiplicative envelope that rounds the elements + * + * @tparam F + * @param events + * @param envelope + * @param lambda + * @param step + */ template void pitchBendEnvelope(const EventVector& events, absl::Span envelope, F&& lambda, float step) { multiplicativeEnvelope(events, envelope, std::forward(lambda), step); } +/** + * @brief Alias for a multiplicative envelope + * + * @tparam F + * @param events + * @param envelope + * @param lambda + */ template void pitchBendEnvelope(const EventVector& events, absl::Span envelope, F&& lambda) { multiplicativeEnvelope(events, envelope, std::forward(lambda)); } +/** + * @brief Builds a linear envelope, possibly quantized, based on the events fetched + * from a midi state and the modifier data. This is a helper function for recurrent + * code in the voice logic. + * + * @tparam F + * @param resources + * @param span + * @param ccData + * @param lambda + */ template void linearModifier(const sfz::Resources& resources, absl::Span span, const sfz::CCData& ccData, F&& lambda) { @@ -217,6 +287,17 @@ void linearModifier(const sfz::Resources& resources, absl::Span span, con } } +/** + * @brief Builds a multiplicative envelope, possibly quantized, based on the events fetched + * from a midi state and the modifier data. This is a helper function for recurrent + * code in the voice logic. + * + * @tparam F + * @param resources + * @param span + * @param ccData + * @param lambda + */ template void multiplicativeModifier(const sfz::Resources& resources, absl::Span span, const sfz::CCData& ccData, F&& lambda) { @@ -236,6 +317,15 @@ void multiplicativeModifier(const sfz::Resources& resources, absl::Span s } } +/** + * @brief Alias for a simple linear modifier with no lambda + * + * @tparam F + * @param resources + * @param span + * @param ccData + * @param lambda + */ inline void linearModifier(const sfz::Resources& resources, absl::Span span, const sfz::CCData& ccData) { linearModifier(resources, span, ccData, [](float x) { return x; }); diff --git a/src/sfizz/Modifiers.h b/src/sfizz/Modifiers.h index bdf4508a..3a6573be 100644 --- a/src/sfizz/Modifiers.h +++ b/src/sfizz/Modifiers.h @@ -1,3 +1,9 @@ +// 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 #include @@ -5,6 +11,10 @@ namespace sfz { +/** + * @brief Base modifier class + * + */ struct Modifier { float value { 0.0f }; float step { 0.0f }; @@ -23,6 +33,11 @@ enum class Mod : size_t { sentinel }; +/** + * @brief Vectors of elements indexed on modifiers with casting and iterators + * + * @tparam T + */ template class ModifierVector : public std::vector { public: @@ -30,6 +45,11 @@ public: const T& operator[](sfz::Mod idx) const { return this->std::vector::operator[](static_cast(idx)); } }; +/** + * @brief Array of elements indexed on modifiers with casting and iterators + * + * @tparam T + */ template class ModifierArray { public: diff --git a/src/sfizz/Smoothers.cpp b/src/sfizz/Smoothers.cpp index 9f40b67d..252d1f50 100644 --- a/src/sfizz/Smoothers.cpp +++ b/src/sfizz/Smoothers.cpp @@ -1,3 +1,9 @@ +// 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 "Smoothers.h" namespace sfz { diff --git a/src/sfizz/Smoothers.h b/src/sfizz/Smoothers.h index 4793f423..20eb4e3a 100644 --- a/src/sfizz/Smoothers.h +++ b/src/sfizz/Smoothers.h @@ -1,3 +1,9 @@ +// 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 "Config.h" @@ -9,11 +15,34 @@ #include namespace sfz { +/** + * @brief Wrapper class for a one pole filter smoother + * + */ class Smoother { public: Smoother(); + /** + * @brief Set the filter cutoff based on the sfz smoothing value + * and the sample rate. + * + * @param smoothValue + * @param sampleRate + */ void setSmoothing(uint8_t smoothValue, float sampleRate); + /** + * @brief Reset the filter state to a given value + * + * @param value + */ void reset(float value = 0.0f); + /** + * @brief Process a span of data. Input and output can refer to the same + * memory. + * + * @param input + * @param output + */ void process(absl::Span input, absl::Span output); private: diff --git a/src/sfizz/Voice.h b/src/sfizz/Voice.h index adbe7d81..6967e780 100644 --- a/src/sfizz/Voice.h +++ b/src/sfizz/Voice.h @@ -333,13 +333,46 @@ private: const AudioSpan& source, AudioSpan& dest, absl::Span indices, absl::Span coeffs); + /** + * @brief Compute the amplitude envelope, applied as a gain to a mono + * or stereo buffer + * + * @param modulationSpan + */ void amplitudeEnvelope(absl::Span modulationSpan) noexcept; + /** + * @brief Amplitude stage for a mono source + * + * @param buffer + */ void ampStageMono(AudioSpan buffer) noexcept; + /** + * @brief Amplitude stage for a stereo source + * + * @param buffer + */ void ampStageStereo(AudioSpan buffer) noexcept; + /** + * @brief Amplitude stage for a mono source + * + * @param buffer + */ void panStageMono(AudioSpan buffer) noexcept; void panStageStereo(AudioSpan buffer) noexcept; + /** + * @brief Amplitude stage for a mono source + * + * @param buffer + */ void filterStageMono(AudioSpan buffer) noexcept; void filterStageStereo(AudioSpan buffer) noexcept; + /** + * @brief Compute the pitch envelope. This envelope is meant to multiply + * the frequency parameter for each sample (which translates to floating + * point intervals for sample-based voices, or phases for generators) + * + * @param pitchSpan + */ void pitchEnvelope(absl::Span pitchSpan) noexcept; /** @@ -348,6 +381,14 @@ private: */ void removeVoiceFromRing() noexcept; + /** + * @brief Helper function to iterate jointly on modifiers and smoothers + * for a given modulation target of type sfz::Mod + * + * @tparam F + * @param modId + * @param lambda + */ template void forEachWithSmoother(sfz::Mod modId, F&& lambda) {