Created a primitive SoundSystem. Can play a sound with 'P' button. Using resourcemanager. Not using the created components yet.
This commit is contained in:
+1
-1
Submodule assets updated: 673d4a4e4c...6cbf2365d4
+1
-1
Submodule deps updated: 1ae6ba5b12...293516d671
@@ -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
|
||||
@@ -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<std::string, ALuint> 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
|
||||
@@ -0,0 +1,62 @@
|
||||
#ifndef SoundSystem_h__
|
||||
#define SoundSystem_h__
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#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<EntityID, Source> m_Sources;
|
||||
|
||||
// Events
|
||||
EventRelay<SoundSystem, Events::PlaySound> m_EPlaySound;
|
||||
bool OnPlaySound(const Events::PlaySound &e);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -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<Game, Events::InputCommand> m_EInputCommand;
|
||||
bool debugOnInputCommand(const Events::InputCommand& e);
|
||||
|
||||
|
||||
@@ -8,4 +8,6 @@
|
||||
<xs:include schemaLocation="Components/Player.xsd"/>
|
||||
<xs:include schemaLocation="Components/AABB.xsd"/>
|
||||
<xs:include schemaLocation="Components/Trigger.xsd"/>
|
||||
<xs:include schemaLocation="Components/Listener.xsd"/>
|
||||
<xs:include schemaLocation="Components/SoundEmitter.xsd"/>
|
||||
</xs:schema>
|
||||
@@ -0,0 +1,3 @@
|
||||
<c:Listener>
|
||||
|
||||
</c:Listener>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:t="types">
|
||||
<xs:import schemaLocation="../Types.xsd" namespace="types"/>
|
||||
|
||||
<xs:element name="Listener">
|
||||
</xs:element>
|
||||
</xs:schema>
|
||||
@@ -0,0 +1,7 @@
|
||||
<c:SoundEmitter>
|
||||
<Gain>1.0</Gain>
|
||||
<Pitch>1.0</Pitch>
|
||||
<MaxDistance>20.0</MaxDistance>
|
||||
<RollOffFactor>1.0</RollOffFactor>
|
||||
<ReferenceDistance>1.0</ReferenceDistance>
|
||||
</c:SoundEmitter>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:t="types">
|
||||
<xs:import schemaLocation="../Types.xsd" namespace="types"/>
|
||||
|
||||
<xs:element name="SoundEmitter">
|
||||
<xs:complexType>
|
||||
<xs:all>
|
||||
<xs:element name="Gain" type="t:float" minOccurs="0"/>
|
||||
<xs:annotation><xs:documentation>The "volume" of the emitter. A value betweeen 0-1</xs:documentation></xs:annotation>
|
||||
<xs:element name="Pitch" type="t:float" minOccurs="0"/>
|
||||
<xs:annotation><xs:documentation>The pitch of the emitter. A value betweeen 0-1</xs:documentation></xs:annotation>
|
||||
<xs:element name="MaxDistance" type="t:float" minOccurs="0"/>
|
||||
<xs:annotation><xs:documentation>The distance where there will no longer be any attenuation.</xs:documentation></xs:annotation>
|
||||
<xs:element name="RollOffFactor" type="t:float" minOccurs="0"/>
|
||||
<xs:annotation><xs:documentation>The rolloff rate of the source.</xs:documentation></xs:annotation>
|
||||
<xs:element name="ReferenceDistance" type="t:float" minOccurs="0"/>
|
||||
<xs:annotation><xs:documentation>The distance that the source will be the loudest.</xs:documentation></xs:annotation>
|
||||
</xs:all>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:schema>
|
||||
@@ -15,6 +15,8 @@
|
||||
<xs:element ref="c:Test" minOccurs="0"/>
|
||||
<xs:element ref="c:RaptorCopter" minOccurs="0"/>
|
||||
<xs:element ref="c:Player" minOccurs="0"/>
|
||||
<xs:element ref="c:Listener" minOccurs="0"/>
|
||||
<xs:element ref="c:SoundEmitter" minOccurs="0"/>
|
||||
</xs:all>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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<Sound>(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;
|
||||
}
|
||||
|
||||
+17
-1
@@ -5,6 +5,7 @@
|
||||
Game::Game(int argc, char* argv[])
|
||||
{
|
||||
ResourceManager::RegisterType<ConfigFile>("ConfigFile");
|
||||
ResourceManager::RegisterType<Sound>("Sound");
|
||||
ResourceManager::RegisterType<Model>("Model");
|
||||
ResourceManager::RegisterType<Texture>("Texture");
|
||||
ResourceManager::RegisterType<EntityXMLFile>("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<Client>();
|
||||
|
||||
m_EventBroker->Process<SoundSystem>();
|
||||
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<Game>();
|
||||
|
||||
Reference in New Issue
Block a user