LCOV - code coverage report
Current view: top level - src/MIDI_Inputs - BankableMIDIMatcherHelpers.hpp (source / functions) Coverage Total Hit
Test: 73449d9b107c772cf65493691543348214e5d5eb Lines: 91.2 % 91 83
Test Date: 2026-06-06 17:44:35 Functions: 100.0 % 13 13
Legend: Lines:     hit not hit

            Line data    Source code
       1              : #pragma once
       2              : 
       3              : #include <Banks/Bank.hpp>
       4              : #include <Banks/BankConfig.hpp>
       5              : #include <Def/MIDIAddress.hpp>
       6              : 
       7              : BEGIN_CS_NAMESPACE
       8              : 
       9              : namespace BankableMIDIMatcherHelpers {
      10              : 
      11              : /**
      12              :  * @brief   Check whether a given address is within a range of given length
      13              :  *          starting from the given base address.
      14              :  * 
      15              :  * @param   tgt
      16              :  *          The address to check
      17              :  * @param   base
      18              :  *          The base address, start of the range.
      19              :  * @param   length
      20              :  *          The length of the range.
      21              :  */
      22           10 : inline bool inRange(uint8_t tgt, uint8_t base, uint8_t length) {
      23           10 :     return (base <= tgt) && (tgt - base < length);
      24              : }
      25              : 
      26              : /**
      27              :  * @brief   Check if the given address is part of the bank relative to the
      28              :  *          base address.
      29              :  * 
      30              :  * Consider the following example:  
      31              :  * A Bank with 4 tracks per bank (T), 2 bank settings (N), 
      32              :  * and a base address of 3.
      33              :  * 
      34              :  * ~~~
      35              :  * 0   1   2   3   4   5   6   7   8   9  10  11  12  ...
      36              :  * ☐   ☐   ☐   ☒   ☐   ☐   ☐   ☒   ☐   ☐   ☐   ☐   ☐  ...
      37              :  * ~~~
      38              :  * 
      39              :  * Addresses before the base adddress are not matched (0, 1, 2).  
      40              :  * Addresses after N * T are not matched (8, 9, 10, 11, 12).  
      41              :  * Addresses with a distance to the base address that is not a multiple of N
      42              :  * are not matched (4, 5, 6).
      43              :  * 
      44              :  * @param   tgt 
      45              :  *          The address to check.
      46              :  * @param   base
      47              :  *          The base address (the address of bank setting 0).
      48              :  * @param   bank
      49              :  *          The bank to match the address in.
      50              :  * 
      51              :  * @note    Equivalent to `matchBankableInRange(toMatch, base, 1)`.
      52              :  */
      53              : template <uint8_t BankSize>
      54           26 : bool matchBankable(uint8_t tgt, uint8_t base, const Bank<BankSize> &bank) {
      55           26 :     const uint8_t N = BankSize;
      56           26 :     const uint8_t B = bank.getTracksPerBank();
      57           26 :     const int8_t F = bank.getSelectionOffset();
      58           26 :     const uint8_t m = tgt;
      59           26 :     const uint8_t b = base;
      60           26 :     uint8_t diff = m - b - F * B;
      61           51 :     return m >= b + F * B && //
      62           50 :            diff < N * B &&   //
      63           50 :            diff % B == 0;
      64              : }
      65              : 
      66              : /// @see @ref matchBankableInRange(MIDIAddress,MIDIAddress,BaseBankConfig<BankSize>,uint8_t)
      67              : template <uint8_t BankSize>
      68           18 : bool matchBankableInRange(uint8_t tgt, uint8_t base, const Bank<BankSize> &bank,
      69              :                           uint8_t rangeLen) {
      70           18 :     const uint8_t R = rangeLen;
      71           18 :     const uint8_t N = BankSize;
      72           18 :     const uint8_t B = bank.getTracksPerBank();
      73           18 :     const int8_t F = bank.getSelectionOffset();
      74           18 :     const uint8_t m = tgt;
      75           18 :     const uint8_t b = base;
      76           18 :     uint8_t diff = m - b - F * B;
      77           32 :     return m >= b + F * B && //
      78           30 :            diff < N * B &&   //
      79           30 :            diff % B < R;
      80              : }
      81              : 
      82              : /// @see @ref getRangeIndex(MIDIAddress,MIDIAddress,BaseBankConfig<BankSize>)
      83              : template <uint8_t BankSize>
      84            8 : uint8_t getRangeIndex(uint8_t tgt, uint8_t base, const Bank<BankSize> &bank) {
      85            8 :     const uint8_t B = bank.getTracksPerBank();
      86            8 :     const int8_t F = bank.getSelectionOffset();
      87            8 :     const uint8_t m = tgt;
      88            8 :     const uint8_t b = base;
      89            8 :     uint8_t diff = m - b - F * B;
      90            8 :     return diff % B;
      91              : }
      92              : 
      93              : /// @see @ref getBankIndex(MIDIAddress,MIDIAddress,BaseBankConfig<BankSize>)
      94              : template <uint8_t BankSize>
      95           32 : uint8_t getBankIndex(uint8_t tgt, uint8_t base, const Bank<BankSize> &bank) {
      96           32 :     const uint8_t B = bank.getTracksPerBank();
      97           32 :     const int8_t F = bank.getSelectionOffset();
      98           32 :     const uint8_t m = tgt;
      99           32 :     const uint8_t b = base;
     100           32 :     uint8_t diff = m - b - F * B;
     101           32 :     return diff / B;
     102              : }
     103              : 
     104              : /**
     105              :  * @brief   Check whether a given address is part of the bank relative to
     106              :  *          the base address.
     107              :  * 
     108              :  * @param   tgt 
     109              :  *          The address to check.
     110              :  * @param   base
     111              :  *          The base address (the address of bank setting 0).
     112              :  * @param   config
     113              :  *          The bank configuration.
     114              :  */
     115              : template <uint8_t BankSize>
     116           20 : bool matchBankable(MIDIAddress tgt, MIDIAddress base,
     117              :                    BaseBankConfig<BankSize> config) {
     118           20 :     if (!tgt.isValid() || !base.isValid())
     119            0 :         return false;
     120           20 :     switch (config.type) {
     121           14 :         case BankType::ChangeAddress: {
     122           84 :             return tgt.getChannel() == base.getChannel() &&
     123           84 :                    tgt.getCableNumber() == base.getCableNumber() &&
     124           14 :                    matchBankable(tgt.getAddress(), base.getAddress(),
     125           28 :                                  config.bank);
     126              :         }
     127            3 :         case BankType::ChangeChannel: {
     128           12 :             return tgt.getAddress() == base.getAddress() &&
     129           21 :                    tgt.getCableNumber() == base.getCableNumber() &&
     130            3 :                    matchBankable(tgt.getRawChannel(), base.getRawChannel(),
     131            6 :                                  config.bank);
     132              :         }
     133            3 :         case BankType::ChangeCable: {
     134           12 :             return tgt.getAddress() == base.getAddress() &&
     135           21 :                    tgt.getChannel() == base.getChannel() &&
     136            3 :                    matchBankable(tgt.getRawCableNumber(),
     137            6 :                                  base.getRawCableNumber(), config.bank);
     138              :         }
     139              :         default: return false; // LCOV_EXCL_LINE
     140              :     }
     141              : }
     142              : 
     143              : /**
     144              :  * @brief   Check whether a given address is part of the bank relative to
     145              :  *          the base address and within a range with a given length.
     146              :  * 
     147              :  * @param   tgt 
     148              :  *          The address to check.
     149              :  * @param   base
     150              :  *          The base address (the address of bank setting 0).
     151              :  * @param   config
     152              :  *          The bank configuration.
     153              :  * @param   length
     154              :  *          The length of the range.
     155              :  */
     156              : template <uint8_t BankSize>
     157           30 : bool matchBankableInRange(MIDIAddress tgt, MIDIAddress base,
     158              :                           BaseBankConfig<BankSize> config, uint8_t length) {
     159           30 :     if (!tgt.isValid() || !base.isValid())
     160            0 :         return false;
     161           30 :     switch (config.type) {
     162           20 :         case ChangeAddress:
     163          114 :             return tgt.getChannel() == base.getChannel() &&
     164          114 :                    tgt.getCableNumber() == base.getCableNumber() &&
     165           18 :                    matchBankableInRange(tgt.getAddress(), base.getAddress(),
     166           38 :                                         config.bank, length);
     167           10 :         case ChangeChannel:
     168           28 :             return inRange(tgt.getAddress(), base.getAddress(), length) &&
     169           54 :                    tgt.getCableNumber() == base.getCableNumber() &&
     170            6 :                    matchBankable(tgt.getRawChannel(), base.getRawChannel(),
     171           16 :                                  config.bank);
     172            0 :         case ChangeCable:
     173            0 :             return inRange(tgt.getAddress(), base.getAddress(), length) &&
     174            0 :                    tgt.getChannel() == base.getChannel() &&
     175            0 :                    matchBankable(tgt.getRawCableNumber(),
     176            0 :                                  base.getRawCableNumber(), config.bank);
     177            0 :         default: return false;
     178              :     }
     179              : }
     180              : 
     181              : /**
     182              :  * @brief   Calculate the bank setting of a given MIDI address, relative to
     183              :  *          a base address.
     184              :  * 
     185              :  * @param   target 
     186              :  *          The MIDI address to calculate the bank setting of.
     187              :  * @param   base
     188              :  *          The base address to compare it to (the address of bank setting 0).
     189              :  * @param   config
     190              :  *          The bank configuration to determine the index.
     191              :  */
     192              : template <uint8_t BankSize>
     193           32 : uint8_t getBankIndex(MIDIAddress target, MIDIAddress base,
     194              :                      BaseBankConfig<BankSize> config) {
     195           32 :     switch (config.type) {
     196           22 :         case BankType::ChangeAddress:
     197           22 :             return getBankIndex(target.getAddress(), base.getAddress(),
     198           44 :                                 config.bank);
     199            7 :         case BankType::ChangeChannel:
     200            7 :             return getBankIndex(target.getRawChannel(), base.getRawChannel(),
     201           14 :                                 config.bank);
     202            3 :         case BankType::ChangeCable:
     203            3 :             return getBankIndex(target.getRawCableNumber(),
     204            6 :                                 base.getRawCableNumber(), config.bank);
     205              :         default: return 0; // LCOV_EXCL_LINE
     206              :     }
     207              : }
     208              : 
     209              : /**
     210              :  * @brief   Calculate the index in the address range of a given MIDI address,
     211              :  *          relative to a base address.
     212              :  * 
     213              :  * @param   tgt 
     214              :  *          The MIDI address to calculate the bank setting of.
     215              :  * @param   base
     216              :  *          The base address to compare it to (beginning of the range for bank
     217              :  *          setting 0).
     218              :  * @param   config
     219              :  *          The bank configuration to determine the index.
     220              :  */
     221              : template <uint8_t BankSize>
     222           12 : uint8_t getRangeIndex(MIDIAddress tgt, MIDIAddress base,
     223              :                       BaseBankConfig<BankSize> config) {
     224           12 :     return config.type == BankType::ChangeAddress
     225            8 :                ? getRangeIndex(tgt.getAddress(), base.getAddress(), config.bank)
     226           20 :                : tgt.getAddress() - base.getAddress();
     227              : }
     228              : 
     229              : } // namespace BankableMIDIMatcherHelpers
     230              : 
     231              : END_CS_NAMESPACE
        

Generated by: LCOV version 2.4-beta