14 #include "devicemanager.h"
22 template<typename T
, size_t N
>
23 static inline size_t countof(const T(&)[N
])
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
*) { }
47 enum ALCExtension extension
;
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)
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
;
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"))
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
134 alcGetIntegerv(mDevice
, ALC_FREQUENCY
, 1, &freq
);
136 throw std::runtime_error("Frequency error");
140 ALCuint
ALDevice::getMaxAuxiliarySends() const
142 if(!alcIsExtensionPresent(mDevice
, "ALC_EXT_EFX"))
146 alcGetIntegerv(mDevice
, ALC_MAX_AUXILIARY_SENDS
, 1, &sends
);
148 throw std::runtime_error("Max auxiliary sends error");
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
);
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
));
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
);
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
);
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");