Skip to content

Commit 25a769b

Browse files
authored
Fix equalizer presets output in JSON, YAML, and ENV formats (#468)
1 parent 1af3973 commit 25a769b

8 files changed

Lines changed: 168 additions & 1 deletion

cli/output/output.cpp

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,12 +165,25 @@ void processFeatureRequest(const FeatureRequest& req, DeviceData& dev, std::stri
165165
}
166166
}
167167

168-
// Equalizer presets count
168+
// Equalizer presets count and presets
169169
if (device_caps & B(CAP_EQUALIZER_PRESET)) {
170170
auto presets_count = hid_device->getEqualizerPresetsCount();
171171
if (presets_count > 0) {
172172
dev.equalizer_presets_count = presets_count;
173173
}
174+
175+
// Get actual preset data if available
176+
auto presets = hid_device->getEqualizerPresets();
177+
if (presets.has_value() && !presets->empty()) {
178+
std::vector<EqualizerPresetData> preset_data;
179+
for (const auto& preset : presets->presets) {
180+
preset_data.push_back(EqualizerPresetData {
181+
.name = preset.name,
182+
.values = preset.values
183+
});
184+
}
185+
dev.equalizer_presets = std::move(preset_data);
186+
}
174187
}
175188

176189
// Process feature requests
@@ -250,6 +263,32 @@ void outputYaml(const OutputData& data)
250263
dev.battery->serialize(s);
251264
}
252265

266+
if (dev.equalizer.has_value()) {
267+
dev.equalizer->serialize(s);
268+
}
269+
270+
if (dev.equalizer_presets_count.has_value()) {
271+
s.write("equalizer_presets_count", *dev.equalizer_presets_count);
272+
}
273+
274+
if (dev.equalizer_presets.has_value() && !dev.equalizer_presets->empty()) {
275+
s.beginObject("equalizer_presets");
276+
for (const auto& preset : *dev.equalizer_presets) {
277+
// Convert name to lowercase for API compatibility
278+
std::string lower_name;
279+
lower_name.reserve(preset.name.size());
280+
for (char c : preset.name) {
281+
lower_name += static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
282+
}
283+
s.writeArray(lower_name, preset.values);
284+
}
285+
s.endObject();
286+
}
287+
288+
if (dev.parametric_eq.has_value()) {
289+
dev.parametric_eq->serialize(s);
290+
}
291+
253292
if (dev.chatmix.has_value()) {
254293
s.write("chatmix", *dev.chatmix);
255294
}
@@ -327,6 +366,40 @@ void outputEnv(const OutputData& data)
327366
s.writeOptional(prefix + "_BATTERY_TIME_TO_EMPTY_MIN", dev.battery->time_to_empty_min);
328367
}
329368

369+
if (dev.equalizer.has_value()) {
370+
s.write(prefix + "_EQUALIZER_BANDS", dev.equalizer->bands_count);
371+
s.write(prefix + "_EQUALIZER_BASELINE", dev.equalizer->baseline);
372+
s.write(prefix + "_EQUALIZER_STEP", static_cast<double>(dev.equalizer->step));
373+
s.write(prefix + "_EQUALIZER_MIN", dev.equalizer->min);
374+
s.write(prefix + "_EQUALIZER_MAX", dev.equalizer->max);
375+
}
376+
377+
if (dev.equalizer_presets_count.has_value()) {
378+
s.write(prefix + "_EQUALIZER_PRESETS_COUNT", *dev.equalizer_presets_count);
379+
}
380+
381+
if (dev.equalizer_presets.has_value() && !dev.equalizer_presets->empty()) {
382+
for (const auto& preset : *dev.equalizer_presets) {
383+
// Convert name to uppercase for ENV variable naming
384+
std::string upper_name;
385+
upper_name.reserve(preset.name.size());
386+
for (char c : preset.name) {
387+
if (c == ' ')
388+
upper_name += '_';
389+
else
390+
upper_name += static_cast<char>(std::toupper(static_cast<unsigned char>(c)));
391+
}
392+
// Output values as comma-separated string
393+
std::string values_str;
394+
for (size_t k = 0; k < preset.values.size(); ++k) {
395+
if (k > 0)
396+
values_str += ",";
397+
values_str += std::format("{:.1f}", preset.values[k]);
398+
}
399+
s.write(std::format("{}_EQUALIZER_PRESET_{}", prefix, upper_name), values_str);
400+
}
401+
}
402+
330403
if (dev.chatmix.has_value()) {
331404
s.write(prefix + "_CHATMIX", *dev.chatmix);
332405
}

