Use an actual Version class type for the ALC and EFX versions
[alure.git] / include / AL / alure2.h
blob3cb7ab05f0dd1f44e96eb4dfb0a8a58acd43b9de
1 #ifndef AL_ALURE2_H
2 #define AL_ALURE2_H
4 #include <vector>
5 #include <string>
6 #include <memory>
7 #include <utility>
8 #include <limits>
9 #include <chrono>
10 #include <array>
11 #include <cmath>
13 #include "alc.h"
14 #include "al.h"
16 #ifdef _WIN32
17 #if defined(ALURE_BUILD_STATIC) || defined(ALURE_STATIC_LIB)
18 #define ALURE_API
19 #elif defined(ALURE_BUILD_DLL)
20 #define ALURE_API __declspec(dllexport)
21 #else
22 #define ALURE_API __declspec(dllimport)
23 #endif
25 #else
27 #define ALURE_API
28 #endif
30 #ifndef EFXEAXREVERBPROPERTIES_DEFINED
31 #define EFXEAXREVERBPROPERTIES_DEFINED
32 typedef struct {
33 float flDensity;
34 float flDiffusion;
35 float flGain;
36 float flGainHF;
37 float flGainLF;
38 float flDecayTime;
39 float flDecayHFRatio;
40 float flDecayLFRatio;
41 float flReflectionsGain;
42 float flReflectionsDelay;
43 float flReflectionsPan[3];
44 float flLateReverbGain;
45 float flLateReverbDelay;
46 float flLateReverbPan[3];
47 float flEchoTime;
48 float flEchoDepth;
49 float flModulationTime;
50 float flModulationDepth;
51 float flAirAbsorptionGainHF;
52 float flHFReference;
53 float flLFReference;
54 float flRoomRolloffFactor;
55 int iDecayHFLimit;
56 } EFXEAXREVERBPROPERTIES, *LPEFXEAXREVERBPROPERTIES;
57 #endif
59 namespace alure {
61 class DeviceManager;
62 class ALDeviceManager;
63 class Device;
64 class ALDevice;
65 class Context;
66 class ALContext;
67 class Listener;
68 class ALListener;
69 class Buffer;
70 class ALBuffer;
71 class Source;
72 class ALSource;
73 class SourceGroup;
74 class ALSourceGroup;
75 class AuxiliaryEffectSlot;
76 class ALAuxiliaryEffectSlot;
77 class Effect;
78 class ALEffect;
79 class Decoder;
80 class DecoderFactory;
81 class MessageHandler;
84 // Duration in seconds, using double precision
85 using Seconds = std::chrono::duration<double>;
87 // A SharedPtr implementation, defaults to C++11's std::shared_ptr. If this is
88 // changed, you must recompile the library.
89 template<typename T>
90 using SharedPtr = std::shared_ptr<T>;
91 template<typename T, typename... Args>
92 constexpr inline SharedPtr<T> MakeShared(Args&&... args)
94 return std::make_shared<T>(std::forward<Args>(args)...);
97 // A UniquePtr implementation, defaults to C++11's std::unique_ptr. If this is
98 // changed, you must recompile the library.
99 template<typename T, typename D = std::default_delete<T>>
100 using UniquePtr = std::unique_ptr<T, D>;
101 template<typename T, typename... Args>
102 constexpr inline UniquePtr<T> MakeUnique(Args&&... args)
104 #if __cplusplus >= 201402L
105 return std::make_unique<T>(std::forward<Args>(args)...);
106 #else
107 return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
108 #endif
111 // A Vector implementation, defaults to C++'s std::vector. If this is changed,
112 // you must recompile the library.
113 template<typename T>
114 using Vector = std::vector<T>;
116 // A static-sized Array implementation, defaults to C++11's std::array. If this
117 // is changed, you must recompile the library.
118 template<typename T, std::size_t N>
119 using Array = std::array<T, N>;
121 // A String implementation, default's to C++'s std::string. If this is changed,
122 // you must recompile the library.
123 using String = std::string;
125 // A rather simple ArrayView container. This allows accepting various array
126 // types (Array, Vector, a static-sized array, a dynamic array + size) without
127 // copying its elements.
128 template<typename T>
129 class ArrayView {
130 T *mElems;
131 size_t mNumElems;
133 public:
134 typedef T *iterator;
135 typedef const T *const_iterator;
137 ArrayView() : mElems(nullptr), mNumElems(0) { }
138 ArrayView(const ArrayView &rhs) : mElems(rhs.data()), mNumElems(rhs.size()) { }
139 ArrayView(ArrayView&& rhs) : mElems(rhs.data()), mNumElems(rhs.size()) { }
140 ArrayView(T *elems, size_t num_elems) : mElems(elems), mNumElems(num_elems) { }
141 template<size_t N>
142 ArrayView(T (&elems)[N]) : mElems(elems), mNumElems(N) { }
143 template<typename OtherT>
144 ArrayView(OtherT &arr) : mElems(arr.data()), mNumElems(arr.size()) { }
146 ArrayView& operator=(const ArrayView &rhs)
148 mElems = rhs.data();
149 mNumElems = rhs.size();
151 ArrayView& operator=(ArrayView&& rhs)
153 mElems = rhs.data();
154 mNumElems = rhs.size();
156 template<size_t N>
157 ArrayView& operator=(T (&elems)[N])
159 mElems = elems;
160 mNumElems = N;
162 template<typename OtherT>
163 ArrayView& operator=(OtherT &arr)
165 mElems = arr.data();
166 mNumElems = arr.size();
170 const T *data() const { return mElems; }
171 T *data() { return mElems; }
173 size_t size() const { return mNumElems; }
174 bool empty() const { return mNumElems == 0; }
176 const T& operator[](size_t i) const { return mElems[i]; }
177 T& operator[](size_t i) { return mElems[i]; }
179 const T& front() const { return mElems[0]; }
180 T& front() { return mElems[0]; }
181 const T& back() const { return mElems[mNumElems-1]; }
182 T& back() { return mElems[mNumElems-1]; }
184 const T& at(size_t i) const
186 if(i >= mNumElems)
187 throw std::out_of_range("alure::ArrayView::at: element out of range");
188 return mElems[i];
190 T& at(size_t i)
192 if(i >= mNumElems)
193 throw std::out_of_range("alure::ArrayView::at: element out of range");
194 return mElems[i];
197 iterator begin() { return mElems; }
198 const_iterator begin() const { return mElems; }
199 const_iterator cbegin() const { return mElems; }
201 iterator end() { return mElems + mNumElems; }
202 const_iterator end() const { return mElems + mNumElems; }
203 const_iterator cend() const { return mElems + mNumElems; }
208 * An attribute pair, for passing attributes to Device::createContext and
209 * Device::reset.
211 using AttributePair = std::pair<ALCint,ALCint>;
212 static_assert(sizeof(AttributePair) == sizeof(ALCint[2]), "Bad AttributePair size");
215 struct FilterParams {
216 ALfloat mGain;
217 ALfloat mGainHF; // For low-pass and band-pass filters
218 ALfloat mGainLF; // For high-pass and band-pass filters
222 class ALURE_API Vector3 {
223 Array<ALfloat,3> mValue;
225 public:
226 constexpr Vector3() noexcept
227 : mValue{{0.0f, 0.0f, 0.0f}}
229 constexpr Vector3(const Vector3 &rhs) noexcept
230 : mValue{{rhs.mValue[0], rhs.mValue[1], rhs.mValue[2]}}
232 constexpr Vector3(ALfloat val) noexcept
233 : mValue{{val, val, val}}
235 constexpr Vector3(ALfloat x, ALfloat y, ALfloat z) noexcept
236 : mValue{{x, y, z}}
238 Vector3(const ALfloat *vec) noexcept
239 : mValue{{vec[0], vec[1], vec[2]}}
242 const ALfloat *getPtr() const noexcept
243 { return mValue.data(); }
245 ALfloat& operator[](size_t i) noexcept
246 { return mValue[i]; }
247 constexpr const ALfloat& operator[](size_t i) const noexcept
248 { return mValue[i]; }
250 #define ALURE_DECL_OP(op) \
251 constexpr Vector3 operator op(const Vector3 &rhs) const noexcept \
253 return Vector3(mValue[0] op rhs.mValue[0], \
254 mValue[1] op rhs.mValue[1], \
255 mValue[2] op rhs.mValue[2]); \
257 ALURE_DECL_OP(+)
258 ALURE_DECL_OP(-)
259 ALURE_DECL_OP(*)
260 ALURE_DECL_OP(/)
261 #undef ALURE_DECL_OP
262 #define ALURE_DECL_OP(op) \
263 Vector3& operator op(const Vector3 &rhs) noexcept \
265 mValue[0] op rhs.mValue[0]; \
266 mValue[1] op rhs.mValue[1]; \
267 mValue[2] op rhs.mValue[2]; \
268 return *this; \
270 ALURE_DECL_OP(+=)
271 ALURE_DECL_OP(-=)
272 ALURE_DECL_OP(*=)
273 ALURE_DECL_OP(/=)
275 #undef ALURE_DECL_OP
276 #define ALURE_DECL_OP(op) \
277 constexpr Vector3 operator op(ALfloat scale) const noexcept \
279 return Vector3(mValue[0] op scale, \
280 mValue[1] op scale, \
281 mValue[2] op scale); \
283 ALURE_DECL_OP(*)
284 ALURE_DECL_OP(/)
285 #undef ALURE_DECL_OP
286 #define ALURE_DECL_OP(op) \
287 Vector3& operator op(ALfloat scale) noexcept \
289 mValue[0] op scale; \
290 mValue[1] op scale; \
291 mValue[2] op scale; \
292 return *this; \
294 ALURE_DECL_OP(*=)
295 ALURE_DECL_OP(/=)
296 #undef ALURE_DECL_OP
298 constexpr ALfloat getLengthSquared() const noexcept
299 { return mValue[0]*mValue[0] + mValue[1]*mValue[1] + mValue[2]*mValue[2]; }
300 ALfloat getLength() const noexcept
301 { return std::sqrt(getLengthSquared()); }
303 constexpr ALfloat getDistanceSquared(const Vector3 &pos) const noexcept
304 { return (pos - *this).getLengthSquared(); }
305 ALfloat getDistance(const Vector3 &pos) const noexcept
306 { return (pos - *this).getLength(); }
308 static_assert(sizeof(Vector3) == sizeof(ALfloat[3]), "Bad Vector3 size");
311 enum class SampleType {
312 UInt8,
313 Int16,
314 Float32,
315 Mulaw
317 ALURE_API const char *GetSampleTypeName(SampleType type);
319 enum class ChannelConfig {
320 /** 1-channel mono sound. */
321 Mono,
322 /** 2-channel stereo sound. */
323 Stereo,
324 /** 2-channel rear sound (back-left and back-right). */
325 Rear,
326 /** 4-channel surround sound. */
327 Quad,
328 /** 5.1 surround sound. */
329 X51,
330 /** 6.1 surround sound. */
331 X61,
332 /** 7.1 surround sound. */
333 X71,
334 /** 3-channel B-Format, using FuMa channel ordering and scaling. */
335 BFormat2D,
336 /** 4-channel B-Format, using FuMa channel ordering and scaling. */
337 BFormat3D
339 ALURE_API const char *GetChannelConfigName(ChannelConfig cfg);
341 ALURE_API ALuint FramesToBytes(ALuint frames, ChannelConfig chans, SampleType type);
342 ALURE_API ALuint BytesToFrames(ALuint bytes, ChannelConfig chans, SampleType type);
345 /** Class for storing a major.minor version number. */
346 class Version {
347 ALuint mMajor : 16;
348 ALuint mMinor : 16;
350 public:
351 Version(ALuint _maj, ALuint _min)
352 : mMajor(std::min<ALuint>(_maj, std::numeric_limits<ALushort>::max()))
353 , mMinor(std::min<ALuint>(_min, std::numeric_limits<ALushort>::max()))
356 constexpr ALuint getMajor() const noexcept { return mMajor; }
357 constexpr ALuint getMinor() const noexcept { return mMinor; }
358 constexpr bool isZero() const noexcept { return mMajor == 0 && mMinor == 0; }
361 #define MAKE_PIMPL(BaseT, ImplT) \
362 private: \
363 ImplT *pImpl; \
365 public: \
366 using handle_type = ImplT*; \
368 BaseT() : pImpl(nullptr) { } \
369 BaseT(ImplT *impl) : pImpl(impl) { } \
370 BaseT(const BaseT&) = default; \
371 BaseT(BaseT&& rhs) : pImpl(rhs.pImpl) { rhs.pImpl = nullptr; } \
373 BaseT& operator=(const BaseT&) = default; \
374 BaseT& operator=(BaseT&& rhs) \
376 pImpl = rhs.pImpl; rhs.pImpl = nullptr; \
377 return *this; \
380 bool operator==(const BaseT &rhs) const { return pImpl == rhs.pImpl; } \
381 bool operator==(BaseT&& rhs) const { return pImpl == rhs.pImpl; } \
383 operator bool() const { return !!pImpl; } \
385 handle_type getHandle() const { return pImpl; }
387 enum class DeviceEnumeration {
388 Basic = ALC_DEVICE_SPECIFIER,
389 Full = ALC_ALL_DEVICES_SPECIFIER,
390 Capture = ALC_CAPTURE_DEVICE_SPECIFIER
393 enum class DefaultDeviceType {
394 Basic = ALC_DEFAULT_DEVICE_SPECIFIER,
395 Full = ALC_DEFAULT_ALL_DEVICES_SPECIFIER,
396 Capture = ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER
400 * A class managing Device objects and other related functionality. This class
401 * is a singleton, only one instance will exist in a process.
403 class ALURE_API DeviceManager {
404 ALDeviceManager *pImpl;
406 DeviceManager(ALDeviceManager *impl) : pImpl(impl) { }
407 friend class ALDeviceManager;
409 public:
410 DeviceManager(const DeviceManager&) = default;
411 DeviceManager(DeviceManager&& rhs) : pImpl(rhs.pImpl) { }
413 /** Retrieves the DeviceManager instance. */
414 static DeviceManager get();
416 /** Queries the existence of a non-device-specific ALC extension. */
417 bool queryExtension(const String &name) const;
419 /** Enumerates available device names of the given type. */
420 Vector<String> enumerate(DeviceEnumeration type) const;
421 /** Retrieves the default device of the given type. */
422 String defaultDeviceName(DefaultDeviceType type) const;
425 * Opens the playback device given by name, or the default if blank. Throws
426 * an exception on error.
428 Device openPlayback(const String &name=String());
431 * Opens the playback device given by name, or the default if blank.
432 * Returns an empty Device on error.
434 Device openPlayback(const String &name, const std::nothrow_t&);
436 /** Opens the default playback device. Returns an empty Device on error. */
437 Device openPlayback(const std::nothrow_t&);
441 enum class PlaybackName {
442 Basic = ALC_DEVICE_SPECIFIER,
443 Full = ALC_ALL_DEVICES_SPECIFIER
446 class ALURE_API Device {
447 MAKE_PIMPL(Device, ALDevice)
449 public:
450 /** Retrieves the device name as given by type. */
451 String getName(PlaybackName type=PlaybackName::Full) const;
452 /** Queries the existence of an ALC extension on this device. */
453 bool queryExtension(const String &name) const;
456 * Retrieves the ALC version supported by this device, as constructed by
457 * MakeVersion.
459 Version getALCVersion() const;
462 * Retrieves the EFX version supported by this device, as constructed by
463 * MakeVersion. If the ALC_EXT_EFX extension is unsupported, this will be
464 * 0.0.
466 Version getEFXVersion() const;
468 /** Retrieves the device's playback frequency, in hz. */
469 ALCuint getFrequency() const;
472 * Retrieves the maximum number of auxiliary source sends. If ALC_EXT_EFX
473 * is unsupported, this will be 0.
475 ALCuint getMaxAuxiliarySends() const;
478 * Enumerates available HRTF names. The names are sorted as OpenAL gives
479 * them, such that the index of a given name is the ID to use with
480 * ALC_HRTF_ID_SOFT.
482 * Requires the ALC_SOFT_HRTF extension.
484 Vector<String> enumerateHRTFNames() const;
487 * Retrieves whether HRTF is enabled on the device or not.
489 * Requires the ALC_SOFT_HRTF extension.
491 bool isHRTFEnabled() const;
494 * Retrieves the name of the HRTF currently being used by this device.
496 * Requires the ALC_SOFT_HRTF extension.
498 String getCurrentHRTF() const;
501 * Resets the device, using the specified attributes.
503 * Requires the ALC_SOFT_HRTF extension.
505 void reset(ArrayView<AttributePair> attributes);
508 * Creates a new Context on this device, using the specified attributes.
510 Context createContext(ArrayView<AttributePair> attributes=ArrayView<AttributePair>());
513 * Pauses device processing, stopping updates for its contexts. Multiple
514 * calls are allowed but it is not reference counted, so the device will
515 * resume after one resumeDSP call.
517 * Requires the ALC_SOFT_pause_device extension.
519 void pauseDSP();
522 * Resumes device processing, restarting updates for its contexts. Multiple
523 * calls are allowed and will no-op.
525 void resumeDSP();
528 * Closes and frees the device. All previously-created contexts must first
529 * be destroyed.
531 void close();
535 enum class DistanceModel {
536 InverseClamped = AL_INVERSE_DISTANCE_CLAMPED,
537 LinearClamped = AL_LINEAR_DISTANCE_CLAMPED,
538 ExponentClamped = AL_EXPONENT_DISTANCE_CLAMPED,
539 Inverse = AL_INVERSE_DISTANCE,
540 Linear = AL_LINEAR_DISTANCE,
541 Exponent = AL_EXPONENT_DISTANCE,
542 None = AL_NONE,
545 class ALURE_API Context {
546 MAKE_PIMPL(Context, ALContext)
548 public:
549 /** Makes the specified context current for OpenAL operations. */
550 static void MakeCurrent(Context context);
551 /** Retrieves the current context used for OpenAL operations. */
552 static Context GetCurrent();
555 * Makes the specified context current for OpenAL operations on the calling
556 * thread only. Requires the ALC_EXT_thread_local_context extension on both
557 * the context's device and the DeviceManager.
559 static void MakeThreadCurrent(Context context);
560 /** Retrieves the thread-specific context used for OpenAL operations. */
561 static Context GetThreadCurrent();
564 * Destroys the context. The context must not be current when this is
565 * called.
567 void destroy();
569 /** Retrieves the Device this context was created from. */
570 Device getDevice();
572 void startBatch();
573 void endBatch();
576 * Retrieves a Listener instance for this context. Each context will only
577 * have one listener.
579 Listener getListener();
582 * Sets a MessageHandler instance which will be used to provide certain
583 * messages back to the application. Only one handler may be set for a
584 * context at a time. The previously set handler will be returned.
586 SharedPtr<MessageHandler> setMessageHandler(SharedPtr<MessageHandler> handler);
588 /** Gets the currently-set message handler. */
589 SharedPtr<MessageHandler> getMessageHandler() const;
592 * Specifies the desired interval that the background thread will be woken
593 * up to process tasks, e.g. keeping streaming sources filled. An interval
594 * of 0 means the background thread will only be woken up manually with
595 * calls to update. The default is 0.
597 void setAsyncWakeInterval(std::chrono::milliseconds msec);
600 * Retrieves the current interval used for waking up the background thread.
602 std::chrono::milliseconds getAsyncWakeInterval() const;
604 // Functions below require the context to be current
607 * Creates a Decoder instance for the given audio file or resource name.
609 SharedPtr<Decoder> createDecoder(const String &name);
612 * Queries if the channel configuration and sample type are supported by
613 * the context.
615 bool isSupported(ChannelConfig channels, SampleType type) const;
618 * Queries the list of resamplers supported by the context. If the
619 * AL_SOFT_source_resampler extension is unsupported this will be an empty
620 * vector, otherwise there will be at least one entry.
622 const Vector<String> &getAvailableResamplers();
624 * Queries the context's default resampler index. Be aware, if the
625 * AL_SOFT_source_resampler extension is unsupported the resampler list
626 * will be empty and this will resturn 0. If you try to access the
627 * resampler list with this index without the extension, undefined behavior
628 * (accessing an out of bounds array index) will occur.
630 ALsizei getDefaultResamplerIndex() const;
633 * Creates and caches a Buffer for the given audio file or resource name.
634 * Multiple calls with the same name will return the same Buffer object.
636 Buffer getBuffer(const String &name);
639 * Creates and caches a Buffer for the given audio file or resource name.
640 * Multiple calls with the same name will return the same Buffer object.
642 * The returned Buffer object will be scheduled for loading asynchronously,
643 * and must be checked with a call to Buffer::getLoadStatus prior to being
644 * played.
646 Buffer getBufferAsync(const String &name);
649 * Creates and caches Buffers for the given audio file or resource names.
650 * Duplicate names or names of buffers already cached are ignored.
652 * The Buffer objects will be scheduled for loading asynchronously, and
653 * should be retrieved later when needed using getBufferAsync or getBuffer.
654 * Buffers that cannot be loaded, for example due to an unsupported format,
655 * will be ignored and a later call to getBuffer or getBufferAsync will
656 * throw an exception. Precached buffers must also be cleaned up with calls
657 * to removeBuffer when no longer needed.
659 * Note that you should avoid trying to asynchronously cache more than 16
660 * buffers at a time. The internal ringbuffer used to communicate with the
661 * background thread can only hold 16 async load requests, and trying to
662 * add more will cause the call to stall until the background thread
663 * completes some loads for more to be filled in.
665 void precacheBuffersAsync(ArrayView<String> names);
668 * Creates and caches a Buffer using the given name. The name may alias an
669 * audio file, but it must not currently exist in the buffer cache. As with
670 * other cached buffers, removeBuffer must be used to remove it from the
671 * cache.
673 Buffer createBufferFrom(const String &name, SharedPtr<Decoder> decoder);
676 * Creates and caches a Buffer using the given name. The name may alias an
677 * audio file, but it must not currently exist in the buffer cache.
679 * The returned Buffer object will be scheduled for loading asynchronously,
680 * and must be checked with a call to Buffer::getLoadStatus prior to being
681 * played. The given decoder will be held on to and used asynchronously to
682 * load the buffer. The decoder must not have its read or seek methods
683 * called while the buffer load status is pending.
685 Buffer createBufferAsyncFrom(const String &name, SharedPtr<Decoder> decoder);
688 * Deletes the cached Buffer object for the given audio file or
689 * resource name. The buffer must not be in use by a Source.
691 void removeBuffer(const String &name);
693 * Deletes the given cached buffer. The buffer must not be in use by a
694 * Source.
696 void removeBuffer(Buffer buffer);
699 * Creates a new Source. There is no practical limit to the number of
700 * sources you may create.
702 Source createSource();
704 AuxiliaryEffectSlot createAuxiliaryEffectSlot();
706 Effect createEffect();
708 SourceGroup createSourceGroup(String name);
709 SourceGroup getSourceGroup(const String &name);
711 /** Sets the doppler factor to apply to all source calculations. */
712 void setDopplerFactor(ALfloat factor);
715 * Sets the speed of sound propogation, in units per second, to calculate
716 * the doppler effect along with other distance-related time effects. The
717 * default is 343.3 units per second (a realistic speed assuming 1 meter
718 * per unit).
720 void setSpeedOfSound(ALfloat speed);
722 void setDistanceModel(DistanceModel model);
725 * Updates the context and all sources belonging to this context (you do
726 * not need to call the individual sources' update method if you call this
727 * function).
729 void update();
732 class ALURE_API Listener {
733 MAKE_PIMPL(Listener, ALListener)
735 public:
736 /** Sets the "master" gain for all context output. */
737 void setGain(ALfloat gain);
740 * Specifies the listener's 3D position, velocity, and orientation
741 * together.
743 void set3DParameters(const Vector3 &position, const Vector3 &velocity, std::pair<Vector3,Vector3> orientation);
745 /** Specifies the listener's 3D position. */
746 void setPosition(ALfloat x, ALfloat y, ALfloat z);
747 void setPosition(const ALfloat *pos);
750 * Specifies the listener's 3D velocity, in units per second. As with
751 * OpenAL, this does not actually alter the listener's position, and
752 * instead just alters the pitch as determined by the doppler effect.
754 void setVelocity(ALfloat x, ALfloat y, ALfloat z);
755 void setVelocity(const ALfloat *vel);
758 * Specifies the listener's 3D orientation, using position-relative 'at'
759 * and 'up' direction vectors.
761 void setOrientation(ALfloat x1, ALfloat y1, ALfloat z1, ALfloat x2, ALfloat y2, ALfloat z2);
762 void setOrientation(const ALfloat *at, const ALfloat *up);
763 void setOrientation(const ALfloat *ori);
766 * Sets the number of meters per unit, used for various effects that rely
767 * on the distance in meters (including air absorption and initial reverb
768 * decay). If this is changed, it's strongly recommended to also set the
769 * speed of sound (e.g. context.setSpeedOfSound(343.3 / m_u) to maintain a
770 * realistic 343.3m/s for sound propgation).
772 void setMetersPerUnit(ALfloat m_u);
776 enum class BufferLoadStatus {
777 Pending,
778 Ready
781 class ALURE_API Buffer {
782 MAKE_PIMPL(Buffer, ALBuffer)
784 public:
786 * Retrieves the length of the buffer in sample frames. The buffer must be
787 * fully loaded before this method is called.
789 ALuint getLength() const;
791 /** Retrieves the buffer's frequency in hz. */
792 ALuint getFrequency() const;
794 /** Retrieves the buffer's sample configuration. */
795 ChannelConfig getChannelConfig() const;
797 /** Retrieves the buffer's sample type. */
798 SampleType getSampleType() const;
801 * Retrieves the storage size used by the buffer, in bytes. The buffer must
802 * be fully loaded before this method is called.
804 ALuint getSize() const;
807 * Sets the buffer's loop points, used for looping sources. If the current
808 * context does not support the AL_SOFT_loop_points extension, start and
809 * end must be 0 and getLength() respectively. Otherwise, start must be
810 * less than end, and end must be less than or equal to getLength().
812 * The buffer must not be in use when this method is called, and the buffer
813 * must be fully loaded.
815 * \param start The starting point, in sample frames (inclusive).
816 * \param end The ending point, in sample frames (exclusive).
818 void setLoopPoints(ALuint start, ALuint end);
821 * Retrieves the current loop points as a [start,end) pair. The buffer must
822 * be fully loaded before this method is called.
824 std::pair<ALuint,ALuint> getLoopPoints() const;
827 * Retrieves the Source objects currently playing the buffer. Stopping the
828 * returned sources will allow the buffer to be removed from the context.
830 Vector<Source> getSources() const;
833 * Queries the buffer's load status. A return of BufferLoadStatus::Pending
834 * indicates the buffer is not finished loading and can't be used with a
835 * call to Source::play. Buffers created with Context::getBuffer will
836 * always return BufferLoadStatus::Ready.
838 BufferLoadStatus getLoadStatus();
840 /** Retrieves the name the buffer was created with. */
841 const String &getName() const;
843 /** Queries if the buffer is in use and can't be removed. */
844 bool isInUse() const;
848 enum class Spatialize {
849 Off = AL_FALSE,
850 On = AL_TRUE,
851 Auto = 0x0002 /* AL_AUTO_SOFT */
854 class ALURE_API Source {
855 MAKE_PIMPL(Source, ALSource)
857 public:
859 * Plays the source using buffer. The same buffer may be played from
860 * multiple sources simultaneously.
862 void play(Buffer buffer);
864 * Plays the source by streaming audio from decoder. This will use
865 * queuesize buffers, each with updatelen sample frames. The given decoder
866 * must *NOT* have its read or seek methods called from elsewhere while in
867 * use.
869 void play(SharedPtr<Decoder> decoder, ALuint updatelen, ALuint queuesize);
871 * Stops playback, releasing the buffer or decoder reference.
873 void stop();
875 /** Pauses the source if it is playing. */
876 void pause();
878 /** Resumes the source if it is paused. */
879 void resume();
881 /** Specifies if the source is currently playing. */
882 bool isPlaying() const;
884 /** Specifies if the source is currently paused. */
885 bool isPaused() const;
888 * Specifies the source's playback priority. Lowest priority sources will
889 * be evicted first when higher priority sources are played.
891 void setPriority(ALuint priority);
892 /** Retrieves the source's priority. */
893 ALuint getPriority() const;
896 * Sets the source's offset, in sample frames. If the source is playing or
897 * paused, it will go to that offset immediately, otherwise the source will
898 * start at the specified offset the next time it's played.
900 void setOffset(uint64_t offset);
902 * Retrieves the source offset in sample frames and its latency in nano-
903 * seconds. For streaming sources, this will be the offset from the
904 * beginning of the stream based on the decoder's reported position.
906 * If the AL_SOFT_source_latency extension is unsupported, the latency will
907 * be 0.
909 std::pair<uint64_t,std::chrono::nanoseconds> getSampleOffsetLatency() const;
910 uint64_t getSampleOffset() const { return std::get<0>(getSampleOffsetLatency()); }
912 * Retrieves the source offset and latency in seconds. For streaming
913 * sources, this will be the offset from the beginning of the stream based
914 * on the decoder's reported position.
916 * If the AL_SOFT_source_latency extension is unsupported, the latency will
917 * be 0.
919 std::pair<Seconds,Seconds> getSecOffsetLatency() const;
920 Seconds getSecOffset() const { return std::get<0>(getSecOffsetLatency()); }
923 * Specifies if the source should loop on the Buffer or Decoder object's
924 * loop points.
926 void setLooping(bool looping);
927 bool getLooping() const;
930 * Specifies a linear pitch shift base. A value of 1.0 is the default
931 * normal speed.
933 void setPitch(ALfloat pitch);
934 ALfloat getPitch() const;
937 * Specifies the base linear gain. A value of 1.0 is the default normal
938 * volume.
940 void setGain(ALfloat gain);
941 ALfloat getGain() const;
944 * Specifies the minimum and maximum gain. The source's gain is clamped to
945 * this range after distance attenuation and cone attenuation are applied
946 * to the gain base, although before the filter gain adjustements.
948 void setGainRange(ALfloat mingain, ALfloat maxgain);
949 std::pair<ALfloat,ALfloat> getGainRange() const;
950 ALfloat getMinGain() const { return std::get<0>(getGainRange()); }
951 ALfloat getMaxGain() const { return std::get<1>(getGainRange()); }
954 * Specifies the reference distance and maximum distance the source will
955 * use for the current distance model. For Clamped distance models, the
956 * source's calculated distance is clamped to the specified range before
957 * applying distance-related attenuation.
959 * For all distance models, the reference distance is the distance at which
960 * the source's volume will not have any extra attenuation (an effective
961 * gain multiplier of 1).
963 void setDistanceRange(ALfloat refdist, ALfloat maxdist);
964 std::pair<ALfloat,ALfloat> getDistanceRange() const;
965 ALfloat getReferenceDistance() const { return std::get<0>(getDistanceRange()); }
966 ALfloat getMaxDistance() const { return std::get<1>(getDistanceRange()); }
968 /** Specifies the source's 3D position, velocity, and direction together. */
969 void set3DParameters(const Vector3 &position, const Vector3 &velocity, const Vector3 &direction);
971 /** Specifies the source's 3D position, velocity, and orientation together. */
972 void set3DParameters(const Vector3 &position, const Vector3 &velocity, std::pair<Vector3,Vector3> orientation);
974 /** Specifies the source's 3D position. */
975 void setPosition(ALfloat x, ALfloat y, ALfloat z);
976 void setPosition(const ALfloat *pos);
977 Vector3 getPosition() const;
980 * Specifies the source's 3D velocity, in units per second. As with OpenAL,
981 * this does not actually alter the source's position, and instead just
982 * alters the pitch as determined by the doppler effect.
984 void setVelocity(ALfloat x, ALfloat y, ALfloat z);
985 void setVelocity(const ALfloat *vel);
986 Vector3 getVelocity() const;
989 * Specifies the source's 3D facing direction. Deprecated in favor of
990 * setOrientation.
992 void setDirection(ALfloat x, ALfloat y, ALfloat z);
993 void setDirection(const ALfloat *dir);
994 Vector3 getDirection() const;
997 * Specifies the source's 3D orientation. Note: unlike the AL_EXT_BFORMAT
998 * extension this property comes from, this also affects the facing
999 * direction, superceding setDirection.
1001 void setOrientation(ALfloat x1, ALfloat y1, ALfloat z1, ALfloat x2, ALfloat y2, ALfloat z2);
1002 void setOrientation(const ALfloat *at, const ALfloat *up);
1003 void setOrientation(const ALfloat *ori);
1004 std::pair<Vector3,Vector3> getOrientation() const;
1007 * Specifies the source's cone angles, in degrees. The inner angle is the
1008 * area within which the listener will hear the source with no extra
1009 * attenuation, while the listener being outside of the outer angle will
1010 * hear the source attenuated according to the outer cone gains.
1012 void setConeAngles(ALfloat inner, ALfloat outer);
1013 std::pair<ALfloat,ALfloat> getConeAngles() const;
1014 ALfloat getInnerConeAngle() const { return std::get<0>(getConeAngles()); }
1015 ALfloat getOuterConeAngle() const { return std::get<1>(getConeAngles()); }
1018 * Specifies the linear gain multiplier when the listener is outside of the
1019 * source's outer cone area. The specified gain applies to all frequencies,
1020 * while gainhf applies extra attenuation to high frequencies.
1022 * \param gainhf has no effect without the ALC_EXT_EFX extension.
1024 void setOuterConeGains(ALfloat gain, ALfloat gainhf=1.0f);
1025 std::pair<ALfloat,ALfloat> getOuterConeGains() const;
1026 ALfloat getOuterConeGain() const { return std::get<0>(getOuterConeGains()); }
1027 ALfloat getOuterConeGainHF() const { return std::get<1>(getOuterConeGains()); }
1030 * Specifies the rolloff factors for the direct and send paths. This is
1031 * effectively a distance scaling relative to the reference distance. Note:
1032 * the room rolloff factor is 0 by default, disabling distance attenuation
1033 * for send paths. This is because the reverb engine will, by default,
1034 * apply a more realistic room attenuation based on the reverb decay time
1035 * and direct path attenuation.
1037 void setRolloffFactors(ALfloat factor, ALfloat roomfactor=0.0f);
1038 std::pair<ALfloat,ALfloat> getRolloffFactors() const;
1039 ALfloat getRolloffFactor() const { return std::get<0>(getRolloffFactors()); }
1040 ALfloat getRoomRolloffFactor() const { return std::get<1>(getRolloffFactors()); }
1043 * Specifies the doppler factor for the doppler effect's pitch shift. This
1044 * effectively scales the source and listener velocities for the doppler
1045 * calculation.
1047 void setDopplerFactor(ALfloat factor);
1048 ALfloat getDopplerFactor() const;
1050 /** Specifies if the source properties are relative to the listener. */
1051 void setRelative(bool relative);
1052 bool getRelative() const;
1055 * Specifies the source's radius. This causes the source to behave as if
1056 * every point within the spherical area emits sound.
1058 * Has no effect without the AL_EXT_SOURCE_RADIUS extension.
1060 void setRadius(ALfloat radius);
1061 ALfloat getRadius() const;
1064 * Specifies the left and right channel angles, in radians, when playing a
1065 * stereo buffer or stream. The angles go counter-clockwise, with 0 being
1066 * in front and positive values going left.
1068 * Has no effect without the AL_EXT_STEREO_ANGLES extension.
1070 void setStereoAngles(ALfloat leftAngle, ALfloat rightAngle);
1071 std::pair<ALfloat,ALfloat> getStereoAngles() const;
1073 void set3DSpatialize(Spatialize spatialize);
1074 Spatialize get3DSpatialize() const;
1076 void setResamplerIndex(ALsizei index);
1077 ALsizei getResamplerIndex() const;
1079 void setAirAbsorptionFactor(ALfloat factor);
1080 ALfloat getAirAbsorptionFactor() const;
1082 void setGainAuto(bool directhf, bool send, bool sendhf);
1083 std::tuple<bool,bool,bool> getGainAuto() const;
1084 bool getDirectGainHFAuto() const { return std::get<0>(getGainAuto()); }
1085 bool getSendGainAuto() const { return std::get<1>(getGainAuto()); }
1086 bool getSendGainHFAuto() const { return std::get<2>(getGainAuto()); }
1088 /** Sets the filter properties on the direct path signal. */
1089 void setDirectFilter(const FilterParams &filter);
1091 * Sets the filter properties on the given send path signal. Any auxiliary
1092 * effect slot on the send path remains in place.
1094 void setSendFilter(ALuint send, const FilterParams &filter);
1096 * Connects the effect slot to the given send path. Any filter properties
1097 * on the send path remain as they were.
1099 void setAuxiliarySend(AuxiliaryEffectSlot slot, ALuint send);
1101 * Connects the effect slot to the given send path, using the filter
1102 * properties.
1104 void setAuxiliarySendFilter(AuxiliaryEffectSlot slot, ALuint send, const FilterParams &filter);
1107 * Releases the source, stopping playback, releasing resources, and
1108 * returning it to the system.
1110 void release();
1114 class ALURE_API SourceGroup {
1115 MAKE_PIMPL(SourceGroup, ALSourceGroup)
1117 public:
1118 /** Retrieves the associated name of the source group. */
1119 const String &getName() const;
1122 * Adds source to the source group. A source may only be part of one group
1123 * at a time, and will automatically be removed from its current group as
1124 * needed.
1126 void addSource(Source source);
1127 /** Removes source from the source group. */
1128 void removeSource(Source source);
1130 /** Adds a list of sources to the group at once. */
1131 void addSources(ArrayView<Source> sources);
1132 /** Removes a list of sources from the source group. */
1133 void removeSources(ArrayView<Source> sources);
1136 * Adds group as a subgroup of the source group. This method will throw an
1137 * exception if group is being added to a group it has as a sub-group (i.e.
1138 * it would create a circular sub-group chain).
1140 void addSubGroup(SourceGroup group);
1141 /** Removes group from the source group. */
1142 void removeSubGroup(SourceGroup group);
1144 /** Returns the list of sources currently in the group. */
1145 Vector<Source> getSources() const;
1147 /** Returns the list of subgroups currently in the group. */
1148 Vector<SourceGroup> getSubGroups() const;
1150 /** Sets the source group gain, which accumulates with its sources. */
1151 void setGain(ALfloat gain);
1152 /** Gets the source group gain. */
1153 ALfloat getGain() const;
1155 /** Sets the source group pitch, which accumulates with its sources. */
1156 void setPitch(ALfloat pitch);
1157 /** Gets the source group pitch. */
1158 ALfloat getPitch() const;
1161 * Pauses all currently-playing sources that are under this group,
1162 * including sub-groups.
1164 void pauseAll() const;
1166 * Resumes all paused sources that are under this group, including
1167 * sub-groups.
1169 void resumeAll() const;
1171 /** Stops all sources that are under this group, including sub-groups. */
1172 void stopAll() const;
1175 * Releases the source group, removing all sources from it before being
1176 * freed.
1178 void release();
1182 struct SourceSend {
1183 Source mSource;
1184 ALuint mSend;
1187 class ALURE_API AuxiliaryEffectSlot {
1188 MAKE_PIMPL(AuxiliaryEffectSlot, ALAuxiliaryEffectSlot)
1190 public:
1191 void setGain(ALfloat gain);
1193 * If set to true, the reverb effect will automatically apply adjustments
1194 * to the source's send slot based on the effect properties.
1196 * Has no effect when using non-reverb effects. Default is true.
1198 void setSendAuto(bool sendauto);
1201 * Updates the effect slot with a new effect. The given effect object may
1202 * be altered or destroyed without affecting the effect slot.
1204 void applyEffect(Effect effect);
1207 * Releases the effect slot, returning it to the system. It must not be in
1208 * use by a source.
1210 void release();
1213 * Retrieves each Source object and its pairing send this effect slot is
1214 * set on. Setting a different (or null) effect slot on each source's given
1215 * send will allow the effect slot to be released.
1217 Vector<SourceSend> getSourceSends() const;
1219 /** Determines if the effect slot is in use by a source. */
1220 bool isInUse() const;
1224 class ALURE_API Effect {
1225 MAKE_PIMPL(Effect, ALEffect)
1227 public:
1229 * Updates the effect with the specified reverb properties. If the
1230 * EAXReverb effect is not supported, it will automatically attempt to
1231 * downgrade to the Standard Reverb effect.
1233 void setReverbProperties(const EFXEAXREVERBPROPERTIES &props);
1235 void destroy();
1240 * Audio decoder interface. Applications may derive from this, implementing the
1241 * necessary methods, and use it in places the API wants a Decoder object.
1243 class ALURE_API Decoder {
1244 public:
1245 virtual ~Decoder();
1247 /** Retrieves the sample frequency, in hz, of the audio being decoded. */
1248 virtual ALuint getFrequency() const = 0;
1249 /** Retrieves the channel configuration of the audio being decoded. */
1250 virtual ChannelConfig getChannelConfig() const = 0;
1251 /** Retrieves the sample type of the audio being decoded. */
1252 virtual SampleType getSampleType() const = 0;
1255 * Retrieves the total length of the audio, in sample frames. If unknown,
1256 * returns 0. Note that if the returned length is 0, the decoder may not be
1257 * used to load a Buffer.
1259 virtual uint64_t getLength() const = 0;
1261 * Seek to pos, specified in sample frames. Returns true if the seek was
1262 * successful.
1264 virtual bool seek(uint64_t pos) = 0;
1267 * Retrieves the loop points, in sample frames, as a [start,end) pair. If
1268 * start >= end, use all available data.
1270 virtual std::pair<uint64_t,uint64_t> getLoopPoints() const = 0;
1273 * Decodes count sample frames, writing them to ptr, and returns the number
1274 * of sample frames written. Returning less than the requested count
1275 * indicates the end of the audio.
1277 virtual ALuint read(ALvoid *ptr, ALuint count) = 0;
1281 * Audio decoder factory interface. Applications may derive from this,
1282 * implementing the necessary methods, and use it in places the API wants a
1283 * DecoderFactory object.
1285 class ALURE_API DecoderFactory {
1286 public:
1287 virtual ~DecoderFactory();
1290 * Creates and returns a Decoder instance for the given resource file. If
1291 * the decoder needs to retain the file handle for reading as-needed, it
1292 * should move the UniquePtr to internal storage.
1294 * \return nullptr if a decoder can't be created from the file.
1296 virtual SharedPtr<Decoder> createDecoder(UniquePtr<std::istream> &file) = 0;
1300 * Registers a decoder factory for decoding audio. Registered factories are
1301 * used in lexicographical order, e.g. if Factory1 is registered with name1 and
1302 * Factory2 is registered with name2, Factory1 will be used before Factory2 if
1303 * name1 < name2. Internal decoder factories are always used after registered
1304 * ones.
1306 * Alure retains a reference to the DecoderFactory instance and will release it
1307 * (potentially destroying the object) when the library unloads.
1309 * \param name A unique name identifying this decoder factory.
1310 * \param factory A DecoderFactory instance used to create Decoder instances.
1312 ALURE_API void RegisterDecoder(const String &name, UniquePtr<DecoderFactory> factory);
1315 * Unregisters a decoder factory by name. Alure returns the instance back to
1316 * the application.
1318 * \param name The unique name identifying a previously-registered decoder
1319 * factory.
1321 * \return The unregistered decoder factory instance, or 0 (nullptr) if a
1322 * decoder factory with the given name doesn't exist.
1324 ALURE_API UniquePtr<DecoderFactory> UnregisterDecoder(const String &name);
1328 * A file I/O factory interface. Applications may derive from this and set an
1329 * instance to be used by the audio decoders. By default, the library uses
1330 * standard I/O.
1332 class ALURE_API FileIOFactory {
1333 public:
1335 * Sets the factory instance to be used by the audio decoders. If a
1336 * previous factory was set, it's returned to the application. Passing in a
1337 * NULL factory reverts to the default.
1339 static UniquePtr<FileIOFactory> set(UniquePtr<FileIOFactory> factory);
1342 * Gets the current FileIOFactory instance being used by the audio
1343 * decoders.
1345 static FileIOFactory &get();
1347 virtual ~FileIOFactory();
1349 /** Opens a read-only binary file for the given name. */
1350 virtual UniquePtr<std::istream> openFile(const String &name) = 0;
1355 * A message handler interface. Applications may derive from this and set an
1356 * instance on a context to receive messages. The base methods are no-ops, so
1357 * derived classes only need to implement methods for relevant messages.
1359 * It's recommended that applications mark their handler methods using the
1360 * override keyword, to ensure they're properly overriding the base methods in
1361 * case they change.
1363 class ALURE_API MessageHandler {
1364 public:
1365 virtual ~MessageHandler();
1368 * Called when the given device has been disconnected and is no longer
1369 * usable for output. As per the ALC_EXT_disconnect specification,
1370 * disconnected devices remain valid, however all playing sources are
1371 * automatically stopped, any sources that are attempted to play will
1372 * immediately stop, and new contexts may not be created on the device.
1374 * Note that connection status is checked during Context::update calls, so
1375 * that method must be called regularly to be notified when a device is
1376 * disconnected. This method may not be called if the device lacks support
1377 * for the ALC_EXT_disconnect extension.
1379 * WARNING: Do not attempt to clean up resources within this callback
1380 * method, as Alure is in the middle of doing updates. Instead, flag the
1381 * device as having been lost and do cleanup later.
1383 virtual void deviceDisconnected(Device device);
1386 * Called when the given source reaches the end of the buffer or stream.
1388 * Sources that stopped automatically will be detected upon a call to
1389 * Context::update or Source::update.
1391 virtual void sourceStopped(Source source);
1394 * Called when the given source was forced to stop. This can be because
1395 * either there were no more system sources and a higher-priority source
1396 * needs to play, or it's part of a SourceGroup (or sub-group thereof) that
1397 * had its SourceGroup::stopAll method called.
1399 virtual void sourceForceStopped(Source source);
1402 * Called when a new buffer is about to be created and loaded. May be
1403 * called asynchronously for buffers being loaded asynchronously.
1405 * \param name The resource name, as passed to Context::getBuffer.
1406 * \param channels Channel configuration of the given audio data.
1407 * \param type Sample type of the given audio data.
1408 * \param samplerate Sample rate of the given audio data.
1409 * \param data The audio data that is about to be fed to the OpenAL buffer.
1411 virtual void bufferLoading(const String &name, ChannelConfig channels, SampleType type, ALuint samplerate, const Vector<ALbyte> &data);
1414 * Called when a resource isn't found, allowing the app to substitute in a
1415 * different resource. For buffers created with Context::getBuffer or
1416 * Context::getBufferAsync, the original name will still be used for the
1417 * cache map so the app doesn't have to keep track of substituted resource
1418 * names.
1420 * This will be called again if the new name isn't found.
1422 * \param name The resource name that was not found.
1423 * \return The replacement resource name to use instead. Returning an empty
1424 * string means to stop trying.
1426 virtual String resourceNotFound(const String &name);
1429 #undef MAKE_PIMPL
1431 } // namespace alure
1433 #endif /* AL_ALURE2_H */