Skip to content

Pipelines

Phil Schatzmann edited this page Apr 19, 2024 · 24 revisions

Currently it is already possible in the Arduino AudioTools Library to define some processing chains: Audio Objects are connected to other objects e.g. by adding the dependent object as parameter in the constructor.

I2SStream i2s
VolumeStream vol(i2s);

Since the very beginning of the library, I planned to have some Pipeline class that would help to define such chains in a more intuitive way. I finally committed this functionality to the Github:

Output Pipelines

An output pipeline acts as an audio sink, so you can write data to it. All pipeline processing components are added with the help of the add() method, finally we define the final output with setOutput().

Calling begin() calls the begin method on all pipeline components which will start them with the default values. Instead of calling begin you can however still start the components individually, the regular way.

Any subclass of ModifyingStream can be used as pipleline component.

Pipeline pipeline;
I2SStream i2s;
VolumeStream volume;

pipeline.add(volume);
pipleine.setOutput(i2s);
pipeline.begin();

Example

Here is a full working example of an internet streaming application, that provides a volume control and outputs the data with 32 bits:

#include "AudioTools.h"
#include "AudioCodecs/CodecMP3Helix.h"

URLStream url("ssid","password");  
Pipeline pipeline;
MP3DecoderHelix helix;
EncodedAudioStream dec(&helix); 
VolumeStream volume;
NumberFormatConverterStream bits;
I2SStream i2s;
StreamCopy copier(pipeline, url);

void setup(){
  Serial.begin(115200);
  AudioLogger::instance().begin(Serial, AudioLogger::Warning);  
  // mp3 radio
  url.begin("http://stream.srg-ssr.ch/m/rsj/mp3_128","audio/mp3");

  // predefine define some values
  volume.setVolume(0.5);
  bits.setToBits(32);

  // setup pipeline
  pipeline.add(dec);
  pipeline.add(volume);
  pipeline.add(bits);
  pipeline.setOutput(i2s);
  // start all components with their default values
  pipeline.begin();
}

void loop(){
  copier.copy();
}

We can just copy the mp3 data into the pipeline!

Input Pipelines

In input pipeline is an audio source, so you can read data from it. All pipeline processing components are added with the help of the add() method and we start the chain by defining the input with setInput(). Calling begin() calls the begin method on all pipeline components. Any subclass of ModifyingStream can be used a pipeline component.

Pipeline pipeline;
I2SStream i2s;
VolumeStream volume;

pipleine.setInput(i2s);
pipeline.add(volume);
pipeline.begin();

Example

Here is a full working example of an internet streaming application, that provides a volume control and outputs the data with 32 bits:

#include "AudioTools.h"
#include "AudioCodecs/CodecMP3Helix.h"
#include "AudioLibs/AudioBoardStream.h"

URLStream url("ssid","password");  
Pipeline pipeline;
MP3DecoderHelix helix;
EncodedAudioStream dec(&helix); 
VolumeStream volume;
NumberFormatConverterStream bits;
AudioBoardStream i2s(AudioKitEs8388V1);
StreamCopy copier(i2s, pipeline);

void setup(){
  Serial.begin(115200);
  AudioLogger::instance().begin(Serial, AudioLogger::Warning);  

  // start i2s
  i2s.begin();

  // mp3 radio
  url.begin("http://stream.srg-ssr.ch/m/rsj/mp3_128","audio/mp3");

  // predefine define some values
  volume.setVolume(0.5);
  bits.setToBits(32);

  // setup pipeline
  pipeline.setInput(url);
  pipeline.add(dec);
  pipeline.add(volume);
  pipeline.add(bits);
  pipeline.addNotifyAudioChange(i2s);
  // start all components with their default values
  pipeline.begin();
}

void loop(){
  copier.copy();
}

We just copy the pipeline to the i2s output. However we need to start i2s separately because this is not part of the pipeline and thus we also need to make sure that i2s is informed about format changes: we can do this like in the example above using addNotifyAudioChange() or we can activate the format change handling in the copier with copier.setSynchAudioInfo(true).