#pragma once #include #include #include BEGIN_CS_NAMESPACE namespace BankableMIDIMatcherHelpers { /** * @brief Check whether a given address is within a range of given length * starting from the given base address. * * @param tgt * The address to check * @param base * The base address, start of the range. * @param length * The length of the range. */ inline bool inRange(uint8_t tgt, uint8_t base, uint8_t length) { return (base <= tgt) && (tgt - base < length); } /** * @brief Check if the given address is part of the bank relative to the * base address. * * Consider the following example: * A Bank with 4 tracks per bank (T), 2 bank settings (N), * and a base address of 3. * * ~~~ * 0 1 2 3 4 5 6 7 8 9 10 11 12 ... * ☐ ☐ ☐ ☒ ☐ ☐ ☐ ☒ ☐ ☐ ☐ ☐ ☐ ... * ~~~ * * Addresses before the base adddress are not matched (0, 1, 2). * Addresses after N * T are not matched (8, 9, 10, 11, 12). * Addresses with a distance to the base address that is not a multiple of N * are not matched (4, 5, 6). * * @param tgt * The address to check. * @param base * The base address (the address of bank setting 0). * @param bank * The bank to match the address in. * * @note Equivalent to `matchBankableInRange(toMatch, base, 1)`. */ template bool matchBankable(uint8_t tgt, uint8_t base, const Bank &bank) { const uint8_t N = BankSize; const uint8_t B = bank.getTracksPerBank(); const int8_t F = bank.getSelectionOffset(); const uint8_t m = tgt; const uint8_t b = base; uint8_t diff = m - b - F * B; return m >= b + F * B && // diff < N * B && // diff % B == 0; } /// @see @ref matchBankableInRange(MIDIAddress,MIDIAddress,BaseBankConfig,uint8_t) template bool matchBankableInRange(uint8_t tgt, uint8_t base, const Bank &bank, uint8_t rangeLen) { const uint8_t R = rangeLen; const uint8_t N = BankSize; const uint8_t B = bank.getTracksPerBank(); const int8_t F = bank.getSelectionOffset(); const uint8_t m = tgt; const uint8_t b = base; uint8_t diff = m - b - F * B; return m >= b + F * B && // diff < N * B && // diff % B < R; } /// @see @ref getRangeIndex(MIDIAddress,MIDIAddress,BaseBankConfig) template uint8_t getRangeIndex(uint8_t tgt, uint8_t base, const Bank &bank) { const uint8_t B = bank.getTracksPerBank(); const int8_t F = bank.getSelectionOffset(); const uint8_t m = tgt; const uint8_t b = base; uint8_t diff = m - b - F * B; return diff % B; } /// @see @ref getBankIndex(MIDIAddress,MIDIAddress,BaseBankConfig) template uint8_t getBankIndex(uint8_t tgt, uint8_t base, const Bank &bank) { const uint8_t B = bank.getTracksPerBank(); const int8_t F = bank.getSelectionOffset(); const uint8_t m = tgt; const uint8_t b = base; uint8_t diff = m - b - F * B; return diff / B; } /** * @brief Check whether a given address is part of the bank relative to * the base address. * * @param tgt * The address to check. * @param base * The base address (the address of bank setting 0). * @param config * The bank configuration. */ template bool matchBankable(MIDIAddress tgt, MIDIAddress base, BaseBankConfig config) { if (!tgt.isValid() || !base.isValid()) return false; switch (config.type) { case BankType::ChangeAddress: { return tgt.getChannel() == base.getChannel() && tgt.getCableNumber() == base.getCableNumber() && matchBankable(tgt.getAddress(), base.getAddress(), config.bank); } case BankType::ChangeChannel: { return tgt.getAddress() == base.getAddress() && tgt.getCableNumber() == base.getCableNumber() && matchBankable(tgt.getRawChannel(), base.getRawChannel(), config.bank); } case BankType::ChangeCable: { return tgt.getAddress() == base.getAddress() && tgt.getChannel() == base.getChannel() && matchBankable(tgt.getRawCableNumber(), base.getRawCableNumber(), config.bank); } default: return false; // LCOV_EXCL_LINE } } /** * @brief Check whether a given address is part of the bank relative to * the base address and within a range with a given length. * * @param tgt * The address to check. * @param base * The base address (the address of bank setting 0). * @param config * The bank configuration. * @param length * The length of the range. */ template bool matchBankableInRange(MIDIAddress tgt, MIDIAddress base, BaseBankConfig config, uint8_t length) { if (!tgt.isValid() || !base.isValid()) return false; switch (config.type) { case ChangeAddress: return tgt.getChannel() == base.getChannel() && tgt.getCableNumber() == base.getCableNumber() && matchBankableInRange(tgt.getAddress(), base.getAddress(), config.bank, length); case ChangeChannel: return inRange(tgt.getAddress(), base.getAddress(), length) && tgt.getCableNumber() == base.getCableNumber() && matchBankable(tgt.getRawChannel(), base.getRawChannel(), config.bank); case ChangeCable: return inRange(tgt.getAddress(), base.getAddress(), length) && tgt.getChannel() == base.getChannel() && matchBankable(tgt.getRawCableNumber(), base.getRawCableNumber(), config.bank); default: return false; } } /** * @brief Calculate the bank setting of a given MIDI address, relative to * a base address. * * @param target * The MIDI address to calculate the bank setting of. * @param base * The base address to compare it to (the address of bank setting 0). * @param config * The bank configuration to determine the index. */ template uint8_t getBankIndex(MIDIAddress target, MIDIAddress base, BaseBankConfig config) { switch (config.type) { case BankType::ChangeAddress: return getBankIndex(target.getAddress(), base.getAddress(), config.bank); case BankType::ChangeChannel: return getBankIndex(target.getRawChannel(), base.getRawChannel(), config.bank); case BankType::ChangeCable: return getBankIndex(target.getRawCableNumber(), base.getRawCableNumber(), config.bank); default: return 0; // LCOV_EXCL_LINE } } /** * @brief Calculate the index in the address range of a given MIDI address, * relative to a base address. * * @param tgt * The MIDI address to calculate the bank setting of. * @param base * The base address to compare it to (beginning of the range for bank * setting 0). * @param config * The bank configuration to determine the index. */ template uint8_t getRangeIndex(MIDIAddress tgt, MIDIAddress base, BaseBankConfig config) { return config.type == BankType::ChangeAddress ? getRangeIndex(tgt.getAddress(), base.getAddress(), config.bank) : tgt.getAddress() - base.getAddress(); } } // namespace BankableMIDIMatcherHelpers END_CS_NAMESPACE