// Copyright (C) 2015 Jérôme Leclercq // This file is part of the "Nazara Engine - Audio module" // For conditions of distribution and use, see copyright notice in Config.hpp #include #include #include #include #include #include #include #include namespace Nz { namespace { DynLib s_library; String s_deviceName; String s_rendererName; String s_vendorName; ALCdevice* s_device = nullptr; ALCcontext* s_context = nullptr; unsigned int s_version; std::size_t ParseDevices(const char* deviceString, std::vector& devices) { if (!deviceString) return 0; std::size_t startSize = devices.size(); std::size_t length; while ((length = std::strlen(deviceString)) > 0) { devices.push_back(String(deviceString, length)); deviceString += length + 1; } return devices.size() - startSize; } } OpenALFunc OpenAL::GetEntry(const String& entryPoint) { return LoadEntry(entryPoint.GetConstBuffer(), false); } String OpenAL::GetRendererName() { return s_rendererName; } String OpenAL::GetVendorName() { return s_vendorName; } unsigned int OpenAL::GetVersion() { return s_version; } bool OpenAL::Initialize(bool openDevice) { if (s_library.IsLoaded()) return true; #if defined(NAZARA_PLATFORM_WINDOWS) ///FIXME: Est-ce qu'OpenAL Soft est une meilleure implémentation que Creative ? /// Si on pouvait se résigner à utiliser OpenAL Soft tout le temps, cela nous permettrait d'utiliser les extensions sonores /// et de donner plus de possibilités techniques au niveau de l'audio. const char* libs[] = { "soft_oal.dll", "wrap_oal.dll", "openal32.dll" }; #elif defined(NAZARA_PLATFORM_LINUX) const char* libs[] = { "libopenal.so.1", "libopenal.so.0", "libopenal.so" }; //#elif defined(NAZARA_PLATFORM_MACOSX) #else NazaraError("Unknown OS"); return false; #endif bool succeeded = false; for (const char* path : libs) { String libPath(path); if (!s_library.Load(libPath)) continue; try { // al alBuffer3f = reinterpret_cast(LoadEntry("alBuffer3f")); alBuffer3i = reinterpret_cast(LoadEntry("alBuffer3i")); alBufferData = reinterpret_cast(LoadEntry("alBufferData")); alBufferf = reinterpret_cast(LoadEntry("alBufferf")); alBufferfv = reinterpret_cast(LoadEntry("alBufferfv")); alBufferi = reinterpret_cast(LoadEntry("alBufferi")); alBufferiv = reinterpret_cast(LoadEntry("alBufferiv")); alDeleteBuffers = reinterpret_cast(LoadEntry("alDeleteBuffers")); alDeleteSources = reinterpret_cast(LoadEntry("alDeleteSources")); alDisable = reinterpret_cast(LoadEntry("alDisable")); alDistanceModel = reinterpret_cast(LoadEntry("alDistanceModel")); alDopplerFactor = reinterpret_cast(LoadEntry("alDopplerFactor")); alDopplerVelocity = reinterpret_cast(LoadEntry("alDopplerVelocity")); alEnable = reinterpret_cast(LoadEntry("alEnable")); alGenBuffers = reinterpret_cast(LoadEntry("alGenBuffers")); alGenSources = reinterpret_cast(LoadEntry("alGenSources")); alGetBoolean = reinterpret_cast(LoadEntry("alGetBoolean")); alGetBooleanv = reinterpret_cast(LoadEntry("alGetBooleanv")); alGetBuffer3f = reinterpret_cast(LoadEntry("alGetBuffer3f")); alGetBuffer3i = reinterpret_cast(LoadEntry("alGetBuffer3i")); alGetBufferf = reinterpret_cast(LoadEntry("alGetBufferf")); alGetBufferfv = reinterpret_cast(LoadEntry("alGetBufferfv")); alGetBufferi = reinterpret_cast(LoadEntry("alGetBufferi")); alGetBufferiv = reinterpret_cast(LoadEntry("alGetBufferiv")); alGetDouble = reinterpret_cast(LoadEntry("alGetDouble")); alGetDoublev = reinterpret_cast(LoadEntry("alGetDoublev")); alGetEnumValue = reinterpret_cast(LoadEntry("alGetEnumValue")); alGetError = reinterpret_cast(LoadEntry("alGetError")); alGetFloat = reinterpret_cast(LoadEntry("alGetFloat")); alGetFloatv = reinterpret_cast(LoadEntry("alGetFloatv")); alGetInteger = reinterpret_cast(LoadEntry("alGetInteger")); alGetIntegerv = reinterpret_cast(LoadEntry("alGetIntegerv")); alGetListener3f = reinterpret_cast(LoadEntry("alGetListener3f")); alGetListener3i = reinterpret_cast(LoadEntry("alGetListener3i")); alGetListenerf = reinterpret_cast(LoadEntry("alGetListenerf")); alGetListenerfv = reinterpret_cast(LoadEntry("alGetListenerfv")); alGetListeneri = reinterpret_cast(LoadEntry("alGetListeneri")); alGetListeneriv = reinterpret_cast(LoadEntry("alGetListeneriv")); alGetProcAddress = reinterpret_cast(LoadEntry("alGetProcAddress")); alGetSource3f = reinterpret_cast(LoadEntry("alGetSource3f")); alGetSource3i = reinterpret_cast(LoadEntry("alGetSource3i")); alGetSourcef = reinterpret_cast(LoadEntry("alGetSourcef")); alGetSourcefv = reinterpret_cast(LoadEntry("alGetSourcefv")); alGetSourcei = reinterpret_cast(LoadEntry("alGetSourcei")); alGetSourceiv = reinterpret_cast(LoadEntry("alGetSourceiv")); alGetString = reinterpret_cast(LoadEntry("alGetString")); alIsBuffer = reinterpret_cast(LoadEntry("alIsBuffer")); alIsEnabled = reinterpret_cast(LoadEntry("alIsEnabled")); alIsExtensionPresent = reinterpret_cast(LoadEntry("alIsExtensionPresent")); alIsSource = reinterpret_cast(LoadEntry("alIsSource")); alListener3f = reinterpret_cast(LoadEntry("alListener3f")); alListener3i = reinterpret_cast(LoadEntry("alListener3i")); alListenerf = reinterpret_cast(LoadEntry("alListenerf")); alListenerfv = reinterpret_cast(LoadEntry("alListenerfv")); alListeneri = reinterpret_cast(LoadEntry("alListeneri")); alListeneriv = reinterpret_cast(LoadEntry("alListeneriv")); alSource3f = reinterpret_cast(LoadEntry("alSource3f")); alSource3i = reinterpret_cast(LoadEntry("alSource3i")); alSourcef = reinterpret_cast(LoadEntry("alSourcef")); alSourcefv = reinterpret_cast(LoadEntry("alSourcefv")); alSourcei = reinterpret_cast(LoadEntry("alSourcei")); alSourceiv = reinterpret_cast(LoadEntry("alSourceiv")); alSourcePause = reinterpret_cast(LoadEntry("alSourcePause")); alSourcePausev = reinterpret_cast(LoadEntry("alSourcePausev")); alSourcePlay = reinterpret_cast(LoadEntry("alSourcePlay")); alSourcePlayv = reinterpret_cast(LoadEntry("alSourcePlayv")); alSourceQueueBuffers = reinterpret_cast(LoadEntry("alSourceQueueBuffers")); alSourceRewind = reinterpret_cast(LoadEntry("alSourceRewind")); alSourceRewindv = reinterpret_cast(LoadEntry("alSourceRewindv")); alSourceStop = reinterpret_cast(LoadEntry("alSourceStop")); alSourceStopv = reinterpret_cast(LoadEntry("alSourceStopv")); alSourceUnqueueBuffers = reinterpret_cast(LoadEntry("alSourceUnqueueBuffers")); alSpeedOfSound = reinterpret_cast(LoadEntry("alSpeedOfSound")); // alc alcCaptureCloseDevice = reinterpret_cast(LoadEntry("alcCaptureCloseDevice")); alcCaptureOpenDevice = reinterpret_cast(LoadEntry("alcCaptureOpenDevice")); alcCaptureSamples = reinterpret_cast(LoadEntry("alcCaptureSamples")); alcCaptureStart = reinterpret_cast(LoadEntry("alcCaptureStart")); alcCaptureStop = reinterpret_cast(LoadEntry("alcCaptureStop")); alcCloseDevice = reinterpret_cast(LoadEntry("alcCloseDevice")); alcCreateContext = reinterpret_cast(LoadEntry("alcCreateContext")); alcDestroyContext = reinterpret_cast(LoadEntry("alcDestroyContext")); alcGetContextsDevice = reinterpret_cast(LoadEntry("alcGetContextsDevice")); alcGetCurrentContext = reinterpret_cast(LoadEntry("alcGetCurrentContext")); alcGetEnumValue = reinterpret_cast(LoadEntry("alcGetEnumValue")); alcGetError = reinterpret_cast(LoadEntry("alcGetError")); alcGetIntegerv = reinterpret_cast(LoadEntry("alcGetIntegerv")); alcGetProcAddress = reinterpret_cast(LoadEntry("alcGetProcAddress")); alcGetString = reinterpret_cast(LoadEntry("alcGetString")); alcIsExtensionPresent = reinterpret_cast(LoadEntry("alcIsExtensionPresent")); alcMakeContextCurrent = reinterpret_cast(LoadEntry("alcMakeContextCurrent")); alcOpenDevice = reinterpret_cast(LoadEntry("alcOpenDevice")); alcProcessContext = reinterpret_cast(LoadEntry("alcProcessContext")); alcSuspendContext = reinterpret_cast(LoadEntry("alcSuspendContext")); succeeded = true; break; } catch (const std::exception& e) { NazaraWarning(libPath + " loading failed: " + String(e.what())); continue; } } if (!succeeded) { NazaraError("Failed to load OpenAL"); Uninitialize(); return false; } if (openDevice) OpenDevice(); return true; } bool OpenAL::IsInitialized() { return s_library.IsLoaded(); } std::size_t OpenAL::QueryInputDevices(std::vector& devices) { const char* deviceString = reinterpret_cast(alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER)); if (!deviceString) return 0; return ParseDevices(deviceString, devices); } std::size_t OpenAL::QueryOutputDevices(std::vector& devices) { const char* deviceString = reinterpret_cast(alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER)); if (!deviceString) return 0; return ParseDevices(deviceString, devices); } bool OpenAL::SetDevice(const String& deviceName) { s_deviceName = deviceName; if (IsInitialized()) { CloseDevice(); return OpenDevice(); } else return true; } void OpenAL::Uninitialize() { CloseDevice(); s_rendererName.Clear(false); s_vendorName.Clear(false); s_library.Unload(); } ///ATTENTION: La valeur entière est le nombre de canaux possédés par ce format ALenum OpenAL::AudioFormat[AudioFormat_Max+1] = {0}; // Valeur ajoutées au chargement d'OpenAL void OpenAL::CloseDevice() { if (s_device) { if (s_context) { alcMakeContextCurrent(nullptr); alcDestroyContext(s_context); s_context = nullptr; } if (!alcCloseDevice(s_device)) // Nous n'avons pas pu fermer le device, ce qui signifie qu'il est en cours d'utilisation NazaraWarning("Failed to close device"); s_device = nullptr; } } bool OpenAL::OpenDevice() { // Initialisation du module s_device = alcOpenDevice(s_deviceName.IsEmpty() ? nullptr : s_deviceName.GetConstBuffer()); // On choisit le device par défaut if (!s_device) { NazaraError("Failed to open default device"); return false; } // Un seul contexte nous suffira s_context = alcCreateContext(s_device, nullptr); if (!s_context) { NazaraError("Failed to create context"); return false; } if (!alcMakeContextCurrent(s_context)) { NazaraError("Failed to activate context"); return false; } s_rendererName = reinterpret_cast(alGetString(AL_RENDERER)); s_vendorName = reinterpret_cast(alGetString(AL_VENDOR)); const ALchar* version = alGetString(AL_VERSION); if (version) { unsigned int major = version[0] - '0'; unsigned int minor = version[2] - '0'; if (major != 0 && major <= 9) { if (minor > 9) { NazaraWarning("Unable to retrieve OpenAL minor version (using 0)"); minor = 0; } s_version = major*100 + minor*10; NazaraDebug("OpenAL version: " + String::Number(major) + '.' + String::Number(minor)); } else { NazaraDebug("Unable to retrieve OpenAL major version"); s_version = 0; } } else { NazaraDebug("Unable to retrieve OpenAL version"); s_version = 0; } // On complète le tableau de formats AudioFormat[AudioFormat_Mono] = AL_FORMAT_MONO16; AudioFormat[AudioFormat_Stereo] = AL_FORMAT_STEREO16; // "The presence of an enum value does not guarantee the applicability of an extension to the current context." if (alIsExtensionPresent("AL_EXT_MCFORMATS")) { AudioFormat[AudioFormat_Quad] = alGetEnumValue("AL_FORMAT_QUAD16"); AudioFormat[AudioFormat_5_1] = alGetEnumValue("AL_FORMAT_51CHN16"); AudioFormat[AudioFormat_6_1] = alGetEnumValue("AL_FORMAT_61CHN16"); AudioFormat[AudioFormat_7_1] = alGetEnumValue("AL_FORMAT_71CHN16"); } else if (alIsExtensionPresent("AL_LOKI_quadriphonic")) AudioFormat[AudioFormat_Quad] = alGetEnumValue("AL_FORMAT_QUAD16_LOKI"); return true; } OpenALFunc OpenAL::LoadEntry(const char* name, bool throwException) { OpenALFunc entry = reinterpret_cast(s_library.GetSymbol(name)); if (!entry && throwException) { std::ostringstream oss; oss << "failed to load \"" << name << '"'; throw std::runtime_error(oss.str()); } return entry; } // al OpenALDetail::LPALBUFFER3F alBuffer3f = nullptr; OpenALDetail::LPALBUFFER3I alBuffer3i = nullptr; OpenALDetail::LPALBUFFERDATA alBufferData = nullptr; OpenALDetail::LPALBUFFERF alBufferf = nullptr; OpenALDetail::LPALBUFFERFV alBufferfv = nullptr; OpenALDetail::LPALBUFFERI alBufferi = nullptr; OpenALDetail::LPALBUFFERIV alBufferiv = nullptr; OpenALDetail::LPALDELETEBUFFERS alDeleteBuffers = nullptr; OpenALDetail::LPALDELETESOURCES alDeleteSources = nullptr; OpenALDetail::LPALDISABLE alDisable = nullptr; OpenALDetail::LPALDISTANCEMODEL alDistanceModel = nullptr; OpenALDetail::LPALDOPPLERFACTOR alDopplerFactor = nullptr; OpenALDetail::LPALDOPPLERVELOCITY alDopplerVelocity = nullptr; OpenALDetail::LPALENABLE alEnable = nullptr; OpenALDetail::LPALGENBUFFERS alGenBuffers = nullptr; OpenALDetail::LPALGENSOURCES alGenSources = nullptr; OpenALDetail::LPALGETBOOLEAN alGetBoolean = nullptr; OpenALDetail::LPALGETBOOLEANV alGetBooleanv = nullptr; OpenALDetail::LPALGETBUFFER3F alGetBuffer3f = nullptr; OpenALDetail::LPALGETBUFFER3I alGetBuffer3i = nullptr; OpenALDetail::LPALGETBUFFERF alGetBufferf = nullptr; OpenALDetail::LPALGETBUFFERFV alGetBufferfv = nullptr; OpenALDetail::LPALGETBUFFERI alGetBufferi = nullptr; OpenALDetail::LPALGETBUFFERIV alGetBufferiv = nullptr; OpenALDetail::LPALGETDOUBLE alGetDouble = nullptr; OpenALDetail::LPALGETDOUBLEV alGetDoublev = nullptr; OpenALDetail::LPALGETENUMVALUE alGetEnumValue = nullptr; OpenALDetail::LPALGETERROR alGetError = nullptr; OpenALDetail::LPALGETFLOAT alGetFloat = nullptr; OpenALDetail::LPALGETFLOATV alGetFloatv = nullptr; OpenALDetail::LPALGETINTEGER alGetInteger = nullptr; OpenALDetail::LPALGETINTEGERV alGetIntegerv = nullptr; OpenALDetail::LPALGETLISTENER3F alGetListener3f = nullptr; OpenALDetail::LPALGETLISTENER3I alGetListener3i = nullptr; OpenALDetail::LPALGETLISTENERF alGetListenerf = nullptr; OpenALDetail::LPALGETLISTENERFV alGetListenerfv = nullptr; OpenALDetail::LPALGETLISTENERI alGetListeneri = nullptr; OpenALDetail::LPALGETLISTENERIV alGetListeneriv = nullptr; OpenALDetail::LPALGETPROCADDRESS alGetProcAddress = nullptr; OpenALDetail::LPALGETSOURCE3F alGetSource3f = nullptr; OpenALDetail::LPALGETSOURCE3I alGetSource3i = nullptr; OpenALDetail::LPALGETSOURCEF alGetSourcef = nullptr; OpenALDetail::LPALGETSOURCEFV alGetSourcefv = nullptr; OpenALDetail::LPALGETSOURCEI alGetSourcei = nullptr; OpenALDetail::LPALGETSOURCEIV alGetSourceiv = nullptr; OpenALDetail::LPALGETSTRING alGetString = nullptr; OpenALDetail::LPALISBUFFER alIsBuffer = nullptr; OpenALDetail::LPALISENABLED alIsEnabled = nullptr; OpenALDetail::LPALISEXTENSIONPRESENT alIsExtensionPresent = nullptr; OpenALDetail::LPALISSOURCE alIsSource = nullptr; OpenALDetail::LPALLISTENER3F alListener3f = nullptr; OpenALDetail::LPALLISTENER3I alListener3i = nullptr; OpenALDetail::LPALLISTENERF alListenerf = nullptr; OpenALDetail::LPALLISTENERFV alListenerfv = nullptr; OpenALDetail::LPALLISTENERI alListeneri = nullptr; OpenALDetail::LPALLISTENERIV alListeneriv = nullptr; OpenALDetail::LPALSOURCE3F alSource3f = nullptr; OpenALDetail::LPALSOURCE3I alSource3i = nullptr; OpenALDetail::LPALSOURCEF alSourcef = nullptr; OpenALDetail::LPALSOURCEFV alSourcefv = nullptr; OpenALDetail::LPALSOURCEI alSourcei = nullptr; OpenALDetail::LPALSOURCEIV alSourceiv = nullptr; OpenALDetail::LPALSOURCEPAUSE alSourcePause = nullptr; OpenALDetail::LPALSOURCEPAUSEV alSourcePausev = nullptr; OpenALDetail::LPALSOURCEPLAY alSourcePlay = nullptr; OpenALDetail::LPALSOURCEPLAYV alSourcePlayv = nullptr; OpenALDetail::LPALSOURCEQUEUEBUFFERS alSourceQueueBuffers = nullptr; OpenALDetail::LPALSOURCEREWIND alSourceRewind = nullptr; OpenALDetail::LPALSOURCEREWINDV alSourceRewindv = nullptr; OpenALDetail::LPALSOURCESTOP alSourceStop = nullptr; OpenALDetail::LPALSOURCESTOPV alSourceStopv = nullptr; OpenALDetail::LPALSOURCEUNQUEUEBUFFERS alSourceUnqueueBuffers = nullptr; OpenALDetail::LPALSPEEDOFSOUND alSpeedOfSound = nullptr; // alc OpenALDetail::LPALCCAPTURECLOSEDEVICE alcCaptureCloseDevice = nullptr; OpenALDetail::LPALCCAPTUREOPENDEVICE alcCaptureOpenDevice = nullptr; OpenALDetail::LPALCCAPTURESAMPLES alcCaptureSamples = nullptr; OpenALDetail::LPALCCAPTURESTART alcCaptureStart = nullptr; OpenALDetail::LPALCCAPTURESTOP alcCaptureStop = nullptr; OpenALDetail::LPALCCLOSEDEVICE alcCloseDevice = nullptr; OpenALDetail::LPALCCREATECONTEXT alcCreateContext = nullptr; OpenALDetail::LPALCDESTROYCONTEXT alcDestroyContext = nullptr; OpenALDetail::LPALCGETCONTEXTSDEVICE alcGetContextsDevice = nullptr; OpenALDetail::LPALCGETCURRENTCONTEXT alcGetCurrentContext = nullptr; OpenALDetail::LPALCGETENUMVALUE alcGetEnumValue = nullptr; OpenALDetail::LPALCGETERROR alcGetError = nullptr; OpenALDetail::LPALCGETINTEGERV alcGetIntegerv = nullptr; OpenALDetail::LPALCGETPROCADDRESS alcGetProcAddress = nullptr; OpenALDetail::LPALCGETSTRING alcGetString = nullptr; OpenALDetail::LPALCISEXTENSIONPRESENT alcIsExtensionPresent = nullptr; OpenALDetail::LPALCMAKECONTEXTCURRENT alcMakeContextCurrent = nullptr; OpenALDetail::LPALCOPENDEVICE alcOpenDevice = nullptr; OpenALDetail::LPALCPROCESSCONTEXT alcProcessContext = nullptr; OpenALDetail::LPALCSUSPENDCONTEXT alcSuspendContext = nullptr; }