Handle AL effect properties with a variant
[openal-soft.git] / al / effects / equalizer.cpp
blobba73530781c6d8a1154a74e989c7881a1646b1a5
2 #include "config.h"
4 #include "AL/al.h"
5 #include "AL/efx.h"
7 #include "alc/effects/base.h"
8 #include "effects.h"
10 #ifdef ALSOFT_EAX
11 #include "alnumeric.h"
12 #include "al/eax/effect.h"
13 #include "al/eax/exception.h"
14 #include "al/eax/utils.h"
15 #endif // ALSOFT_EAX
18 namespace {
20 constexpr EffectProps genDefaultProps() noexcept
22 EqualizerProps props{};
23 props.LowCutoff = AL_EQUALIZER_DEFAULT_LOW_CUTOFF;
24 props.LowGain = AL_EQUALIZER_DEFAULT_LOW_GAIN;
25 props.Mid1Center = AL_EQUALIZER_DEFAULT_MID1_CENTER;
26 props.Mid1Gain = AL_EQUALIZER_DEFAULT_MID1_GAIN;
27 props.Mid1Width = AL_EQUALIZER_DEFAULT_MID1_WIDTH;
28 props.Mid2Center = AL_EQUALIZER_DEFAULT_MID2_CENTER;
29 props.Mid2Gain = AL_EQUALIZER_DEFAULT_MID2_GAIN;
30 props.Mid2Width = AL_EQUALIZER_DEFAULT_MID2_WIDTH;
31 props.HighCutoff = AL_EQUALIZER_DEFAULT_HIGH_CUTOFF;
32 props.HighGain = AL_EQUALIZER_DEFAULT_HIGH_GAIN;
33 return props;
36 } // namespace
38 const EffectProps EqualizerEffectProps{genDefaultProps()};
40 void EqualizerEffectHandler::SetParami(EqualizerProps&, ALenum param, int)
41 { throw effect_exception{AL_INVALID_ENUM, "Invalid equalizer integer property 0x%04x", param}; }
42 void EqualizerEffectHandler::SetParamiv(EqualizerProps&, ALenum param, const int*)
44 throw effect_exception{AL_INVALID_ENUM, "Invalid equalizer integer-vector property 0x%04x",
45 param};
47 void EqualizerEffectHandler::SetParamf(EqualizerProps &props, ALenum param, float val)
49 switch(param)
51 case AL_EQUALIZER_LOW_GAIN:
52 if(!(val >= AL_EQUALIZER_MIN_LOW_GAIN && val <= AL_EQUALIZER_MAX_LOW_GAIN))
53 throw effect_exception{AL_INVALID_VALUE, "Equalizer low-band gain out of range"};
54 props.LowGain = val;
55 break;
57 case AL_EQUALIZER_LOW_CUTOFF:
58 if(!(val >= AL_EQUALIZER_MIN_LOW_CUTOFF && val <= AL_EQUALIZER_MAX_LOW_CUTOFF))
59 throw effect_exception{AL_INVALID_VALUE, "Equalizer low-band cutoff out of range"};
60 props.LowCutoff = val;
61 break;
63 case AL_EQUALIZER_MID1_GAIN:
64 if(!(val >= AL_EQUALIZER_MIN_MID1_GAIN && val <= AL_EQUALIZER_MAX_MID1_GAIN))
65 throw effect_exception{AL_INVALID_VALUE, "Equalizer mid1-band gain out of range"};
66 props.Mid1Gain = val;
67 break;
69 case AL_EQUALIZER_MID1_CENTER:
70 if(!(val >= AL_EQUALIZER_MIN_MID1_CENTER && val <= AL_EQUALIZER_MAX_MID1_CENTER))
71 throw effect_exception{AL_INVALID_VALUE, "Equalizer mid1-band center out of range"};
72 props.Mid1Center = val;
73 break;
75 case AL_EQUALIZER_MID1_WIDTH:
76 if(!(val >= AL_EQUALIZER_MIN_MID1_WIDTH && val <= AL_EQUALIZER_MAX_MID1_WIDTH))
77 throw effect_exception{AL_INVALID_VALUE, "Equalizer mid1-band width out of range"};
78 props.Mid1Width = val;
79 break;
81 case AL_EQUALIZER_MID2_GAIN:
82 if(!(val >= AL_EQUALIZER_MIN_MID2_GAIN && val <= AL_EQUALIZER_MAX_MID2_GAIN))
83 throw effect_exception{AL_INVALID_VALUE, "Equalizer mid2-band gain out of range"};
84 props.Mid2Gain = val;
85 break;
87 case AL_EQUALIZER_MID2_CENTER:
88 if(!(val >= AL_EQUALIZER_MIN_MID2_CENTER && val <= AL_EQUALIZER_MAX_MID2_CENTER))
89 throw effect_exception{AL_INVALID_VALUE, "Equalizer mid2-band center out of range"};
90 props.Mid2Center = val;
91 break;
93 case AL_EQUALIZER_MID2_WIDTH:
94 if(!(val >= AL_EQUALIZER_MIN_MID2_WIDTH && val <= AL_EQUALIZER_MAX_MID2_WIDTH))
95 throw effect_exception{AL_INVALID_VALUE, "Equalizer mid2-band width out of range"};
96 props.Mid2Width = val;
97 break;
99 case AL_EQUALIZER_HIGH_GAIN:
100 if(!(val >= AL_EQUALIZER_MIN_HIGH_GAIN && val <= AL_EQUALIZER_MAX_HIGH_GAIN))
101 throw effect_exception{AL_INVALID_VALUE, "Equalizer high-band gain out of range"};
102 props.HighGain = val;
103 break;
105 case AL_EQUALIZER_HIGH_CUTOFF:
106 if(!(val >= AL_EQUALIZER_MIN_HIGH_CUTOFF && val <= AL_EQUALIZER_MAX_HIGH_CUTOFF))
107 throw effect_exception{AL_INVALID_VALUE, "Equalizer high-band cutoff out of range"};
108 props.HighCutoff = val;
109 break;
111 default:
112 throw effect_exception{AL_INVALID_ENUM, "Invalid equalizer float property 0x%04x", param};
115 void EqualizerEffectHandler::SetParamfv(EqualizerProps &props, ALenum param, const float *vals)
116 { SetParamf(props, param, *vals); }
118 void EqualizerEffectHandler::GetParami(const EqualizerProps&, ALenum param, int*)
119 { throw effect_exception{AL_INVALID_ENUM, "Invalid equalizer integer property 0x%04x", param}; }
120 void EqualizerEffectHandler::GetParamiv(const EqualizerProps&, ALenum param, int*)
122 throw effect_exception{AL_INVALID_ENUM, "Invalid equalizer integer-vector property 0x%04x",
123 param};
125 void EqualizerEffectHandler::GetParamf(const EqualizerProps &props, ALenum param, float *val)
127 switch(param)
129 case AL_EQUALIZER_LOW_GAIN: *val = props.LowGain; break;
130 case AL_EQUALIZER_LOW_CUTOFF: *val = props.LowCutoff; break;
131 case AL_EQUALIZER_MID1_GAIN: *val = props.Mid1Gain; break;
132 case AL_EQUALIZER_MID1_CENTER: *val = props.Mid1Center; break;
133 case AL_EQUALIZER_MID1_WIDTH: *val = props.Mid1Width; break;
134 case AL_EQUALIZER_MID2_GAIN: *val = props.Mid2Gain; break;
135 case AL_EQUALIZER_MID2_CENTER: *val = props.Mid2Center; break;
136 case AL_EQUALIZER_MID2_WIDTH: *val = props.Mid2Width; break;
137 case AL_EQUALIZER_HIGH_GAIN: *val = props.HighGain; break;
138 case AL_EQUALIZER_HIGH_CUTOFF: *val = props.HighCutoff; break;
140 default:
141 throw effect_exception{AL_INVALID_ENUM, "Invalid equalizer float property 0x%04x", param};
144 void EqualizerEffectHandler::GetParamfv(const EqualizerProps &props, ALenum param, float *vals)
145 { GetParamf(props, param, vals); }
148 #ifdef ALSOFT_EAX
149 namespace {
151 using EqualizerCommitter = EaxCommitter<EaxEqualizerCommitter>;
153 struct LowGainValidator {
154 void operator()(long lLowGain) const
156 eax_validate_range<EqualizerCommitter::Exception>(
157 "Low Gain",
158 lLowGain,
159 EAXEQUALIZER_MINLOWGAIN,
160 EAXEQUALIZER_MAXLOWGAIN);
162 }; // LowGainValidator
164 struct LowCutOffValidator {
165 void operator()(float flLowCutOff) const
167 eax_validate_range<EqualizerCommitter::Exception>(
168 "Low Cutoff",
169 flLowCutOff,
170 EAXEQUALIZER_MINLOWCUTOFF,
171 EAXEQUALIZER_MAXLOWCUTOFF);
173 }; // LowCutOffValidator
175 struct Mid1GainValidator {
176 void operator()(long lMid1Gain) const
178 eax_validate_range<EqualizerCommitter::Exception>(
179 "Mid1 Gain",
180 lMid1Gain,
181 EAXEQUALIZER_MINMID1GAIN,
182 EAXEQUALIZER_MAXMID1GAIN);
184 }; // Mid1GainValidator
186 struct Mid1CenterValidator {
187 void operator()(float flMid1Center) const
189 eax_validate_range<EqualizerCommitter::Exception>(
190 "Mid1 Center",
191 flMid1Center,
192 EAXEQUALIZER_MINMID1CENTER,
193 EAXEQUALIZER_MAXMID1CENTER);
195 }; // Mid1CenterValidator
197 struct Mid1WidthValidator {
198 void operator()(float flMid1Width) const
200 eax_validate_range<EqualizerCommitter::Exception>(
201 "Mid1 Width",
202 flMid1Width,
203 EAXEQUALIZER_MINMID1WIDTH,
204 EAXEQUALIZER_MAXMID1WIDTH);
206 }; // Mid1WidthValidator
208 struct Mid2GainValidator {
209 void operator()(long lMid2Gain) const
211 eax_validate_range<EqualizerCommitter::Exception>(
212 "Mid2 Gain",
213 lMid2Gain,
214 EAXEQUALIZER_MINMID2GAIN,
215 EAXEQUALIZER_MAXMID2GAIN);
217 }; // Mid2GainValidator
219 struct Mid2CenterValidator {
220 void operator()(float flMid2Center) const
222 eax_validate_range<EqualizerCommitter::Exception>(
223 "Mid2 Center",
224 flMid2Center,
225 EAXEQUALIZER_MINMID2CENTER,
226 EAXEQUALIZER_MAXMID2CENTER);
228 }; // Mid2CenterValidator
230 struct Mid2WidthValidator {
231 void operator()(float flMid2Width) const
233 eax_validate_range<EqualizerCommitter::Exception>(
234 "Mid2 Width",
235 flMid2Width,
236 EAXEQUALIZER_MINMID2WIDTH,
237 EAXEQUALIZER_MAXMID2WIDTH);
239 }; // Mid2WidthValidator
241 struct HighGainValidator {
242 void operator()(long lHighGain) const
244 eax_validate_range<EqualizerCommitter::Exception>(
245 "High Gain",
246 lHighGain,
247 EAXEQUALIZER_MINHIGHGAIN,
248 EAXEQUALIZER_MAXHIGHGAIN);
250 }; // HighGainValidator
252 struct HighCutOffValidator {
253 void operator()(float flHighCutOff) const
255 eax_validate_range<EqualizerCommitter::Exception>(
256 "High Cutoff",
257 flHighCutOff,
258 EAXEQUALIZER_MINHIGHCUTOFF,
259 EAXEQUALIZER_MAXHIGHCUTOFF);
261 }; // HighCutOffValidator
263 struct AllValidator {
264 void operator()(const EAXEQUALIZERPROPERTIES& all) const
266 LowGainValidator{}(all.lLowGain);
267 LowCutOffValidator{}(all.flLowCutOff);
268 Mid1GainValidator{}(all.lMid1Gain);
269 Mid1CenterValidator{}(all.flMid1Center);
270 Mid1WidthValidator{}(all.flMid1Width);
271 Mid2GainValidator{}(all.lMid2Gain);
272 Mid2CenterValidator{}(all.flMid2Center);
273 Mid2WidthValidator{}(all.flMid2Width);
274 HighGainValidator{}(all.lHighGain);
275 HighCutOffValidator{}(all.flHighCutOff);
277 }; // AllValidator
279 } // namespace
281 template<>
282 struct EqualizerCommitter::Exception : public EaxException {
283 explicit Exception(const char* message) : EaxException{"EAX_EQUALIZER_EFFECT", message}
287 template<>
288 [[noreturn]] void EqualizerCommitter::fail(const char *message)
290 throw Exception{message};
293 bool EaxEqualizerCommitter::commit(const EAXEQUALIZERPROPERTIES &props)
295 if(auto *cur = std::get_if<EAXEQUALIZERPROPERTIES>(&mEaxProps); cur && *cur == props)
296 return false;
298 mEaxProps = props;
299 mAlProps = [&]{
300 EqualizerProps ret{};
301 ret.LowGain = level_mb_to_gain(static_cast<float>(props.lLowGain));
302 ret.LowCutoff = props.flLowCutOff;
303 ret.Mid1Gain = level_mb_to_gain(static_cast<float>(props.lMid1Gain));
304 ret.Mid1Center = props.flMid1Center;
305 ret.Mid1Width = props.flMid1Width;
306 ret.Mid2Gain = level_mb_to_gain(static_cast<float>(props.lMid2Gain));
307 ret.Mid2Center = props.flMid2Center;
308 ret.Mid2Width = props.flMid2Width;
309 ret.HighGain = level_mb_to_gain(static_cast<float>(props.lHighGain));
310 ret.HighCutoff = props.flHighCutOff;
311 return ret;
312 }();
314 return true;
317 void EaxEqualizerCommitter::SetDefaults(EaxEffectProps &props)
319 static constexpr EAXEQUALIZERPROPERTIES defprops{[]
321 EAXEQUALIZERPROPERTIES ret{};
322 ret.lLowGain = EAXEQUALIZER_DEFAULTLOWGAIN;
323 ret.flLowCutOff = EAXEQUALIZER_DEFAULTLOWCUTOFF;
324 ret.lMid1Gain = EAXEQUALIZER_DEFAULTMID1GAIN;
325 ret.flMid1Center = EAXEQUALIZER_DEFAULTMID1CENTER;
326 ret.flMid1Width = EAXEQUALIZER_DEFAULTMID1WIDTH;
327 ret.lMid2Gain = EAXEQUALIZER_DEFAULTMID2GAIN;
328 ret.flMid2Center = EAXEQUALIZER_DEFAULTMID2CENTER;
329 ret.flMid2Width = EAXEQUALIZER_DEFAULTMID2WIDTH;
330 ret.lHighGain = EAXEQUALIZER_DEFAULTHIGHGAIN;
331 ret.flHighCutOff = EAXEQUALIZER_DEFAULTHIGHCUTOFF;
332 return ret;
333 }()};
334 props = defprops;
337 void EaxEqualizerCommitter::Get(const EaxCall &call, const EAXEQUALIZERPROPERTIES &props)
339 switch(call.get_property_id())
341 case EAXEQUALIZER_NONE: break;
342 case EAXEQUALIZER_ALLPARAMETERS: call.set_value<Exception>(props); break;
343 case EAXEQUALIZER_LOWGAIN: call.set_value<Exception>(props.lLowGain); break;
344 case EAXEQUALIZER_LOWCUTOFF: call.set_value<Exception>(props.flLowCutOff); break;
345 case EAXEQUALIZER_MID1GAIN: call.set_value<Exception>(props.lMid1Gain); break;
346 case EAXEQUALIZER_MID1CENTER: call.set_value<Exception>(props.flMid1Center); break;
347 case EAXEQUALIZER_MID1WIDTH: call.set_value<Exception>(props.flMid1Width); break;
348 case EAXEQUALIZER_MID2GAIN: call.set_value<Exception>(props.lMid2Gain); break;
349 case EAXEQUALIZER_MID2CENTER: call.set_value<Exception>(props.flMid2Center); break;
350 case EAXEQUALIZER_MID2WIDTH: call.set_value<Exception>(props.flMid2Width); break;
351 case EAXEQUALIZER_HIGHGAIN: call.set_value<Exception>(props.lHighGain); break;
352 case EAXEQUALIZER_HIGHCUTOFF: call.set_value<Exception>(props.flHighCutOff); break;
353 default: fail_unknown_property_id();
357 void EaxEqualizerCommitter::Set(const EaxCall &call, EAXEQUALIZERPROPERTIES &props)
359 switch(call.get_property_id())
361 case EAXEQUALIZER_NONE: break;
362 case EAXEQUALIZER_ALLPARAMETERS: defer<AllValidator>(call, props); break;
363 case EAXEQUALIZER_LOWGAIN: defer<LowGainValidator>(call, props.lLowGain); break;
364 case EAXEQUALIZER_LOWCUTOFF: defer<LowCutOffValidator>(call, props.flLowCutOff); break;
365 case EAXEQUALIZER_MID1GAIN: defer<Mid1GainValidator>(call, props.lMid1Gain); break;
366 case EAXEQUALIZER_MID1CENTER: defer<Mid1CenterValidator>(call, props.flMid1Center); break;
367 case EAXEQUALIZER_MID1WIDTH: defer<Mid1WidthValidator>(call, props.flMid1Width); break;
368 case EAXEQUALIZER_MID2GAIN: defer<Mid2GainValidator>(call, props.lMid2Gain); break;
369 case EAXEQUALIZER_MID2CENTER: defer<Mid2CenterValidator>(call, props.flMid2Center); break;
370 case EAXEQUALIZER_MID2WIDTH: defer<Mid2WidthValidator>(call, props.flMid2Width); break;
371 case EAXEQUALIZER_HIGHGAIN: defer<HighGainValidator>(call, props.lHighGain); break;
372 case EAXEQUALIZER_HIGHCUTOFF: defer<HighCutOffValidator>(call, props.flHighCutOff); break;
373 default: fail_unknown_property_id();
377 #endif // ALSOFT_EAX