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