arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Modules Pages
AnalogAudioArduino.h
1#pragma once
2
3#include <limits.h> // for INT_MIN and INT_MAX
4
5#include "AnalogConfigStd.h"
6#include "AudioTools/CoreAudio/AudioAnalog/AnalogDriverBase.h"
7#include "AudioTools/CoreAudio/AudioTimer/AudioTimer.h"
8#include "AudioTools/CoreAudio/AudioStreams.h"
9#include "AudioTools/CoreAudio/Buffers.h"
10
11namespace audio_tools {
12
22 public:
23 AnalogAudioArduino() = default;
24
30
31 void setAudioInfo(AudioInfo info) override {
32 TRACEI();
33 if (config.sample_rate != info.sample_rate ||
34 config.channels != info.channels ||
35 config.bits_per_sample != info.bits_per_sample) {
36 config.sample_rate = info.sample_rate;
37 config.bits_per_sample = info.bits_per_sample;
38 config.channels = info.channels;
39 config.logInfo();
40 setupTimer();
41 }
42 }
43
45 bool begin() override { return begin(config); }
46
47 bool begin(AnalogConfigStd cfg) {
48 TRACED();
49
50 config = cfg;
51 if (config.rx_tx_mode == RXTX_MODE) {
52 LOGE("RXTX not supported");
53 return false;
54 }
55
56 frame_size = config.channels * (config.bits_per_sample / 8);
57 result_factor = 1;
58
59 if (!setupPins()) return false;
60
61 if (!setupTx()) return false;
62
63 if (!setupBuffer()) return false;
64
65 // (re)start timer
66 return setupTimer();
67 }
68
69 void end() override { timer.end(); }
70
71 int available() override {
72 if (config.rx_tx_mode == TX_MODE) return 0;
73 return buffer == nullptr ? 0 : buffer->available() * 2;
74 };
75
77 size_t readBytes(uint8_t *data, size_t len) override {
78 if (config.rx_tx_mode == TX_MODE) return 0;
79 if (buffer == nullptr) return 0;
80 int bytes = len / frame_size * frame_size;
81 return buffer->readArray(data, bytes);
82 }
83
84 int availableForWrite() override {
85 if (config.rx_tx_mode == RX_MODE) return 0;
86 if (buffer == nullptr) return 0;
87 return config.is_blocking_write ? config.buffer_size
88 : buffer->availableForWrite();
89 }
90
91 size_t write(const uint8_t *data, size_t len) override {
92 LOGD("write: %d", (int)len);
93 if (config.rx_tx_mode == RX_MODE) return 0;
94 // only process full frames
95 len = len / frame_size * frame_size;
96
97 if (isCombinedChannel()) {
98 ChannelReducer cr(1, 2, config.bits_per_sample);
99 len = cr.convert((uint8_t *)data, len);
100 LOGD("ChannelReducer len: %d", (int)len);
101 }
102
103 if (isDecimateActive()) {
104 Decimate dec(decim, 1, config.bits_per_sample);
105 len = dec.convert((uint8_t *)data, len);
106 LOGD("Decimate len: %d for factor %d", (int)len, decim);
107 }
108
109 // blocking write ?
110 if (config.is_blocking_write) {
111 LOGD("Waiting for buffer to be available");
112 while (buffer->availableForWrite() < len) {
113 delay(10);
114 }
115 }
116
117 size_t result = 0;;
118 switch(config.bits_per_sample){
119 case 8: {
120 result = buffer->writeArray(data, len);
121 } break;
122 case 16: {
123 size_t samples = len / 2;
124 int16_t *p16 = (int16_t*)data;
125 for (int j=0;j<samples;j++){
126 uint8_t sample = map(p16[j],-32768, 32767,0,255);
127 if (buffer->write(sample)){
128 result += 2;
129 } else {
130 break;
131 }
132 }
133 } break;
134 case 24: {
135 size_t samples = len / 3;
136 int24_t *p24 = (int24_t*)data;
137 for (int j=0;j<samples;j++){
138 uint8_t sample = map(p24[j],-8388608, 8388607,0,255);
139 if (buffer->write(sample)){
140 result += 3;
141 } else {
142 break;
143 }
144 }
145
146 } break;
147 case 32: {
148 size_t samples = len / 4;
149 int32_t *p32 = (int32_t*)data;
150 for (int j=0;j<samples;j++){
151 uint8_t sample = map(p32[j],-2147483648, 2147483647,0,255);
152 if (buffer->write(sample)){
153 result += 4;
154 } else {
155 break;
156 }
157 }
158
159 } break;
160 }
161
162 // write data
163 return result * result_factor;
164 }
165
166 protected:
167 AnalogConfigStd config;
168 TimerAlarmRepeating timer;
169 BaseBuffer<uint8_t> *buffer = nullptr;
170 int avg_value, min, max, count;
171 bool is_combined_channels = false;
172 uint16_t frame_size = 0;
173 int result_factor = 1;
174 int decim = 1;
175
176
177 bool setupTx() {
178 if (config.rx_tx_mode == TX_MODE) {
179 // check channels
180 if (config.channels > ANALOG_MAX_OUT_CHANNELS) {
181 if (config.channels == 2) {
182 is_combined_channels = true;
183 config.channels = 1;
184 } else {
185 LOGE("Unsupported channels");
186 return false;
187 }
188 }
189 if (isDecimateActive()) {
190 LOGI("Using reduced sample rate: %d", effectiveOutputSampleRate());
191 decim = decimation();
192 result_factor = result_factor * decim;
193 }
194 if (isCombinedChannel()) {
195 LOGI("Combining channels");
196 result_factor = result_factor * 2;
197 }
198 }
199 return true;
200 }
201
202 bool setupBuffer() {
203 if (buffer == nullptr) {
204 // allocate buffer_count
205 buffer = new RingBuffer<uint8_t>(config.buffer_size * config.buffer_count);
206 if (buffer == nullptr) {
207 LOGE("Not enough memory for buffer");
208 return false;
209 }
210 }
211 return true;
212 }
213
214 bool setupTimer() {
215 int sample_rate = config.rx_tx_mode == TX_MODE ? effectiveOutputSampleRate()
216 : config.sample_rate;
217 LOGI("sample_rate: %d", sample_rate);
218 timer.setCallbackParameter(this);
219 return timer.begin(callback, sample_rate, TimeUnit::HZ);
220 }
221
223 static void callback(void *arg) {
224 int16_t value = 0;
226 // prevent NPE
227 if (self->buffer == nullptr) return;
228
229 // Logic for reading audio data
230 if (self->config.rx_tx_mode == RX_MODE) {
231 int channels = self->config.channels;
232 for (int j = 0; j < channels; j++) {
233 // provides value in range 0…4095
234 value = analogRead(self->config.pins_data[j]);
235 if (self->config.is_auto_center_read) {
236 self->updateMinMax(value);
237 }
238 value = (value - self->avg_value) * 16;
239 self->buffer->write(value);
240 }
241 // Logic for writing audio data
242 } else if (self->config.rx_tx_mode == TX_MODE) {
243 int channels = self->config.channels;
244 for (int j = 0; j < channels; j++) {
245 int16_t sample = self->buffer->read();
246 int pin = self->config.pins_data[j];
247 analogWrite(pin, sample);
248 //LOGW("analogWrite(%d, %d)", pin, sample);
249 }
250 }
251 }
252
254 bool setupPins() {
255 TRACED();
256
257 Pins& pins = config.pins();
258 if (pins.size()<config.channels){
259 LOGE("Only pins %d of %d defined", pins.size(), config.channels);
260 return false;
261 }
262
263
264 if (config.rx_tx_mode == RX_MODE) {
265 LOGI("rx start_pin: %d", config.start_pin);
266 // setup pins for read
267 for (int j = 0; j < config.channels; j++) {
268 int pin = config.pins_data [j];
269 pinMode(pin, INPUT);
270 LOGD("pinMode(%d, INPUT)", pin);
271 }
272
273 if (config.is_auto_center_read) {
274 // calculate the avarage value to center the signal
275 for (int j = 0; j < 1024; j++) {
276 updateMinMax(analogRead(config.pins_data[0]));
277 }
278 LOGI("Avg Signal was %d", avg_value);
279 }
280 } else if (config.rx_tx_mode == TX_MODE) {
281 // setup pins for read
282 for (int j = 0; j < config.channels; j++) {
283 int pin = config.pins_data[j];
284 LOGI("tx pin %d: %d", j, pin);
285 pinMode(pin, OUTPUT);
286 LOGD("pinMode(%d, OUTPUT)", pin);
287 }
288 }
289 return true;
290 }
291
292 void updateMinMax(int value) {
293 if (value < min) min = value;
294 if (value > max) max = value;
295 if (count++ == 1024) updateAvg();
296 }
297
298 void updateAvg() {
299 avg_value = (max + min) / 2;
300 min = INT_MAX;
301 max = INT_MIN;
302 count = 0;
303 }
304
308 return config.sample_rate >= config.max_sample_rate;
309 }
310
311 // combined stereo channel to mono
312 bool isCombinedChannel() { return is_combined_channels; }
313
315 int effectiveOutputSampleRate() { return config.sample_rate / decimation(); }
316
317 int decimation() {
318 if (config.sample_rate <= config.max_sample_rate) return 1;
319 for (int j = 2; j < 6; j += 2) {
320 if (config.sample_rate / j <= config.max_sample_rate) {
321 return j;
322 }
323 }
324 return 6;
325 }
326};
327
328} // namespace audio_tools
Analog Data IO using a timer and the Arduino analogRead() method and writing using analogWrite();.
Definition AnalogAudioArduino.h:21
static void callback(void *arg)
Sample data and write to buffer.
Definition AnalogAudioArduino.h:223
bool isDecimateActive()
Definition AnalogAudioArduino.h:307
int effectiveOutputSampleRate()
Returns the effective output sample rate.
Definition AnalogAudioArduino.h:315
size_t readBytes(uint8_t *data, size_t len) override
Provides the sampled audio data.
Definition AnalogAudioArduino.h:77
bool setupPins()
pinmode input for defined analog pins
Definition AnalogAudioArduino.h:254
AnalogConfigStd defaultConfig()
provides the default configuration
Definition AnalogAudioArduino.h:26
bool begin() override
Reopen with last config.
Definition AnalogAudioArduino.h:45
void setAudioInfo(AudioInfo info) override
Defines the input AudioInfo.
Definition AnalogAudioArduino.h:31
Generic ADC and DAC configuration.
Definition AnalogConfigStd.h:31
Base class for all Audio Streams. It support the boolean operator to test if the object is ready with...
Definition BaseStream.h:115
virtual int readArray(T data[], int len)
reads multiple values
Definition Buffers.h:41
virtual int writeArray(const T data[], int len)
Fills the buffer data.
Definition Buffers.h:65
virtual T read()=0
reads a single value
virtual int availableForWrite()=0
provides the number of entries that are available to write
virtual bool write(T data)=0
write add an entry to the buffer
virtual int available()=0
provides the number of entries that are available to read
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 AudioConfig.h:885
long map(long x, long in_min, long in_max, long out_min, long out_max)
Maps input to output values.
Definition NoArduino.h:186
Basic Audio information which drives e.g. I2S.
Definition AudioTypes.h:52
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition AudioTypes.h:55
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition AudioTypes.h:57
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition AudioTypes.h:59