Skip to content

Writing your Custom Input&Output Class

Phil Schatzmann edited this page Oct 5, 2024 · 13 revisions

To implement your custom input or output class you can create a subclass of AudioStream and implement the following methods:

  • begin() - add your logic to start the processing
  • end() - add your logic to end the processing
  • setAudioInfo() - optional: handle changes to the sample rate, channels or bits per sample.

Output:

  • availableForWrite() - report the bytes that we can write
  • write() - writes an array of audio data.

Input:

  • available() - return the bytes that are available to read
  • readBytes() - read the bytes

Here is a simple example for an environment where the input and output is automatically handled via a callback method. We just write the data to a buffer and let the callback handle the data from the buffer.

#pragma once; #include "AudioTools.h" // import all core functionality //#include "AudioTools/CoreAudio/AudioStreams.h" // only import AudioStream namespace audio_tools { /**  * @brief Custom Stream   */ class CustomStream : public AudioStream { public: CustomStream() { self = this; }; /// Starts the processing bool begin() { TRACEI(); // add your start logic: e.g. start callbacks return true; } /// Stops the processing and releases the memory void end() { TRACEI(); // add your stop logic } void setAudioInfo(AudioInfo info) override { TRACED(); AudioStream::setAudioInfo(info); // add your custom logic for changing the sample rate, channels or bits_per_sample } /// Limit amount of data to be written int availableForWrite() { return 1024; } /// Write audio data to buffer size_t write(const uint8_t *buffer, size_t size) override { // write to buffer or use your custom logic return write_buffer.writeArray(buffer, size); } /// amount of data available int available() { return read_buffer.available(); } /// Read from audio data to buffer size_t readBytes(uint8_t *buffer, size_t size) override { // write to buffer or use your custom logic size_t result = read_buffer.readArray(buffer, size); return result; } protected: // output buffer NBuffer<uint8_t> write_buffer{1024, 3}; NBuffer<uint8_t> read_buffer{1024, 3}; static CustomStream* self; // sometimes your IO needs to be handled via a callback static void AudioCallback(uint8_t *in, uint8_t *out, size_t size) { // get data from write buffer to fill out self->write_buffer.readArray(out, size); // fill read_buffer from in self->read_buffer.writeArray(in, size); } }; CustomStream *CustomStream::self = nullptr; } // namespace audio_tools

After this you can test it e.g. with the following sketch:

#include "AudioTools.h" AudioInfo info(44100, 2, 16); SineWaveGenerator<int16_t> sineWave(32000); // subclass of SoundGenerator with max amplitude of 32000 GeneratedSoundStream<int16_t> sound(sineWave); // Stream generated from sine wave CustomStream out; StreamCopy copier(out, sound); // copies sound into i2s // Arduino Setup void setup(void) { // Open Serial  Serial.begin(115200); AudioLogger::instance().begin(Serial, AudioLogger::Info); out.begin(info); sound.begin(info); // Setup sine wave sineWave.begin(info, N_B4); } // Arduino loop - copy sound to out  void loop() { copier.copy(); }
Clone this wiki locally