From 95d3343341db5e16d390decccb3a4aa8c949c847 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 12 Nov 2020 08:04:55 +0100 Subject: [PATCH] Add API to process CC events received by automation --- src/sfizz.h | 17 ++++++++++++++ src/sfizz.hpp | 15 +++++++++++++ src/sfizz/Synth.cpp | 45 ++++++++++++++++++++++++------------- src/sfizz/Synth.h | 9 ++++++++ src/sfizz/SynthPrivate.h | 10 +++++++++ src/sfizz/sfizz.cpp | 5 +++++ src/sfizz/sfizz_wrapper.cpp | 5 +++++ 7 files changed, 90 insertions(+), 16 deletions(-) diff --git a/src/sfizz.h b/src/sfizz.h index b20e7eae..b2e74c62 100644 --- a/src/sfizz.h +++ b/src/sfizz.h @@ -321,6 +321,23 @@ SFIZZ_EXPORTED_API void sfizz_send_cc(sfizz_synth_t* synth, int delay, int cc_nu */ SFIZZ_EXPORTED_API void sfizz_send_hdcc(sfizz_synth_t* synth, int delay, int cc_number, float norm_value); +/** + * @brief Send a high precision CC automation to the synth. + * + * This updates the CC value known to the synth, but without performing + * additional MIDI-specific interpretations. (eg. the CC 120 and up) + * + * As with all MIDI events, this needs to happen before the call to + * sfizz_render_block() in each block and should appear in order of the delays. + * @since 0.6.0 + * + * @param synth The synth. + * @param delay The delay of the event in the block, in samples. + * @param cc_number The MIDI CC number. + * @param norm_value The normalized CC value, in domain 0 to 1. + */ +SFIZZ_EXPORTED_API void sfizz_automate_hdcc(sfizz_synth_t* synth, int delay, int cc_number, float norm_value); + /** * @brief Send a pitch wheel event. * diff --git a/src/sfizz.hpp b/src/sfizz.hpp index f86eea8a..426795e4 100644 --- a/src/sfizz.hpp +++ b/src/sfizz.hpp @@ -296,6 +296,21 @@ public: */ void hdcc(int delay, int ccNumber, float normValue) noexcept; + /** + * @brief Send a high precision CC automation to the synth + * + * This updates the CC value known to the synth, but without performing + * additional MIDI-specific interpretations. (eg. the CC 120 and up) + * + * @since 0.6.0 + * + * @param delay the delay at which the event occurs; this should be lower + * than the size of the block in the next call to renderBlock(). + * @param ccNumber the cc number. + * @param normValue the normalized cc value, in domain 0 to 1. + */ + void automateHdcc(int delay, int ccNumber, float normValue) noexcept; + /** * @brief Send a pitch bend event to the synth * @since 0.2.0 diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 3ea3236f..79651e4e 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -1090,34 +1090,47 @@ void Synth::Impl::ccDispatch(int delay, int ccNumber, float value) noexcept } void Synth::hdcc(int delay, int ccNumber, float normValue) noexcept +{ + Impl& impl = *impl_; + impl.performHdcc(delay, ccNumber, normValue, true); +} + +void Synth::automateHdcc(int delay, int ccNumber, float normValue) noexcept +{ + Impl& impl = *impl_; + impl.performHdcc(delay, ccNumber, normValue, false); +} + +void Synth::Impl::performHdcc(int delay, int ccNumber, float normValue, bool asMidi) noexcept { ASSERT(ccNumber < config::numCCs); ASSERT(ccNumber >= 0); - Impl& impl = *impl_; - ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration }; - impl.resources_.midiState.ccEvent(delay, ccNumber, normValue); + ScopedTiming logger { dispatchDuration_, ScopedTiming::Operation::addToDuration }; + resources_.midiState.ccEvent(delay, ccNumber, normValue); - const std::unique_lock lock { impl.callbackGuard_, std::try_to_lock }; + const std::unique_lock lock { callbackGuard_, std::try_to_lock }; if (!lock.owns_lock()) return; - if (ccNumber == config::resetCC) { - impl.resetAllControllers(delay); - return; + if (asMidi) { + if (ccNumber == config::resetCC) { + resetAllControllers(delay); + return; + } + + if (ccNumber == config::allNotesOffCC || ccNumber == config::allSoundOffCC) { + for (auto& voice : voiceManager_) + voice.reset(); + resources_.midiState.allNotesOff(delay); + return; + } } - if (ccNumber == config::allNotesOffCC || ccNumber == config::allSoundOffCC) { - for (auto& voice : impl.voiceManager_) - voice.reset(); - impl.resources_.midiState.allNotesOff(delay); - return; - } - - for (auto& voice : impl.voiceManager_) + for (auto& voice : voiceManager_) voice.registerCC(delay, ccNumber, normValue); - impl.ccDispatch(delay, ccNumber, normValue); + ccDispatch(delay, ccNumber, normValue); } void Synth::Impl::setDefaultHdcc(int ccNumber, float value) diff --git a/src/sfizz/Synth.h b/src/sfizz/Synth.h index 0e53b17e..b95f193f 100644 --- a/src/sfizz/Synth.h +++ b/src/sfizz/Synth.h @@ -342,6 +342,15 @@ public: * @param normValue the normalized cc value, in domain 0 to 1 */ void hdcc(int delay, int ccNumber, float normValue) noexcept; + /** + * @brief Send a high precision CC automation to the synth + * + * @param delay the delay at which the event occurs; this should be lower + * than the size of the block in the next call to renderBlock(). + * @param ccNumber the cc number. + * @param normValue the normalized cc value, in domain 0 to 1. + */ + void automateHdcc(int delay, int ccNumber, float normValue) noexcept; /** * @brief Get the current value of a controller under the current instrument * diff --git a/src/sfizz/SynthPrivate.h b/src/sfizz/SynthPrivate.h index 5daf775b..bcc48e24 100644 --- a/src/sfizz/SynthPrivate.h +++ b/src/sfizz/SynthPrivate.h @@ -179,6 +179,16 @@ struct Synth::Impl final: public Parser::Listener { std::bitset collectAllUsedCCs(); + /** + * @brief Perform a CC event + * + * @param delay The delay + * @param ccNumber The CC number + * @param normValue The normalized value + * @param asMidi Whether to process as a MIDI event + */ + void performHdcc(int delay, int ccNumber, float normValue, bool asMidi) noexcept; + /** * @brief Set the default value for a CC * diff --git a/src/sfizz/sfizz.cpp b/src/sfizz/sfizz.cpp index 18b2a10c..a8cc7e7c 100644 --- a/src/sfizz/sfizz.cpp +++ b/src/sfizz/sfizz.cpp @@ -144,6 +144,11 @@ void sfz::Sfizz::hdcc(int delay, int ccNumber, float normValue) noexcept synth->hdcc(delay, ccNumber, normValue); } +void sfz::Sfizz::automateHdcc(int delay, int ccNumber, float normValue) noexcept +{ + synth->automateHdcc(delay, ccNumber, normValue); +} + void sfz::Sfizz::pitchWheel(int delay, int pitch) noexcept { synth->pitchWheel(delay, pitch); diff --git a/src/sfizz/sfizz_wrapper.cpp b/src/sfizz/sfizz_wrapper.cpp index 0ca6de29..f4d1866c 100644 --- a/src/sfizz/sfizz_wrapper.cpp +++ b/src/sfizz/sfizz_wrapper.cpp @@ -146,6 +146,11 @@ void sfizz_send_hdcc(sfizz_synth_t* synth, int delay, int cc_number, float norm_ auto* self = reinterpret_cast(synth); self->hdcc(delay, cc_number, norm_value); } +void sfizz_automate_hdcc(sfizz_synth_t* synth, int delay, int cc_number, float norm_value) +{ + auto* self = reinterpret_cast(synth); + self->automateHdcc(delay, cc_number, norm_value); +} void sfizz_send_pitch_wheel(sfizz_synth_t* synth, int delay, int pitch) { auto* self = reinterpret_cast(synth);