arduino-audio-tools
AudioDAC.h
1 #pragma once
2 
3 #include "AudioTools/CoreAudio/AudioLogger.h"
4 #include "AudioTools/CoreAudio/Buffers.h"
5 #include "AudioTools/CoreAudio/AudioTimer/AudioTimer.h"
6 #include "AudioTools/CoreAudio/AudioOutput.h"
7 
8 namespace audio_tools {
9 
10 // forward declaration
11 class OversamplingDAC;
12 volatile uint32_t output_frame_count = 0;
13 
20 class DACInfo : public AudioInfo {
21  public:
22  friend class OversamplingDAC;
23 
24  DACInfo() {
25  sample_rate = 44100;
26  channels = 2;
27  }
28 
31 
33  int start_pin = PIN_PWM_START;
34 
36  int output_bits = 64;
37 
39  uint32_t outputBitRate() {
40  const int bits = sizeof(int32_t) * 8;
41  return sample_rate * oversample_factor * bits;
42  }
43 
45  uint32_t outputSampleRate() {
46  return (uint32_t)sample_rate * oversample_factor;
47  }
48 
50  void logInfo(bool withPins=false) {
51  AudioInfo::logInfo();
52  LOGI("oversample_factor: %d",oversample_factor );
53  LOGI("output_bits: %d",output_bits );
54  if (withPins){
55  for (int j=0;j<channels;j++){
56  LOGI("pin%d: %d", j, start_pin+j);
57  }
58  }
59  }
60 };
61 
68 class DACOut {
69  public:
70  void write(int pin, bool value){
71  digitalWrite(pin, value);
72  }
73 };
74 
75 
82 class OversamplingDAC : public AudioOutput {
83  public:
84 
86  }
87 
88  virtual ~OversamplingDAC(){
89  end();
90  }
91 
92  virtual DACInfo defaultConfig() {
93  DACInfo result;
94  return result;
95  }
96 
98  virtual bool begin(DACInfo cfg){
99  TRACED();
100 
101  // reset if already running
102  if (active){
103  end();
104  }
105 
106  // start processing
107  this->info = cfg;
108 
109  // check audio data
110  if (info.bits_per_sample!=16){
111  LOGE("Only 16 Bits per sample are supported - you requested %d", info.bits_per_sample);
112  return false;
113  }
114 
115  if (info.sample_rate <= 0){
116  LOGE("invalid sample_rate: %d", info.sample_rate);
117  return false;
118  }
119 
120  // setup memory
121  const int channels = info.channels;
122  current_values = new int32_t[channels];
123  last_values = new int32_t[channels];
124  cummulated_error = new int32_t[channels];
125  startTimer();
126  active = true;
127  return true;
128  }
129 
130  virtual uint32_t outputRate() = 0;
131 
133  virtual void end() {
134  TRACED();
135  active = false;
136  reset();
137  timer_object.end();
138  }
139 
141  virtual size_t write(uint8_t c){
142  int result = 1;
143  write_buffer[write_buffer_pos++] = c;
144  if (write_buffer_pos==4){
145  result = write(write_buffer, 4);
146  if (result<=0){
147  // write failed - so we need to trigger a re-write
148  write_buffer_pos=3;
149  } else{
150  result = 1;
151  }
152  }
153  return result;
154  }
155 
157  virtual size_t write(const uint8_t *data, size_t len){
158  TRACED();
159  if (len==0) return 0;
160  int16_t *ptr = (int16_t *)data;
161 
162  // fill buffer with delta sigma data
163  int frames = std::min(len/(bytes_per_sample*info.channels), (size_t) availableFramesToWrite());
164  while(is_blocking && frames==0){
165  delay(10);
166  frames = std::min(len/(bytes_per_sample*info.channels), (size_t) availableFramesToWrite());
167  }
168  int samples = frames * info.channels;
169  for (int j=0; j<samples; j++){
170  quantize(ptr[j], j % 2);
171  }
172  // return bytes
173  return samples*2;
174  }
175 
177  virtual uint32_t outputFrameCount() {
178  return output_frame_count;
179  }
180 
181 
182  TimerAlarmRepeating &timer() {
183  return timer_object;
184  }
185 
186  void setBlocking(bool blocking){
187  is_blocking = blocking;
188  }
189 
190  bool isBlocking() {
191  return is_blocking;
192  }
193 
194  protected:
195  TimerAlarmRepeating timer_object;
196  DACInfo info;
197  DACOut out;
198  int32_t *current_values = nullptr;
199  int32_t *last_values = nullptr;
200  int32_t *cummulated_error = nullptr;
201  uint8_t write_buffer[4];
202  //uint32_t output_frame_count = 0;
203  uint8_t bytes_per_sample = 2;
204  int write_buffer_pos = 0;
205  int current_bit = -1;
206  const int fixedPosValue=0x007fff00; /* 24.8 of max-signed-int */
207  bool active;
208  bool is_blocking = true;
209 
211  virtual void quantize(int16_t newSamp, int left_right_idx) = 0;
212 
214  virtual size_t availableFramesToWrite() = 0;
215 
217  virtual void reset() {
218  if (current_values!=nullptr){
219  delete current_values;
220  current_values = nullptr;
221  }
222  if (last_values!=nullptr){
223  delete last_values;
224  last_values = nullptr;
225  }
226  if (cummulated_error!=nullptr){
227  delete cummulated_error;
228  cummulated_error = nullptr;
229  }
230  }
231 
232  virtual void startTimer() = 0;
233 
234 };
235 
236 
237 
246 class SimpleDAC : public OversamplingDAC {
247  friend void dacTimerCallback(void *ptr);
248 
249  public:
250  SimpleDAC() : OversamplingDAC() {
251  }
252 
253  ~SimpleDAC(){
254  end();
255  if (active_count!=nullptr){
256  delete[]active_count;
257  }
258  }
259 
260  bool begin(DACInfo cfg) override {
261  TRACED();
262  cfg.logInfo(true);
263  // default processing
264  return OversamplingDAC::begin(cfg);
265  if (active_count==nullptr){
266  active_count = new uint8_t[cfg.channels];
267  }
268  }
269 
270  uint32_t outputRate() override {
271  return info.outputBitRate();
272  }
273 
274 
275  virtual void startTimer() {
276  TRACED();
277  // start (optional) timer
278  if (outputRate()>0){
279  uint32_t timeUs = AudioTime::toTimeUs(outputRate());
280  auto dacTimerCallback = [] (void *ptr)->void IRAM_ATTR {
281  output_frame_count++;
282  ((SimpleDAC*) ptr)->writePins();
283  };
284  timer_object.setCallbackParameter(this);
285  timer_object.begin(dacTimerCallback, timeUs, US);
286  LOGI("Timer started");
287  } else {
288  LOGW("No output because output Rate <=0");
289  }
290  }
291 
292 
293  protected:
294  RingBuffer<uint8_t> buffer = RingBuffer<uint8_t>(DEFAULT_BUFFER_SIZE);
295  int bit_counter = 0;
296  uint8_t *active_count=nullptr;
297  DACOut out;
298 
299  void writePins() {
300  int channels = info.channels;
301  int32_t current_values[channels];
302  if (active && buffer.available()>=2){
303  // determine number of hight bits
304  if (bit_counter==0){
305  active_count[0]=buffer.read();
306  active_count[1]=buffer.read();
307  }
308 
309  // write bits for all channels
310  for (int j=0;j<channels;j++){
311  out.write(info.start_pin+j, active_count[j]<=bit_counter);
312  }
313 
314  // move to next bit
315  bit_counter++;
316  if (bit_counter>=info.output_bits){
317  bit_counter = 0;
318  }
319  }
320  }
321  size_t availableFramesToWrite() override {
322  // 1 sample = 1 byte -> divide by channels
323  return buffer.availableForWrite() / info.channels;
324  }
325 
327  void quantize(int16_t audioValue, int left_right_idx) override {
328  // map to values from intput to number of active output_bits;
329  uint16_t sample = map(audioValue, -32768, 32767, 0, info.output_bits );
330  buffer.write(sample);
331  }
332 
333 
334 };
335 
336 
347  public:
349  }
350 
351  bool begin(DACInfo cfg) override {
352  TRACED();
353  cfg.logInfo(true);
354  // default processing
355  return OversamplingDAC::begin(cfg);
356  }
357 
358  virtual uint32_t outputRate() override {
359  return info.outputBitRate();
360  }
361 
362  virtual void startTimer() {
363  TRACED();
364  // start (optional) timer
365  if (outputRate()>0){
366  uint32_t timeUs = AudioTime::toTimeUs(outputRate());
367  auto dacTimerCallback = [] (void *ptr)->void IRAM_ATTR {
368  output_frame_count++;
369  ((OversamplingDAC32*) ptr)->writePins();
370  };
371  timer_object.setCallbackParameter(this);
372  timer_object.begin(dacTimerCallback, timeUs, US);
373  LOGI("Timer started");
374  } else {
375  LOGW("No output because output Rate <=0");
376  }
377  }
378 
379 
380  protected:
381  RingBuffer<int32_t> buffer = RingBuffer<int32_t>(DEFAULT_BUFFER_SIZE);
382  DACOut out;
383 
384 
385  size_t availableFramesToWrite() override {
386  // 1 sample = 4 types -> divede by 4 and channels
387  return buffer.availableForWrite() / (sizeof(int32_t) * info.channels);
388  }
389 
391  void writePins() {
392  int channels = info.channels;
393  int32_t current_values[channels];
394  if (active && buffer.available()>=2){
395  // determine new values for all channels when all bits have been written
396  if (current_bit < 0){
397  for (int j=0;j<channels;j++){
398  current_values[j] = buffer.read();
399  }
400  current_bit = 31;
401  }
402 
403  // write bits for all channels
404  for (int j=0;j<channels;j++){
405  out.write(info.start_pin+j, current_values[j] >> (current_bit) & 1);
406  }
407  // move to next bit
408  current_bit--;
409  }
410  }
411 
413  virtual void quantize(int16_t newSamp, int left_right_idx) override{
414  // map to unsigned
415  uint16_t sample = newSamp + (0xFFFF / 2);
416  // Don't need lastSamp anymore, store this one for next round
417  last_values[left_right_idx] = sample;
418 
419  // How much the comparison signal changes each oversample step
420  int32_t diffPerStep = (sample - last_values[left_right_idx]) >> (4 + info.oversample_factor);
421  for (int j = 0; j < info.oversample_factor; j++) {
422  // convert to bits
423  uint32_t bits = 0xFFFFFFFF; // max value
424  bits = bits >> (32 - (sample/2048));
425  buffer.write(bits);
426  }
427  }
428 };
429 
430 
431 
439 class SerialDAC : public OversamplingDAC32 {
440  public:
442  serial = &Serial;
443  }
444 
446  serial = &out;
447  }
448 
449  DACInfo defaultConfig() override {
450  DACInfo result;
451  result.oversample_factor = 10;
452  return result;
453  }
454 
455  bool begin(DACInfo info) override {
456  TRACED();
457  info.logInfo(false);
458  this->cfg = &info;
459  // setup baud rate in the uart
460  int rate = info.sample_rate * 8 * info.oversample_factor ; //outputSampleRate();
461  LOGI("Setting Baudrate: %d", rate);
462  if (rate>0){
463  serial->begin(rate);
464  } else {
465  LOGE("sample_rate not defined");
466  }
467  // default processing
468  return OversamplingDAC::begin(info);
469  }
470 
472  virtual size_t write(const uint8_t *data, size_t len) override {
473  TRACED();
474  return serial->write(data, len);
475  }
476 
477  virtual uint32_t outputRate() override {
478  return 0;
479  }
480 
481 
482  protected:
483  HardwareSerial *serial = nullptr;
484  int16_t totalSamples;
485  DACInfo *cfg;
486 
488  virtual void quantize(int16_t newSamp, int left_right_idx) override {
489  if (left_right_idx==0){
490  totalSamples = newSamp;
491  } else {
492  totalSamples += newSamp;
493  }
494  // on last channel we output
495  if (left_right_idx==cfg->channels-1) {
496  // combine left and right and map to unsigned
497  uint16_t sample = (totalSamples / cfg->channels) + (0xFFFF / 2);
498  // How much the comparison signal changes each oversample step
499  int32_t diffPerStep = (sample - last_values[left_right_idx]) >> (4 + info.oversample_factor);
500  for (int j = 0; j < info.oversample_factor; j++) {
501  // convert to bits
502  uint32_t bits = 0xFFFFFFFF; // max value
503  bits = bits >> (32 - (sample/2048));
504  buffer.write(bits);
505  }
506  }
507  }
508 };
509 
510 #ifdef USE_DELTASIGMA
511 
521 class DeltaSigmaDAC : public OversamplingDAC32 {
522  public:
523  DeltaSigmaDAC() : OversamplingDAC32() {}
524 
525  DACInfo defaultConfig() override {
526  DACInfo result;
527  result.oversample_factor = 2;
528  return result;
529  }
530 
531  bool begin(DACInfo cfg) override {
532  TRACED();
533  cfg.logInfo(true);
534  // default processing
535  return OversamplingDAC::begin(cfg);
536  }
537 
538  virtual uint32_t outputRate() override {
539  return info.outputBitRate();
540  }
541 
542 
543  protected:
545  virtual void quantize(int16_t newSamp, int left_right_idx) override {
546  // Don't need lastSamp anymore, store this one for next round
547  last_values[left_right_idx] = newSamp;
548 
549  // How much the comparison signal changes each oversample step
550  int32_t diffPerStep = (newSamp - last_values[left_right_idx]) >> (4 + info.oversample_factor);
551  for (int j = 0; j < info.oversample_factor; j++) {
552  uint32_t bits = 0; // The bits we convert the sample into, MSB to go on the wire first
553 
554  for (int i = 32; i > 0; i--) {
555  bits = bits << 1;
556  if (cummulated_error[left_right_idx] < 0) {
557  bits |= 1;
558  cummulated_error[left_right_idx] += fixedPosValue - newSamp;
559  } else {
560  // Bits[0] = 0 handled already by left shift
561  cummulated_error[left_right_idx] -= fixedPosValue + newSamp;
562  }
563  newSamp += diffPerStep; // Move the reference signal towards destination
564  }
565  buffer.write(bits);
566  }
567  }
568 };
569 
570 #endif
571 
572 #ifdef ESP32
573 
574 
579 class PWMDAC : public OversamplingDAC {
580  public:
581  PWMDAC(int pwmFrequency=PWM_FREQENCY) : OversamplingDAC() {
582  pmw_frequency = pwmFrequency;
583  }
584 
585  virtual ~PWMDAC(){
586  end();
587  }
588 
589  virtual DACInfo defaultConfig() {
590  DACInfo result;
591  // we use 16bits by default
592  result.output_bits = 16;
593  return result;
594  }
595 
596  virtual bool begin(DACInfo cfg) override {
597  TRACED();
598  cfg.logInfo(true);
599  // default processing
600  bool result = OversamplingDAC::begin(cfg);
601  // automatic scaling
602  max_pwm_value = pow(2, info.output_bits);
603  setupPins();
604 
605  return result;
606  }
607 
609  virtual uint32_t outputRate() override {
610  return info.sample_rate;
611  }
612 
613  protected:
614  RingBuffer<uint16_t> buffer = RingBuffer<uint16_t>(DEFAULT_BUFFER_SIZE);
615  uint32_t max_pwm_value;
616  uint32_t pmw_frequency;
617 
618  virtual size_t availableFramesToWrite() override {
619  // 1 sample = 1 byte -> divide by channels
620  return buffer.availableForWrite() / info.channels;
621  }
622 
624  virtual void quantize(int16_t audioValue, int left_right_idx) override {
625  // map to values from intput to number of active output_bits;
626  uint16_t sample = map(audioValue, -32768, 32767, 0, max_pwm_value );
627  buffer.write(sample);
628  }
629 
630  void setupPins() {
631  TRACED();
632  LOGI("pmw_frequency: %u", pmw_frequency)
633  LOGI("max_pwm_value: %u", max_pwm_value)
634  for (int ch=0;ch<info.channels;ch++){
635  ledcSetup(ch, pmw_frequency, info.output_bits);
636  // attach the channel to the GPIO to be controlled
637  ledcAttachPin(info.start_pin, ch);
638  }
639  }
640 
642  void writePins() {
643  if (buffer.available()>=info.channels){
644  for (int ch=0;ch<info.channels;ch++){
645  ledcWrite(ch, buffer.read());
646  }
647  }
648  }
649 
650  virtual void startTimer() override {
651  TRACED();
652  // start (optional) timer
653  if (outputRate()>0){
654  uint32_t timeUs = AudioTime::toTimeUs(outputRate());
655  auto dacTimerCallback = [] (void *ptr)->void IRAM_ATTR {
656  output_frame_count++;
657  ((PWMDAC*) ptr)->writePins();
658  };
659  timer_object.setCallbackParameter(this);
660  timer_object.begin(dacTimerCallback, timeUs, US);
661  LOGI("Timer started");
662  } else {
663  LOGW("No output because output Rate <=0");
664  }
665  }
666 };
667 
668 
669 #endif
670 
671 } // namesapce
672 
Abstract Audio Ouptut class.
Definition: AudioOutput.h:22
static uint32_t toTimeUs(uint32_t samplingRate, uint8_t limit=10)
converts sampling rate to delay in microseconds (μs)
Definition: AudioTypes.h:254
Config info for DeltaSigma DAC.
Definition: AudioDAC.h:20
void logInfo(bool withPins=false)
Logs the configuration settings to the console (if logging is active)
Definition: AudioDAC.h:50
int output_bits
Max number of bits used to output signal.
Definition: AudioDAC.h:36
int start_pin
Defines the pins: channel 0 is start_pin, channel 1 is start_pin+1 etc.
Definition: AudioDAC.h:33
uint32_t outputSampleRate()
Provides the update frame rate.
Definition: AudioDAC.h:45
uint32_t outputBitRate()
Provides the update bit rate.
Definition: AudioDAC.h:39
int oversample_factor
By default we do not oversample.
Definition: AudioDAC.h:30
Output method for DeltaSigma DAC.
Definition: AudioDAC.h:68
Definition: NoArduino.h:149
Software Implementation of a Simple DAC - We quantize a digital int16_t sample my mapping the value t...
Definition: AudioDAC.h:346
size_t availableFramesToWrite() override
determines how many frames we can write to the buffer
Definition: AudioDAC.h:385
bool begin(DACInfo cfg) override
starts the Delta Sigma DAC
Definition: AudioDAC.h:351
void writePins()
Default output.
Definition: AudioDAC.h:391
virtual void quantize(int16_t newSamp, int left_right_idx) override
updates the buffer with analog value (represented by number of 1)
Definition: AudioDAC.h:413
Abstract Software Implementation of an Oversampling DAC.
Definition: AudioDAC.h:82
virtual uint32_t outputFrameCount()
To be used for testing, we just count the number of frames that were sent to output.
Definition: AudioDAC.h:177
virtual void reset()
Releases the memory.
Definition: AudioDAC.h:217
virtual size_t availableFramesToWrite()=0
determines how many frames we can write to the buffer
virtual void quantize(int16_t newSamp, int left_right_idx)=0
updates the buffer with analog value (represented by number of 1)
virtual size_t write(const uint8_t *data, size_t len)
Writes the audio data to the output buffer.
Definition: AudioDAC.h:157
virtual size_t write(uint8_t c)
Writes a single byte (of audio data) to the output buffer.
Definition: AudioDAC.h:141
virtual bool begin(DACInfo cfg)
starts the Delta Sigma DAC
Definition: AudioDAC.h:98
virtual void end()
Stops the output.
Definition: AudioDAC.h:133
Audio Output with PWM signal.
Definition: AudioDAC.h:579
virtual bool begin(DACInfo cfg) override
starts the Delta Sigma DAC
Definition: AudioDAC.h:596
virtual size_t availableFramesToWrite() override
determines how many frames we can write to the buffer
Definition: AudioDAC.h:618
virtual uint32_t outputRate() override
We use the sample rate to output values.
Definition: AudioDAC.h:609
void writePins()
Output data to pins.
Definition: AudioDAC.h:642
virtual void quantize(int16_t audioValue, int left_right_idx) override
updates the buffer with analog value (represented by number of 1)
Definition: AudioDAC.h:624
virtual T read()
reads a single value
Definition: Buffers.h:309
virtual int availableForWrite()
provides the number of entries that are available to write
Definition: Buffers.h:369
virtual int available()
provides the number of entries that are available to read
Definition: Buffers.h:366
virtual bool write(T data)
write add an entry to the buffer
Definition: Buffers.h:347
A SimpleDAC which uses the Serial UART to output values. This implementation is not using any timers ...
Definition: AudioDAC.h:439
virtual size_t write(const uint8_t *data, size_t len) override
just write the data to the UART w/o buffering
Definition: AudioDAC.h:472
bool begin(DACInfo info) override
starts the Delta Sigma DAC
Definition: AudioDAC.h:455
virtual void quantize(int16_t newSamp, int left_right_idx) override
updates the buffer with analog value (represented by number of 1)
Definition: AudioDAC.h:488
Software Implementation of a Simple DAC - We quantize a digital int16_t sample my mapping the value t...
Definition: AudioDAC.h:246
size_t availableFramesToWrite() override
determines how many frames we can write to the buffer
Definition: AudioDAC.h:321
void quantize(int16_t audioValue, int left_right_idx) override
updates the buffer with analog value (represented by number of 1)
Definition: AudioDAC.h:327
bool begin(DACInfo cfg) override
starts the Delta Sigma DAC
Definition: AudioDAC.h:260
Common Interface definition for TimerAlarmRepeating.
Definition: AudioTimer.h:25
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition: AudioConfig.h:821
long map(long x, long in_min, long in_max, long out_min, long out_max)
Maps input to output values.
Definition: NoArduino.h:162
Basic Audio information which drives e.g. I2S.
Definition: AudioTypes.h:50
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition: AudioTypes.h:53
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition: AudioTypes.h:55
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition: AudioTypes.h:57