-
- Notifications
You must be signed in to change notification settings - Fork 309
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(); }