arduino-audio-tools
AudioTypes.h
1 #pragma once
2 
3 #include "AudioConfig.h"
4 #ifdef USE_TYPETRAITS
5 # include <type_traits>
6 # include <limits>
7 #endif
8 
9 #include "AudioTools/CoreAudio/AudioLogger.h"
10 #include "AudioTools/CoreAudio/AudioBasic/Collections/Vector.h"
11 
12 // fix compile error for ESP32 C3
13 #undef HZ
14 
15 // MIN
16 #undef MIN
17 #define MIN(A, B) ((A) < (B) ? (A) : (B))
18 
19 
20 namespace audio_tools {
21 
22 using sample_rate_t = uint32_t;
23 
28 enum RxTxMode {UNDEFINED_MODE=0, TX_MODE=1, RX_MODE=2, RXTX_MODE=3 };
29 
35 enum MemoryType {RAM, PS_RAM, FLASH_RAM};
36 
40 static const char* RxTxModeNames[4]={"UNDEFINED_MODE","TX_MODE","RX_MODE","RXTX_MODE" };
45 enum TimeUnit {MS, US, HZ};
46 static const char* TimeUnitStr[3] {"MS","US","HZ"};
47 
52 struct AudioInfo {
53 
55  sample_rate_t sample_rate = DEFAULT_SAMPLE_RATE;
57  uint16_t channels = DEFAULT_CHANNELS;
59  uint8_t bits_per_sample = DEFAULT_BITS_PER_SAMPLE;
60 
62  AudioInfo() = default;
63 
65  AudioInfo(sample_rate_t sampleRate, uint16_t channelCount, uint8_t bitsPerSample) {
66  sample_rate = sampleRate;
67  channels = channelCount;
68  bits_per_sample = bitsPerSample;
69  };
70 
72  AudioInfo(const AudioInfo &) = default;
73 
75  bool operator==(AudioInfo alt){
77  }
78 
80  bool operator!=(AudioInfo alt){
81  return !(*this == alt);
82  }
83 
85  bool equals(AudioInfo alt){
86  return *this == alt;
87  }
88 
91  return channels == alt.channels && bits_per_sample == alt.bits_per_sample;
92  }
93 
95  void set(AudioInfo info) {
96  sample_rate = info.sample_rate;
97  channels = info.channels;
99  }
100 
102  void setAudioInfo(AudioInfo info) {
103  set(info);
104  }
105 
107  void copyFrom(AudioInfo info){
108  setAudioInfo(info);
109  }
110 
111 #ifndef SWIG
114  setAudioInfo(info);
115  return *this;
116  }
117 #endif
119  operator bool() {
120  return sample_rate > 0 && channels > 0 && bits_per_sample > 0;
121  }
122 
123  virtual void clear(){
124  sample_rate = 0;
125  channels = 0;
126  bits_per_sample = 0;
127  }
128 
129  virtual void logInfo(const char* source="") {
130  LOGI("%s sample_rate: %d / channels: %d / bits_per_sample: %d",source, (int) sample_rate, (int)channels, (int)bits_per_sample);
131  }
132 
133 };
134 
140  public:
142  virtual void setAudioInfo(AudioInfo info) = 0;
144  virtual AudioInfo audioInfo() = 0;
146  virtual AudioInfo audioInfoOut() { return audioInfo();}
147 };
148 // Support legacy name
149 #if USE_OBSOLETE
150 using AudioBaseInfo = AudioInfo;
151 using AudioBaseInfoDependent = AudioInfoSupport;
152 using AudioInfoDependent = AudioInfoSupport;
153 #endif
154 
160  public:
163  if (!notify_vector.contains(&bi)) notify_vector.push_back(&bi);
164  }
165 
168  int pos = notify_vector.indexOf(&bi);
169  if (pos<0) return false;
170  notify_vector.erase(pos);
171  return true;
172  }
173 
175  virtual void clearNotifyAudioChange() {
176  notify_vector.clear();
177  }
178 
180  void setNotifyActive(bool flag){
181  is_notify_active = flag;
182  }
183 
186  return is_notify_active;
187  }
188 
189  protected:
190  Vector<AudioInfoSupport*> notify_vector;
191  bool is_notify_active = true;
192 
193  void notifyAudioChange(AudioInfo info){
194  if (isNotifyActive()){
195  for(auto n : notify_vector){
196  n->setAudioInfo(info);
197  }
198  }
199  }
200 
201 };
202 
208  public:
210  virtual float volume() { return volume_value; }
212  virtual bool setVolume(float volume) {
213  volume_value = volume;
214  return true;
215  }
216  protected:
217  float volume_value = 1.0f;
218 };
219 
225  public:
226  virtual size_t write(const uint8_t *data, size_t len) = 0;
227  virtual void setAudioInfo(AudioInfo from) = 0;
228  virtual void setOutput(Print &out_stream) = 0;
229  virtual operator bool() = 0;
230  virtual bool begin() = 0;
231  virtual bool begin(AudioInfo info) {
232  setAudioInfo(info);
233  return begin();
234  }
235  virtual void end() = 0;
236  protected:
237  void writeBlocking(Print *out, uint8_t* data, size_t len){
238  TRACED();
239  int open = len;
240  int written = 0;
241  while(open>0){
242  int result = out->write(data+written, open);
243  open -= result;
244  written += result;
245  }
246  }
247 };
248 
253 class AudioTime {
254  public:
256  static uint32_t toTimeUs(uint32_t samplingRate, uint8_t limit=10){
257  uint32_t result = 1000000l / samplingRate;
258  if (1000000l % samplingRate!=0){
259  result++;
260  }
261  if (result <= limit){
262  LOGW("Time for samplingRate %u -> %u is < %u μs - we rounded up", (unsigned int)samplingRate, (unsigned int)result, (unsigned int)limit);
263  result = limit;
264  }
265  return result;
266  }
267 
269  static uint32_t toBytes(uint32_t millis, AudioInfo info){
270  size_t samples = info.sample_rate * millis / 1000;
271  size_t bytes = samples * info.channels * info.bits_per_sample / 8;
272  return bytes;
273  }
274 
275  static uint32_t toTimeMs(uint32_t samplingRate, uint8_t limit=1){
276  uint32_t result = 1000l / samplingRate;
277  if (1000000l % samplingRate!=0){
278  result++;
279  }
280  if (result <= limit){
281  LOGW("Time for samplingRate %u -> %u is < %u μs - we rounded up", (unsigned int)samplingRate, (unsigned int)result, (unsigned int)limit);
282  result = limit;
283  }
284  return result;
285  }
286 
287  static float toRateUs(uint32_t time_us){
288  return 1000000.0 / time_us;
289  }
290 
291  static float toRateMs(uint32_t time_ms){
292  return 1000.0 / time_ms;
293  }
294 };
295 
303 template <typename T>
304 inline T mapT(T x, T in_min, T in_max, T out_min, T out_max) {
305  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
306 }
307 
308 
309 
315  public:
317  static int64_t maxValue(int value_bits_per_sample){
318  switch(value_bits_per_sample){
319  case 8:
320  return 127;
321  case 16:
322  return 32767;
323  case 24:
324  return 8388607;
325  case 32:
326  return 2147483647;
327  }
328  return 32767;
329  }
330 
332  template <typename T>
333  static float maxValueT(){
334 #ifdef USE_TYPETRAITS
335  // int24_t uses 4 bytes instead of 3!
336  //return (std::is_same<T, int24_t>::value ) ? 8388607 : maxValue(sizeof(T)*8);
337  return std::numeric_limits<T>::max();
338 #else
339  return maxValue(sizeof(T)*8);
340 #endif
341  }
342 
343  template <typename T>
344  static float minValueT(){
345 #ifdef USE_TYPETRAITS
346  // int24_t uses 4 bytes instead of 3!
347  //return (std::is_same<T, int24_t>::value ) ? 8388607 : maxValue(sizeof(T)*8);
348  return std::numeric_limits<T>::min();
349 #else
350  return -maxValue(sizeof(T)*8);
351 #endif
352  }
353 
354 
355 
357  template <typename T>
358  static T clipT(float value){
359  float mv = maxValueT<T>();
360  if (value > mv){
361  return mv;
362  } else if (value < -mv){
363  return -mv;
364  }
365  return value;
366  }
367 
369  inline static int32_t clip(float value, int bits){
370  float mv = maxValue(bits);
371  if (value > mv){
372  return mv;
373  } else if (value < -mv){
374  return -mv;
375  }
376  return value;
377  }
378 
380  template <typename T>
381  static float toFloatT(T value) {
382  return static_cast<float>(value) / maxValueT<T>();
383  }
384 
386  template <typename T>
387  static T fromFloatT(float value){
388  return value * maxValueT<T>();
389  }
390 
392  inline static float toFloat(int32_t value, int bits) {
393  return static_cast<float>(value) / maxValue(bits);
394  }
395 
397  inline static int32_t fromFloat(float value, int bits){
398  return clip(value * maxValue(bits), bits);
399  }
400 
402  template <typename FromT, typename ToT>
403  static ToT convert(FromT value){
404  float value1 = value;
405  float minTo = minValueT<ToT>();
406  float maxTo = maxValueT<ToT>();
407  float maxFrom = maxValueT<FromT>();
408  float minFrom = minValueT<FromT>();
409 
410  if (maxTo - minTo > 1.0f
411  || maxFrom - minFrom > 1.0f) {
412  return mapT<float>(value1, minFrom, maxFrom, minTo, maxTo);
413  }
414 
415 
416  return value1 * maxValueT<ToT>() / maxValueT<FromT>();
417  }
418 
420  template <typename FromT, typename ToT>
421  static void convertArray(FromT* from, ToT*to, int samples, float vol=1.0f){
422  float factor = static_cast<float>(maxValueT<ToT>()) / maxValueT<FromT>();
423  float vol_factor = factor * vol;
424  for (int j=0;j<samples;j++){
425  to[j] = clipT<ToT>(vol * convert<FromT, ToT>(from[j]));
426  }
427  }
428 
429 };
430 
431 #if defined(USE_I2S)
432 
436 enum I2SFormat {
437  I2S_STD_FORMAT,
438  I2S_LSB_FORMAT,
439  I2S_MSB_FORMAT,
440  I2S_PHILIPS_FORMAT,
441  I2S_RIGHT_JUSTIFIED_FORMAT,
442  I2S_LEFT_JUSTIFIED_FORMAT,
443  I2S_PCM,
444 };
445 
446 static const char* i2s_formats[] = {"I2S_STD_FORMAT","I2S_LSB_FORMAT","I2S_MSB_FORMAT","I2S_PHILIPS_FORMAT","I2S_RIGHT_JUSTIFIED_FORMAT","I2S_LEFT_JUSTIFIED_FORMAT","I2S_PCM"};
447 
452  Digital,
453  Analog,
454  PDM,
455  TDM,
456 };
457 
458 static const char* i2s_signal_types[] = {"Digital","Analog","PDM","TDM"};
459 
460 #endif
461 
463 template<typename T>
464 T readSample(Stream* p_stream){
465  T result=0;
466  uint8_t *p_result = (uint8_t*) &result;
467  int open = sizeof(T);
468  int total = 0;
469  // copy missing data
470  while (open>0){
471  int read = p_stream->readBytes(p_result+total, open);
472  open -= read;
473  total += read;
474  }
475  return result;
476 }
477 
479 template<typename T>
480 size_t readSamples(Stream* p_stream, T* data, int samples, int retryCount=-1){
481  uint8_t *p_result = (uint8_t*) data;
482  int open = samples*sizeof(T);
483  int total = 0;
484  int count0 = 0;
485  // copy missing data - we abort after 5 x read returned 0 bytes
486  while (open > 0){
487  int read = p_stream->readBytes(p_result+total, open);
488  open -= read;
489  total += read;
490  if (read == 0){
491  count0++;
492  delay(1);
493  } else {
494  count0 = 0;
495  }
496  // abort loop
497  if (retryCount >= 0 && count0 > retryCount)
498  break;
499  }
500  // convert bytes to samples
501  return total / sizeof(T);
502 }
503 
505 template<typename T>
506 size_t writeSamples(Print* p_out, T* data, int samples, int maxSamples=512){
507  uint8_t *p_result = (uint8_t*) data;
508  int open = samples*sizeof(T);
509  int total = 0;
510  // copy missing data
511  while (open>0){
512  int to_write = min(open, static_cast<int>(maxSamples*sizeof(T)));
513  int written = p_out->write(p_result+total, to_write );
514  open -= written;
515  total += written;
516  }
517  // convert bytes to samples
518  return total / sizeof(T);
519 }
520 
521 
523 static const char* mime_pcm = "audio/pcm";
524 
525 
526 #ifndef IS_DESKTOP
528 inline void waitFor(HardwareSerial &out){
529  while(!out);
530 }
531 #endif
532 
534 inline void waitFor(bool &flag){
535  while(!flag);
536 }
537 
540 
541 
542 }
Supports the subscription to audio change notifications.
Definition: AudioTypes.h:159
bool isNotifyActive()
Checks if the automatic AudioInfo update is active.
Definition: AudioTypes.h:185
virtual void addNotifyAudioChange(AudioInfoSupport &bi)
Adds target to be notified about audio changes.
Definition: AudioTypes.h:162
void setNotifyActive(bool flag)
Deactivate/Reactivate automatic AudioInfo updates: (default is active)
Definition: AudioTypes.h:180
virtual bool removeNotifyAudioChange(AudioInfoSupport &bi)
Removes a target in order not to be notified about audio changes.
Definition: AudioTypes.h:167
virtual void clearNotifyAudioChange()
Deletes all change notify subscriptions.
Definition: AudioTypes.h:175
Supports changes to the sampling rate, bits and channels.
Definition: AudioTypes.h:139
virtual AudioInfo audioInfoOut()
provides the actual output AudioInfo: this is usually the same as audioInfo() unless we use a transfo...
Definition: AudioTypes.h:146
virtual AudioInfo audioInfo()=0
provides the actual input AudioInfo
virtual void setAudioInfo(AudioInfo info)=0
Defines the input AudioInfo.
Tools for calculating timer values.
Definition: AudioTypes.h:253
static uint32_t toBytes(uint32_t millis, AudioInfo info)
converts milliseconds to bytes
Definition: AudioTypes.h:269
static uint32_t toTimeUs(uint32_t samplingRate, uint8_t limit=10)
converts sampling rate to delay in microseconds (μs)
Definition: AudioTypes.h:256
E.g. used by Encoders and Decoders.
Definition: AudioTypes.h:224
virtual void setAudioInfo(AudioInfo from)=0
Defines the input AudioInfo.
Definition: NoArduino.h:149
Converts from a source to a target number with a different type.
Definition: AudioTypes.h:314
static float toFloatT(T value)
Convert an integer integer autio type to a float (with max 1.0)
Definition: AudioTypes.h:381
static T fromFloatT(float value)
Convert a float (with max 1.0) to an integer autio type.
Definition: AudioTypes.h:387
static void convertArray(FromT *from, ToT *to, int samples, float vol=1.0f)
Convert an array of int types.
Definition: AudioTypes.h:421
static float toFloat(int32_t value, int bits)
Convert an integer integer autio type to a float (with max 1.0)
Definition: AudioTypes.h:392
static T clipT(float value)
Clips the value to avoid any over or underflows.
Definition: AudioTypes.h:358
static int32_t fromFloat(float value, int bits)
Convert a float (with max 1.0) to an integer autio type.
Definition: AudioTypes.h:397
static int64_t maxValue(int value_bits_per_sample)
provides the biggest number for the indicated number of bits
Definition: AudioTypes.h:317
static ToT convert(FromT value)
Convert an int number from one type to another.
Definition: AudioTypes.h:403
static int32_t clip(float value, int bits)
clips a value
Definition: AudioTypes.h:369
static float maxValueT()
provides the biggest number for the indicated type
Definition: AudioTypes.h:333
Definition: NoArduino.h:58
Definition: NoArduino.h:125
Vector implementation which provides the most important methods as defined by std::vector....
Definition: Vector.h:21
Supports the setting and getting of the volume.
Definition: AudioTypes.h:207
virtual float volume()
provides the actual volume in the range of 0.0f to 1.0f
Definition: AudioTypes.h:210
virtual bool setVolume(float volume)
define the actual volume in the range of 0.0f to 1.0f
Definition: AudioTypes.h:212
MemoryType
Memory types.
Definition: AudioTypes.h:35
void waitFor(bool &flag)
wait for flag to be active
Definition: AudioTypes.h:534
RxTxMode
The Microcontroller is the Audio Source (TX_MODE) or Audio Sink (RX_MODE). RXTX_MODE is Source and Si...
Definition: AudioTypes.h:28
TimeUnit
Time Units.
Definition: AudioTypes.h:45
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition: AudioConfig.h:868
size_t readSamples(Stream *p_stream, T *data, int samples, int retryCount=-1)
guaranteed to return the requested data
Definition: AudioTypes.h:480
I2SSignalType
I2S Signal Types: Digital, Analog, PDM.
Definition: AudioTypes.h:451
static const char * mime_pcm
Mime type for PCM.
Definition: AudioTypes.h:523
static const char * RxTxModeNames[4]
Text string (description) for RxTxMode.
Definition: AudioTypes.h:40
T readSample(Stream *p_stream)
guaranteed to return the requested data
Definition: AudioTypes.h:464
uint32_t millis()
Returns the milliseconds since the start.
Definition: Time.h:12
I2SFormat
I2S Formats.
Definition: AudioTypes.h:436
T mapT(T x, T in_min, T in_max, T out_min, T out_max)
Similar to Arduino map function but using floats.
Definition: AudioTypes.h:304
size_t writeSamples(Print *p_out, T *data, int samples, int maxSamples=512)
guaranteed to return the requested data
Definition: AudioTypes.h:506
Basic Audio information which drives e.g. I2S.
Definition: AudioTypes.h:52
void copyFrom(AudioInfo info)
Same as set.
Definition: AudioTypes.h:107
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition: AudioTypes.h:55
bool equals(AudioInfo alt)
Returns true if alt values are the same like the current values.
Definition: AudioTypes.h:85
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition: AudioTypes.h:57
AudioInfo & operator=(const AudioInfo &info)
Same as set.
Definition: AudioTypes.h:113
void set(AudioInfo info)
Copies the values from info.
Definition: AudioTypes.h:95
AudioInfo(const AudioInfo &)=default
Copy constructor.
bool operator==(AudioInfo alt)
Returns true if alt values are the same like the current values.
Definition: AudioTypes.h:75
void setAudioInfo(AudioInfo info)
Same as set.
Definition: AudioTypes.h:102
bool equalsExSampleRate(AudioInfo alt)
Checks if only the sample rate is different.
Definition: AudioTypes.h:90
bool operator!=(AudioInfo alt)
Returns true if alt values are the different from the current values.
Definition: AudioTypes.h:80
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition: AudioTypes.h:59
AudioInfo(sample_rate_t sampleRate, uint16_t channelCount, uint8_t bitsPerSample)
Constructor which supports all attribures as parameters.
Definition: AudioTypes.h:65
AudioInfo()=default
Default constructor.