Handle AL effect properties with a variant
[openal-soft.git] / al / effects / modulator.cpp
blob856c85a977877199abbc64931124163cbfadc63f
2 #include "config.h"
4 #include <optional>
5 #include <stdexcept>
7 #include "AL/al.h"
8 #include "AL/efx.h"
10 #include "alc/effects/base.h"
11 #include "effects.h"
13 #ifdef ALSOFT_EAX
14 #include <cassert>
15 #include "alnumeric.h"
16 #include "al/eax/effect.h"
17 #include "al/eax/exception.h"
18 #include "al/eax/utils.h"
19 #endif // ALSOFT_EAX
22 namespace {
24 constexpr std::optional<ModulatorWaveform> WaveformFromEmum(ALenum value) noexcept
26 switch(value)
28 case AL_RING_MODULATOR_SINUSOID: return ModulatorWaveform::Sinusoid;
29 case AL_RING_MODULATOR_SAWTOOTH: return ModulatorWaveform::Sawtooth;
30 case AL_RING_MODULATOR_SQUARE: return ModulatorWaveform::Square;
32 return std::nullopt;
34 constexpr ALenum EnumFromWaveform(ModulatorWaveform type)
36 switch(type)
38 case ModulatorWaveform::Sinusoid: return AL_RING_MODULATOR_SINUSOID;
39 case ModulatorWaveform::Sawtooth: return AL_RING_MODULATOR_SAWTOOTH;
40 case ModulatorWaveform::Square: return AL_RING_MODULATOR_SQUARE;
42 throw std::runtime_error{"Invalid modulator waveform: " +
43 std::to_string(static_cast<int>(type))};
46 constexpr EffectProps genDefaultProps() noexcept
48 ModulatorProps props{};
49 props.Frequency = AL_RING_MODULATOR_DEFAULT_FREQUENCY;
50 props.HighPassCutoff = AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF;
51 props.Waveform = WaveformFromEmum(AL_RING_MODULATOR_DEFAULT_WAVEFORM).value();
52 return props;
55 } // namespace
57 const EffectProps ModulatorEffectProps{genDefaultProps()};
59 void ModulatorEffectHandler::SetParami(ModulatorProps &props, ALenum param, int val)
61 switch(param)
63 case AL_RING_MODULATOR_FREQUENCY:
64 case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
65 SetParamf(props, param, static_cast<float>(val));
66 break;
68 case AL_RING_MODULATOR_WAVEFORM:
69 if(auto formopt = WaveformFromEmum(val))
70 props.Waveform = *formopt;
71 else
72 throw effect_exception{AL_INVALID_VALUE, "Invalid modulator waveform: 0x%04x", val};
73 break;
75 default:
76 throw effect_exception{AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x",
77 param};
80 void ModulatorEffectHandler::SetParamiv(ModulatorProps &props, ALenum param, const int *vals)
81 { SetParami(props, param, *vals); }
83 void ModulatorEffectHandler::SetParamf(ModulatorProps &props, ALenum param, float val)
85 switch(param)
87 case AL_RING_MODULATOR_FREQUENCY:
88 if(!(val >= AL_RING_MODULATOR_MIN_FREQUENCY && val <= AL_RING_MODULATOR_MAX_FREQUENCY))
89 throw effect_exception{AL_INVALID_VALUE, "Modulator frequency out of range: %f", val};
90 props.Frequency = val;
91 break;
93 case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
94 if(!(val >= AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF && val <= AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF))
95 throw effect_exception{AL_INVALID_VALUE, "Modulator high-pass cutoff out of range: %f", val};
96 props.HighPassCutoff = val;
97 break;
99 default:
100 throw effect_exception{AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param};
103 void ModulatorEffectHandler::SetParamfv(ModulatorProps &props, ALenum param, const float *vals)
104 { SetParamf(props, param, *vals); }
106 void ModulatorEffectHandler::GetParami(const ModulatorProps &props, ALenum param, int *val)
108 switch(param)
110 case AL_RING_MODULATOR_FREQUENCY: *val = static_cast<int>(props.Frequency); break;
111 case AL_RING_MODULATOR_HIGHPASS_CUTOFF: *val = static_cast<int>(props.HighPassCutoff); break;
112 case AL_RING_MODULATOR_WAVEFORM: *val = EnumFromWaveform(props.Waveform); break;
114 default:
115 throw effect_exception{AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x",
116 param};
119 void ModulatorEffectHandler::GetParamiv(const ModulatorProps &props, ALenum param, int *vals)
120 { GetParami(props, param, vals); }
121 void ModulatorEffectHandler::GetParamf(const ModulatorProps &props, ALenum param, float *val)
123 switch(param)
125 case AL_RING_MODULATOR_FREQUENCY: *val = props.Frequency; break;
126 case AL_RING_MODULATOR_HIGHPASS_CUTOFF: *val = props.HighPassCutoff; break;
128 default:
129 throw effect_exception{AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param};
132 void ModulatorEffectHandler::GetParamfv(const ModulatorProps &props, ALenum param, float *vals)
133 { GetParamf(props, param, vals); }
136 #ifdef ALSOFT_EAX
137 namespace {
139 using ModulatorCommitter = EaxCommitter<EaxModulatorCommitter>;
141 struct FrequencyValidator {
142 void operator()(float flFrequency) const
144 eax_validate_range<ModulatorCommitter::Exception>(
145 "Frequency",
146 flFrequency,
147 EAXRINGMODULATOR_MINFREQUENCY,
148 EAXRINGMODULATOR_MAXFREQUENCY);
150 }; // FrequencyValidator
152 struct HighPassCutOffValidator {
153 void operator()(float flHighPassCutOff) const
155 eax_validate_range<ModulatorCommitter::Exception>(
156 "High-Pass Cutoff",
157 flHighPassCutOff,
158 EAXRINGMODULATOR_MINHIGHPASSCUTOFF,
159 EAXRINGMODULATOR_MAXHIGHPASSCUTOFF);
161 }; // HighPassCutOffValidator
163 struct WaveformValidator {
164 void operator()(unsigned long ulWaveform) const
166 eax_validate_range<ModulatorCommitter::Exception>(
167 "Waveform",
168 ulWaveform,
169 EAXRINGMODULATOR_MINWAVEFORM,
170 EAXRINGMODULATOR_MAXWAVEFORM);
172 }; // WaveformValidator
174 struct AllValidator {
175 void operator()(const EAXRINGMODULATORPROPERTIES& all) const
177 FrequencyValidator{}(all.flFrequency);
178 HighPassCutOffValidator{}(all.flHighPassCutOff);
179 WaveformValidator{}(all.ulWaveform);
181 }; // AllValidator
183 } // namespace
185 template<>
186 struct ModulatorCommitter::Exception : public EaxException {
187 explicit Exception(const char *message) : EaxException{"EAX_RING_MODULATOR_EFFECT", message}
191 template<>
192 [[noreturn]] void ModulatorCommitter::fail(const char *message)
194 throw Exception{message};
197 bool EaxModulatorCommitter::commit(const EAXRINGMODULATORPROPERTIES &props)
199 if(auto *cur = std::get_if<EAXRINGMODULATORPROPERTIES>(&mEaxProps); cur && *cur == props)
200 return false;
202 mEaxProps = props;
204 auto get_waveform = [](unsigned long form)
206 if(form == EAX_RINGMODULATOR_SINUSOID)
207 return ModulatorWaveform::Sinusoid;
208 if(form == EAX_RINGMODULATOR_SAWTOOTH)
209 return ModulatorWaveform::Sawtooth;
210 if(form == EAX_RINGMODULATOR_SQUARE)
211 return ModulatorWaveform::Square;
212 return ModulatorWaveform::Sinusoid;
215 mAlProps = [&]{
216 ModulatorProps ret{};
217 ret.Frequency = props.flFrequency;
218 ret.HighPassCutoff = props.flHighPassCutOff;
219 ret.Waveform = get_waveform(props.ulWaveform);
220 return ret;
221 }();
223 return true;
226 void EaxModulatorCommitter::SetDefaults(EaxEffectProps &props)
228 static constexpr EAXRINGMODULATORPROPERTIES defprops{[]
230 EAXRINGMODULATORPROPERTIES ret{};
231 ret.flFrequency = EAXRINGMODULATOR_DEFAULTFREQUENCY;
232 ret.flHighPassCutOff = EAXRINGMODULATOR_DEFAULTHIGHPASSCUTOFF;
233 ret.ulWaveform = EAXRINGMODULATOR_DEFAULTWAVEFORM;
234 return ret;
235 }()};
236 props = defprops;
239 void EaxModulatorCommitter::Get(const EaxCall &call, const EAXRINGMODULATORPROPERTIES &props)
241 switch(call.get_property_id())
243 case EAXRINGMODULATOR_NONE: break;
244 case EAXRINGMODULATOR_ALLPARAMETERS: call.set_value<Exception>(props); break;
245 case EAXRINGMODULATOR_FREQUENCY: call.set_value<Exception>(props.flFrequency); break;
246 case EAXRINGMODULATOR_HIGHPASSCUTOFF: call.set_value<Exception>(props.flHighPassCutOff); break;
247 case EAXRINGMODULATOR_WAVEFORM: call.set_value<Exception>(props.ulWaveform); break;
248 default: fail_unknown_property_id();
252 void EaxModulatorCommitter::Set(const EaxCall &call, EAXRINGMODULATORPROPERTIES &props)
254 switch(call.get_property_id())
256 case EAXRINGMODULATOR_NONE: break;
257 case EAXRINGMODULATOR_ALLPARAMETERS: defer<AllValidator>(call, props); break;
258 case EAXRINGMODULATOR_FREQUENCY: defer<FrequencyValidator>(call, props.flFrequency); break;
259 case EAXRINGMODULATOR_HIGHPASSCUTOFF: defer<HighPassCutOffValidator>(call, props.flHighPassCutOff); break;
260 case EAXRINGMODULATOR_WAVEFORM: defer<WaveformValidator>(call, props.ulWaveform); break;
261 default: fail_unknown_property_id();
265 #endif // ALSOFT_EAX