arduino-audio-tools
Pipeline.h
1 #pragma once
2 
3 #include "AudioTools/AudioOutput.h"
4 #include "AudioTools/AudioStreams.h"
5 
6 namespace audio_tools {
7 
16 class Pipeline : public AudioStream {
17  friend MultiOutput;
18 
19  public:
20  Pipeline() = default;
22  bool add(ModifyingStream& io) {
23  if (has_output) {
24  LOGE("Output already defined");
25  is_ok = false;
26  return false;
27  }
28  if (has_input) {
29  if (p_stream == nullptr) {
30  LOGE("Input not defined");
31  is_ok = false;
32  return false;
33  }
34 
35  // predecessor notifies successor
36  if (p_ai_source != nullptr) {
37  p_ai_source->addNotifyAudioChange(io);
38  }
39 
40  // we set up an input chain
41  components.push_back(&io);
42  io.setStream(*p_stream);
43  p_stream = &io;
44  p_ai_source = &io;
45  } else {
46  // we assume an output chain
47  if (size() > 0) {
48  auto& last_c = last();
49  last_c.setOutput(io);
50  last_c.addNotifyAudioChange(io);
51  }
52  components.push_back(&io);
53  }
54  return true;
55  }
56 
58  bool add(ModifyingOutput& out) {
59  if (has_output) {
60  LOGE("Output already defined");
61  is_ok = false;
62  return false;
63  }
64  if (has_input) {
65  LOGE("Input not supported");
66  is_ok = false;
67  return false;
68  }
70  cleanup.push_back(io);
71  return add(*io);
72  }
73 
75  bool setOutput(AudioOutput& out) {
76  p_out_print = &out;
77  if (size() > 0) {
79  }
80  return setOutput((Print&)out);
81  }
82 
84  bool setOutput(AudioStream& out) {
85  p_out_stream = &out;
86  if (size() > 0) {
88  }
89  return setOutput((Print&)out);
90  }
91 
93  bool setOutput(Print& out) {
94  if (has_output) {
95  LOGE("Output already defined");
96  is_ok = false;
97  return false;
98  }
99  p_print = &out;
100  if (size() > 0) {
101  last().setOutput(out);
102  }
103  // must be last element
104  has_output = true;
105  return true;
106  }
107 
109  bool setInput(AudioStream& in) {
110  p_ai_source = ∈
111  p_ai_input = ∈
112  return setInput((Stream&)in);
113  }
114 
116  bool setInput(Stream& in) {
117  if (has_output) {
118  LOGE("Defined as output");
119  is_ok = false;
120  return false;
121  }
122  if (has_input) {
123  LOGE("Input already defined");
124  is_ok = false;
125  return false;
126  }
127  // must be first
128  has_input = true;
129  p_stream = ∈
130  return true;
131  }
132 
133  int availableForWrite() override {
134  if (!is_active) return 0;
135  if (size() == 0) {
136  if (p_print != nullptr) return p_print->availableForWrite();
137  return 0;
138  }
139  return components[0]->availableForWrite();
140  }
141 
142  size_t write(const uint8_t* data, size_t bytes) override {
143  if (!is_active) return 0;
144  if (size() == 0) {
145  if (p_print != nullptr) return p_print->write(data, bytes);
146  return 0;
147  }
148  LOGD("write: %u", (unsigned)bytes);
149  return components[0]->write(data, bytes);
150  }
151 
152  int available() override {
153  if (!is_active) return 0;
154  Stream* in = getInput();
155  if (in == nullptr) return 0;
156  return in->available();
157  }
158 
159  size_t readBytes(uint8_t* data, size_t bytes) override {
160  if (!is_active) return 0;
161  Stream* in = getInput();
162  if (in == nullptr) return 0;
163  return in->readBytes(data, bytes);
164  }
165 
168  bool begin(AudioInfo info) {
169  LOGI("begin");
170  bool rc = begin();
171  setAudioInfo(info);
172  audioInfoOut().logInfo("pipeline out:");
173  return rc;
174  }
175 
177  bool begin() override {
178  has_output = false;
179  bool ok = true;
180 
181  // avoid too much noise
182  setNotifyActive(false);
183 
184  // start components
185  for (auto c : components) {
186  ok = ok && c->begin();
187  }
188  // start output
189  if (p_out_stream != nullptr) {
190  ok = ok && p_out_stream->begin();
191  } else if (p_out_print != nullptr) {
192  ok = ok && p_out_print->begin();
193  }
194  // start input
195  if (p_ai_input != nullptr) {
196  ok = ok && p_ai_input->begin();
197  }
198 
199  setNotifyActive(true);
200  is_active = ok;
201  is_ok = ok;
202  return ok;
203  }
204 
206  void end() override {
207  for (auto c : components) {
208  c->end();
209  }
210  components.clear();
211  for (auto& c : cleanup) {
212  delete c;
213  }
214  cleanup.clear();
215 
216  has_output = false;
217  has_input = false;
218  p_out_print = nullptr;
219  p_out_stream = nullptr;
220  p_print = nullptr;
221  p_stream = nullptr;
222  p_ai_source = nullptr;
223  p_ai_input = nullptr;
224  is_ok = false;
225  is_active = true;
226  }
227 
229  void setAudioInfo(AudioInfo newInfo) override {
230  this->info = newInfo;
231  if (has_input && p_ai_input != nullptr) {
232  p_ai_input->setAudioInfo(info);
233  } else if (has_output) {
234  components[0]->setAudioInfo(info);
235  }
236  }
237 
239  AudioInfo audioInfoOut() override {
240  AudioInfo info = audioInfo();
241  if (size() > 0) {
242  info = last().audioInfoOut();
243  }
244  return info;
245  }
246 
248  bool hasComponents() { return size() > 0; }
249 
251  int size() { return components.size(); }
252 
254  ModifyingStream& last() { return *components[size() - 1]; }
255 
257  ModifyingStream& operator[](int idx) { return *components[idx]; }
258 
261  if (size() > 0) last().addNotifyAudioChange(bi);
262  }
263 
265  void setNotifyActive(bool flag) {
266  is_notify_active = flag;
267  for (auto c : components) {
268  c->setNotifyActive(flag);
269  }
270  }
271 
273  void setActive(bool flag){
274  is_active = flag;
275  }
276 
278  bool isActive(){
279  return is_active;
280  }
281 
283  bool isOK(){
284  return is_ok;
285  }
286 
288  operator bool() { return is_ok && is_active; }
289 
290  protected:
291  Vector<ModifyingStream*> components{0};
292  Vector<ModifyingStream*> cleanup{0};
293  bool has_output = false;
294  bool has_input = false;
295  bool is_ok = true;
296  bool is_active = true;
297  // prior input for input pipline
298  Stream* p_stream = nullptr;
299  AudioInfoSource* p_ai_source = nullptr;
300  AudioStream* p_ai_input = nullptr;
301  // output for notifications, begin and end calls
302  AudioOutput* p_out_print = nullptr;
303  AudioStream* p_out_stream = nullptr;
304  Print* p_print = nullptr;
305 
308  ModifyingStreamAdapter(ModifyingOutput& out) { p_out = &out; }
310  void setStream(Stream& in) override { p_out->setOutput(in); }
312  void setOutput(Print& out) override { p_out->setOutput(out); }
314  int available() override { return 0; }
315 
316  size_t write(const uint8_t* data, size_t len) override {
317  return p_out->write(data, len);
318  }
319 
320  bool begin() override { return p_out->begin(); }
321 
322  void end() override { p_out->end(); }
323 
324  void setAudioInfo(AudioInfo info) override { p_out->setAudioInfo(info); }
325 
327  p_out->addNotifyAudioChange(bi);
328  }
329 
330  protected:
331  ModifyingOutput* p_out = nullptr;
332  };
333 
337  Stream* in = p_stream;
338  if (size() > 0) {
339  in = &last();
340  }
341  return in;
342  }
343 };
344 
345 } // namespace audio_tools
virtual void addNotifyAudioChange(AudioInfoSupport &bi)
Adds target to be notified about audio changes.
Definition: AudioTypes.h:158
Supports changes to the sampling rate, bits and channels.
Definition: AudioTypes.h:136
virtual AudioInfo audioInfoOut()
provides the actual output AudioInfo: this is usually the same as audioInfo() unless we use a transfo...
Definition: AudioTypes.h:143
Abstract Audio Ouptut class.
Definition: AudioOutput.h:22
virtual void setAudioInfo(AudioInfo newInfo) override
Defines the input AudioInfo.
Definition: AudioOutput.h:46
Base class for all Audio Streams. It support the boolean operator to test if the object is ready with...
Definition: AudioStreams.h:24
virtual void setAudioInfo(AudioInfo newInfo) override
Defines the input AudioInfo.
Definition: AudioStreams.h:32
virtual AudioInfo audioInfo() override
provides the actual input AudioInfo
Definition: AudioStreams.h:55
Abstract class: Objects can be put into a pipleline.
Definition: AudioOutput.h:96
virtual void setOutput(Print &out)=0
Defines/Changes the output target.
Abstract class: Objects can be put into a pipleline.
Definition: AudioStreams.h:136
virtual void setStream(Stream &in)=0
Defines/Changes the input & output.
virtual void setOutput(Print &out)=0
Defines/Changes the output target.
Replicates the output to multiple destinations.
Definition: AudioIO.h:288
We can build a input or an output chain: an input chain starts with setInput(); followed by add() an ...
Definition: Pipeline.h:16
ModifyingStream & operator[](int idx)
Access to the components by index.
Definition: Pipeline.h:257
bool setOutput(AudioStream &out)
Defines the output for an output pipeline: must be last call after add()
Definition: Pipeline.h:84
bool isOK()
Returns true if pipeline is correctly set up.
Definition: Pipeline.h:283
void addNotifyAudioChange(AudioInfoSupport &bi) override
Subscribes to notifications on last component of the chain.
Definition: Pipeline.h:260
void setAudioInfo(AudioInfo newInfo) override
Defines the AudioInfo for the first node.
Definition: Pipeline.h:229
Stream * getInput()
Definition: Pipeline.h:336
bool hasComponents()
Returns true if we have at least 1 component.
Definition: Pipeline.h:248
ModifyingStream & last()
Provides the last component.
Definition: Pipeline.h:254
void end() override
Calls end on all components.
Definition: Pipeline.h:206
bool setOutput(AudioOutput &out)
Defines the output for an output pipeline: must be last call after add()
Definition: Pipeline.h:75
bool setOutput(Print &out)
Defines the output for an output pipeline: must be last call after add()
Definition: Pipeline.h:93
bool setInput(AudioStream &in)
Defines the input for an input pipeline: must be first call before add()
Definition: Pipeline.h:109
void setNotifyActive(bool flag)
Activates/deactivates notifications.
Definition: Pipeline.h:265
bool setInput(Stream &in)
Defines the input for an input pipeline: must be first call before add()
Definition: Pipeline.h:116
bool add(ModifyingStream &io)
adds a component
Definition: Pipeline.h:22
bool isActive()
Determines if the pipeline is active.
Definition: Pipeline.h:278
bool add(ModifyingOutput &out)
adds a component
Definition: Pipeline.h:58
AudioInfo audioInfoOut() override
Provides the resulting AudioInfo from the last node.
Definition: Pipeline.h:239
void setActive(bool flag)
Activates/deactivates the pipeline (default is active)
Definition: Pipeline.h:273
bool begin() override
Optional method: Calls begin on all components.
Definition: Pipeline.h:177
bool begin(AudioInfo info)
Definition: Pipeline.h:168
int size()
Provides the number of components.
Definition: Pipeline.h:251
Definition: NoArduino.h:58
Definition: NoArduino.h:125
Vector implementation which provides the most important methods as defined by std::vector....
Definition: Vector.h:21
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition: AnalogAudio.h:10
Basic Audio information which drives e.g. I2S.
Definition: AudioTypes.h:50
Support for ModifyingOutput.
Definition: Pipeline.h:307
void setOutput(Print &out) override
Defines/Changes the output target.
Definition: Pipeline.h:312
void addNotifyAudioChange(AudioInfoSupport &bi) override
Adds target to be notified about audio changes.
Definition: Pipeline.h:326
int available() override
Read not supported.
Definition: Pipeline.h:314
void setAudioInfo(AudioInfo info) override
Defines the input AudioInfo.
Definition: Pipeline.h:324
void setStream(Stream &in) override
Defines/Changes the input & output.
Definition: Pipeline.h:310