Line data Source code
1 : #pragma once 2 : 3 : #include "MIDIInputElement.hpp" 4 : #include <AH/Containers/LinkedList.hpp> 5 : 6 : #if defined(ESP32) 7 : #include <mutex> 8 : #define GUARD_LIST_LOCK std::lock_guard<std::mutex> guard_(mutex) 9 : #else 10 : #define GUARD_LIST_LOCK 11 : #endif 12 : 13 : BEGIN_CS_NAMESPACE 14 : 15 : /** 16 : * @brief Class for objects that listen for incoming MIDI Program Change 17 : * events. 18 : * 19 : * @ingroup MIDIInputElements 20 : */ 21 : class MIDIInputElementPC : public MIDIInputElement, 22 : public DoublyLinkable<MIDIInputElementPC> { 23 : public: 24 : /** 25 : * @brief Constructor. 26 : * @todo Documentation. 27 : */ 28 2 : MIDIInputElementPC(const MIDIAddress &address) : MIDIInputElement(address) { 29 : GUARD_LIST_LOCK; 30 2 : elements.append(this); 31 2 : } 32 : 33 : /** 34 : * @brief Destructor. 35 : * @todo Documentation. 36 : */ 37 2 : virtual ~MIDIInputElementPC() { 38 : GUARD_LIST_LOCK; 39 2 : elements.remove(this); 40 2 : } 41 : 42 0 : static void beginAll() { 43 : GUARD_LIST_LOCK; 44 0 : for (MIDIInputElementPC &el : elements) 45 0 : el.begin(); 46 0 : } 47 : 48 : /** 49 : * @brief Reset all MIDIInputElementPC elements to their 50 : * initial state. 51 : * 52 : * @see MIDIInputElementPC#reset 53 : */ 54 : static void resetAll() { 55 : GUARD_LIST_LOCK; 56 : for (MIDIInputElementPC &el : elements) 57 : el.reset(); 58 : } 59 : 60 : /** 61 : * @brief Update all MIDIInputElementPC elements. 62 : */ 63 0 : static void updateAll() { 64 : GUARD_LIST_LOCK; 65 0 : for (MIDIInputElementPC &el : elements) 66 0 : el.update(); 67 0 : } 68 : 69 : /** 70 : * @brief Update all MIDIInputElementPC elements with a new MIDI 71 : * message. 72 : * 73 : * @see MIDIInputElementPC#updateWith 74 : */ 75 0 : static void updateAllWith(const ChannelMessageMatcher &midimsg) { 76 0 : for (MIDIInputElementPC &e : elements) 77 0 : if (e.updateWith(midimsg)) { 78 0 : e.moveDown(); 79 0 : return; 80 0 : } 81 : // No mutex required: 82 : // e.moveDown may alter the list, but if it does, it always returns, 83 : // and we stop iterating, so it doesn't matter. 84 0 : } 85 : 86 : private: 87 : /// Program Change doesn't have an address, so the target consists of just 88 : /// the channel and the cable number. 89 0 : MIDIAddress getTarget(const ChannelMessageMatcher &midimsg) const override { 90 0 : return { 91 : 0, 92 0 : Channel(midimsg.channel), 93 0 : Cable(midimsg.CN), 94 : }; 95 : } 96 : 97 : /** 98 : * @brief Move down this element in the linked list of elements. 99 : * 100 : * This means that the element will be checked earlier on the next 101 : * iteration. 102 : */ 103 0 : void moveDown() { 104 : GUARD_LIST_LOCK; 105 0 : elements.moveDown(this); 106 0 : } 107 : 108 : static DoublyLinkedList<MIDIInputElementPC> elements; 109 : #ifdef ESP32 110 : static std::mutex mutex; 111 : #endif 112 : }; 113 : 114 : #undef GUARD_LIST_LOCK 115 : 116 : END_CS_NAMESPACE