cli/output/output_data.hpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,11 @@ struct ErrorData {
107107
std::string message;
108108
};
109109

110+
struct EqualizerPresetData {
111+
std::string name;
112+
std::vector<float> values;
113+
};
114+
110115
struct EqualizerData {
111116
int bands_count = 0;
112117
int baseline = 0;
@@ -175,6 +180,7 @@ struct DeviceData {
175180
std::optional<int> chatmix;
176181
std::optional<EqualizerData> equalizer;
177182
std::optional<int> equalizer_presets_count;
183+
std::optional<std::vector<EqualizerPresetData>> equalizer_presets;
178184
std::optional<ParametricEqData> parametric_eq;
179185

180186
std::vector<ActionData> actions;
@@ -205,6 +211,20 @@ struct DeviceData {
205211
s.write("equalizer_presets_count", *equalizer_presets_count);
206212
}
207213

214+
if (equalizer_presets.has_value() && !equalizer_presets->empty()) {
215+
s.beginObject("equalizer_presets");
216+
for (const auto& preset : *equalizer_presets) {
217+
// Convert name to lowercase for API compatibility
218+
std::string lower_name;
219+
lower_name.reserve(preset.name.size());
220+
for (char c : preset.name) {
221+
lower_name += static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
222+
}
223+
s.writeArray(lower_name, preset.values);
224+
}
225+
s.endObject();
226+
}
227+
208228
if (parametric_eq.has_value()) {
209229
parametric_eq->serialize(s);
210230
}

lib/devices/headsetcontrol_test.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,18 @@ class HeadsetControlTest : public HIDDevice {
8787
return 4;
8888
}
8989

90+
std::optional<EqualizerPresets> getEqualizerPresets() const override
91+
{
92+
EqualizerPresets presets;
93+
presets.presets = {
94+
{ "Flat", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
95+
{ "Bass Boost", { 6.0f, 4.0f, 2.0f, 0, 0, 0, 0, 0, 0, 0 } },
96+
{ "Treble Boost", { 0, 0, 0, 0, 0, 0, 2.0f, 4.0f, 6.0f, 6.0f } },
97+
{ "V-Shape", { 4.0f, 2.0f, 0, -2.0f, -2.0f, -2.0f, 0, 2.0f, 4.0f, 4.0f } }
98+
};
99+
return presets;
100+
}
101+
90102
// Rich Results V2 API
91103
Result<BatteryResult> getBattery([[maybe_unused]] hid_device* device_handle) override
92104
{

lib/devices/steelseries_arctis_7_plus.hpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,19 @@ class SteelSeriesArctis7Plus : public protocols::SteelSeriesNovaDevice<SteelSeri
7272
return EQUALIZER_PRESETS_COUNT;
7373
}
7474

75+
std::optional<EqualizerPresets> getEqualizerPresets() const override
76+
{
77+
// Convert raw byte values to dB using: value = (raw - EQUALIZER_BASELINE) / 2.0f
78+
EqualizerPresets presets;
79+
presets.presets = {
80+
{ "Flat", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
81+
{ "Bass Boost", { 3.5f, 4.0f, 1.0f, -1.5f, -1.5f, -1.0f, -1.0f, -1.0f, -1.0f, 5.5f } },
82+
{ "Smiley", { 3.0f, 1.5f, -1.5f, -4.0f, -4.0f, -2.5f, 1.5f, 3.0f, 4.0f, 3.5f } },
83+
{ "Focus", { -5.0f, -1.0f, -3.5f, -2.5f, 4.0f, 6.0f, 3.5f, -3.5f, 0.0f, -3.5f } }
84+
};
85+
return presets;
86+
}
87+
7588
// Rich Results V2 API
7689
Result<BatteryResult> getBattery(hid_device* device_handle) override
7790
{

lib/devices/steelseries_arctis_nova_3.hpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,19 @@ class SteelSeriesArctisNova3 : public protocols::SteelSeriesNovaDevice<SteelSeri
8686
return EQUALIZER_PRESETS_COUNT;
8787
}
8888

89+
std::optional<EqualizerPresets> getEqualizerPresets() const override
90+
{
91+
// Convert raw byte values to dB using: value = (raw - EQUALIZER_BASELINE) / 2.0f
92+
EqualizerPresets presets;
93+
presets.presets = {
94+
{ "Flat", { 0, 0, 0, 0, 0, 0 } },
95+
{ "Bass", { 4.0f, 2.5f, -1.5f, 0, 0, 0 } },
96+
{ "Smiley", { 3.0f, 1.5f, -2.5f, -1.0f, 1.5f, 3.0f } },
97+
{ "Focus", { -4.0f, -3.5f, -1.5f, 2.0f, 4.0f, 0 } }
98+
};
99+
return presets;
100+
}
101+
89102
// Rich Results V2 API
90103
Result<SidetoneResult> setSidetone(hid_device* device_handle, uint8_t level) override
91104
{

lib/devices/steelseries_arctis_nova_3p_wireless.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,18 @@ class SteelSeriesArctisNova3PWireless : public protocols::SteelSeriesNovaDevice<
128128
return EQUALIZER_PRESETS_COUNT;
129129
}
130130

131+
std::optional<EqualizerPresets> getEqualizerPresets() const override
132+
{
133+
EqualizerPresets presets;
134+
presets.presets = {
135+
{ "Flat", std::vector<float>(PRESET_FLAT.begin(), PRESET_FLAT.end()) },
136+
{ "Bass", std::vector<float>(PRESET_BASS.begin(), PRESET_BASS.end()) },
137+
{ "Focus", std::vector<float>(PRESET_FOCUS.begin(), PRESET_FOCUS.end()) },
138+
{ "Smiley", std::vector<float>(PRESET_SMILEY.begin(), PRESET_SMILEY.end()) }
139+
};
140+
return presets;
141+
}
142+
131143
std::optional<ParametricEqualizerInfo> getParametricEqualizerInfo() const override
132144
{
133145
// Supported filters: LowShelf, LowPass, Peaking, HighPass, HighShelf, Notch

lib/devices/steelseries_arctis_nova_5.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,18 @@ class SteelSeriesArctisNova5 : public protocols::SteelSeriesNovaDevice<SteelSeri
114114
return EQUALIZER_PRESETS_COUNT;
115115
}
116116

117+
std::optional<EqualizerPresets> getEqualizerPresets() const override
118+
{
119+
EqualizerPresets presets;
120+
presets.presets = {
121+
{ "Flat", std::vector<float>(PRESET_FLAT.begin(), PRESET_FLAT.end()) },
122+
{ "Bass", std::vector<float>(PRESET_BASS.begin(), PRESET_BASS.end()) },
123+
{ "Focus", std::vector<float>(PRESET_FOCUS.begin(), PRESET_FOCUS.end()) },
124+
{ "Smiley", std::vector<float>(PRESET_SMILEY.begin(), PRESET_SMILEY.end()) }
125+
};
126+
return presets;
127+
}
128+
117129
std::optional<ParametricEqualizerInfo> getParametricEqualizerInfo() const override
118130
{
119131
// Supported filters: LowShelf, LowPass, Peaking, HighPass, HighShelf

lib/devices/steelseries_arctis_nova_7.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,18 @@ class SteelSeriesArctisNova7 : public protocols::SteelSeriesNovaDevice<SteelSeri
8484
return EQUALIZER_PRESETS_COUNT;
8585
}
8686

87+
std::optional<EqualizerPresets> getEqualizerPresets() const override
88+
{
89+
EqualizerPresets presets;
90+
presets.presets = {
91+
{ "Flat", std::vector<float>(PRESET_FLAT.begin(), PRESET_FLAT.end()) },
92+
{ "Bass", std::vector<float>(PRESET_BASS.begin(), PRESET_BASS.end()) },
93+
{ "Focus", std::vector<float>(PRESET_FOCUS.begin(), PRESET_FOCUS.end()) },
94+
{ "Smiley", std::vector<float>(PRESET_SMILEY.begin(), PRESET_SMILEY.end()) }
95+
};
96+
return presets;
97+
}
98+
8799
constexpr capability_detail getCapabilityDetail([[maybe_unused]] enum capabilities cap) const override
88100
{
89101
return { .usagepage = 0xffc0, .usageid = 0x1, .interface_id = 3 };

0 commit comments

Comments
 (0)