1 /*******************************************************************************
2 * Copyright 2009-2016 Jörg Müller
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 ******************************************************************************/
16
17 #include "SequenceHandle.h"
18 #include "sequence/SequenceEntry.h"
19 #include "devices/ReadDevice.h"
20 #include "Exception.h"
21
22 #include <mutex>
23
24 #define KEEP_TIME 10
25
26 AUD_NAMESPACE_BEGIN
27
start()28 void SequenceHandle::start()
29 {
30 // we already tried to start, aborting
31 if(!m_valid)
32 return;
33
34 // in case the sound is playing, we need to stop first
35 stop();
36
37 std::lock_guard<ILockable> lock(*m_entry);
38
39 // let's try playing
40 if(m_entry->m_sound.get())
41 {
42 try
43 {
44 m_handle = m_device.play(m_entry->m_sound, true);
45 m_3dhandle = std::dynamic_pointer_cast<I3DHandle>(m_handle);
46 }
47 catch(Exception&)
48 {
49 // handle stays invalid in case we get an exception
50 }
51
52 // after starting we have to set the properties, so let's ensure that
53 m_status--;
54 }
55
56 // if the sound could not be played, we invalidate
57 m_valid = m_handle.get();
58 }
59
updatePosition(double position)60 bool SequenceHandle::updatePosition(double position)
61 {
62 std::lock_guard<ILockable> lock(*m_entry);
63
64 if(m_handle.get())
65 {
66 // we currently have a handle, let's check where we are
67 if(position >= m_entry->m_end)
68 {
69 if(position >= m_entry->m_end + KEEP_TIME)
70 // far end, stopping
71 stop();
72 else
73 {
74 // close end, just pausing
75 m_handle->pause();
76 return true;
77 }
78 }
79 else if(position >= m_entry->m_begin)
80 {
81 // inside, resuming
82 m_handle->resume();
83 return true;
84 }
85 else
86 {
87 if(position < m_entry->m_begin - KEEP_TIME)
88 // far beginning, stopping
89 stop();
90 else
91 {
92 // close beginning, just pausing
93 m_handle->pause();
94 return true;
95 }
96 }
97 }
98 else
99 {
100 // we don't have a handle, let's start if we should be playing
101 if(position >= m_entry->m_begin && position <= m_entry->m_end)
102 {
103 start();
104 return m_valid;
105 }
106 }
107
108 return false;
109 }
110
SequenceHandle(std::shared_ptr<SequenceEntry> entry,ReadDevice & device)111 SequenceHandle::SequenceHandle(std::shared_ptr<SequenceEntry> entry, ReadDevice& device) :
112 m_entry(entry),
113 m_valid(true),
114 m_status(0),
115 m_pos_status(0),
116 m_sound_status(0),
117 m_device(device)
118 {
119 }
120
~SequenceHandle()121 SequenceHandle::~SequenceHandle()
122 {
123 stop();
124 }
125
compare(std::shared_ptr<SequenceEntry> entry) const126 int SequenceHandle::compare(std::shared_ptr<SequenceEntry> entry) const
127 {
128 if(m_entry->getID() < entry->getID())
129 return -1;
130 else if(m_entry->getID() == entry->getID())
131 return 0;
132 return 1;
133 }
134
stop()135 void SequenceHandle::stop()
136 {
137 if(m_handle.get())
138 m_handle->stop();
139 m_handle = nullptr;
140 m_3dhandle = nullptr;
141 }
142
update(double position,float frame,float fps)143 void SequenceHandle::update(double position, float frame, float fps)
144 {
145 if(m_sound_status != m_entry->m_sound_status)
146 {
147 // if a new sound has been set, it's possible to get valid again!
148 m_sound_status = m_entry->m_sound_status;
149 m_valid = true;
150
151 // stop whatever sound has been playing
152 stop();
153
154 // seek starts and seeks to the correct position
155 if(!seek(position))
156 // no handle, aborting
157 return;
158 }
159 else
160 {
161 if(!m_valid)
162 // invalid, aborting
163 return;
164
165 if(m_handle.get())
166 {
167 // we have a handle, let's update the position
168 if(!updatePosition(position))
169 // lost handle, aborting
170 return;
171 }
172 else
173 {
174 // we don't have a handle, let's see if we can start
175 if(!seek(position))
176 return;
177 }
178 }
179
180 std::lock_guard<ILockable> lock(*m_entry);
181 if(m_pos_status != m_entry->m_pos_status)
182 {
183 m_pos_status = m_entry->m_pos_status;
184
185 // position changed, need to seek
186 if(!seek(position))
187 // lost handle, aborting
188 return;
189 }
190
191 // so far everything alright and handle is there, let's keep going
192
193 if(m_status != m_entry->m_status)
194 {
195 m_3dhandle->setRelative(m_entry->m_relative);
196 m_3dhandle->setVolumeMaximum(m_entry->m_volume_max);
197 m_3dhandle->setVolumeMinimum(m_entry->m_volume_min);
198 m_3dhandle->setDistanceMaximum(m_entry->m_distance_max);
199 m_3dhandle->setDistanceReference(m_entry->m_distance_reference);
200 m_3dhandle->setAttenuation(m_entry->m_attenuation);
201 m_3dhandle->setConeAngleOuter(m_entry->m_cone_angle_outer);
202 m_3dhandle->setConeAngleInner(m_entry->m_cone_angle_inner);
203 m_3dhandle->setConeVolumeOuter(m_entry->m_cone_volume_outer);
204
205 m_status = m_entry->m_status;
206 }
207
208 float value;
209
210 m_entry->m_volume.read(frame, &value);
211 m_handle->setVolume(value);
212 m_entry->m_pitch.read(frame, &value);
213 m_handle->setPitch(value);
214 m_entry->m_panning.read(frame, &value);
215 SoftwareDevice::setPanning(m_handle.get(), value);
216
217 Vector3 v, v2;
218 Quaternion q;
219
220 m_entry->m_orientation.read(frame, q.get());
221 m_3dhandle->setOrientation(q);
222 m_entry->m_location.read(frame, v.get());
223 m_3dhandle->setLocation(v);
224 m_entry->m_location.read(frame + 1, v2.get());
225 v2 -= v;
226 m_3dhandle->setVelocity(v2 * fps);
227
228 if(m_entry->m_muted)
229 m_handle->setVolume(0);
230 }
231
seek(double position)232 bool SequenceHandle::seek(double position)
233 {
234 if(!m_valid)
235 // sound not valid, aborting
236 return false;
237
238 if(!updatePosition(position))
239 // no handle, aborting
240 return false;
241
242 std::lock_guard<ILockable> lock(*m_entry);
243 double seekpos = position - m_entry->m_begin;
244 if(seekpos < 0)
245 seekpos = 0;
246 seekpos += m_entry->m_skip;
247 m_handle->setPitch(1.0f);
248 m_handle->seek(seekpos);
249
250 return true;
251 }
252
253 AUD_NAMESPACE_END
254