diff options
Diffstat (limited to 'examples/device/audio_test')
| -rw-r--r-- | examples/device/audio_test/CMakeLists.txt | 15 | ||||
| -rw-r--r-- | examples/device/audio_test/Makefile | 8 | ||||
| -rw-r--r-- | examples/device/audio_test/skip.txt | 1 | ||||
| -rw-r--r-- | examples/device/audio_test/src/main.c | 56 | ||||
| -rwxr-xr-x | examples/device/audio_test/src/plot_audio_samples.py | 50 | ||||
| -rw-r--r-- | examples/device/audio_test/src/tusb_config.h | 11 | ||||
| -rw-r--r-- | examples/device/audio_test/src/usb_descriptors.c | 28 |
7 files changed, 113 insertions, 56 deletions
diff --git a/examples/device/audio_test/CMakeLists.txt b/examples/device/audio_test/CMakeLists.txt index 6a7e68c3d..3382530c6 100644 --- a/examples/device/audio_test/CMakeLists.txt +++ b/examples/device/audio_test/CMakeLists.txt @@ -2,32 +2,29 @@ cmake_minimum_required(VERSION 3.20) include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake) -# gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>) -family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR}) - -project(${PROJECT} C CXX ASM) +project(audio_test C CXX ASM) # Checks this example is valid for the family and initializes the project -family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}) +family_initialize_project(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}) # Espressif has its own cmake build system if(FAMILY STREQUAL "espressif") return() endif() -add_executable(${PROJECT}) +add_executable(${PROJECT_NAME}) # Example source -target_sources(${PROJECT} PUBLIC +target_sources(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c ) # Example include -target_include_directories(${PROJECT} PUBLIC +target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src ) # Configure compilation flags and libraries for the example without RTOS. # See the corresponding function in hw/bsp/FAMILY/family.cmake for details. -family_configure_device_example(${PROJECT} noos) +family_configure_device_example(${PROJECT_NAME} noos) diff --git a/examples/device/audio_test/Makefile b/examples/device/audio_test/Makefile index 7fa475da5..035e90308 100644 --- a/examples/device/audio_test/Makefile +++ b/examples/device/audio_test/Makefile @@ -1,11 +1,11 @@ -include ../../build_system/make/make.mk +include ../../../hw/bsp/family_support.mk INC += \ src \ - $(TOP)/hw \ + # Example source EXAMPLE_SOURCE += $(wildcard src/*.c) -SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE)) +SRC_C += $(addprefix $(EXAMPLE_PATH)/, $(EXAMPLE_SOURCE)) -include ../../build_system/make/rules.mk +include ../../../hw/bsp/family_rules.mk diff --git a/examples/device/audio_test/skip.txt b/examples/device/audio_test/skip.txt index 65b137814..42394bb11 100644 --- a/examples/device/audio_test/skip.txt +++ b/examples/device/audio_test/skip.txt @@ -2,3 +2,4 @@ mcu:SAMD11 mcu:SAME5X mcu:SAMG family:espressif +mcu:CH583 diff --git a/examples/device/audio_test/src/main.c b/examples/device/audio_test/src/main.c index 5b3beec24..876a41d06 100644 --- a/examples/device/audio_test/src/main.c +++ b/examples/device/audio_test/src/main.c @@ -63,8 +63,8 @@ uint32_t sampFreq; uint8_t clkValid; // Range states -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 +audio20_control_range_2_n_t(1) volumeRng[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1];// Volume range state +audio20_control_range_4_n_t(1) sampleFreqRng; // Sample frequency range state // Audio test data uint16_t test_buffer_audio[CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE / 1000 * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX / 2]; @@ -138,8 +138,10 @@ void tud_resume_cb(void) { // In a real application, this would be replaced with actual I2S receive callback. void audio_task(void) { static uint32_t start_ms = 0; - uint32_t curr_ms = board_millis(); - if (start_ms == curr_ms) return;// not enough time + uint32_t curr_ms = tusb_time_millis_api(); + if (start_ms == curr_ms) { + return; // not enough time + } start_ms = curr_ms; for (size_t cnt = 0; cnt < sizeof(test_buffer_audio) / 2; cnt++) { test_buffer_audio[cnt] = startVal++; @@ -157,7 +159,7 @@ bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const *p_req (void) pBuff; // We do not support any set range requests here, only current value requests - TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR); + TU_VERIFY(p_request->bRequest == AUDIO20_CS_REQ_CUR); // Page 91 in UAC2 specification uint8_t channelNum = TU_U16_LOW(p_request->wValue); @@ -177,7 +179,7 @@ bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const *p_re (void) pBuff; // We do not support any set range requests here, only current value requests - TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR); + TU_VERIFY(p_request->bRequest == AUDIO20_CS_REQ_CUR); // Page 91 in UAC2 specification uint8_t channelNum = TU_U16_LOW(p_request->wValue); @@ -204,25 +206,25 @@ bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p (void) itf; // We do not support any set range requests here, only current value requests - TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR); + TU_VERIFY(p_request->bRequest == AUDIO20_CS_REQ_CUR); // If request is for our feature unit if (entityID == 2) { switch (ctrlSel) { - case AUDIO_FU_CTRL_MUTE: + case AUDIO20_FU_CTRL_MUTE: // Request uses format layout 1 - TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_1_t)); + TU_VERIFY(p_request->wLength == sizeof(audio20_control_cur_1_t)); - mute[channelNum] = ((audio_control_cur_1_t *) pBuff)->bCur; + mute[channelNum] = ((audio20_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: + case AUDIO20_FU_CTRL_VOLUME: // Request uses format layout 2 - TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_2_t)); + TU_VERIFY(p_request->wLength == sizeof(audio20_control_cur_2_t)); - volume[channelNum] = (uint16_t) ((audio_control_cur_2_t *) pBuff)->bCur; + volume[channelNum] = (uint16_t) ((audio20_control_cur_2_t *) pBuff)->bCur; TU_LOG2(" Set Volume: %d dB of channel: %u\r\n", volume[channelNum], channelNum); return true; @@ -283,13 +285,13 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p // Input terminal (Microphone input) if (entityID == 1) { switch (ctrlSel) { - case AUDIO_TE_CTRL_CONNECTOR: { + case AUDIO20_TE_CTRL_CONNECTOR: { // The terminal connector control only has a get request with only the CUR attribute. - audio_desc_channel_cluster_t ret; + audio20_desc_channel_cluster_t ret; // Those are dummy values for now ret.bNrChannels = 1; - ret.bmChannelConfig = (audio_channel_config_t) 0; + ret.bmChannelConfig = (audio20_channel_config_t) 0; ret.iChannelNames = 0; TU_LOG2(" Get terminal connector\r\n"); @@ -307,23 +309,23 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p // Feature unit if (entityID == 2) { switch (ctrlSel) { - case AUDIO_FU_CTRL_MUTE: + case AUDIO20_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_audio_buffer_and_schedule_control_xfer(rhport, p_request, &mute[channelNum], 1); - case AUDIO_FU_CTRL_VOLUME: + case AUDIO20_FU_CTRL_VOLUME: switch (p_request->bRequest) { - case AUDIO_CS_REQ_CUR: + case AUDIO20_CS_REQ_CUR: TU_LOG2(" Get Volume of channel: %u\r\n", channelNum); return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &volume[channelNum], sizeof(volume[channelNum])); - case AUDIO_CS_REQ_RANGE: + case AUDIO20_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) + audio20_control_range_2_n_t(1) ret; ret.wNumSubRanges = 1; @@ -350,14 +352,14 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p // Clock Source unit if (entityID == 4) { switch (ctrlSel) { - case AUDIO_CS_CTRL_SAM_FREQ: + case AUDIO20_CS_CTRL_SAM_FREQ: // channelNum is always zero in this case switch (p_request->bRequest) { - case AUDIO_CS_REQ_CUR: + case AUDIO20_CS_REQ_CUR: TU_LOG2(" Get Sample Freq.\r\n"); return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &sampFreq, sizeof(sampFreq)); - case AUDIO_CS_REQ_RANGE: + case AUDIO20_CS_REQ_RANGE: TU_LOG2(" Get Sample Freq. range\r\n"); return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &sampleFreqRng, sizeof(sampleFreqRng)); @@ -368,7 +370,7 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p } break; - case AUDIO_CS_CTRL_CLK_VALID: + case AUDIO20_CS_CTRL_CLK_VALID: // Only cur attribute exists for this request TU_LOG2(" Get Sample Freq. valid\r\n"); return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &clkValid, sizeof(clkValid)); @@ -400,7 +402,9 @@ void led_blinking_task(void) { static bool led_state = false; // Blink every interval ms - if (board_millis() - start_ms < blink_interval_ms) return;// not enough time + if (tusb_time_millis_api() - start_ms < blink_interval_ms) { + return; // not enough time + } start_ms += blink_interval_ms; board_led_write(led_state); diff --git a/examples/device/audio_test/src/plot_audio_samples.py b/examples/device/audio_test/src/plot_audio_samples.py index 2be8948ea..af01b7b3e 100755 --- a/examples/device/audio_test/src/plot_audio_samples.py +++ b/examples/device/audio_test/src/plot_audio_samples.py @@ -5,6 +5,52 @@ import numpy as np import platform import csv + +def find_windows_input_device(name_hint, channels, preferred_apis=None): + """Pick a Windows input device index from query_devices() output.""" + preferred_apis = preferred_apis or [] + name_hint = name_hint.lower() + candidates = [] + + for index in range(len(sd.query_devices())): + device_info = sd.query_devices(index) + max_input_channels = int(device_info.get('max_input_channels', 0)) + + if max_input_channels < channels: + continue + + device_name = str(device_info.get('name', '')).lower() + if name_hint not in device_name: + continue + + score = 0 + + # Prefer exact channel matches (for example 1ch source over a 4ch source). + if max_input_channels == channels: + score += 100 + else: + score += 10 + + hostapi_index = int(device_info.get('hostapi', -1)) + api_name = '' + if hostapi_index >= 0: + hostapi_info = sd.query_hostapis(hostapi_index) + api_name = str(hostapi_info.get('name', '')).lower() + + for priority, api_hint in enumerate(preferred_apis): + if api_hint in api_name: + score += 50 - priority + break + + candidates.append((score, index)) + + if not candidates: + raise ValueError( + 'No input device matching hint="{}" with at least {} channels'.format(name_hint, channels) + ) + + return max(candidates, key=lambda item: item[0])[1] + if __name__ == '__main__': # If you got "ValueError: No input device matching", that is because your PC name example device @@ -15,8 +61,8 @@ if __name__ == '__main__': duration = 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), Windows WASAPI' + # Match by substring to support names like "Microphone (2- MicNode)". + device = find_windows_input_device('micnode', channels=1, preferred_apis=['wasapi', 'mme', 'wdm-ks']) elif platform.system() == 'Darwin': device = 'MicNode' else: diff --git a/examples/device/audio_test/src/tusb_config.h b/examples/device/audio_test/src/tusb_config.h index 10bf53809..e311d892f 100644 --- a/examples/device/audio_test/src/tusb_config.h +++ b/examples/device/audio_test/src/tusb_config.h @@ -23,8 +23,8 @@ * */ -#ifndef _TUSB_CONFIG_H_ -#define _TUSB_CONFIG_H_ +#ifndef TUSB_CONFIG_H_ +#define TUSB_CONFIG_H_ #ifdef __cplusplus extern "C" { @@ -108,13 +108,10 @@ extern "C" { // Have a look into audio_device.h for all configurations #define CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE 48000 -#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_MIC_ONE_CH_DESC_LEN -#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64 // Size of control request buffer - #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 TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX) +#define CFG_TUD_AUDIO_EP_SZ_IN TUD_AUDIO_EP_SIZE(TUD_OPT_HIGH_SPEED, CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX) #define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX CFG_TUD_AUDIO_EP_SZ_IN #define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ (TUD_OPT_HIGH_SPEED ? 32 : 4) * CFG_TUD_AUDIO_EP_SZ_IN // Example write FIFO every 1ms, so it should be 8 times larger for HS device @@ -122,4 +119,4 @@ extern "C" { } #endif -#endif /* _TUSB_CONFIG_H_ */ +#endif /* TUSB_CONFIG_H_ */ diff --git a/examples/device/audio_test/src/usb_descriptors.c b/examples/device/audio_test/src/usb_descriptors.c index 9864377f6..cea4eb8d1 100644 --- a/examples/device/audio_test/src/usb_descriptors.c +++ b/examples/device/audio_test/src/usb_descriptors.c @@ -32,14 +32,14 @@ * Auto ProductID layout's Bitmap: * [MSB] AUDIO | MIDI | HID | MSC | CDC [LSB] */ -#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) ) -#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \ - _PID_MAP(MIDI, 3) | _PID_MAP(AUDIO, 4) | _PID_MAP(VENDOR, 5) ) +#define PID_MAP(itf, n) ((CFG_TUD_##itf) ? (1 << (n)) : 0) +#define USB_PID (0x4000 | PID_MAP(CDC, 0) | PID_MAP(MSC, 1) | PID_MAP(HID, 2) | \ + PID_MAP(MIDI, 3) | PID_MAP(AUDIO, 4) | PID_MAP(VENDOR, 5) ) //--------------------------------------------------------------------+ // Device Descriptors //--------------------------------------------------------------------+ -tusb_desc_device_t const desc_device = +static tusb_desc_device_t const desc_device = { .bLength = sizeof(tusb_desc_device_t), .bDescriptorType = TUSB_DESC_DEVICE, @@ -80,7 +80,7 @@ enum ITF_NUM_TOTAL }; -#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_AUDIO * TUD_AUDIO_MIC_ONE_CH_DESC_LEN) +#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_AUDIO * TUD_AUDIO20_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 @@ -91,6 +91,14 @@ enum // nRF5x ISO can only be endpoint 8 #define EPNUM_AUDIO 0x08 +#elif TU_CHECK_MCU(OPT_MCU_MAX32650, OPT_MCU_MAX32666, OPT_MCU_MAX32690, OPT_MCU_MAX78002) + // Put audio iso on EP>=8 so the 2048/4096-byte FIFOs can back double packet buffering + #define EPNUM_AUDIO 0x0A + +#elif TU_CHECK_MCU(OPT_MCU_CH32V20X, OPT_MCU_CH32V307) + // Only EP3 is available for ISO + #define EPNUM_AUDIO 0x03 + #else #define EPNUM_AUDIO 0x01 #endif @@ -101,7 +109,7 @@ uint8_t const desc_configuration[] = TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), // Interface number, string index, EP Out & EP In address, EP size - 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) + TUD_AUDIO20_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 @@ -158,14 +166,18 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors. // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors - if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL; + if (!(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0]))) { + return NULL; + } const char *str = string_desc_arr[index]; // Cap at max char chr_count = strlen(str); size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type - if ( chr_count > max_count ) chr_count = max_count; + if (chr_count > max_count) { + chr_count = max_count; + } // Convert ASCII string into UTF-16 for ( size_t i = 0; i < chr_count; i++ ) { |
