Merge develop.

develop
Vyom Fadia 2020-05-08 22:04:54 +01:00
commit 46dec92cf5
14 changed files with 4164 additions and 6 deletions

6
.gitignore vendored
View File

@ -1,12 +1,6 @@
Build/
[._]*.s[a-v][a-z]
[._]*.sw[a-p]
[._]s[a-rt-v][a-z]
[._]ss[a-gi-z]
[._]sw[a-p]
.vs/
.vscode/
Documentation/Build/
Phoenix/ThirdParty/

3
.gitmodules vendored
View File

@ -13,3 +13,6 @@
[submodule "Phoenix/ThirdParty/json"]
path = Phoenix/ThirdParty/json
url = https://github.com/nlohmann/json.git
[submodule "Phoenix/ThirdParty/openal-soft"]
path = Phoenix/ThirdParty/openal-soft
url = https://github.com/kcat/openal-soft.git

View File

@ -27,3 +27,10 @@ source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}/Source" PREFIX "Source Files" FIL
add_dependencies(${PROJECT_NAME} PhoenixAssets-client)
add_dependencies(${PROJECT_NAME} PhoenixModules-client)
add_dependencies(${PROJECT_NAME} PhoenixSaves-client)
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:OpenAL>
$<TARGET_FILE_DIR:${PROJECT_NAME}>/$<TARGET_FILE_NAME:OpenAL>
)

View File

@ -0,0 +1,185 @@
// Copyright 2019-20 Genten Studios
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors
// may be used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#pragma once
#include <Client/Audio/Listener.hpp>
#include <Client/Audio/Source.hpp>
#include <AL/alc.h>
#include <minimp3/minimp3.h>
#include <unordered_map>
namespace phx::audio
{
/**
* @brief Stores data to pass between the Audio engine and Sources.
*/
struct AudioData
{
/**
* @brief The buffer ID, more for internal use.
*/
unsigned int buffer;
/**
* @brief The duration of the audio, minutes and seconds.
*/
Duration duration;
};
/**
* @brief Loads audio and provides an ability to play them.
*
* This class is to be used in conjunction with the Source class. Currently
* only MP3 is supported, future version may include OGG support.
*
* @paragraph Usage
* Before use, you must call ``initialize()`` to produce the OpenAL context,
* otherwise a barrage of errors will be displayed in the console. Before
* shutdown of the game, make sure all playing Sources are stopped and you
* have called the ``teardown()`` method to clear any existing buffers from
* memory.
*
* The destructor must be called before teardown, you can do this by
* initializing before a scope, and tearing down after the end of the scope,
* while instantiating the Audio class within the closed scope.
*
* @code
* using namespace phx;
*
* audio::Audio::initialize();
*
* {
* audio::Audio manager;
* manager.loadMP3("core:song1", "Assets/Song1.mp3");
* manager.loadMP3("core:song2", "Assets/Song2.mp3");
*
* audio::Source source;
* source.setAudioData(manager.getAudioData("core:song1"));
* // also possible to do: manager["core:song1"]
*
* source.enableSpatial(true);
* source.setPosition({ 10.f, 0.f, 0.f });
*
* audio::Listener* listener = manager.getListener();
* listener->setGain(...);
* listener->setPosition(...);
*
* source.play();
* }
* @endcode
*/
class Audio
{
public:
Audio() = default;
/**
* @brief Deletes all existing buffers registered on this instance.
*
* Needs to be called before teardown, so consider creating the Audio
* object in a closed scope after initialization and teardown.
*/
~Audio();
/**
* @brief Initializes the audio subsystem, creates an OpenAL context.
* @return true on success
* @return false on failure.
*
* This needs to be called before an Audio object is instantiated. This
* function creates an OpenAL context on a specific audio device. This
* cannot currently be chosen, it is automatic. Eventually, however,
* once a UI is added, extra methods will be implemented to allow the
* option to select an output device.
*/
static bool initialize();
/**
* @brief Shuts down the audio subsystem.
*
* This needs to be called after all Audio objects have been destructed
* since the destructors delete all existing buffers. This function
* destroys the OpenAL context and closes the audio device - if all
* destructors are not called, there will be a list of errors outputted
* to console about existing buffers not being deleted.
*/
static void teardown();
/**
* @brief Loads an MP3 into a buffer, ready for playing in a Source.
* @param uniqueName The unique name for the audio clip.
* @param filePath The path including the filename of the audio.
*
* This method does won't cause a segfault if an unexpected file is
* provided, however it will not load that file in, and an error will be
* logged. This function will load an MP3 file into an OpenAL buffer
* ready for use in Sources.
*/
void loadMP3(const std::string& uniqueName,
const std::string& filePath);
/**
* @brief Gets the audio data for a Source to use before playing.
* @param uniqueName The unique name of the audio clip being retrieved.
* @return The buffer and duration for a valid unique name,
* alternatively, a dummy buffer and duration will be returned.
*
* This function will return a buffer of -1 if an invalid uniqueName is
* provided. Since it's an unsigned integer, -1 doesn't really exist,
* but checking for it will in an if statement, so check whether the
* buffer is -1 before using on an actual Source.
*/
AudioData getAudioData(const std::string& uniqueName) const;
// [] operator, like an unordered_map, just redirected to getAudioData,
// essentially just a QoL feature.
AudioData operator[](const std::string& uniqueName) const
{
return getAudioData(uniqueName);
}
/**
* @brief The listener (you, what you hear in your headphones)
* @return The listener object.
*/
Listener* getListener() { return &m_listener; }
private:
static ALCcontext* m_context;
static ALCdevice* m_device;
static mp3dec_t m_mp3;
Listener m_listener;
// maps uniqueName from loadMP3 to a buffer id + duration.
std::unordered_map<std::string, AudioData> m_buffers;
};
} // namespace phx::audio

