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
28 #include "alc/effects/base.h"
30 #include "alnumbers.h"
31 #include "alnumeric.h"
33 #include "core/ambidefs.h"
34 #include "core/bufferline.h"
35 #include "core/context.h"
36 #include "core/devformat.h"
37 #include "core/device.h"
38 #include "core/effectslot.h"
39 #include "core/filters/biquad.h"
40 #include "core/mixer.h"
41 #include "intrusive_ptr.h"
46 using uint
= unsigned int;
48 #define MAX_UPDATE_SAMPLES 128
50 #define WAVEFORM_FRACBITS 24
51 #define WAVEFORM_FRACONE (1<<WAVEFORM_FRACBITS)
52 #define WAVEFORM_FRACMASK (WAVEFORM_FRACONE-1)
54 inline float Sin(uint index
)
56 constexpr float scale
{al::numbers::pi_v
<float>*2.0f
/ WAVEFORM_FRACONE
};
57 return std::sin(static_cast<float>(index
) * scale
);
60 inline float Saw(uint index
)
61 { return static_cast<float>(index
)*(2.0f
/WAVEFORM_FRACONE
) - 1.0f
; }
63 inline float Square(uint index
)
64 { return static_cast<float>(static_cast<int>((index
>>(WAVEFORM_FRACBITS
-2))&2) - 1); }
66 inline float One(uint
) { return 1.0f
; }
68 template<float (&func
)(uint
)>
69 void Modulate(float *RESTRICT dst
, uint index
, const uint step
, size_t todo
)
71 for(size_t i
{0u};i
< todo
;i
++)
74 index
&= WAVEFORM_FRACMASK
;
80 struct ModulatorState final
: public EffectState
{
81 void (*mGetSamples
)(float*RESTRICT
, uint
, const uint
, size_t){};
89 float CurrentGains
[MAX_OUTPUT_CHANNELS
]{};
90 float TargetGains
[MAX_OUTPUT_CHANNELS
]{};
91 } mChans
[MaxAmbiChannels
];
94 void deviceUpdate(const DeviceBase
*device
, const Buffer
&buffer
) override
;
95 void update(const ContextBase
*context
, const EffectSlot
*slot
, const EffectProps
*props
,
96 const EffectTarget target
) override
;
97 void process(const size_t samplesToDo
, const al::span
<const FloatBufferLine
> samplesIn
,
98 const al::span
<FloatBufferLine
> samplesOut
) override
;
100 DEF_NEWDEL(ModulatorState
)
103 void ModulatorState::deviceUpdate(const DeviceBase
*, const Buffer
&)
105 for(auto &e
: mChans
)
108 std::fill(std::begin(e
.CurrentGains
), std::end(e
.CurrentGains
), 0.0f
);
112 void ModulatorState::update(const ContextBase
*context
, const EffectSlot
*slot
,
113 const EffectProps
*props
, const EffectTarget target
)
115 const DeviceBase
*device
{context
->mDevice
};
117 const float step
{props
->Modulator
.Frequency
/ static_cast<float>(device
->Frequency
)};
118 mStep
= fastf2u(clampf(step
*WAVEFORM_FRACONE
, 0.0f
, float{WAVEFORM_FRACONE
-1}));
121 mGetSamples
= Modulate
<One
>;
122 else if(props
->Modulator
.Waveform
== ModulatorWaveform::Sinusoid
)
123 mGetSamples
= Modulate
<Sin
>;
124 else if(props
->Modulator
.Waveform
== ModulatorWaveform::Sawtooth
)
125 mGetSamples
= Modulate
<Saw
>;
126 else /*if(props->Modulator.Waveform == ModulatorWaveform::Square)*/
127 mGetSamples
= Modulate
<Square
>;
129 float f0norm
{props
->Modulator
.HighPassCutoff
/ static_cast<float>(device
->Frequency
)};
130 f0norm
= clampf(f0norm
, 1.0f
/512.0f
, 0.49f
);
131 /* Bandwidth value is constant in octaves. */
132 mChans
[0].Filter
.setParamsFromBandwidth(BiquadType::HighPass
, f0norm
, 1.0f
, 0.75f
);
133 for(size_t i
{1u};i
< slot
->Wet
.Buffer
.size();++i
)
134 mChans
[i
].Filter
.copyParamsFrom(mChans
[0].Filter
);
136 mOutTarget
= target
.Main
->Buffer
;
137 auto set_gains
= [slot
,target
](auto &chan
, al::span
<const float,MaxAmbiChannels
> coeffs
)
138 { ComputePanGains(target
.Main
, coeffs
.data(), slot
->Gain
, chan
.TargetGains
); };
139 SetAmbiPanIdentity(std::begin(mChans
), slot
->Wet
.Buffer
.size(), set_gains
);
142 void ModulatorState::process(const size_t samplesToDo
, const al::span
<const FloatBufferLine
> samplesIn
, const al::span
<FloatBufferLine
> samplesOut
)
144 for(size_t base
{0u};base
< samplesToDo
;)
146 alignas(16) float modsamples
[MAX_UPDATE_SAMPLES
];
147 const size_t td
{minz(MAX_UPDATE_SAMPLES
, samplesToDo
-base
)};
149 mGetSamples(modsamples
, mIndex
, mStep
, td
);
150 mIndex
+= static_cast<uint
>(mStep
* td
);
151 mIndex
&= WAVEFORM_FRACMASK
;
153 auto chandata
= std::begin(mChans
);
154 for(const auto &input
: samplesIn
)
156 alignas(16) float temps
[MAX_UPDATE_SAMPLES
];
158 chandata
->Filter
.process({&input
[base
], td
}, temps
);
159 for(size_t i
{0u};i
< td
;i
++)
160 temps
[i
] *= modsamples
[i
];
162 MixSamples({temps
, td
}, samplesOut
, chandata
->CurrentGains
, chandata
->TargetGains
,
163 samplesToDo
-base
, base
);
172 struct ModulatorStateFactory final
: public EffectStateFactory
{
173 al::intrusive_ptr
<EffectState
> create() override
174 { return al::intrusive_ptr
<EffectState
>{new ModulatorState
{}}; }
179 EffectStateFactory
*ModulatorStateFactory_getFactory()
181 static ModulatorStateFactory ModulatorFactory
{};
182 return &ModulatorFactory
;