// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #include #include #include #include "usb_mixer.h" #define MIXER_UNIT_DISPLAY_VALUE 2 #define MIXER_UNIT_DISPLAY_MIN 3 #define MIXER_UNIT_DISPLAY_MAX 4 #define MIXER_UNIT_DISPLAY_RES 5 // TODO // res, min, max #ifdef _WIN32 int mixer_init(TCHAR guid[GUID_STR_LEN]) #else int mixer_init(void) #endif { #ifdef _WIN32 int ret = usb_mixer_connect(guid); #else int ret = usb_mixer_connect(); #endif /* Open the connection to the USB mixer */ if (ret == USB_MIXER_FAILURE) { return USB_MIXER_FAILURE; } return USB_MIXER_SUCCESS; } int mixer_deinit(void) { // Close the connection to the USB mixer if (usb_mixer_disconnect() == USB_MIXER_FAILURE) { return USB_MIXER_FAILURE; } return USB_MIXER_SUCCESS; } int mixer_display(unsigned int mixer_index, unsigned int type) { int i = 0; int j = 0; int num_inputs = usb_mixer_get_num_inputs(mixer_index); int num_outputs = usb_mixer_get_num_outputs(mixer_index); printf("\n"); switch (type) { case MIXER_UNIT_DISPLAY_VALUE: //mixer_update_all_values(mixer_index); printf(" Mixer Values (%d)\n", mixer_index); printf(" ----------------\n\n"); break; case MIXER_UNIT_DISPLAY_MIN: printf(" Mixer Ranges Min (%d)\n", mixer_index); printf(" --------------------\n\n"); break; case MIXER_UNIT_DISPLAY_MAX: printf(" Mixer Ranges Max (%d)\n", mixer_index); printf(" --------------------\n\n"); break; case MIXER_UNIT_DISPLAY_RES: printf(" Mixer Ranges Res (%d)\n", mixer_index); printf(" --------------------\n\n"); break; default: return USB_MIXER_FAILURE; break; } printf(" \t\t\t"); printf("Mixer Outputs\n"); printf("\t\t "); for (i = 0; i < num_outputs; i++) { printf(" %d", i+1); } printf("\n"); for (i = 0; i < num_inputs; i++) { printf(" %-20s", usb_mixer_get_input_name(mixer_index,i)); for (j = 0; j < num_outputs; j++) { switch (type) { case MIXER_UNIT_DISPLAY_VALUE: { double mixNodeVal = usb_mixer_get_value(mixer_index, (i*num_outputs)+j); int nodeid = (i*num_outputs)+j; if (mixNodeVal <= -127.996)// todo shoud be < min { printf("\t%3d:[ %s ]", nodeid,"-inf"); } else { printf("\t%3d:[%08.03f]", nodeid, mixNodeVal); } } break; case MIXER_UNIT_DISPLAY_MIN: { int nodeid = (i*num_outputs)+j; printf("\t%3d:[%08.03f]", nodeid, usb_mixer_get_min(mixer_index, (i*num_outputs)+j)) ; } break; case MIXER_UNIT_DISPLAY_MAX: { int nodeid = (i*num_outputs)+j; printf("\t%3d:[%08.03f]", nodeid, usb_mixer_get_max(mixer_index, (i*num_outputs)+j)) ; } break; case MIXER_UNIT_DISPLAY_RES: { int nodeid = (i*num_outputs)+j; printf("\t%3d:[%08.03f]", nodeid, usb_mixer_get_res(mixer_index, (i*num_outputs)+j)) ; } break; default: return USB_MIXER_FAILURE; break; } } printf("\n"); } printf("\n"); return USB_MIXER_SUCCESS; } /* Displays basic mixer information */ int mixer_display_info(void) { unsigned int i = 0; int num_mixers = usb_mixer_get_num_mixers(); printf("\n"); printf(" Mixer Info\n"); printf(" ----------\n\n"); printf(" Mixers : %d\n\n", num_mixers); for (i = 0; i < num_mixers; i++) { int num_inputs = usb_mixer_get_num_inputs(i); int num_outputs = usb_mixer_get_num_outputs(i); printf(" Mixer %d\n", i); printf(" -------\n"); printf(" Inputs : %d\n" " Outputs : %d\n\n", num_inputs, num_outputs); printf(" Mixer Output Labels:\n"); for(int j = 0; j < num_outputs; j++) { printf(" %d: %s\n", j,usb_mixer_get_output_name(i,j)); } //printf("\n Selectable Inputs (%d): \n", usb_mixsel_get_input_count(i)); //for(int j = 0; j < usb_mixsel_get_input_count(i); j++) //{ // printf(" %d: %s\n", j, usb_mixsel_get_input_string(i,j)); //} } printf("\n"); return USB_MIXER_SUCCESS; } void display_available_mixer_sources(int mixIndex) { printf("\n"); printf(" Available Mixer Sources (%d)\n", mixIndex); printf(" -------------------------\n\n"); for(int j = 0; j < usb_mixsel_get_input_count(mixIndex); j++) { printf(" %d: %s\n", j, usb_mixsel_get_input_string(mixIndex,j)); } } /* Gets the current mixer inputs from the device an displays them */ void display_mixer_sources(int mixerIndex) { printf("\n"); printf(" Current Mixer Sources (%d)\n", mixerIndex); printf(" -------------------------\n\n"); /* Note, mixSel output cound and mixer input chan count should be the same! */ printf(" Number of mixer sources: %d\n", usb_mixsel_get_output_count(mixerIndex)); /* Get the current channel number for every mixer input */ for(int i = 0; i < usb_mixsel_get_output_count(mixerIndex); i++) { int inputChan = (int)usb_mixsel_get_state(mixerIndex, i); char *str = usb_mixer_get_input_name(mixerIndex,inputChan); printf(" Mixer input %d: Source chan id: %d (%s)\n", i, inputChan, str); } } /* set mixer source */ void set_mixer_source(unsigned mixerIndex, unsigned dst, unsigned src) { usb_mixsel_set_state(mixerIndex, dst, src); /* String lookup */ char *str = usb_mixer_get_input_name(mixerIndex, dst); int state = usb_mixsel_get_state(mixerIndex, dst); printf("\n Set mixer(%d) input %d to device input %d (%s)\n", mixerIndex, dst, state, str); } void display_aud_channel_map() { printf("\n"); printf(" Audio Output Channel Map\n"); printf(" ------------------------\n\n"); for (int i=0;i>8), offset&0xff, unitId, data); } void print_levels(const char* levelTitle, unsigned char* levels, int levelBytes) { unsigned levelCount = levelBytes/2; unsigned short* levelData = (unsigned short*) levels; printf("\n %s Level Data\n" " ----------------------\n\n" "%d bytes (%d channels) returned:\n" , levelTitle, levelBytes, levelCount); for(int i = 0; i " #endif "\n"); fprintf(stderr, #ifdef _WIN32 " -g Driver GUID string, eg. -g{E5A2658B-817D-4A02-A1DE-B628A93DDF5D}\n" #endif " --display-info\n" " --display-mixer-nodes mixer_id\n" " --display-min mixer_id\n" " --display-max mixer_id\n" " --display-res mixer_id\n" " --set-value mixer_id, mixer_node, value\n" " --get-value mixer_id, mixer_node\n" "\n" " --set-mixer-source mixer_id dst channel_id, src_channel_id\n" " --display-current-mixer-sources mixer_id\n" " --display-available-mixer-sources mixer_id\n" "\n" " --set-aud-channel-map dst_channel_id, src_channel_id\n" " --display-aud-channel-map \n" " --display-aud-channel-map-sources\n" " --set-daw-channel-map dst_channel_id, src_channel_id\n" " --display-daw-channel-map \n" " --display-daw-channel-map-sources\n" "\n" " --get-mixer-levels-input mixer_id\n" " --get-mixer-levels-output mixer_id\n" " --vendor-audio-request-get bRequest, ControlSelector, ChannelNumber, UnitId\n" " --vendor-audio-request-set bRequest, ControlSelector, ChannelNumber, UnitId, Data[0], Data[1],...\n" ); } void usage_error() { fprintf(stderr, "ERROR :: incorrect number of arguments passed. See --help\n"); } int main (int argc, char **argv) { unsigned int mixer_index = 0; unsigned int result = 0; int min_argc; // arg_idx is the position in the arguments to start parsing to skip the "-g" GUID option on Windows int arg_idx; #ifdef _WIN32 // Driver GUID string is required on Windows min_argc = 3; arg_idx = 2; #else min_argc = 2; arg_idx = 1; #endif if (argc < min_argc) { fprintf(stderr, "ERROR :: No options passed to mixer application\n"); mixer_display_usage(); return -1; } #ifdef _WIN32 TCHAR driver_guid[GUID_STR_LEN]; if (strncmp(argv[1], "-g", 2) == 0) { swprintf(driver_guid, GUID_STR_LEN, L"%hs", argv[1]+2); } else { fprintf(stderr, "ERROR :: First option must be driver GUID\n"); return -1; } #endif if (strcmp(argv[1], "--help") == 0) { mixer_display_usage(); return 0; } #ifdef _WIN32 int ret = mixer_init(driver_guid); #else int ret = mixer_init(); #endif if (ret != USB_MIXER_SUCCESS) { fprintf(stderr, "ERROR :: Cannot connect\n"); return -1; } if (strcmp(argv[arg_idx], "--display-info") == 0) { mixer_display_info(); } else if (strcmp(argv[arg_idx], "--display-mixer-nodes") == 0) { if (argv[arg_idx+1]) { mixer_index = atoi(argv[arg_idx+1]); } else { fprintf(stderr, "ERROR :: No mixer index supplied\n"); return -1; } mixer_display(mixer_index, MIXER_UNIT_DISPLAY_VALUE); } else if (strcmp(argv[arg_idx], "--display-mixer-nodes") == 0) { if (argv[2]) { mixer_index = atoi(argv[arg_idx+1]); } else { fprintf(stderr, "ERROR :: No mixer index supplied\n"); return -1; } mixer_display(mixer_index, MIXER_UNIT_DISPLAY_VALUE); } else if (strcmp(argv[arg_idx], "--display-min") == 0) { if (argv[arg_idx+1]) { mixer_index = atoi(argv[arg_idx+1]); } else { fprintf(stderr, "ERROR :: No mixer index supplied\n"); return -1; } mixer_display(mixer_index, MIXER_UNIT_DISPLAY_MIN); } else if (strcmp(argv[arg_idx], "--display-max") == 0) { if (argv[arg_idx+1]) { mixer_index = atoi(argv[arg_idx+1]); } else { fprintf(stderr, "ERROR :: No mixer index supplied\n"); return -1; } mixer_display(mixer_index, MIXER_UNIT_DISPLAY_MAX); } else if (strcmp(argv[arg_idx], "--display-res") == 0) { if (argv[arg_idx+1]) { mixer_index = atoi(argv[arg_idx+1]); } else { fprintf(stderr, "ERROR :: No mixer index supplied\n"); return -1; } mixer_display(mixer_index, MIXER_UNIT_DISPLAY_RES); } else if (strcmp(argv[arg_idx], "--set-value") == 0) { unsigned int mixer_unit = 0; double value = 0; if (argc - arg_idx < 4) { fprintf(stderr, "ERROR :: incorrect number of arguments passed\n"); return -1; } mixer_index = atoi(argv[arg_idx+1]); mixer_unit = atoi(argv[arg_idx+2]); if (strcmp(argv[arg_idx+3],"-inf")==0) value = -128; else value = atof(argv[arg_idx+3]); usb_mixer_set_value(mixer_index, mixer_unit, value); } else if (strcmp(argv[arg_idx], "--get-value") == 0) { unsigned int mixer_unit = 0; double result = 0; if (argc - arg_idx < 3) { fprintf(stderr, "ERROR :: incorrect number of arguments passed\n"); return -1; } mixer_index = atoi(argv[arg_idx+1]); mixer_unit = atoi(argv[arg_idx+2]); result = usb_mixer_get_value(mixer_index, mixer_unit); if (result <= -127.996) printf("%s\n", "-inf"); else printf("%g\n",result); } else if (strcmp(argv[arg_idx], "--display-current-mixer-sources") == 0) { if(argc - arg_idx < 2) { usage_error(); return -1; } display_mixer_sources(atoi(argv[arg_idx+1])); } else if (strcmp(argv[arg_idx], "--display-available-mixer-sources") == 0) { if(argc - arg_idx < 2) { usage_error(); return -1; } display_available_mixer_sources(atoi(argv[arg_idx+1])); } else if(strcmp(argv[arg_idx], "--set-mixer-source") == 0) { if(argc - arg_idx < 4) { usage_error(); return -1; } set_mixer_source(atoi(argv[arg_idx+1]), atoi(argv[arg_idx+2]), atoi(argv[arg_idx+3])); } else if (strcmp(argv[arg_idx], "--display-aud-channel-map") == 0) { /* Display the channel mapping to the devices audio outputs */ display_aud_channel_map(); } else if (strcmp(argv[arg_idx], "--display-aud-channel-map-sources") == 0) { display_aud_channel_map_sources(); } else if (strcmp(argv[arg_idx], "--display-daw-channel-map") == 0) { /* Display the channel mapping to the devices DAW output to host */ display_daw_channel_map(); } else if (strcmp(argv[arg_idx], "--display-daw-channel-map-sources") == 0) { display_daw_channel_map_sources(); } else if (strcmp(argv[arg_idx], "--set-aud-channel-map") == 0) { unsigned int dst = 0; unsigned int src = 0; if (argc - arg_idx != 3) { usage_error(); return -1; } dst = atoi(argv[arg_idx+1]); src = atoi(argv[arg_idx+2]); usb_set_aud_channel_map(dst, src); } else if (strcmp(argv[arg_idx], "--set-daw-channel-map") == 0) { unsigned int dst = 0; unsigned int src = 0; if (argc - arg_idx != 3) { usage_error(); return -1; } dst = atoi(argv[arg_idx+1]); src = atoi(argv[arg_idx+2]); usb_set_usb_channel_map(dst, src); } else if(strcmp(argv[arg_idx], "--get-mixer-levels-input") == 0 || strcmp(argv[arg_idx],"--get-mixer-levels-output") == 0) { unsigned int dst = 0; unsigned char levels[64]; int datalength = 0; int offset = 0; if (argc - arg_idx < 2) { fprintf(stderr, "ERROR :: incorrect number of arguments passed\n"); return -1; } if(strcmp(argv[arg_idx],"--get-mixer-levels-output") == 0) offset = 1; for(int i = 0; i < 64; i++) levels[i] = 0; dst = atoi(argv[arg_idx+1]); /* Mem request to mixer with offset of 0 gives input levels */ datalength = usb_mixer_mem_get(dst, offset, levels); if(datalength < 0) { fprintf(stderr, "ERROR in control request: %d\n", datalength); return -1; } if(offset) print_levels("Mixer Output", levels, datalength); else print_levels("Mixer Input", levels, datalength); } else if(strcmp(argv[arg_idx], "--vendor-audio-request-get") == 0) { unsigned int bRequest = 0; unsigned int cs = 0; unsigned int cn = 0; unsigned int unitId = 0; int datalength = 0; unsigned char data[64]; if(argc - arg_idx < 5) { fprintf(stderr, "ERROR :: incorrect number of arguments passed\n"); return -1; } for(int i = 0; i < 64; i++) data[i] = 0; bRequest = atoi(argv[arg_idx+1]); cs = atoi(argv[arg_idx+2]); cn = atoi(argv[arg_idx+3]); unitId = atoi(argv[arg_idx+4]); /* Do request */ datalength = usb_audio_request_get(bRequest, cs, cn, unitId, data); /* Print result */ if(datalength < 0) { fprintf(stderr, "ERROR in control request: %d\n", datalength); } else { printf("Response (%d bytes):\n", datalength); for(int i = 0; i < datalength; i++) printf("0x%02x\n" ,data[i]); } } else if(strcmp(argv[arg_idx], "--vendor-audio-request-set") == 0) { unsigned int bRequest = 0; unsigned int cs = 0; unsigned int cn = 0; unsigned int unitId = 0; unsigned char data[64]; for(int i=0; i<64; i++) { data[i] = 0; } if(argc - arg_idx < 6) { fprintf(stderr, "ERROR :: incorrect number of arguments passed - no data passed\n"); return -1; } bRequest = atoi(argv[arg_idx+1]); cs = atoi(argv[arg_idx+2]); cn = atoi(argv[arg_idx+3]); unitId = atoi(argv[arg_idx+4]); /* Get data */ for(int i=0; i < argc-arg_idx-5; i++) { data[i] = atoi(argv[i+arg_idx+5]); } result = usb_audio_request_set(bRequest, cs, cn, unitId, data, argc-arg_idx-5); if(result < 0) { fprintf(stderr, "ERROR :: Error detected in Set request: %d\n", result); return -1; } } else { fprintf(stderr, "ERROR :: Invalid option passed to mixer application\n"); return -1; } mixer_deinit(); return result; }