Don't inline DeviceManager's private constructor
[alure.git] / src / sourcegroup.cpp
blob1cd3bbe1d1a658b112ee23b77ffa5c092764c236
2 #include "sourcegroup.h"
4 #include <algorithm>
6 #include "source.h"
7 #include "context.h"
9 namespace alure
12 void SourceGroupImpl::insertSubGroup(SourceGroupImpl *group)
14 auto iter = std::lower_bound(mSubGroups.begin(), mSubGroups.end(), group);
15 if(iter == mSubGroups.end() || *iter != group)
16 mSubGroups.insert(iter, group);
19 void SourceGroupImpl::eraseSubGroup(SourceGroupImpl *group)
21 auto iter = std::lower_bound(mSubGroups.begin(), mSubGroups.end(), group);
22 if(iter != mSubGroups.end() && *iter == group) mSubGroups.erase(iter);
26 void SourceGroupImpl::unsetParent()
28 mParent = nullptr;
29 update(1.0f, 1.0f);
32 void SourceGroupImpl::update(ALfloat gain, ALfloat pitch)
34 mParentProps.mGain = gain;
35 mParentProps.mPitch = pitch;
37 gain *= mGain;
38 pitch *= mPitch;
39 for(SourceImpl *alsrc : mSources)
40 alsrc->groupPropUpdate(gain, pitch);
41 for(SourceGroupImpl *group : mSubGroups)
42 group->update(gain, pitch);
46 bool SourceGroupImpl::findInSubGroups(SourceGroupImpl *group) const
48 auto iter = std::lower_bound(mSubGroups.begin(), mSubGroups.end(), group);
49 if(iter != mSubGroups.end() && *iter == group) return true;
51 for(SourceGroupImpl *grp : mSubGroups)
53 if(grp->findInSubGroups(group))
54 return true;
56 return false;
60 void SourceGroupImpl::insertSource(SourceImpl *source)
62 auto iter = std::lower_bound(mSources.begin(), mSources.end(), source);
63 if(iter == mSources.end() || *iter != source)
64 mSources.insert(iter, source);
67 void SourceGroupImpl::eraseSource(SourceImpl *source)
69 auto iter = std::lower_bound(mSources.begin(), mSources.end(), source);
70 if(iter != mSources.end() && *iter == source)
71 mSources.erase(iter);
75 DECL_THUNK1(void, SourceGroup, setParentGroup,, SourceGroup)
76 void SourceGroupImpl::setParentGroup(SourceGroup group)
78 CheckContext(mContext);
80 SourceGroupImpl *parent = group.getHandle();
81 if(!parent)
83 if(mParent)
84 mParent->eraseSubGroup(this);
85 mParent = nullptr;
86 update(1.0f, 1.0f);
88 else
90 if(this == parent || findInSubGroups(parent))
91 throw std::runtime_error("Attempted circular group chain");
93 parent->insertSubGroup(this);
95 Batcher batcher = mContext.getBatcher();
96 if(mParent)
97 mParent->eraseSubGroup(this);
98 mParent = parent;
99 update(mParent->getAppliedGain(), mParent->getAppliedPitch());
104 DECL_THUNK0(Vector<Source>, SourceGroup, getSources, const)
105 Vector<Source> SourceGroupImpl::getSources() const
107 Vector<Source> ret;
108 ret.reserve(mSources.size());
109 for(SourceImpl *src : mSources)
110 ret.emplace_back(src);
111 return ret;
114 DECL_THUNK0(Vector<SourceGroup>, SourceGroup, getSubGroups, const)
115 Vector<SourceGroup> SourceGroupImpl::getSubGroups() const
117 Vector<SourceGroup> ret;
118 ret.reserve(mSubGroups.size());
119 for(SourceGroupImpl *grp : mSubGroups)
120 ret.emplace_back(grp);
121 return ret;
125 DECL_THUNK1(void, SourceGroup, setGain,, ALfloat)
126 void SourceGroupImpl::setGain(ALfloat gain)
128 if(!(gain >= 0.0f))
129 throw std::out_of_range("Gain out of range");
130 CheckContext(mContext);
131 mGain = gain;
132 gain *= mParentProps.mGain;
133 ALfloat pitch = mPitch * mParentProps.mPitch;
134 Batcher batcher = mContext.getBatcher();
135 for(SourceImpl *alsrc : mSources)
136 alsrc->groupPropUpdate(gain, pitch);
137 for(SourceGroupImpl *group : mSubGroups)
138 group->update(gain, pitch);
141 DECL_THUNK1(void, SourceGroup, setPitch,, ALfloat)
142 void SourceGroupImpl::setPitch(ALfloat pitch)
144 if(!(pitch > 0.0f))
145 throw std::out_of_range("Pitch out of range");
146 CheckContext(mContext);
147 mPitch = pitch;
148 ALfloat gain = mGain * mParentProps.mGain;
149 pitch *= mParentProps.mPitch;
150 Batcher batcher = mContext.getBatcher();
151 for(SourceImpl *alsrc : mSources)
152 alsrc->groupPropUpdate(gain, pitch);
153 for(SourceGroupImpl *group : mSubGroups)
154 group->update(gain, pitch);
158 void SourceGroupImpl::collectPlayingSourceIds(Vector<ALuint> &sourceids) const
160 for(SourceImpl *alsrc : mSources)
162 if(ALuint id = alsrc->getId())
163 sourceids.push_back(id);
165 for(SourceGroupImpl *group : mSubGroups)
166 group->collectPlayingSourceIds(sourceids);
169 void SourceGroupImpl::updatePausedStatus() const
171 for(SourceImpl *alsrc : mSources)
172 alsrc->checkPaused();
173 for(SourceGroupImpl *group : mSubGroups)
174 group->updatePausedStatus();
177 DECL_THUNK0(void, SourceGroup, pauseAll, const)
178 void SourceGroupImpl::pauseAll() const
180 CheckContext(mContext);
181 auto lock = mContext.getSourceStreamLock();
183 Vector<ALuint> sourceids;
184 sourceids.reserve(16);
185 collectPlayingSourceIds(sourceids);
186 if(!sourceids.empty())
188 alSourcePausev(sourceids.size(), sourceids.data());
189 updatePausedStatus();
191 lock.unlock();
195 void SourceGroupImpl::collectPausedSourceIds(Vector<ALuint> &sourceids) const
197 for(SourceImpl *alsrc : mSources)
199 if(alsrc->isPaused())
200 sourceids.push_back(alsrc->getId());
202 for(SourceGroupImpl *group : mSubGroups)
203 group->collectPausedSourceIds(sourceids);
206 void SourceGroupImpl::updatePlayingStatus() const
208 for(SourceImpl *alsrc : mSources)
209 alsrc->unsetPaused();
210 for(SourceGroupImpl *group : mSubGroups)
211 group->updatePlayingStatus();
214 DECL_THUNK0(void, SourceGroup, resumeAll, const)
215 void SourceGroupImpl::resumeAll() const
217 CheckContext(mContext);
218 auto lock = mContext.getSourceStreamLock();
220 Vector<ALuint> sourceids;
221 sourceids.reserve(16);
222 collectPausedSourceIds(sourceids);
223 if(!sourceids.empty())
225 alSourcePlayv(sourceids.size(), sourceids.data());
226 updatePlayingStatus();
228 lock.unlock();
232 void SourceGroupImpl::collectSourceIds(Vector<ALuint> &sourceids) const
234 for(SourceImpl *alsrc : mSources)
236 if(ALuint id = alsrc->getId())
237 sourceids.push_back(id);
239 for(SourceGroupImpl *group : mSubGroups)
240 group->collectSourceIds(sourceids);
243 void SourceGroupImpl::updateStoppedStatus() const
245 for(SourceImpl *alsrc : mSources)
247 mContext.removePendingSource(alsrc);
248 mContext.removeFadingSource(alsrc);
249 mContext.removePlayingSource(alsrc);
250 alsrc->makeStopped(false);
251 mContext.send(&MessageHandler::sourceForceStopped, alsrc);
253 for(SourceGroupImpl *group : mSubGroups)
254 group->updateStoppedStatus();
257 DECL_THUNK0(void, SourceGroup, stopAll, const)
258 void SourceGroupImpl::stopAll() const
260 CheckContext(mContext);
262 Vector<ALuint> sourceids;
263 sourceids.reserve(16);
264 collectSourceIds(sourceids);
265 if(!sourceids.empty())
267 auto lock = mContext.getSourceStreamLock();
268 alSourceRewindv(sourceids.size(), sourceids.data());
269 updateStoppedStatus();
274 void SourceGroup::release()
276 SourceGroupImpl *i = pImpl;
277 pImpl = nullptr;
278 i->release();
280 void SourceGroupImpl::release()
282 CheckContext(mContext);
283 Batcher batcher = mContext.getBatcher();
284 for(SourceImpl *source : mSources)
285 source->unsetGroup();
286 mSources.clear();
287 for(SourceGroupImpl *group : mSubGroups)
288 group->unsetParent();
289 mSubGroups.clear();
290 if(mParent)
291 mParent->eraseSubGroup(this);
292 mParent = nullptr;
294 mContext.freeSourceGroup(this);
298 DECL_THUNK0(SourceGroup, SourceGroup, getParentGroup, const)
299 DECL_THUNK0(ALfloat, SourceGroup, getGain, const)
300 DECL_THUNK0(ALfloat, SourceGroup, getPitch, const)
302 } // namespace alure