231 lines
8.0 KiB
C++
231 lines
8.0 KiB
C++
#pragma once
|
|
|
|
#include <Banks/Bank.hpp>
|
|
#include <Banks/BankConfig.hpp>
|
|
#include <Def/MIDIAddress.hpp>
|
|
|
|
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 <uint8_t BankSize>
|
|
bool matchBankable(uint8_t tgt, uint8_t base, const Bank<BankSize> &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<BankSize>,uint8_t)
|
|
template <uint8_t BankSize>
|
|
bool matchBankableInRange(uint8_t tgt, uint8_t base, const Bank<BankSize> &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<BankSize>)
|
|
template <uint8_t BankSize>
|
|
uint8_t getRangeIndex(uint8_t tgt, uint8_t base, const Bank<BankSize> &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<BankSize>)
|
|
template <uint8_t BankSize>
|
|
uint8_t getBankIndex(uint8_t tgt, uint8_t base, const Bank<BankSize> &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 <uint8_t BankSize>
|
|
bool matchBankable(MIDIAddress tgt, MIDIAddress base,
|
|
BaseBankConfig<BankSize> 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 <uint8_t BankSize>
|
|
bool matchBankableInRange(MIDIAddress tgt, MIDIAddress base,
|
|
BaseBankConfig<BankSize> 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 BankSize>
|
|
uint8_t getBankIndex(MIDIAddress target, MIDIAddress base,
|
|
BaseBankConfig<BankSize> 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 BankSize>
|
|
uint8_t getRangeIndex(MIDIAddress tgt, MIDIAddress base,
|
|
BaseBankConfig<BankSize> config) {
|
|
return config.type == BankType::ChangeAddress
|
|
? getRangeIndex(tgt.getAddress(), base.getAddress(), config.bank)
|
|
: tgt.getAddress() - base.getAddress();
|
|
}
|
|
|
|
} // namespace BankableMIDIMatcherHelpers
|
|
|
|
END_CS_NAMESPACE |