View File

@ -0,0 +1,8 @@
set(currentDir ${CMAKE_CURRENT_LIST_DIR})
set(audioHeaders
${currentDir}/Source.hpp
${currentDir}/Listener.hpp
${currentDir}/Audio.hpp
PARENT_SCOPE
)

View File

@ -0,0 +1,113 @@
// Copyright 2019-20 Genten Studios
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors
// may be used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#pragma once
#include <Common/Math/Math.hpp>
namespace phx::audio
{
/**
* @brief The listener, the player side of positional audio.
*
* This is basically a dummy class. You can only have one listener per
* OpenAL context, and it's global. There are no variables, just OpenAL
* calls within these functions. The reason this exists is to provide an
* easier, more intuitive way to control the player's positional data.
*
* @paragraph Usage
* @code
* audio::Audio manager;
* manager.loadMP3("core:cow_going_moo_for_1_minute", "Assets/moo.mp3");
*
* audio::Source source;
* source.setAudioData(manager["core:cow_going_moo_for_1_minute"]);
*
* source.enableSpatial(true);
* source.setPosition({ 0.f, 10.f, 0.f });
*
* source.play();
*
* audio::Listener* listener = manager.getListener();
* listener.setPosition({ 0.f, 0.f, 0.f });
*
* // pseudo code
* thread::sleep(10 seconds);
*
* listener.setPosition({ 10.f, 0.f, 0.f });
*
* // pseudo code
* thread::sleep(10 seconds);
*
* same thing continued...
*/
class Listener
{
public:
/**
* @brief Sets the gain the listener will use.
* @param gain The gain everything should be finally adjusted to.
*
* Using a scale of 0 to 1.0, this can be used as a way to control
* volume.
*/
void setGain(float gain);
/**
* @brief Sets the position of the listener.
* @param position The position of the listener.
*/
void setPosition(math::vec3 position);
/**
* @brief Sets the velocity of the listener.
* @param velocity The velocity of the listener.
*
* Velocity is a vector quantity, this means it contains direction and
* magnitude. The velocity is a combination of speed and the direction
* in which it is moving.
*
* Velocity is also important in the applying the "Doppler Effect".
*/
void setVelocity(math::vec3 velocity);
/**
* @brief Sets the orientation of the player.
* @param direction The direction of the player.
* @param up The up vector of the player (what way up they are.)
*/
void setOrientation(math::vec3 direction, math::vec3 up);
private:
// private constructor because you shouldn't be able to make a Listener.
Listener() = default;
~Listener() = default;
friend class Audio;
};
} // namespace phx::audio

View File

