Skip to content

Commit

Permalink
Added equalizer info for artico nova pro wireless, artic nova 3, arti…
Browse files Browse the repository at this point in the history
…c nova 7 plus

Fix a crash caused by get_float_data_from_parameter() function and added allocatioo and deallocation for equalizer bands_values

Added Bands step for equalizer info; changed equlalizer preset values type; added equalizer info and refactor in steelseries_artic_nova_7.c

Added equalizer and equalizer preset output  json info
  • Loading branch information
nicola02nb authored and Sapd committed Jul 22, 2024
1 parent b340ebc commit 38cd8b9
Show file tree
Hide file tree
Showing 11 changed files with 159 additions and 28 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ cmake-build-debug/

.vscode/*
*.code-workspace
*.cache/

.DS_Store
24 changes: 23 additions & 1 deletion src/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,24 @@ typedef struct {
enum microphone_status microphone_status;
} BatteryInfo;

typedef struct {
int bands_count;
int bands_baseline;
float bands_step;
int bands_min;
int bands_max;
} EqualizerInfo;

typedef struct {
char* name;
float* values;
} EqualizerPreset;

typedef struct {
int count;
EqualizerPreset presets[];
} EqualizerPresets;

enum headsetcontrol_errors {
HSC_ERROR = -100,
HSC_READ_TIMEOUT = -101,
Expand Down Expand Up @@ -128,7 +146,7 @@ struct equalizer_settings {
/// The size of the bands array
int size;
/// The equalizer frequency bands values
float bands_values[];
float* bands_values;
};

/** @brief Defines the basic data of a device
Expand All @@ -148,6 +166,10 @@ struct device {
/// Name of device, used as information for the user
char device_name[64];

// Equalizer Infos
EqualizerInfo* equalizer;
EqualizerPresets* eqaulizer_presets;

wchar_t device_hid_vendorname[64];
wchar_t device_hid_productname[64];

Expand Down
19 changes: 18 additions & 1 deletion src/devices/headsetcontrol_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,22 @@ static struct device device_headsetcontrol_test;

#define TESTBYTES_SEND 32

static const uint16_t PRODUCT_IDS[] = { PRODUCT_TESTDEVICE };
#define EQUALIZER_BANDS_COUNT 10
#define EQUALIZER_BASELINE 0
#define EQUALIZER_STEP 0.5
#define EQUALIZER_BAND_MIN -10
#define EQUALIZER_BAND_MAX +10
#define EQUALIZER_PRESETS_COUNT 2

static const uint16_t PRODUCT_IDS[] = { PRODUCT_TESTDEVICE };
static EqualizerInfo EQUALIZER = { EQUALIZER_BANDS_COUNT, EQUALIZER_BASELINE, EQUALIZER_STEP, EQUALIZER_BAND_MIN, EQUALIZER_BAND_MAX };
static float preset_flat[EQUALIZER_BANDS_COUNT] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static float preset_random[EQUALIZER_BANDS_COUNT] = { 6, -8, 1.5, 7, -1, -7.5, -9, 0, 9, 10 };
static EqualizerPresets EQUALIZER_PRESETS = {
EQUALIZER_PRESETS_COUNT,
{ { "flat", preset_flat },
{ "random", preset_random } }
};

static int headsetcontrol_test_send_sidetone(hid_device* device_handle, uint8_t num);
static BatteryInfo headsetcontrol_test_request_battery(hid_device* device_handle);
Expand Down Expand Up @@ -39,6 +54,8 @@ void headsetcontrol_test_init(struct device** device)
device_headsetcontrol_test.idVendor = VENDOR_TESTDEVICE;
device_headsetcontrol_test.idProductsSupported = PRODUCT_IDS;
device_headsetcontrol_test.numIdProducts = 1;
device_headsetcontrol_test.equalizer = &EQUALIZER;
device_headsetcontrol_test.eqaulizer_presets = &EQUALIZER_PRESETS;

strncpy(device_headsetcontrol_test.device_name, "HeadsetControl Test device", sizeof(device_headsetcontrol_test.device_name));
// normally filled by hid in main.c
Expand Down
2 changes: 2 additions & 0 deletions src/devices/steelseries_arctis_7_plus.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ static struct device device_arctis;
#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 };
static EqualizerInfo EQUALIZER = { EQUALIZER_BANDS_SIZE, 0, 0.5, EQUALIZER_BAND_MIN, EQUALIZER_BAND_MAX };

static int arctis_7_plus_send_sidetone(hid_device* device_handle, uint8_t num);
static int arctis_7_plus_send_inactive_time(hid_device* device_handle, uint8_t num);
Expand All @@ -42,6 +43,7 @@ void arctis_7_plus_init(struct device** device)
device_arctis.idVendor = VENDOR_STEELSERIES;
device_arctis.idProductsSupported = PRODUCT_IDS;
device_arctis.numIdProducts = sizeof(PRODUCT_IDS) / sizeof(PRODUCT_IDS[0]);
device_arctis.equalizer = &EQUALIZER;

strncpy(device_arctis.device_name, "SteelSeries Arctis 7+", sizeof(device_arctis.device_name));

Expand Down
2 changes: 2 additions & 0 deletions src/devices/steelseries_arctis_nova_3.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ static struct device device_arctis;

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
static EqualizerInfo EQUALIZER = { EQUALIZER_BANDS_SIZE, 0, 0.5, EQUALIZER_BAND_MIN, EQUALIZER_BAND_MAX };

static int arctis_nova_3_send_sidetone(hid_device* device_handle, uint8_t num);
static int arctis_nova_3_send_equalizer_preset(hid_device* device_handle, uint8_t num);
Expand All @@ -29,6 +30,7 @@ void arctis_nova_3_init(struct device** device)
device_arctis.idVendor = VENDOR_STEELSERIES;
device_arctis.idProductsSupported = PRODUCT_IDS;
device_arctis.numIdProducts = sizeof(PRODUCT_IDS) / sizeof(PRODUCT_IDS[0]);
device_arctis.equalizer = &EQUALIZER;

strncpy(device_arctis.device_name, "SteelSeries Arctis Nova 3", sizeof(device_arctis.device_name));

Expand Down
80 changes: 58 additions & 22 deletions src/devices/steelseries_arctis_nova_7.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,29 @@ static struct device device_arctis;
#define HEADSET_OFFLINE 0x00
#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_7x_v2, ID_ARCTIS_NOVA_7p, ID_ARCTIS_NOVA_7_DIABLO_IV };
#define EQUALIZER_BANDS_COUNT 10
#define EQUALIZER_BASELINE 0
#define EQUALIZER_STEP 0.5
#define EQUALIZER_BAND_MIN -10
#define EQUALIZER_BAND_MAX +10
#define EQUALIZER_PRESETS_COUNT 4

static const uint16_t PRODUCT_IDS[] = { ID_ARCTIS_NOVA_7, ID_ARCTIS_NOVA_7x, ID_ARCTIS_NOVA_7x_v2, ID_ARCTIS_NOVA_7p, ID_ARCTIS_NOVA_7_DIABLO_IV };
static const uint8_t SAVE_DATA[MSG_SIZE] = { 0x06, 0x09 };

float flat[EQUALIZER_BANDS_COUNT] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
float bass[EQUALIZER_BANDS_COUNT] = { 3.5, 5.5, 4, 1, -1.5, -1.5, -1, -1, -1, -1 };
float focus[EQUALIZER_BANDS_COUNT] = { -5, -3.5, -1, -3.5, -2.5, 4, 6, -3.5, 0 };
float smiley[EQUALIZER_BANDS_COUNT] = { 3, 3.5, 1.5, -1.5, -4, -4, -2.5, 1.5, 3, 4 };

static EqualizerInfo EQUALIZER = { EQUALIZER_BANDS_COUNT, EQUALIZER_BASELINE, EQUALIZER_STEP, EQUALIZER_BAND_MIN, EQUALIZER_BAND_MAX };
static EqualizerPresets EQUALIZER_PRESETS = {
EQUALIZER_PRESETS_COUNT,
{ { "flat", flat },
{ "bass", bass },
{ "focus", focus },
{ "smiley", smiley } }
};

static int arctis_nova_7_send_sidetone(hid_device* device_handle, uint8_t num);
static int arctis_nova_7_send_inactive_time(hid_device* device_handle, uint8_t num);
Expand All @@ -48,6 +65,8 @@ void arctis_nova_7_init(struct device** device)
device_arctis.idVendor = VENDOR_STEELSERIES;
device_arctis.idProductsSupported = PRODUCT_IDS;
device_arctis.numIdProducts = sizeof(PRODUCT_IDS) / sizeof(PRODUCT_IDS[0]);
device_arctis.equalizer = &EQUALIZER;
device_arctis.eqaulizer_presets = &EQUALIZER_PRESETS;

strncpy(device_arctis.device_name, "SteelSeries Arctis Nova 7", sizeof(device_arctis.device_name));

Expand Down Expand Up @@ -142,10 +161,16 @@ static BatteryInfo arctis_nova_7_request_battery(hid_device* device_handle)

int bat = data_read[2];

if (bat > BATTERY_MAX)
if (bat >= BATTERY_MAX)
info.level = 100;
else if (bat == 0x3)
info.level = 50;
else if (bat == 0x2)
info.level = 15;
else if (bat == 0x1)
info.level = 5;
else
info.level = map(bat, BATTERY_MIN, BATTERY_MAX, 0, 100);
info.level = 0;

return info;
}
Expand Down Expand Up @@ -184,35 +209,47 @@ static int arctis_nova_7_send_equalizer_preset(hid_device* device_handle, uint8_
{
// This headset supports only 4 presets:
// flat (default), bass boost, smiley, focus
struct equalizer_settings preset;
preset.size = EQUALIZER_BANDS_COUNT;

switch (num) {
case 0: {
uint8_t flat[MSG_SIZE] = { 0x0, 0x33, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x0 };
return hid_write(device_handle, flat, MSG_SIZE);
preset.bands_values = flat;
break;
// uint8_t flat[MSG_SIZE] = { 0x0, 0x33, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x0 };
// return hid_write(device_handle, flat, MSG_SIZE);
}
case 1: {
uint8_t bass[MSG_SIZE] = { 0x0, 0x33, 0x1b, 0x1f, 0x1c, 0x16, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x0 };
return hid_write(device_handle, bass, MSG_SIZE);
preset.bands_values = bass;
break;
// uint8_t bass[MSG_SIZE] = { 0x0, 0x33, 0x1b, 0x1f, 0x1c, 0x16, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x0 };
// return hid_write(device_handle, bass, MSG_SIZE);
}
case 2: {
uint8_t smiley[MSG_SIZE] = { 0x0, 0x33, 0x0a, 0x0d, 0x12, 0x0d, 0x0f, 0x1c, 0x20, 0x1b, 0x0d, 0x14, 0x0 };
return hid_write(device_handle, smiley, MSG_SIZE);
preset.bands_values = focus;
break;
// uint8_t focus[MSG_SIZE] = { 0x0, 0x33, 0x1a, 0x1b, 0x17, 0x11, 0x0c, 0x0c, 0x0f, 0x17, 0x1a, 0x1c, 0x0 };
// return hid_write(device_handle, focus, MSG_SIZE);
}
case 3: {
uint8_t focus[MSG_SIZE] = { 0x0, 0x33, 0x1a, 0x1b, 0x17, 0x11, 0x0c, 0x0c, 0x0f, 0x17, 0x1a, 0x1c, 0x0 };
return hid_write(device_handle, focus, MSG_SIZE);
preset.bands_values = smiley;
break;
// uint8_t smiley[MSG_SIZE] = { 0x0, 0x33, 0x0a, 0x0d, 0x12, 0x0d, 0x0f, 0x1c, 0x20, 0x1b, 0x0d, 0x14, 0x0 };
// return hid_write(device_handle, smiley, MSG_SIZE);
}
default: {
printf("Device only supports 0-3 range for presets.\n");
return HSC_OUT_OF_BOUNDS;
}
}

return arctis_nova_7_send_equalizer(device_handle, &preset);
}

static int arctis_nova_7_send_equalizer(hid_device* device_handle, struct equalizer_settings* settings)
{
if (settings->size != EQUALIZER_BANDS_SIZE) {
printf("Device only supports %d bands.\n", EQUALIZER_BANDS_SIZE);
if (settings->size != EQUALIZER_BANDS_COUNT) {
printf("Device only supports %d bands.\n", EQUALIZER_BANDS_COUNT);
return HSC_OUT_OF_BOUNDS;
}

Expand All @@ -224,7 +261,7 @@ static int arctis_nova_7_send_equalizer(hid_device* device_handle, struct equali
return HSC_OUT_OF_BOUNDS;
}

data[i + 2] = (uint8_t)(EQUALIZER_BASELINE + band_value);
data[i + 2] = (uint8_t)(0x14 + band_value);
}
data[settings->size + 3] = 0x0;

Expand All @@ -244,10 +281,9 @@ int arctis_nova_7_read_device_status(hid_device* device_handle, unsigned char* d

static int arctis_nova_7_bluetooth_when_powered_on(hid_device* device_handle, uint8_t num)
{
unsigned char data[MSG_SIZE] = { 0x00, 0xb2, num };
unsigned char data2[MSG_SIZE] = { 0x00, 0x09, 0 };
unsigned char data[MSG_SIZE] = { 0x00, 0xb2, num };
if (hid_write(device_handle, data, MSG_SIZE) >= 0) {
return hid_write(device_handle, data2, MSG_SIZE);
return hid_write(device_handle, SAVE_DATA, MSG_SIZE);
}
return HSC_READ_TIMEOUT;
}
Expand Down
2 changes: 2 additions & 0 deletions src/devices/steelseries_arctis_nova_pro_wireless.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ enum {
};

static const uint16_t PRODUCT_IDS[] = { ID_ARCTIS_NOVA_PRO_WIRELESS_BASE_STATION };
static EqualizerInfo EQUALIZER = { EQUALIZER_BANDS_SIZE, 0, 0.5, EQUALIZER_BAND_MIN, EQUALIZER_BAND_MAX };

static int set_sidetone(hid_device* device_handle, uint8_t num);
static BatteryInfo get_battery(hid_device* device_handle);
Expand All @@ -64,6 +65,7 @@ void arctis_nova_pro_wireless_init(struct device** device)
device_arctis.idVendor = VENDOR_STEELSERIES;
device_arctis.idProductsSupported = PRODUCT_IDS;
device_arctis.numIdProducts = sizeof(PRODUCT_IDS) / sizeof(PRODUCT_IDS[0]);
device_arctis.equalizer = &EQUALIZER;

strncpy(device_arctis.device_name, "SteelSeries Arctis Nova Pro Wireless", sizeof(device_arctis.device_name));

Expand Down
8 changes: 6 additions & 2 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -605,8 +605,9 @@ int main(int argc, char* argv[])
return 1;
}

equalizer = malloc(sizeof(struct equalizer_settings) + size * sizeof(float));
equalizer->size = size;
equalizer = malloc(sizeof(struct equalizer_settings));
equalizer->size = size;
equalizer->bands_values = malloc(sizeof(float) * size);
for (int i = 0; i < size; i++) {
equalizer->bands_values[i] = read_buffer[i];
}
Expand Down Expand Up @@ -950,6 +951,9 @@ int main(int argc, char* argv[])
free(featureRequests[i].result.message);
}

if (equalizer != NULL) {
free(equalizer->bands_values);
}
free(equalizer);

terminate_hid(&device_handle, &hid_path);
Expand Down
33 changes: 33 additions & 0 deletions src/output.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,11 @@ void initializeHeadsetInfo(HeadsetInfo* info, struct device* device)
info->vendor_name = device->device_hid_vendorname;
info->product_name = device->device_hid_productname;

info->equalizer = device->equalizer;
info->equalizer_presets = device->eqaulizer_presets,
info->has_equalizer_info = info->equalizer != NULL;
info->has_equalizer_presets_info = info->equalizer_presets != NULL;

info->capabilities_amount = 0;

for (int i = 0; i < NUM_CAPABILITIES; i++) {
Expand Down Expand Up @@ -378,6 +383,34 @@ void output_json(HeadsetControlStatus* status, HeadsetInfo* infos)
printf(" }");
}

if (info->has_equalizer_info) {
printf(",\n \"equalizer\": {\n");
printf(" \"bands\": %d,\n", info->equalizer->bands_count);
printf(" \"baseline\": %d,\n", info->equalizer->bands_baseline);
printf(" \"step\": %.1f,\n", info->equalizer->bands_step);
printf(" \"min\": %d,\n", info->equalizer->bands_min);
printf(" \"max\": %d\n", info->equalizer->bands_max);
printf(" }");

if (info->has_equalizer_presets_info) {
printf(",\n \"equalizer_presets_count\": %d", info->equalizer_presets->count);
printf(",\n \"equalizer_presets\": {\n");
for (int i = 0; i < info->equalizer_presets->count; i++) {
EqualizerPreset* presets = info->equalizer_presets->presets;
printf(" \"%s\": [ ", presets[i].name);
for (int j = 0; j < info->equalizer->bands_count; j++) {
printf("%.1f", presets[i].values[j]);
if (j < info->equalizer->bands_count - 1)
printf(", ");
}
printf(" ]");
if (i < info->equalizer_presets->count - 1)
printf(",\n");
}
printf("\n }");
}
}

if (info->has_chatmix_info) {
printf(",\n \"chatmix\": %d", info->chatmix);
}
Expand Down
5 changes: 5 additions & 0 deletions src/output.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ typedef struct {
bool has_chatmix_info;
int chatmix;

bool has_equalizer_info;
EqualizerInfo* equalizer;
bool has_equalizer_presets_info;
EqualizerPresets* equalizer_presets;

Action actions[MAX_ACTIONS];
int action_count;

Expand Down
11 changes: 9 additions & 2 deletions src/utility.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,15 @@ 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);
// Make a copy of the input string to avoid modifying the original
char* input_copy = strdup(input);
if (input_copy == NULL) {
// Memory allocation failed
return -1;
}

// For each token in the string, parse and store in dest[].
char* token = strtok(input_copy, delim);
int i = 0;
while (token) {
char* endptr;
Expand Down

0 comments on commit 38cd8b9

Please sign in to comment.