2 #include "AudioConfig.h"
3 #include "AudioTools/AudioTypes.h"
4 #include "AudioTools/BaseConverter.h"
5 #include "AudioTools/Buffers.h"
9 #if !defined(ARDUINO) || defined(IS_DESKTOP)
10 #define FLUSH_OVERRIDE override
12 #define FLUSH_OVERRIDE
26 virtual size_t write(
const uint8_t *buffer,
size_t size)
override = 0;
28 virtual size_t write(uint8_t ch)
override {
35 virtual int availableForWrite()
override {
return DEFAULT_BUFFER_SIZE; }
39 virtual void flush() FLUSH_OVERRIDE {
53 if (out) notifyAudioChange(out);
65 for (
int j = 0; j < len / 2; j++) {
66 write((uint8_t *)&zero, 2);
75 virtual bool begin() {
79 virtual void end() { is_active =
false; }
80 operator bool() {
return is_active; }
85 SingleBuffer<uint8_t> tmp{MAX_SINGLE_CHARS};
86 bool is_active =
false;
114 CsvOutput(
int buffer_size = DEFAULT_BUFFER_SIZE,
bool active =
true) {
115 this->is_active = active;
120 bool active =
true) {
121 this->out_ptr = &out;
122 this->is_active = active;
155 this->is_active =
true;
165 this->is_active =
true;
171 virtual size_t write(
const uint8_t *data,
size_t len)
override {
172 LOGD(
"CsvOutput::write: %d", (
int)len);
174 LOGE(
"is not active");
179 LOGW(
"Channels not defined: using 2");
182 size_t lenChannels = len / (
sizeof(T) * cfg.
channels);
183 if (lenChannels > 0) {
184 writeFrames((T *)data, lenChannels);
185 }
else if (len ==
sizeof(T)) {
187 T *data_value = (T *)data;
188 out_ptr->print(data_value[0]);
194 out_ptr->print(delimiter_str);
197 LOGE(
"Unsupported size: %d for channels %d and bits: %d", (
int)len,
204 int availableForWrite()
override {
return 1024; }
208 Print *out_ptr = &Serial;
210 const char *delimiter_str =
",";
212 void writeFrames(T *data_ptr,
int frameCount) {
213 for (
size_t j = 0; j < frameCount; j++) {
214 for (
int ch = 0; ch < cfg.
channels; ch++) {
215 if (out_ptr !=
nullptr && data_ptr !=
nullptr) {
216 int value = *data_ptr;
217 out_ptr->print(value);
221 this->out_ptr->print(delimiter_str);
223 this->out_ptr->println();
229 template <
typename T>
using CsvStream = CsvOutput<T>;
239 HexDumpOutput(
int buffer_size = DEFAULT_BUFFER_SIZE,
bool active =
true) {
240 this->is_active = active;
245 bool active =
true) {
246 this->out_ptr = &out;
247 this->is_active = active;
250 bool begin()
override {
252 this->is_active =
true;
257 void flush()
override {
262 virtual size_t write(
const uint8_t *data,
size_t len)
override {
266 for (
size_t j = 0; j < len; j++) {
267 out_ptr->print(data[j], HEX);
271 out_ptr->print(
" - ");
282 AudioInfo defaultConfig(
RxTxMode mode = TX_MODE) {
288 Print *out_ptr = &Serial;
293 using HexDumpStream = HexDumpOutput;
302 template <
typename T>
308 setOutput(finalOutput);
309 setOutputCount(outputStreamCount);
312 void setOutput(
Print &finalOutput) { p_final_output = &finalOutput; }
314 void setOutputCount(
int count) {
315 output_count = count;
316 buffers.resize(count);
317 for (
int i = 0; i < count; i++) {
318 buffers[i] =
nullptr;
320 weights.resize(count);
321 for (
int i = 0; i < count; i++) {
325 update_total_weights();
331 if (channel <
size()) {
332 weights[channel] = weight;
334 LOGE(
"Invalid channel %d - max is %d", channel,
size() - 1);
336 update_total_weights();
340 bool begin(
int copy_buffer_size_bytes = DEFAULT_BUFFER_SIZE,
343 size_bytes = copy_buffer_size_bytes;
345 memory_type = memoryType;
346 allocate_buffers(size_bytes);
359 int size() {
return output_count; }
361 size_t write(uint8_t)
override {
return 0; }
365 size_t write(
const uint8_t *buffer_c,
size_t bytes)
override {
366 size_t result = write(stream_idx, buffer_c, bytes);
369 if (stream_idx >= output_count) {
376 size_t write(
int idx,
const uint8_t *buffer_c,
size_t bytes) {
377 LOGD(
"write idx %d: %d", stream_idx, bytes);
379 RingBuffer<T> *p_buffer = idx < output_count ? buffers[idx] :
nullptr;
380 assert(p_buffer !=
nullptr);
381 size_t samples = bytes /
sizeof(T);
383 LOGW(
"Available Buffer too small %d: requested: %d -> increase the "
387 result = p_buffer->
writeArray((T *)buffer_c, samples) *
sizeof(T);
400 if (p_buffer ==
nullptr)
411 size_t samples = size_bytes /
sizeof(T);
412 for (
int j = 0; j < output_count; j++) {
413 samples = MIN(samples, (
size_t)buffers[j]->available());
419 output.resize(samples);
420 memset(output.data(), 0, samples *
sizeof(T));
421 for (
int j = 0; j < output_count; j++) {
422 float weight = weights[j];
424 for (
int i = 0; i < samples; i++) {
425 output[i] += weight * buffers[j]->read() / total_weights;
430 LOGD(
"write to final out: %d", samples *
sizeof(T));
431 p_final_output->write((uint8_t *)output.data(), samples *
sizeof(T));
439 if (
size != size_bytes) {
440 allocate_buffers(
size);
448 Vector<float> weights{0};
449 Print *p_final_output =
nullptr;
450 float total_weights = 0.0;
451 bool is_active =
false;
456 void *p_memory =
nullptr;
458 void update_total_weights() {
460 for (
int j = 0; j < weights.size(); j++) {
461 total_weights += weights[j];
465 void allocate_buffers(
int size) {
467 for (
int j = 0; j < output_count; j++) {
468 if (buffers[j] !=
nullptr) {
471 #if defined(ESP32) && defined(ARDUINO)
472 if (memory_type == PS_RAM && ESP.getFreePsram() >=
size) {
473 p_memory = ps_malloc(
size);
474 LOGI(
"Buffer %d allocated %d bytes in PS_RAM", j,
size);
476 p_memory = malloc(
size);
477 LOGI(
"Buffer %d allocated %d bytes in RAM", j,
size);
479 if (p_memory !=
nullptr) {
480 buffers[j] =
new (p_memory) RingBuffer<T>(
size /
sizeof(T));
482 LOGE(
"Not enough memory to allocate %d bytes",
size);
485 buffers[j] =
new RingBuffer<T>(
size /
sizeof(T));
490 void free_buffers() {
492 for (
int j = 0; j < output_count; j++) {
493 if (buffers[j] !=
nullptr) {
496 if (p_memory !=
nullptr) {
500 buffers[j] =
nullptr;
523 size_t write(
const uint8_t *buffer,
size_t size) {
527 updateVolumes<int16_t>(buffer, size);
530 updateVolumes<int24_t>(buffer, size);
533 updateVolumes<int32_t>(buffer, size);
549 if (volumes.size() == 0) {
550 LOGE(
"begin not called!");
553 if (channel >= volumes.size()) {
554 LOGE(
"invalid channel %d", channel);
557 return volumes[channel];
563 for (
int j = 0; j < info.
channels; j++) {
570 float f_volume_tmp = 0;
573 Vector<float> volumes_tmp{0};
575 template <
typename T>
void updateVolumes(
const uint8_t *buffer,
size_t size) {
576 T *bufferT = (T *)buffer;
577 int samplesCount = size /
sizeof(T);
578 for (
int j = 0; j < samplesCount; j++) {
579 float tmp = abs(
static_cast<float>(bufferT[j]));
580 updateVolume(tmp, j);
585 void updateVolume(
float tmp,
int j) {
586 if (tmp > f_volume_tmp) {
589 if (volumes_tmp.size() > 0 && info.
channels > 0) {
591 if (tmp > volumes_tmp[ch]) {
592 volumes_tmp[ch] = tmp;
598 f_volume = f_volume_tmp;
599 for (
int j = 0; j < info.
channels; j++) {
600 volumes[j] = volumes_tmp[j];
606 using VolumePrint = VolumeOutput;
619 if (p_next ==
nullptr) {
620 LOGE(
"start must not be null");
631 size_t write(
const uint8_t *buffer,
size_t len)
override {
632 if (p_next ==
nullptr)
634 if (pos + len <= max_size) {
635 memcpy(p_next, buffer, len);
640 LOGE(
"Buffer too small: pos:%d, size: %d ", pos, (
int)max_size);
645 int availableForWrite()
override {
return max_size - pos; }
647 int size() {
return max_size; }
651 uint8_t *p_start =
nullptr;
652 uint8_t *p_next =
nullptr;
677 def.channel = channel;
679 out_channels.push_back(def);
682 size_t write(
const uint8_t *buffer,
size_t size)
override {
685 return writeT<int16_t>(buffer, size);
687 return writeT<int24_t>(buffer, size);
689 return writeT<int32_t>(buffer, size);
697 Print *p_out =
nullptr;
702 template <
typename T>
703 size_t writeT(
const uint8_t *buffer,
size_t size) {
704 int sample_count = size /
sizeof(T);
705 int result_size = sample_count / cfg.
channels;
706 T *data = (T *)buffer;
707 T result[result_size];
709 for (
int ch = 0; ch < out_channels.size(); ch++) {
713 for (
int j = def.channel; j < sample_count; j += cfg.
channels) {
714 result[i++] = data[j];
718 def.p_out->write((uint8_t *)result, result_size *
sizeof(T));
719 if (written != result_size *
sizeof(T)) {
720 LOGW(
"Could not write all samples");
MemoryType
Memory types.
Definition: AudioTypes.h:33
RxTxMode
The Microcontroller is the Audio Source (TX_MODE) or Audio Sink (RX_MODE). RXTX_MODE is Source and Si...
Definition: AudioTypes.h:26