LCOV - code coverage report
Current view: top level - src/Banks - BankableAddresses.hpp (source / functions) Hit Total Coverage
Test: 3a807a259ebe0769dd942f7f612dca5273937539 Lines: 21 24 87.5 %
Date: 2024-03-24 17:16:54 Functions: 11 11 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* ✔ */
       2             : 
       3             : #pragma once
       4             : 
       5             : #include "Bank.hpp"
       6             : #include "BankConfig.hpp"
       7             : #include <Def/MIDIAddress.hpp>
       8             : 
       9             : BEGIN_CS_NAMESPACE
      10             : 
      11             : /// Class for keeping track of the active bank, and allows locking of the
      12             : /// bank setting.
      13             : ///
      14             : /// @see @ref OutputBankableMIDIAddress
      15             : class OutputBankableMIDIAddress_Base {
      16             :   protected:
      17             :     /**
      18             :      * @brief   Constructor.
      19             :      * 
      20             :      * @param   bank
      21             :      *          The bank to add this element to.
      22             :      */
      23          43 :     OutputBankableMIDIAddress_Base(const OutputBank &bank) : bank(bank) {}
      24             : 
      25             :   public:
      26             :     /** 
      27             :      * @brief   Get the actual bank setting (no matter whether the element is 
      28             :      *          locked or not).
      29             :      */
      30          22 :     setting_t getRawBankSetting() const { return bank.getSelection(); }
      31             : 
      32             :     /**
      33             :      * @brief   Get the bank setting.
      34             :      * 
      35             :      * If the element is locked, the bank setting from the moment it was locked
      36             :      * is returned.
      37             :      */
      38          44 :     setting_t getSelection() const {
      39          44 :         return lockedSetting == Unlocked ? getRawBankSetting() : lockedSetting;
      40             :     }
      41             : 
      42             :     /**
      43             :      * @brief   Lock the bank setting.
      44             :      * 
      45             :      * As long as it's locked, `getSelection` will return the current setting,
      46             :      * independent from the actual bank setting.
      47             :      */
      48          14 :     void lock() {
      49          14 :         if (lockedSetting == Unlocked)
      50          14 :             lockedSetting = getRawBankSetting();
      51          14 :     }
      52             : 
      53             :     /**
      54             :      * @brief   Unlock the bank setting.
      55             :      * 
      56             :      * After unlocking, @ref getSelection will return the actual bank setting 
      57             :      * again.
      58             :      */
      59          14 :     void unlock() { lockedSetting = Unlocked; }
      60             : 
      61             :   protected:
      62             :     const OutputBank &bank;
      63             : 
      64             :   private:
      65             :     constexpr static setting_t Unlocked = NoSetting;
      66             :     setting_t lockedSetting = Unlocked;
      67             : };
      68             : 
      69             : /**
      70             :  * @brief   A base class for all MIDIOutputElement%s that can be banked.
      71             :  * 
      72             :  * @note    These elements don't have to be updated when the bank setting is 
      73             :  *          changed, because they poll the bank setting each time they send a
      74             :  *          MIDI event.  
      75             :  *          They are not added to the bank, they just keep a reference to the 
      76             :  *          bank they're a part of.  
      77             :  * 
      78             :  * @note    To prevent 'sticky' notes (i.e. a button is pressed, a note on is
      79             :  *          sent, the bank is changed, the button is released, and the note off
      80             :  *          is sent to a different address, causing the first note to keep on 
      81             :  *          playing indefinitely), there must be a way to lock the bank setting
      82             :  *          while a note is playing. Then when it is no longer playing, the 
      83             :  *          bank setting is unlocked.
      84             :  */
      85             : class OutputBankableMIDIAddress : public OutputBankableMIDIAddress_Base {
      86             :   public:
      87             :     /**
      88             :      * @brief   Create a new OutputBankableMIDIAddress object.
      89             :      * 
      90             :      * @param   bank
      91             :      *          The bank to add this element to.
      92             :      * @param   type
      93             :      *          What address type to change (address, channel or cable number).
      94             :      */
      95          31 :     OutputBankableMIDIAddress(const OutputBank &bank, BankType type)
      96          31 :         : OutputBankableMIDIAddress_Base(bank), type(type) {}
      97             : 
      98             :     /**
      99             :      * @brief   Create a new OutputBankableMIDIAddress object.
     100             :      * 
     101             :      * @param   config
     102             :      *          The bank and address type to change.
     103             :      * 
     104             :      * @see     OutputBankableMIDIAddress::OutputBankableMIDIAddress(Bank<N> &, BankType)
     105             :      */
     106          31 :     OutputBankableMIDIAddress(BaseOutputBankConfig config)
     107          31 :         : OutputBankableMIDIAddress(config.bank, config.type) {}
     108             : 
     109             :     /** 
     110             :      * @brief   Get the offset relative to the base address.
     111             :      */
     112          36 :     RelativeMIDIAddress getAddressOffset(setting_t bankindex) const {
     113          36 :         int8_t offset = bank.getOffsetOfSetting(bankindex);
     114          36 :         switch (type) {
     115          36 :             case ChangeAddress: return {offset, 0, 0};
     116           0 :             case ChangeChannel: return {0, offset, 0};
     117           0 :             case ChangeCable: return {0, 0, offset};
     118           0 :             default: return {};
     119             :         }
     120             :     }
     121             :     /// @copydoc getAddressOffset(setting_t) const
     122          36 :     RelativeMIDIAddress getAddressOffset() const {
     123          36 :         return getAddressOffset(getSelection());
     124             :     }
     125             : 
     126             :   private:
     127             :     const BankType type;
     128             : };
     129             : 
     130             : /**
     131             :  * @brief   A base class for all MIDIOutputElement%s that can have one of many
     132             :  *          addresses.
     133             :  *          
     134             :  * The bank setting determines the address that's being used.
     135             :  *          
     136             :  * @note    To prevent 'sticky' notes (i.e. a button is pressed, a note on is
     137             :  *          sent, the bank is changed, the button is released, and the note off
     138             :  *          is sent to a different address, causing the first note to keep on 
     139             :  *          playing indefinitely), there must be a way to lock the bank setting
     140             :  *          while a note is playing. Then when it is no longer playing, the 
     141             :  *          bank setting is unlocked.
     142             :  * 
     143             :  * @invariant `getSelection` and `getRawBankSetting` always return a number in 
     144             :  *            the half-open interval 
     145             :  *            @f$ \left[0, \mathrm{bank.getNumberOfBanks()}\right) \cap 
     146             :  *            \mathbb{N} @f$.
     147             :  */
     148             : class ManyAddresses_Base : public OutputBankableMIDIAddress_Base {
     149             :   public:
     150             :     /**
     151             :      * @brief   Constructor.
     152             :      * 
     153             :      * @param   bank
     154             :      *          The bank to add this element to.
     155             :      * @tparam  NumBanks
     156             :      *          The number of bank settings @p bank has.
     157             :      */
     158             :     template <uint8_t NumBanks>
     159          12 :     ManyAddresses_Base(const Bank<NumBanks> &bank)
     160          12 :         : OutputBankableMIDIAddress_Base(bank) {}
     161             : };
     162             : 
     163             : END_CS_NAMESPACE

Generated by: LCOV version 1.15