Fix types and casts for MSVC
[alure.git] / src / device.cpp
blob0c0aefd74cc7b120ab6600c2272edee6d6cb1f5a
2 #include "config.h"
4 #include "device.h"
6 #include <string.h>
8 #include <stdexcept>
9 #include <algorithm>
11 #include "devicemanager.h"
12 #include "context.h"
13 #include "buffer.h"
16 namespace {
18 using alure::DeviceImpl;
19 using alure::ALC;
22 template<typename T>
23 inline void LoadALCFunc(ALCdevice *device, T **func, const char *name)
24 { *func = reinterpret_cast<T*>(alcGetProcAddress(device, name)); }
26 void LoadPauseDevice(DeviceImpl *device)
28 LoadALCFunc(device->getALCdevice(), &device->alcDevicePauseSOFT, "alcDevicePauseSOFT");
29 LoadALCFunc(device->getALCdevice(), &device->alcDeviceResumeSOFT, "alcDeviceResumeSOFT");
32 void LoadHrtf(DeviceImpl *device)
34 LoadALCFunc(device->getALCdevice(), &device->alcGetStringiSOFT, "alcGetStringiSOFT");
35 LoadALCFunc(device->getALCdevice(), &device->alcResetDeviceSOFT, "alcResetDeviceSOFT");
38 void LoadNothing(DeviceImpl*) { }
40 static const struct {
41 ALC extension;
42 const char name[32];
43 void (&loader)(DeviceImpl*);
44 } ALCExtensionList[] = {
45 { ALC::ENUMERATE_ALL_EXT, "ALC_ENUMERATE_ALL_EXT", LoadNothing },
46 { ALC::EXT_EFX, "ALC_EXT_EFX", LoadNothing },
47 { ALC::EXT_thread_local_context, "ALC_EXT_thread_local_context", LoadNothing },
48 { ALC::SOFT_device_pause, "ALC_SOFT_pause_device", LoadPauseDevice },
49 { ALC::SOFT_HRTF, "ALC_SOFT_HRTF", LoadHrtf },
52 } // namespace
54 namespace alure {
56 void DeviceImpl::setupExts()
58 mHasExt.clear();
59 for(const auto &entry : ALCExtensionList)
61 if(!alcIsExtensionPresent(mDevice, entry.name))
62 continue;
63 mHasExt.set(static_cast<size_t>(entry.extension));
64 entry.loader(this);
69 DeviceImpl::DeviceImpl(const char *name)
71 mDevice = alcOpenDevice(name);
72 if(!mDevice) throw alc_error(alcGetError(nullptr), "alcOpenDevice failed");
74 setupExts();
77 DeviceImpl::~DeviceImpl()
79 mContexts.clear();
81 if(mDevice)
82 alcCloseDevice(mDevice);
83 mDevice = nullptr;
87 void DeviceImpl::removeContext(ContextImpl *ctx)
89 auto iter = std::find_if(mContexts.begin(), mContexts.end(),
90 [ctx](const UniquePtr<ContextImpl> &entry) -> bool
91 { return entry.get() == ctx; }
93 if(iter != mContexts.end()) mContexts.erase(iter);
97 DECL_THUNK1(String, Device, getName, const, PlaybackName)
98 String DeviceImpl::getName(PlaybackName type) const
100 if(type == PlaybackName::Full && !hasExtension(ALC::ENUMERATE_ALL_EXT))
101 type = PlaybackName::Basic;
102 alcGetError(mDevice);
103 const ALCchar *name = alcGetString(mDevice, (ALenum)type);
104 if(alcGetError(mDevice) != ALC_NO_ERROR || !name)
105 name = alcGetString(mDevice, (ALenum)PlaybackName::Basic);
106 return name ? String(name) : String();
109 bool Device::queryExtension(const String &name) const
110 { return pImpl->queryExtension(name.c_str()); }
111 DECL_THUNK1(bool, Device, queryExtension, const, const char*)
112 bool DeviceImpl::queryExtension(const char *name) const
114 return static_cast<bool>(alcIsExtensionPresent(mDevice, name));
117 DECL_THUNK0(Version, Device, getALCVersion, const)
118 Version DeviceImpl::getALCVersion() const
120 ALCint major=-1, minor=-1;
121 alcGetIntegerv(mDevice, ALC_MAJOR_VERSION, 1, &major);
122 alcGetIntegerv(mDevice, ALC_MINOR_VERSION, 1, &minor);
123 if(major < 0 || minor < 0)
124 throw std::runtime_error("ALC version error");
125 return Version{ (ALCuint)major, (ALCuint)minor };
128 DECL_THUNK0(Version, Device, getEFXVersion, const)
129 Version DeviceImpl::getEFXVersion() const
131 if(!hasExtension(ALC::EXT_EFX))
132 return Version{ 0u, 0u };
134 ALCint major=-1, minor=-1;
135 alcGetIntegerv(mDevice, ALC_EFX_MAJOR_VERSION, 1, &major);
136 alcGetIntegerv(mDevice, ALC_EFX_MINOR_VERSION, 1, &minor);
137 if(major < 0 || minor < 0)
138 throw std::runtime_error("EFX version error");
139 return Version{ (ALCuint)major, (ALCuint)minor };
142 DECL_THUNK0(ALCuint, Device, getFrequency, const)
143 ALCuint DeviceImpl::getFrequency() const
145 ALCint freq = -1;
146 alcGetIntegerv(mDevice, ALC_FREQUENCY, 1, &freq);
147 if(freq < 0)
148 throw std::runtime_error("Frequency error");
149 return freq;
152 DECL_THUNK0(ALCuint, Device, getMaxAuxiliarySends, const)
153 ALCuint DeviceImpl::getMaxAuxiliarySends() const
155 if(!hasExtension(ALC::EXT_EFX))
156 return 0;
158 ALCint sends=-1;
159 alcGetIntegerv(mDevice, ALC_MAX_AUXILIARY_SENDS, 1, &sends);
160 if(sends < 0)
161 throw std::runtime_error("Max auxiliary sends error");
162 return sends;
166 DECL_THUNK0(Vector<String>, Device, enumerateHRTFNames, const)
167 Vector<String> DeviceImpl::enumerateHRTFNames() const
169 Vector<String> hrtfs;
170 if(!hasExtension(ALC::SOFT_HRTF))
171 return hrtfs;
173 ALCint num_hrtfs = -1;
174 alcGetIntegerv(mDevice, ALC_NUM_HRTF_SPECIFIERS_SOFT, 1, &num_hrtfs);
175 if(num_hrtfs < 0)
176 throw std::runtime_error("HRTF specifier count error");
178 hrtfs.reserve(num_hrtfs);
179 for(int i = 0;i < num_hrtfs;++i)
180 hrtfs.emplace_back(alcGetStringiSOFT(mDevice, ALC_HRTF_SPECIFIER_SOFT, i));
181 return hrtfs;
184 DECL_THUNK0(bool, Device, isHRTFEnabled, const)
185 bool DeviceImpl::isHRTFEnabled() const
187 if(!hasExtension(ALC::SOFT_HRTF))
188 return false;
190 ALCint hrtf_state = -1;
191 alcGetIntegerv(mDevice, ALC_HRTF_SOFT, 1, &hrtf_state);
192 if(hrtf_state == -1)
193 throw std::runtime_error("HRTF state error");
194 return hrtf_state != ALC_FALSE;
197 DECL_THUNK0(String, Device, getCurrentHRTF, const)
198 String DeviceImpl::getCurrentHRTF() const
200 if(!hasExtension(ALC::SOFT_HRTF))
201 return String();
202 return String(alcGetString(mDevice, ALC_HRTF_SPECIFIER_SOFT));
205 DECL_THUNK1(void, Device, reset,, ArrayView<AttributePair>)
206 void DeviceImpl::reset(ArrayView<AttributePair> attributes)
208 if(!hasExtension(ALC::SOFT_HRTF))
209 return;
210 ALCboolean success = ALC_FALSE;
211 if(attributes.end()) /* No explicit attributes. */
212 success = alcResetDeviceSOFT(mDevice, nullptr);
213 else
215 auto attr_end = std::find_if(attributes.rbegin(), attributes.rend(),
216 [](const AttributePair &attr) -> bool
217 { return std::get<0>(attr) == 0; }
219 if(attr_end == attributes.rend())
221 /* Attribute list was not properly terminated. Copy the attribute
222 * list and add the 0 sentinel.
224 Vector<AttributePair> attrs;
225 attrs.reserve(attributes.size() + 1);
226 std::copy(attributes.begin(), attributes.end(), std::back_inserter(attrs));
227 attrs.push_back(AttributesEnd());
228 success = alcResetDeviceSOFT(mDevice, &std::get<0>(attrs.front()));
230 else
231 success = alcResetDeviceSOFT(mDevice, &std::get<0>(attributes.front()));
233 if(!success)
234 throw alc_error(alcGetError(mDevice), "alcResetDeviceSOFT failed");
238 DECL_THUNK1(Context, Device, createContext,, ArrayView<AttributePair>)
239 Context DeviceImpl::createContext(ArrayView<AttributePair> attributes)
241 Vector<AttributePair> attrs;
242 if(!attributes.empty())
244 auto attr_end = std::find_if(attributes.rbegin(), attributes.rend(),
245 [](const AttributePair &attr) -> bool
246 { return std::get<0>(attr) == 0; }
248 if(attr_end == attributes.rend())
250 /* Attribute list was not properly terminated. Copy the attribute
251 * list and add the 0 sentinel.
253 attrs.reserve(attributes.size() + 1);
254 std::copy(attributes.begin(), attributes.end(), std::back_inserter(attrs));
255 attrs.push_back(AttributesEnd());
256 attributes = attrs;
260 mContexts.emplace_back(MakeUnique<ContextImpl>(*this, attributes));
261 return Context(mContexts.back().get());
264 Context Device::createContext(const std::nothrow_t&) noexcept
265 { return createContext({}, std::nothrow); }
266 Context Device::createContext(ArrayView<AttributePair> attrs, const std::nothrow_t&) noexcept
268 try {
269 return pImpl->createContext(attrs);
271 catch(...) {
273 return Context();
277 DECL_THUNK0(void, Device, pauseDSP,)
278 void DeviceImpl::pauseDSP()
280 if(!hasExtension(ALC::SOFT_device_pause))
281 throw std::runtime_error("ALC_SOFT_pause_device not supported");
282 alcDevicePauseSOFT(mDevice);
285 DECL_THUNK0(void, Device, resumeDSP,)
286 void DeviceImpl::resumeDSP()
288 if(hasExtension(ALC::SOFT_device_pause))
289 alcDeviceResumeSOFT(mDevice);
293 void Device::close()
295 DeviceImpl *i = pImpl;
296 pImpl = nullptr;
297 i->close();
299 void DeviceImpl::close()
301 if(!mContexts.empty())
302 throw std::runtime_error("Trying to close device with contexts");
304 if(alcCloseDevice(mDevice) == ALC_FALSE)
305 throw alc_error(alcGetError(mDevice), "alcCloseDevice failed");
306 mDevice = nullptr;
308 DeviceManagerImpl::getInstance()->removeDevice(this);
311 } // namespace alure