Control Surface  1.2.0
MIDI Control Surface library for Arduino
MIDI_Pipes.cpp
Go to the documentation of this file.
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 
10 
12 
13 // :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: //
14 
15 void MIDI_Sink::connectSourcePipe(MIDI_Pipe *source) {
16  if (this->sourcePipe == nullptr) {
17  source->connectSink(this);
18  this->sourcePipe = source;
19  } else {
20  this->sourcePipe->connectSourcePipe(source);
21  }
22 }
23 
25  if (sourcePipe != nullptr) {
28  sourcePipe = nullptr;
29  }
30 }
31 
33  if (sourcePipe != nullptr) {
35  sourcePipe = nullptr;
36  }
37 }
38 
40  if (!hasSourcePipe())
41  return false;
42  return sourcePipe->disconnect(source);
43 }
44 
46 
48  : sourcePipe(std::exchange(other.sourcePipe, nullptr)) {
49  if (this->hasSourcePipe()) {
50  this->sourcePipe->disconnectSink();
51  this->sourcePipe->connectSink(this);
52  }
53 }
54 
56  std::swap(this->sourcePipe, other.sourcePipe);
57  if (this->hasSourcePipe()) {
58  this->sourcePipe->disconnectSink();
59  this->sourcePipe->connectSink(this);
60  }
61  if (other.hasSourcePipe()) {
62  other.sourcePipe->disconnectSink();
63  other.sourcePipe->connectSink(this);
64  }
65  return *this;
66 }
67 
68 // :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: //
69 
71  if (this->sinkPipe == nullptr) {
72  sink->connectSource(this);
73  this->sinkPipe = sink;
74  } else {
75  this->sinkPipe->connectSinkPipe(sink);
76  }
77 }
78 
80  if (sinkPipe != nullptr) {
83  sinkPipe = nullptr;
84  }
85 }
86 
88  if (sinkPipe != nullptr) {
90  sinkPipe = nullptr;
91  }
92 }
93 
95  if (!hasSinkPipe())
96  return false;
97  return sinkPipe->disconnect(sink);
98 }
99 
101  : sinkPipe(std::exchange(other.sinkPipe, nullptr)) {
102  if (this->hasSinkPipe()) {
103  this->sinkPipe->disconnectSource();
104  this->sinkPipe->connectSource(this);
105  }
106 }
107 
109  std::swap(this->sinkPipe, other.sinkPipe);
110  if (this->hasSinkPipe()) {
111  this->sinkPipe->disconnectSource();
112  this->sinkPipe->connectSource(this);
113  }
114  if (other.hasSinkPipe()) {
115  other.sinkPipe->disconnectSource();
116  other.sinkPipe->connectSource(this);
117  }
118  return *this;
119 }
120 
122 
123 void MIDI_Source::exclusive(cn_t cn, bool exclusive) {
124  if (hasSinkPipe())
126 }
127 
128 bool MIDI_Source::canWrite(cn_t cn) const {
129  return !hasSinkPipe() || sinkPipe->isAvailableForWrite(cn);
130 }
131 
133  if (sinkPipe != nullptr) {
134  sinkPipe->pipeMIDI(msg);
135  }
136 }
138  if (sinkPipe != nullptr) {
139  sinkPipe->pipeMIDI(msg);
140  }
141 }
143  if (sinkPipe != nullptr) {
144  sinkPipe->pipeMIDI(msg);
145  }
146 }
147 
148 // :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: //
149 
151  if (this->sink != nullptr) {
152  FATAL_ERROR(F("This pipe is already connected to a sink"), 0x9145);
153  return; // LCOV_EXCL_LINE
154  }
155  this->sink = sink;
156 }
157 
158 void MIDI_Pipe::disconnectSink() { this->sink = nullptr; }
159 
161  if (this->source != nullptr) {
162  FATAL_ERROR(F("This pipe is already connected to a source"), 0x9146);
163  return; // LCOV_EXCL_LINE
164  }
165  this->source = source;
166 }
167 
168 void MIDI_Pipe::disconnectSource() { this->source = nullptr; }
169 
171  if (hasSink() && hasThroughIn()) {
172  auto oldSink = sink;
173  auto oldThroughIn = throughIn;
175  this->disconnectSourcePipesShallow(); // disconnect throughIn
176  oldSink->connectSourcePipe(oldThroughIn);
177  }
178  if (hasSource() && hasThroughOut()) {
179  auto oldSource = source;
180  auto oldThroughOut = throughOut;
182  this->disconnectSinkPipesShallow(); // disconnect throughOut
183  oldSource->connectSinkPipe(oldThroughOut);
184  }
185  if (hasSink())
187 
188  if (hasSource())
190 
191  if (hasThroughIn() || hasThroughOut())
192  FATAL_ERROR(F("Invalid state"), 0x9147); // LCOV_EXCL_LINE
193 }
194 
196 
197 #if defined(ESP32) || !defined(ARDUINO)
198 static std::mutex pipe_exclusive_mutex;
199 #endif
200 
201 void MIDI_Pipe::exclusive(cn_t cn, bool exclusive) {
202 #if defined(ESP32) || !defined(ARDUINO)
203  std::lock_guard<std::mutex> lock_guard(pipe_exclusive_mutex);
204 #endif
205  if (hasSink())
207  if (hasThroughIn())
209 }
210 
212 
MIDI_Source::connectSinkPipe
void connectSinkPipe(MIDI_Pipe *sink)
Fully connect a sink pipe to this source.
Definition: MIDI_Pipes.cpp:70
MIDI_Pipe
Class that routes MIDI messages from a MIDI_Source to a MIDI_Sink.
Definition: MIDI_Pipes.hpp:270
MIDI_Pipe::source
MIDI_Source * source
Definition: MIDI_Pipes.hpp:489
MIDI_Pipe::~MIDI_Pipe
virtual ~MIDI_Pipe()
Destructor.
Definition: MIDI_Pipes.cpp:195
MIDI_Source
Class that can send MIDI messages to a MIDI pipe.
Definition: MIDI_Pipes.hpp:125
TrueMIDI_Source
A MIDI_Source that is not a MIDI_Pipe.
Definition: MIDI_Pipes.hpp:219
MIDI_Source::MIDI_Source
MIDI_Source()=default
Default constructor.
SysExMessage
Definition: MIDI_MessageTypes.hpp:138
MIDI_Pipe::throughIn
MIDI_Pipe *& throughIn
Definition: MIDI_Pipes.hpp:491
MIDI_Pipe::hasThroughOut
bool hasThroughOut() const
Check if this pipe has a "through" output that sends all incoming messages from the input (source) to...
Definition: MIDI_Pipes.hpp:311
Error.hpp
MIDI_Pipe::connectSource
void connectSource(MIDI_Source *source)
Set the source pointer to point to the given source.
Definition: MIDI_Pipes.cpp:160
MIDI_Source::hasSinkPipe
bool hasSinkPipe() const
Check if this source is connected to a sink pipe.
Definition: MIDI_Pipes.hpp:189
MIDI_Pipe::throughOut
MIDI_Pipe *& throughOut
Definition: MIDI_Pipes.hpp:490
MIDI_Pipe::isAvailableForWrite
bool isAvailableForWrite(cn_t cn) const
Check if any of the sinks or outputs of this chain of pipes are locked for the given cable number.
Definition: MIDI_Pipes.hpp:482
MIDI_Sink::MIDI_Sink
MIDI_Sink()=default
Default constructor.
MIDI_Pipe::disconnectSource
void disconnectSource()
Set the source pointer to null.
Definition: MIDI_Pipes.cpp:168
BEGIN_CS_NAMESPACE
#define BEGIN_CS_NAMESPACE
Definition: Settings/NamespaceSettings.hpp:9
AH_DIAGNOSTIC_POP
#define AH_DIAGNOSTIC_POP()
Definition: Warnings.hpp:36
MIDI_Source::operator=
MIDI_Source & operator=(const MIDI_Source &)=delete
Copy assignment (copying not allowed).
MIDI_Sink::~MIDI_Sink
virtual ~MIDI_Sink()
Destructor.
Definition: MIDI_Pipes.cpp:45
MIDI_Source::disconnectSinkPipes
void disconnectSinkPipes()
Disconnect all sink pipes that this source sinks to (recursively).
Definition: MIDI_Pipes.cpp:79
MIDI_Pipe::pipeMIDI
void pipeMIDI(ChannelMessage msg)
Accept a MIDI message from the source, forward it to the "through" output if necessary,...
Definition: MIDI_Pipes.hpp:320
MIDI_Sink::hasSourcePipe
bool hasSourcePipe() const
Check if this sink is connected to a source pipe.
Definition: MIDI_Pipes.hpp:94
FATAL_ERROR
#define FATAL_ERROR(msg, errc)
Print the error message and error code, and stop the execution.
Definition: Error.hpp:60
MIDI_Sink::sourcePipe
MIDI_Pipe * sourcePipe
Definition: MIDI_Pipes.hpp:117
END_CS_NAMESPACE
#define END_CS_NAMESPACE
Definition: Settings/NamespaceSettings.hpp:10
TrueMIDI_Sink
A MIDI_Sink that is not a MIDI_Pipe.
Definition: MIDI_Pipes.hpp:217
MIDI_Sink::lockDownstream
virtual void lockDownstream(cn_t cn, bool lock)
Base case for recursive lock function.
Definition: MIDI_Pipes.hpp:105
MIDI_Pipe::lockUpstream
void lockUpstream(cn_t cn, bool lock)
Lock this pipe and all other pipes further upstream (following the path of the "trough" input).
Definition: MIDI_Pipes.hpp:405
MIDI_Source::sinkPipe
MIDI_Pipe * sinkPipe
Definition: MIDI_Pipes.hpp:209
MIDI_Source::sourceMIDItoPipe
void sourceMIDItoPipe(ChannelMessage)
Send a MIDI Channel Message.
Definition: MIDI_Pipes.cpp:132
RealTimeMessage
Definition: MIDI_MessageTypes.hpp:173
MIDI_Sink::disconnectSourcePipes
void disconnectSourcePipes()
Disconnect all source pipes that sink to this sink (recursively).
Definition: MIDI_Pipes.cpp:24
MIDI_Source::disconnectSinkPipesShallow
void disconnectSinkPipesShallow()
Disconnect only the first pipe connected to this source.
Definition: MIDI_Pipes.cpp:87
MIDI_Sink::connectSourcePipe
void connectSourcePipe(MIDI_Pipe *source)
Fully connect a source pipe to this sink.
Definition: MIDI_Pipes.cpp:15
MIDI_Sink::operator=
MIDI_Sink & operator=(const MIDI_Sink &)=delete
Copy assignment (copying not allowed).
MIDI_Pipe::hasSource
bool hasSource() const
Check if this pipe is connected to a source.
Definition: MIDI_Pipes.hpp:308
MIDI_Sink::disconnectSourcePipesShallow
void disconnectSourcePipesShallow()
Disconnect only the first pipe connected to this sink.
Definition: MIDI_Pipes.cpp:32
MIDI_Pipe::hasSink
bool hasSink() const
Check if this pipe is connected to a sink.
Definition: MIDI_Pipes.hpp:306
MIDI_Source::exclusive
void exclusive(cn_t cn, bool exclusive=true)
Enter or exit exclusive mode for the given cable number.
Definition: MIDI_Pipes.cpp:123
cn_t
uint8_t cn_t
Data type for cable numbers.
Definition: MIDI_Pipes.hpp:14
MIDI_Notes::F
constexpr int8_t F
Definition: Notes.hpp:23
MIDI_Sink::disconnect
bool disconnect(TrueMIDI_Source &source)
Disconnect the given source from this sink.
Definition: MIDI_Pipes.cpp:39
MIDI_Source::canWrite
bool canWrite(cn_t cn) const
Check if this source can write to the sinks it connects to.
Definition: MIDI_Pipes.cpp:128
std
Definition: vector.cpp:5
MIDI_Source::~MIDI_Source
virtual ~MIDI_Source()
Destructor.
Definition: MIDI_Pipes.cpp:121
AH_DIAGNOSTIC_WERROR
#define AH_DIAGNOSTIC_WERROR()
Definition: Warnings.hpp:35
ChannelMessage
Definition: MIDI_MessageTypes.hpp:72
MIDI_Pipe::disconnect
void disconnect()
Disconnect this pipe from all other pipes, sources and sinks.
Definition: MIDI_Pipes.cpp:170
MIDI_Pipes.hpp
MIDI_Sink
Class that can receive MIDI messages from a MIDI pipe.
Definition: MIDI_Pipes.hpp:51
MIDI_Pipe::disconnectSink
void disconnectSink()
Set the sink pointer to null.
Definition: MIDI_Pipes.cpp:158
MIDI_Source::disconnect
bool disconnect(TrueMIDI_Sink &sink)
Disconnect the given sink from this source.
Definition: MIDI_Pipes.cpp:94
MIDI_Pipe::connectSink
void connectSink(MIDI_Sink *sink)
Set the sink pointer to point to the given sink.
Definition: MIDI_Pipes.cpp:150
MIDI_Pipe::sink
MIDI_Sink * sink
Definition: MIDI_Pipes.hpp:488
MIDI_Pipe::hasThroughIn
bool hasThroughIn() const
Check if this pipe has a "through" input that merges all messages from another pipe into the output (...
Definition: MIDI_Pipes.hpp:314
MIDI_Pipe::exclusive
void exclusive(cn_t cn, bool exclusive=true)
Enter or exit exclusive mode for the given cable number.
Definition: MIDI_Pipes.cpp:201