2 * OpenAL cross platform audio library
3 * Copyright (C) 2009 by Chris Robinson.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
29 #include "al/auxeffectslot.h"
31 #include "alcontext.h"
33 #include "filters/biquad.h"
39 #define MAX_UPDATE_SAMPLES 128
41 #define WAVEFORM_FRACBITS 24
42 #define WAVEFORM_FRACONE (1<<WAVEFORM_FRACBITS)
43 #define WAVEFORM_FRACMASK (WAVEFORM_FRACONE-1)
45 inline ALfloat
Sin(ALuint index
)
47 return std::sin(static_cast<ALfloat
>(index
) *
48 (al::MathDefs
<float>::Tau() / ALfloat
{WAVEFORM_FRACONE
}));
51 inline ALfloat
Saw(ALuint index
)
53 return static_cast<ALfloat
>(index
)*(2.0f
/WAVEFORM_FRACONE
) - 1.0f
;
56 inline ALfloat
Square(ALuint index
)
58 return static_cast<ALfloat
>(((index
>>(WAVEFORM_FRACBITS
-2))&2) - 1);
61 inline ALfloat
One(ALuint
)
66 template<ALfloat
func(ALuint
)>
67 void Modulate(ALfloat
*RESTRICT dst
, ALuint index
, const ALuint step
, size_t todo
)
69 for(size_t i
{0u};i
< todo
;i
++)
72 index
&= WAVEFORM_FRACMASK
;
78 struct ModulatorState final
: public EffectState
{
79 void (*mGetSamples
)(ALfloat
*RESTRICT
, ALuint
, const ALuint
, size_t){};
87 ALfloat CurrentGains
[MAX_OUTPUT_CHANNELS
]{};
88 ALfloat TargetGains
[MAX_OUTPUT_CHANNELS
]{};
89 } mChans
[MAX_AMBI_CHANNELS
];
92 ALboolean
deviceUpdate(const ALCdevice
*device
) override
;
93 void update(const ALCcontext
*context
, const ALeffectslot
*slot
, const EffectProps
*props
, const EffectTarget target
) override
;
94 void process(const size_t samplesToDo
, const al::span
<const FloatBufferLine
> samplesIn
, const al::span
<FloatBufferLine
> samplesOut
) override
;
96 DEF_NEWDEL(ModulatorState
)
99 ALboolean
ModulatorState::deviceUpdate(const ALCdevice
*)
101 for(auto &e
: mChans
)
104 std::fill(std::begin(e
.CurrentGains
), std::end(e
.CurrentGains
), 0.0f
);
109 void ModulatorState::update(const ALCcontext
*context
, const ALeffectslot
*slot
, const EffectProps
*props
, const EffectTarget target
)
111 const ALCdevice
*device
{context
->mDevice
.get()};
113 const float step
{props
->Modulator
.Frequency
/ static_cast<ALfloat
>(device
->Frequency
)};
114 mStep
= fastf2u(clampf(step
*WAVEFORM_FRACONE
, 0.0f
, ALfloat
{WAVEFORM_FRACONE
-1}));
117 mGetSamples
= Modulate
<One
>;
118 else if(props
->Modulator
.Waveform
== AL_RING_MODULATOR_SINUSOID
)
119 mGetSamples
= Modulate
<Sin
>;
120 else if(props
->Modulator
.Waveform
== AL_RING_MODULATOR_SAWTOOTH
)
121 mGetSamples
= Modulate
<Saw
>;
122 else /*if(props->Modulator.Waveform == AL_RING_MODULATOR_SQUARE)*/
123 mGetSamples
= Modulate
<Square
>;
125 ALfloat f0norm
{props
->Modulator
.HighPassCutoff
/ static_cast<ALfloat
>(device
->Frequency
)};
126 f0norm
= clampf(f0norm
, 1.0f
/512.0f
, 0.49f
);
127 /* Bandwidth value is constant in octaves. */
128 mChans
[0].Filter
.setParams(BiquadType::HighPass
, 1.0f
, f0norm
,
129 BiquadFilter::rcpQFromBandwidth(f0norm
, 0.75f
));
130 for(size_t i
{1u};i
< slot
->Wet
.Buffer
.size();++i
)
131 mChans
[i
].Filter
.copyParamsFrom(mChans
[0].Filter
);
133 mOutTarget
= target
.Main
->Buffer
;
134 for(size_t i
{0u};i
< slot
->Wet
.Buffer
.size();++i
)
136 auto coeffs
= GetAmbiIdentityRow(i
);
137 ComputePanGains(target
.Main
, coeffs
.data(), slot
->Params
.Gain
, mChans
[i
].TargetGains
);
141 void ModulatorState::process(const size_t samplesToDo
, const al::span
<const FloatBufferLine
> samplesIn
, const al::span
<FloatBufferLine
> samplesOut
)
143 for(size_t base
{0u};base
< samplesToDo
;)
145 alignas(16) ALfloat modsamples
[MAX_UPDATE_SAMPLES
];
146 size_t td
{minz(MAX_UPDATE_SAMPLES
, samplesToDo
-base
)};
148 mGetSamples(modsamples
, mIndex
, mStep
, td
);
149 mIndex
+= static_cast<ALuint
>(mStep
* td
);
150 mIndex
&= WAVEFORM_FRACMASK
;
152 auto chandata
= std::addressof(mChans
[0]);
153 for(const auto &input
: samplesIn
)
155 alignas(16) ALfloat temps
[MAX_UPDATE_SAMPLES
];
157 chandata
->Filter
.process(temps
, &input
[base
], td
);
158 for(size_t i
{0u};i
< td
;i
++)
159 temps
[i
] *= modsamples
[i
];
161 MixSamples({temps
, td
}, samplesOut
, chandata
->CurrentGains
, chandata
->TargetGains
,
162 samplesToDo
-base
, base
);
171 void Modulator_setParamf(EffectProps
*props
, ALCcontext
*context
, ALenum param
, ALfloat val
)
175 case AL_RING_MODULATOR_FREQUENCY
:
176 if(!(val
>= AL_RING_MODULATOR_MIN_FREQUENCY
&& val
<= AL_RING_MODULATOR_MAX_FREQUENCY
))
177 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "Modulator frequency out of range");
178 props
->Modulator
.Frequency
= val
;
181 case AL_RING_MODULATOR_HIGHPASS_CUTOFF
:
182 if(!(val
>= AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF
&& val
<= AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF
))
183 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "Modulator high-pass cutoff out of range");
184 props
->Modulator
.HighPassCutoff
= val
;
188 context
->setError(AL_INVALID_ENUM
, "Invalid modulator float property 0x%04x", param
);
191 void Modulator_setParamfv(EffectProps
*props
, ALCcontext
*context
, ALenum param
, const ALfloat
*vals
)
192 { Modulator_setParamf(props
, context
, param
, vals
[0]); }
193 void Modulator_setParami(EffectProps
*props
, ALCcontext
*context
, ALenum param
, ALint val
)
197 case AL_RING_MODULATOR_FREQUENCY
:
198 case AL_RING_MODULATOR_HIGHPASS_CUTOFF
:
199 Modulator_setParamf(props
, context
, param
, static_cast<ALfloat
>(val
));
202 case AL_RING_MODULATOR_WAVEFORM
:
203 if(!(val
>= AL_RING_MODULATOR_MIN_WAVEFORM
&& val
<= AL_RING_MODULATOR_MAX_WAVEFORM
))
204 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "Invalid modulator waveform");
205 props
->Modulator
.Waveform
= val
;
209 context
->setError(AL_INVALID_ENUM
, "Invalid modulator integer property 0x%04x", param
);
212 void Modulator_setParamiv(EffectProps
*props
, ALCcontext
*context
, ALenum param
, const ALint
*vals
)
213 { Modulator_setParami(props
, context
, param
, vals
[0]); }
215 void Modulator_getParami(const EffectProps
*props
, ALCcontext
*context
, ALenum param
, ALint
*val
)
219 case AL_RING_MODULATOR_FREQUENCY
:
220 *val
= static_cast<ALint
>(props
->Modulator
.Frequency
);
222 case AL_RING_MODULATOR_HIGHPASS_CUTOFF
:
223 *val
= static_cast<ALint
>(props
->Modulator
.HighPassCutoff
);
225 case AL_RING_MODULATOR_WAVEFORM
:
226 *val
= props
->Modulator
.Waveform
;
230 context
->setError(AL_INVALID_ENUM
, "Invalid modulator integer property 0x%04x", param
);
233 void Modulator_getParamiv(const EffectProps
*props
, ALCcontext
*context
, ALenum param
, ALint
*vals
)
234 { Modulator_getParami(props
, context
, param
, vals
); }
235 void Modulator_getParamf(const EffectProps
*props
, ALCcontext
*context
, ALenum param
, ALfloat
*val
)
239 case AL_RING_MODULATOR_FREQUENCY
:
240 *val
= props
->Modulator
.Frequency
;
242 case AL_RING_MODULATOR_HIGHPASS_CUTOFF
:
243 *val
= props
->Modulator
.HighPassCutoff
;
247 context
->setError(AL_INVALID_ENUM
, "Invalid modulator float property 0x%04x", param
);
250 void Modulator_getParamfv(const EffectProps
*props
, ALCcontext
*context
, ALenum param
, ALfloat
*vals
)
251 { Modulator_getParamf(props
, context
, param
, vals
); }
253 DEFINE_ALEFFECT_VTABLE(Modulator
);
256 struct ModulatorStateFactory final
: public EffectStateFactory
{
257 EffectState
*create() override
{ return new ModulatorState
{}; }
258 EffectProps
getDefaultProps() const noexcept override
;
259 const EffectVtable
*getEffectVtable() const noexcept override
{ return &Modulator_vtable
; }
262 EffectProps
ModulatorStateFactory::getDefaultProps() const noexcept
265 props
.Modulator
.Frequency
= AL_RING_MODULATOR_DEFAULT_FREQUENCY
;
266 props
.Modulator
.HighPassCutoff
= AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF
;
267 props
.Modulator
.Waveform
= AL_RING_MODULATOR_DEFAULT_WAVEFORM
;
273 EffectStateFactory
*ModulatorStateFactory_getFactory()
275 static ModulatorStateFactory ModulatorFactory
{};
276 return &ModulatorFactory
;