Skip to content

Commit

Permalink
Add parametric equalizer and implement it for Arctis Nova 5
Browse files Browse the repository at this point in the history
  • Loading branch information
ne0phyte committed Feb 7, 2025
1 parent 343d071 commit c30d005
Show file tree
Hide file tree
Showing 12 changed files with 653 additions and 137 deletions.
54 changes: 27 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,33 +9,33 @@ talking. This differs from a simple loopback via PulseAudio as you won't have an

## Supported Headsets

| Device | sidetone | battery | notification sound | lights | inactive time | chatmix | voice prompts | rotate to mute | equalizer preset | equalizer | microphone mute led brightness | microphone volume | volume limiter | bluetooth when powered on | bluetooth call volume |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| Corsair Headset Device | x | x | x | x | | | | | | | | | | | |
| HyperX Cloud Alpha Wireless | x | x | | | x | | x | | | | | | | | |
| HyperX Cloud Flight Wireless | | x | | | | | | | | | | | | | |
| HyperX Cloud 3 | x | | | | | | | | | | | | | | |
| Logitech G430 | x | | | | | | | | | | | | | | |
| Logitech G432/G433 | x | | | | | | | | | | | | | | |
| Logitech G533 | x | x | | | x | | | | | | | | | | |
| Logitech G535 | x | x | | | x | | | | | | | | | | |
| Logitech G930 | x | x | | | | | | | | | | | | | |
| Logitech G633/G635/G733/G933/G935 | x | x | | x | | | | | | | | | | | |
| Logitech G PRO Series | x | x | | | x | | | | | | | | | | |
| Logitech G PRO X 2 | x | | | | x | | | | | | | | | | |
| Logitech Zone Wired/Zone 750 | x | | | | | | x | x | | | | | | | |
| SteelSeries Arctis (1/7X/7P) Wireless | x | x | | | x | | | | | | | | | | |
| SteelSeries Arctis (7/Pro) | x | x | | x | x | x | | | | | | | | | |
| SteelSeries Arctis 9 | x | x | | | x | x | | | | | | | | | |
| SteelSeries Arctis Pro Wireless | x | x | | | x | | | | | | | | | | |
| ROCCAT Elo 7.1 Air | | | | x | x | | | | | | | | | | |
| ROCCAT Elo 7.1 USB | | | | x | | | | | | | | | | | |
| SteelSeries Arctis Nova 3 | x | | | | | | | | x | x | x | x | | | |
| SteelSeries Arctis Nova (5/5X) | x | x | | | x | x | | | x | x | x | x | x | | |
| SteelSeries Arctis Nova 7 | x | x | | | x | x | | | x | x | x | x | x | x | x |
| SteelSeries Arctis 7+ | x | x | | | x | x | | | x | x | | | | | |
| SteelSeries Arctis Nova Pro Wireless | x | x | | x | x | | | | x | x | | | | | |
| HeadsetControl Test device | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x |
| Device | sidetone | battery | notification sound | lights | inactive time | chatmix | voice prompts | rotate to mute | equalizer preset | equalizer | parametric equalizer | microphone mute led brightness | microphone volume | volume limiter | bluetooth when powered on | bluetooth call volume |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| Corsair Headset Device | x | x | x | x | | | | | | | | | | | | |
| HyperX Cloud Alpha Wireless | x | x | | | x | | x | | | | | | | | | |
| HyperX Cloud Flight Wireless | | x | | | | | | | | | | | | | | |
| HyperX Cloud 3 | x | | | | | | | | | | | | | | | |
| Logitech G430 | x | | | | | | | | | | | | | | | |
| Logitech G432/G433 | x | | | | | | | | | | | | | | | |
| Logitech G533 | x | x | | | x | | | | | | | | | | | |
| Logitech G535 | x | x | | | x | | | | | | | | | | | |
| Logitech G930 | x | x | | | | | | | | | | | | | | |
| Logitech G633/G635/G733/G933/G935 | x | x | | x | | | | | | | | | | | | |
| Logitech G PRO Series | x | x | | | x | | | | | | | | | | | |
| Logitech G PRO X 2 | x | | | | x | | | | | | | | | | | |
| Logitech Zone Wired/Zone 750 | x | | | | | | x | x | | | | | | | | |
| SteelSeries Arctis (1/7X/7P) Wireless | x | x | | | x | | | | | | | | | | | |
| SteelSeries Arctis (7/Pro) | x | x | | x | x | x | | | | | | | | | | |
| SteelSeries Arctis 9 | x | x | | | x | x | | | | | | | | | | |
| SteelSeries Arctis Pro Wireless | x | x | | | x | | | | | | | | | | | |
| ROCCAT Elo 7.1 Air | | | | x | x | | | | | | | | | | | |
| ROCCAT Elo 7.1 USB | | | | x | | | | | | | | | | | | |
| SteelSeries Arctis Nova 3 | x | | | | | | | | x | x | | x | x | | | |
| SteelSeries Arctis Nova (5/5X) | x | x | | | x | x | | | x | x | x | x | x | x | | |
| SteelSeries Arctis Nova 7 | x | x | | | x | x | | | x | x | | x | x | x | x | x |
| SteelSeries Arctis 7+ | x | x | | | x | x | | | x | x | | | | | | |
| SteelSeries Arctis Nova Pro Wireless | x | x | | x | x | | | | x | x | | | | | | |
| HeadsetControl Test device | x | x | x | x | x | x | x | x | x | x | | x | x | x | x | x |

