Pass small trivially-copyable types by value
[openal-soft.git] / al / listener.cpp
blob30ceed04044520e9094ad26347cf77970c4d23a5
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2000 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include "listener.h"
25 #include <algorithm>
26 #include <cmath>
27 #include <mutex>
29 #include "AL/al.h"
30 #include "AL/alc.h"
31 #include "AL/efx.h"
33 #include "alc/context.h"
34 #include "alc/inprogext.h"
35 #include "alspan.h"
36 #include "direct_defs.h"
37 #include "error.h"
38 #include "opthelpers.h"
41 namespace {
43 inline void UpdateProps(ALCcontext *context)
45 if(!context->mDeferUpdates)
47 UpdateContextProps(context);
48 return;
50 context->mPropsDirty = true;
53 inline void CommitAndUpdateProps(ALCcontext *context)
55 if(!context->mDeferUpdates)
57 #ifdef ALSOFT_EAX
58 if(context->eaxNeedsCommit())
60 context->mPropsDirty = true;
61 context->applyAllUpdates();
62 return;
64 #endif
65 UpdateContextProps(context);
66 return;
68 context->mPropsDirty = true;
71 } // namespace
73 AL_API DECL_FUNC2(void, alListenerf, ALenum,param, ALfloat,value)
74 FORCE_ALIGN void AL_APIENTRY alListenerfDirect(ALCcontext *context, ALenum param, ALfloat value) noexcept
75 try {
76 ALlistener &listener = context->mListener;
77 std::lock_guard<std::mutex> proplock{context->mPropLock};
78 switch(param)
80 case AL_GAIN:
81 if(!(value >= 0.0f && std::isfinite(value)))
82 throw al::context_error{AL_INVALID_VALUE, "Listener gain out of range"};
83 listener.Gain = value;
84 UpdateProps(context);
85 return;
87 case AL_METERS_PER_UNIT:
88 if(!(value >= AL_MIN_METERS_PER_UNIT && value <= AL_MAX_METERS_PER_UNIT))
89 throw al::context_error{AL_INVALID_VALUE, "Listener meters per unit out of range"};
90 listener.mMetersPerUnit = value;
91 UpdateProps(context);
92 return;
94 throw al::context_error{AL_INVALID_ENUM, "Invalid listener float property 0x%x", param};
96 catch(al::context_error& e) {
97 context->setError(e.errorCode(), "%s", e.what());
100 AL_API DECL_FUNC4(void, alListener3f, ALenum,param, ALfloat,value1, ALfloat,value2, ALfloat,value3)
101 FORCE_ALIGN void AL_APIENTRY alListener3fDirect(ALCcontext *context, ALenum param, ALfloat value1,
102 ALfloat value2, ALfloat value3) noexcept
103 try {
104 ALlistener &listener = context->mListener;
105 std::lock_guard<std::mutex> proplock{context->mPropLock};
106 switch(param)
108 case AL_POSITION:
109 if(!(std::isfinite(value1) && std::isfinite(value2) && std::isfinite(value3)))
110 throw al::context_error{AL_INVALID_VALUE, "Listener position out of range"};
111 listener.Position[0] = value1;
112 listener.Position[1] = value2;
113 listener.Position[2] = value3;
114 CommitAndUpdateProps(context);
115 return;
117 case AL_VELOCITY:
118 if(!(std::isfinite(value1) && std::isfinite(value2) && std::isfinite(value3)))
119 throw al::context_error{AL_INVALID_VALUE, "Listener velocity out of range"};
120 listener.Velocity[0] = value1;
121 listener.Velocity[1] = value2;
122 listener.Velocity[2] = value3;
123 CommitAndUpdateProps(context);
124 return;
126 throw al::context_error{AL_INVALID_ENUM, "Invalid listener 3-float property 0x%x", param};
128 catch(al::context_error& e) {
129 context->setError(e.errorCode(), "%s", e.what());
132 AL_API DECL_FUNC2(void, alListenerfv, ALenum,param, const ALfloat*,values)
133 FORCE_ALIGN void AL_APIENTRY alListenerfvDirect(ALCcontext *context, ALenum param,
134 const ALfloat *values) noexcept
135 try {
136 if(!values)
137 throw al::context_error{AL_INVALID_VALUE, "NULL pointer"};
139 switch(param)
141 case AL_GAIN:
142 case AL_METERS_PER_UNIT:
143 alListenerfDirect(context, param, *values);
144 return;
146 case AL_POSITION:
147 case AL_VELOCITY:
148 auto vals = al::span<const float,3>{values, 3_uz};
149 alListener3fDirect(context, param, vals[0], vals[1], vals[2]);
150 return;
153 ALlistener &listener = context->mListener;
154 std::lock_guard<std::mutex> proplock{context->mPropLock};
155 switch(param)
157 case AL_ORIENTATION:
158 auto vals = al::span<const float,6>{values, 6_uz};
159 if(!std::all_of(vals.cbegin(), vals.cend(), [](float f) { return std::isfinite(f); }))
160 return context->setError(AL_INVALID_VALUE, "Listener orientation out of range");
161 /* AT then UP */
162 std::copy_n(vals.cbegin(), 3, listener.OrientAt.begin());
163 std::copy_n(vals.cbegin()+3, 3, listener.OrientUp.begin());
164 CommitAndUpdateProps(context);
165 return;
167 throw al::context_error{AL_INVALID_ENUM, "Invalid listener float-vector property 0x%x", param};
169 catch(al::context_error& e) {
170 context->setError(e.errorCode(), "%s", e.what());
174 AL_API DECL_FUNC2(void, alListeneri, ALenum,param, ALint,value)
175 FORCE_ALIGN void AL_APIENTRY alListeneriDirect(ALCcontext *context, ALenum param, ALint /*value*/) noexcept
176 try {
177 std::lock_guard<std::mutex> proplock{context->mPropLock};
178 throw al::context_error{AL_INVALID_ENUM, "Invalid listener integer property 0x%x", param};
180 catch(al::context_error& e) {
181 context->setError(e.errorCode(), "%s", e.what());
184 AL_API DECL_FUNC4(void, alListener3i, ALenum,param, ALint,value1, ALint,value2, ALint,value3)
185 FORCE_ALIGN void AL_APIENTRY alListener3iDirect(ALCcontext *context, ALenum param, ALint value1,
186 ALint value2, ALint value3) noexcept
187 try {
188 switch(param)
190 case AL_POSITION:
191 case AL_VELOCITY:
192 alListener3fDirect(context, param, static_cast<ALfloat>(value1),
193 static_cast<ALfloat>(value2), static_cast<ALfloat>(value3));
194 return;
197 std::lock_guard<std::mutex> proplock{context->mPropLock};
198 throw al::context_error{AL_INVALID_ENUM, "Invalid listener 3-integer property 0x%x", param};
200 catch(al::context_error& e) {
201 context->setError(e.errorCode(), "%s", e.what());
204 AL_API DECL_FUNC2(void, alListeneriv, ALenum,param, const ALint*,values)
205 FORCE_ALIGN void AL_APIENTRY alListenerivDirect(ALCcontext *context, ALenum param,
206 const ALint *values) noexcept
207 try {
208 if(!values)
209 throw al::context_error{AL_INVALID_VALUE, "NULL pointer"};
211 al::span<const ALint> vals;
212 switch(param)
214 case AL_POSITION:
215 case AL_VELOCITY:
216 vals = {values, 3_uz};
217 alListener3fDirect(context, param, static_cast<ALfloat>(vals[0]),
218 static_cast<ALfloat>(vals[1]), static_cast<ALfloat>(vals[2]));
219 return;
221 case AL_ORIENTATION:
222 vals = {values, 6_uz};
223 const std::array fvals{static_cast<ALfloat>(vals[0]), static_cast<ALfloat>(vals[1]),
224 static_cast<ALfloat>(vals[2]), static_cast<ALfloat>(vals[3]),
225 static_cast<ALfloat>(vals[4]), static_cast<ALfloat>(vals[5]),
227 alListenerfvDirect(context, param, fvals.data());
228 return;
231 std::lock_guard<std::mutex> proplock{context->mPropLock};
232 throw al::context_error{AL_INVALID_ENUM, "Invalid listener integer-vector property 0x%x",
233 param};
235 catch(al::context_error& e) {
236 context->setError(e.errorCode(), "%s", e.what());
240 AL_API DECL_FUNC2(void, alGetListenerf, ALenum,param, ALfloat*,value)
241 FORCE_ALIGN void AL_APIENTRY alGetListenerfDirect(ALCcontext *context, ALenum param,
242 ALfloat *value) noexcept
243 try {
244 if(!value)
245 throw al::context_error{AL_INVALID_VALUE, "NULL pointer"};
247 ALlistener &listener = context->mListener;
248 std::lock_guard<std::mutex> proplock{context->mPropLock};
249 switch(param)
251 case AL_GAIN: *value = listener.Gain; return;
252 case AL_METERS_PER_UNIT: *value = listener.mMetersPerUnit; return;
254 throw al::context_error{AL_INVALID_ENUM, "Invalid listener float property 0x%x", param};
256 catch(al::context_error& e) {
257 context->setError(e.errorCode(), "%s", e.what());
260 AL_API DECL_FUNC4(void, alGetListener3f, ALenum,param, ALfloat*,value1, ALfloat*,value2, ALfloat*,value3)
261 FORCE_ALIGN void AL_APIENTRY alGetListener3fDirect(ALCcontext *context, ALenum param,
262 ALfloat *value1, ALfloat *value2, ALfloat *value3) noexcept
263 try {
264 if(!value1 || !value2 || !value3)
265 throw al::context_error{AL_INVALID_VALUE, "NULL pointer"};
267 ALlistener &listener = context->mListener;
268 std::lock_guard<std::mutex> proplock{context->mPropLock};
269 switch(param)
271 case AL_POSITION:
272 *value1 = listener.Position[0];
273 *value2 = listener.Position[1];
274 *value3 = listener.Position[2];
275 return;
277 case AL_VELOCITY:
278 *value1 = listener.Velocity[0];
279 *value2 = listener.Velocity[1];
280 *value3 = listener.Velocity[2];
281 return;
283 throw al::context_error{AL_INVALID_ENUM, "Invalid listener 3-float property 0x%x", param};
285 catch(al::context_error& e) {
286 context->setError(e.errorCode(), "%s", e.what());
289 AL_API DECL_FUNC2(void, alGetListenerfv, ALenum,param, ALfloat*,values)
290 FORCE_ALIGN void AL_APIENTRY alGetListenerfvDirect(ALCcontext *context, ALenum param,
291 ALfloat *values) noexcept
292 try {
293 if(!values)
294 throw al::context_error{AL_INVALID_VALUE, "NULL pointer"};
296 switch(param)
298 case AL_GAIN:
299 case AL_METERS_PER_UNIT:
300 alGetListenerfDirect(context, param, values);
301 return;
303 case AL_POSITION:
304 case AL_VELOCITY:
305 auto vals = al::span<ALfloat,3>{values, 3_uz};
306 alGetListener3fDirect(context, param, &vals[0], &vals[1], &vals[2]);
307 return;
310 ALlistener &listener = context->mListener;
311 std::lock_guard<std::mutex> proplock{context->mPropLock};
312 switch(param)
314 case AL_ORIENTATION:
315 al::span<ALfloat,6> vals{values, 6_uz};
316 // AT then UP
317 std::copy_n(listener.OrientAt.cbegin(), 3, vals.begin());
318 std::copy_n(listener.OrientUp.cbegin(), 3, vals.begin()+3);
319 return;
321 throw al::context_error{AL_INVALID_ENUM, "Invalid listener float-vector property 0x%x", param};
323 catch(al::context_error& e) {
324 context->setError(e.errorCode(), "%s", e.what());
328 AL_API DECL_FUNC2(void, alGetListeneri, ALenum,param, ALint*,value)
329 FORCE_ALIGN void AL_APIENTRY alGetListeneriDirect(ALCcontext *context, ALenum param, ALint *value) noexcept
330 try {
331 if(!value) throw al::context_error{AL_INVALID_VALUE, "NULL pointer"};
332 std::lock_guard<std::mutex> proplock{context->mPropLock};
333 throw al::context_error{AL_INVALID_ENUM, "Invalid listener integer property 0x%x", param};
335 catch(al::context_error& e) {
336 context->setError(e.errorCode(), "%s", e.what());
339 AL_API DECL_FUNC4(void, alGetListener3i, ALenum,param, ALint*,value1, ALint*,value2, ALint*,value3)
340 FORCE_ALIGN void AL_APIENTRY alGetListener3iDirect(ALCcontext *context, ALenum param,
341 ALint *value1, ALint *value2, ALint *value3) noexcept
342 try {
343 if(!value1 || !value2 || !value3)
344 throw al::context_error{AL_INVALID_VALUE, "NULL pointer"};
346 ALlistener &listener = context->mListener;
347 std::lock_guard<std::mutex> proplock{context->mPropLock};
348 switch(param)
350 case AL_POSITION:
351 *value1 = static_cast<ALint>(listener.Position[0]);
352 *value2 = static_cast<ALint>(listener.Position[1]);
353 *value3 = static_cast<ALint>(listener.Position[2]);
354 return;
356 case AL_VELOCITY:
357 *value1 = static_cast<ALint>(listener.Velocity[0]);
358 *value2 = static_cast<ALint>(listener.Velocity[1]);
359 *value3 = static_cast<ALint>(listener.Velocity[2]);
360 return;
362 throw al::context_error{AL_INVALID_ENUM, "Invalid listener 3-integer property 0x%x", param};
364 catch(al::context_error& e) {
365 context->setError(e.errorCode(), "%s", e.what());
368 AL_API DECL_FUNC2(void, alGetListeneriv, ALenum,param, ALint*,values)
369 FORCE_ALIGN void AL_APIENTRY alGetListenerivDirect(ALCcontext *context, ALenum param,
370 ALint *values) noexcept
371 try {
372 if(!values)
373 throw al::context_error{AL_INVALID_VALUE, "NULL pointer"};
375 switch(param)
377 case AL_POSITION:
378 case AL_VELOCITY:
379 auto vals = al::span<ALint,3>{values, 3_uz};
380 alGetListener3iDirect(context, param, &vals[0], &vals[1], &vals[2]);
381 return;
384 ALlistener &listener = context->mListener;
385 std::lock_guard<std::mutex> proplock{context->mPropLock};
387 static constexpr auto f2i = [](const float val) noexcept { return static_cast<ALint>(val); };
388 switch(param)
390 case AL_ORIENTATION:
391 auto vals = al::span<ALint,6>{values, 6_uz};
392 // AT then UP
393 std::transform(listener.OrientAt.cbegin(), listener.OrientAt.cend(), vals.begin(), f2i);
394 std::transform(listener.OrientUp.cbegin(), listener.OrientUp.cend(), vals.begin()+3, f2i);
395 return;
397 throw al::context_error{AL_INVALID_ENUM, "Invalid listener integer-vector property 0x%x",
398 param};
400 catch(al::context_error& e) {
401 context->setError(e.errorCode(), "%s", e.what());