Line data Source code
1 : #pragma once
2 :
3 : #include <Banks/BankableMIDIInput.hpp>
4 : #include <MIDI_Inputs/MIDIInputElementCC.hpp>
5 : #include <MIDI_Inputs/MIDIInputElementNote.hpp>
6 :
7 : BEGIN_CS_NAMESPACE
8 :
9 : class INoteCCValue {
10 : protected:
11 11 : INoteCCValue(uint8_t rangeLength) : rangeLength{rangeLength} {}
12 :
13 : public:
14 4 : uint8_t length() const { return rangeLength; }
15 : virtual uint8_t getValue(uint8_t index) const = 0;
16 15 : uint8_t getValue() const { return getValue(0); }
17 :
18 : private:
19 : uint8_t rangeLength;
20 : };
21 :
22 : class NoteCCRangeEmptyCallback {
23 : public:
24 9 : void begin(const INoteCCValue &) {}
25 13 : void update(const INoteCCValue &, uint8_t) {}
26 30 : void updateAll(const INoteCCValue &) {}
27 : };
28 :
29 2 : struct SimpleNoteCCValueCallback {
30 : protected:
31 2 : SimpleNoteCCValueCallback() = default;
32 :
33 : public:
34 0 : virtual void begin(const INoteCCValue &) {}
35 : virtual void update(const INoteCCValue &, uint8_t) = 0;
36 2 : virtual void updateAll(const INoteCCValue ¬eccval) {
37 4 : for (uint8_t i = 0; i < noteccval.length(); ++i)
38 2 : update(noteccval, i);
39 2 : }
40 : };
41 :
42 : // -------------------------------------------------------------------------- //
43 :
44 : template <class MIDIInput_t, uint8_t RangeLen, uint8_t NumBanks, class Callback>
45 11 : class NoteCCRange : public MIDIInput_t, public INoteCCValue {
46 : public:
47 11 : NoteCCRange(MIDICNChannelAddress address, const Callback &callback)
48 22 : : MIDIInput_t{address}, INoteCCValue{RangeLen}, callback(callback) {}
49 :
50 : /// @todo check index bounds
51 134 : uint8_t getValue(uint8_t index) const override {
52 134 : return values[getSelection()][index];
53 : }
54 : using INoteCCValue::getValue;
55 :
56 : /// Initialize
57 11 : void begin() override { callback.begin(*this); }
58 : /// Reset all values to zero
59 2 : void reset() override {
60 2 : values = {{}};
61 2 : callback.updateAll(*this);
62 2 : }
63 :
64 : private:
65 21 : bool updateImpl(const ChannelMessageMatcher &midimsg,
66 : const MIDICNChannelAddress &target) override {
67 21 : uint8_t bankIndex = this->getBankIndex(target);
68 21 : uint8_t rangeIndex = this->getRangeIndex(target);
69 21 : uint8_t value = getValueFromMIDIMessage(midimsg);
70 21 : values[bankIndex][rangeIndex] = value;
71 21 : if (bankIndex == this->getSelection())
72 17 : callback.update(*this, rangeIndex);
73 21 : return true;
74 : }
75 :
76 : static uint8_t
77 21 : getValueFromMIDIMessage(const ChannelMessageMatcher &midimsg) {
78 21 : return midimsg.type == NOTE_OFF ? 0 : midimsg.data2;
79 : }
80 :
81 : /// Get the active bank selection
82 39 : virtual uint8_t getSelection() const { return 0; }
83 :
84 : /// Get the bank index from a MIDI address
85 13 : virtual setting_t getBankIndex(MIDICNChannelAddress target) const {
86 : (void)target;
87 13 : return 0;
88 : }
89 :
90 13 : virtual uint8_t getRangeIndex(MIDICNChannelAddress target) const {
91 13 : return target.getAddress() - this->address.getAddress();
92 : }
93 :
94 15 : Array<Array<uint8_t, RangeLen>, NumBanks> values = {{}};
95 :
96 : public:
97 : Callback callback;
98 : constexpr static uint8_t length() { return RangeLen; }
99 : };
100 :
101 : // -------------------------------------------------------------------------- //
102 :
103 : template <class MIDIInput_t, uint8_t RangeLen,
104 : class Callback = NoteCCRangeEmptyCallback>
105 7 : class GenericNoteCCRange
106 : : public NoteCCRange<MIDIInput_t, RangeLen, 1, Callback> {
107 : public:
108 7 : GenericNoteCCRange(MIDICNChannelAddress address, const Callback &callback)
109 7 : : NoteCCRange<MIDIInput_t, RangeLen, 1, Callback>{address, callback} {}
110 :
111 : private:
112 : /// Check if the address of the incoming MIDI message is within the range
113 : /// of addresses of this element.
114 13 : bool match(const MIDICNChannelAddress &target) const override {
115 13 : return MIDICNChannelAddress::matchAddressInRange( //
116 13 : target, this->address, RangeLen);
117 : }
118 : };
119 :
120 : /**
121 : * @brief MIDI Input Element that listens to a range of notes.
122 : *
123 : * @ingroup MIDIInputElements
124 : * @tparam RangeLen
125 : * The length of the range of notes to listen to.
126 : */
127 : template <uint8_t RangeLen>
128 1 : class NoteRange : public GenericNoteCCRange<MIDIInputElementNote, RangeLen> {
129 : public:
130 1 : NoteRange(MIDICNChannelAddress address)
131 1 : : GenericNoteCCRange<MIDIInputElementNote, RangeLen>{address, {}} {}
132 : };
133 :
134 4 : class NoteValue : public GenericNoteCCRange<MIDIInputElementNote, 1> {
135 : public:
136 4 : NoteValue(MIDICNChannelAddress address)
137 4 : : GenericNoteCCRange<MIDIInputElementNote, 1>{address, {}} {}
138 : };
139 : using MIDINote[[deprecated("Use NoteValue instead")]] = NoteValue;
140 :
141 : template <uint8_t RangeLen>
142 : class CCRange : public GenericNoteCCRange<MIDIInputElementCC, RangeLen> {
143 : public:
144 : CCRange(MIDICNChannelAddress address)
145 : : GenericNoteCCRange<MIDIInputElementCC, RangeLen>{address, {}} {}
146 : };
147 :
148 : class CCValue : public GenericNoteCCRange<MIDIInputElementCC, 1> {
149 : public:
150 : CCValue(MIDICNChannelAddress address)
151 : : GenericNoteCCRange<MIDIInputElementCC, 1>{address, {}} {}
152 : };
153 :
154 : // -------------------------------------------------------------------------- //
155 :
156 : namespace Bankable {
157 :
158 : /// @tparam RangeLen
159 : /// The length of the range.
160 : /// @tparam NumBanks
161 : /// The size of the bank.
162 : template <class MIDIInput_t, uint8_t RangeLen, uint8_t NumBanks,
163 : class Callback = NoteCCRangeEmptyCallback>
164 4 : class GenericNoteCCRange
165 : : public NoteCCRange<MIDIInput_t, RangeLen, NumBanks, Callback>,
166 : public BankableMIDIInput<NumBanks> {
167 : public:
168 4 : GenericNoteCCRange(BankConfig<NumBanks> config,
169 : MIDICNChannelAddress address,
170 : const Callback &callback)
171 4 : : NoteCCRange<MIDIInput_t, RangeLen, NumBanks, Callback>{
172 4 : address,
173 4 : callback,
174 8 : }, BankableMIDIInput<NumBanks>{config} {}
175 :
176 : private:
177 : /// Check if the address of the incoming MIDI message is within the range
178 : /// of addresses and in one of the banks of this element.
179 20 : bool match(const MIDICNChannelAddress &target) const override {
180 40 : return BankableMIDIInput<NumBanks>::matchBankableAddressInRange(
181 20 : target, this->address, RangeLen);
182 : }
183 :
184 116 : setting_t getSelection() const override {
185 116 : return BankableMIDIInput<NumBanks>::getSelection();
186 : };
187 :
188 8 : uint8_t getBankIndex(MIDICNChannelAddress target) const override {
189 8 : return BankableMIDIInput<NumBanks>::getBankIndex(target, this->address);
190 : }
191 :
192 8 : uint8_t getRangeIndex(MIDICNChannelAddress target) const override {
193 16 : return BankableMIDIInput<NumBanks>::getRangeIndex(target,
194 8 : this->address);
195 : }
196 :
197 28 : void onBankSettingChange() override { this->callback.updateAll(*this); }
198 : };
199 :
200 : template <uint8_t RangeLen, uint8_t NumBanks>
201 4 : class NoteRange
202 : : public GenericNoteCCRange<MIDIInputElementNote, RangeLen, NumBanks> {
203 : public:
204 4 : NoteRange(BankConfig<NumBanks> config, MIDICNChannelAddress address)
205 4 : : GenericNoteCCRange<MIDIInputElementNote, RangeLen, NumBanks>{
206 8 : config, address, {}} {}
207 : };
208 :
209 : template <uint8_t NumBanks>
210 : class NoteValue : public GenericNoteCCRange<MIDIInputElementNote, 1, NumBanks> {
211 : public:
212 : NoteValue(BankConfig<NumBanks> config, MIDICNChannelAddress address)
213 : : GenericNoteCCRange<MIDIInputElementNote, 1, NumBanks>{
214 : config, address, {}} {}
215 : };
216 : template <uint8_t NumBanks>
217 : using MIDINote[[deprecated("Use NoteValue instead")]] = NoteValue<NumBanks>;
218 :
219 : template <uint8_t RangeLen, uint8_t NumBanks>
220 : class CCRange
221 : : public GenericNoteCCRange<MIDIInputElementCC, RangeLen, NumBanks> {
222 : public:
223 : CCRange(BankConfig<NumBanks> config, MIDICNChannelAddress address)
224 : : GenericNoteCCRange<MIDIInputElementCC, RangeLen, NumBanks>{
225 : config, address, {}} {}
226 : };
227 :
228 : template <uint8_t NumBanks>
229 : class CCValue : public GenericNoteCCRange<MIDIInputElementCC, 1, NumBanks> {
230 : public:
231 : CCValue(BankConfig<NumBanks> config, MIDICNChannelAddress address)
232 : : GenericNoteCCRange<MIDIInputElementCC, 1, NumBanks>{
233 : config, address, {}} {}
234 : };
235 :
236 : } // namespace Bankable
237 :
238 : END_CS_NAMESPACE
|