From 40ec2003b41eaf1351eb14ca9e8666d26bc1082e Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 21 Aug 2012 15:04:00 +0200 Subject: [PATCH] Added Audio module Fixed examples resources not being commited Temporary removed static build configurations --- .gitignore | 2 +- build/scripts/common.lua | 4 +- build/scripts/common_examples.lua | 14 +- build/scripts/module/audio.lua | 36 +++ examples/AnimatedMesh/build.lua | 2 +- examples/DopplerEffect/build.lua | 37 +++ examples/DopplerEffect/main.cpp | 68 +++++ examples/ListSequences/build.lua | 8 +- examples/bin/shaders/basic.frag | 10 + examples/bin/shaders/basic.vert | 14 + include/Nazara/Audio.hpp | 36 +++ include/Nazara/Audio/Audio.hpp | 58 ++++ include/Nazara/Audio/Config.hpp | 41 +++ include/Nazara/Audio/Debug.hpp | 11 + include/Nazara/Audio/DebugOff.hpp | 8 + include/Nazara/Audio/Enums.hpp | 32 +++ include/Nazara/Audio/Sound.hpp | 48 ++++ include/Nazara/Audio/SoundBuffer.hpp | 64 +++++ include/Nazara/Audio/SoundEmitter.hpp | 60 +++++ include/Nazara/Core/Initializer.hpp | 2 + include/Nazara/Core/Initializer.inl | 3 +- include/Nazara/Math/Basic.inl | 2 +- src/Nazara/Audio/Audio.cpp | 285 ++++++++++++++++++++ src/Nazara/Audio/Loaders/sndfile.hpp | 15 ++ src/Nazara/Audio/Loaders/sndfile/Loader.cpp | 135 ++++++++++ src/Nazara/Audio/Sound.cpp | 180 +++++++++++++ src/Nazara/Audio/SoundBuffer.cpp | 223 +++++++++++++++ src/Nazara/Audio/SoundEmitter.cpp | 156 +++++++++++ 28 files changed, 1541 insertions(+), 13 deletions(-) create mode 100644 build/scripts/module/audio.lua create mode 100644 examples/DopplerEffect/build.lua create mode 100644 examples/DopplerEffect/main.cpp create mode 100644 examples/bin/shaders/basic.frag create mode 100644 examples/bin/shaders/basic.vert create mode 100644 include/Nazara/Audio.hpp create mode 100644 include/Nazara/Audio/Audio.hpp create mode 100644 include/Nazara/Audio/Config.hpp create mode 100644 include/Nazara/Audio/Debug.hpp create mode 100644 include/Nazara/Audio/DebugOff.hpp create mode 100644 include/Nazara/Audio/Enums.hpp create mode 100644 include/Nazara/Audio/Sound.hpp create mode 100644 include/Nazara/Audio/SoundBuffer.hpp create mode 100644 include/Nazara/Audio/SoundEmitter.hpp create mode 100644 src/Nazara/Audio/Audio.cpp create mode 100644 src/Nazara/Audio/Loaders/sndfile.hpp create mode 100644 src/Nazara/Audio/Loaders/sndfile/Loader.cpp create mode 100644 src/Nazara/Audio/Sound.cpp create mode 100644 src/Nazara/Audio/SoundBuffer.cpp create mode 100644 src/Nazara/Audio/SoundEmitter.cpp diff --git a/.gitignore b/.gitignore index c8a3d8d30..05f2ebb62 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # Codeblocks *.cbp +*.cbTemp *.cscope_file_list *.depend *.layout @@ -126,7 +127,6 @@ publish *.Publish.xml # Others -[Bb]in [Oo]bj sql TestResults diff --git a/build/scripts/common.lua b/build/scripts/common.lua index faaa95654..f369473c4 100644 --- a/build/scripts/common.lua +++ b/build/scripts/common.lua @@ -1,8 +1,8 @@ -- Configuration générale configurations { - "DebugStatic", - "ReleaseStatic", +-- "DebugStatic", +-- "ReleaseStatic", "DebugDLL", "ReleaseDLL" } diff --git a/build/scripts/common_examples.lua b/build/scripts/common_examples.lua index 03b087a3d..fd00cf90c 100644 --- a/build/scripts/common_examples.lua +++ b/build/scripts/common_examples.lua @@ -1,8 +1,8 @@ -- Configuration générale configurations { - "DebugStatic", - "ReleaseStatic", +-- "DebugStatic", +-- "ReleaseStatic", "DebugDLL", "ReleaseDLL" } @@ -10,10 +10,18 @@ configurations language "C++" location("../examples/build/" .. _ACTION) +debugdir "../examples/bin" + includedirs "../include" -debugdir "../examples/bin" libdirs "../lib" + +if (_OPTIONS["x64"]) then + libdirs "../extlibs/lib/x64" +end + +libdirs "../extlibs/lib/x86" + targetdir "../examples/bin" configuration "Debug*" diff --git a/build/scripts/module/audio.lua b/build/scripts/module/audio.lua new file mode 100644 index 000000000..c46087c86 --- /dev/null +++ b/build/scripts/module/audio.lua @@ -0,0 +1,36 @@ +if (not _OPTIONS["one-library"]) then + project "NazaraAudio" +end + +files +{ + "../include/Nazara/Audio/**.hpp", + "../include/Nazara/Audio/**.inl", + "../src/Nazara/Audio/**.hpp", + "../src/Nazara/Audio/**.cpp" +} + +if (os.is("windows")) then + excludes { "../src/Nazara/Audio/Posix/*.hpp", "../src/Nazara/Audio/Posix/*.cpp" } + links "OpenAL32" + links "sndfile-1" +else + excludes { "../src/Nazara/Audio/Win32/*.hpp", "../src/Nazara/Audio/Win32/*.cpp" } + -- Link posix ? +end + +if (_OPTIONS["one-library"]) then + excludes "../src/Nazara/Audio/Debug/Leaks.cpp" +else + configuration "DebugStatic" + links "NazaraCore-s-d" + + configuration "ReleaseStatic" + links "NazaraCore-s" + + configuration "DebugDLL" + links "NazaraCore-d" + + configuration "ReleaseDLL" + links "NazaraCore" +end \ No newline at end of file diff --git a/examples/AnimatedMesh/build.lua b/examples/AnimatedMesh/build.lua index 7a0eae18e..a5d657395 100644 --- a/examples/AnimatedMesh/build.lua +++ b/examples/AnimatedMesh/build.lua @@ -27,8 +27,8 @@ else configuration "DebugDLL" links "NazaraRenderer-d" - links "NazaraCore-d" links "NazaraUtility-d" + links "NazaraCore-d" configuration "ReleaseDLL" links "NazaraRenderer" diff --git a/examples/DopplerEffect/build.lua b/examples/DopplerEffect/build.lua new file mode 100644 index 000000000..6e48bff00 --- /dev/null +++ b/examples/DopplerEffect/build.lua @@ -0,0 +1,37 @@ +kind "ConsoleApp" + +files "main.cpp" + +if (_OPTIONS["one-library"]) then + configuration "DebugStatic" + links "NazaraEngine-s-d" + + configuration "ReleaseStatic" + links "NazaraEngine-s" + + configuration "DebugDLL" + links "NazaraEngine-d" + + configuration "ReleaseDLL" + links "NazaraEngine" +else + configuration "DebugStatic" + links "NazaraAudio-s-d" + links "NazaraUtility-s-d" + links "NazaraCore-s-d" + + configuration "ReleaseStatic" + links "NazaraAudio-s" + links "NazaraUtility-s" + links "NazaraCore-s" + + configuration "DebugDLL" + links "NazaraAudio-d" + links "NazaraUtility-d" + links "NazaraCore-d" + + configuration "ReleaseDLL" + links "NazaraAudio" + links "NazaraUtility" + links "NazaraCore" +end diff --git a/examples/DopplerEffect/main.cpp b/examples/DopplerEffect/main.cpp new file mode 100644 index 000000000..b02b416c3 --- /dev/null +++ b/examples/DopplerEffect/main.cpp @@ -0,0 +1,68 @@ +#include +#include +#include // Thread::Sleep +#include +#include + +int main() +{ + // NzKeyboard ne nécessite pas l'initialisation d'Utility + NzInitializer audio; + if (!audio) + { + std::cout << "Failed to initialize audio module" << std::endl; + std::getchar(); + return 1; + } + + NzSound sound; + if (!sound.LoadFromFile("resources/siren.wav")) + { + std::cout << "Failed to load sound" << std::endl; + std::getchar(); + return 1; + } + + std::cout << "Demonstration de l'effet doppler avec Nazara" << std::endl; + std::cout << "Appuyez sur entree pour demarrer" << std::endl; + std::cout << "Appuyez sur echap pour arreter" << std::endl; + + std::getchar(); + + // On fait en sorte de répéter le son + sound.EnableLooping(true); + + // La source du son se situe en (50, 0, 5) + sound.SetPosition(50, 0, 5); + + // Et possède une vitesse de -10 par seconde sur l'axe X + sound.SetVelocity(-10, 0, 0); + + // On joue le son + sound.Play(); + + // La boucle du programme (Pour déplacer le son) + NzClock clock; + while (sound.GetStatus() == nzSoundStatus_Playing) + { + // Comme le son se joue dans un thread séparé, on peut mettre en pause celui-ci régulièrement + int sleepTime = 1000/60 - clock.GetMilliseconds(); // 60 FPS + + if (sleepTime > 0) + NzThread::Sleep(sleepTime); + + // On bouge la source du son en fonction du au temps depuis chaque mise à jour + NzVector3f pos = sound.GetPosition() + sound.GetVelocity()*clock.GetSeconds(); + sound.SetPosition(pos); + + std::cout << "Sound position: " << pos << std::endl; + + // Si la position de la source atteint une certaine position, ou si l'utilisateur appuie sur echap + if (pos.x < -50.f || NzKeyboard::IsKeyPressed(NzKeyboard::Escape)) + sound.Stop(); // On arrête le son (Stoppant également la boucle) + + clock.Restart(); + } + + return 0; +} diff --git a/examples/ListSequences/build.lua b/examples/ListSequences/build.lua index 9e90b1616..d43cb7d64 100644 --- a/examples/ListSequences/build.lua +++ b/examples/ListSequences/build.lua @@ -16,18 +16,18 @@ if (_OPTIONS["one-library"]) then links "NazaraEngine" else configuration "DebugStatic" - links "NazaraCore-s-d" links "NazaraUtility-s-d" + links "NazaraCore-s-d" configuration "ReleaseStatic" - links "NazaraCore-s" links "NazaraUtility-s" + links "NazaraCore-s" configuration "DebugDLL" - links "NazaraCore-d" links "NazaraUtility-d" + links "NazaraCore-d" configuration "ReleaseDLL" - links "NazaraCore" links "NazaraUtility" + links "NazaraCore" end diff --git a/examples/bin/shaders/basic.frag b/examples/bin/shaders/basic.frag new file mode 100644 index 000000000..e8a5f4c69 --- /dev/null +++ b/examples/bin/shaders/basic.frag @@ -0,0 +1,10 @@ +#version 110 + +varying vec2 TexCoord; + +uniform sampler2D texture; + +void main() +{ + gl_FragColor = texture2D(texture, TexCoord); +} diff --git a/examples/bin/shaders/basic.vert b/examples/bin/shaders/basic.vert new file mode 100644 index 000000000..3f332e560 --- /dev/null +++ b/examples/bin/shaders/basic.vert @@ -0,0 +1,14 @@ +#version 110 + +attribute vec3 Position; +attribute vec2 TexCoord0; + +uniform mat4 WorldViewProjMatrix; + +varying vec2 TexCoord; + +void main() +{ + gl_Position = WorldViewProjMatrix * vec4(Position, 1.0); + TexCoord = TexCoord0; +} diff --git a/include/Nazara/Audio.hpp b/include/Nazara/Audio.hpp new file mode 100644 index 000000000..1cc185a95 --- /dev/null +++ b/include/Nazara/Audio.hpp @@ -0,0 +1,36 @@ +// This file was automatically generated by Nazara + +/* + Nazara Engine - Audio module + + Copyright (C) 2012 Jérôme "Lynix" Leclercq (Lynix680@gmail.com) + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished to do + so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/include/Nazara/Audio/Audio.hpp b/include/Nazara/Audio/Audio.hpp new file mode 100644 index 000000000..adffcc110 --- /dev/null +++ b/include/Nazara/Audio/Audio.hpp @@ -0,0 +1,58 @@ +// Copyright (C) 2012 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 + +#pragma once + +#ifndef NAZARA_AUDIO_HPP +#define NAZARA_AUDIO_HPP + +#include +#include +#include +#include +#include + +class NAZARA_API NzAudio +{ + friend class NzMusic; + friend class NzSoundBuffer; + + public: + NzAudio() = delete; + ~NzAudio() = delete; + + static nzAudioFormat GetAudioFormat(unsigned int channelCount); + static float GetDopplerFactor(); + static float GetGlobalVolume(); + static NzVector3f GetListenerDirection(); + static NzVector3f GetListenerPosition(); + //static NzQuaternionf GetListenerRotation(); + static NzVector3f GetListenerVelocity(); + static float GetSpeedOfSound(); + + static bool Initialize(); + + static bool IsFormatSupported(nzAudioFormat format); + static bool IsInitialized(); + + static void SetDopplerFactor(float dopplerFactor); + static void SetGlobalVolume(float volume); + static void SetListenerDirection(const NzVector3f& direction); + static void SetListenerDirection(float dirX, float dirY, float dirZ); + static void SetListenerPosition(const NzVector3f& position); + static void SetListenerPosition(float x, float y, float z); + //static void SetListenerRotation(const NzQuaternionf& rotation); + static void SetListenerVelocity(const NzVector3f& velocity); + static void SetListenerVelocity(float velX, float velY, float velZ); + static void SetSpeedOfSound(float speed); + + static void Uninitialize(); + + private: + static unsigned int GetOpenALFormat(nzAudioFormat format); + + static unsigned int s_moduleReferenceCouter; +}; + +#endif // NAZARA_AUDIO_HPP diff --git a/include/Nazara/Audio/Config.hpp b/include/Nazara/Audio/Config.hpp new file mode 100644 index 000000000..e3b2bcd3e --- /dev/null +++ b/include/Nazara/Audio/Config.hpp @@ -0,0 +1,41 @@ +/* + Nazara Engine - Audio module + + Copyright (C) 2012 Jérôme "Lynix" Leclercq (Lynix680@gmail.com) + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished to do + so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +#pragma once + +#ifndef NAZARA_CONFIG_AUDIO_HPP +#define NAZARA_CONFIG_AUDIO_HPP + +/// Chaque modification d'un paramètre du module nécessite une recompilation de celui-ci + +// Utilise un tracker pour repérer les éventuels leaks (Ralentit l'exécution) +#define NAZARA_AUDIO_MEMORYLEAKTRACKER 0 + +// Active les tests de sécurité basés sur le code (Conseillé pour le développement) +#define NAZARA_AUDIO_SAFE 1 + +// Le nombre de buffers utilisés lors du streaming d'objets audio (Au moins deux) +#define NAZARA_AUDIO_STREAMEDBUFFERCOUNT 2 + +#endif // NAZARA_CONFIG_AUDIO_HPP diff --git a/include/Nazara/Audio/Debug.hpp b/include/Nazara/Audio/Debug.hpp new file mode 100644 index 000000000..3db3dcd92 --- /dev/null +++ b/include/Nazara/Audio/Debug.hpp @@ -0,0 +1,11 @@ +// Copyright (C) 2012 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 +#if NAZARA_AUDIO_MEMORYLEAKTRACKER || defined(NAZARA_DEBUG) + #include + + #define delete NzMemoryManager::NextFree(__FILE__, __LINE__), delete + #define new new(__FILE__, __LINE__) +#endif diff --git a/include/Nazara/Audio/DebugOff.hpp b/include/Nazara/Audio/DebugOff.hpp new file mode 100644 index 000000000..13ff944c7 --- /dev/null +++ b/include/Nazara/Audio/DebugOff.hpp @@ -0,0 +1,8 @@ +// Copyright (C) 2012 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 + +#if NAZARA_AUDIO_MEMORYLEAKTRACKER || defined(NAZARA_DEBUG) + #undef delete + #undef new +#endif diff --git a/include/Nazara/Audio/Enums.hpp b/include/Nazara/Audio/Enums.hpp new file mode 100644 index 000000000..70729d19d --- /dev/null +++ b/include/Nazara/Audio/Enums.hpp @@ -0,0 +1,32 @@ +// Copyright (C) 2012 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 + +#pragma once + +#ifndef NAZARA_ENUMS_HPP +#define NAZARA_ENUMS_HPP + +enum nzAudioFormat +{ + nzAudioFormat_Unknown = -1, + + // La valeur entière est le nombre de canaux possédés par ce format + nzAudioFormat_Mono = 1, + nzAudioFormat_Stereo = 2, + nzAudioFormat_Quad = 4, + nzAudioFormat_5_1 = 6, + nzAudioFormat_6_1 = 7, + nzAudioFormat_7_1 = 8, + + nzAudioFormat_Max = nzAudioFormat_7_1 +}; + +enum nzSoundStatus +{ + nzSoundStatus_Playing, + nzSoundStatus_Paused, + nzSoundStatus_Stopped +}; + +#endif // NAZARA_ENUMS_HPP diff --git a/include/Nazara/Audio/Sound.hpp b/include/Nazara/Audio/Sound.hpp new file mode 100644 index 000000000..1b2ac77e6 --- /dev/null +++ b/include/Nazara/Audio/Sound.hpp @@ -0,0 +1,48 @@ +// Copyright (C) 2012 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 + +#pragma once + +#ifndef NAZARA_SOUND_HPP +#define NAZARA_SOUND_HPP + +#include +#include +#include +#include + +class NAZARA_API NzSound : public NzSoundEmitter +{ + public: + NzSound() = default; + NzSound(const NzSoundBuffer* soundBuffer); + NzSound(const NzSound& sound); + ~NzSound(); + + void EnableLooping(bool loop); + + const NzSoundBuffer* GetBuffer() const; + nzUInt32 GetDuration() const; + nzUInt32 GetPlayingOffset() const; + nzSoundStatus GetStatus() const; + + bool IsLooping() const; + + bool LoadFromFile(const NzString& filePath, const NzSoundBufferParams& params = NzSoundBufferParams()); + bool LoadFromMemory(const void* data, std::size_t size, const NzSoundBufferParams& params = NzSoundBufferParams()); + bool LoadFromStream(NzInputStream& stream, const NzSoundBufferParams& params = NzSoundBufferParams()); + + void Pause(); + bool Play(); + + void SetBuffer(const NzSoundBuffer* buffer); + void SetPlayingOffset(nzUInt32 offset); + + void Stop(); + + private: + const NzSoundBuffer* m_buffer = nullptr; +}; + +#endif // NAZARA_SOUND_HPP diff --git a/include/Nazara/Audio/SoundBuffer.hpp b/include/Nazara/Audio/SoundBuffer.hpp new file mode 100644 index 000000000..71b69e173 --- /dev/null +++ b/include/Nazara/Audio/SoundBuffer.hpp @@ -0,0 +1,64 @@ +// Copyright (C) 2012 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 + +#pragma once + +#ifndef NAZARA_SOUNDBUFFER_HPP +#define NAZARA_SOUNDBUFFER_HPP + +#include +#include +#include +#include +#include +#include + +struct NzSoundBufferParams +{ + bool IsValid() const; +}; + +class NzSound; +class NzSoundBuffer; + +using NzSoundBufferLoader = NzResourceLoader; + +struct NzSoundBufferImpl; + +class NAZARA_API NzSoundBuffer : public NzResource, public NzNonCopyable +{ + friend NzSound; + friend NzSoundBufferLoader; + + public: + NzSoundBuffer() = default; + NzSoundBuffer(nzAudioFormat format, unsigned int sampleCount, unsigned int sampleRate, const nzInt16* samples); + ~NzSoundBuffer(); + + bool Create(nzAudioFormat format, unsigned int sampleCount, unsigned int sampleRate, const nzInt16* samples); + void Destroy(); + + nzUInt32 GetDuration() const; + nzAudioFormat GetFormat() const; + const nzInt16* GetSamples() const; + unsigned int GetSampleCount() const; + unsigned int GetSampleRate() const; + + bool IsValid() const; + + bool LoadFromFile(const NzString& filePath, const NzSoundBufferParams& params = NzSoundBufferParams()); + bool LoadFromMemory(const void* data, std::size_t size, const NzSoundBufferParams& params = NzSoundBufferParams()); + bool LoadFromStream(NzInputStream& stream, const NzSoundBufferParams& params = NzSoundBufferParams()); + + static bool IsFormatSupported(nzAudioFormat format); + + private: + unsigned int GetOpenALBuffer() const; + + NzSoundBufferImpl* m_impl = nullptr; + + static NzSoundBufferLoader::LoaderList s_loaders; +}; + +#endif // NAZARA_SOUNDBUFFER_HPP diff --git a/include/Nazara/Audio/SoundEmitter.hpp b/include/Nazara/Audio/SoundEmitter.hpp new file mode 100644 index 000000000..7d4d41d6a --- /dev/null +++ b/include/Nazara/Audio/SoundEmitter.hpp @@ -0,0 +1,60 @@ +// Copyright (C) 2012 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 + +#pragma once + +#ifndef NAZARA_SOUNDEMITTER_HPP +#define NAZARA_SOUNDEMITTER_HPP + +#include +#include +#include +#include +#include + +class NAZARA_API NzSoundEmitter +{ + public: + virtual ~NzSoundEmitter(); + + virtual void EnableLooping(bool loop) = 0; + void EnableSpatialization(bool spatialization); + + float GetAttenuation() const; + virtual nzUInt32 GetDuration() const = 0; + float GetMinDistance() const; + float GetPitch() const; + virtual nzUInt32 GetPlayingOffset() const = 0; + NzVector3f GetPosition() const; + NzVector3f GetVelocity() const; + virtual nzSoundStatus GetStatus() const = 0; + float GetVolume() const; + + virtual bool IsLooping() const = 0; + bool IsSpatialized() const; + + virtual void Pause() = 0; + virtual bool Play() = 0; + + void SetAttenuation(float attenuation); + void SetMinDistance(float minDistance); + void SetPitch(float pitch); + void SetPosition(const NzVector3f& position); + void SetPosition(float x, float y, float z); + void SetVelocity(const NzVector3f& velocity); + void SetVelocity(float velX, float velY, float velZ); + void SetVolume(float volume); + + virtual void Stop() = 0; + + protected: + NzSoundEmitter(); + NzSoundEmitter(const NzSoundEmitter& emitter); + + nzSoundStatus GetInternalStatus() const; + + unsigned int m_source; +}; + +#endif // NAZARA_SOUNDEMITTER_HPP diff --git a/include/Nazara/Core/Initializer.hpp b/include/Nazara/Core/Initializer.hpp index 66108a7a9..e6b04d462 100644 --- a/include/Nazara/Core/Initializer.hpp +++ b/include/Nazara/Core/Initializer.hpp @@ -7,6 +7,8 @@ #ifndef NAZARA_INITIALIZER_HPP #define NAZARA_INITIALIZER_HPP +///TODO: Utiliser les variadic template pour initialiser plusieurs modules à la fois ? + #include template diff --git a/include/Nazara/Core/Initializer.inl b/include/Nazara/Core/Initializer.inl index 2f814517d..4c031418d 100644 --- a/include/Nazara/Core/Initializer.inl +++ b/include/Nazara/Core/Initializer.inl @@ -17,7 +17,8 @@ NzInitializer::NzInitializer(Args... args) template NzInitializer::~NzInitializer() { - T::Uninitialize(); + if (T::IsInitialized()) + T::Uninitialize(); } template diff --git a/include/Nazara/Math/Basic.inl b/include/Nazara/Math/Basic.inl index 92f17ddd2..875ca00f8 100644 --- a/include/Nazara/Math/Basic.inl +++ b/include/Nazara/Math/Basic.inl @@ -193,7 +193,7 @@ T NzNormalizeAngle(T angle) template bool NzNumberEquals(T a, T b) { - return std::fabs(a-b) <= std::numeric_limits::epsilon(); + return std::fabs(a-b) < std::numeric_limits::epsilon(); } NzString NzNumberToString(long long number, nzUInt8 radix) diff --git a/src/Nazara/Audio/Audio.cpp b/src/Nazara/Audio/Audio.cpp new file mode 100644 index 000000000..eb5aaa0e6 --- /dev/null +++ b/src/Nazara/Audio/Audio.cpp @@ -0,0 +1,285 @@ +// Copyright (C) 2012 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 +#include +#include + +namespace +{ + ALenum formats[nzAudioFormat_Max+1] = {0}; + ALCdevice* device = nullptr; + ALCcontext* context = nullptr; +} + +nzAudioFormat NzAudio::GetAudioFormat(unsigned int channelCount) +{ + switch (channelCount) + { + case 1: + case 2: + case 4: + case 6: + case 7: + case 8: + return static_cast(channelCount); + + default: + NazaraError("Invalid channel count: " + NzString::Number(channelCount)); + return nzAudioFormat_Unknown; + } +} + +float NzAudio::GetDopplerFactor() +{ + return alGetFloat(AL_DOPPLER_FACTOR); +} + +float NzAudio::GetGlobalVolume() +{ + ALfloat gain = 0.f; + alGetListenerf(AL_GAIN, &gain); + + return gain*100.f; +} + +NzVector3f NzAudio::GetListenerDirection() +{ + ALfloat orientation[6]; + alGetListenerfv(AL_ORIENTATION, orientation); + + return NzVector3f(orientation[0], orientation[1], orientation[2]); +} + +NzVector3f NzAudio::GetListenerPosition() +{ + NzVector3f position; + alGetListenerfv(AL_POSITION, position); + + return position; +} +/* +NzQuaternionf NzAudio::GetListenerRotation() +{ + // http://stackoverflow.com/questions/1171849/finding-quaternion-representing-the-rotation-from-one-vector-to-another + float orientation[6]; + alGetListenerfv(AL_ORIENTATION, orientation); + + NzVector3f forward(orientation[0], orientation[1], orientation[2]); + NzVector3f up(orientation[3], orientation[4], orientation[5]); + + NzQuaternionf rotation; + NzVector3f a = NzVector3f::CrossProduct(forward, up); + rotation.x = a.x; + rotation.y = a.y; + rotation.z = a.z; + rotation.w = std::sqrt(forward.SquaredLength() * up.SquaredLength()) + NzVector3f::DotProduct(forward, up); + + return rotation; +} +*/ +NzVector3f NzAudio::GetListenerVelocity() +{ + NzVector3f velocity; + alGetListenerfv(AL_VELOCITY, velocity); + + return velocity; +} + +float NzAudio::GetSpeedOfSound() +{ + return alGetFloat(AL_SPEED_OF_SOUND); +} + +bool NzAudio::Initialize() +{ + if (s_moduleReferenceCouter++ != 0) + return true; // Déjà initialisé + + // Initialisation des dépendances + if (!NzCore::Initialize()) + { + NazaraError("Failed to initialize core module"); + return false; + } + + // Initialisation du module + device = alcOpenDevice(nullptr); // On choisit le device par défaut + if (!device) + { + NazaraError("Failed to open default device"); + return false; + } + + // Un seul contexte nous suffira + context = alcCreateContext(device, nullptr); + if (!context) + { + NazaraError("Failed to create context"); + + alcCloseDevice(device); + return false; + } + + if (!alcMakeContextCurrent(context)) + { + NazaraError("Failed to activate context"); + + alcDestroyContext(context); + alcCloseDevice(device); + return false; + } + + // Définition de l'orientation + /*{ + NzVector3f forward = NzVector3f::Forward(); + NzVector3f up = NzVector3f::Up(); + + ALfloat orientation[6] = + { + forward.x, forward.y, forward.z, + up.x, up.y, up.z + }; + + alListenerfv(AL_ORIENTATION, orientation); + }*/ + + formats[nzAudioFormat_Mono] = AL_FORMAT_MONO16; + formats[nzAudioFormat_Stereo] = AL_FORMAT_STEREO16; + formats[nzAudioFormat_Quad] = alGetEnumValue("AL_FORMAT_QUAD16"); + formats[nzAudioFormat_5_1] = alGetEnumValue("AL_FORMAT_51CHN16"); + formats[nzAudioFormat_6_1] = alGetEnumValue("AL_FORMAT_61CHN16"); + formats[nzAudioFormat_7_1] = alGetEnumValue("AL_FORMAT_71CHN16"); + + NzLoaders_sndfile_Register(); + + NazaraNotice("Initialized: Audio module"); + + return true; +} + +bool NzAudio::IsFormatSupported(nzAudioFormat format) +{ + if (format == nzAudioFormat_Unknown) + return false; + + return formats[format] != 0; +} + +bool NzAudio::IsInitialized() +{ + return s_moduleReferenceCouter != 0; +} + +void NzAudio::SetDopplerFactor(float dopplerFactor) +{ + alDopplerFactor(dopplerFactor); +} + +void NzAudio::SetGlobalVolume(float volume) +{ + alListenerf(AL_GAIN, volume*0.01f); +} + +void NzAudio::SetListenerDirection(const NzVector3f& direction) +{ + ALfloat orientation[6] = + { + direction.x, direction.y, direction.z, + 0.f, 1.f, 0.f + }; + + alListenerfv(AL_ORIENTATION, orientation); +} + +void NzAudio::SetListenerDirection(float dirX, float dirY, float dirZ) +{ + ALfloat orientation[6] = + { + dirX, dirY, dirZ, + 0.f, 1.f, 0.f + }; + + alListenerfv(AL_ORIENTATION, orientation); +} + +void NzAudio::SetListenerPosition(const NzVector3f& position) +{ + alListenerfv(AL_POSITION, position); +} + +void NzAudio::SetListenerPosition(float x, float y, float z) +{ + alListener3f(AL_POSITION, x, y, z); +} +/* +void NzAudio::SetListenerRotation(const NzQuaternionf& rotation) +{ + NzVector3f forward = rotation * NzVector3f::Forward(); + NzVector3f up = NzVector3f::Up(); + + ALfloat orientation[6] = + { + forward.x, forward.y, forward.z, + up.x, up.y, up.z + }; + + alListenerfv(AL_ORIENTATION, orientation); +} +*/ +void NzAudio::SetListenerVelocity(const NzVector3f& velocity) +{ + alListenerfv(AL_VELOCITY, velocity); +} + +void NzAudio::SetListenerVelocity(float velX, float velY, float velZ) +{ + alListener3f(AL_VELOCITY, velX, velY, velZ); +} + +void NzAudio::SetSpeedOfSound(float speed) +{ + alSpeedOfSound(speed); +} + +void NzAudio::Uninitialize() +{ + if (--s_moduleReferenceCouter != 0) + return; // Encore utilisé + + // Libération du module + alcMakeContextCurrent(nullptr); + alcDestroyContext(context); + + if (!alcCloseDevice(device)) + // Nous n'avons pas pu fermer le device, ce qui signifie qu'il est en cours d'utilisation + NazaraWarning("Failed to close device"); + + NazaraNotice("Uninitialized: Audio module"); + + // Libération des dépendances + NzCore::Uninitialize(); +} + +unsigned int NzAudio::GetOpenALFormat(nzAudioFormat format) +{ + #ifdef NAZARA_DEBUG + if (format == nzAudioFormat_Unknown) + { + NazaraInternalError("Invalid audio format"); + return 0; + } + #endif + + return formats[format]; +} + +unsigned int NzAudio::s_moduleReferenceCouter = 0; diff --git a/src/Nazara/Audio/Loaders/sndfile.hpp b/src/Nazara/Audio/Loaders/sndfile.hpp new file mode 100644 index 000000000..73532fb87 --- /dev/null +++ b/src/Nazara/Audio/Loaders/sndfile.hpp @@ -0,0 +1,15 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_LOADERS_SNDFILE_HPP +#define NAZARA_LOADERS_SNDFILE_HPP + +#include + +void NzLoaders_sndfile_Register(); +void NzLoaders_sndfile_Unregister(); + +#endif // NAZARA_LOADERS_SNDFILE_HPP diff --git a/src/Nazara/Audio/Loaders/sndfile/Loader.cpp b/src/Nazara/Audio/Loaders/sndfile/Loader.cpp new file mode 100644 index 000000000..3e0c73c51 --- /dev/null +++ b/src/Nazara/Audio/Loaders/sndfile/Loader.cpp @@ -0,0 +1,135 @@ +// Copyright (C) 2012 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 +#include +#include + +namespace +{ + sf_count_t GetSize(void* user_data) + { + NzInputStream* stream = reinterpret_cast(user_data); + return stream->GetSize(); + } + + sf_count_t Read(void* ptr, sf_count_t count, void* user_data) + { + NzInputStream* stream = reinterpret_cast(user_data); + return stream->Read(ptr, count); + } + + sf_count_t Seek(sf_count_t offset, int whence, void* user_data) + { + NzInputStream* stream = reinterpret_cast(user_data); + switch (whence) + { + case SEEK_CUR: + stream->Read(nullptr, offset); + break; + + case SEEK_END: + stream->SetCursorPos(stream->GetSize()+offset); + break; + + case SEEK_SET: + stream->SetCursorPos(offset); + break; + + default: + NazaraInternalError("Seek mode not handled"); + } + + return stream->GetCursorPos(); + } + + sf_count_t Tell(void* user_data) + { + NzInputStream* stream = reinterpret_cast(user_data); + return stream->GetCursorPos(); + } + + static SF_VIRTUAL_IO callbacks = {GetSize, Seek, Read, nullptr, Tell}; + + bool NzLoader_sndfile_Check(NzInputStream& stream, const NzSoundBufferParams& parameters) + { + NazaraUnused(parameters); + + SF_INFO info; + SNDFILE* file = sf_open_virtual(&callbacks, SFM_READ, &info, &stream); + if (file) + { + sf_close(file); + return true; + } + else + return false; + } + + bool NzLoader_sndfile_Load(NzSoundBuffer* soundBuffer, NzInputStream& stream, const NzSoundBufferParams& parameters) + { + NazaraUnused(parameters); + + SF_INFO infos; + SNDFILE* file = sf_open_virtual(&callbacks, SFM_READ, &infos, &stream); + if (!file) + { + NazaraError("Failed to load sound file: " + NzString(sf_strerror(file))); + return false; + } + + nzAudioFormat format = NzAudio::GetAudioFormat(infos.channels); + if (format == nzAudioFormat_Unknown) + { + NazaraError("Channel count not handled"); + sf_close(file); + + return false; + } + + unsigned int sampleCount = infos.frames*infos.channels; + nzInt16* samples = new nzInt16[sampleCount]; + if (sf_read_short(file, samples, sampleCount) != sampleCount) + { + NazaraError("Failed to read samples"); + delete[] samples; + sf_close(file); + + return false; + } + + if (!soundBuffer->Create(format, infos.frames*infos.channels, infos.samplerate, samples)) + { + NazaraError("Failed to create sound buffer"); + sf_close(file); + + return false; + } + + delete[] samples; + + return true; + } +} + +void NzLoaders_sndfile_Register() +{ + NzSoundBufferLoader::RegisterLoader("aiff,au,avr,caf,flac,htk,ircam,mat4,mat5,mpc2k,nist,ogg,paf,pvf,raw,rf64,sd2,sds,svx,voc,w64,wav,wve", + NzLoader_sndfile_Check, + NzLoader_sndfile_Load); +} + +void NzLoaders_sndfile_Unregister() +{ + NzSoundBufferLoader::UnregisterLoader("aiff,au,avr,caf,flac,htk,ircam,mat4,mat5,mpc2k,nist,ogg,paf,pvf,raw,rf64,sd2,sds,svx,voc,w64,wav,wve", + NzLoader_sndfile_Check, + NzLoader_sndfile_Load); +} diff --git a/src/Nazara/Audio/Sound.cpp b/src/Nazara/Audio/Sound.cpp new file mode 100644 index 000000000..9f21e3b57 --- /dev/null +++ b/src/Nazara/Audio/Sound.cpp @@ -0,0 +1,180 @@ +// Copyright (C) 2012 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 + +NzSound::NzSound(const NzSoundBuffer* soundBuffer) +{ + SetBuffer(soundBuffer); +} + +NzSound::NzSound(const NzSound& sound) : +NzSoundEmitter(sound) +{ + SetBuffer(sound.m_buffer); +} + +NzSound::~NzSound() +{ + Stop(); + + if (m_buffer) + m_buffer->RemoveResourceReference(); +} + +void NzSound::EnableLooping(bool loop) +{ + alSourcei(m_source, AL_LOOPING, loop); +} + +const NzSoundBuffer* NzSound::GetBuffer() const +{ + return m_buffer; +} + +nzUInt32 NzSound::GetDuration() const +{ + #if NAZARA_AUDIO_SAFE + if (!m_buffer) + { + NazaraError("No sound buffer"); + return 0; + } + #endif + + return m_buffer->GetDuration(); +} + +nzUInt32 NzSound::GetPlayingOffset() const +{ + ALfloat seconds = -1.f; + alGetSourcef(m_source, AL_SEC_OFFSET, &seconds); + + return static_cast(seconds*1000); +} + +nzSoundStatus NzSound::GetStatus() const +{ + return GetInternalStatus(); +} + +bool NzSound::IsLooping() const +{ + ALint loop; + alGetSourcei(m_source, AL_LOOPING, &loop); + + return loop != AL_FALSE; +} + +bool NzSound::LoadFromFile(const NzString& filePath, const NzSoundBufferParams& params) +{ + NzSoundBuffer* buffer = new NzSoundBuffer; + if (!buffer->LoadFromFile(filePath, params)) + { + NazaraError("Failed to load buffer from file (" + filePath + ')'); + delete buffer; + + return false; + } + + SetBuffer(buffer); + + buffer->SetPersistent(false); + + return true; +} + +bool NzSound::LoadFromMemory(const void* data, std::size_t size, const NzSoundBufferParams& params) +{ + NzSoundBuffer* buffer = new NzSoundBuffer; + if (!buffer->LoadFromMemory(data, size, params)) + { + NazaraError("Failed to load buffer from memory (" + NzString::Pointer(data) + ')'); + delete buffer; + + return false; + } + + SetBuffer(buffer); + + buffer->SetPersistent(false); + + return true; +} + +bool NzSound::LoadFromStream(NzInputStream& stream, const NzSoundBufferParams& params) +{ + NzSoundBuffer* buffer = new NzSoundBuffer; + if (!buffer->LoadFromStream(stream, params)) + { + NazaraError("Failed to load buffer from stream"); + delete buffer; + + return false; + } + + SetBuffer(buffer); + + buffer->SetPersistent(false); + + return true; +} + +void NzSound::Pause() +{ + alSourcePause(m_source); +} + +bool NzSound::Play() +{ + #if NAZARA_AUDIO_SAFE + if (!m_buffer) + { + NazaraError("No sound buffer to play"); + return false; + } + #endif + + alSourcePlay(m_source); + + return true; +} + +void NzSound::SetBuffer(const NzSoundBuffer* buffer) +{ + if (m_buffer == buffer) + return; + + Stop(); + + if (m_buffer) + m_buffer->RemoveResourceReference(); + + m_buffer = buffer; + + if (m_buffer) + { + m_buffer->AddResourceReference(); + alSourcei(m_source, AL_BUFFER, m_buffer->GetOpenALBuffer()); + } + else + alSourcei(m_source, AL_BUFFER, AL_NONE); +} + +void NzSound::SetPlayingOffset(nzUInt32 offset) +{ + alSourcef(m_source, AL_SEC_OFFSET, offset/1000.f); +} + +void NzSound::Stop() +{ + alSourceStop(m_source); +} diff --git a/src/Nazara/Audio/SoundBuffer.cpp b/src/Nazara/Audio/SoundBuffer.cpp new file mode 100644 index 000000000..6c5bdd1ac --- /dev/null +++ b/src/Nazara/Audio/SoundBuffer.cpp @@ -0,0 +1,223 @@ +// Copyright (C) 2012 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 + +///FIXME: Adapter la création + +bool NzSoundBufferParams::IsValid() const +{ + return true; +} + +struct NzSoundBufferImpl +{ + ALuint buffer; + nzAudioFormat format; + nzUInt32 duration; + nzInt16* samples; + unsigned int sampleCount; + unsigned int sampleRate; +}; + +NzSoundBuffer::NzSoundBuffer(nzAudioFormat format, unsigned int sampleCount, unsigned int sampleRate, const nzInt16* samples) +{ + Create(format, sampleCount, sampleRate, samples); + + #ifdef NAZARA_DEBUG + if (!m_impl) + { + NazaraError("Failed to create sound buffer"); + throw std::runtime_error("Constructor failed"); + } + #endif +} + +NzSoundBuffer::~NzSoundBuffer() +{ + Destroy(); +} + +bool NzSoundBuffer::Create(nzAudioFormat format, unsigned int sampleCount, unsigned int sampleRate, const nzInt16* samples) +{ + Destroy(); + + if (sampleCount == 0) + return true; + + #if NAZARA_AUDIO_SAFE + if (!IsFormatSupported(format)) + { + NazaraError("Audio format is not supported"); + return false; + } + + if (sampleRate == 0) + { + NazaraError("Sample rate must be different from zero"); + return false; + } + + if (!samples) + { + NazaraError("Invalid sample source"); + return false; + } + #endif + + // On vide le stack d'erreurs + while (alGetError() != AL_NO_ERROR); + + ALuint buffer; + alGenBuffers(1, &buffer); + + if (alGetError() != AL_NO_ERROR) + { + NazaraError("Failed to create OpenAL buffer"); + return false; + } + + alBufferData(buffer, NzAudio::GetOpenALFormat(format), samples, sampleCount*sizeof(nzInt16), sampleRate); + + if (alGetError() != AL_NO_ERROR) + { + NazaraError("Failed to set OpenAL buffer"); + alDeleteBuffers(1, &buffer); + + return false; + } + + m_impl = new NzSoundBufferImpl; + m_impl->buffer = buffer; + m_impl->duration = 1000 * (sampleCount / (format * sampleRate)); + m_impl->format = format; + m_impl->sampleCount = sampleCount; + m_impl->sampleRate = sampleRate; + m_impl->samples = new nzInt16[sampleCount]; + std::memcpy(&m_impl->samples[0], samples, sampleCount*sizeof(nzInt16)); + + return true; +} + +void NzSoundBuffer::Destroy() +{ + if (m_impl) + { + delete[] m_impl->samples; + delete m_impl; + m_impl = nullptr; + } +} + +nzUInt32 NzSoundBuffer::GetDuration() const +{ + #if NAZARA_AUDIO_SAFE + if (!m_impl) + { + NazaraError("Sound buffer not created"); + return 0; + } + #endif + + return m_impl->duration; +} + +nzAudioFormat NzSoundBuffer::GetFormat() const +{ + #if NAZARA_AUDIO_SAFE + if (!m_impl) + { + NazaraError("Sound buffer not created"); + return nzAudioFormat_Unknown; + } + #endif + + return m_impl->format; +} + +const nzInt16* NzSoundBuffer::GetSamples() const +{ + #if NAZARA_AUDIO_SAFE + if (!m_impl) + { + NazaraError("Sound buffer not created"); + return nullptr; + } + #endif + + return m_impl->samples; +} + +unsigned int NzSoundBuffer::GetSampleCount() const +{ + #if NAZARA_AUDIO_SAFE + if (!m_impl) + { + NazaraError("Sound buffer not created"); + return 0; + } + #endif + + return m_impl->sampleCount; +} + +unsigned int NzSoundBuffer::GetSampleRate() const +{ + #if NAZARA_AUDIO_SAFE + if (!m_impl) + { + NazaraError("Sound buffer not created"); + return 0; + } + #endif + + return m_impl->sampleRate; +} + +bool NzSoundBuffer::IsValid() const +{ + return m_impl != nullptr; +} + +bool NzSoundBuffer::LoadFromFile(const NzString& filePath, const NzSoundBufferParams& params) +{ + return NzSoundBufferLoader::LoadFromFile(this, filePath, params); +} + +bool NzSoundBuffer::LoadFromMemory(const void* data, std::size_t size, const NzSoundBufferParams& params) +{ + return NzSoundBufferLoader::LoadFromMemory(this, data, size, params); +} + +bool NzSoundBuffer::LoadFromStream(NzInputStream& stream, const NzSoundBufferParams& params) +{ + return NzSoundBufferLoader::LoadFromStream(this, stream, params); +} + +bool NzSoundBuffer::IsFormatSupported(nzAudioFormat format) +{ + return NzAudio::IsFormatSupported(format); +} + +unsigned int NzSoundBuffer::GetOpenALBuffer() const +{ + #ifdef NAZARA_DEBUG + if (!m_impl) + { + NazaraInternalError("Sound buffer not created"); + return AL_NONE; + } + #endif + + return m_impl->buffer; +} + +NzSoundBufferLoader::LoaderList NzSoundBuffer::s_loaders; diff --git a/src/Nazara/Audio/SoundEmitter.cpp b/src/Nazara/Audio/SoundEmitter.cpp new file mode 100644 index 000000000..5ce197f47 --- /dev/null +++ b/src/Nazara/Audio/SoundEmitter.cpp @@ -0,0 +1,156 @@ +// Copyright (C) 2012 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 + +// http://connect.creativelabs.com/openal/Documentation/OpenAL_Programmers_Guide.pdf + +#include +#include +#include +#include + +NzSoundEmitter::NzSoundEmitter() +{ + alGenSources(1, &m_source); +} + +NzSoundEmitter::NzSoundEmitter(const NzSoundEmitter& emitter) +{ + alGenSources(1, &m_source); + + SetAttenuation(emitter.GetAttenuation()); + SetMinDistance(emitter.GetMinDistance()); + SetPitch(emitter.GetPitch()); + // Pas de copie de position ou de vitesse + SetVolume(emitter.GetVolume()); +} + +NzSoundEmitter::~NzSoundEmitter() +{ + alDeleteSources(1, &m_source); +} + +void NzSoundEmitter::EnableSpatialization(bool spatialization) +{ + alSourcei(m_source, AL_SOURCE_RELATIVE, spatialization); +} + +float NzSoundEmitter::GetAttenuation() const +{ + ALfloat attenuation; + alGetSourcef(m_source, AL_ROLLOFF_FACTOR, &attenuation); + + return attenuation; +} + +float NzSoundEmitter::GetMinDistance() const +{ + ALfloat distance; + alGetSourcef(m_source, AL_REFERENCE_DISTANCE, &distance); + + return distance; +} + +float NzSoundEmitter::GetPitch() const +{ + ALfloat pitch; + alGetSourcef(m_source, AL_PITCH, &pitch); + + return pitch; +} + +NzVector3f NzSoundEmitter::GetPosition() const +{ + NzVector3f position; + alGetSourcefv(m_source, AL_POSITION, position); + + return position; +} + +NzVector3f NzSoundEmitter::GetVelocity() const +{ + NzVector3f velocity; + alGetSourcefv(m_source, AL_VELOCITY, velocity); + + return velocity; +} + +float NzSoundEmitter::GetVolume() const +{ + ALfloat gain; + alGetSourcef(m_source, AL_GAIN, &gain); + + return gain * 100.f; +} + +bool NzSoundEmitter::IsSpatialized() const +{ + ALint relative; + alGetSourcei(m_source, AL_SOURCE_RELATIVE, &relative); + + return relative != AL_FALSE; +} + +void NzSoundEmitter::SetAttenuation(float attenuation) +{ + alSourcef(m_source, AL_ROLLOFF_FACTOR, attenuation); +} + +void NzSoundEmitter::SetMinDistance(float minDistance) +{ + alSourcef(m_source, AL_REFERENCE_DISTANCE, minDistance); +} + +void NzSoundEmitter::SetPitch(float pitch) +{ + alSourcef(m_source, AL_PITCH, pitch); +} + +void NzSoundEmitter::SetPosition(const NzVector3f& position) +{ + alSourcefv(m_source, AL_POSITION, position); +} + +void NzSoundEmitter::SetPosition(float x, float y, float z) +{ + alSource3f(m_source, AL_POSITION, x, y, z); +} + +void NzSoundEmitter::SetVelocity(const NzVector3f& velocity) +{ + alSourcefv(m_source, AL_VELOCITY, velocity); +} + +void NzSoundEmitter::SetVelocity(float velX, float velY, float velZ) +{ + alSource3f(m_source, AL_VELOCITY, velX, velY, velZ); +} + +void NzSoundEmitter::SetVolume(float volume) +{ + alSourcef(m_source, AL_GAIN, volume*0.01f); +} + +nzSoundStatus NzSoundEmitter::GetInternalStatus() const +{ + ALint state; + alGetSourcei(m_source, AL_SOURCE_STATE, &state); + + switch (state) + { + case AL_INITIAL: + case AL_STOPPED: + return nzSoundStatus_Stopped; + + case AL_PAUSED: + return nzSoundStatus_Paused; + + case AL_PLAYING: + return nzSoundStatus_Playing; + + default: + NazaraInternalError("Source state unrecognized"); + } + + return nzSoundStatus_Stopped; +}