Line data Source code
1 : #include "MIDI_Pipes.hpp" 2 : #include <AH/Error/Error.hpp> 3 : #include <AH/STL/utility> 4 : 5 : #if defined(ESP32) || !defined(ARDUINO) 6 : #include <mutex> 7 : #endif 8 : 9 : AH_DIAGNOSTIC_WERROR() 10 : 11 : BEGIN_CS_NAMESPACE 12 : 13 : // :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: // 14 : 15 272 : void MIDI_Sink::connectSourcePipe(MIDI_Pipe *source) { 16 272 : if (this->sourcePipe == nullptr) { 17 221 : source->connectSink(this); 18 221 : this->sourcePipe = source; 19 221 : } else { 20 51 : this->sourcePipe->connectSourcePipe(source); 21 : } 22 271 : } 23 : 24 385 : void MIDI_Sink::disconnectSourcePipes() { 25 385 : if (sourcePipe != nullptr) { 26 64 : sourcePipe->disconnectSourcePipes(); 27 64 : sourcePipe->disconnect(); 28 64 : sourcePipe = nullptr; 29 64 : } 30 385 : } 31 : 32 220 : void MIDI_Sink::disconnectSourcePipesShallow() { 33 220 : if (sourcePipe != nullptr) { 34 220 : sourcePipe->disconnectSink(); 35 220 : sourcePipe = nullptr; 36 220 : } 37 220 : } 38 : 39 13 : bool MIDI_Sink::disconnect(TrueMIDI_Source &source) { 40 13 : if (!hasSourcePipe()) 41 3 : return false; 42 10 : return sourcePipe->disconnect(source); 43 13 : } 44 : 45 320 : MIDI_Sink::~MIDI_Sink() { disconnectSourcePipes(); } 46 : 47 5 : MIDI_Sink::MIDI_Sink(MIDI_Sink &&other) 48 5 : : sourcePipe(std::exchange(other.sourcePipe, nullptr)) { 49 5 : if (this->hasSourcePipe()) { 50 5 : this->sourcePipe->disconnectSink(); 51 5 : this->sourcePipe->connectSink(this); 52 5 : } 53 5 : } 54 : 55 2 : MIDI_Sink &MIDI_Sink::operator=(MIDI_Sink &&other) { 56 2 : std::swap(this->sourcePipe, other.sourcePipe); 57 2 : if (this->hasSourcePipe()) { 58 2 : this->sourcePipe->disconnectSink(); 59 2 : this->sourcePipe->connectSink(this); 60 2 : } 61 2 : if (other.hasSourcePipe()) { 62 0 : other.sourcePipe->disconnectSink(); 63 0 : other.sourcePipe->connectSink(this); 64 0 : } 65 2 : return *this; 66 : } 67 : 68 : // :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: // 69 : 70 267 : void MIDI_Source::connectSinkPipe(MIDI_Pipe *sink) { 71 267 : if (this->sinkPipe == nullptr) { 72 217 : sink->connectSource(this); 73 217 : this->sinkPipe = sink; 74 217 : } else { 75 50 : this->sinkPipe->connectSinkPipe(sink); 76 : } 77 266 : } 78 : 79 414 : void MIDI_Source::disconnectSinkPipes() { 80 414 : if (sinkPipe != nullptr) { 81 96 : sinkPipe->disconnectSinkPipes(); 82 96 : sinkPipe->disconnect(); 83 96 : sinkPipe = nullptr; 84 96 : } 85 414 : } 86 : 87 216 : void MIDI_Source::disconnectSinkPipesShallow() { 88 216 : if (sinkPipe != nullptr) { 89 216 : sinkPipe->disconnectSource(); 90 216 : sinkPipe = nullptr; 91 216 : } 92 216 : } 93 : 94 13 : bool MIDI_Source::disconnect(TrueMIDI_Sink &sink) { 95 13 : if (!hasSinkPipe()) 96 3 : return false; 97 10 : return sinkPipe->disconnect(sink); 98 13 : } 99 : 100 5 : MIDI_Source::MIDI_Source(MIDI_Source &&other) 101 5 : : sinkPipe(std::exchange(other.sinkPipe, nullptr)) { 102 5 : if (this->hasSinkPipe()) { 103 5 : this->sinkPipe->disconnectSource(); 104 5 : this->sinkPipe->connectSource(this); 105 5 : } 106 5 : } 107 : 108 2 : MIDI_Source &MIDI_Source::operator=(MIDI_Source &&other) { 109 2 : std::swap(this->sinkPipe, other.sinkPipe); 110 2 : if (this->hasSinkPipe()) { 111 2 : this->sinkPipe->disconnectSource(); 112 2 : this->sinkPipe->connectSource(this); 113 2 : } 114 2 : if (other.hasSinkPipe()) { 115 0 : other.sinkPipe->disconnectSource(); 116 0 : other.sinkPipe->connectSource(this); 117 0 : } 118 2 : return *this; 119 : } 120 : 121 317 : MIDI_Source::~MIDI_Source() { disconnectSinkPipes(); } 122 : 123 14 : void MIDI_Source::exclusive(cn_t cn, bool exclusive) { 124 14 : if (hasSinkPipe()) 125 14 : sinkPipe->exclusive(cn, exclusive); 126 14 : } 127 : 128 61 : bool MIDI_Source::canWrite(cn_t cn) const { 129 61 : return !hasSinkPipe() || sinkPipe->isAvailableForWrite(cn); 130 : } 131 : 132 123 : void MIDI_Source::sourceMIDItoPipe(ChannelMessage msg) { 133 123 : if (sinkPipe != nullptr) { 134 110 : sinkPipe->pipeMIDI(msg); 135 110 : } 136 123 : } 137 12 : void MIDI_Source::sourceMIDItoPipe(SysExMessage msg) { 138 12 : if (sinkPipe != nullptr) { 139 7 : sinkPipe->pipeMIDI(msg); 140 7 : } 141 12 : } 142 18 : void MIDI_Source::sourceMIDItoPipe(RealTimeMessage msg) { 143 18 : if (sinkPipe != nullptr) { 144 15 : sinkPipe->pipeMIDI(msg); 145 15 : } 146 18 : } 147 : 148 : // :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: // 149 : 150 228 : void MIDI_Pipe::connectSink(MIDI_Sink *sink) { 151 228 : if (this->sink != nullptr) { 152 1 : FATAL_ERROR(F("This pipe is already connected to a sink"), 0x9145); 153 : return; // LCOV_EXCL_LINE 154 : } 155 227 : this->sink = sink; 156 228 : } 157 : 158 227 : void MIDI_Pipe::disconnectSink() { this->sink = nullptr; } 159 : 160 224 : void MIDI_Pipe::connectSource(MIDI_Source *source) { 161 224 : if (this->source != nullptr) { 162 1 : FATAL_ERROR(F("This pipe is already connected to a source"), 0x9146); 163 : return; // LCOV_EXCL_LINE 164 : } 165 223 : this->source = source; 166 224 : } 167 : 168 223 : void MIDI_Pipe::disconnectSource() { this->source = nullptr; } 169 : 170 318 : void MIDI_Pipe::disconnect() { 171 318 : if (hasSink() && hasThroughIn()) { 172 16 : auto oldSink = sink; 173 16 : auto oldThroughIn = throughIn; 174 16 : sink->disconnectSourcePipesShallow(); 175 16 : this->disconnectSourcePipesShallow(); // disconnect throughIn 176 16 : oldSink->connectSourcePipe(oldThroughIn); 177 16 : } 178 318 : if (hasSource() && hasThroughOut()) { 179 14 : auto oldSource = source; 180 14 : auto oldThroughOut = throughOut; 181 14 : source->disconnectSinkPipesShallow(); 182 14 : this->disconnectSinkPipesShallow(); // disconnect throughOut 183 14 : oldSource->connectSinkPipe(oldThroughOut); 184 14 : } 185 318 : if (hasSink()) 186 188 : sink->disconnectSourcePipesShallow(); 187 : 188 318 : if (hasSource()) 189 188 : source->disconnectSinkPipesShallow(); 190 : 191 318 : if (hasThroughIn() || hasThroughOut()) 192 : FATAL_ERROR(F("Invalid state"), 0x9147); // LCOV_EXCL_LINE 193 318 : } 194 : 195 140 : MIDI_Pipe::~MIDI_Pipe() { disconnect(); } 196 : 197 : #if defined(ESP32) || !defined(ARDUINO) 198 : static std::mutex pipe_exclusive_mutex; 199 : #endif 200 : 201 14 : void MIDI_Pipe::exclusive(cn_t cn, bool exclusive) { 202 : #if defined(ESP32) || !defined(ARDUINO) 203 14 : std::lock_guard<std::mutex> lock_guard(pipe_exclusive_mutex); 204 : #endif 205 14 : if (hasSink()) 206 14 : sink->lockDownstream(cn, exclusive); 207 14 : if (hasThroughIn()) 208 10 : throughIn->lockUpstream(cn, exclusive); 209 14 : } 210 : 211 : END_CS_NAMESPACE 212 : 213 : AH_DIAGNOSTIC_POP()