From d8c4c6e5ff9138285aed5b10429f5ea5ab64e151 Mon Sep 17 00:00:00 2001 From: stiffly Date: Thu, 7 Jan 2016 15:22:46 +0100 Subject: [PATCH] Created a primitive SoundSystem. Can play a sound with 'P' button. Using resourcemanager. Not using the created components yet. --- assets | 2 +- deps | 2 +- include/Engine/Sound/EPlaySound.h | 18 +++ include/Engine/Sound/Sound.h | 113 +++++++++++++++++++ include/Engine/Sound/SoundSystem.h | 62 ++++++++++ include/Game/Game.h | 7 ++ resources/Schema/Components.xsd | 2 + resources/Schema/Components/Listener.xml | 3 + resources/Schema/Components/Listener.xsd | 8 ++ resources/Schema/Components/SoundEmitter.xml | 7 ++ resources/Schema/Components/SoundEmitter.xsd | 22 ++++ resources/Schema/Types/Entity.xsd | 2 + src/Engine/CMakeLists.txt | 11 +- src/Engine/Sound/SoundSystem.cpp | 66 +++++++++++ src/Game/Game.cpp | 18 ++- 15 files changed, 338 insertions(+), 5 deletions(-) create mode 100644 include/Engine/Sound/EPlaySound.h create mode 100644 include/Engine/Sound/Sound.h create mode 100644 include/Engine/Sound/SoundSystem.h create mode 100644 resources/Schema/Components/Listener.xml create mode 100644 resources/Schema/Components/Listener.xsd create mode 100644 resources/Schema/Components/SoundEmitter.xml create mode 100644 resources/Schema/Components/SoundEmitter.xsd create mode 100644 src/Engine/Sound/SoundSystem.cpp diff --git a/assets b/assets index 673d4a4e..6cbf2365 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 673d4a4e4c5a3f5bc9fedf82234e8f8751f63a44 +Subproject commit 6cbf2365d49e6280750ea3bcd0f9c271779e6f15 diff --git a/deps b/deps index 1ae6ba5b..293516d6 160000 --- a/deps +++ b/deps @@ -1 +1 @@ -Subproject commit 1ae6ba5b1297ed71b560aee211b9f0007ba52547 +Subproject commit 293516d671b97de26594fe979b7898b7e271e24c diff --git a/include/Engine/Sound/EPlaySound.h b/include/Engine/Sound/EPlaySound.h new file mode 100644 index 00000000..83fc4629 --- /dev/null +++ b/include/Engine/Sound/EPlaySound.h @@ -0,0 +1,18 @@ +#ifndef Events_PlaySound_h__ +#define Events_PlaySound_h__ + +#include "Core/EventBroker.h" +#include "Core/Entity.h" + +namespace Events +{ + + struct PlaySound : Event +{ + std::string FilePath; + EntityID emitter; +}; + +} + +#endif \ No newline at end of file diff --git a/include/Engine/Sound/Sound.h b/include/Engine/Sound/Sound.h new file mode 100644 index 00000000..ffb9b30e --- /dev/null +++ b/include/Engine/Sound/Sound.h @@ -0,0 +1,113 @@ +#ifndef Sound_h__ +#define Sound_h__ + +#include "Core/ResourceManager.h" + +class Sound : public Resource +{ + friend class ResourceManager; +public: + Sound(std::string path) { m_Buffer = LoadFile(path); } + ~Sound() { ClearBuffer(); } + ALuint Buffer() { return m_Buffer; } + std::string Path() { return m_Path; } + float Gain() { return m_Gain; } + void SetGain(float value) { m_Gain = value; } + void ClearBuffer() { alDeleteBuffers(1, &m_Buffer); m_BufferCache.clear(); }; + +private: + float m_Gain = 1; + ALuint m_Buffer; + std::string m_Path; + + // File info + char m_Type[4]; + unsigned long m_Size, m_ChunkSize; + short m_FormatType, m_Channels; + unsigned long m_SampleRate, m_AvgBytesPerSec; + short m_BytesPerSample, m_BitsPerSample; + unsigned int m_DataSize; + std::map m_BufferCache; + + ALuint LoadFile(std::string path) + { + if (m_BufferCache.find(path) != m_BufferCache.end()) { + return m_BufferCache[path]; + } + + //// Open file + FILE *fp = fopen(path.c_str(), "rb"); + if (!fp) { + printf("Failed to open file %s, no such file exists", path.c_str()); + return 0; + } + + //// CHECK FOR VALID WAVE-FILE + fread(m_Type, sizeof(char), 4, fp); + if (m_Type[0] != 'R' || m_Type[1] != 'I' || m_Type[2] != 'F' || m_Type[3] != 'F') { + printf("ERROR: No RIFF in WAVE-file"); + return 0; + } + + fread(&m_Size, 4 * sizeof(char), 1, fp); + fread(m_Type, sizeof(char), 4, fp); + if (m_Type[0] != 'W' || m_Type[1] != 'A' || m_Type[2] != 'V' || m_Type[3] != 'E') { + printf("ERROR: Not WAVE-file"); + return 0; + } + + fread(m_Type, sizeof(char), 4, fp); + if (m_Type[0] != 'f' || m_Type[1] != 'm' || m_Type[2] != 't' || m_Type[3] != ' ') { + printf("ERROR: No fmt in WAVE-file"); + return 0; + } + + //// READ THE DATA FROM WAVE-FILE + fread(&m_ChunkSize, 4 * sizeof(char), 1, fp); + fread(&m_FormatType, 2 * sizeof(char), 1, fp); + fread(&m_Channels, 2 * sizeof(char), 1, fp); + fread(&m_SampleRate, 4 * sizeof(char), 1, fp); + fread(&m_AvgBytesPerSec, 4 * sizeof(char), 1, fp); + fread(&m_BytesPerSample, 2 * sizeof(char), 1, fp); + fread(&m_BitsPerSample, 2 * sizeof(char), 1, fp); + + fread(m_Type, sizeof(char), 4, fp); + if (m_Type[0] != 'd' || m_Type[1] != 'a' || m_Type[2] != 't' || m_Type[3] != 'a') { + printf("ERROR: WAVE-file Missing data"); + return 0; + } + + fread(&m_DataSize, 4 * sizeof(char), 1, fp); + + unsigned char* buf = new unsigned char[m_DataSize]; + fread(buf, sizeof(char), m_DataSize, fp); + fclose(fp); + + //// Create buffer + ALuint format = 0; + if (m_BitsPerSample == 8) { + if (m_Channels == 1) { + format = AL_FORMAT_MONO8; + } else if (m_Channels == 2) { + format = AL_FORMAT_STEREO8; + } + } + if (m_BitsPerSample == 16) { + if (m_Channels == 1) { + format = AL_FORMAT_MONO16; + } else if (m_Channels == 2) { + format = AL_FORMAT_STEREO16; + } + } + + ALuint buffer; + alGenBuffers(1, &buffer); + alBufferData(buffer, format, buf, m_DataSize, m_SampleRate); + delete[] buf; + + m_BufferCache[path] = buffer; + return buffer; + } +}; + +#endif diff --git a/include/Engine/Sound/SoundSystem.h b/include/Engine/Sound/SoundSystem.h new file mode 100644 index 00000000..0035a3bb --- /dev/null +++ b/include/Engine/Sound/SoundSystem.h @@ -0,0 +1,62 @@ +#ifndef SoundSystem_h__ +#define SoundSystem_h__ + +#include + +#include "glm/common.hpp" +#include "OpenAL/al.h" +#include "OpenAL/alc.h" + +#include "Core/World.h" +#include "Core/EventBroker.h" +#include "Sound/Sound.h" +#include "Sound/EPlaySound.h" + +struct Source +{ + Sound* SoundResource; + ALuint ALsource; +}; + +class SoundSystem +{ +public: + SoundSystem() { } + SoundSystem(EventBroker* eventBroker); + ~SoundSystem(); + void Update() { } // Update emitters +private: + // Private setters and getters for working with glm + void setListenerPos(glm::vec3 pos) { alListener3f(AL_POSITION, pos.x, pos.y, pos.z); }; + glm::vec3 listnerPos() { glm::vec3 pos; alGetListener3f(AL_POSITION, &pos.x, &pos.y, &pos.z); return pos; }; + void setListenerVel(glm::vec3 vel) { alListener3f(AL_VELOCITY, vel.x, vel.y, vel.z); }; + glm::vec3 listenerVel() { glm::vec3 vel; alGetListener3f(AL_VELOCITY, &vel.x, &vel.y, &vel.z); return vel; }; + void setListenerOri(glm::vec3 ori) { alListener3f(AL_ORIENTATION, ori.x, ori.y, ori.z); }; + glm::vec3 listenerOri() { glm::vec3 ori; alGetListener3f(AL_ORIENTATION, &ori.x, &ori.y, &ori.z); return ori; }; + void setSourcePos(ALuint source, glm::vec3 pos) { ALfloat spos[3] = { pos.x, pos.y, pos.z }; alSourcefv(source, AL_POSITION, spos); }; + void setSourceVel(ALuint source, glm::vec3 vel) { ALfloat svel[3] = { vel.x, vel.y, vel.z }; alSourcefv(source, AL_VELOCITY, svel); }; + void setSourceOri(ALuint source, glm::vec3 ori) { ALfloat sori[3] = { ori.x, ori.y, ori.z }; alSourcefv(source, AL_ORIENTATION, sori); }; + + // Logic + World* m_World; + EventBroker* m_EventBroker; + + ALuint createSource(); + void playSound(Source source); + void stopSound(Source source); + void stopEmitter(EntityID emitter); + + // OpenAL system variables + ALCdevice* m_ALCdevice = nullptr; + ALCcontext* m_ALCcontext = nullptr; + + // Logic + std::unordered_map m_Sources; + + // Events + EventRelay m_EPlaySound; + bool OnPlaySound(const Events::PlaySound &e); + +}; + +#endif \ No newline at end of file diff --git a/include/Game/Game.h b/include/Game/Game.h index 33dc88a6..6b284c74 100644 --- a/include/Game/Game.h +++ b/include/Game/Game.h @@ -25,6 +25,10 @@ #include "Network/Server.h" #include "Network/Client.h" +// Sound +#include "Sound/SoundSystem.h" +#include "Sound/EPlaySound.h" + class Game { @@ -54,6 +58,9 @@ private: Network* m_ClientOrServer; bool m_IsClientOrServer = false; + // Sound + SoundSystem* m_SoundSystem; + EventRelay m_EInputCommand; bool debugOnInputCommand(const Events::InputCommand& e); diff --git a/resources/Schema/Components.xsd b/resources/Schema/Components.xsd index fd04fd39..a287431c 100644 --- a/resources/Schema/Components.xsd +++ b/resources/Schema/Components.xsd @@ -8,4 +8,6 @@ + + \ No newline at end of file diff --git a/resources/Schema/Components/Listener.xml b/resources/Schema/Components/Listener.xml new file mode 100644 index 00000000..7d1fac13 --- /dev/null +++ b/resources/Schema/Components/Listener.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/resources/Schema/Components/Listener.xsd b/resources/Schema/Components/Listener.xsd new file mode 100644 index 00000000..5f71f11a --- /dev/null +++ b/resources/Schema/Components/Listener.xsd @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/resources/Schema/Components/SoundEmitter.xml b/resources/Schema/Components/SoundEmitter.xml new file mode 100644 index 00000000..a032dfbb --- /dev/null +++ b/resources/Schema/Components/SoundEmitter.xml @@ -0,0 +1,7 @@ + + 1.0 + 1.0 + 20.0 + 1.0 + 1.0 + \ No newline at end of file diff --git a/resources/Schema/Components/SoundEmitter.xsd b/resources/Schema/Components/SoundEmitter.xsd new file mode 100644 index 00000000..6bebcac5 --- /dev/null +++ b/resources/Schema/Components/SoundEmitter.xsd @@ -0,0 +1,22 @@ + + + + + + + + + + The "volume" of the emitter. A value betweeen 0-1 + + The pitch of the emitter. A value betweeen 0-1 + + The distance where there will no longer be any attenuation. + + The rolloff rate of the source. + + The distance that the source will be the loudest. + + + + \ No newline at end of file diff --git a/resources/Schema/Types/Entity.xsd b/resources/Schema/Types/Entity.xsd index 92f7dc31..67612935 100644 --- a/resources/Schema/Types/Entity.xsd +++ b/resources/Schema/Types/Entity.xsd @@ -15,6 +15,8 @@ + + diff --git a/src/Engine/CMakeLists.txt b/src/Engine/CMakeLists.txt index 5d43db8b..40bc9cb0 100644 --- a/src/Engine/CMakeLists.txt +++ b/src/Engine/CMakeLists.txt @@ -9,8 +9,8 @@ find_package(ZLIB REQUIRED) find_package(PNG REQUIRED) find_package(Xerces REQUIRED) # Because FindOpenAL is retarded -#set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "${CMAKE_SOURCE_DIR}/deps/include/AL") -#find_package(OpenAL REQUIRED) +set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "${CMAKE_SOURCE_DIR}/deps/include/OpenAL") +find_package(OpenAL REQUIRED) if(UNIX) find_package(X11 REQUIRED) endif() @@ -52,6 +52,12 @@ file(GLOB SOURCE_FILES_Network ) source_group(Network FILES ${SOURCE_FILES_Network}) +file(GLOB SOURCE_FILES_Sound + "${INCLUDE_PATH}/Sound/*.h" + "Sound/*.cpp" +) +source_group(Sound FILES ${SOURCE_FILES_Sound}) + file(GLOB SOURCE_FILES_Rendering "${INCLUDE_PATH}/Rendering/*.h" "Rendering/*.cpp" @@ -86,6 +92,7 @@ set(SOURCE_FILES ${SOURCE_FILES_Core_Util} ${SOURCE_FILES_Input} ${SOURCE_FILES_Network} + ${SOURCE_FILES_Sound} ${SOURCE_FILES_GUI} ${SOURCE_FILES_Rendering} ${SOURCE_FILES_Rendering_Util} diff --git a/src/Engine/Sound/SoundSystem.cpp b/src/Engine/Sound/SoundSystem.cpp new file mode 100644 index 00000000..965f97a4 --- /dev/null +++ b/src/Engine/Sound/SoundSystem.cpp @@ -0,0 +1,66 @@ +#include "Sound/SoundSystem.h" + +SoundSystem::SoundSystem(EventBroker* eventBroker) +{ + m_EventBroker = eventBroker; + // Initialize OpenAL + m_ALCdevice = alcOpenDevice(nullptr); + if (m_ALCdevice != nullptr) { + m_ALCcontext = alcCreateContext(m_ALCdevice, nullptr); + alcMakeContextCurrent(m_ALCcontext); + } else { + LOG_ERROR("OpenAL failed to initialize."); + } + + alSpeedOfSound(340.29f); // Speed of sound + alDistanceModel(AL_INVERSE_DISTANCE); + + EVENT_SUBSCRIBE_MEMBER(m_EPlaySound, &SoundSystem::OnPlaySound); + //m_EPlaySound = decltype(m_EPlaySound)(std::bind(&SoundSystem::OnPlaySound, this, std::placeholders::_1)); + //m_EventBroker->Subscribe(m_EPlaySound); +} + +SoundSystem::~SoundSystem() +{ + alcDestroyContext(m_ALCcontext); + alcCloseDevice(m_ALCdevice); + delete m_ALCcontext; + delete m_ALCdevice; +} + +ALuint SoundSystem::createSource() +{ + ALuint source; + alGenSources((ALuint)1, &source); + alSourcei(source, AL_REFERENCE_DISTANCE, 1.0); + alSourcei(source, AL_MAX_DISTANCE, FLT_MAX); + return source; +} + +void SoundSystem::playSound(Source source) +{ + alSourcei(source.ALsource, AL_BUFFER, source.SoundResource->Buffer()); + alSourcePlay(source.ALsource); +} + +void SoundSystem::stopSound(Source source) +{ } + +void SoundSystem::stopEmitter(EntityID emitter) +{ } + +bool SoundSystem::OnPlaySound(const Events::PlaySound & e) +{ + Sound *sound = ResourceManager::Load(e.FilePath); + if (sound == nullptr) { + return false; + } + ALuint source = createSource(); + Source sauce; + sauce.ALsource = source; + sauce.SoundResource = sound; + playSound(sauce); + LOG_INFO("You are playing an imaginary sound now! :D"); + return false; +} + diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index 033db642..66ab6fae 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -5,6 +5,7 @@ Game::Game(int argc, char* argv[]) { ResourceManager::RegisterType("ConfigFile"); + ResourceManager::RegisterType("Sound"); ResourceManager::RegisterType("Model"); ResourceManager::RegisterType("Texture"); ResourceManager::RegisterType("EntityXMLFile"); @@ -63,6 +64,9 @@ Game::Game(int argc, char* argv[]) //boost::thread workerThread(&Game::networkFunction, this); networkFunction(); } + EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &Game::debugOnInputCommand); + m_SoundSystem = new SoundSystem(m_EventBroker); + m_LastTime = glfwGetTime(); } @@ -103,9 +107,11 @@ void Game::Tick() // Iterate through systems and update world! m_SystemPipeline->Update(m_World, dt); + debugTick(dt); m_Renderer->Update(dt); m_EventBroker->Process(); - + m_EventBroker->Process(); + m_SoundSystem->Update(); m_RenderQueueFactory->Update(m_World); GLERROR("Game::Tick m_RenderQueueFactory->Update"); m_Renderer->Draw(m_RenderQueueFactory->RenderQueues()); @@ -114,6 +120,16 @@ void Game::Tick() m_EventBroker->Clear(); } +bool Game::debugOnInputCommand(const Events::InputCommand & e) +{ + if (e.Command == "PlaySound" && e.Value > 0) { + Events::PlaySound e; + e.FilePath = "Audio/crosscounter.wav"; + m_EventBroker->Publish(e); + } + return true; +} + void Game::debugTick(double dt) { m_EventBroker->Process();