Add missing comparison operators for pimpl objects
[alure.git] / src / sourcegroup.cpp
blobfd90866f2e47f974a001e018475d0647f03ae3a9
2 #include "sourcegroup.h"
4 #include <algorithm>
6 #include "source.h"
7 #include "context.h"
9 namespace alure
12 void SourceGroupImpl::eraseSubGroup(SourceGroupImpl *group)
14 auto iter = std::lower_bound(mSubGroups.begin(), mSubGroups.end(), group);
15 if(iter != mSubGroups.end() && *iter == group) mSubGroups.erase(iter);
19 void SourceGroupImpl::setParentGroup(SourceGroupImpl *group)
21 if(mParent)
22 mParent->eraseSubGroup(this);
23 mParent = group;
24 SourceGroupProps props;
25 mParent->applyPropTree(props);
26 update(props.mGain, props.mPitch);
29 void SourceGroupImpl::unsetParentGroup()
31 mParent = nullptr;
32 update(1.0f, 1.0f);
35 void SourceGroupImpl::update(ALfloat gain, ALfloat pitch)
37 mParentProps.mGain = gain;
38 mParentProps.mPitch = pitch;
40 gain *= mGain;
41 pitch *= mPitch;
42 for(SourceImpl *alsrc : mSources)
43 alsrc->groupPropUpdate(gain, pitch);
44 for(SourceGroupImpl *group : mSubGroups)
45 group->update(gain, pitch);
49 bool SourceGroupImpl::findInSubGroups(SourceGroupImpl *group) const
51 auto iter = std::lower_bound(mSubGroups.begin(), mSubGroups.end(), group);
52 if(iter != mSubGroups.end() && *iter == group) return true;
54 for(SourceGroupImpl *group : mSubGroups)
56 if(group->findInSubGroups(group))
57 return true;
59 return false;
63 void SourceGroupImpl::addSource(Source source)
65 SourceImpl *alsrc = source.getHandle();
66 if(!alsrc) throw std::runtime_error("Source is not valid");
67 CheckContext(mContext);
69 auto iter = std::lower_bound(mSources.begin(), mSources.end(), alsrc);
70 if(iter != mSources.end() && *iter == alsrc) return;
72 mSources.insert(iter, alsrc);
73 alsrc->setGroup(this);
76 void SourceGroupImpl::removeSource(Source source)
78 CheckContext(mContext);
79 auto iter = std::lower_bound(mSources.begin(), mSources.end(), source.getHandle());
80 if(iter != mSources.end() && *iter == source.getHandle())
82 (*iter)->unsetGroup();
83 mSources.erase(iter);
88 void SourceGroupImpl::addSources(ArrayView<Source> sources)
90 CheckContext(mContext);
91 if(sources.empty())
92 return;
94 Vector<SourceImpl*> alsrcs;
95 alsrcs.reserve(sources.size());
97 for(Source source : sources)
99 alsrcs.push_back(source.getHandle());
100 if(!alsrcs.back()) throw std::runtime_error("Source is not valid");
103 Batcher batcher = mContext->getBatcher();
104 for(SourceImpl *alsrc : alsrcs)
106 auto iter = std::lower_bound(mSources.begin(), mSources.end(), alsrc);
107 if(iter != mSources.end() && *iter == alsrc) continue;
109 mSources.insert(iter, alsrc);
110 alsrc->setGroup(this);
114 void SourceGroupImpl::removeSources(ArrayView<Source> sources)
116 Batcher batcher = mContext->getBatcher();
117 for(Source source : sources)
119 auto iter = std::lower_bound(mSources.begin(), mSources.end(), source.getHandle());
120 if(iter != mSources.end() && *iter == source.getHandle())
122 (*iter)->unsetGroup();
123 mSources.erase(iter);
129 void SourceGroupImpl::addSubGroup(SourceGroup group)
131 SourceGroupImpl *algrp = group.getHandle();
132 if(!algrp) throw std::runtime_error("SourceGroup is not valid");
133 CheckContext(mContext);
135 auto iter = std::lower_bound(mSubGroups.begin(), mSubGroups.end(), algrp);
136 if(iter != mSubGroups.end() && *iter == algrp) return;
138 if(this == algrp || algrp->findInSubGroups(this))
139 throw std::runtime_error("Attempted circular group chain");
141 mSubGroups.insert(iter, algrp);
142 Batcher batcher = mContext->getBatcher();
143 algrp->setParentGroup(this);
146 void SourceGroupImpl::removeSubGroup(SourceGroup group)
148 auto iter = std::lower_bound(mSubGroups.begin(), mSubGroups.end(), group.getHandle());
149 if(iter != mSubGroups.end() && *iter == group.getHandle())
151 Batcher batcher = mContext->getBatcher();
152 (*iter)->unsetParentGroup();
153 mSubGroups.erase(iter);
158 Vector<Source> SourceGroupImpl::getSources() const
160 Vector<Source> ret;
161 ret.reserve(mSources.size());
162 for(SourceImpl *src : mSources)
163 ret.emplace_back(Source(src));
164 return ret;
167 Vector<SourceGroup> SourceGroupImpl::getSubGroups() const
169 Vector<SourceGroup> ret;
170 ret.reserve(mSubGroups.size());
171 for(SourceGroupImpl *grp : mSubGroups)
172 ret.emplace_back(SourceGroup(grp));
173 return ret;
177 void SourceGroupImpl::setGain(ALfloat gain)
179 if(!(gain >= 0.0f))
180 throw std::runtime_error("Gain out of range");
181 CheckContext(mContext);
182 mGain = gain;
183 gain *= mParentProps.mGain;
184 ALfloat pitch = mPitch * mParentProps.mPitch;
185 Batcher batcher = mContext->getBatcher();
186 for(SourceImpl *alsrc : mSources)
187 alsrc->groupPropUpdate(gain, pitch);
188 for(SourceGroupImpl *group : mSubGroups)
189 group->update(gain, pitch);
192 void SourceGroupImpl::setPitch(ALfloat pitch)
194 if(!(pitch > 0.0f))
195 throw std::runtime_error("Pitch out of range");
196 CheckContext(mContext);
197 mPitch = pitch;
198 ALfloat gain = mGain * mParentProps.mGain;
199 pitch *= mParentProps.mPitch;
200 Batcher batcher = mContext->getBatcher();
201 for(SourceImpl *alsrc : mSources)
202 alsrc->groupPropUpdate(gain, pitch);
203 for(SourceGroupImpl *group : mSubGroups)
204 group->update(gain, pitch);
208 void SourceGroupImpl::collectPlayingSourceIds(Vector<ALuint> &sourceids) const
210 for(SourceImpl *alsrc : mSources)
212 if(ALuint id = alsrc->getId())
213 sourceids.push_back(id);
215 for(SourceGroupImpl *group : mSubGroups)
216 group->collectPlayingSourceIds(sourceids);
219 void SourceGroupImpl::updatePausedStatus() const
221 for(SourceImpl *alsrc : mSources)
222 alsrc->checkPaused();
223 for(SourceGroupImpl *group : mSubGroups)
224 group->updatePausedStatus();
227 void SourceGroupImpl::pauseAll() const
229 CheckContext(mContext);
230 auto lock = mContext->getSourceStreamLock();
232 Vector<ALuint> sourceids;
233 sourceids.reserve(16);
234 collectPlayingSourceIds(sourceids);
235 if(!sourceids.empty())
237 alSourcePausev(sourceids.size(), sourceids.data());
238 updatePausedStatus();
240 lock.unlock();
244 void SourceGroupImpl::collectPausedSourceIds(Vector<ALuint> &sourceids) const
246 for(SourceImpl *alsrc : mSources)
248 if(alsrc->isPaused())
249 sourceids.push_back(alsrc->getId());
251 for(SourceGroupImpl *group : mSubGroups)
252 group->collectPausedSourceIds(sourceids);
255 void SourceGroupImpl::updatePlayingStatus() const
257 for(SourceImpl *alsrc : mSources)
258 alsrc->unsetPaused();
259 for(SourceGroupImpl *group : mSubGroups)
260 group->updatePlayingStatus();
263 void SourceGroupImpl::resumeAll() const
265 CheckContext(mContext);
266 auto lock = mContext->getSourceStreamLock();
268 Vector<ALuint> sourceids;
269 sourceids.reserve(16);
270 collectPausedSourceIds(sourceids);
271 if(!sourceids.empty())
273 alSourcePlayv(sourceids.size(), sourceids.data());
274 updatePlayingStatus();
276 lock.unlock();
280 void SourceGroupImpl::collectSourceIds(Vector<ALuint> &sourceids) const
282 for(SourceImpl *alsrc : mSources)
284 if(ALuint id = alsrc->getId())
285 sourceids.push_back(id);
287 for(SourceGroupImpl *group : mSubGroups)
288 group->collectSourceIds(sourceids);
291 void SourceGroupImpl::updateStoppedStatus() const
293 for(SourceImpl *alsrc : mSources)
295 mContext->removePendingSource(alsrc);
296 mContext->removeFadingSource(alsrc);
297 mContext->removePlayingSource(alsrc);
298 alsrc->makeStopped(false);
299 mContext->send(&MessageHandler::sourceForceStopped, alsrc);
301 for(SourceGroupImpl *group : mSubGroups)
302 group->updateStoppedStatus();
305 void SourceGroupImpl::stopAll() const
307 CheckContext(mContext);
309 Vector<ALuint> sourceids;
310 sourceids.reserve(16);
311 collectSourceIds(sourceids);
312 if(!sourceids.empty())
314 auto lock = mContext->getSourceStreamLock();
315 alSourceRewindv(sourceids.size(), sourceids.data());
316 updateStoppedStatus();
321 void SourceGroupImpl::release()
323 CheckContext(mContext);
324 Batcher batcher = mContext->getBatcher();
325 for(SourceImpl *source : mSources)
326 source->unsetGroup();
327 mSources.clear();
328 for(SourceGroupImpl *group : mSubGroups)
329 group->unsetParentGroup();
330 mSubGroups.clear();
331 if(mParent)
332 mParent->eraseSubGroup(this);
333 mParent = nullptr;
335 mContext->freeSourceGroup(this);
339 DECL_THUNK0(StringView, SourceGroup, getName, const)
340 DECL_THUNK1(void, SourceGroup, addSource,, Source)
341 DECL_THUNK1(void, SourceGroup, removeSource,, Source)
342 DECL_THUNK1(void, SourceGroup, addSources,, ArrayView<Source>)
343 DECL_THUNK1(void, SourceGroup, removeSources,, ArrayView<Source>)
344 DECL_THUNK1(void, SourceGroup, addSubGroup,, SourceGroup)
345 DECL_THUNK1(void, SourceGroup, removeSubGroup,, SourceGroup)
346 DECL_THUNK0(Vector<Source>, SourceGroup, getSources, const)
347 DECL_THUNK0(Vector<SourceGroup>, SourceGroup, getSubGroups, const)
348 DECL_THUNK1(void, SourceGroup, setGain,, ALfloat)
349 DECL_THUNK0(ALfloat, SourceGroup, getGain, const)
350 DECL_THUNK1(void, SourceGroup, setPitch,, ALfloat)
351 DECL_THUNK0(ALfloat, SourceGroup, getPitch, const)
352 DECL_THUNK0(void, SourceGroup, pauseAll, const)
353 DECL_THUNK0(void, SourceGroup, resumeAll, const)
354 DECL_THUNK0(void, SourceGroup, stopAll, const)
355 void SourceGroup::release()
357 pImpl->release();
358 pImpl = nullptr;
361 } // namespace alure