@ -0,0 +1,234 @@
// Copyright 2019-20 Genten Studios
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors
// may be used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#pragma once
#include <Common/Math/Math.hpp>
#include <AL/al.h>
namespace phx::audio
{
/**
* @brief A struct holding the duration of an audio clip, in minutes and
* seconds.
*
* @ref AudioData
*/
struct Duration
{
unsigned int minutes;
unsigned int seconds;
};
struct AudioData;
/**
* @brief The source of audio.
*
* This class represents an audio source, like a speaker or a sheep...
*
* The source initially has spatial support disabled, as well as looping.
* This is idea mainly for things like background music, since they can be
* looped and shouldn't be affected by the player's position.
*
* @paragraph Usage
* @code
* audio::Audio manager;
* manager.loadMP3("core:song", "Assets/song.mp3");
* manager.loadMP3("core:song2", "Assets/song.mp3");
*
* audio::Source source;
* source.setAudioData(manager["core:song"]);
* source.enableSpatial(true);
* source.enableLoop(true);
*
* // one is same as input.
* source.setGain(1.f);
* source.setPitch(1.f);
*
* source.play();
*
* // wait for source to finish playing whatever it's playing.
* while (source.status() != Source::State::Stopped)
* {
* ;
* }
*
* source.setAudioData(manager["core:song2"]);
* ...
* @endcode
*/
class Source
{
public:
/**
* @brief The current playing state of the Source.
*/
enum class State
{
/**
* @brief The Source is playing.
*/
PLAYING = AL_PLAYING,
/**
* @brief The source is paused.
*/
PAUSED = AL_PAUSED,
/**
* @brief The source is stopped, so either it hasn't been started,
* or it has finished.
*/
STOPPED = AL_STOPPED
};
public:
/**
* @brief Constructs a Source object.
*/
Source();
/**
* @brief Constructs a Source object but with AudioData from the start.
* @param data The audio data to use.
*
* This one is useful if you know exactly what audio needs to be played.
* The AudioData can be set later on so using this constructor is not
* particularly necessary.
*/
explicit Source(AudioData data);
/**
* @brief Destroys a Source object.
*/
~Source();
/**
* @brief Allows for enabling/disabling spatial audio as required.
* @param enable Whether to enable spatial audio or not.
*
* Spatial audio is disabled by default. This is useful for things like
* background music, etc... Spatial audio is required for position-based
* audio, such as surrounding entities, world audio, etc...
*/
void enableSpatial(bool enable);
/**
* @brief Allows for enabling/disabling the audio from looping.
* @param enable Whether to enable looping or not.
*
* Looping is disabled by default, since most sounds are a
* play-on-demand rather than all the time. Things like ambient audio or
* background music are more likely to be looped, so enabling this is
* necessary.
*/
void enableLoop(bool enable);
/**
* @brief Sets the position of the source.
* @param pos The position of the source.
*/
void setPos(math::vec3 pos);
/**
* @brief Sets the direction of the source.
* @param direction The direction the source is facing.
*/
void setDirection(math::vec3 direction);
/**
* @brief Sets the velocity of the source.
* @param velocity The velocity of the source.
*
* Velocity is a vector quantity, this means it contains direction and
* magnitude. The velocity is a combination of speed and the direction
* in which it is moving.
*
* Velocity is also important in the applying the "Doppler Effect".
*/
void setVelocity(math::vec3 velocity);
/**
* @brief Sets the gain of the source.
* @param gain The gain the audio will be played back at.
*/
void setGain(float gain);
/**
* @brief Sets the pitch of the source.
* @param pitch The pitch the audio will be played back at.
*/
void setPitch(float pitch);
/**
* @brief Returns the duration of the audio clip.
* @return The duration of the audio clip.
*
* This can return 0, 0 due to the seconds being an unsigned int,
* lacking the precision of a float.
*
* @todo Increase the resolution of Duration, to allow for telling the
* duration of clips shorter than a second.
*/
Duration getDuration() const;
/**
* @brief Returns the playing status of the source.
* @return The status of the source: playing, paused or finished.
*/
State status() const;
/**
* @brief Sets the audio for the source to use, comes from audio::Audio.
* @param buffer The data associated to the audio requested.
*
* This method should be used with the audio::Audio class.
* audio::Audio::getAudioData("core:song") will return an AudioData
* object for the source to use and play.
*/
void setAudioData(AudioData buffer);
/**
* @brief Plays the audio. Calling again will pause.
*/
void play() const;
private:
// internal variable for OpenAL.
unsigned int m_source = 0;
math::vec3 m_position;
math::vec3 m_direction;
math::vec3 m_velocity;
float m_gain = 1.f;
float m_pitch = 1.f;
Duration m_duration;
};
} // namespace phx::audio