For non-supported headsets on Linux: There is a chance that you can set the sidetone via AlsaMixer

Expand Down
73 changes: 73 additions & 0 deletions src/arrays.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<array name="com_google_android_gms_fonts_certs">
<item>@array/com_google_android_gms_fonts_certs_dev</item>
<item>@array/com_google_android_gms_fonts_certs_prod</item>
</array>
<string-array name="com_google_android_gms_fonts_certs_dev">
<item>MIIEqDCCA5CgAwIBAgIJANWFuGx90071MA0GCSqGSIb3DQEBBAUAMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAeFw0wODA0MTUyMzM2NTZaFw0zNTA5MDEyMzM2NTZaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBANbOLggKv+IxTdGNs8/TGFy0PTP6DHThvbbR24kT9ixcOd9W+EaBPWW+wPPKQmsHxajtWjmQwWfna8mZuSeJS48LIgAZlKkpFeVyxW0qMBujb8X8ETrWy550NaFtI6t9+u7hZeTfHwqNvacKhp1RbE6dBRGWynwMVX8XW8N1+UjFaq6GCJukT4qmpN2afb8sCjUigq0GuMwYXrFVee74bQgLHWGJwPmvmLHC69EH6kWr22ijx4OKXlSIx2xT1AsSHee70w5iDBiK4aph27yH3TxkXy9V89TDdexAcKk/cVHYNnDBapcavl7y0RiQ4biu8ymM8Ga/nmzhRKya6G0cGw8CAQOjgfwwgfkwHQYDVR0OBBYEFI0cxb6VTEM8YYY6FbBMvAPyT+CyMIHJBgNVHSMEgcEwgb6AFI0cxb6VTEM8YYY6FbBMvAPyT+CyoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJANWFuGx90071MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBABnTDPEF+3iSP0wNfdIjIz1AlnrPzgAIHVvXxunW7SBrDhEglQZBbKJEk5kT0mtKoOD1JMrSu1xuTKEBahWRbqHsXclaXjoBADb0kkjVEJu/Lh5hgYZnOjvlba8Ld7HCKePCVePoTJBdI4fvugnL8TsgK05aIskyY0hKI9L8KfqfGTl1lzOv2KoWD0KWwtAWPoGChZxmQ+nBli+gwYMzM1vAkP+aayLe0a1EQimlOalO762r0GXO0ks+UeXde2Z4e+8S/pf7pITEI/tP+MxJTALw9QUWEv9lKTk+jkbqxbsh8nfBUapfKqYn0eidpwq2AzVp3juYl7//fKnaPhJD9gs=</item>
</string-array>
<string-array name="com_google_android_gms_fonts_certs_prod">
<item>MIIEQzCCAyugAwIBAgIJAMLgh0ZkSjCNMA0GCSqGSIb3DQEBBAUAMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDAeFw0wODA4MjEyMzEzMzRaFw0zNjAxMDcyMzEzMzRaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAKtWLgDYO6IIrgqWbxJOKdoR8qtW0I9Y4sypEwPpt1TTcvZApxsdyxMJZ2JORland2qSGT2y5b+3JKkedxiLDmpHpDsz2WCbdxgxRczfey5YZnTJ4VZbH0xqWVW/8lGmPav5xVwnIiJS6HXk+BVKZF+JcWjAsb/GEuq/eFdpuzSqeYTcfi6idkyugwfYwXFU1+5fZKUaRKYCwkkFQVfcAs1fXA5V+++FGfvjJ/CxURaSxaBvGdGDhfXE28LWuT9ozCl5xw4Yq5OGazvV24mZVSoOO0yZ31j7kYvtwYK6NeADwbSxDdJEqO4k//0zOHKrUiGYXtqw/A0LFFtqoZKFjnkCAQOjgdkwgdYwHQYDVR0OBBYEFMd9jMIhF1Ylmn/Tgt9r45jk14alMIGmBgNVHSMEgZ4wgZuAFMd9jMIhF1Ylmn/Tgt9r45jk14aloXikdjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLR29vZ2xlIEluYy4xEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMTB0FuZHJvaWSCCQDC4IdGZEowjTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4IBAQBt0lLO74UwLDYKqs6Tm8/yzKkEu116FmH4rkaymUIE0P9KaMftGlMexFlaYjzmB2OxZyl6euNXEsQH8gjwyxCUKRJNexBiGcCEyj6z+a1fuHHvkiaai+KL8W1EyNmgjmyy8AW7P+LLlkR+ho5zEHatRbM/YAnqGcFh5iZBqpknHf1SKMXFh4dd239FJ1jWYfbMDMy3NS5CTMQ2XFI1MvcyUTdZPErjQfTbQe3aDQsQcafEQPD+nqActifKZ0Np0IS9L9kR/wbNvyz6ENwPiTrjV2KRkEjH78ZMcUQXg0L3BYHJ3lc69Vs5Ddf9uUGGMYldX3WfMBEmh/9iFBDAaTCK</item>
</string-array>
<string-array name="headset_commands_array">
<item>Select</item>
<item>0x09 Save Profile</item>
<item>0x10 Get FW Version</item>
<item>0x11 Get Headset Status</item>
<item>0x12 Get Serial Number</item>
<item>0x18 Get EQ Preset Name (2.4)</item>
<item>0x18 Get EQ Preset Name (BT)</item>
<item>0x19 Set EQ Preset Name (2.4)</item>
<item>0x19 Set EQ Preset Name (BT)</item>
<item>0x20 Get Audio Settings</item>
<item>0x21 Set Audio Settings</item>
<item>0x26 Get Volume Limiter</item>
<item>0x27 Set Volume Limiter (on)</item>
<item>0x27 Set Volume Limiter (off)</item>
<item>0x28 Set Custom Bluetooth EQ Band</item>
<item>0x31 Set Custom EQ Band</item>
<item>0x33 Set Custom EQ</item>
<item>0x36 Set Custom Bluetooth EQ</item>
<item>0x37 Set Mic Volume (max)</item>
<item>0x37 Set Mic Volume (min)</item>
<item>0x39 Set Sidetone (max)</item>
<item>0x39 Set Sidetone (off)</item>
<item>0x3B Set Onboard Effects Status (on)</item>
<item>0x3B Set Onboard Effects Status (off)</item>
<item>0xA7 Set EQ Sync Status (on)</item>
<item>0xA7 Set EQ Sync Status (off)</item>
<item>0xA8 Get EQ Sync Status</item>
<item>0xAA Set Audio Mode (2.4)</item>
<item>0xAA Set Audio Mode (BT)</item>
<item>0xAB Get Audio Mode</item>
<item>0xB0 Get Headset/Wireless Settings</item>
<item>0xB1 Set Headset/Wireless Settings</item>
<item>0xB8 Set ANC Level (3/High)</item>
<item>0xB8 Set ANC Level (1/Low)</item>
<item>0xB9 Set Transparent Level (10)</item>
<item>0xB9 Set Transparent Level (1)</item>
<item>0xBB Set Mic Muted (on)</item>
<item>0xBB Set Mic Muted (off)</item>
<item>0xBD Enable Transparent / ANC (ANC)</item>
<item>0xBD Enable Transparent / ANC (T)</item>
<item>0xBD Enable Transparent / ANC (off)</item>
<item>0xC0 Get Auto-Off Timer Delay</item>
<item>0xC1 Set Auto-Off Timer Delay (1min)</item>
<item>0xC1 Set Auto-Off Timer Delay (off)</item>
<item>0xC4 Get Wear Sense Config</item>
<item>0xC5 Set Wear Sense Config (both)</item>
<item>0xC5 Set Wear Sense Config (left)</item>
<item>0xC5 Set Wear Sense Config (right)</item>
<item>0xC5 Set Wear Sense Config (off)</item>
<item>0xC8 Get Button Mappings</item>
<item>0xC9 Set Button Mappings</item>
<item>0xFD Factory Reset</item>
</string-array>
<array name="preloaded_fonts">
<item>@font/inter</item>
<item>@font/inter_bold</item>
<item>@font/inter_medium</item>
<item>@font/inter_semibold</item>
</array>
</resources>
13 changes: 13 additions & 0 deletions src/device.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const char* const capabilities_str[NUM_CAPABILITIES]
[CAP_ROTATE_TO_MUTE] = "rotate to mute",
[CAP_EQUALIZER_PRESET] = "equalizer preset",
[CAP_EQUALIZER] = "equalizer",
[CAP_PARAMETRIC_EQUALIZER] = "parametric equalizer",
[CAP_MICROPHONE_MUTE_LED_BRIGHTNESS] = "microphone mute led brightness",
[CAP_MICROPHONE_VOLUME] = "microphone volume",
[CAP_VOLUME_LIMITER] = "volume limiter",
Expand All @@ -31,6 +32,7 @@ const char* const capabilities_str_enum[NUM_CAPABILITIES]
[CAP_ROTATE_TO_MUTE] = "CAP_ROTATE_TO_MUTE",
[CAP_EQUALIZER_PRESET] = "CAP_EQUALIZER_PRESET",
[CAP_EQUALIZER] = "CAP_EQUALIZER",
[CAP_PARAMETRIC_EQUALIZER] = "CAP_PARAMETRIC_EQUALIZER",
[CAP_MICROPHONE_MUTE_LED_BRIGHTNESS] = "CAP_MICROPHONE_MUTE_LED_BRIGHTNESS",
[CAP_MICROPHONE_VOLUME] = "CAP_MICROPHONE_VOLUME",
[CAP_VOLUME_LIMITER] = "CAP_VOLUME_LIMITER",
Expand All @@ -50,10 +52,21 @@ const char capabilities_str_short[NUM_CAPABILITIES]
[CAP_ROTATE_TO_MUTE] = 'r',
[CAP_EQUALIZER_PRESET] = 'p',
[CAP_EQUALIZER] = 'e',
[CAP_PARAMETRIC_EQUALIZER] = 'q',
[CAP_MICROPHONE_MUTE_LED_BRIGHTNESS] = 't',
[CAP_MICROPHONE_VOLUME] = 'o',
// new capabilities since short output was deprecated
[CAP_VOLUME_LIMITER] = '\0',
[CAP_BT_WHEN_POWERED_ON] = '\0',
[CAP_BT_CALL_VOLUME] = '\0'
};

