]> git.tdb.fi Git - ext/openal.git/blob - al/effects/modulator.cpp
Import OpenAL Soft 1.23.1 sources
[ext/openal.git] / al / effects / modulator.cpp
1
2 #include "config.h"
3
4 #include <stdexcept>
5
6 #include "AL/al.h"
7 #include "AL/efx.h"
8
9 #include "alc/effects/base.h"
10 #include "aloptional.h"
11 #include "effects.h"
12
13 #ifdef ALSOFT_EAX
14 #include <cassert>
15 #include "alnumeric.h"
16 #include "al/eax/exception.h"
17 #include "al/eax/utils.h"
18 #endif // ALSOFT_EAX
19
20
21 namespace {
22
23 al::optional<ModulatorWaveform> WaveformFromEmum(ALenum value)
24 {
25     switch(value)
26     {
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;
30     }
31     return al::nullopt;
32 }
33 ALenum EnumFromWaveform(ModulatorWaveform type)
34 {
35     switch(type)
36     {
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;
40     }
41     throw std::runtime_error{"Invalid modulator waveform: " +
42         std::to_string(static_cast<int>(type))};
43 }
44
45 void Modulator_setParamf(EffectProps *props, ALenum param, float val)
46 {
47     switch(param)
48     {
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;
53         break;
54
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;
59         break;
60
61     default:
62         throw effect_exception{AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param};
63     }
64 }
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)
68 {
69     switch(param)
70     {
71     case AL_RING_MODULATOR_FREQUENCY:
72     case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
73         Modulator_setParamf(props, param, static_cast<float>(val));
74         break;
75
76     case AL_RING_MODULATOR_WAVEFORM:
77         if(auto formopt = WaveformFromEmum(val))
78             props->Modulator.Waveform = *formopt;
79         else
80             throw effect_exception{AL_INVALID_VALUE, "Invalid modulator waveform: 0x%04x", val};
81         break;
82
83     default:
84         throw effect_exception{AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x",
85             param};
86     }
87 }
88 void Modulator_setParamiv(EffectProps *props, ALenum param, const int *vals)
89 { Modulator_setParami(props, param, vals[0]); }
90
91 void Modulator_getParami(const EffectProps *props, ALenum param, int *val)
92 {
93     switch(param)
94     {
95     case AL_RING_MODULATOR_FREQUENCY:
96         *val = static_cast<int>(props->Modulator.Frequency);
97         break;
98     case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
99         *val = static_cast<int>(props->Modulator.HighPassCutoff);
100         break;
101     case AL_RING_MODULATOR_WAVEFORM:
102         *val = EnumFromWaveform(props->Modulator.Waveform);
103         break;
104
105     default:
106         throw effect_exception{AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x",
107             param};
108     }
109 }
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)
113 {
114     switch(param)
115     {
116     case AL_RING_MODULATOR_FREQUENCY:
117         *val = props->Modulator.Frequency;
118         break;
119     case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
120         *val = props->Modulator.HighPassCutoff;
121         break;
122
123     default:
124         throw effect_exception{AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param};
125     }
126 }
127 void Modulator_getParamfv(const EffectProps *props, ALenum param, float *vals)
128 { Modulator_getParamf(props, param, vals); }
129
130 EffectProps genDefaultProps() noexcept
131 {
132     EffectProps props{};
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);
136     return props;
137 }
138
139 } // namespace
140
141 DEFINE_ALEFFECT_VTABLE(Modulator);
142
143 const EffectProps ModulatorEffectProps{genDefaultProps()};
144
145 #ifdef ALSOFT_EAX
146 namespace {
147
148 using ModulatorCommitter = EaxCommitter<EaxModulatorCommitter>;
149
150 struct FrequencyValidator {
151     void operator()(float flFrequency) const
152     {
153         eax_validate_range<ModulatorCommitter::Exception>(
154             "Frequency",
155             flFrequency,
156             EAXRINGMODULATOR_MINFREQUENCY,
157             EAXRINGMODULATOR_MAXFREQUENCY);
158     }
159 }; // FrequencyValidator
160
161 struct HighPassCutOffValidator {
162     void operator()(float flHighPassCutOff) const
163     {
164         eax_validate_range<ModulatorCommitter::Exception>(
165             "High-Pass Cutoff",
166             flHighPassCutOff,
167             EAXRINGMODULATOR_MINHIGHPASSCUTOFF,
168             EAXRINGMODULATOR_MAXHIGHPASSCUTOFF);
169     }
170 }; // HighPassCutOffValidator
171
172 struct WaveformValidator {
173     void operator()(unsigned long ulWaveform) const
174     {
175         eax_validate_range<ModulatorCommitter::Exception>(
176             "Waveform",
177             ulWaveform,
178             EAXRINGMODULATOR_MINWAVEFORM,
179             EAXRINGMODULATOR_MAXWAVEFORM);
180     }
181 }; // WaveformValidator
182
183 struct AllValidator {
184     void operator()(const EAXRINGMODULATORPROPERTIES& all) const
185     {
186         FrequencyValidator{}(all.flFrequency);
187         HighPassCutOffValidator{}(all.flHighPassCutOff);
188         WaveformValidator{}(all.ulWaveform);
189     }
190 }; // AllValidator
191
192 } // namespace
193
194 template<>
195 struct ModulatorCommitter::Exception : public EaxException {
196     explicit Exception(const char *message) : EaxException{"EAX_RING_MODULATOR_EFFECT", message}
197     { }
198 };
199
200 template<>
201 [[noreturn]] void ModulatorCommitter::fail(const char *message)
202 {
203     throw Exception{message};
204 }
205
206 template<>
207 bool ModulatorCommitter::commit(const EaxEffectProps &props)
208 {
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)
213         return false;
214
215     mEaxProps = props;
216
217     auto get_waveform = [](unsigned long form)
218     {
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;
226     };
227
228     mAlProps.Modulator.Frequency = props.mModulator.flFrequency;
229     mAlProps.Modulator.HighPassCutoff = props.mModulator.flHighPassCutOff;
230     mAlProps.Modulator.Waveform = get_waveform(props.mModulator.ulWaveform);
231
232     return true;
233 }
234
235 template<>
236 void ModulatorCommitter::SetDefaults(EaxEffectProps &props)
237 {
238     props.mType = EaxEffectType::Modulator;
239     props.mModulator.flFrequency = EAXRINGMODULATOR_DEFAULTFREQUENCY;
240     props.mModulator.flHighPassCutOff = EAXRINGMODULATOR_DEFAULTHIGHPASSCUTOFF;
241     props.mModulator.ulWaveform = EAXRINGMODULATOR_DEFAULTWAVEFORM;
242 }
243
244 template<>
245 void ModulatorCommitter::Get(const EaxCall &call, const EaxEffectProps &props)
246 {
247     switch(call.get_property_id())
248     {
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();
255     }
256 }
257
258 template<>
259 void ModulatorCommitter::Set(const EaxCall &call, EaxEffectProps &props)
260 {
261     switch (call.get_property_id())
262     {
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();
269     }
270 }
271
272 #endif // ALSOFT_EAX