Skip to content

Commit 7e4929c

Browse files
committed
Feat: Add equalizer support for SteelSeries Arctis Nova 3P Wireless
1 parent 6c68c26 commit 7e4929c

File tree

1 file changed

+76
-11
lines changed

1 file changed

+76
-11
lines changed

src/devices/steelseries_arctis_nova_3p_wireless.c

Lines changed: 76 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,22 @@
55
#include <stdio.h>
66
#include <string.h>
77

8-
enum { MSG_SIZE = 64 };
8+
#define MSG_SIZE 64
99

10-
enum { ID_ARCTIS_NOVA_3P_WIRELESS = 0x2269 };
10+
#define ID_ARCTIS_NOVA_3P_WIRELESS 0x2269
1111

12-
enum {
13-
HEADSET_ONLINE = 0x03,
14-
HEADSET_OFFLINE = 0x02
15-
};
12+
#define HEADSET_ONLINE 0x03
13+
#define HEADSET_OFFLINE 0x02
1614

17-
enum {
18-
BATTERY_MAX = 0x64,
19-
BATTERY_MIN = 0x00
20-
};
15+
#define BATTERY_MAX 0x64
16+
#define BATTERY_MIN 0x00
17+
18+
#define EQUALIZER_BANDS_COUNT 10
19+
#define EQUALIZER_GAIN_STEP 0.1
20+
#define EQUALIZER_GAIN_MIN -12
21+
#define EQUALIZER_GAIN_MAX 12
22+
23+
static EqualizerInfo equalizer = { EQUALIZER_BANDS_COUNT, 0, EQUALIZER_GAIN_STEP, EQUALIZER_GAIN_MIN, EQUALIZER_GAIN_MAX };
2124

2225
static struct device device_arctis;
2326

@@ -28,20 +31,23 @@ static int arctis_nova_3p_wireless_send_sidetone(hid_device* device_handle, uint
2831
static int arctis_nova_3p_wireless_send_microphone_volume(hid_device* device_handle, uint8_t num);
2932
static int arctis_nova_3p_wireless_send_inactive_time(hid_device* device_handle, uint8_t num);
3033
static BatteryInfo arctis_nova_3p_wireless_request_battery(hid_device* device_handle);
34+
static int arctis_nova_3p_send_equalizer(hid_device* device_handle, struct equalizer_settings* settings);
3135

3236
void arctis_nova_3p_wireless_init(struct device** device)
3337
{
3438
device_arctis.idVendor = VENDOR_STEELSERIES;
3539
device_arctis.idProductsSupported = PRODUCT_IDS;
3640
device_arctis.numIdProducts = sizeof(PRODUCT_IDS) / sizeof(PRODUCT_IDS[0]);
41+
device_arctis.equalizer = &equalizer;
3742

3843
strncpy(device_arctis.device_name, "SteelSeries Arctis Nova 3P Wireless", sizeof(device_arctis.device_name));
3944

40-
device_arctis.capabilities = B(CAP_SIDETONE) | B(CAP_INACTIVE_TIME) | B(CAP_MICROPHONE_VOLUME) | B(CAP_BATTERY_STATUS);
45+
device_arctis.capabilities = B(CAP_SIDETONE) | B(CAP_INACTIVE_TIME) | B(CAP_MICROPHONE_VOLUME) | B(CAP_BATTERY_STATUS) | B(CAP_EQUALIZER);
4146
device_arctis.send_sidetone = &arctis_nova_3p_wireless_send_sidetone;
4247
device_arctis.send_inactive_time = &arctis_nova_3p_wireless_send_inactive_time;
4348
device_arctis.send_microphone_volume = &arctis_nova_3p_wireless_send_microphone_volume;
4449
device_arctis.request_battery = &arctis_nova_3p_wireless_request_battery;
50+
device_arctis.send_equalizer = &arctis_nova_3p_send_equalizer;
4551

4652
*device = &device_arctis;
4753
}
@@ -139,3 +145,62 @@ static BatteryInfo arctis_nova_3p_wireless_request_battery(hid_device* device_ha
139145
info.level = map(bat, BATTERY_MIN, BATTERY_MAX, 0, 100);
140146
return info;
141147
}
148+
149+
static int arctis_nova_3p_send_equalizer(hid_device* device_handle, struct equalizer_settings* settings)
150+
{
151+
if (settings->size != EQUALIZER_BANDS_COUNT) {
152+
printf("Device only supports %d bands.\n", EQUALIZER_BANDS_COUNT);
153+
return HSC_OUT_OF_BOUNDS;
154+
}
155+
uint8_t data[MSG_SIZE] = { 0x33 };
156+
157+
// default frequencies for each band (2 bytes per band)
158+
const unsigned char band_freq_le[2 * EQUALIZER_BANDS_COUNT] = {
159+
0x20,
160+
0x0,
161+
0x40,
162+
0x0,
163+
0x7d,
164+
0x0,
165+
0xfa,
166+
0x0,
167+
0xf4,
168+
0x1,
169+
0xe8,
170+
0x3,
171+
0xd0,
172+
0x7,
173+
0xa0,
174+
0xf,
175+
0x40,
176+
0x1f,
177+
0x80,
178+
0x3e,
179+
};
180+
181+
for (size_t i = 0; i < settings->size; i++) {
182+
float gain_value = settings->bands_values[i];
183+
if (gain_value < EQUALIZER_GAIN_MIN || gain_value > EQUALIZER_GAIN_MAX) {
184+
printf("Device only supports gains ranging from %d to %d.\n", EQUALIZER_GAIN_MIN, EQUALIZER_GAIN_MAX);
185+
return HSC_OUT_OF_BOUNDS;
186+
}
187+
uint8_t raw_gain_value;
188+
if (gain_value < 0) {
189+
gain_value = (-gain_value) / EQUALIZER_GAIN_STEP;
190+
raw_gain_value = (0xff - ((uint8_t)gain_value)) + 1;
191+
} else {
192+
raw_gain_value = (uint8_t)(gain_value / EQUALIZER_GAIN_STEP);
193+
}
194+
195+
data[1 + 6 * i + 0] = band_freq_le[2 * i];
196+
data[1 + 6 * i + 1] = band_freq_le[2 * i + 1];
197+
data[1 + 6 * i + 2] = 0x1; // use Peaking EQ by default
198+
data[1 + 6 * i + 3] = raw_gain_value;
199+
// use a default quality factor of 1.414 (approximated sqrt(2)) multiplied by 1000 to have a fixed 16 bit number number
200+
data[1 + 6 * i + 4] = 0x86;
201+
data[1 + 6 * i + 5] = 0x5;
202+
}
203+
204+
hid_send_feature_report(device_handle, data, MSG_SIZE);
205+
return hid_send_feature_report(device_handle, SAVE_DATA, MSG_SIZE);
206+
}

0 commit comments

Comments
 (0)