summaryrefslogtreecommitdiff
path: root/examples/device/audio_test/src
diff options
context:
space:
mode:
authorHa Thach <[email protected]>2021-04-16 01:59:47 +0700
committerGitHub <[email protected]>2021-04-16 01:59:47 +0700
commitc611199632b9288eff76c1c4bfdce5d8cc024748 (patch)
tree8ccd5c0b34b4f1eb89276fce866ee34a9ff608e1 /examples/device/audio_test/src
parent93dffba0ac905d8525c3092a52888e1a5db96390 (diff)
parentc7e4a8616640165b48cfb0ba4f9346982faa4344 (diff)
Merge pull request #593 from hathach/edpt_ISO_xfer
Edpt iso xfer
Diffstat (limited to 'examples/device/audio_test/src')
-rw-r--r--examples/device/audio_test/src/main.c164
-rw-r--r--examples/device/audio_test/src/plot_audio_samples.py34
-rw-r--r--examples/device/audio_test/src/tusb_config.h27
-rw-r--r--examples/device/audio_test/src/usb_descriptors.c11
4 files changed, 140 insertions, 96 deletions
diff --git a/examples/device/audio_test/src/main.c b/examples/device/audio_test/src/main.c
index 7f0ce3652..9a2fdd3a1 100644
--- a/examples/device/audio_test/src/main.c
+++ b/examples/device/audio_test/src/main.c
@@ -23,6 +23,14 @@
*
*/
+/* plot_audio_samples.py requires following modules:
+ * $ sudo apt install libportaudio
+ * $ pip3 install sounddevice matplotlib
+ *
+ * Then run
+ * $ python3 plot_audio_samples.py
+ */
+
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -34,6 +42,10 @@
// MACRO CONSTANT TYPEDEF PROTYPES
//--------------------------------------------------------------------+
+#ifndef AUDIO_SAMPLE_RATE
+#define AUDIO_SAMPLE_RATE 48000
+#endif
+
/* Blink pattern
* - 250 ms : device not mounted
* - 1000 ms : device mounted
@@ -49,17 +61,17 @@ static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED;
// Audio controls
// Current states
-bool mute[CFG_TUD_AUDIO_N_CHANNELS_TX + 1]; // +1 for master channel 0
-uint16_t volume[CFG_TUD_AUDIO_N_CHANNELS_TX + 1]; // +1 for master channel 0
+bool mute[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1]; // +1 for master channel 0
+uint16_t volume[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1]; // +1 for master channel 0
uint32_t sampFreq;
uint8_t clkValid;
// Range states
-audio_control_range_2_n_t(1) volumeRng[CFG_TUD_AUDIO_N_CHANNELS_TX+1]; // Volume range state
+audio_control_range_2_n_t(1) volumeRng[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX+1]; // Volume range state
audio_control_range_4_n_t(1) sampleFreqRng; // Sample frequency range state
// Audio test data
-uint16_t test_buffer_audio[CFG_TUD_AUDIO_TX_FIFO_SIZE/2];
+uint16_t test_buffer_audio[CFG_TUD_AUDIO_EP_SZ_IN/2];
uint16_t startVal = 0;
void led_blinking_task(void);
@@ -73,12 +85,12 @@ int main(void)
tusb_init();
// Init values
- sampFreq = 44100;
+ sampFreq = AUDIO_SAMPLE_RATE;
clkValid = 1;
sampleFreqRng.wNumSubRanges = 1;
- sampleFreqRng.subrange[0].bMin = 44100;
- sampleFreqRng.subrange[0].bMax = 44100;
+ sampleFreqRng.subrange[0].bMin = AUDIO_SAMPLE_RATE;
+ sampleFreqRng.subrange[0].bMax = AUDIO_SAMPLE_RATE;
sampleFreqRng.subrange[0].bRes = 0;
while (1)
@@ -203,7 +215,6 @@ bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *
mute[channelNum] = ((audio_control_cur_1_t*) pBuff)->bCur;
TU_LOG2(" Set Mute: %d of channel: %u\r\n", mute[channelNum], channelNum);
-
return true;
case AUDIO_FU_CTRL_VOLUME:
@@ -213,8 +224,7 @@ bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *
volume[channelNum] = ((audio_control_cur_2_t*) pBuff)->bCur;
TU_LOG2(" Set Volume: %d dB of channel: %u\r\n", volume[channelNum], channelNum);
-
- return true;
+ return true;
// Unknown/Unsupported control
default:
@@ -271,96 +281,110 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *
// Input terminal (Microphone input)
if (entityID == 1)
{
- switch (ctrlSel)
+ switch ( ctrlSel )
{
- case AUDIO_TE_CTRL_CONNECTOR:;
- // The terminal connector control only has a get request with only the CUR attribute.
+ case AUDIO_TE_CTRL_CONNECTOR:
+ {
+ // The terminal connector control only has a get request with only the CUR attribute.
+ audio_desc_channel_cluster_t ret;
- audio_desc_channel_cluster_t ret;
+ // Those are dummy values for now
+ ret.bNrChannels = 1;
+ ret.bmChannelConfig = 0;
+ ret.iChannelNames = 0;
- // Those are dummy values for now
- ret.bNrChannels = 1;
- ret.bmChannelConfig = 0;
- ret.iChannelNames = 0;
+ TU_LOG2(" Get terminal connector\r\n");
- TU_LOG2(" Get terminal connector\r\n");
+ return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, (void*) &ret, sizeof(ret));
+ }
+ break;
- return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, (void*)&ret, sizeof(ret));
-
- // Unknown/Unsupported control selector
- default: TU_BREAKPOINT(); return false;
+ // Unknown/Unsupported control selector
+ default:
+ TU_BREAKPOINT();
+ return false;
}
}
// Feature unit
if (entityID == 2)
{
- switch (ctrlSel)
+ switch ( ctrlSel )
{
case AUDIO_FU_CTRL_MUTE:
- // Audio control mute cur parameter block consists of only one byte - we thus can send it right away
- // There does not exist a range parameter block for mute
- TU_LOG2(" Get Mute of channel: %u\r\n", channelNum);
- return tud_control_xfer(rhport, p_request, &mute[channelNum], 1);
+ // Audio control mute cur parameter block consists of only one byte - we thus can send it right away
+ // There does not exist a range parameter block for mute
+ TU_LOG2(" Get Mute of channel: %u\r\n", channelNum);
+ return tud_control_xfer(rhport, p_request, &mute[channelNum], 1);
case AUDIO_FU_CTRL_VOLUME:
+ switch ( p_request->bRequest )
+ {
+ case AUDIO_CS_REQ_CUR:
+ TU_LOG2(" Get Volume of channel: %u\r\n", channelNum);
+ return tud_control_xfer(rhport, p_request, &volume[channelNum], sizeof(volume[channelNum]));
- switch (p_request->bRequest)
- {
- case AUDIO_CS_REQ_CUR:
- TU_LOG2(" Get Volume of channel: %u\r\n", channelNum);
- return tud_control_xfer(rhport, p_request, &volume[channelNum], sizeof(volume[channelNum]));
- case AUDIO_CS_REQ_RANGE:
- TU_LOG2(" Get Volume range of channel: %u\r\n", channelNum);
+ case AUDIO_CS_REQ_RANGE:
+ TU_LOG2(" Get Volume range of channel: %u\r\n", channelNum);
- // Copy values - only for testing - better is version below
- audio_control_range_2_n_t(1) ret;
+ // Copy values - only for testing - better is version below
+ audio_control_range_2_n_t(1)
+ ret;
- ret.wNumSubRanges = 1;
- ret.subrange[0].bMin = -90; // -90 dB
- ret.subrange[0].bMax = 90; // +90 dB
- ret.subrange[0].bRes = 1; // 1 dB steps
+ ret.wNumSubRanges = 1;
+ ret.subrange[0].bMin = -90; // -90 dB
+ ret.subrange[0].bMax = 90; // +90 dB
+ ret.subrange[0].bRes = 1; // 1 dB steps
- return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, (void*)&ret, sizeof(ret));
+ return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, (void*) &ret, sizeof(ret));
- // Unknown/Unsupported control
- default: TU_BREAKPOINT(); return false;
- }
+ // Unknown/Unsupported control
+ default:
+ TU_BREAKPOINT();
+ return false;
+ }
+ break;
- // Unknown/Unsupported control
- default: TU_BREAKPOINT(); return false;
+ // Unknown/Unsupported control
+ default:
+ TU_BREAKPOINT();
+ return false;
}
}
// Clock Source unit
- if (entityID == 4)
+ if ( entityID == 4 )
{
- switch (ctrlSel)
+ switch ( ctrlSel )
{
case AUDIO_CS_CTRL_SAM_FREQ:
+ // channelNum is always zero in this case
+ switch ( p_request->bRequest )
+ {
+ case AUDIO_CS_REQ_CUR:
+ TU_LOG2(" Get Sample Freq.\r\n");
+ return tud_control_xfer(rhport, p_request, &sampFreq, sizeof(sampFreq));
- // channelNum is always zero in this case
-
- switch (p_request->bRequest)
- {
- case AUDIO_CS_REQ_CUR:
- TU_LOG2(" Get Sample Freq.\r\n");
- return tud_control_xfer(rhport, p_request, &sampFreq, sizeof(sampFreq));
- case AUDIO_CS_REQ_RANGE:
- TU_LOG2(" Get Sample Freq. range\r\n");
- return tud_control_xfer(rhport, p_request, &sampleFreqRng, sizeof(sampleFreqRng));
+ case AUDIO_CS_REQ_RANGE:
+ TU_LOG2(" Get Sample Freq. range\r\n");
+ return tud_control_xfer(rhport, p_request, &sampleFreqRng, sizeof(sampleFreqRng));
- // Unknown/Unsupported control
- default: TU_BREAKPOINT(); return false;
- }
+ // Unknown/Unsupported control
+ default:
+ TU_BREAKPOINT();
+ return false;
+ }
+ break;
- case AUDIO_CS_CTRL_CLK_VALID:
- // Only cur attribute exists for this request
- TU_LOG2(" Get Sample Freq. valid\r\n");
- return tud_control_xfer(rhport, p_request, &clkValid, sizeof(clkValid));
+ case AUDIO_CS_CTRL_CLK_VALID:
+ // Only cur attribute exists for this request
+ TU_LOG2(" Get Sample Freq. valid\r\n");
+ return tud_control_xfer(rhport, p_request, &clkValid, sizeof(clkValid));
- // Unknown/Unsupported control
- default: TU_BREAKPOINT(); return false;
+ // Unknown/Unsupported control
+ default:
+ TU_BREAKPOINT();
+ return false;
}
}
@@ -375,7 +399,7 @@ bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t itf, uint8_t ep_in, u
(void) ep_in;
(void) cur_alt_setting;
- tud_audio_write ((uint8_t *)test_buffer_audio, CFG_TUD_AUDIO_TX_FIFO_SIZE);
+ tud_audio_write ((uint8_t *)test_buffer_audio, CFG_TUD_AUDIO_EP_SZ_IN);
return true;
}
@@ -388,7 +412,7 @@ bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied, uin
(void) ep_in;
(void) cur_alt_setting;
- for (size_t cnt = 0; cnt < CFG_TUD_AUDIO_TX_FIFO_SIZE/2; cnt++)
+ for (size_t cnt = 0; cnt < CFG_TUD_AUDIO_EP_SZ_IN/2; cnt++)
{
test_buffer_audio[cnt] = startVal++;
}
diff --git a/examples/device/audio_test/src/plot_audio_samples.py b/examples/device/audio_test/src/plot_audio_samples.py
new file mode 100644
index 000000000..6e3c4978e
--- /dev/null
+++ b/examples/device/audio_test/src/plot_audio_samples.py
@@ -0,0 +1,34 @@
+import sounddevice as sd
+import matplotlib.pyplot as plt
+import numpy as np
+import platform
+
+if __name__ == '__main__':
+
+ # If you got "ValueError: No input device matching", that is because your PC name example device
+ # differently from tested list below. Uncomment the next line to see full list and try to pick correct one
+ # print(sd.query_devices())
+
+ fs = 48000 # Sample rate
+ duration = 100e-3 # Duration of recording
+
+ if platform.system() == 'Windows':
+ # MME is needed since there are more than one MicNode device APIs (at least in Windows)
+ device = 'Microphone (MicNode) MME'
+ elif platform.system() == 'Darwin':
+ device = 'MicNode'
+ else:
+ device ='default'
+
+ myrecording = sd.rec(int(duration * fs), samplerate=fs, channels=1, dtype='int16', device=device)
+ print('Waiting...')
+ sd.wait() # Wait until recording is finished
+ print('Done!')
+
+ time = np.arange(0, duration, 1 / fs) # time vector
+ plt.plot(time, myrecording)
+ plt.xlabel('Time [s]')
+ plt.ylabel('Amplitude')
+ plt.title('MicNode')
+ plt.show()
+ \ No newline at end of file
diff --git a/examples/device/audio_test/src/tusb_config.h b/examples/device/audio_test/src/tusb_config.h
index 61e63f073..683a1a567 100644
--- a/examples/device/audio_test/src/tusb_config.h
+++ b/examples/device/audio_test/src/tusb_config.h
@@ -91,25 +91,18 @@ extern "C" {
// AUDIO CLASS DRIVER CONFIGURATION
//--------------------------------------------------------------------
-// Audio format type
-#define CFG_TUD_AUDIO_USE_TX_FIFO 1
-#define CFG_TUD_AUDIO_FORMAT_TYPE_TX AUDIO_FORMAT_TYPE_I
-#define CFG_TUD_AUDIO_FORMAT_TYPE_RX AUDIO_FORMAT_TYPE_UNDEFINED
+// Have a look into audio_device.h for all configurations
-// Audio format type I specifications
-#define CFG_TUD_AUDIO_FORMAT_TYPE_I_TX AUDIO_DATA_FORMAT_TYPE_I_PCM
-#define CFG_TUD_AUDIO_N_CHANNELS_TX 1
-#define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX 2
+#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_MIC_ONE_CH_DESC_LEN
+#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 1 // Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes)
+#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64 // Size of control request buffer
-// EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense)
-#define CFG_TUD_AUDIO_EPSIZE_IN 48*CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX*CFG_TUD_AUDIO_N_CHANNELS_TX // 48 Samples (48 kHz) x 2 Bytes/Sample x 1 Channels
-#define CFG_TUD_AUDIO_TX_FIFO_SIZE 48*2 // 48 Samples (48 kHz) x 2 Bytes/Sample (1/2 word)
-
-// Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes)
-#define CFG_TUD_AUDIO_N_AS_INT 1
-
-// Size of control request buffer
-#define CFG_TUD_AUDIO_CTRL_BUF_SIZE 64
+#define CFG_TUD_AUDIO_ENABLE_EP_IN 1
+#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX 2 // Driver gets this info from the descriptors - we define it here to use it to setup the descriptors and to do calculations with it below
+#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 1 // Driver gets this info from the descriptors - we define it here to use it to setup the descriptors and to do calculations with it below - be aware: for different number of channels you need another descriptor!
+#define CFG_TUD_AUDIO_EP_SZ_IN 48 * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX // 48 Samples (48 kHz) x 2 Bytes/Sample x 1 Channel
+#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX CFG_TUD_AUDIO_EP_SZ_IN // Maximum EP IN size for all AS alternate settings used
+#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ CFG_TUD_AUDIO_EP_SZ_IN + 1
#ifdef __cplusplus
}
diff --git a/examples/device/audio_test/src/usb_descriptors.c b/examples/device/audio_test/src/usb_descriptors.c
index 02d018823..67dd34d2a 100644
--- a/examples/device/audio_test/src/usb_descriptors.c
+++ b/examples/device/audio_test/src/usb_descriptors.c
@@ -79,7 +79,7 @@ enum
ITF_NUM_TOTAL
};
-#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_AUDIO * TUD_AUDIO_MIC_DESC_LEN)
+#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_AUDIO * TUD_AUDIO_MIC_ONE_CH_DESC_LEN)
#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX
// LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
@@ -89,20 +89,13 @@ enum
#define EPNUM_AUDIO 0x01
#endif
-// These variables are required by the audio driver in audio_device.c
-
-// List of audio descriptor lengths which is required by audio driver - you need as many entries as CFG_TUD_AUDIO - unfortunately this is not possible to determine otherwise
-const uint16_t tud_audio_desc_lengths[] = {TUD_AUDIO_MIC_DESC_LEN};
-
-// TAKE CARE - THE NUMBER OF AUDIO STREAMING INTERFACES PER AUDIO FUNCTION MUST NOT EXCEED CFG_TUD_AUDIO_N_AS_INT - IF IT DOES INCREASE CFG_TUD_AUDIO_N_AS_INT IN tusb_config.h!
-
uint8_t const desc_configuration[] =
{
// Interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
// Interface number, string index, EP Out & EP In address, EP size
- TUD_AUDIO_MIC_DESCRIPTOR(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_stridx*/ 0, /*_nBytesPerSample*/ 3, /*_nBitsUsedPerSample*/ 24, /*_epin*/ 0x80 | EPNUM_AUDIO, /*_epsize*/ 48*4)
+ TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_stridx*/ 0, /*_nBytesPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, /*_nBitsUsedPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX*8, /*_epin*/ 0x80 | EPNUM_AUDIO, /*_epsize*/ CFG_TUD_AUDIO_EP_SZ_IN)
};
// Invoked when received GET CONFIGURATION DESCRIPTOR