audio_dac_additive.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. /* Copyright 2016-2019 Jack Humbert
  2. * Copyright 2020 JohSchneider
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include "audio.h"
  18. #include <ch.h>
  19. #include <hal.h>
  20. /*
  21. Audio Driver: DAC
  22. which utilizes the dac unit many STM32 are equipped with, to output a modulated waveform from samples stored in the dac_buffer_* array who are passed to the hardware through DMA
  23. it is also possible to have a custom sample-LUT by implementing/overriding 'dac_value_generate'
  24. this driver allows for multiple simultaneous tones to be played through one single channel by doing additive wave-synthesis
  25. */
  26. #if !defined(AUDIO_PIN)
  27. # error "Audio feature enabled, but no suitable pin selected as AUDIO_PIN - see docs/feature_audio under 'ARM (DAC additive)' for available options."
  28. #endif
  29. #if defined(AUDIO_PIN_ALT) && !defined(AUDIO_PIN_ALT_AS_NEGATIVE)
  30. # pragma message "Audio feature: AUDIO_PIN_ALT set, but not AUDIO_PIN_ALT_AS_NEGATIVE - pin will be left unused; audio might still work though."
  31. #endif
  32. #if !defined(AUDIO_PIN_ALT)
  33. // no ALT pin defined is valid, but the c-ifs below need some value set
  34. # define AUDIO_PIN_ALT PAL_NOLINE
  35. #endif
  36. #if !defined(AUDIO_DAC_SAMPLE_WAVEFORM_SINE) && !defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE) && !defined(AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE) && !defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID)
  37. # define AUDIO_DAC_SAMPLE_WAVEFORM_SINE
  38. #endif
  39. #ifdef AUDIO_DAC_SAMPLE_WAVEFORM_SINE
  40. /* one full sine wave over [0,2*pi], but shifted up one amplitude and left pi/4; for the samples to start at 0
  41. */
  42. static const dacsample_t dac_buffer_sine[AUDIO_DAC_BUFFER_SIZE] = {
  43. // 256 values, max 4095
  44. 0x0, 0x1, 0x2, 0x6, 0xa, 0xf, 0x16, 0x1e, 0x27, 0x32, 0x3d, 0x4a, 0x58, 0x67, 0x78, 0x89, 0x9c, 0xb0, 0xc5, 0xdb, 0xf2, 0x10a, 0x123, 0x13e, 0x159, 0x175, 0x193, 0x1b1, 0x1d1, 0x1f1, 0x212, 0x235, 0x258, 0x27c, 0x2a0, 0x2c6, 0x2ed, 0x314, 0x33c, 0x365, 0x38e, 0x3b8, 0x3e3, 0x40e, 0x43a, 0x467, 0x494, 0x4c2, 0x4f0, 0x51f, 0x54e, 0x57d, 0x5ad, 0x5dd, 0x60e, 0x63f, 0x670, 0x6a1, 0x6d3, 0x705, 0x737, 0x769, 0x79b, 0x7cd, 0x800, 0x832, 0x864, 0x896, 0x8c8, 0x8fa, 0x92c, 0x95e, 0x98f, 0x9c0, 0x9f1, 0xa22, 0xa52, 0xa82, 0xab1, 0xae0, 0xb0f, 0xb3d, 0xb6b, 0xb98, 0xbc5, 0xbf1, 0xc1c, 0xc47, 0xc71, 0xc9a, 0xcc3, 0xceb, 0xd12, 0xd39, 0xd5f, 0xd83, 0xda7, 0xdca, 0xded, 0xe0e, 0xe2e, 0xe4e, 0xe6c, 0xe8a, 0xea6, 0xec1, 0xedc, 0xef5, 0xf0d, 0xf24, 0xf3a, 0xf4f, 0xf63, 0xf76, 0xf87, 0xf98, 0xfa7, 0xfb5, 0xfc2, 0xfcd, 0xfd8, 0xfe1, 0xfe9, 0xff0, 0xff5, 0xff9, 0xffd, 0xffe,
  45. 0xfff, 0xffe, 0xffd, 0xff9, 0xff5, 0xff0, 0xfe9, 0xfe1, 0xfd8, 0xfcd, 0xfc2, 0xfb5, 0xfa7, 0xf98, 0xf87, 0xf76, 0xf63, 0xf4f, 0xf3a, 0xf24, 0xf0d, 0xef5, 0xedc, 0xec1, 0xea6, 0xe8a, 0xe6c, 0xe4e, 0xe2e, 0xe0e, 0xded, 0xdca, 0xda7, 0xd83, 0xd5f, 0xd39, 0xd12, 0xceb, 0xcc3, 0xc9a, 0xc71, 0xc47, 0xc1c, 0xbf1, 0xbc5, 0xb98, 0xb6b, 0xb3d, 0xb0f, 0xae0, 0xab1, 0xa82, 0xa52, 0xa22, 0x9f1, 0x9c0, 0x98f, 0x95e, 0x92c, 0x8fa, 0x8c8, 0x896, 0x864, 0x832, 0x800, 0x7cd, 0x79b, 0x769, 0x737, 0x705, 0x6d3, 0x6a1, 0x670, 0x63f, 0x60e, 0x5dd, 0x5ad, 0x57d, 0x54e, 0x51f, 0x4f0, 0x4c2, 0x494, 0x467, 0x43a, 0x40e, 0x3e3, 0x3b8, 0x38e, 0x365, 0x33c, 0x314, 0x2ed, 0x2c6, 0x2a0, 0x27c, 0x258, 0x235, 0x212, 0x1f1, 0x1d1, 0x1b1, 0x193, 0x175, 0x159, 0x13e, 0x123, 0x10a, 0xf2, 0xdb, 0xc5, 0xb0, 0x9c, 0x89, 0x78, 0x67, 0x58, 0x4a, 0x3d, 0x32, 0x27, 0x1e, 0x16, 0xf, 0xa, 0x6, 0x2, 0x1};
  46. #endif // AUDIO_DAC_SAMPLE_WAVEFORM_SINE
  47. #ifdef AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE
  48. static const dacsample_t dac_buffer_triangle[AUDIO_DAC_BUFFER_SIZE] = {
  49. // 256 values, max 4095
  50. 0x0, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0, 0x100, 0x120, 0x140, 0x160, 0x180, 0x1a0, 0x1c0, 0x1e0, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0x400, 0x420, 0x440, 0x460, 0x480, 0x4a0, 0x4c0, 0x4e0, 0x500, 0x520, 0x540, 0x560, 0x580, 0x5a0, 0x5c0, 0x5e0, 0x600, 0x620, 0x640, 0x660, 0x680, 0x6a0, 0x6c0, 0x6e0, 0x700, 0x720, 0x740, 0x760, 0x780, 0x7a0, 0x7c0, 0x7e0, 0x800, 0x81f, 0x83f, 0x85f, 0x87f, 0x89f, 0x8bf, 0x8df, 0x8ff, 0x91f, 0x93f, 0x95f, 0x97f, 0x99f, 0x9bf, 0x9df, 0x9ff, 0xa1f, 0xa3f, 0xa5f, 0xa7f, 0xa9f, 0xabf, 0xadf, 0xaff, 0xb1f, 0xb3f, 0xb5f, 0xb7f, 0xb9f, 0xbbf, 0xbdf, 0xbff, 0xc1f, 0xc3f, 0xc5f, 0xc7f, 0xc9f, 0xcbf, 0xcdf, 0xcff, 0xd1f, 0xd3f, 0xd5f, 0xd7f, 0xd9f, 0xdbf, 0xddf, 0xdff, 0xe1f, 0xe3f, 0xe5f, 0xe7f, 0xe9f, 0xebf, 0xedf, 0xeff, 0xf1f, 0xf3f, 0xf5f, 0xf7f, 0xf9f, 0xfbf, 0xfdf,
  51. 0xfff, 0xfdf, 0xfbf, 0xf9f, 0xf7f, 0xf5f, 0xf3f, 0xf1f, 0xeff, 0xedf, 0xebf, 0xe9f, 0xe7f, 0xe5f, 0xe3f, 0xe1f, 0xdff, 0xddf, 0xdbf, 0xd9f, 0xd7f, 0xd5f, 0xd3f, 0xd1f, 0xcff, 0xcdf, 0xcbf, 0xc9f, 0xc7f, 0xc5f, 0xc3f, 0xc1f, 0xbff, 0xbdf, 0xbbf, 0xb9f, 0xb7f, 0xb5f, 0xb3f, 0xb1f, 0xaff, 0xadf, 0xabf, 0xa9f, 0xa7f, 0xa5f, 0xa3f, 0xa1f, 0x9ff, 0x9df, 0x9bf, 0x99f, 0x97f, 0x95f, 0x93f, 0x91f, 0x8ff, 0x8df, 0x8bf, 0x89f, 0x87f, 0x85f, 0x83f, 0x81f, 0x800, 0x7e0, 0x7c0, 0x7a0, 0x780, 0x760, 0x740, 0x720, 0x700, 0x6e0, 0x6c0, 0x6a0, 0x680, 0x660, 0x640, 0x620, 0x600, 0x5e0, 0x5c0, 0x5a0, 0x580, 0x560, 0x540, 0x520, 0x500, 0x4e0, 0x4c0, 0x4a0, 0x480, 0x460, 0x440, 0x420, 0x400, 0x3e0, 0x3c0, 0x3a0, 0x380, 0x360, 0x340, 0x320, 0x300, 0x2e0, 0x2c0, 0x2a0, 0x280, 0x260, 0x240, 0x220, 0x200, 0x1e0, 0x1c0, 0x1a0, 0x180, 0x160, 0x140, 0x120, 0x100, 0xe0, 0xc0, 0xa0, 0x80, 0x60, 0x40, 0x20};
  52. #endif // AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE
  53. #ifdef AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE
  54. static const dacsample_t dac_buffer_square[AUDIO_DAC_BUFFER_SIZE] = {
  55. [0 ... AUDIO_DAC_BUFFER_SIZE / 2 - 1] = 0, // first and
  56. [AUDIO_DAC_BUFFER_SIZE / 2 ... AUDIO_DAC_BUFFER_SIZE - 1] = AUDIO_DAC_SAMPLE_MAX, // second half
  57. };
  58. #endif // AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE
  59. /*
  60. // four steps: 0, 1/3, 2/3 and 1
  61. static const dacsample_t dac_buffer_staircase[AUDIO_DAC_BUFFER_SIZE] = {
  62. [0 ... AUDIO_DAC_BUFFER_SIZE/3 -1 ] = 0,
  63. [AUDIO_DAC_BUFFER_SIZE / 4 ... AUDIO_DAC_BUFFER_SIZE / 2 -1 ] = AUDIO_DAC_SAMPLE_MAX / 3,
  64. [AUDIO_DAC_BUFFER_SIZE / 2 ... 3 * AUDIO_DAC_BUFFER_SIZE / 4 -1 ] = 2 * AUDIO_DAC_SAMPLE_MAX / 3,
  65. [3 * AUDIO_DAC_BUFFER_SIZE / 4 ... AUDIO_DAC_BUFFER_SIZE -1 ] = AUDIO_DAC_SAMPLE_MAX,
  66. }
  67. */
  68. #ifdef AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID
  69. static const dacsample_t dac_buffer_trapezoid[AUDIO_DAC_BUFFER_SIZE] = {0x0, 0x1f, 0x7f, 0xdf, 0x13f, 0x19f, 0x1ff, 0x25f, 0x2bf, 0x31f, 0x37f, 0x3df, 0x43f, 0x49f, 0x4ff, 0x55f, 0x5bf, 0x61f, 0x67f, 0x6df, 0x73f, 0x79f, 0x7ff, 0x85f, 0x8bf, 0x91f, 0x97f, 0x9df, 0xa3f, 0xa9f, 0xaff, 0xb5f, 0xbbf, 0xc1f, 0xc7f, 0xcdf, 0xd3f, 0xd9f, 0xdff, 0xe5f, 0xebf, 0xf1f, 0xf7f, 0xfdf, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
  70. 0xfff, 0xfdf, 0xf7f, 0xf1f, 0xebf, 0xe5f, 0xdff, 0xd9f, 0xd3f, 0xcdf, 0xc7f, 0xc1f, 0xbbf, 0xb5f, 0xaff, 0xa9f, 0xa3f, 0x9df, 0x97f, 0x91f, 0x8bf, 0x85f, 0x7ff, 0x79f, 0x73f, 0x6df, 0x67f, 0x61f, 0x5bf, 0x55f, 0x4ff, 0x49f, 0x43f, 0x3df, 0x37f, 0x31f, 0x2bf, 0x25f, 0x1ff, 0x19f, 0x13f, 0xdf, 0x7f, 0x1f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
  71. #endif // AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID
  72. static dacsample_t dac_buffer_empty[AUDIO_DAC_BUFFER_SIZE] = {AUDIO_DAC_OFF_VALUE};
  73. /* keep track of the sample position for for each frequency */
  74. static float dac_if[AUDIO_MAX_SIMULTANEOUS_TONES] = {0.0};
  75. static float active_tones_snapshot[AUDIO_MAX_SIMULTANEOUS_TONES] = {0, 0};
  76. static uint8_t active_tones_snapshot_length = 0;
  77. typedef enum {
  78. OUTPUT_SHOULD_START,
  79. OUTPUT_RUN_NORMALLY,
  80. // path 1: wait for zero, then change/update active tones
  81. OUTPUT_TONES_CHANGED,
  82. OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE,
  83. // path 2: hardware should stop, wait for zero then turn output off = stop the timer
  84. OUTPUT_SHOULD_STOP,
  85. OUTPUT_REACHED_ZERO_BEFORE_OFF,
  86. OUTPUT_OFF,
  87. OUTPUT_OFF_1,
  88. OUTPUT_OFF_2, // trailing off: giving the DAC two more conversion cycles until the AUDIO_DAC_OFF_VALUE reaches the output, then turn the timer off, which leaves the output at that level
  89. number_of_output_states
  90. } output_states_t;
  91. output_states_t state = OUTPUT_OFF_2;
  92. /**
  93. * Generation of the waveform being passed to the callback. Declared weak so users
  94. * can override it with their own wave-forms/noises.
  95. */
  96. __attribute__((weak)) uint16_t dac_value_generate(void) {
  97. // DAC is running/asking for values but snapshot length is zero -> must be playing a pause
  98. if (active_tones_snapshot_length == 0) {
  99. return AUDIO_DAC_OFF_VALUE;
  100. }
  101. /* doing additive wave synthesis over all currently playing tones = adding up
  102. * sine-wave-samples for each frequency, scaled by the number of active tones
  103. */
  104. uint16_t value = 0;
  105. float frequency = 0.0f;
  106. for (uint8_t i = 0; i < active_tones_snapshot_length; i++) {
  107. /* Note: a user implementation does not have to rely on the active_tones_snapshot, but
  108. * could directly query the active frequencies through audio_get_processed_frequency */
  109. frequency = active_tones_snapshot[i];
  110. dac_if[i] = dac_if[i] + ((frequency * AUDIO_DAC_BUFFER_SIZE) / AUDIO_DAC_SAMPLE_RATE) * 2 / 3;
  111. /*Note: the 2/3 are necessary to get the correct frequencies on the
  112. * DAC output (as measured with an oscilloscope), since the gpt
  113. * timer runs with 3*AUDIO_DAC_SAMPLE_RATE; and the DAC callback
  114. * is called twice per conversion.*/
  115. dac_if[i] = fmod(dac_if[i], AUDIO_DAC_BUFFER_SIZE);
  116. // Wavetable generation/lookup
  117. uint16_t dac_i = (uint16_t)dac_if[i];
  118. #if defined(AUDIO_DAC_SAMPLE_WAVEFORM_SINE)
  119. value += dac_buffer_sine[dac_i] / active_tones_snapshot_length;
  120. #elif defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE)
  121. value += dac_buffer_triangle[dac_i] / active_tones_snapshot_length;
  122. #elif defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID)
  123. value += dac_buffer_trapezoid[dac_i] / active_tones_snapshot_length;
  124. #elif defined(AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE)
  125. value += dac_buffer_square[dac_i] / active_tones_snapshot_length;
  126. #endif
  127. /*
  128. // SINE
  129. value += dac_buffer_sine[dac_i] / active_tones_snapshot_length / 3;
  130. // TRIANGLE
  131. value += dac_buffer_triangle[dac_i] / active_tones_snapshot_length / 3;
  132. // SQUARE
  133. value += dac_buffer_square[dac_i] / active_tones_snapshot_length / 3;
  134. //NOTE: combination of these three wave-forms is more exemplary - and doesn't sound particularly good :-P
  135. */
  136. // STAIRS (mostly usefully as test-pattern)
  137. // value_avg = dac_buffer_staircase[dac_i] / active_tones_snapshot_length;
  138. }
  139. return value;
  140. }
  141. /**
  142. * DAC streaming callback. Does all of the main computing for playing songs.
  143. *
  144. * Note: chibios calls this CB twice: during the 'half buffer event', and the 'full buffer event'.
  145. */
  146. static void dac_end(DACDriver *dacp) {
  147. dacsample_t *sample_p = (dacp)->samples;
  148. // work on the other half of the buffer
  149. if (dacIsBufferComplete(dacp)) {
  150. sample_p += AUDIO_DAC_BUFFER_SIZE / 2; // 'half_index'
  151. }
  152. for (uint8_t s = 0; s < AUDIO_DAC_BUFFER_SIZE / 2; s++) {
  153. if (OUTPUT_OFF <= state) {
  154. sample_p[s] = AUDIO_DAC_OFF_VALUE;
  155. continue;
  156. } else {
  157. sample_p[s] = dac_value_generate();
  158. }
  159. /* zero crossing (or approach, whereas zero == DAC_OFF_VALUE, which can be configured to anything from 0 to DAC_SAMPLE_MAX)
  160. * ============================*=*========================== AUDIO_DAC_SAMPLE_MAX
  161. * * *
  162. * * *
  163. * ---------------------------------------------------------
  164. * * * } AUDIO_DAC_SAMPLE_MAX/100
  165. * --------------------------------------------------------- AUDIO_DAC_OFF_VALUE
  166. * * * } AUDIO_DAC_SAMPLE_MAX/100
  167. * ---------------------------------------------------------
  168. * *
  169. * * *
  170. * * *
  171. * =====*=*================================================= 0x0
  172. */
  173. if (((sample_p[s] + (AUDIO_DAC_SAMPLE_MAX / 100)) > AUDIO_DAC_OFF_VALUE) && // value approaches from below
  174. (sample_p[s] < (AUDIO_DAC_OFF_VALUE + (AUDIO_DAC_SAMPLE_MAX / 100))) // or above
  175. ) {
  176. if ((OUTPUT_SHOULD_START == state) && (active_tones_snapshot_length > 0)) {
  177. state = OUTPUT_RUN_NORMALLY;
  178. } else if (OUTPUT_TONES_CHANGED == state) {
  179. state = OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE;
  180. } else if (OUTPUT_SHOULD_STOP == state) {
  181. state = OUTPUT_REACHED_ZERO_BEFORE_OFF;
  182. }
  183. }
  184. // still 'ramping up', reset the output to OFF_VALUE until the generated values reach that value, to do a smooth handover
  185. if (OUTPUT_SHOULD_START == state) {
  186. sample_p[s] = AUDIO_DAC_OFF_VALUE;
  187. }
  188. if ((OUTPUT_SHOULD_START == state) || (OUTPUT_REACHED_ZERO_BEFORE_OFF == state) || (OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE == state)) {
  189. uint8_t active_tones = MIN(AUDIO_MAX_SIMULTANEOUS_TONES, audio_get_number_of_active_tones());
  190. active_tones_snapshot_length = 0;
  191. // update the snapshot - once, and only on occasion that something changed;
  192. // -> saves cpu cycles (?)
  193. for (uint8_t i = 0; i < active_tones; i++) {
  194. float freq = audio_get_processed_frequency(i);
  195. if (freq > 0) { // disregard 'rest' notes, with valid frequency 0.0f; which would only lower the resulting waveform volume during the additive synthesis step
  196. active_tones_snapshot[active_tones_snapshot_length++] = freq;
  197. }
  198. }
  199. if ((0 == active_tones_snapshot_length) && (OUTPUT_REACHED_ZERO_BEFORE_OFF == state)) {
  200. state = OUTPUT_OFF;
  201. }
  202. if (OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE == state) {
  203. state = OUTPUT_RUN_NORMALLY;
  204. }
  205. }
  206. }
  207. // update audio internal state (note position, current_note, ...)
  208. if (audio_update_state()) {
  209. if (OUTPUT_SHOULD_STOP != state) {
  210. state = OUTPUT_TONES_CHANGED;
  211. }
  212. }
  213. if (OUTPUT_OFF <= state) {
  214. if (OUTPUT_OFF_2 == state) {
  215. // stopping timer6 = stopping the DAC at whatever value it is currently pushing to the output = AUDIO_DAC_OFF_VALUE
  216. gptStopTimer(&GPTD6);
  217. } else {
  218. state++;
  219. }
  220. }
  221. }
  222. static void dac_error(DACDriver *dacp, dacerror_t err) {
  223. (void)dacp;
  224. (void)err;
  225. chSysHalt("DAC failure. halp");
  226. }
  227. static const GPTConfig gpt6cfg1 = {.frequency = AUDIO_DAC_SAMPLE_RATE * 3,
  228. .callback = NULL,
  229. .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */
  230. .dier = 0U};
  231. static const DACConfig dac_conf = {.init = AUDIO_DAC_OFF_VALUE, .datamode = DAC_DHRM_12BIT_RIGHT};
  232. /**
  233. * @note The DAC_TRG(0) here selects the Timer 6 TRGO event, which is triggered
  234. * on the rising edge after 3 APB1 clock cycles, causing our gpt6cfg1.frequency
  235. * to be a third of what we expect.
  236. *
  237. * Here are all the values for DAC_TRG (TSEL in the ref manual)
  238. * TIM15_TRGO 0b011
  239. * TIM2_TRGO 0b100
  240. * TIM3_TRGO 0b001
  241. * TIM6_TRGO 0b000
  242. * TIM7_TRGO 0b010
  243. * EXTI9 0b110
  244. * SWTRIG 0b111
  245. */
  246. static const DACConversionGroup dac_conv_cfg = {.num_channels = 1U, .end_cb = dac_end, .error_cb = dac_error, .trigger = DAC_TRG(0b000)};
  247. void audio_driver_initialize() {
  248. if ((AUDIO_PIN == A4) || (AUDIO_PIN_ALT == A4)) {
  249. palSetLineMode(A4, PAL_MODE_INPUT_ANALOG);
  250. dacStart(&DACD1, &dac_conf);
  251. }
  252. if ((AUDIO_PIN == A5) || (AUDIO_PIN_ALT == A5)) {
  253. palSetLineMode(A5, PAL_MODE_INPUT_ANALOG);
  254. dacStart(&DACD2, &dac_conf);
  255. }
  256. /* enable the output buffer, to directly drive external loads with no additional circuitry
  257. *
  258. * see: AN4566 Application note: Extending the DAC performance of STM32 microcontrollers
  259. * Note: Buffer-Off bit -> has to be set 0 to enable the output buffer
  260. * Note: enabling the output buffer imparts an additional dc-offset of a couple mV
  261. *
  262. * this is done here, reaching directly into the stm32 registers since chibios has not implemented BOFF handling yet
  263. * (see: chibios/os/hal/ports/STM32/todo.txt '- BOFF handling in DACv1.'
  264. */
  265. DACD1.params->dac->CR &= ~DAC_CR_BOFF1;
  266. DACD2.params->dac->CR &= ~DAC_CR_BOFF2;
  267. if (AUDIO_PIN == A4) {
  268. dacStartConversion(&DACD1, &dac_conv_cfg, dac_buffer_empty, AUDIO_DAC_BUFFER_SIZE);
  269. } else if (AUDIO_PIN == A5) {
  270. dacStartConversion(&DACD2, &dac_conv_cfg, dac_buffer_empty, AUDIO_DAC_BUFFER_SIZE);
  271. }
  272. // no inverted/out-of-phase waveform (yet?), only pulling AUDIO_PIN_ALT to AUDIO_DAC_OFF_VALUE
  273. #if defined(AUDIO_PIN_ALT_AS_NEGATIVE)
  274. if (AUDIO_PIN_ALT == A4) {
  275. dacPutChannelX(&DACD1, 0, AUDIO_DAC_OFF_VALUE);
  276. } else if (AUDIO_PIN_ALT == A5) {
  277. dacPutChannelX(&DACD2, 0, AUDIO_DAC_OFF_VALUE);
  278. }
  279. #endif
  280. gptStart(&GPTD6, &gpt6cfg1);
  281. }
  282. void audio_driver_stop(void) {
  283. state = OUTPUT_SHOULD_STOP;
  284. }
  285. void audio_driver_start(void) {
  286. gptStartContinuous(&GPTD6, 2U);
  287. for (uint8_t i = 0; i < AUDIO_MAX_SIMULTANEOUS_TONES; i++) {
  288. dac_if[i] = 0.0f;
  289. active_tones_snapshot[i] = 0.0f;
  290. }
  291. active_tones_snapshot_length = 0;
  292. state = OUTPUT_SHOULD_START;
  293. }