View File

@ -0,0 +1,187 @@
// Copyright 2019-20 Genten Studios
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors
// may be used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include <Client/Audio/Audio.hpp>
#include <Common/Logger.hpp>
#include <AL/al.h>
#include <AL/alc.h>
#pragma warning(disable : 4267 4244)
#define MINIMP3_ONLY_MP3
#define MINIMP3_IMPLEMENTATION
#include <minimp3/minimp3.h>
#include <minimp3/minimp3_ex.h>
using namespace phx::audio;
ALCcontext* Audio::m_context = nullptr;
ALCdevice* Audio::m_device = nullptr;
mp3dec_t Audio::m_mp3;
Audio::~Audio()
{
// deletes all buffers of registered sounds.
for (auto& it : m_buffers)
{
alDeleteBuffers(1, &it.second.buffer);
}
}
bool Audio::initialize()
{
// opens an audio device.
m_device = alcOpenDevice(nullptr);
if (!m_device)
{
LOG_FATAL("AUDIO")
<< "Could not open an audio device! No audio will be played.";
return false;
}
// creates an OpenAL context.
m_context = alcCreateContext(m_device, nullptr);
if (!m_context)
{
LOG_FATAL("AUDIO")
<< "Could not create an audio context! No audio will be played.";
alcCloseDevice(m_device);
return false;
}
// makes the context current.
if (alcMakeContextCurrent(m_context) == ALC_FALSE)
{
LOG_FATAL("AUDIO")
<< "Could not create an audio context! No audio will be played.";
alcDestroyContext(m_context);
alcCloseDevice(m_device);
return false;
}
// initializes the MP3 loaded.
mp3dec_init(&m_mp3);
// place some initial values for the listener, this is all changeable and
// should be immediately changed to the actual position of the player once
// instantiated.
ALfloat listenerPos[] = {0.0, 0.0, 0.0};
ALfloat listenerVel[] = {0.0, 0.0, 0.0};
ALfloat listenerOri[] = {0.0, 0.0, -1.0, 0.0, 1.0, 0.0};
alListenerfv(AL_POSITION, listenerPos);
alListenerfv(AL_VELOCITY, listenerVel);
alListenerfv(AL_ORIENTATION, listenerOri);
return true;
}
void Audio::teardown()
{
// destroys the context and closes the audio device.
alcMakeContextCurrent(nullptr);
alcDestroyContext(m_context);
alcCloseDevice(m_device);
}
void Audio::loadMP3(const std::string& uniqueName, const std::string& filePath)
{
// checks if uniqueName already exists, if so, then overwrite what's there.
const auto it = m_buffers.find(uniqueName);
if (it != m_buffers.end())
{
LOG_WARNING("AUDIO") << "The sound with the unique name: " << uniqueName
<< " already exists, but will be overwritten.";
}
// load the mp3 file. will just return empty if the file cannot be read.
mp3dec_file_info_t info;
if (mp3dec_load(&m_mp3, filePath.c_str(), &info, nullptr, nullptr))
{
LOG_FATAL("AUDIO")
<< "An unexpected (but recoverable) error occurred while loading: "
<< filePath;
return;
}
// calculates the size of the buffer by the amount of samples and the size of each sample.
const unsigned int bufferSize = info.samples * sizeof(mp3d_sample_t);
// gets the duration of the audio, initially as a simple float, but then converted to minutes and seconds.
const float durationSeconds = static_cast<float>(bufferSize) / (static_cast<float>(info.avg_bitrate_kbps) * 1024.f);
const Duration duration = {
static_cast<unsigned int>(durationSeconds / 60.f),
static_cast<unsigned int>(durationSeconds) % 60};
unsigned int buffer;
// if uniqueName wasn't found, the buffer doesn't exist, otherwise overwrite
// the existing buffer to prevent undefined behaviour and wasted memory.
if (it == m_buffers.end())
{
alGenBuffers(1, &buffer);
}
else
{
buffer = it->second.buffer;
}
// fill the buffer with the data.
alBufferData(buffer,
info.channels == 2 ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16,
info.buffer, bufferSize, info.hz);
// checks for an error.
if (alGetError() != AL_NO_ERROR)
{
LOG_FATAL("AUDIO")
<< "An unexpected (but recoverable) error occurred while loading: "
<< filePath;
}
// adds the buffer ID and duration to the unordered_map, where it is
// associated with the uniqueName. this can then be retrieved in
// getAudioData or [].
m_buffers.insert_or_assign(uniqueName, AudioData {buffer, duration});
}
AudioData Audio::getAudioData(const std::string& uniqueName) const
{
auto it = m_buffers.find(uniqueName);
if (it == m_buffers.end())
{
// if not found, return some dummy data.
return {static_cast<unsigned int>(-1), {0, 0}};
}
return it->second;
}

