Teensy 4.1 core updated for C++20
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

208 lines
6.3KB

  1. /* Teensyduino Core Library
  2. * http://www.pjrc.com/teensy/
  3. * Copyright (c) 2016 PJRC.COM, LLC.
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining
  6. * a copy of this software and associated documentation files (the
  7. * "Software"), to deal in the Software without restriction, including
  8. * without limitation the rights to use, copy, modify, merge, publish,
  9. * distribute, sublicense, and/or sell copies of the Software, and to
  10. * permit persons to whom the Software is furnished to do so, subject to
  11. * the following conditions:
  12. *
  13. * 1. The above copyright notice and this permission notice shall be
  14. * included in all copies or substantial portions of the Software.
  15. *
  16. * 2. If the Software is incorporated into a build system that allows
  17. * selection among a list of target devices, then similar target
  18. * devices manufactured by PJRC.COM must be included in the list of
  19. * target devices and selectable in the same manner.
  20. *
  21. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  22. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  23. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  24. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  25. * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  26. * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  27. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  28. * SOFTWARE.
  29. */
  30. #include "usb_audio.h"
  31. #include "HardwareSerial.h"
  32. #include <string.h> // for memcpy()
  33. #ifdef AUDIO_INTERFACE // defined by usb_dev.h -> usb_desc.h
  34. #if F_CPU >= 20000000
  35. bool AudioInputUSB::update_responsibility;
  36. audio_block_t * AudioInputUSB::incoming_left;
  37. audio_block_t * AudioInputUSB::incoming_right;
  38. audio_block_t * AudioInputUSB::ready_left;
  39. audio_block_t * AudioInputUSB::ready_right;
  40. uint16_t AudioInputUSB::incoming_count;
  41. uint8_t AudioInputUSB::underflow_flag;
  42. #define DMABUFATTR __attribute__ ((section(".dmabuffers"), aligned (4)))
  43. uint16_t usb_audio_receive_buffer[AUDIO_RX_SIZE/2] DMABUFATTR;
  44. uint16_t usb_audio_transmit_buffer[AUDIO_TX_SIZE/2] DMABUFATTR;
  45. uint32_t usb_audio_sync_feedback DMABUFATTR;
  46. void AudioInputUSB::begin(void)
  47. {
  48. incoming_count = 0;
  49. incoming_left = NULL;
  50. incoming_right = NULL;
  51. ready_left = NULL;
  52. ready_right = NULL;
  53. underflow_flag = 1;
  54. // update_responsibility = update_setup();
  55. // TODO: update responsibility is tough, partly because the USB
  56. // interrupts aren't sychronous to the audio library block size,
  57. // but also because the PC may stop transmitting data, which
  58. // means we no longer get receive callbacks from usb_dev.
  59. update_responsibility = false;
  60. usb_audio_sync_feedback = 722824;
  61. usb_audio_sync_feedback = 723700; // too fast?
  62. //usb_audio_sync_feedback = 722534; // too slow
  63. }
  64. static void copy_to_buffers(const uint32_t *src, int16_t *left, int16_t *right, unsigned int len)
  65. {
  66. // TODO: optimize...
  67. while (len > 0) {
  68. uint32_t n = *src++;
  69. *left++ = n & 0xFFFF;
  70. *right++ = n >> 16;
  71. len--;
  72. }
  73. }
  74. // Called from the USB interrupt when an isochronous packet arrives
  75. // we must completely remove it from the receive buffer before returning
  76. //
  77. void usb_audio_receive_callback(unsigned int len)
  78. {
  79. unsigned int count, avail;
  80. audio_block_t *left, *right;
  81. const uint32_t *data;
  82. len >>= 2; // 1 sample = 4 bytes: 2 left, 2 right
  83. data = (const uint32_t *)usb_audio_receive_buffer;
  84. //serial_print(".");
  85. //serial_phex(usb_audio_receive_buffer[0]);
  86. count = AudioInputUSB::incoming_count;
  87. left = AudioInputUSB::incoming_left;
  88. right = AudioInputUSB::incoming_right;
  89. if (left == NULL) {
  90. left = AudioStream::allocate();
  91. if (left == NULL) return;
  92. AudioInputUSB::incoming_left = left;
  93. }
  94. if (right == NULL) {
  95. right = AudioStream::allocate();
  96. if (right == NULL) return;
  97. AudioInputUSB::incoming_right = right;
  98. }
  99. while (len > 0) {
  100. avail = AUDIO_BLOCK_SAMPLES - count;
  101. if (len < avail) {
  102. //serial_print(".");
  103. copy_to_buffers(data, left->data + count, right->data + count, len);
  104. AudioInputUSB::incoming_count = count + len;
  105. return;
  106. } else if (avail > 0) {
  107. //serial_print("^");
  108. copy_to_buffers(data, left->data + count, right->data + count, avail);
  109. data += avail;
  110. len -= avail;
  111. if (AudioInputUSB::ready_left || AudioInputUSB::ready_right) {
  112. // buffer overrun, PC sending too fast
  113. AudioInputUSB::incoming_count = count + avail;
  114. serial_print("!");
  115. return;
  116. }
  117. send:
  118. AudioInputUSB::ready_left = left;
  119. AudioInputUSB::ready_right = right;
  120. //if (AudioInputUSB::update_responsibility) AudioStream::update_all();
  121. left = AudioStream::allocate();
  122. if (left == NULL) {
  123. AudioInputUSB::incoming_left = NULL;
  124. AudioInputUSB::incoming_right = NULL;
  125. AudioInputUSB::incoming_count = 0;
  126. return;
  127. }
  128. right = AudioStream::allocate();
  129. if (right == NULL) {
  130. AudioStream::release(left);
  131. AudioInputUSB::incoming_left = NULL;
  132. AudioInputUSB::incoming_right = NULL;
  133. AudioInputUSB::incoming_count = 0;
  134. return;
  135. }
  136. AudioInputUSB::incoming_left = left;
  137. AudioInputUSB::incoming_right = right;
  138. if (AudioInputUSB::underflow_flag) {
  139. AudioInputUSB::underflow_flag = 0;
  140. memset(left->data + count, 0, AUDIO_BLOCK_SAMPLES);
  141. memset(right->data + count, 0, AUDIO_BLOCK_SAMPLES);
  142. count = AUDIO_BLOCK_SAMPLES/2;
  143. serial_print("*");
  144. } else {
  145. count = 0;
  146. }
  147. } else {
  148. if (AudioInputUSB::ready_left || AudioInputUSB::ready_right) return;
  149. goto send; // recover from buffer overrun
  150. }
  151. }
  152. AudioInputUSB::incoming_count = count;
  153. }
  154. void AudioInputUSB::update(void)
  155. {
  156. audio_block_t *left, *right;
  157. __disable_irq();
  158. left = ready_left;
  159. ready_left = NULL;
  160. right = ready_right;
  161. ready_right = NULL;
  162. // TODO: use incoming_count for USB isochronous feedback
  163. uint16_t c = incoming_count;
  164. __enable_irq();
  165. //serial_phex(c);
  166. //serial_print(".");
  167. if (!left || !right) {
  168. underflow_flag = 1;
  169. serial_print("#"); // buffer underrun - PC sending too slow
  170. }
  171. if (left) {
  172. transmit(left, 0);
  173. release(left);
  174. }
  175. if (right) {
  176. transmit(right, 1);
  177. release(right);
  178. }
  179. }
  180. // Called from the USB interrupt when ready to transmit another
  181. // isochronous packet. If we place data into the transmit buffer,
  182. // the return is the number of bytes. Otherwise, return 0 means
  183. // no data to transmit
  184. unsigned int usb_audio_transmit_callback(void)
  185. {
  186. return 0;
  187. }
  188. #endif // F_CPU
  189. #endif // AUDIO_INTERFACE