]> git.tdb.fi Git - ext/openal.git/blob - alc/effects/dedicated.cpp
Import OpenAL Soft 1.23.1 sources
[ext/openal.git] / alc / effects / dedicated.cpp
1 /**
2  * OpenAL cross platform audio library
3  * Copyright (C) 2011 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.
8  *
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.
13  *
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
19  */
20
21 #include "config.h"
22
23 #include <algorithm>
24 #include <array>
25 #include <cstdlib>
26 #include <iterator>
27
28 #include "alc/effects/base.h"
29 #include "almalloc.h"
30 #include "alspan.h"
31 #include "core/bufferline.h"
32 #include "core/devformat.h"
33 #include "core/device.h"
34 #include "core/effectslot.h"
35 #include "core/mixer.h"
36 #include "intrusive_ptr.h"
37
38 struct ContextBase;
39
40
41 namespace {
42
43 using uint = unsigned int;
44
45 struct DedicatedState final : public EffectState {
46     /* The "dedicated" effect can output to the real output, so should have
47      * gains for all possible output channels and not just the main ambisonic
48      * buffer.
49      */
50     float mCurrentGains[MAX_OUTPUT_CHANNELS];
51     float mTargetGains[MAX_OUTPUT_CHANNELS];
52
53
54     void deviceUpdate(const DeviceBase *device, const BufferStorage *buffer) override;
55     void update(const ContextBase *context, const EffectSlot *slot, const EffectProps *props,
56         const EffectTarget target) override;
57     void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn,
58         const al::span<FloatBufferLine> samplesOut) override;
59
60     DEF_NEWDEL(DedicatedState)
61 };
62
63 void DedicatedState::deviceUpdate(const DeviceBase*, const BufferStorage*)
64 {
65     std::fill(std::begin(mCurrentGains), std::end(mCurrentGains), 0.0f);
66 }
67
68 void DedicatedState::update(const ContextBase*, const EffectSlot *slot,
69     const EffectProps *props, const EffectTarget target)
70 {
71     std::fill(std::begin(mTargetGains), std::end(mTargetGains), 0.0f);
72
73     const float Gain{slot->Gain * props->Dedicated.Gain};
74
75     if(slot->EffectType == EffectSlotType::DedicatedLFE)
76     {
77         const uint idx{target.RealOut ? target.RealOut->ChannelIndex[LFE] : InvalidChannelIndex};
78         if(idx != InvalidChannelIndex)
79         {
80             mOutTarget = target.RealOut->Buffer;
81             mTargetGains[idx] = Gain;
82         }
83     }
84     else if(slot->EffectType == EffectSlotType::DedicatedDialog)
85     {
86         /* Dialog goes to the front-center speaker if it exists, otherwise it
87          * plays from the front-center location. */
88         const uint idx{target.RealOut ? target.RealOut->ChannelIndex[FrontCenter]
89             : InvalidChannelIndex};
90         if(idx != InvalidChannelIndex)
91         {
92             mOutTarget = target.RealOut->Buffer;
93             mTargetGains[idx] = Gain;
94         }
95         else
96         {
97             static constexpr auto coeffs = CalcDirectionCoeffs({0.0f, 0.0f, -1.0f});
98
99             mOutTarget = target.Main->Buffer;
100             ComputePanGains(target.Main, coeffs.data(), Gain, mTargetGains);
101         }
102     }
103 }
104
105 void DedicatedState::process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn, const al::span<FloatBufferLine> samplesOut)
106 {
107     MixSamples({samplesIn[0].data(), samplesToDo}, samplesOut, mCurrentGains, mTargetGains,
108         samplesToDo, 0);
109 }
110
111
112 struct DedicatedStateFactory final : public EffectStateFactory {
113     al::intrusive_ptr<EffectState> create() override
114     { return al::intrusive_ptr<EffectState>{new DedicatedState{}}; }
115 };
116
117 } // namespace
118
119 EffectStateFactory *DedicatedStateFactory_getFactory()
120 {
121     static DedicatedStateFactory DedicatedFactory{};
122     return &DedicatedFactory;
123 }