From 464a12a5679d431b148aea53bceba88b9414ad1f Mon Sep 17 00:00:00 2001 From: ShiningLea Date: Sat, 30 Dec 2023 12:42:33 +0100 Subject: [PATCH] Introduce internal equalizer baseline and band limit (#320) * Introduce internal equalizer baseline Signed-off-by: AnErrupTion * Add Arctis Nova 3 in README.md Signed-off-by: AnErrupTion * Add baseline and band limit to Arctis Nova Pro Wireless Signed-off-by: AnErrupTion --------- Signed-off-by: AnErrupTion --- README.md | 2 ++ src/dev.c | 8 +++--- src/device.h | 2 +- src/devices/steelseries_arctis_7_plus.c | 11 +++++++- src/devices/steelseries_arctis_nova_3.c | 11 +++++++- src/devices/steelseries_arctis_nova_7.c | 11 +++++++- .../steelseries_arctis_nova_pro_wireless.c | 11 +++++++- src/main.c | 8 +++--- src/utility.c | 28 +++++++++++++++---- src/utility.h | 14 +++++++++- 10 files changed, 86 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 97e2bfa..6b65501 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,8 @@ talking. This differs from a simple loopback via PulseAudio as you won't have an - Sidetone, Battery - SteelSeries Arctis 1, Arctis 1 for XBox - Sidetone, Battery, Inactive time +- SteelSeries Arctis Nova 3 + - Sidetone, Equalizer Presets, Equalizer, Microphone Mute LED Brightness, Microphone Volume - SteelSeries Arctis (7 and Pro) - Sidetone, Battery, Inactive time, Chat-Mix level, LED on/off (allows to turn off the blinking LED on the base-station) - SteelSeries Arctis 7+ diff --git a/src/dev.c b/src/dev.c index 487d150..35d35ec 100644 --- a/src/dev.c +++ b/src/dev.c @@ -173,8 +173,8 @@ int dev_main(int argc, char* argv[]) int print_deviceinfo = 0; #define BUFFERLENGTH 1024 - char* sendbuffer = calloc(BUFFERLENGTH, sizeof(char)); - char* sendreportbuffer = calloc(BUFFERLENGTH, sizeof(char)); + unsigned char* sendbuffer = calloc(BUFFERLENGTH, sizeof(char)); + unsigned char* sendreportbuffer = calloc(BUFFERLENGTH, sizeof(char)); unsigned char* receivebuffer = malloc(sizeof(char) * BUFFERLENGTH); unsigned char* receivereportbuffer = malloc(sizeof(char) * BUFFERLENGTH); @@ -240,7 +240,7 @@ int dev_main(int argc, char* argv[]) break; } case 's': { // --send string - int size = get_data_from_parameter(optarg, sendbuffer, BUFFERLENGTH); + int size = get_byte_data_from_parameter(optarg, sendbuffer, BUFFERLENGTH); if (size < 0) { fprintf(stderr, "Data to send larger than %d\n", BUFFERLENGTH); @@ -257,7 +257,7 @@ int dev_main(int argc, char* argv[]) break; } case 'f': { // --send-feature string - int size = get_data_from_parameter(optarg, sendreportbuffer, BUFFERLENGTH); + int size = get_byte_data_from_parameter(optarg, sendreportbuffer, BUFFERLENGTH); if (size < 0) { fprintf(stderr, "Data to send for feature report larger than %d\n", BUFFERLENGTH); diff --git a/src/device.h b/src/device.h index 9b13b0c..bcddc3d 100644 --- a/src/device.h +++ b/src/device.h @@ -68,7 +68,7 @@ struct equalizer_settings { /// The size of the bands array int size; /// The equalizer frequency bands values - char bands_values[]; + float bands_values[]; }; /** @brief Defines the basic data of a device diff --git a/src/devices/steelseries_arctis_7_plus.c b/src/devices/steelseries_arctis_7_plus.c index eabb3b2..747c77a 100644 --- a/src/devices/steelseries_arctis_7_plus.c +++ b/src/devices/steelseries_arctis_7_plus.c @@ -22,6 +22,9 @@ static struct device device_arctis; #define STATUS_BUF_SIZE 6 #define EQUALIZER_BANDS_SIZE 10 +#define EQUALIZER_BASELINE 0x18 +#define EQUALIZER_BAND_MIN -12 +#define EQUALIZER_BAND_MAX +12 static const uint16_t PRODUCT_IDS[] = { ID_ARCTIS_7_PLUS, ID_ARCTIS_7_PLUS_PS5, ID_ARCTIS_7_PLUS_XBOX, ID_ARCTIS_7_PLUS_DESTINY }; @@ -186,7 +189,13 @@ static int arctis_7_plus_send_equalizer(hid_device* device_handle, struct equali uint8_t data[MSG_SIZE] = { 0x0, 0x33 }; for (int i = 0; i < settings->size; i++) { - data[i + 2] = (uint8_t)settings->bands_values[i]; + float band_value = settings->bands_values[i]; + if (band_value < EQUALIZER_BAND_MIN || band_value > EQUALIZER_BAND_MAX) { + printf("Device only supports bands ranging from %d to %d.\n", EQUALIZER_BAND_MIN, EQUALIZER_BAND_MAX); + return HSC_OUT_OF_BOUNDS; + } + + data[i + 2] = (uint8_t)(EQUALIZER_BASELINE + 2 * band_value); } data[settings->size + 3] = 0x0; diff --git a/src/devices/steelseries_arctis_nova_3.c b/src/devices/steelseries_arctis_nova_3.c index 36b218d..ec28037 100644 --- a/src/devices/steelseries_arctis_nova_3.c +++ b/src/devices/steelseries_arctis_nova_3.c @@ -11,6 +11,9 @@ static struct device device_arctis; #define ID_ARCTIS_NOVA_3 0x12ec #define EQUALIZER_BANDS_SIZE 6 +#define EQUALIZER_BASELINE 0x14 +#define EQUALIZER_BAND_MIN -6 +#define EQUALIZER_BAND_MAX +6 static const uint16_t PRODUCT_IDS[] = { ID_ARCTIS_NOVA_3 }; static const uint8_t SAVE_DATA[MSG_SIZE] = { 0x06, 0x09 }; // Command to save settings to headset @@ -111,7 +114,13 @@ static int arctis_nova_3_send_equalizer(hid_device* device_handle, struct equali uint8_t data[MSG_SIZE] = { 0x06, 0x33 }; for (int i = 0; i < settings->size; i++) { - data[i + 2] = (uint8_t)settings->bands_values[i]; + float band_value = settings->bands_values[i]; + if (band_value < EQUALIZER_BAND_MIN || band_value > EQUALIZER_BAND_MAX) { + printf("Device only supports bands ranging from %d to %d.\n", EQUALIZER_BAND_MIN, EQUALIZER_BAND_MAX); + return HSC_OUT_OF_BOUNDS; + } + + data[i + 2] = (uint8_t)(EQUALIZER_BASELINE + 2 * band_value); } return hid_send_feature_report(device_handle, data, MSG_SIZE); diff --git a/src/devices/steelseries_arctis_nova_7.c b/src/devices/steelseries_arctis_nova_7.c index 341c4ae..e19cc28 100644 --- a/src/devices/steelseries_arctis_nova_7.c +++ b/src/devices/steelseries_arctis_nova_7.c @@ -22,6 +22,9 @@ static struct device device_arctis; #define STATUS_BUF_SIZE 8 #define EQUALIZER_BANDS_SIZE 10 +#define EQUALIZER_BASELINE 0x14 +#define EQUALIZER_BAND_MIN -10 +#define EQUALIZER_BAND_MAX +10 static const uint16_t PRODUCT_IDS[] = { ID_ARCTIS_NOVA_7, ID_ARCTIS_NOVA_7x, ID_ARCTIS_NOVA_7p, ID_ARCTIS_NOVA_7_DIABLO_IV }; @@ -188,7 +191,13 @@ static int arctis_nova_7_send_equalizer(hid_device* device_handle, struct equali uint8_t data[MSG_SIZE] = { 0x0, 0x33 }; for (int i = 0; i < settings->size; i++) { - data[i + 2] = (uint8_t)settings->bands_values[i]; + float band_value = settings->bands_values[i]; + if (band_value < EQUALIZER_BAND_MIN || band_value > EQUALIZER_BAND_MAX) { + printf("Device only supports bands ranging from %d to %d.\n", EQUALIZER_BAND_MIN, EQUALIZER_BAND_MAX); + return HSC_OUT_OF_BOUNDS; + } + + data[i + 2] = (uint8_t)(EQUALIZER_BASELINE + band_value); } data[settings->size + 3] = 0x0; diff --git a/src/devices/steelseries_arctis_nova_pro_wireless.c b/src/devices/steelseries_arctis_nova_pro_wireless.c index d2e4995..266478a 100644 --- a/src/devices/steelseries_arctis_nova_pro_wireless.c +++ b/src/devices/steelseries_arctis_nova_pro_wireless.c @@ -42,6 +42,9 @@ enum mic_mute_led_brightness { enum { EQUALIZER_PRESET_CUSTOM = 4, EQUALIZER_BANDS_SIZE = 10, + EQUALIZER_BASELINE = 0x14, + EQUALIZER_BAND_MIN = -10, + EQUALIZER_BAND_MAX = +10, }; static const uint16_t PRODUCT_IDS[] = { ID_ARCTIS_NOVA_PRO_WIRELESS_BASE_STATION }; @@ -194,7 +197,13 @@ static int set_equalizer(hid_device* device_handle, struct equalizer_settings* s uint8_t data[MSG_SIZE] = { 0x06, 0x33 }; for (int i = 0; i < settings->size; i++) { - data[i + 2] = (uint8_t)settings->bands_values[i]; + float band_value = settings->bands_values[i]; + if (band_value < EQUALIZER_BAND_MIN || band_value > EQUALIZER_BAND_MAX) { + printf("Device only supports bands ranging from %d to %d.\n", EQUALIZER_BAND_MIN, EQUALIZER_BAND_MAX); + return HSC_OUT_OF_BOUNDS; + } + + data[i + 2] = (uint8_t)(EQUALIZER_BASELINE + 2 * band_value); } return hid_write(device_handle, data, MSG_SIZE); diff --git a/src/main.c b/src/main.c index ecaa215..ae64f2a 100644 --- a/src/main.c +++ b/src/main.c @@ -310,7 +310,7 @@ int main(int argc, char* argv[]) struct equalizer_settings* equalizer = NULL; #define BUFFERLENGTH 1024 - char* read_buffer = calloc(BUFFERLENGTH, sizeof(char)); + float* read_buffer = calloc(BUFFERLENGTH, sizeof(float)); struct option opts[] = { { "battery", no_argument, NULL, 'b' }, @@ -350,7 +350,7 @@ int main(int argc, char* argv[]) short_output = 1; break; case 'e': { - int size = get_data_from_parameter(optarg, read_buffer, BUFFERLENGTH); + int size = get_float_data_from_parameter(optarg, read_buffer, BUFFERLENGTH); if (size < 0) { fprintf(stderr, "Equalizer bands values size larger than supported %d\n", BUFFERLENGTH); @@ -362,7 +362,7 @@ int main(int argc, char* argv[]) return 1; } - equalizer = malloc(sizeof(struct equalizer_settings) + size * sizeof(char)); + equalizer = malloc(sizeof(struct equalizer_settings) + size * sizeof(float)); equalizer->size = size; for (int i = 0; i < size; i++) { equalizer->bands_values[i] = read_buffer[i]; @@ -454,7 +454,7 @@ int main(int argc, char* argv[]) printf(" -m, --chatmix\t\t\tRetrieves the current chat-mix-dial level setting between 0 and 128. Below 64 is the game side and above is the chat side.\n"); printf(" -v, --voice-prompt 0|1\tTurn voice prompts on or off (0 = off, 1 = on)\n"); printf(" -r, --rotate-to-mute 0|1\tTurn rotate to mute feature on or off (0 = off, 1 = on)\n"); - printf(" -e, --equalizer string\tSets equalizer to specified curve, string must contain band values specific to the device (hex or decimal) delimited by spaces, or commas, or new-lines e.g \"0x18, 0x18, 0x18, 0x18, 0x18\".\n"); + printf(" -e, --equalizer string\tSets equalizer to specified curve, string must contain band values (hex or decimal), with minimum and maximum values specific to the device and delimited by spaces, or commas, or new-lines e.g \"0, 0, 0, 0, 0\".\n"); printf(" -p, --equalizer-preset number\tSets equalizer preset, number must be between 0 and 3, 0 sets the default\n"); printf(" --microphone-mute-led-brightness number\tSets microphone mute LED brightness, number must be between 0 and 3\n"); printf(" --microphone-volume number\tSets microphone volume, number must be between 0 and 128\n"); diff --git a/src/utility.c b/src/utility.c index 93524fc..eff591c 100644 --- a/src/utility.c +++ b/src/utility.c @@ -79,14 +79,10 @@ size_t hexdump(char* out, size_t out_size, unsigned char* data, size_t data_size return i; } -int get_data_from_parameter(char* input, char* dest, size_t len) +int get_byte_data_from_parameter(char* input, unsigned char* dest, size_t len) { const char* delim = " ,{}\n\r"; - size_t sz = strlen(input); - char* str = (char*)malloc(sz + 1); - strcpy(str, input); - // For each token in the string, parse and store in buf[]. char* token = strtok(input, delim); int i = 0; @@ -101,6 +97,26 @@ int get_data_from_parameter(char* input, char* dest, size_t len) token = strtok(NULL, delim); } - free(str); + return i; +} + +int get_float_data_from_parameter(char* input, float* dest, size_t len) +{ + const char* delim = " ,{}\n\r"; + + // For each token in the string, parse and store in buf[]. + char* token = strtok(input, delim); + int i = 0; + while (token) { + char* endptr; + float val = strtof(token, &endptr); + + if (i >= len) + return -1; + + dest[i++] = val; + token = strtok(NULL, delim); + } + return i; } \ No newline at end of file diff --git a/src/utility.h b/src/utility.h index 676e92b..710d387 100644 --- a/src/utility.h +++ b/src/utility.h @@ -73,4 +73,16 @@ size_t hexdump(char* out, size_t out_size, unsigned char* data, size_t data_size * @param len max dest length * @return int amount of data converted */ -int get_data_from_parameter(char* input, char* dest, size_t len); \ No newline at end of file +int get_byte_data_from_parameter(char* input, unsigned char* dest, size_t len); + +/** + * @brief Accepts textual input and converts them to a sendable buffer + * + * Parses data like "0xff, 123, 0xb" and converts them to an array of len 3 + * + * @param input string + * @param dest destination array + * @param len max dest length + * @return int amount of data converted + */ +int get_float_data_from_parameter(char* input, float* dest, size_t len); \ No newline at end of file