View File

@ -0,0 +1,8 @@
set(currentDir ${CMAKE_CURRENT_LIST_DIR})
set(audioSources
${currentDir}/Source.cpp
${currentDir}/Listener.cpp
${currentDir}/Audio.cpp
PARENT_SCOPE
)

View File

@ -0,0 +1,52 @@
// Copyright 2019-20 Genten Studios
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors
// may be used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include <Client/Audio/Listener.hpp>
#include <AL/al.h>
using namespace phx::audio;
void Listener::setGain(float gain) { alListenerf(AL_GAIN, gain); }
void Listener::setPosition(math::vec3 position)
{
alListenerfv(AL_POSITION, &position.x);
}
void Listener::setVelocity(math::vec3 velocity)
{
alListenerfv(AL_VELOCITY, &velocity.x);
}
void Listener::setOrientation(math::vec3 direction, math::vec3 up)
{
float orientation[6] = {direction.x, direction.y, direction.z,
up.x, up.y, up.z};
alListenerfv(AL_ORIENTATION, orientation);
}

View File

@ -0,0 +1,116 @@
// Copyright 2019-20 Genten Studios
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors
// may be used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include <Client/Audio/Source.hpp>
#include <Client/Audio/Audio.hpp>
#include <AL/al.h>
#include <AL/alext.h>
using namespace phx::audio;
Source::Source()
{
// creates an OpenAL source, ready for setting a buffer and playing back.
alGenSources(1, &m_source);
}
Source::Source(AudioData data)
{
// generates an OpenAL source and sets the buffer to be used during
// playback.
alGenSources(1, &m_source);
alSourcei(m_source, AL_BUFFER, data.buffer);
m_duration = data.duration;
}
Source::~Source()
{
// deletes the OpenAL source that was created.
// this will NOT delete the buffer (the storage for the actual audio).
alDeleteSources(1, &m_source);
}
void Source::enableSpatial(bool enable)
{
alSourcei(m_source, AL_SOURCE_SPATIALIZE_SOFT,
enable ? AL_TRUE : AL_FALSE);
}
void Source::enableLoop(bool enable)
{
alSourcei(m_source, AL_LOOPING, enable ? AL_TRUE : AL_FALSE);
}
void Source::setPos(math::vec3 pos)
{
m_position = pos;
alSourcefv(m_source, AL_POSITION, &m_position.x);
}
void Source::setDirection(math::vec3 direction)
{
m_direction = direction;
alSourcefv(m_source, AL_DIRECTION, &m_direction.x);
}
void Source::setVelocity(math::vec3 velocity)
{
m_velocity = velocity;
alSourcefv(m_source, AL_VELOCITY, &velocity.x);
}
void Source::setGain(float gain)
{
m_gain = gain;
alSourcef(m_source, AL_GAIN, gain);
}
void Source::setPitch(float pitch)
{
m_pitch = pitch;
alSourcef(m_source, AL_PITCH, pitch);
}
Duration Source::getDuration() const { return m_duration; }
Source::State Source::status() const
{
int state;
alGetSourcei(m_source, AL_SOURCE_STATE, &state);
return static_cast<State>(state);
}
void Source::setAudioData(AudioData data)
{
m_duration = data.duration;
alSourcei(m_source, AL_BUFFER, data.buffer);
}
void Source::play() const { alSourcePlay(m_source); }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1
Phoenix/ThirdParty/openal-soft vendored Submodule

@ -0,0 +1 @@
Subproject commit f5e0eef34db3a3ab94b61a2f99f84f078ba947e7