9 #include "alc/effects/base.h"
10 #include "aloptional.h"
15 #include "alnumeric.h"
16 #include "al/eax/exception.h"
17 #include "al/eax/utils.h"
23 al::optional<ModulatorWaveform> WaveformFromEmum(ALenum value)
27 case AL_RING_MODULATOR_SINUSOID: return ModulatorWaveform::Sinusoid;
28 case AL_RING_MODULATOR_SAWTOOTH: return ModulatorWaveform::Sawtooth;
29 case AL_RING_MODULATOR_SQUARE: return ModulatorWaveform::Square;
33 ALenum EnumFromWaveform(ModulatorWaveform type)
37 case ModulatorWaveform::Sinusoid: return AL_RING_MODULATOR_SINUSOID;
38 case ModulatorWaveform::Sawtooth: return AL_RING_MODULATOR_SAWTOOTH;
39 case ModulatorWaveform::Square: return AL_RING_MODULATOR_SQUARE;
41 throw std::runtime_error{"Invalid modulator waveform: " +
42 std::to_string(static_cast<int>(type))};
45 void Modulator_setParamf(EffectProps *props, ALenum param, float val)
49 case AL_RING_MODULATOR_FREQUENCY:
50 if(!(val >= AL_RING_MODULATOR_MIN_FREQUENCY && val <= AL_RING_MODULATOR_MAX_FREQUENCY))
51 throw effect_exception{AL_INVALID_VALUE, "Modulator frequency out of range: %f", val};
52 props->Modulator.Frequency = val;
55 case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
56 if(!(val >= AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF && val <= AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF))
57 throw effect_exception{AL_INVALID_VALUE, "Modulator high-pass cutoff out of range: %f", val};
58 props->Modulator.HighPassCutoff = val;
62 throw effect_exception{AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param};
65 void Modulator_setParamfv(EffectProps *props, ALenum param, const float *vals)
66 { Modulator_setParamf(props, param, vals[0]); }
67 void Modulator_setParami(EffectProps *props, ALenum param, int val)
71 case AL_RING_MODULATOR_FREQUENCY:
72 case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
73 Modulator_setParamf(props, param, static_cast<float>(val));
76 case AL_RING_MODULATOR_WAVEFORM:
77 if(auto formopt = WaveformFromEmum(val))
78 props->Modulator.Waveform = *formopt;
80 throw effect_exception{AL_INVALID_VALUE, "Invalid modulator waveform: 0x%04x", val};
84 throw effect_exception{AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x",
88 void Modulator_setParamiv(EffectProps *props, ALenum param, const int *vals)
89 { Modulator_setParami(props, param, vals[0]); }
91 void Modulator_getParami(const EffectProps *props, ALenum param, int *val)
95 case AL_RING_MODULATOR_FREQUENCY:
96 *val = static_cast<int>(props->Modulator.Frequency);
98 case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
99 *val = static_cast<int>(props->Modulator.HighPassCutoff);
101 case AL_RING_MODULATOR_WAVEFORM:
102 *val = EnumFromWaveform(props->Modulator.Waveform);
106 throw effect_exception{AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x",
110 void Modulator_getParamiv(const EffectProps *props, ALenum param, int *vals)
111 { Modulator_getParami(props, param, vals); }
112 void Modulator_getParamf(const EffectProps *props, ALenum param, float *val)
116 case AL_RING_MODULATOR_FREQUENCY:
117 *val = props->Modulator.Frequency;
119 case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
120 *val = props->Modulator.HighPassCutoff;
124 throw effect_exception{AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param};
127 void Modulator_getParamfv(const EffectProps *props, ALenum param, float *vals)
128 { Modulator_getParamf(props, param, vals); }
130 EffectProps genDefaultProps() noexcept
133 props.Modulator.Frequency = AL_RING_MODULATOR_DEFAULT_FREQUENCY;
134 props.Modulator.HighPassCutoff = AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF;
135 props.Modulator.Waveform = *WaveformFromEmum(AL_RING_MODULATOR_DEFAULT_WAVEFORM);
141 DEFINE_ALEFFECT_VTABLE(Modulator);
143 const EffectProps ModulatorEffectProps{genDefaultProps()};
148 using ModulatorCommitter = EaxCommitter<EaxModulatorCommitter>;
150 struct FrequencyValidator {
151 void operator()(float flFrequency) const
153 eax_validate_range<ModulatorCommitter::Exception>(
156 EAXRINGMODULATOR_MINFREQUENCY,
157 EAXRINGMODULATOR_MAXFREQUENCY);
159 }; // FrequencyValidator
161 struct HighPassCutOffValidator {
162 void operator()(float flHighPassCutOff) const
164 eax_validate_range<ModulatorCommitter::Exception>(
167 EAXRINGMODULATOR_MINHIGHPASSCUTOFF,
168 EAXRINGMODULATOR_MAXHIGHPASSCUTOFF);
170 }; // HighPassCutOffValidator
172 struct WaveformValidator {
173 void operator()(unsigned long ulWaveform) const
175 eax_validate_range<ModulatorCommitter::Exception>(
178 EAXRINGMODULATOR_MINWAVEFORM,
179 EAXRINGMODULATOR_MAXWAVEFORM);
181 }; // WaveformValidator
183 struct AllValidator {
184 void operator()(const EAXRINGMODULATORPROPERTIES& all) const
186 FrequencyValidator{}(all.flFrequency);
187 HighPassCutOffValidator{}(all.flHighPassCutOff);
188 WaveformValidator{}(all.ulWaveform);
195 struct ModulatorCommitter::Exception : public EaxException {
196 explicit Exception(const char *message) : EaxException{"EAX_RING_MODULATOR_EFFECT", message}
201 [[noreturn]] void ModulatorCommitter::fail(const char *message)
203 throw Exception{message};
207 bool ModulatorCommitter::commit(const EaxEffectProps &props)
209 if(props.mType == mEaxProps.mType
210 && mEaxProps.mModulator.flFrequency == props.mModulator.flFrequency
211 && mEaxProps.mModulator.flHighPassCutOff == props.mModulator.flHighPassCutOff
212 && mEaxProps.mModulator.ulWaveform == props.mModulator.ulWaveform)
217 auto get_waveform = [](unsigned long form)
219 if(form == EAX_RINGMODULATOR_SINUSOID)
220 return ModulatorWaveform::Sinusoid;
221 if(form == EAX_RINGMODULATOR_SAWTOOTH)
222 return ModulatorWaveform::Sawtooth;
223 if(form == EAX_RINGMODULATOR_SQUARE)
224 return ModulatorWaveform::Square;
225 return ModulatorWaveform::Sinusoid;
228 mAlProps.Modulator.Frequency = props.mModulator.flFrequency;
229 mAlProps.Modulator.HighPassCutoff = props.mModulator.flHighPassCutOff;
230 mAlProps.Modulator.Waveform = get_waveform(props.mModulator.ulWaveform);
236 void ModulatorCommitter::SetDefaults(EaxEffectProps &props)
238 props.mType = EaxEffectType::Modulator;
239 props.mModulator.flFrequency = EAXRINGMODULATOR_DEFAULTFREQUENCY;
240 props.mModulator.flHighPassCutOff = EAXRINGMODULATOR_DEFAULTHIGHPASSCUTOFF;
241 props.mModulator.ulWaveform = EAXRINGMODULATOR_DEFAULTWAVEFORM;
245 void ModulatorCommitter::Get(const EaxCall &call, const EaxEffectProps &props)
247 switch(call.get_property_id())
249 case EAXRINGMODULATOR_NONE: break;
250 case EAXRINGMODULATOR_ALLPARAMETERS: call.set_value<Exception>(props.mModulator); break;
251 case EAXRINGMODULATOR_FREQUENCY: call.set_value<Exception>(props.mModulator.flFrequency); break;
252 case EAXRINGMODULATOR_HIGHPASSCUTOFF: call.set_value<Exception>(props.mModulator.flHighPassCutOff); break;
253 case EAXRINGMODULATOR_WAVEFORM: call.set_value<Exception>(props.mModulator.ulWaveform); break;
254 default: fail_unknown_property_id();
259 void ModulatorCommitter::Set(const EaxCall &call, EaxEffectProps &props)
261 switch (call.get_property_id())
263 case EAXRINGMODULATOR_NONE: break;
264 case EAXRINGMODULATOR_ALLPARAMETERS: defer<AllValidator>(call, props.mModulator); break;
265 case EAXRINGMODULATOR_FREQUENCY: defer<FrequencyValidator>(call, props.mModulator.flFrequency); break;
266 case EAXRINGMODULATOR_HIGHPASSCUTOFF: defer<HighPassCutOffValidator>(call, props.mModulator.flHighPassCutOff); break;
267 case EAXRINGMODULATOR_WAVEFORM: defer<WaveformValidator>(call, props.mModulator.ulWaveform); break;
268 default: fail_unknown_property_id();