LCOV - code coverage report
Current view: top level - src/MIDI_Inputs - MIDIInputElement.hpp (source / functions) Hit Total Coverage
Test: 169c36a3797bc662d84b5726f34a3f37d3c58247 Lines: 31 31 100.0 %
Date: 2024-11-09 15:32:27 Functions: 60 85 70.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : #pragma once
       2             : 
       3             : #include <Def/MIDIAddress.hpp>
       4             : #include <MIDI_Parsers/MIDI_MessageTypes.hpp>
       5             : 
       6             : #include <Banks/Bank.hpp> // Bank<N>, BankSettingChangeCallback
       7             : 
       8             : #include <AH/Containers/Updatable.hpp>
       9             : #include <AH/STL/type_traits>
      10             : 
      11             : BEGIN_CS_NAMESPACE
      12             : 
      13             : // -------------------------------------------------------------------------- //
      14             : 
      15             : /**
      16             :  * @brief   A class for objects that listen for incoming MIDI events.
      17             :  * 
      18             :  * They can either update some kind of display, or they can just save the state.
      19             :  */
      20             : template <MIDIMessageType Type>
      21             : class MIDIInputElement : public AH::UpdatableCRTP<MIDIInputElement<Type>> {
      22             :   protected:
      23          64 :     MIDIInputElement() = default;
      24             : 
      25             :   public:
      26          64 :     virtual ~MIDIInputElement() = default;
      27             : 
      28             :   public:
      29             :     using MessageType =
      30             :         typename std::conditional<Type == MIDIMessageType::SysExStart,
      31             :                                   SysExMessage, ChannelMessage>::type;
      32             : 
      33             :     /// Initialize the input element.
      34             :     virtual void begin() {} // LCOV_EXCL_LINE
      35             : 
      36             :     /// Reset the input element to its initial state.
      37             :     virtual void reset() {} // LCOV_EXCL_LINE
      38             : 
      39             :     /// Update the value of the input element. Used for decaying VU meters etc.
      40             :     virtual void update() {} // LCOV_EXCL_LINE
      41             : 
      42             :     /// Receive a new MIDI message and update the internal state.
      43             :     virtual bool updateWith(MessageType midimsg) = 0;
      44             : 
      45             :     /// Update all
      46          72 :     static bool updateAllWith(MessageType midimsg) {
      47         152 :         for (auto &el : MIDIInputElement::updatables) {
      48          75 :             if (el.updateWith(midimsg)) {
      49          67 :                 el.moveDown();
      50          67 :                 return true;
      51             :             }
      52             :         }
      53           5 :         return false;
      54             :     }
      55             : 
      56             :     /// Update all
      57           1 :     static void updateAll() {
      58           1 :         MIDIInputElement::applyToAll(&MIDIInputElement::update);
      59           1 :     }
      60             : 
      61             :     /// Begin all
      62           6 :     static void beginAll() {
      63           6 :         MIDIInputElement::applyToAll(&MIDIInputElement::begin);
      64           6 :     }
      65             : 
      66             :     /// Reset all
      67           3 :     static void resetAll() {
      68           3 :         MIDIInputElement::applyToAll(&MIDIInputElement::reset);
      69           3 :     }
      70             : };
      71             : 
      72             : // -------------------------------------------------------------------------- //
      73             : 
      74             : /// The @ref MIDIInputElement base class is very general: you give it a MIDI
      75             : /// message, and it calls the `updateWith()` method with that message. Each
      76             : /// instance must then determine whether the message is meant for them or not.
      77             : /// This is often a very repetitive task, so that logic is best isolated in a
      78             : /// so-called “Matcher”. The Matcher looks at the MIDI message, checks if it
      79             : /// matches its MIDI address, for example, and if so, it extracts some data
      80             : /// (such as the MIDI velocity value from the message). Then it returns whether
      81             : /// it matched and the extra data as a “Matcher::Result” object. If the message
      82             : /// matched, that Result object is passed to the
      83             : /// @ref MatchingMIDIInputElement::handleUpdate() method, so it can be handled
      84             : /// there.
      85             : ///
      86             : /// @todo   Pass the MIDI message to the @ref handleUpdate() method.
      87             : template <MIDIMessageType Type, class Matcher>
      88             : class MatchingMIDIInputElement : public MIDIInputElement<Type> {
      89             :   protected:
      90          51 :     MatchingMIDIInputElement(const Matcher &matcher) : matcher(matcher) {}
      91             : 
      92             :   public:
      93             :     using MessageType = typename MIDIInputElement<Type>::MessageType;
      94             : 
      95         176 :     bool updateWith(MessageType midimsg) override {
      96         176 :         auto match = matcher(midimsg);
      97         176 :         if (match.match)
      98         154 :             handleUpdate(match);
      99         176 :         return match.match;
     100             :     }
     101             : 
     102             :     virtual void handleUpdate(typename Matcher::Result match) = 0;
     103             : 
     104             :   protected:
     105             :     Matcher matcher;
     106             : };
     107             : 
     108             : // -------------------------------------------------------------------------- //
     109             : 
     110             : /// Similar to @ref MatchingMIDIInputElement, but for Bankable MIDI Input
     111             : /// Elements.
     112             : template <MIDIMessageType Type, class Matcher>
     113             : class BankableMatchingMIDIInputElement
     114             :     : public MatchingMIDIInputElement<Type, Matcher>,
     115             :       public BankSettingChangeCallback {
     116             :     friend class Bank<Matcher::getBankSize()>;
     117             : 
     118             :   protected:
     119             :     /// Create a new BankableMatchingMIDIInputElement object, and add it to the
     120             :     /// bank.
     121          17 :     BankableMatchingMIDIInputElement(const Matcher &matcher)
     122          17 :         : MatchingMIDIInputElement<Type, Matcher>(matcher) {
     123          17 :         this->matcher.getBank().add(this);
     124          17 :     }
     125             : 
     126         272 :     uint8_t getActiveBank() const { return this->matcher.getSelection(); }
     127             : 
     128             :   public:
     129             :     /// Destructor: remove element from the bank.
     130          17 :     virtual ~BankableMatchingMIDIInputElement() {
     131          17 :         this->matcher.getBank().remove(this);
     132          34 :     }
     133             : };
     134             : 
     135             : // -------------------------------------------------------------------------- //
     136             : 
     137             : /// MIDI Input Element that listens for MIDI Note On/Off messages.
     138             : using MIDIInputElementNote = MIDIInputElement<MIDIMessageType::NoteOn>;
     139             : /// MIDI Input Element that listens for MIDI Key Pressure messages.
     140             : using MIDIInputElementKP = MIDIInputElement<MIDIMessageType::KeyPressure>;
     141             : /// MIDI Input Element that listens for MIDI Control Change messages.
     142             : using MIDIInputElementCC = MIDIInputElement<MIDIMessageType::ControlChange>;
     143             : /// MIDI Input Element that listens for MIDI Program Change messages.
     144             : using MIDIInputElementPC = MIDIInputElement<MIDIMessageType::ProgramChange>;
     145             : /// MIDI Input Element that listens for MIDI Channel Pressure messages.
     146             : using MIDIInputElementCP = MIDIInputElement<MIDIMessageType::ChannelPressure>;
     147             : /// MIDI Input Element that listens for MIDI Pitch Bend messages.
     148             : using MIDIInputElementPB = MIDIInputElement<MIDIMessageType::PitchBend>;
     149             : /// MIDI Input Element that listens for MIDI System Exclusive messages.
     150             : using MIDIInputElementSysEx = MIDIInputElement<MIDIMessageType::SysExStart>;
     151             : 
     152             : END_CS_NAMESPACE

Generated by: LCOV version 1.15