LCOV - code coverage report
Current view: top level - src/MIDI_Inputs - NoteCCRange.hpp (source / functions) Hit Total Coverage
Test: e224b347cd670555e44f06608ac41bd1ace9d9d8 Lines: 70 71 98.6 %
Date: 2020-09-08 17:44:46 Functions: 89 113 78.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : #pragma once
       2             : 
       3             : #include <Banks/BankableMIDIInput.hpp>
       4             : #include <MIDI_Inputs/MIDIInputElementCC.hpp>
       5             : #include <MIDI_Inputs/MIDIInputElementNote.hpp>
       6             : 
       7             : BEGIN_CS_NAMESPACE
       8             : 
       9             : /**
      10             :  * @brief   Interface for NoteCCValue objects: provides getters for the 
      11             :  *          velocity or controller values.
      12             :  */
      13             : class INoteCCValue {
      14             :   protected:
      15          12 :     INoteCCValue(uint8_t rangeLength) : rangeLength{rangeLength} {}
      16             : 
      17             :   public:
      18             :     /// Get the length of the range of note/CC addresses.
      19           6 :     uint8_t length() const { return rangeLength; }
      20             :     /// Get the velocity or controller value for the given index in the range.
      21             :     virtual uint8_t getValue(uint8_t index) const = 0;
      22             :     /// Get the velocity or controller value of the first or only note or
      23             :     /// controller.
      24          15 :     uint8_t getValue() const { return getValue(0); }
      25             : 
      26             :   private:
      27             :     uint8_t rangeLength;
      28             : };
      29             : 
      30             : /**
      31             :  * @brief   A callback for NoteCCRange that doesn't do anything.
      32             :  */
      33             : class NoteCCRangeEmptyCallback {
      34             :   public:
      35           9 :     void begin(const INoteCCValue &) {}
      36          13 :     void update(const INoteCCValue &, uint8_t) {}
      37          30 :     void updateAll(const INoteCCValue &) {}
      38             : };
      39             : 
      40             : /**
      41             :  * @brief   A callback for NoteCCRange with an action that can be implemented 
      42             :  *          by the user.
      43             :  * 
      44             :  * Provides default implementations for `begin` and `updateAll`.
      45             :  */
      46           3 : struct SimpleNoteCCValueCallback {
      47             :   protected:
      48           3 :     SimpleNoteCCValueCallback() = default;
      49             : 
      50             :   public:
      51             :     /// Initialize: called once
      52           0 :     virtual void begin(const INoteCCValue &) {}
      53             :     /// Update the given index: called when a new message is received for this
      54             :     /// index
      55             :     virtual void update(const INoteCCValue &noteccval, uint8_t index) = 0;
      56             :     /// Update all values: called when a bank change causes all values to
      57             :     /// (possibly) change, or when the entire range is reset to zero.
      58           3 :     virtual void updateAll(const INoteCCValue &noteccval) {
      59           6 :         for (uint8_t i = 0; i < noteccval.length(); ++i)
      60           3 :             update(noteccval, i);
      61           3 :     }
      62             : };
      63             : 
      64             : // -------------------------------------------------------------------------- //
      65             : 
      66             : /** 
      67             :  * @brief   Base class for all other classes that listen for incoming MIDI Note 
      68             :  *          or Control Change messages and saves their values.
      69             :  * 
      70             :  * Can listen to a range of addresses or a single address.
      71             :  */
      72             : template <class MIDIInput_t, uint8_t RangeLen, uint8_t NumBanks, class Callback>
      73          12 : class NoteCCRange : public MIDIInput_t, public INoteCCValue {
      74             :   public:
      75          12 :     NoteCCRange(MIDIAddress address, const Callback &callback)
      76          24 :         : MIDIInput_t{address}, INoteCCValue{RangeLen}, callback(callback) {}
      77             : 
      78             :     /// @todo   check index bounds
      79         138 :     uint8_t getValue(uint8_t index) const final override {
      80         138 :         return values[getSelection()][index];
      81             :     }
      82             :     using INoteCCValue::getValue;
      83             : 
      84             :     /// Initialize
      85          12 :     void begin() override { callback.begin(*this); }
      86             :     /// Reset all values to zero
      87           2 :     void reset() override {
      88           2 :         values = {{}};
      89           2 :         callback.updateAll(*this);
      90           2 :     }
      91             : 
      92             :   private:
      93             :     // Called when a MIDI message comes in, and if that message has been matched
      94             :     // by the `match` method.
      95          24 :     bool updateImpl(const ChannelMessageMatcher &midimsg,
      96             :                     const MIDIAddress &target) override {
      97             :         // Compute the offsets/indices in the range and the bank.
      98             :         // E.g. if the start address of the range is 10 and the incoming message
      99             :         // is on address 15, the range index will be 5 = 15 - 10.
     100             :         // Very similar for banks, but in that case there are 3 possible 
     101             :         // addresses (note/controller number, MIDI channel and MIDI cable).
     102          24 :         uint8_t bankIndex = this->getBankIndex(target);
     103          24 :         uint8_t rangeIndex = this->getRangeIndex(target);
     104             :         // extract the velocity or controller value from the message
     105          24 :         uint8_t value = getValueFromMIDIMessage(midimsg);
     106             :         // save the value
     107          24 :         values[bankIndex][rangeIndex] = value;
     108             :         // if the bank that the message belongs to is the active bank,
     109             :         // update the display
     110          24 :         if (bankIndex == this->getSelection())
     111          20 :             callback.update(*this, rangeIndex);
     112             :         // event was handled successfully
     113          24 :         return true;
     114          24 :     }
     115             : 
     116             :     /// Extract the "value" from a MIDI Note or Control Change message.
     117             :     /// For Note On and Control Change, this is simply the second data byte,
     118             :     /// for Note Off, it's zero.
     119             :     static uint8_t
     120          24 :     getValueFromMIDIMessage(const ChannelMessageMatcher &midimsg) {
     121          24 :         return midimsg.type == MIDIMessageType::NOTE_OFF ? 0 : midimsg.data2;
     122             :     }
     123             : 
     124             :     /// Get the active bank selection.
     125          46 :     virtual uint8_t getSelection() const { return 0; }
     126             : 
     127             :     /// Get the bank index from a MIDI address.
     128          16 :     virtual setting_t getBankIndex(MIDIAddress target) const {
     129             :         // Default implementation for non-bankable version (bank is always 0)
     130             :         (void)target;
     131          16 :         return 0;
     132             :     }
     133             : 
     134             :     /// Get the index of the given MIDI address in the range
     135          16 :     virtual uint8_t getRangeIndex(MIDIAddress target) const {
     136             :         // Default implementation for non-bankable version (base address of the 
     137             :         // range is fixed)
     138          16 :         return target.getAddress() - this->address.getAddress();
     139             :     }
     140             : 
     141             :     /// A 2D array for saving all values of the range, for all banks.
     142          16 :     Array<Array<uint8_t, RangeLen>, NumBanks> values = {{}};
     143             : 
     144             :   public:
     145             :     /// Callback that is called when a value in the active bank changes.
     146             :     Callback callback;
     147             :     /// Get the length of the range.
     148             :     constexpr static uint8_t length() { return RangeLen; }
     149             : };
     150             : 
     151             : // -------------------------------------------------------------------------- //
     152             : 
     153             : template <class MIDIInput_t, uint8_t RangeLen,
     154             :           class Callback = NoteCCRangeEmptyCallback>
     155           8 : class GenericNoteCCRange
     156             :     : public NoteCCRange<MIDIInput_t, RangeLen, 1, Callback> {
     157             :   public:
     158           8 :     GenericNoteCCRange(MIDIAddress address, const Callback &callback)
     159           8 :         : NoteCCRange<MIDIInput_t, RangeLen, 1, Callback>{address, callback} {}
     160             : 
     161             :   private:
     162             :     /// Check if the address of the incoming MIDI message is within the range
     163             :     /// of addresses of this element.
     164          16 :     bool match(const MIDIAddress &target) const override {
     165          16 :         return MIDIAddress::matchAddressInRange( //
     166          16 :             target, this->address, RangeLen);
     167             :     }
     168             : };
     169             : 
     170             : template <uint8_t RangeLen, class Callback = NoteCCRangeEmptyCallback>
     171             : using GenericNoteRange =
     172             :     GenericNoteCCRange<MIDIInputElementNote, RangeLen, Callback>;
     173             : 
     174             : template <uint8_t RangeLen, class Callback = NoteCCRangeEmptyCallback>
     175             : using GenericCCRange =
     176             :     GenericNoteCCRange<MIDIInputElementCC, RangeLen, Callback>;
     177             : 
     178             : template <class Callback = NoteCCRangeEmptyCallback>
     179             : using GenericNoteValue = GenericNoteCCRange<MIDIInputElementNote, 1, Callback>;
     180             : 
     181             : template <class Callback = NoteCCRangeEmptyCallback>
     182             : using GenericCCValue = GenericNoteCCRange<MIDIInputElementCC, 1, Callback>;
     183             : 
     184             : /**
     185             :  * @brief   MIDI Input Element that listens to a range of notes and saves their
     186             :  *          velocity values.
     187             :  * 
     188             :  * @ingroup MIDIInputElements
     189             :  * @tparam  RangeLen 
     190             :  *          The length of the range of notes to listen to.
     191             :  */
     192             : template <uint8_t RangeLen>
     193           1 : class NoteRange : public GenericNoteRange<RangeLen> {
     194             :   public:
     195           1 :     NoteRange(MIDIAddress address)
     196           1 :         : GenericNoteRange<RangeLen>{address, {}} {}
     197             : };
     198             : 
     199             : /**
     200             :  * @brief   MIDI Input Element that listens to a single note and saves its 
     201             :  *          velocity value.
     202             :  * 
     203             :  * @ingroup MIDIInputElements
     204             :  */
     205           4 : class NoteValue : public GenericNoteValue<> {
     206             :   public:
     207           4 :     NoteValue(MIDIAddress address) : GenericNoteValue<>{address, {}} {}
     208             : };
     209             : using MIDINote[[deprecated("Use NoteValue instead")]] = NoteValue;
     210             : 
     211             : /**
     212             :  * @brief   MIDI Input Element that listens to a range of controllers
     213             :  *          and saves their values.
     214             :  * 
     215             :  * @ingroup MIDIInputElements
     216             :  * @tparam  RangeLen 
     217             :  *          The length of the range of controllers to listen to.
     218             :  */
     219             : template <uint8_t RangeLen>
     220             : class CCRange : public GenericCCRange<RangeLen> {
     221             :   public:
     222             :     CCRange(MIDIAddress address)
     223             :         : GenericCCRange<RangeLen>{address, {}} {}
     224             : };
     225             : 
     226             : /**
     227             :  * @brief   MIDI Input Element that listens to a single controller and saves its
     228             :  *          value.
     229             :  * 
     230             :  * @ingroup MIDIInputElements
     231             :  */
     232             : class CCValue : public GenericCCValue<> {
     233             :   public:
     234             :     CCValue(MIDIAddress address) : GenericCCValue<>{address, {}} {}
     235             : };
     236             : 
     237             : // -------------------------------------------------------------------------- //
     238             : 
     239             : namespace Bankable {
     240             : 
     241             : /// @tparam RangeLen
     242             : ///         The length of the range.
     243             : /// @tparam NumBanks
     244             : ///         The size of the bank.
     245             : template <class MIDIInput_t, uint8_t RangeLen, uint8_t NumBanks,
     246             :           class Callback = NoteCCRangeEmptyCallback>
     247           4 : class GenericNoteCCRange
     248             :     : public NoteCCRange<MIDIInput_t, RangeLen, NumBanks, Callback>,
     249             :       public BankableMIDIInput<NumBanks> {
     250             :   public:
     251           4 :     GenericNoteCCRange(BankConfig<NumBanks> config,
     252             :                        MIDIAddress address,
     253             :                        const Callback &callback)
     254           4 :         : NoteCCRange<MIDIInput_t, RangeLen, NumBanks, Callback>{
     255           4 :             address,
     256           4 :             callback,
     257           8 :         }, BankableMIDIInput<NumBanks>{config} {}
     258             : 
     259             :   private:
     260             :     /// Check if the address of the incoming MIDI message is within the range
     261             :     /// of addresses and in one of the banks of this element.
     262          20 :     bool match(const MIDIAddress &target) const override {
     263          40 :         return BankableMIDIInput<NumBanks>::matchBankableAddressInRange(
     264          20 :             target, this->address, RangeLen);
     265             :     }
     266             : 
     267         116 :     setting_t getSelection() const override {
     268         116 :         return BankableMIDIInput<NumBanks>::getSelection();
     269             :     };
     270             : 
     271           8 :     uint8_t getBankIndex(MIDIAddress target) const override {
     272           8 :         return BankableMIDIInput<NumBanks>::getBankIndex(target, this->address);
     273             :     }
     274             : 
     275           8 :     uint8_t getRangeIndex(MIDIAddress target) const override {
     276          16 :         return BankableMIDIInput<NumBanks>::getRangeIndex(target,
     277           8 :                                                           this->address);
     278             :     }
     279             : 
     280          28 :     void onBankSettingChange() override { this->callback.updateAll(*this); }
     281             : };
     282             : 
     283             : template <uint8_t RangeLen, uint8_t NumBanks,
     284             :           class Callback = NoteCCRangeEmptyCallback>
     285             : using GenericNoteRange =
     286             :     GenericNoteCCRange<MIDIInputElementNote, RangeLen, NumBanks, Callback>;
     287             : 
     288             : template <uint8_t RangeLen, uint8_t NumBanks,
     289             :           class Callback = NoteCCRangeEmptyCallback>
     290             : using GenericCCRange =
     291             :     GenericNoteCCRange<MIDIInputElementCC, RangeLen, NumBanks, Callback>;
     292             : 
     293             : template <uint8_t NumBanks, class Callback = NoteCCRangeEmptyCallback>
     294             : using GenericNoteValue =
     295             :     GenericNoteCCRange<MIDIInputElementNote, 1, NumBanks, Callback>;
     296             : 
     297             : template <uint8_t NumBanks, class Callback = NoteCCRangeEmptyCallback>
     298             : using GenericCCValue =
     299             :     GenericNoteCCRange<MIDIInputElementCC, 1, NumBanks, Callback>;
     300             : 
     301             : /**
     302             :  * @brief   MIDI Input Element that listens to a range of notes and saves their
     303             :  *          velocity values.
     304             :  * 
     305             :  * @ingroup BankableMIDIInputElements
     306             :  * @tparam  RangeLen 
     307             :  *          The length of the range of notes to listen to.
     308             :  * @tparam  NumBanks 
     309             :  *          The size of the bank.
     310             :  */
     311             : template <uint8_t RangeLen, uint8_t NumBanks>
     312           4 : class NoteRange : public GenericNoteRange<RangeLen, NumBanks> {
     313             :   public:
     314           4 :     NoteRange(BankConfig<NumBanks> config, MIDIAddress address)
     315           4 :         : GenericNoteRange<RangeLen, NumBanks>{config, address, {}} {}
     316             : };
     317             : 
     318             : /**
     319             :  * @brief   MIDI Input Element that listens to a single note and saves its
     320             :  *          value.
     321             :  * 
     322             :  * @ingroup BankableMIDIInputElements
     323             :  * @tparam  NumBanks 
     324             :  *          The size of the bank.
     325             :  */
     326             : template <uint8_t NumBanks>
     327             : class NoteValue : public GenericNoteValue<NumBanks> {
     328             :   public:
     329             :     NoteValue(BankConfig<NumBanks> config, MIDIAddress address)
     330             :         : GenericNoteValue<NumBanks>{config, address, {}} {}
     331             : };
     332             : 
     333             : /// Deprecated.
     334             : /// @see Bankable::NoteValue
     335             : template <uint8_t NumBanks>
     336             : using MIDINote[[deprecated("Use NoteValue instead")]] = NoteValue<NumBanks>;
     337             : 
     338             : /**
     339             :  * @brief   MIDI Input Element that listens to a range of controllers and saves 
     340             :  *          their values.
     341             :  * 
     342             :  * @ingroup BankableMIDIInputElements
     343             :  * @tparam  RangeLen 
     344             :  *          The length of the range of controllers to listen to.
     345             :  * @tparam  NumBanks 
     346             :  *          The size of the bank.
     347             :  */
     348             : template <uint8_t RangeLen, uint8_t NumBanks>
     349             : class CCRange : public GenericCCRange<RangeLen, NumBanks> {
     350             :   public:
     351             :     CCRange(BankConfig<NumBanks> config, MIDIAddress address)
     352             :         : GenericCCRange<RangeLen, NumBanks>{config, address, {}} {}
     353             : };
     354             : 
     355             : /**
     356             :  * @brief   MIDI Input Element that listens to a single controller and saves its
     357             :  *          value.
     358             :  * 
     359             :  * @ingroup BankableMIDIInputElements
     360             :  * @tparam  NumBanks 
     361             :  *          The size of the bank.
     362             :  */
     363             : template <uint8_t NumBanks>
     364             : class CCValue : public GenericCCValue<NumBanks> {
     365             :   public:
     366             :     CCValue(BankConfig<NumBanks> config, MIDIAddress address)
     367             :         : GenericCCValue<NumBanks>{config, address, {}} {}
     368             : };
     369             : 
     370             : } // namespace Bankable
     371             : 
     372             : END_CS_NAMESPACE

Generated by: LCOV version 1.14-6-g40580cd