Document some source methods
[alure.git] / src / device.cpp
blobf1425a678e36bac263ec6203fca3eab87b7402e1
2 #include "config.h"
4 #include "device.h"
6 #include <string.h>
8 #include <stdexcept>
9 #include <algorithm>
11 #include "alc.h"
12 #include "alext.h"
14 #include "devicemanager.h"
15 #include "context.h"
16 #include "buffer.h"
19 namespace alure
22 template<typename T, size_t N>
23 static inline size_t countof(const T(&)[N])
24 { return N; }
27 template<typename T>
28 static inline void LoadALCFunc(ALCdevice *device, T **func, const char *name)
29 { *func = reinterpret_cast<T*>(alcGetProcAddress(device, name)); }
32 static void LoadPauseDevice(ALDevice *device)
34 LoadALCFunc(device->getDevice(), &device->alcDevicePauseSOFT, "alcDevicePauseSOFT");
35 LoadALCFunc(device->getDevice(), &device->alcDeviceResumeSOFT, "alcDeviceResumeSOFT");
38 static void LoadHrtf(ALDevice *device)
40 LoadALCFunc(device->getDevice(), &device->alcGetStringiSOFT, "alcGetStringiSOFT");
41 LoadALCFunc(device->getDevice(), &device->alcResetDeviceSOFT, "alcResetDeviceSOFT");
44 static void LoadNothing(ALDevice*) { }
46 static const struct {
47 enum ALCExtension extension;
48 const char name[32];
49 void (*loader)(ALDevice*);
50 } ALCExtensionList[] = {
51 { EXT_thread_local_context, "ALC_EXT_thread_local_context", LoadNothing },
52 { SOFT_device_pause, "ALC_SOFT_pause_device", LoadPauseDevice },
53 { SOFT_HRTF, "ALC_SOFT_HRTF", LoadHrtf },
57 void ALDevice::setupExts()
59 for(size_t i = 0;i < countof(ALCExtensionList);i++)
61 mHasExt[ALCExtensionList[i].extension] = alcIsExtensionPresent(mDevice, ALCExtensionList[i].name);
62 if(mHasExt[ALCExtensionList[i].extension])
63 ALCExtensionList[i].loader(this);
68 ALDevice::ALDevice(ALCdevice* device)
69 : mDevice(device), mHasExt{false}, alcDevicePauseSOFT(nullptr), alcDeviceResumeSOFT(nullptr)
71 setupExts();
74 ALDevice::~ALDevice()
79 void ALDevice::removeContext(ALContext *ctx)
81 std::vector<ALContext*>::iterator iter;
82 iter = std::find(mContexts.begin(), mContexts.end(), ctx);
83 if(iter != mContexts.end())
84 mContexts.erase(iter);
88 std::string ALDevice::getName(PlaybackDeviceType type) const
90 if(type == PlaybackDevType_Complete && !alcIsExtensionPresent(mDevice, "ALC_ENUMERATE_ALL_EXT"))
91 type = PlaybackDevType_Basic;
92 alcGetError(mDevice);
93 const ALCchar *name = alcGetString(mDevice, type);
94 if(alcGetError(mDevice) != ALC_NO_ERROR || !name)
95 name = alcGetString(mDevice, PlaybackDevType_Basic);
96 return std::string(name ? name : "");
99 bool ALDevice::queryExtension(const char *extname) const
101 return alcIsExtensionPresent(mDevice, extname);
104 ALCuint ALDevice::getALCVersion() const
106 ALCint major=-1, minor=-1;
107 alcGetIntegerv(mDevice, ALC_MAJOR_VERSION, 1, &major);
108 alcGetIntegerv(mDevice, ALC_MINOR_VERSION, 1, &minor);
109 if(major < 0 || minor < 0)
110 throw std::runtime_error("ALC version error");
111 major = std::min<ALCint>(major, std::numeric_limits<ALCushort>::max());
112 minor = std::min<ALCint>(minor, std::numeric_limits<ALCushort>::max());
113 return MakeVersion((ALCushort)major, (ALCushort)minor);
116 ALCuint ALDevice::getEFXVersion() const
118 if(!alcIsExtensionPresent(mDevice, "ALC_EXT_EFX"))
119 return 0;
121 ALCint major=-1, minor=-1;
122 alcGetIntegerv(mDevice, ALC_EFX_MAJOR_VERSION, 1, &major);
123 alcGetIntegerv(mDevice, ALC_EFX_MINOR_VERSION, 1, &minor);
124 if(major < 0 || minor < 0)
125 throw std::runtime_error("EFX version error");
126 major = std::min<ALCint>(major, std::numeric_limits<ALCushort>::max());
127 minor = std::min<ALCint>(minor, std::numeric_limits<ALCushort>::max());
128 return MakeVersion((ALCushort)major, (ALCushort)minor);
131 ALCuint ALDevice::getFrequency() const
133 ALCint freq = -1;
134 alcGetIntegerv(mDevice, ALC_FREQUENCY, 1, &freq);
135 if(freq < 0)
136 throw std::runtime_error("Frequency error");
137 return freq;
140 ALCuint ALDevice::getMaxAuxiliarySends() const
142 if(!alcIsExtensionPresent(mDevice, "ALC_EXT_EFX"))
143 return 0;
145 ALCint sends=-1;
146 alcGetIntegerv(mDevice, ALC_MAX_AUXILIARY_SENDS, 1, &sends);
147 if(sends == -1)
148 throw std::runtime_error("Max auxiliary sends error");
149 return sends;
153 std::vector<std::string> ALDevice::enumerateHRTFNames() const
155 if(!hasExtension(SOFT_HRTF))
156 throw std::runtime_error("ALC_SOFT_HRTF not supported");
158 ALCint num_hrtfs = -1;
159 alcGetIntegerv(mDevice, ALC_NUM_HRTF_SPECIFIERS_SOFT, 1, &num_hrtfs);
160 if(num_hrtfs == -1)
161 throw std::runtime_error("HRTF specifier count error");
163 std::vector<std::string> hrtfs;
164 hrtfs.reserve(num_hrtfs);
165 for(int i = 0;i < num_hrtfs;++i)
166 hrtfs.push_back(alcGetStringiSOFT(mDevice, ALC_HRTF_SPECIFIER_SOFT, i));
167 return hrtfs;
170 bool ALDevice::isHRTFEnabled() const
172 if(!hasExtension(SOFT_HRTF))
173 throw std::runtime_error("ALC_SOFT_HRTF not supported");
175 ALCint hrtf_state = -1;
176 alcGetIntegerv(mDevice, ALC_HRTF_SOFT, 1, &hrtf_state);
177 if(hrtf_state == -1)
178 throw std::runtime_error("HRTF state error");
179 return hrtf_state != ALC_FALSE;
182 std::string ALDevice::getCurrentHRTF() const
184 if(!hasExtension(SOFT_HRTF))
185 throw std::runtime_error("ALC_SOFT_HRTF not supported");
186 return std::string(alcGetString(mDevice, ALC_HRTF_SPECIFIER_SOFT));
189 void ALDevice::reset(ALCint *attributes)
191 if(!hasExtension(SOFT_HRTF))
192 throw std::runtime_error("ALC_SOFT_HRTF not supported");
193 if(!alcResetDeviceSOFT(mDevice, attributes))
194 throw std::runtime_error("Device reset error");
198 Context *ALDevice::createContext(ALCint *attribs)
200 ALCcontext *ctx = alcCreateContext(mDevice, attribs);
201 if(!ctx) throw std::runtime_error("Failed to create context");
203 ALContext *ret = new ALContext(ctx, this);
204 mContexts.push_back(ret);
205 return ret;
209 void ALDevice::pauseDSP()
211 if(!hasExtension(SOFT_device_pause))
212 throw std::runtime_error("ALC_SOFT_pause_device not supported");
213 alcDevicePauseSOFT(mDevice);
216 void ALDevice::resumeDSP()
218 if(hasExtension(SOFT_device_pause))
219 alcDeviceResumeSOFT(mDevice);
223 void ALDevice::close()
225 if(!mContexts.empty())
226 throw std::runtime_error("Trying to close device with contexts");
228 if(alcCloseDevice(mDevice) == ALC_FALSE)
229 throw std::runtime_error("Failed to close device");
230 mDevice = 0;
232 delete this;