Control Surface disable-pipes
MIDI Control Surface library for Arduino
MIDI_Pipes.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <Settings/SettingsWrapper.hpp>
4#if !DISABLE_PIPES
5
7#include <AH/STL/cstdint>
8#include <AH/STL/limits>
9#include <AH/STL/utility>
12#include <Settings/NamespaceSettings.hpp>
13
15
17
18struct MIDIStaller;
20 reinterpret_cast<MIDIStaller *>(std::numeric_limits<std::uintptr_t>::max());
21
65class MIDI_Pipe;
66class MIDI_Source;
67class MIDI_Sink;
72
74class MIDI_Sink {
75 public:
77 MIDI_Sink() = default;
78
80 MIDI_Sink(const MIDI_Sink &) = delete;
82 MIDI_Sink &operator=(const MIDI_Sink &) = delete;
83
85 MIDI_Sink(MIDI_Sink &&other);
87 MIDI_Sink &operator=(MIDI_Sink &&other);
88
90 virtual ~MIDI_Sink();
91
94
98 virtual void sinkMIDIfromPipe(SysExMessage) = 0;
103
105
108
110 void connectSourcePipe(MIDI_Pipe *source);
112 void disconnectSourcePipes();
117 bool disconnect(TrueMIDI_Source &source);
118 bool disconnect(MIDI_Pipe &) = delete;
120 bool hasSourcePipe() const { return sourcePipe != nullptr; }
123 MIDI_Pipe *getSourcePipe() { return sourcePipe; }
124
126
127 private:
136 virtual MIDI_Sink *getFinalSink() { return this; }
142 void disconnectSourcePipesShallow();
143
144 protected:
145 MIDI_Pipe *sourcePipe = nullptr;
146
147 friend class MIDI_Pipe;
148
149 public:
150 static void swap(MIDI_Sink &a, MIDI_Sink &b);
151 friend void swap(MIDI_Sink &a, MIDI_Sink &b) { swap(a, b); }
152};
153
154// :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: //
155
158 public:
160 MIDI_Source() = default;
161
163 MIDI_Source(const MIDI_Source &) = delete;
166
168 MIDI_Source(MIDI_Source &&other);
171
173 virtual ~MIDI_Source();
174
177
186
188
191
199 void stall(MIDIStaller *cause = eternal_stall);
205 void unstall(MIDIStaller *cause = eternal_stall);
207 bool isStalled() const;
210 MIDIStaller *getStaller() const;
213 const char *getStallerName() const;
216 void handleStallers() const;
217
219
222
224 void connectSinkPipe(MIDI_Pipe *sink);
226 void disconnectSinkPipes();
231 bool disconnect(TrueMIDI_Sink &sink);
232 bool disconnect(MIDI_Pipe &) = delete;
234 bool hasSinkPipe() const { return sinkPipe != nullptr; }
238
240
241 private:
244 virtual void stallUpstream(MIDIStaller *, MIDI_Sink *) {}
250 virtual MIDI_Source *getInitialSource() { return this; }
257
258 protected:
259 MIDI_Pipe *sinkPipe = nullptr;
260
261 friend class MIDI_Pipe;
262
263 public:
264 static void swap(MIDI_Source &a, MIDI_Source &b);
265 friend void swap(MIDI_Source &a, MIDI_Source &b) { swap(a, b); }
266};
267
268// :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: //
269
329class MIDI_Pipe : private MIDI_Sink, private MIDI_Source {
330 public:
332 MIDI_Pipe() = default;
333
335 MIDI_Pipe(const MIDI_Pipe &) = delete;
337 MIDI_Pipe &operator=(const MIDI_Pipe &) = delete;
338
341 MIDI_Pipe(MIDI_Pipe &&) = delete;
345
347 virtual ~MIDI_Pipe();
348
349 private:
352
360 virtual void mapForwardMIDI(SysExMessage msg) { sourceMIDItoSink(msg); }
365
367
368 public:
371
373 bool isStalled() const { return sink_staller || through_staller; }
381 const char *getSinkStallerName() const;
389 const char *getThroughStallerName() const;
392 MIDIStaller *getStaller() const;
395 const char *getStallerName() const;
400 return sink_staller == nullptr || sink_staller == cause;
401 }
406 return through_staller == nullptr || through_staller == cause;
407 }
408
411 void handleStallers() const;
412
414
415 public:
418
420 bool hasSink() const { return sink != nullptr; }
422 bool hasSource() const { return source != nullptr; }
425 bool hasThroughOut() const { return throughOut != nullptr; }
428 bool hasThroughIn() const { return throughIn != nullptr; }
429
431
432 public:
435
439 void disconnect();
445 if (getFinalSink() == &sink) {
446 disconnect();
447 return true;
448 }
449 if (hasThroughOut()) {
450 return throughOut->disconnect(sink);
451 }
452 return false;
453 }
459 if (getInitialSource() == &source) {
460 disconnect();
461 return true;
462 }
463 if (hasThroughIn()) {
464 return throughIn->disconnect(source);
465 }
466 return false;
467 }
468 bool disconnect(MIDI_Pipe &) = delete;
469
473 MIDI_Sink *getSink() { return sink; }
478
482 return hasSink() ? sink->getFinalSink() : nullptr;
483 }
487 return hasSource() ? source->getInitialSource() : nullptr;
488 }
489
491
492 private:
495
501 void disconnectSink();
507 void disconnectSource();
508
510
511 protected:
514 template <class Message>
515 void sourceMIDItoSink(Message msg) {
516 if (hasSink())
518 }
519
520 protected:
525 template <class Message>
526 void acceptMIDIfromSource(Message msg) {
527 if (hasThroughOut())
529 mapForwardMIDI(msg);
530 }
531
532 private:
535 void sinkMIDIfromPipe(ChannelMessage msg) override {
536 sourceMIDItoSink(msg);
537 }
539 void sinkMIDIfromPipe(SysExMessage msg) override { sourceMIDItoSink(msg); }
542 sourceMIDItoSink(msg);
543 }
546 sourceMIDItoSink(msg);
547 }
548
549 private:
552
560 void stallDownstream(MIDIStaller *cause, MIDI_Source *stallsrc) override;
562 void unstallDownstream(MIDIStaller *cause, MIDI_Source *stallsrc) override;
563
568 void stallUpstream(MIDIStaller *cause, MIDI_Sink *stallsrc) override;
570 void unstallUpstream(MIDIStaller *cause, MIDI_Sink *stallsrc) override;
571
573
574 private:
575 MIDI_Sink *sink = nullptr;
576 MIDI_Source *source = nullptr;
581
582 friend class MIDI_Sink;
583 friend class MIDI_Source;
584};
585
586// :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: //
587
590
592using BidirectionalMIDI_Pipe = std::pair<MIDI_Pipe, MIDI_Pipe>;
593
596 source.connectSinkPipe(&pipe);
597 return pipe;
598}
599
602 sink.connectSourcePipe(&pipe);
603 return sink;
604}
605
608 sink.connectSourcePipe(&pipe);
609 return pipe;
610}
611
614 source.connectSinkPipe(&pipe);
615 return source;
616}
617
620
623 TrueMIDI_SinkSource &sinksource) {
624 sinksource.connectSinkPipe(&pipe.first);
625 sinksource.connectSourcePipe(&pipe.second);
626 return sinksource;
627}
628
632 sinksource.connectSinkPipe(&pipe.second);
633 sinksource.connectSourcePipe(&pipe.first);
634 return pipe;
635}
636
637// :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: //
638
647template <size_t N, class Pipe = MIDI_Pipe>
649 Pipe pipes[N];
650 size_t index = 0;
651
652 Pipe &getNext() {
653 if (index >= N)
654 FATAL_ERROR(F("Not enough pipes available"), 0x2459);
655 return pipes[index++];
656 }
657 Pipe &operator[](size_t i) { return pipes[i]; }
658 const Pipe &operator[](size_t i) const { return pipes[i]; }
659};
660
661template <size_t N>
664
665template <size_t N, class Pipe>
667 MIDI_PipeFactory<N, Pipe> &pipe_fact) {
668 return source >> pipe_fact.getNext();
669}
670
671template <size_t N, class Pipe>
673
674template <size_t N, class Pipe>
676 TrueMIDI_Sink &sink) {
677 return pipe_fact.getNext() >> sink;
678}
679
680template <size_t N, class Pipe>
682
683template <size_t N, class Pipe>
685 MIDI_PipeFactory<N, Pipe> &pipe_fact) {
686 return sink << pipe_fact.getNext();
687}
688
689template <size_t N, class Pipe>
691 TrueMIDI_Source &source) {
692 return pipe_fact.getNext() << source;
693}
694
695template <size_t N>
696inline TrueMIDI_SinkSource &
698 TrueMIDI_SinkSource &sinksource) {
699 return pipe_fact.getNext() | sinksource;
700}
701
702template <size_t N>
706 return sinksource | pipe_fact.getNext();
707}
708
710
712
714
715#else
716
718
719struct TrueMIDI_Source {
720 template <class... Args>
721 void sourceMIDItoPipe(Args &&...) {}
722};
723struct TrueMIDI_Sink {};
725
727
728#endif
void swap(AHEncoder &a, AHEncoder &b)
Definition: AHEncoder.cpp:25
MIDIStaller *const eternal_stall
Definition: MIDI_Pipes.hpp:19
#define END_CS_NAMESPACE
#define BEGIN_CS_NAMESPACE
#define AH_DIAGNOSTIC_POP()
Definition: Warnings.hpp:53
#define AH_DIAGNOSTIC_WERROR()
Definition: Warnings.hpp:52
Class that routes MIDI messages from a MIDI_Source to a MIDI_Sink.
Definition: MIDI_Pipes.hpp:329
void acceptMIDIfromSource(Message msg)
Accept a MIDI message from the source, forward it to the “through” output if necessary,...
Definition: MIDI_Pipes.hpp:526
bool hasSink() const
Check if this pipe is connected to a sink.
Definition: MIDI_Pipes.hpp:420
void sourceMIDItoSink(Message msg)
Send the given MIDI message to the sink of this pipe.
Definition: MIDI_Pipes.hpp:515
const char * getStallerName() const
Get the name of any staller.
Definition: MIDI_Pipes.cpp:337
MIDI_Pipe(MIDI_Pipe &&)=delete
Move constructor.
MIDIStaller * getStaller() const
Get any staller: returns getSinkStaller() if it's not null, getThroughStaller() otherwise.
Definition: MIDI_Pipes.cpp:333
virtual void mapForwardMIDI(SysExMessage msg)
Function that maps, edits or filters MIDI messages, and then forwards them to the sink of the pipe.
Definition: MIDI_Pipes.hpp:360
MIDI_Source * source
Definition: MIDI_Pipes.hpp:576
bool disconnect(MIDI_Pipe &)=delete
MIDI_Pipe * getThroughOut()
Get the pipe connected to the “through” output of this pipe.
Definition: MIDI_Pipes.hpp:475
void connectSource(MIDI_Source *source)
Set the source pointer to point to the given source.
Definition: MIDI_Pipes.cpp:203
MIDI_Sink * sink
Definition: MIDI_Pipes.hpp:575
MIDI_Pipe(const MIDI_Pipe &)=delete
Copy constructor (copying not allowed).
virtual void mapForwardMIDI(RealTimeMessage msg)
Function that maps, edits or filters MIDI messages, and then forwards them to the sink of the pipe.
Definition: MIDI_Pipes.hpp:364
void sinkMIDIfromPipe(SysCommonMessage msg) override
Called when data arrives from an upstream pipe connected to our “through” input, this function forwar...
Definition: MIDI_Pipes.hpp:541
virtual void mapForwardMIDI(SysCommonMessage msg)
Function that maps, edits or filters MIDI messages, and then forwards them to the sink of the pipe.
Definition: MIDI_Pipes.hpp:362
void unstallDownstream(MIDIStaller *cause, MIDI_Source *stallsrc) override
Undoes the stalling by stallDownstream.
Definition: MIDI_Pipes.cpp:283
bool hasSource() const
Check if this pipe is connected to a source.
Definition: MIDI_Pipes.hpp:422
void stallDownstream(MIDIStaller *cause, MIDI_Source *stallsrc) override
Stall this pipe and all other pipes further downstream (following the path of the sink and the “throu...
Definition: MIDI_Pipes.cpp:240
MIDI_Pipe & operator=(MIDI_Pipe &&)=delete
Move assignment.
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:425
MIDIStaller * getThroughStaller() const
Get the staller (cause of the stall) that causes the “through” output of this pipe to be stalled.
Definition: MIDI_Pipes.hpp:386
MIDIStaller * through_staller
Definition: MIDI_Pipes.hpp:580
void connectSink(MIDI_Sink *sink)
Set the sink pointer to point to the given sink.
Definition: MIDI_Pipes.cpp:193
const char * getSinkStallerName() const
Get the name of the staller (cause of the stall) that causes the sink of this pipe to be stalled.
Definition: MIDI_Pipes.cpp:325
MIDI_Pipe & operator=(const MIDI_Pipe &)=delete
Copy assignment (copying not allowed).
void sinkMIDIfromPipe(RealTimeMessage msg) override
Called when data arrives from an upstream pipe connected to our “through” input, this function forwar...
Definition: MIDI_Pipes.hpp:545
MIDI_Pipe *& throughOut
Definition: MIDI_Pipes.hpp:577
bool isStalled() const
Check if this pipe is stalled.
Definition: MIDI_Pipes.hpp:373
MIDIStaller * sink_staller
Definition: MIDI_Pipes.hpp:579
virtual ~MIDI_Pipe()
Destructor.
Definition: MIDI_Pipes.cpp:238
const char * getThroughStallerName() const
Get the name of the staller (cause of the stall) that causes the “through” output of this pipe to be ...
Definition: MIDI_Pipes.cpp:329
void unstallUpstream(MIDIStaller *cause, MIDI_Sink *stallsrc) override
Undoes the stalling by stallUpstream.
Definition: MIDI_Pipes.cpp:307
void disconnect()
Disconnect this pipe from all other pipes, sources and sinks.
Definition: MIDI_Pipes.cpp:213
MIDI_Source * getSource()
Get the immediate source of this pipe.
Definition: MIDI_Pipes.hpp:471
bool disconnect(TrueMIDI_Sink &sink)
Disconnect the given sink from this pipe.
Definition: MIDI_Pipes.hpp:444
void sinkMIDIfromPipe(ChannelMessage msg) override
Called when data arrives from an upstream pipe connected to our “through” input, this function forwar...
Definition: MIDI_Pipes.hpp:535
virtual void mapForwardMIDI(ChannelMessage msg)
Function that maps, edits or filters MIDI messages, and then forwards them to the sink of the pipe.
Definition: MIDI_Pipes.hpp:358
MIDI_Sink * getFinalSink() override
Get the sink this pipe eventually sinks to, following the chain recursively.
Definition: MIDI_Pipes.hpp:481
MIDI_Sink * getSink()
Get the immediate sink of this pipe.
Definition: MIDI_Pipes.hpp:473
void handleStallers() const
Give the code that is stalling the MIDI pipe the opportunity to do its job and unstall the pipe.
Definition: MIDI_Pipes.cpp:341
MIDI_Pipe *& throughIn
Definition: MIDI_Pipes.hpp:578
MIDI_Pipe * getThroughIn()
Get the pipe connected to the “through” input of this pipe.
Definition: MIDI_Pipes.hpp:477
void disconnectSink()
Set the sink pointer to null.
Definition: MIDI_Pipes.cpp:201
MIDIStaller * getSinkStaller() const
Get the staller (cause of the stall) that causes the sink of this pipe to be stalled.
Definition: MIDI_Pipes.hpp:378
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:428
MIDI_Pipe()=default
Default constructor.
bool throughIsUnstalledOrStalledBy(MIDIStaller *cause)
Returns true if this pipe is either not stalled at all, or if the pipe is stalled by the given stalle...
Definition: MIDI_Pipes.hpp:405
void disconnectSource()
Set the source pointer to null.
Definition: MIDI_Pipes.cpp:211
bool disconnect(TrueMIDI_Source &source)
Disconnect the given source from this pipe.
Definition: MIDI_Pipes.hpp:458
MIDI_Source * getInitialSource() override
Get the original source that sources to this pipe, following the chain recursively.
Definition: MIDI_Pipes.hpp:486
bool sinkIsUnstalledOrStalledBy(MIDIStaller *cause)
Returns true if this pipe is either not stalled at all, or if the pipe is stalled by the given stalle...
Definition: MIDI_Pipes.hpp:399
void sinkMIDIfromPipe(SysExMessage msg) override
Called when data arrives from an upstream pipe connected to our “through” input, this function forwar...
Definition: MIDI_Pipes.hpp:539
void stallUpstream(MIDIStaller *cause, MIDI_Sink *stallsrc) override
Stall this pipe and all other pipes further upstream (following the path of the "trough" input).
Definition: MIDI_Pipes.cpp:265
Receives MIDI messages from a MIDI pipe.
Definition: MIDI_Pipes.hpp:74
virtual void sinkMIDIfromPipe(RealTimeMessage)=0
Accept an incoming MIDI Real-Time message.
void connectSourcePipe(MIDI_Pipe *source)
Fully connect a source pipe to this sink.
Definition: MIDI_Pipes.cpp:19
virtual void stallDownstream(MIDIStaller *, MIDI_Source *)
Base case for recursive stall function.
Definition: MIDI_Pipes.hpp:130
bool disconnect(MIDI_Pipe &)=delete
MIDI_Sink(const MIDI_Sink &)=delete
Copy constructor (copying not allowed).
friend void swap(MIDI_Sink &a, MIDI_Sink &b)
Definition: MIDI_Pipes.hpp:151
virtual void unstallDownstream(MIDIStaller *, MIDI_Source *)
Base case for recursive un-stall function.
Definition: MIDI_Pipes.hpp:133
virtual void sinkMIDIfromPipe(SysCommonMessage)=0
Accept an incoming MIDI System Common message.
MIDI_Sink()=default
Default constructor.
virtual MIDI_Sink * getFinalSink()
Base case for recursive function.
Definition: MIDI_Pipes.hpp:136
virtual void sinkMIDIfromPipe(ChannelMessage)=0
Accept an incoming MIDI Channel message.
MIDI_Pipe * getSourcePipe()
Get a pointer to the pipe this sink is connected to, or nullptr if not connected.
Definition: MIDI_Pipes.hpp:123
MIDI_Pipe * sourcePipe
Definition: MIDI_Pipes.hpp:145
virtual void sinkMIDIfromPipe(SysExMessage)=0
Accept an incoming MIDI System Exclusive message.
bool hasSourcePipe() const
Check if this sink is connected to a source pipe.
Definition: MIDI_Pipes.hpp:120
MIDI_Sink & operator=(const MIDI_Sink &)=delete
Copy assignment (copying not allowed).
Class that can send MIDI messages to a MIDI pipe.
Definition: MIDI_Pipes.hpp:157
MIDI_Pipe * getSinkPipe()
Get a pointer to the pipe this source is connected to, or nullptr if not connected.
Definition: MIDI_Pipes.hpp:237
virtual MIDI_Source * getInitialSource()
Base case for recursive function.
Definition: MIDI_Pipes.hpp:250
const char * getStallerName() const
Get the name of whatever is causing this MIDI source to be stalled.
Definition: MIDI_Pipes.cpp:182
void connectSinkPipe(MIDI_Pipe *sink)
Fully connect a sink pipe to this source.
Definition: MIDI_Pipes.cpp:78
virtual ~MIDI_Source()
Destructor.
Definition: MIDI_Pipes.cpp:133
MIDIStaller * getStaller() const
Get a pointer to whatever is causing this MIDI source to be stalled.
Definition: MIDI_Pipes.cpp:176
bool disconnect(MIDI_Pipe &)=delete
MIDI_Source()=default
Default constructor.
void sourceMIDItoPipe(ChannelMessage)
Send a MIDI Channel Message down the pipe.
Definition: MIDI_Pipes.cpp:135
MIDI_Pipe * sinkPipe
Definition: MIDI_Pipes.hpp:259
void stall(MIDIStaller *cause=eternal_stall)
Stall this MIDI source.
Definition: MIDI_Pipes.cpp:160
virtual void stallUpstream(MIDIStaller *, MIDI_Sink *)
Base case for recursive stall function.
Definition: MIDI_Pipes.hpp:244
bool isStalled() const
Check if this source can write to the sinks it connects to.
Definition: MIDI_Pipes.cpp:170
static void swap(MIDI_Source &a, MIDI_Source &b)
Definition: MIDI_Pipes.cpp:116
void disconnectSinkPipesShallow()
Disconnect only the first pipe connected to this source.
Definition: MIDI_Pipes.cpp:95
bool disconnect(TrueMIDI_Sink &sink)
Disconnect the given sink from this source.
Definition: MIDI_Pipes.cpp:102
void disconnectSinkPipes()
Disconnect all sink pipes that this source sinks to (recursively).
Definition: MIDI_Pipes.cpp:87
MIDI_Source & operator=(const MIDI_Source &)=delete
Copy assignment (copying not allowed).
void handleStallers() const
Give the code that is stalling the MIDI sink pipes the opportunity to do its job and un-stall the pip...
Definition: MIDI_Pipes.cpp:186
virtual void unstallUpstream(MIDIStaller *, MIDI_Sink *)
Base case for recursive un-stall function.
Definition: MIDI_Pipes.hpp:247
MIDI_Source(const MIDI_Source &)=delete
Copy constructor (copying not allowed).
bool hasSinkPipe() const
Check if this source is connected to a sink pipe.
Definition: MIDI_Pipes.hpp:234
void unstall(MIDIStaller *cause=eternal_stall)
Un-stall the pipes connected to this source, so other sources are allowed to send again.
Definition: MIDI_Pipes.cpp:165
#define FATAL_ERROR(msg, errc)
Print the error message and error code, and stop the execution.
Definition: Error.hpp:60
constexpr auto max(const T &a, const U &b) -> decltype(a< b ? b :a)
Return the larger of two numbers/objects.
Definition: MinMaxFix.hpp:22
TrueMIDI_SinkSource & operator|(BidirectionalMIDI_Pipe &pipe, TrueMIDI_SinkSource &sinksource)
Connect a pipe to a sink+source (pipe | source+sink).
Definition: MIDI_Pipes.hpp:622
std::pair< MIDI_Pipe, MIDI_Pipe > BidirectionalMIDI_Pipe
A bidirectional pipe consists of two unidirectional pipes.
Definition: MIDI_Pipes.hpp:592
MIDI_Pipe & operator>>(TrueMIDI_Source &source, MIDI_Pipe &pipe)
Connect a source to a pipe (source >> pipe).
Definition: MIDI_Pipes.hpp:595
Print & operator<<(Print &os, Quaternion e)
Printing.
Definition: Quaternion.cpp:28
Struct that can cause a MIDI_Pipe to be stalled.
Class that produces multiple MIDI_Pipes.
Definition: MIDI_Pipes.hpp:648
Pipe & operator[](size_t i)
Definition: MIDI_Pipes.hpp:657
const Pipe & operator[](size_t i) const
Definition: MIDI_Pipes.hpp:658
A struct that is both a TrueMIDI_Sink and a TrueMIDI_Source.
Definition: MIDI_Pipes.hpp:589