1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#include "Components/BsCAudioSource.h"
4#include "Scene/BsSceneObject.h"
5#include "Utility/BsTime.h"
6#include "Private/RTTI/BsCAudioSourceRTTI.h"
7
8using namespace std::placeholders;
9
10namespace bs
11{
12 CAudioSource::CAudioSource()
13 {
14 setName("AudioSource");
15
16 mNotifyFlags = TCF_Transform;
17 }
18
19 CAudioSource::CAudioSource(const HSceneObject& parent)
20 : Component(parent)
21 {
22 setName("AudioSource");
23
24 mNotifyFlags = TCF_Transform;
25 }
26
27 void CAudioSource::setClip(const HAudioClip& clip)
28 {
29 if (mAudioClip == clip)
30 return;
31
32 mAudioClip = clip;
33
34 if (mInternal != nullptr)
35 mInternal->setClip(clip);
36 }
37
38 void CAudioSource::setVolume(float volume)
39 {
40 if (mVolume == volume)
41 return;
42
43 mVolume = volume;
44
45 if (mInternal != nullptr)
46 mInternal->setVolume(volume);
47 }
48
49 void CAudioSource::setPitch(float pitch)
50 {
51 if (mPitch == pitch)
52 return;
53
54 mPitch = pitch;
55
56 if (mInternal != nullptr)
57 mInternal->setPitch(pitch);
58 }
59
60 void CAudioSource::setIsLooping(bool loop)
61 {
62 if (mLoop == loop)
63 return;
64
65 mLoop = loop;
66
67 if (mInternal != nullptr)
68 mInternal->setIsLooping(loop);
69 }
70
71 void CAudioSource::setPriority(UINT32 priority)
72 {
73 if (mPriority == priority)
74 return;
75
76 mPriority = priority;
77
78 if (mInternal != nullptr)
79 mInternal->setPriority(priority);
80 }
81
82 void CAudioSource::setMinDistance(float distance)
83 {
84 if (mMinDistance == distance)
85 return;
86
87 mMinDistance = distance;
88
89 if (mInternal != nullptr)
90 mInternal->setMinDistance(distance);
91 }
92
93 void CAudioSource::setAttenuation(float attenuation)
94 {
95 if (mAttenuation == attenuation)
96 return;
97
98 mAttenuation = attenuation;
99
100 if (mInternal != nullptr)
101 mInternal->setAttenuation(attenuation);
102 }
103
104 void CAudioSource::play()
105 {
106 if (mInternal != nullptr)
107 mInternal->play();
108 }
109
110 void CAudioSource::pause()
111 {
112 if (mInternal != nullptr)
113 mInternal->pause();
114 }
115
116 void CAudioSource::stop()
117 {
118 if (mInternal != nullptr)
119 mInternal->stop();
120 }
121
122 void CAudioSource::setTime(float position)
123 {
124 if (mInternal != nullptr)
125 mInternal->setTime(position);
126 }
127
128 float CAudioSource::getTime() const
129 {
130 if (mInternal != nullptr)
131 return mInternal->getTime();
132
133 return 0.0f;
134 }
135
136 AudioSourceState CAudioSource::getState() const
137 {
138 if (mInternal != nullptr)
139 return mInternal->getState();
140
141 return AudioSourceState::Stopped;
142 }
143
144 void CAudioSource::onInitialized()
145 {
146
147 }
148
149 void CAudioSource::onDestroyed()
150 {
151 destroyInternal();
152 }
153
154 void CAudioSource::onDisabled()
155 {
156 destroyInternal();
157 }
158
159 void CAudioSource::onEnabled()
160 {
161 restoreInternal();
162
163 if (mPlayOnStart)
164 play();
165 }
166
167 void CAudioSource::onTransformChanged(TransformChangedFlags flags)
168 {
169 if (!SO()->getActive())
170 return;
171
172 if ((flags & (TCF_Parent | TCF_Transform)) != 0)
173 updateTransform();
174 }
175
176 void CAudioSource::update()
177 {
178 const Vector3 worldPos = SO()->getTransform().getPosition();
179
180 const float frameDelta = gTime().getFrameDelta();
181 if(frameDelta > 0.0f)
182 mVelocity = (worldPos - mLastPosition) / frameDelta;
183 else
184 mVelocity = Vector3::ZERO;
185
186 mLastPosition = worldPos;
187 }
188
189 void CAudioSource::restoreInternal()
190 {
191 if (mInternal == nullptr)
192 mInternal = AudioSource::create();
193
194 // Note: Merge into one call to avoid many virtual function calls
195 mInternal->setClip(mAudioClip);
196 mInternal->setVolume(mVolume);
197 mInternal->setPitch(mPitch);
198 mInternal->setIsLooping(mLoop);
199 mInternal->setPriority(mPriority);
200 mInternal->setMinDistance(mMinDistance);
201 mInternal->setAttenuation(mAttenuation);
202
203 updateTransform();
204 }
205
206 void CAudioSource::destroyInternal()
207 {
208 // This should release the last reference and destroy the internal listener
209 mInternal = nullptr;
210 }
211
212 void CAudioSource::updateTransform()
213 {
214 mInternal->setTransform(SO()->getTransform());
215 mInternal->setVelocity(mVelocity);
216 }
217
218 RTTITypeBase* CAudioSource::getRTTIStatic()
219 {
220 return CAudioSourceRTTI::instance();
221 }
222
223 RTTITypeBase* CAudioSource::getRTTI() const
224 {
225 return CAudioSource::getRTTIStatic();
226 }
227}