LCOV - code coverage report
Current view: top level - src/Banks - Bank.hpp (source / functions) Hit Total Coverage
Test: 169c36a3797bc662d84b5726f34a3f37d3c58247 Lines: 27 28 96.4 %
Date: 2024-11-09 15:32:27 Functions: 20 22 90.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* ✔ */
       2             : 
       3             : #pragma once
       4             : 
       5             : #include <AH/Containers/LinkedList.hpp>
       6             : #include <AH/Debug/Debug.hpp>
       7             : #include <AH/Error/Error.hpp>
       8             : #include <Selectors/Selectable.hpp>
       9             : 
      10             : BEGIN_CS_NAMESPACE
      11             : 
      12             : template <setting_t N>
      13             : class BankableMIDIInput;
      14             : 
      15             : /// A class for changing the address of BankableMIDIOutput%s.
      16             : class OutputBank {
      17             :   public:
      18             :     /// Create a new OutputBank object.
      19             :     ///
      20             :     /// @param  tracksPerBank
      21             :     ///         The number of addresses/tracks to skip for each bank setting.
      22             :     ///         Must be strictly positive.
      23             :     /// @param  initialSelection
      24             :     ///         The initial bank setting.
      25             :     /// @param  selectionOffset
      26             :     ///         The offset added to the bank setting before computing the
      27             :     ///         actual address offset.
      28          45 :     OutputBank(uint8_t tracksPerBank = 1, setting_t initialSelection = 0,
      29             :                int8_t selectionOffset = 0)
      30          45 :         : tracksPerBank(tracksPerBank), bankSetting(initialSelection),
      31          45 :           selectionOffset(selectionOffset) {
      32          45 :         if (tracksPerBank == 0)
      33           1 :             FATAL_ERROR(F("A Bank must have a non-zero number of tracks."),
      34             :                         0x4573);
      35          44 :     }
      36             : 
      37             :     /// Select the given bank setting.
      38             :     ///
      39             :     /// @param   setting
      40             :     ///          The new setting to select (zero-based).
      41          90 :     void select(setting_t setting) { bankSetting = setting; }
      42             : 
      43             :     /// Get the current bank setting (zero-based).
      44         331 :     setting_t getSelection() const { return bankSetting; }
      45             :     /// Get the offset of the bank setting.
      46         144 :     int8_t getSelectionOffset() const { return selectionOffset; }
      47             : 
      48             :     /// Get the number of tracks per bank.
      49             :     /// This is the number of addresses/tracks to skip for each bank setting.
      50         147 :     uint8_t getTracksPerBank() const { return tracksPerBank; }
      51             : 
      52             :     /// The same as @ref getOffset, but for a given setting.
      53          60 :     int8_t getOffsetOfSetting(setting_t s) const {
      54          60 :         return (s + getSelectionOffset()) * getTracksPerBank();
      55             :     }
      56             :     /// Get the address offset (number of banks times the index of the selected
      57             :     /// bank after applying the offset)
      58          24 :     int8_t getOffset() const { return getOffsetOfSetting(getSelection()); }
      59             : 
      60             :   private:
      61             :     uint8_t tracksPerBank;
      62             :     setting_t bankSetting;
      63             :     int8_t selectionOffset;
      64             : };
      65             : 
      66             : /// Callback class for Bankable objects that need to be notified when the
      67             : /// active setting of their Bank changes.
      68             : class BankSettingChangeCallback
      69             :     : public DoublyLinkable<BankSettingChangeCallback> {
      70             :     template <setting_t N>
      71             :     friend class Bank;
      72             : 
      73             :   private:
      74             :     /// A function to be executed each time the bank setting changes.
      75             :     /// Think of an LED that indicates whether a track is muted or not. If this
      76             :     /// LED is bankable, let's say with 4 tracks per bank, 2 banks, and a base
      77             :     /// address of 3, then this LED object keeps the state of tracks 3 and 7.
      78             :     /// When the bank setting is 0, the LED displays the state of track 3, when
      79             :     /// the bank setting is 1, the LED displays the state of track 7.
      80             :     /// To know when to update the LED, this callback is used.
      81           0 :     virtual void onBankSettingChange() {}
      82             : };
      83             : 
      84             : /// A class that groups @ref BankableMIDIOutputElements and
      85             : /// @ref BankableMIDIInputElements, and allows the user to change the addresses
      86             : /// of these elements.
      87             : ///
      88             : /// @see FAQ: @ref faq-change-address-runtime
      89             : /// @see FAQ: @ref faq-banks
      90             : ///
      91             : /// @tparam NumBanks
      92             : ///         The number of banks.
      93             : template <setting_t NumBanks>
      94             : class Bank : public Selectable<NumBanks>, public OutputBank {
      95             : 
      96             :   public:
      97             :     /// Construct a new Bank object.
      98             :     ///
      99             :     /// @param  tracksPerBank
     100             :     ///         The number of addresses/tracks to skip for each bank setting.
     101             :     ///         Must be strictly positive.
     102             :     /// @param  initialSelection
     103             :     ///         The initial bank setting.
     104             :     /// @param  selectionOffset
     105             :     ///         The offset added to the bank setting before computing the
     106             :     ///         actual address offset.
     107          28 :     Bank(uint8_t tracksPerBank = 1, setting_t initialSelection = 0,
     108             :          int8_t selectionOffset = 0)
     109             :         : Selectable<NumBanks>(initialSelection),
     110          28 :           OutputBank(tracksPerBank, initialSelection, selectionOffset) {}
     111             : 
     112             :     /// Select the given bank setting.
     113             :     ///
     114             :     /// All Bankable MIDI Input elements that were added to this bank will be
     115             :     /// updated.
     116             :     ///
     117             :     /// @param  bankSetting
     118             :     ///         The new setting to select.
     119             :     void select(setting_t bankSetting) override;
     120             : 
     121             :     /// Get the number of banks.
     122             :     constexpr static uint8_t getNumberOfBanks() { return NumBanks; }
     123             : 
     124             :   public:
     125             :     /// Add a Bankable MIDI Input Element to the bank.
     126             :     ///
     127             :     /// @param  bankable
     128             :     ///         The MIDI Input Element to be added.
     129             :     void add(BankSettingChangeCallback *bankable);
     130             : 
     131             :     /// Remove a Bankable MIDI Input Element from the bank.
     132             :     ///
     133             :     /// @param  bankable
     134             :     ///         The MIDI Input Element to be removed.
     135             :     void remove(BankSettingChangeCallback *bankable);
     136             : 
     137             :   private:
     138             :     /// A linked list of all Bankable MIDI Input Elements that have been added
     139             :     /// to this bank, and that should be updated when the bank setting changes.
     140             :     /// The list is updated automatically when Bankable MIDI Input Elements are
     141             :     /// created or destroyed.
     142             :     DoublyLinkedList<BankSettingChangeCallback> inputBankables;
     143             : };
     144             : 
     145             : END_CS_NAMESPACE
     146             : 
     147             : // ---------------------------- Implementations ----------------------------- //
     148             : 
     149             : BEGIN_CS_NAMESPACE
     150             : 
     151             : template <setting_t NumBanks>
     152          17 : void Bank<NumBanks>::add(BankSettingChangeCallback *bankable) {
     153          17 :     inputBankables.append(bankable);
     154          17 : }
     155             : 
     156             : template <setting_t NumBanks>
     157          17 : void Bank<NumBanks>::remove(BankSettingChangeCallback *bankable) {
     158          17 :     inputBankables.remove(bankable);
     159          17 : }
     160             : 
     161             : template <setting_t NumBanks>
     162          80 : void Bank<NumBanks>::select(setting_t bankSetting) {
     163          80 :     bankSetting = this->validateSetting(bankSetting);
     164          79 :     OutputBank::select(bankSetting);
     165         220 :     for (BankSettingChangeCallback &e : inputBankables)
     166          62 :         e.onBankSettingChange();
     167          79 : }
     168             : 
     169             : END_CS_NAMESPACE

Generated by: LCOV version 1.15