arduino-audio-tools
AudioTypes.h
1 #pragma once
2 
3 #include "AudioConfig.h"
4 #ifdef USE_TYPETRAITS
5 # include <type_traits>
6 #endif
7 #include "AudioTools/AudioLogger.h"
8 #include "AudioBasic/Collections/Vector.h"
9 
10 // fix compile error for ESP32 C3
11 #undef HZ
12 
13 // MIN
14 #undef MIN
15 #define MIN(A, B) ((A) < (B) ? (A) : (B))
16 
17 
18 namespace audio_tools {
19 
20 using sample_rate_t = uint32_t;
21 
26 enum RxTxMode {UNDEFINED_MODE=0, TX_MODE=1, RX_MODE=2, RXTX_MODE=3 };
27 
33 enum MemoryType {RAM, PS_RAM, FLASH_RAM};
34 
38 static const char* RxTxModeNames[]={"UNDEFINED_MODE","TX_MODE","RX_MODE","RXTX_MODE" };
43 enum TimeUnit {MS, US, HZ};
44 static const char* TimeUnitStr[] {"MS","US","HZ"};
45 
50 struct AudioInfo {
51 
53  sample_rate_t sample_rate = DEFAULT_SAMPLE_RATE;
55  uint16_t channels = DEFAULT_CHANNELS;
57  uint8_t bits_per_sample = DEFAULT_BITS_PER_SAMPLE;
58 
60  AudioInfo() = default;
61 
63  AudioInfo(sample_rate_t sampleRate, uint16_t channelCount, uint8_t bitsPerSample) {
64  sample_rate = sampleRate;
65  channels = channelCount;
66  bits_per_sample = bitsPerSample;
67  };
68 
70  AudioInfo(const AudioInfo &) = default;
71 
73  bool operator==(AudioInfo alt){
75  }
76 
78  bool operator!=(AudioInfo alt){
79  return !(*this == alt);
80  }
81 
83  bool equals(AudioInfo alt){
84  return *this == alt;
85  }
86 
89  return channels == alt.channels && bits_per_sample == alt.bits_per_sample;
90  }
91 
93  void set(AudioInfo info) {
94  sample_rate = info.sample_rate;
95  channels = info.channels;
97  }
98 
100  void setAudioInfo(AudioInfo info) {
101  set(info);
102  }
103 
105  void copyFrom(AudioInfo info){
106  setAudioInfo(info);
107  }
108 
111  setAudioInfo(info);
112  return *this;
113  }
114 
116  operator bool() {
117  return sample_rate > 0 && channels > 0 && bits_per_sample > 0;
118  }
119 
120  virtual void clear(){
121  sample_rate = 0;
122  channels = 0;
123  bits_per_sample = 0;
124  }
125 
126  virtual void logInfo(const char* source="") {
127  LOGI("%s sample_rate: %d / channels: %d / bits_per_sample: %d",source, (int) sample_rate, (int)channels, (int)bits_per_sample);
128  }
129 
130 };
131 
137  public:
139  virtual void setAudioInfo(AudioInfo info) = 0;
141  virtual AudioInfo audioInfo() = 0;
143  virtual AudioInfo audioInfoOut() { return audioInfo();}
144 };
145 // Support legacy name
146 using AudioBaseInfo = AudioInfo;
147 using AudioBaseInfoDependent = AudioInfoSupport;
148 using AudioInfoDependent = AudioInfoSupport;
149 
150 
156  public:
159  if (!notify_vector.contains(&bi)) notify_vector.push_back(&bi);
160  }
161 
164  int pos = notify_vector.indexOf(&bi);
165  if (pos<0) return false;
166  notify_vector.erase(pos);
167  return true;
168  }
169 
171  virtual void clearNotifyAudioChange() {
172  notify_vector.clear();
173  }
174 
175 #if USE_OBSOLETE
177  virtual void setNotifyAudioChange(AudioInfoSupport &bi) {
179  }
180 #endif
181 
183  void setNotifyActive(bool flag){
184  is_notify_active = flag;
185  }
186 
189  return is_notify_active;
190  }
191 
192  protected:
193  Vector<AudioInfoSupport*> notify_vector;
194  bool is_notify_active = true;
195 
196  void notifyAudioChange(AudioInfo info){
197  if (isNotifyActive()){
198  for(auto n : notify_vector){
199  n->setAudioInfo(info);
200  }
201  }
202  }
203 
204 };
205 
211  public:
213  virtual float volume() { return volume_value; }
215  virtual bool setVolume(float volume) {
216  volume_value = volume;
217  return true;
218  }
219  protected:
220  float volume_value = 1.0f;
221 };
222 
228  public:
229  virtual size_t write(const void *in_ptr, size_t in_size) = 0;
230  virtual void setAudioInfo(AudioInfo from) = 0;
231  virtual void setOutput(Print &out_stream) = 0;
232  virtual operator bool() = 0;
233  virtual bool begin() = 0;
234  virtual bool begin(AudioInfo info) {
235  setAudioInfo(info);
236  return begin();
237  }
238  virtual void end() = 0;
239  protected:
240  void writeBlocking(Print *out, uint8_t* data, size_t len){
241  TRACED();
242  int open = len;
243  int written = 0;
244  while(open>0){
245  int result = out->write(data+written, open);
246  open -= result;
247  written += result;
248  }
249  }
250 };
251 
256 class AudioTime {
257  public:
259  static uint32_t toTimeUs(uint32_t samplingRate, uint8_t limit=10){
260  uint32_t result = 1000000l / samplingRate;
261  if (1000000l % samplingRate!=0){
262  result++;
263  }
264  if (result <= limit){
265  LOGW("Time for samplingRate %u -> %u is < %u μs - we rounded up", (unsigned int)samplingRate, (unsigned int)result, (unsigned int)limit);
266  result = limit;
267  }
268  return result;
269  }
270 
272  static uint32_t toBytes(uint32_t millis, AudioInfo info){
273  size_t samples = info.sample_rate * millis / 1000;
274  size_t bytes = samples * info.channels * info.bits_per_sample / 8;
275  return bytes;
276  }
277 
278  static uint32_t toTimeMs(uint32_t samplingRate, uint8_t limit=1){
279  uint32_t result = 1000l / samplingRate;
280  if (1000000l % samplingRate!=0){
281  result++;
282  }
283  if (result <= limit){
284  LOGW("Time for samplingRate %u -> %u is < %u μs - we rounded up", (unsigned int)samplingRate, (unsigned int)result, (unsigned int)limit);
285  result = limit;
286  }
287  return result;
288  }
289 
290  static float toRateUs(uint32_t time_us){
291  return 1000000.0 / time_us;
292  }
293 
294  static float toRateMs(uint32_t time_ms){
295  return 1000.0 / time_ms;
296  }
297 };
298 
304  public:
305  static int32_t convertFrom24To32(int24_t value) {
306  return value.scale32();
307  }
308 
309  static int16_t convertFrom24To16(int24_t value) {
310  return value.scale16();
311  }
312 
313  static float convertFrom24ToFloat(int24_t value) {
314  return value.scaleFloat();
315  }
316 
317  static int16_t convertFrom32To16(int32_t value) {
318  return static_cast<float>(value) / INT32_MAX * INT16_MAX;
319  }
320 
321  static int16_t convert16(int value, int value_bits_per_sample){
322  return value * NumberConverter::maxValue(16) / NumberConverter::maxValue(value_bits_per_sample);
323  }
324 
325  static int16_t convert8(int value, int value_bits_per_sample){
326  return value * NumberConverter::maxValue(8) / NumberConverter::maxValue(value_bits_per_sample);
327  }
328 
330  static int64_t maxValue(int value_bits_per_sample){
331  switch(value_bits_per_sample){
332  case 8:
333  return 127;
334  case 16:
335  return 32767;
336  case 24:
337  return 8388607;
338  case 32:
339  return 2147483647;
340  }
341  return 32767;
342  }
343 
345  template <typename T>
346  static int64_t maxValueT(){
347 #ifdef USE_TYPETRAITS
348  // int24_t uses 4 bytes instead of 3!
349  return (std::is_same<T, int24_t>::value ) ? 8388607 : maxValue(sizeof(T)*8);
350 #else
351  return maxValue(sizeof(T)*8);
352 #endif
353  }
354 
356  template <typename T>
357  static T clip(int64_t value){
358  T mv = maxValue(sizeof(T)*8);
359  if (value > mv){
360  return mv;
361  } else if (value < -mv){
362  return -mv;
363  }
364  return value;
365  }
366 
368  template <typename FromT, typename ToT>
369  static ToT convert(FromT value){
370  int64_t value1 = value;
371  return clip<ToT>(value1 * maxValueT<ToT>() / maxValueT<FromT>());
372  }
373 
374  template <typename FromT, typename ToT>
375  static void convertArray(FromT* from, ToT*to, int samples, float vol=1.0f){
376  float factor = static_cast<float>(maxValueT<ToT>()) / maxValueT<FromT>();
377  float vol_factor = factor * vol;
378  for (int j=0;j<samples;j++){
379  to[j] = clip<ToT>(vol_factor * from[j]);
380  }
381  }
382 
383 };
384 
385 #if defined(USE_I2S)
386 
390 enum I2SFormat {
391  I2S_STD_FORMAT,
392  I2S_LSB_FORMAT,
393  I2S_MSB_FORMAT,
394  I2S_PHILIPS_FORMAT,
395  I2S_RIGHT_JUSTIFIED_FORMAT,
396  I2S_LEFT_JUSTIFIED_FORMAT,
397  I2S_PCM,
398 };
399 
400 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"};
401 
406  Digital,
407  Analog,
408  PDM,
409  TDM,
410 };
411 
412 static const char* i2s_signal_types[] = {"Digital","Analog","PDM","TDM"};
413 
414 #endif
415 
417 template<typename T>
418 T readSample(Stream* p_stream){
419  T result=0;
420  uint8_t *p_result = (uint8_t*) &result;
421  int open = sizeof(T);
422  int total = 0;
423  // copy missing data
424  while (open>0){
425  int read = p_stream->readBytes(p_result+total, open);
426  open -= read;
427  total += read;
428  }
429  return result;
430 }
431 
433 template<typename T>
434 size_t readSamples(Stream* p_stream, T* data, int samples, int retryCount=-1){
435  uint8_t *p_result = (uint8_t*) data;
436  int open = samples*sizeof(T);
437  int total = 0;
438  int count0 = 0;
439  // copy missing data - we abort after 5 x read returned 0 bytes
440  while (open > 0){
441  int read = p_stream->readBytes(p_result+total, open);
442  open -= read;
443  total += read;
444  if (read == 0){
445  count0++;
446  delay(1);
447  } else {
448  count0 = 0;
449  }
450  // abort loop
451  if (retryCount >= 0 && count0 > retryCount)
452  break;
453  }
454  // convert bytes to samples
455  return total / sizeof(T);
456 }
457 
459 template<typename T>
460 size_t writeSamples(Print* p_out, T* data, int samples, int maxSamples=512){
461  uint8_t *p_result = (uint8_t*) data;
462  int open = samples*sizeof(T);
463  int total = 0;
464  // copy missing data
465  while (open>0){
466  int to_write = min(open, static_cast<int>(maxSamples*sizeof(T)));
467  int written = p_out->write(p_result+total, to_write );
468  open -= written;
469  total += written;
470  }
471  // convert bytes to samples
472  return total / sizeof(T);
473 }
474 
475 
483 inline float mapFloat(float x, float in_min, float in_max, float out_min, float out_max) {
484  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
485 }
486 
488 static const char* mime_pcm = "audio/pcm";
489 
490 
491 #ifndef IS_DESKTOP
493 inline void waitFor(HardwareSerial &out){
494  while(!out);
495 }
496 #endif
497 
499 inline void waitFor(bool &flag){
500  while(!flag);
501 }
502 
505 
506 
507 }
Supports the subscription to audio change notifications.
Definition: AudioTypes.h:155
bool isNotifyActive()
Checks if the automatic AudioInfo update is active.
Definition: AudioTypes.h:188
virtual void addNotifyAudioChange(AudioInfoSupport &bi)
Adds target to be notified about audio changes.
Definition: AudioTypes.h:158
void setNotifyActive(bool flag)
Deactivate/Reactivate automatic AudioInfo updates: (default is active)
Definition: AudioTypes.h:183
virtual bool removeNotifyAudioChange(AudioInfoSupport &bi)
Removes a target in order not to be notified about audio changes.
Definition: AudioTypes.h:163
virtual void clearNotifyAudioChange()
Deletes all change notify subscriptions.
Definition: AudioTypes.h:171
Supports changes to the sampling rate, bits and channels.
Definition: AudioTypes.h:136
virtual AudioInfo audioInfoOut()
provides the actual output AudioInfo: this is usually the same as audioInfo() unless we use a transfo...
Definition: AudioTypes.h:143
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:256
static uint32_t toBytes(uint32_t millis, AudioInfo info)
converts milliseconds to bytes
Definition: AudioTypes.h:272
static uint32_t toTimeUs(uint32_t samplingRate, uint8_t limit=10)
converts sampling rate to delay in microseconds (μs)
Definition: AudioTypes.h:259
E.g. used by Encoders and Decoders.
Definition: AudioTypes.h:227
virtual void setAudioInfo(AudioInfo from)=0
Defines the input AudioInfo.
Definition: NoArduino.h:148
Converts from a source to a target number with a different type.
Definition: AudioTypes.h:303
static T clip(int64_t value)
Clips the value to avoid any over or underflows.
Definition: AudioTypes.h:357
static int64_t maxValue(int value_bits_per_sample)
provides the biggest number for the indicated number of bits
Definition: AudioTypes.h:330
static ToT convert(FromT value)
Convert a number from one type to another.
Definition: AudioTypes.h:369
static int64_t maxValueT()
provides the biggest number for the indicated type
Definition: AudioTypes.h:346
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:210
virtual float volume()
provides the actual volume in the range of 0.0f to 1.0f
Definition: AudioTypes.h:213
virtual bool setVolume(float volume)
define the actual volume in the range of 0.0f to 1.0f
Definition: AudioTypes.h:215
24bit integer which is used for I2S sound processing. The values are represented as int32_t,...
Definition: Int24_4bytes_t.h:16
int32_t scale32() const
provides value between -2,147,483,647 and 2,147,483,647
Definition: Int24_4bytes_t.h:115
int16_t scale16() const
provides value between -32767 and 32767
Definition: Int24_4bytes_t.h:110
float scaleFloat() const
provides value between -1.0 and 1.0
Definition: Int24_4bytes_t.h:120
MemoryType
Memory types.
Definition: AudioTypes.h:33
void waitFor(bool &flag)
wait for flag to be active
Definition: AudioTypes.h:499
RxTxMode
The Microcontroller is the Audio Source (TX_MODE) or Audio Sink (RX_MODE). RXTX_MODE is Source and Si...
Definition: AudioTypes.h:26
TimeUnit
Time Units.
Definition: AudioTypes.h:43
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition: AnalogAudio.h:10
size_t readSamples(Stream *p_stream, T *data, int samples, int retryCount=-1)
guaranteed to return the requested data
Definition: AudioTypes.h:434
I2SSignalType
I2S Signal Types: Digital, Analog, PDM.
Definition: AudioTypes.h:405
float mapFloat(float x, float in_min, float in_max, float out_min, float out_max)
Similar to Arduino map function but using floats.
Definition: AudioTypes.h:483
static const char * mime_pcm
Mime type for PCM.
Definition: AudioTypes.h:488
T readSample(Stream *p_stream)
guaranteed to return the requested data
Definition: AudioTypes.h:418
I2SFormat
I2S Formats.
Definition: AudioTypes.h:390
void delay(uint32_t ms)
Waits for the indicated milliseconds.
Definition: Millis.h:11
static const char * RxTxModeNames[]
Text string (description) for RxTxMode.
Definition: AudioTypes.h:38
uint32_t millis()
Returns the milliseconds since the start.
Definition: Millis.h:18
size_t writeSamples(Print *p_out, T *data, int samples, int maxSamples=512)
guaranteed to return the requested data
Definition: AudioTypes.h:460
Basic Audio information which drives e.g. I2S.
Definition: AudioTypes.h:50
void copyFrom(AudioInfo info)
Same as set.
Definition: AudioTypes.h:105
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition: AudioTypes.h:53
bool equals(AudioInfo alt)
Returns true if alt values are the same like the current values.
Definition: AudioTypes.h:83
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition: AudioTypes.h:55
AudioInfo & operator=(const AudioInfo &info)
Same as set.
Definition: AudioTypes.h:110
void set(AudioInfo info)
Copies the values from info.
Definition: AudioTypes.h:93
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:73
void setAudioInfo(AudioInfo info)
Same as set.
Definition: AudioTypes.h:100
bool equalsExSampleRate(AudioInfo alt)
Checks if only the sample rate is different.
Definition: AudioTypes.h:88
bool operator!=(AudioInfo alt)
Returns true if alt values are the different from the current values.
Definition: AudioTypes.h:78
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition: AudioTypes.h:57
AudioInfo(sample_rate_t sampleRate, uint16_t channelCount, uint8_t bitsPerSample)
Constructor which supports all attribures as parameters.
Definition: AudioTypes.h:63
AudioInfo()=default
Default constructor.