Update the OpenAL Soft download
[alure.git] / src / sourcegroup.cpp
blob6d8d05329599e1831d25a1a45419a67d755189ec
2 #include "sourcegroup.h"
4 #include <algorithm>
6 #include "source.h"
7 #include "context.h"
9 namespace alure {
11 void SourceGroupImpl::insertSubGroup(SourceGroupImpl *group)
13 auto iter = std::lower_bound(mSubGroups.begin(), mSubGroups.end(), group);
14 if(iter == mSubGroups.end() || *iter != group)
15 mSubGroups.insert(iter, group);
18 void SourceGroupImpl::eraseSubGroup(SourceGroupImpl *group)
20 auto iter = std::lower_bound(mSubGroups.begin(), mSubGroups.end(), group);
21 if(iter != mSubGroups.end() && *iter == group) mSubGroups.erase(iter);
25 void SourceGroupImpl::unsetParent()
27 mParent = nullptr;
28 update(1.0f, 1.0f);
31 void SourceGroupImpl::update(ALfloat gain, ALfloat pitch)
33 mParentProps.mGain = gain;
34 mParentProps.mPitch = pitch;
36 gain *= mGain;
37 pitch *= mPitch;
38 for(SourceImpl *alsrc : mSources)
39 alsrc->groupPropUpdate(gain, pitch);
40 for(SourceGroupImpl *group : mSubGroups)
41 group->update(gain, pitch);
45 bool SourceGroupImpl::findInSubGroups(SourceGroupImpl *group) const
47 auto iter = std::lower_bound(mSubGroups.begin(), mSubGroups.end(), group);
48 if(iter != mSubGroups.end() && *iter == group) return true;
50 for(SourceGroupImpl *grp : mSubGroups)
52 if(grp->findInSubGroups(group))
53 return true;
55 return false;
59 void SourceGroupImpl::insertSource(SourceImpl *source)
61 auto iter = std::lower_bound(mSources.begin(), mSources.end(), source);
62 if(iter == mSources.end() || *iter != source)
63 mSources.insert(iter, source);
66 void SourceGroupImpl::eraseSource(SourceImpl *source)
68 auto iter = std::lower_bound(mSources.begin(), mSources.end(), source);
69 if(iter != mSources.end() && *iter == source)
70 mSources.erase(iter);
74 DECL_THUNK1(void, SourceGroup, setParentGroup,, SourceGroup)
75 void SourceGroupImpl::setParentGroup(SourceGroup group)
77 CheckContext(mContext);
79 SourceGroupImpl *parent = group.getHandle();
80 if(!parent)
82 if(mParent)
83 mParent->eraseSubGroup(this);
84 mParent = nullptr;
85 update(1.0f, 1.0f);
87 else
89 if(this == parent || findInSubGroups(parent))
90 throw std::runtime_error("Attempted circular group chain");
92 parent->insertSubGroup(this);
94 Batcher batcher = mContext.getBatcher();
95 if(mParent)
96 mParent->eraseSubGroup(this);
97 mParent = parent;
98 update(mParent->getAppliedGain(), mParent->getAppliedPitch());
103 DECL_THUNK0(Vector<Source>, SourceGroup, getSources, const)
104 Vector<Source> SourceGroupImpl::getSources() const
106 Vector<Source> ret;
107 ret.reserve(mSources.size());
108 for(SourceImpl *src : mSources)
109 ret.emplace_back(src);
110 return ret;
113 DECL_THUNK0(Vector<SourceGroup>, SourceGroup, getSubGroups, const)
114 Vector<SourceGroup> SourceGroupImpl::getSubGroups() const
116 Vector<SourceGroup> ret;
117 ret.reserve(mSubGroups.size());
118 for(SourceGroupImpl *grp : mSubGroups)
119 ret.emplace_back(grp);
120 return ret;
124 DECL_THUNK1(void, SourceGroup, setGain,, ALfloat)
125 void SourceGroupImpl::setGain(ALfloat gain)
127 if(!(gain >= 0.0f))
128 throw std::out_of_range("Gain out of range");
129 CheckContext(mContext);
130 mGain = gain;
131 gain *= mParentProps.mGain;
132 ALfloat pitch = mPitch * mParentProps.mPitch;
133 Batcher batcher = mContext.getBatcher();
134 for(SourceImpl *alsrc : mSources)
135 alsrc->groupPropUpdate(gain, pitch);
136 for(SourceGroupImpl *group : mSubGroups)
137 group->update(gain, pitch);
140 DECL_THUNK1(void, SourceGroup, setPitch,, ALfloat)
141 void SourceGroupImpl::setPitch(ALfloat pitch)
143 if(!(pitch > 0.0f))
144 throw std::out_of_range("Pitch out of range");
145 CheckContext(mContext);
146 mPitch = pitch;
147 ALfloat gain = mGain * mParentProps.mGain;
148 pitch *= mParentProps.mPitch;
149 Batcher batcher = mContext.getBatcher();
150 for(SourceImpl *alsrc : mSources)
151 alsrc->groupPropUpdate(gain, pitch);
152 for(SourceGroupImpl *group : mSubGroups)
153 group->update(gain, pitch);
157 void SourceGroupImpl::collectPlayingSourceIds(Vector<ALuint> &sourceids) const
159 for(SourceImpl *alsrc : mSources)
161 if(ALuint id = alsrc->getId())
162 sourceids.push_back(id);
164 for(SourceGroupImpl *group : mSubGroups)
165 group->collectPlayingSourceIds(sourceids);
168 void SourceGroupImpl::updatePausedStatus() const
170 for(SourceImpl *alsrc : mSources)
171 alsrc->checkPaused();
172 for(SourceGroupImpl *group : mSubGroups)
173 group->updatePausedStatus();
176 DECL_THUNK0(void, SourceGroup, pauseAll, const)
177 void SourceGroupImpl::pauseAll() const
179 CheckContext(mContext);
180 auto lock = mContext.getSourceStreamLock();
182 Vector<ALuint> sourceids;
183 sourceids.reserve(16);
184 collectPlayingSourceIds(sourceids);
185 if(!sourceids.empty())
187 alSourcePausev(static_cast<ALsizei>(sourceids.size()), sourceids.data());
188 updatePausedStatus();
190 lock.unlock();
194 void SourceGroupImpl::collectPausedSourceIds(Vector<ALuint> &sourceids) const
196 for(SourceImpl *alsrc : mSources)
198 if(alsrc->isPaused())
199 sourceids.push_back(alsrc->getId());
201 for(SourceGroupImpl *group : mSubGroups)
202 group->collectPausedSourceIds(sourceids);
205 void SourceGroupImpl::updatePlayingStatus() const
207 for(SourceImpl *alsrc : mSources)
208 alsrc->unsetPaused();
209 for(SourceGroupImpl *group : mSubGroups)
210 group->updatePlayingStatus();
213 DECL_THUNK0(void, SourceGroup, resumeAll, const)
214 void SourceGroupImpl::resumeAll() const
216 CheckContext(mContext);
217 auto lock = mContext.getSourceStreamLock();
219 Vector<ALuint> sourceids;
220 sourceids.reserve(16);
221 collectPausedSourceIds(sourceids);
222 if(!sourceids.empty())
224 alSourcePlayv(static_cast<ALsizei>(sourceids.size()), sourceids.data());
225 updatePlayingStatus();
227 lock.unlock();
231 void SourceGroupImpl::collectSourceIds(Vector<ALuint> &sourceids) const
233 for(SourceImpl *alsrc : mSources)
235 if(ALuint id = alsrc->getId())
236 sourceids.push_back(id);
238 for(SourceGroupImpl *group : mSubGroups)
239 group->collectSourceIds(sourceids);
242 void SourceGroupImpl::updateStoppedStatus() const
244 for(SourceImpl *alsrc : mSources)
246 mContext.removePendingSource(alsrc);
247 mContext.removeFadingSource(alsrc);
248 mContext.removePlayingSource(alsrc);
249 alsrc->makeStopped(false);
250 mContext.send(&MessageHandler::sourceForceStopped, alsrc);
252 for(SourceGroupImpl *group : mSubGroups)
253 group->updateStoppedStatus();
256 DECL_THUNK0(void, SourceGroup, stopAll, const)
257 void SourceGroupImpl::stopAll() const
259 CheckContext(mContext);
261 Vector<ALuint> sourceids;
262 sourceids.reserve(16);
263 collectSourceIds(sourceids);
264 if(!sourceids.empty())
266 auto lock = mContext.getSourceStreamLock();
267 alSourceRewindv(static_cast<ALsizei>(sourceids.size()), sourceids.data());
268 updateStoppedStatus();
273 void SourceGroup::destroy()
275 SourceGroupImpl *i = pImpl;
276 pImpl = nullptr;
277 i->destroy();
279 void SourceGroupImpl::destroy()
281 CheckContext(mContext);
282 Batcher batcher = mContext.getBatcher();
283 for(SourceImpl *source : mSources)
284 source->unsetGroup();
285 mSources.clear();
286 for(SourceGroupImpl *group : mSubGroups)
287 group->unsetParent();
288 mSubGroups.clear();
289 if(mParent)
290 mParent->eraseSubGroup(this);
291 mParent = nullptr;
293 mContext.freeSourceGroup(this);
297 DECL_THUNK0(SourceGroup, SourceGroup, getParentGroup, const)
298 DECL_THUNK0(ALfloat, SourceGroup, getGain, const)
299 DECL_THUNK0(ALfloat, SourceGroup, getPitch, const)
301 } // namespace alure