LCOV - code coverage report
Current view: top level - src/MIDI_Inputs - MIDIInputElement.hpp (source / functions) Coverage Total Hit
Test: 73449d9b107c772cf65493691543348214e5d5eb Lines: 100.0 % 31 31
Test Date: 2026-06-06 17:44:35 Functions: 80.0 % 75 60
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           80 :         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 2.4-beta