Change EAX, UWP, and RTKIT feature defines to 0/1 macros
[openal-soft.git] / al / listener.cpp
blobcc9268d60f8e91655092eaa45398efca9d3356a5
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 "alnumeric.h"
35 #include "alspan.h"
36 #include "direct_defs.h"
37 #include "error.h"
40 namespace {
42 inline void UpdateProps(ALCcontext *context)
44 if(!context->mDeferUpdates)
46 UpdateContextProps(context);
47 return;
49 context->mPropsDirty = true;
52 inline void CommitAndUpdateProps(ALCcontext *context)
54 if(!context->mDeferUpdates)
56 #if ALSOFT_EAX
57 if(context->eaxNeedsCommit())
59 context->mPropsDirty = true;
60 context->applyAllUpdates();
61 return;
63 #endif
64 UpdateContextProps(context);
65 return;
67 context->mPropsDirty = true;
70 } // namespace
72 AL_API DECL_FUNC2(void, alListenerf, ALenum,param, ALfloat,value)
73 FORCE_ALIGN void AL_APIENTRY alListenerfDirect(ALCcontext *context, ALenum param, ALfloat value) noexcept
74 try {
75 ALlistener &listener = context->mListener;
76 std::lock_guard<std::mutex> proplock{context->mPropLock};
77 switch(param)
79 case AL_GAIN:
80 if(!(value >= 0.0f && std::isfinite(value)))
81 throw al::context_error{AL_INVALID_VALUE, "Listener gain out of range"};
82 listener.Gain = value;
83 UpdateProps(context);
84 return;
86 case AL_METERS_PER_UNIT:
87 if(!(value >= AL_MIN_METERS_PER_UNIT && value <= AL_MAX_METERS_PER_UNIT))
88 throw al::context_error{AL_INVALID_VALUE, "Listener meters per unit out of range"};
89 listener.mMetersPerUnit = value;
90 UpdateProps(context);
91 return;
93 throw al::context_error{AL_INVALID_ENUM, "Invalid listener float property 0x%x", param};
95 catch(al::context_error& e) {
96 context->setError(e.errorCode(), "%s", e.what());
99 AL_API DECL_FUNC4(void, alListener3f, ALenum,param, ALfloat,value1, ALfloat,value2, ALfloat,value3)
100 FORCE_ALIGN void AL_APIENTRY alListener3fDirect(ALCcontext *context, ALenum param, ALfloat value1,
101 ALfloat value2, ALfloat value3) noexcept
102 try {
103 ALlistener &listener = context->mListener;
104 std::lock_guard<std::mutex> proplock{context->mPropLock};
105 switch(param)
107 case AL_POSITION:
108 if(!(std::isfinite(value1) && std::isfinite(value2) && std::isfinite(value3)))
109 throw al::context_error{AL_INVALID_VALUE, "Listener position out of range"};
110 listener.Position[0] = value1;
111 listener.Position[1] = value2;
112 listener.Position[2] = value3;
113 CommitAndUpdateProps(context);
114 return;
116 case AL_VELOCITY:
117 if(!(std::isfinite(value1) && std::isfinite(value2) && std::isfinite(value3)))
118 throw al::context_error{AL_INVALID_VALUE, "Listener velocity out of range"};
119 listener.Velocity[0] = value1;
120 listener.Velocity[1] = value2;
121 listener.Velocity[2] = value3;
122 CommitAndUpdateProps(context);
123 return;
125 throw al::context_error{AL_INVALID_ENUM, "Invalid listener 3-float property 0x%x", param};
127 catch(al::context_error& e) {
128 context->setError(e.errorCode(), "%s", e.what());
131 AL_API DECL_FUNC2(void, alListenerfv, ALenum,param, const ALfloat*,values)
132 FORCE_ALIGN void AL_APIENTRY alListenerfvDirect(ALCcontext *context, ALenum param,
133 const ALfloat *values) noexcept
134 try {
135 if(!values)
136 throw al::context_error{AL_INVALID_VALUE, "NULL pointer"};
138 switch(param)
140 case AL_GAIN:
141 case AL_METERS_PER_UNIT:
142 alListenerfDirect(context, param, *values);
143 return;
145 case AL_POSITION:
146 case AL_VELOCITY:
147 auto vals = al::span<const float,3>{values, 3_uz};
148 alListener3fDirect(context, param, vals[0], vals[1], vals[2]);
149 return;
152 ALlistener &listener = context->mListener;
153 std::lock_guard<std::mutex> proplock{context->mPropLock};
154 switch(param)
156 case AL_ORIENTATION:
157 auto vals = al::span<const float,6>{values, 6_uz};
158 if(!std::all_of(vals.cbegin(), vals.cend(), [](float f) { return std::isfinite(f); }))
159 return context->setError(AL_INVALID_VALUE, "Listener orientation out of range");
160 /* AT then UP */
161 std::copy_n(vals.cbegin(), 3, listener.OrientAt.begin());
162 std::copy_n(vals.cbegin()+3, 3, listener.OrientUp.begin());
163 CommitAndUpdateProps(context);
164 return;
166 throw al::context_error{AL_INVALID_ENUM, "Invalid listener float-vector property 0x%x", param};
168 catch(al::context_error& e) {
169 context->setError(e.errorCode(), "%s", e.what());
173 AL_API DECL_FUNC2(void, alListeneri, ALenum,param, ALint,value)
174 FORCE_ALIGN void AL_APIENTRY alListeneriDirect(ALCcontext *context, ALenum param, ALint /*value*/) noexcept
175 try {
176 std::lock_guard<std::mutex> proplock{context->mPropLock};
177 throw al::context_error{AL_INVALID_ENUM, "Invalid listener integer property 0x%x", param};
179 catch(al::context_error& e) {
180 context->setError(e.errorCode(), "%s", e.what());
183 AL_API DECL_FUNC4(void, alListener3i, ALenum,param, ALint,value1, ALint,value2, ALint,value3)
184 FORCE_ALIGN void AL_APIENTRY alListener3iDirect(ALCcontext *context, ALenum param, ALint value1,
185 ALint value2, ALint value3) noexcept
186 try {
187 switch(param)
189 case AL_POSITION:
190 case AL_VELOCITY:
191 alListener3fDirect(context, param, static_cast<ALfloat>(value1),
192 static_cast<ALfloat>(value2), static_cast<ALfloat>(value3));
193 return;
196 std::lock_guard<std::mutex> proplock{context->mPropLock};
197 throw al::context_error{AL_INVALID_ENUM, "Invalid listener 3-integer property 0x%x", param};
199 catch(al::context_error& e) {
200 context->setError(e.errorCode(), "%s", e.what());
203 AL_API DECL_FUNC2(void, alListeneriv, ALenum,param, const ALint*,values)
204 FORCE_ALIGN void AL_APIENTRY alListenerivDirect(ALCcontext *context, ALenum param,
205 const ALint *values) noexcept
206 try {
207 if(!values)
208 throw al::context_error{AL_INVALID_VALUE, "NULL pointer"};
210 al::span<const ALint> vals;
211 switch(param)
213 case AL_POSITION:
214 case AL_VELOCITY:
215 vals = {values, 3_uz};
216 alListener3fDirect(context, param, static_cast<ALfloat>(vals[0]),
217 static_cast<ALfloat>(vals[1]), static_cast<ALfloat>(vals[2]));
218 return;
220 case AL_ORIENTATION:
221 vals = {values, 6_uz};
222 const std::array fvals{static_cast<ALfloat>(vals[0]), static_cast<ALfloat>(vals[1]),
223 static_cast<ALfloat>(vals[2]), static_cast<ALfloat>(vals[3]),
224 static_cast<ALfloat>(vals[4]), static_cast<ALfloat>(vals[5]),
226 alListenerfvDirect(context, param, fvals.data());
227 return;
230 std::lock_guard<std::mutex> proplock{context->mPropLock};
231 throw al::context_error{AL_INVALID_ENUM, "Invalid listener integer-vector property 0x%x",
232 param};
234 catch(al::context_error& e) {
235 context->setError(e.errorCode(), "%s", e.what());
239 AL_API DECL_FUNC2(void, alGetListenerf, ALenum,param, ALfloat*,value)
240 FORCE_ALIGN void AL_APIENTRY alGetListenerfDirect(ALCcontext *context, ALenum param,
241 ALfloat *value) noexcept
242 try {
243 if(!value)
244 throw al::context_error{AL_INVALID_VALUE, "NULL pointer"};
246 ALlistener &listener = context->mListener;
247 std::lock_guard<std::mutex> proplock{context->mPropLock};
248 switch(param)
250 case AL_GAIN: *value = listener.Gain; return;
251 case AL_METERS_PER_UNIT: *value = listener.mMetersPerUnit; return;
253 throw al::context_error{AL_INVALID_ENUM, "Invalid listener float property 0x%x", param};
255 catch(al::context_error& e) {
256 context->setError(e.errorCode(), "%s", e.what());
259 AL_API DECL_FUNC4(void, alGetListener3f, ALenum,param, ALfloat*,value1, ALfloat*,value2, ALfloat*,value3)
260 FORCE_ALIGN void AL_APIENTRY alGetListener3fDirect(ALCcontext *context, ALenum param,
261 ALfloat *value1, ALfloat *value2, ALfloat *value3) noexcept
262 try {
263 if(!value1 || !value2 || !value3)
264 throw al::context_error{AL_INVALID_VALUE, "NULL pointer"};
266 ALlistener &listener = context->mListener;
267 std::lock_guard<std::mutex> proplock{context->mPropLock};
268 switch(param)
270 case AL_POSITION:
271 *value1 = listener.Position[0];
272 *value2 = listener.Position[1];
273 *value3 = listener.Position[2];
274 return;
276 case AL_VELOCITY:
277 *value1 = listener.Velocity[0];
278 *value2 = listener.Velocity[1];
279 *value3 = listener.Velocity[2];
280 return;
282 throw al::context_error{AL_INVALID_ENUM, "Invalid listener 3-float property 0x%x", param};
284 catch(al::context_error& e) {
285 context->setError(e.errorCode(), "%s", e.what());
288 AL_API DECL_FUNC2(void, alGetListenerfv, ALenum,param, ALfloat*,values)
289 FORCE_ALIGN void AL_APIENTRY alGetListenerfvDirect(ALCcontext *context, ALenum param,
290 ALfloat *values) noexcept
291 try {
292 if(!values)
293 throw al::context_error{AL_INVALID_VALUE, "NULL pointer"};
295 switch(param)
297 case AL_GAIN:
298 case AL_METERS_PER_UNIT:
299 alGetListenerfDirect(context, param, values);
300 return;
302 case AL_POSITION:
303 case AL_VELOCITY:
304 auto vals = al::span<ALfloat,3>{values, 3_uz};
305 alGetListener3fDirect(context, param, &vals[0], &vals[1], &vals[2]);
306 return;
309 ALlistener &listener = context->mListener;
310 std::lock_guard<std::mutex> proplock{context->mPropLock};
311 switch(param)
313 case AL_ORIENTATION:
314 al::span<ALfloat,6> vals{values, 6_uz};
315 // AT then UP
316 std::copy_n(listener.OrientAt.cbegin(), 3, vals.begin());
317 std::copy_n(listener.OrientUp.cbegin(), 3, vals.begin()+3);
318 return;
320 throw al::context_error{AL_INVALID_ENUM, "Invalid listener float-vector property 0x%x", param};
322 catch(al::context_error& e) {
323 context->setError(e.errorCode(), "%s", e.what());
327 AL_API DECL_FUNC2(void, alGetListeneri, ALenum,param, ALint*,value)
328 FORCE_ALIGN void AL_APIENTRY alGetListeneriDirect(ALCcontext *context, ALenum param, ALint *value) noexcept
329 try {
330 if(!value) throw al::context_error{AL_INVALID_VALUE, "NULL pointer"};
331 std::lock_guard<std::mutex> proplock{context->mPropLock};
332 throw al::context_error{AL_INVALID_ENUM, "Invalid listener integer property 0x%x", param};
334 catch(al::context_error& e) {
335 context->setError(e.errorCode(), "%s", e.what());
338 AL_API DECL_FUNC4(void, alGetListener3i, ALenum,param, ALint*,value1, ALint*,value2, ALint*,value3)
339 FORCE_ALIGN void AL_APIENTRY alGetListener3iDirect(ALCcontext *context, ALenum param,
340 ALint *value1, ALint *value2, ALint *value3) noexcept
341 try {
342 if(!value1 || !value2 || !value3)
343 throw al::context_error{AL_INVALID_VALUE, "NULL pointer"};
345 ALlistener &listener = context->mListener;
346 std::lock_guard<std::mutex> proplock{context->mPropLock};
347 switch(param)
349 case AL_POSITION:
350 *value1 = static_cast<ALint>(listener.Position[0]);
351 *value2 = static_cast<ALint>(listener.Position[1]);
352 *value3 = static_cast<ALint>(listener.Position[2]);
353 return;
355 case AL_VELOCITY:
356 *value1 = static_cast<ALint>(listener.Velocity[0]);
357 *value2 = static_cast<ALint>(listener.Velocity[1]);
358 *value3 = static_cast<ALint>(listener.Velocity[2]);
359 return;
361 throw al::context_error{AL_INVALID_ENUM, "Invalid listener 3-integer property 0x%x", param};
363 catch(al::context_error& e) {
364 context->setError(e.errorCode(), "%s", e.what());
367 AL_API DECL_FUNC2(void, alGetListeneriv, ALenum,param, ALint*,values)
368 FORCE_ALIGN void AL_APIENTRY alGetListenerivDirect(ALCcontext *context, ALenum param,
369 ALint *values) noexcept
370 try {
371 if(!values)
372 throw al::context_error{AL_INVALID_VALUE, "NULL pointer"};
374 switch(param)
376 case AL_POSITION:
377 case AL_VELOCITY:
378 auto vals = al::span<ALint,3>{values, 3_uz};
379 alGetListener3iDirect(context, param, &vals[0], &vals[1], &vals[2]);
380 return;
383 ALlistener &listener = context->mListener;
384 std::lock_guard<std::mutex> proplock{context->mPropLock};
386 static constexpr auto f2i = [](const float val) noexcept { return static_cast<ALint>(val); };
387 switch(param)
389 case AL_ORIENTATION:
390 auto vals = al::span<ALint,6>{values, 6_uz};
391 // AT then UP
392 std::transform(listener.OrientAt.cbegin(), listener.OrientAt.cend(), vals.begin(), f2i);
393 std::transform(listener.OrientUp.cbegin(), listener.OrientUp.cend(), vals.begin()+3, f2i);
394 return;
396 throw al::context_error{AL_INVALID_ENUM, "Invalid listener integer-vector property 0x%x",
397 param};
399 catch(al::context_error& e) {
400 context->setError(e.errorCode(), "%s", e.what());