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

Generated by: LCOV version 1.14-5-g4ff2ed6