const char* const equalizer_filter_type_str[NUM_EQ_FILTER_TYPES]
= {
[EQ_FILTER_LOWSHELF] = "lowshelf",
[EQ_FILTER_LOWPASS] = "lowpass",
[EQ_FILTER_PEAKING] = "peaking",
[EQ_FILTER_HIGHPASS] = "highpass",
[EQ_FILTER_HIGHSHELF] = "highshelf"

};
68 changes: 66 additions & 2 deletions src/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ enum capabilities {
CAP_ROTATE_TO_MUTE,
CAP_EQUALIZER_PRESET,
CAP_EQUALIZER,
CAP_PARAMETRIC_EQUALIZER,
CAP_MICROPHONE_MUTE_LED_BRIGHTNESS,
CAP_MICROPHONE_VOLUME,
CAP_VOLUME_LIMITER,
Expand Down Expand Up @@ -103,6 +104,19 @@ typedef struct {
float* values;
} EqualizerPreset;

typedef struct {
int bands_count;
float gain_base; // default/base gain
float gain_step;
float gain_min;
float gain_max;
float q_factor_min; // q factor
float q_factor_max;
int freq_min; // frequency
int freq_max;
int filter_types; // bitmap containing available filter types
} ParametricEqualizerInfo;

typedef struct {
int count;
EqualizerPreset presets[];
Expand All @@ -112,6 +126,7 @@ enum headsetcontrol_errors {
HSC_ERROR = -100,
HSC_READ_TIMEOUT = -101,
HSC_OUT_OF_BOUNDS = -102,
HSC_INVALID_ARG = -103,
};

typedef enum {
Expand Down Expand Up @@ -140,7 +155,7 @@ typedef struct {
FeatureResult result;
} FeatureRequest;

/** @brief Defines equalizer custom setings
/** @brief Defines equalizer custom settings
*/
struct equalizer_settings {
/// The size of the bands array
Expand All @@ -149,6 +164,36 @@ struct equalizer_settings {
float* bands_values;
};

typedef enum {
EQ_FILTER_LOWSHELF,
EQ_FILTER_LOWPASS,
EQ_FILTER_PEAKING,
EQ_FILTER_HIGHPASS,
EQ_FILTER_HIGHSHELF,
NUM_EQ_FILTER_TYPES
} EqualizerFilterType;

/// Enum name of every parametric equalizer filter type
extern const char* const equalizer_filter_type_str[NUM_EQ_FILTER_TYPES];

/** @brief Defines parametric equalizer custom settings
*/
struct parametric_equalizer_settings {
/// The size of the bands array
int size;
/// The equalizer bands
struct parametric_equalizer_band* bands;
};

/** @brief Defines parameteric equalizer band
*/
struct parametric_equalizer_band {
float frequency;
float gain;
float q_factor;
EqualizerFilterType type;
};

/** @brief Defines the basic data of a device
*
* Also defines function pointers for using supported features
Expand All @@ -168,7 +213,8 @@ struct device {

// Equalizer Infos
EqualizerInfo* equalizer;
EqualizerPresets* eqaulizer_presets;
EqualizerPresets* equalizer_presets;
ParametricEqualizerInfo* parametric_equalizer;

wchar_t device_hid_vendorname[64];
wchar_t device_hid_productname[64];
Expand Down Expand Up @@ -318,6 +364,24 @@ struct device {
*/
int (*send_equalizer)(hid_device* hid_device, struct equalizer_settings* settings);

/** @brief Function pointer for setting headset parametric equalizer
*
* Forwards the request to the device specific implementation
*
* @param device_handle The hidapi handle. Must be the same
* device as defined here (same ids)
* @param settings The parametric equalizer settings containing
* the filter values
*
* @returns > 0 on success
* HSC_OUT_OF_BOUNDS on equalizer settings size out of range
* specific to this hardware
* HSC_INVALID_ARG on equalizer filter type invalid/unsupported
* specific to this hardware
* -1 HIDAPI error
*/
int (*send_parametric_equalizer)(hid_device* hid_device, struct parametric_equalizer_settings* settings);

/** @brief Function pointer for setting headset microphone mute LED brightness
*
* Forwards the request to the device specific implementation
Expand Down
Loading

0 comments on commit c30d005

Please sign in to comment.