LCOV - code coverage report
Current view: top level - src/Banks - Bank.hpp (source / functions) Coverage Total Hit
Test: 73449d9b107c772cf65493691543348214e5d5eb Lines: 96.4 % 28 27
Test Date: 2026-06-06 17:44:35 Functions: 90.9 % 22 20
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          141 :     for (BankSettingChangeCallback &e : inputBankables)
     166           62 :         e.onBankSettingChange();
     167           79 : }
     168              : 
     169              : END_CS_NAMESPACE
        

Generated by: LCOV version 2.4-beta