Files
3d_audio/lib_xua/host_usb_mixer_control/mixer_app.cpp
Steven Dan d8b2974133 init
2025-12-11 09:43:42 +08:00

763 lines
21 KiB
C++

// Copyright 2022-2024 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#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<usb_get_aud_channel_map_num_outputs();i++)
{
int x = usb_get_aud_channel_map(i);
printf("%d (DEVICE OUT - %s) source is ",i, usb_get_aud_channel_map_name(i));
switch (usb_get_aud_channel_map_type(x))
{
case USB_CHAN_OUT:
printf(" %d (DAW OUT - %s)\n",x,usb_get_aud_channel_map_name(x));
break;
case USB_CHAN_IN:
printf("%d (DEVICE IN - %s)\n",x,usb_get_aud_channel_map_name(x));
break;
case USB_CHAN_MIXER:
printf("%d (%s)\n",x,usb_get_aud_channel_map_name(x));
break;
}
}
}
void display_daw_channel_map()
{
printf("\n");
printf(" DAW Output To Host Channel Map\n");
printf(" ------------------------\n\n");
for (int i=0;i<usb_get_usb_channel_map_num_outputs();i++)
{
int x = usb_get_usb_channel_map(i);
printf("%d (DAW IN - %s) source is ",i, usb_get_usb_channel_map_name(i + usb_get_aud_channel_map_num_outputs()));
switch (usb_get_usb_channel_map_type(x))
{
case USB_CHAN_OUT:
printf(" %d (DAW OUT - %s)\n",x,usb_get_usb_channel_map_name(x));
break;
case USB_CHAN_IN:
printf("%d (DEVICE IN - %s)\n",x,usb_get_usb_channel_map_name(x));
break;
case USB_CHAN_MIXER:
printf("%d (%s)\n",x,usb_get_usb_channel_map_name(x));
break;
}
}
}
void display_aud_channel_map_sources(void)
{
printf("\n");
printf(" Audio Output Channel Map Source List\n");
printf(" ------------------------------------\n\n");
for (int i=0;i<usb_get_aud_channel_map_num_inputs();i++) {
switch (usb_get_aud_channel_map_type(i))
{
case USB_CHAN_OUT:
printf("%d (DAW OUT - %s)\n",i,usb_get_aud_channel_map_name(i));
break;
case USB_CHAN_IN:
printf("%d (DEVICE IN - %s)\n",i,usb_get_aud_channel_map_name(i));
break;
case USB_CHAN_MIXER:
printf("%d (%s)\n",i,usb_get_aud_channel_map_name(i));
break;
}
}
}
void display_daw_channel_map_sources(void)
{
printf("\n");
printf(" DAW Output to Host Channel Map Source List\n");
printf(" ------------------------------------------\n\n");
for (int i=0;i<usb_get_usb_channel_map_num_inputs();i++) {
switch (usb_get_usb_channel_map_type(i))
{
case USB_CHAN_OUT:
printf("%d (DAW OUT - %s)\n",i,usb_get_usb_channel_map_name(i));
break;
case USB_CHAN_IN:
printf("%d (DEVICE IN - %s)\n",i,usb_get_usb_channel_map_name(i));
break;
case USB_CHAN_MIXER:
printf("%d (%s)\n",i,usb_get_usb_channel_map_name(i));
break;
}
}
}
int usb_audio_request_get(unsigned bRequest, unsigned cs, unsigned cn, unsigned unitId, unsigned char *data)
{
char reqStr[] = "Custom";
if(bRequest == CUR)
{
strcpy(reqStr, "CUR");
}
else if(bRequest == RANGE)
{
strcpy(reqStr, "RANGE");
}
else if(bRequest == MEM)
{
strcpy(reqStr, "MEM");
}
printf("Performing class GET request to Audio Interface:\n\
bRequest: 0x%02x (%s)\n\
wValue: 0x%04x (Control Sel: %d, Channel Number: %d)\n\
wIndex: 0x%04x (Interface: 0, Entity: %d)\n\
\n", bRequest, reqStr, (cs<<8)|cn, cs, cn, unitId<<8, unitId);
return usb_audio_class_get(bRequest, cs, cn, unitId, 64, data);
}
int usb_audio_request_set(unsigned bRequest, unsigned cs, unsigned cn, unsigned unitId,
unsigned char *data, int datalength)
{
char reqStr[] = "Custom";
if(bRequest == CUR)
{
strcpy(reqStr, "CUR");
}
else if(bRequest == RANGE)
{
strcpy(reqStr, "RANGE");
}
{
strcpy(reqStr, "MEM");
}
printf("Performing class SET request to Audio Interface:\n\
bRequest: 0x%02x (%s)\n\
wValue: 0x%04x (Control Sel: %d, Channel Number: %d)\n\
wIndex: 0x%04x (Interface: 0, Entity: %d)\n\
\n", bRequest, reqStr, (cs<<8)|cn, cs, cn, unitId<<8, unitId);
return usb_audio_class_set(bRequest, cs, cn, unitId, datalength, data);
}
int usb_audio_memreq_get(unsigned unitId, unsigned offset, unsigned char *data)
{
/* Mem requests dont have CS/CN, just an offset.. */
return usb_audio_request_get(MEM, (offset>>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<levelCount; i++)
{
printf("%s %d: 0x%04x\n", levelTitle, i,levelData[i]);
}
}
void mixer_display_usage(void) {
fprintf(stderr, "Usage: xmos_mixer "
#ifdef _WIN32
"-g<GUID> "
#endif
"<options>\n");
fprintf(stderr,
#ifdef _WIN32
" -g<GUID> 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;
}