// Copyright (C) 2020 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 namespace Nz { /*! * \ingroup audio * \class Nz::SoundEmitter * \brief Audio class that represents a sound source, that emits sound * * \remark Module Audio needs to be initialized to use this class * \remark This class is abstract */ /*! * \brief Constructs a SoundEmitter object */ SoundEmitter::SoundEmitter() { alGenSources(1, &m_source); } /*! * \brief Constructs a SoundEmitter object which is a copy of another * * \param emitter SoundEmitter to copy * * \remark Position and velocity are not copied */ SoundEmitter::SoundEmitter(const SoundEmitter& emitter) { if (emitter.m_source != InvalidSource) { alGenSources(1, &m_source); SetAttenuation(emitter.GetAttenuation()); SetMinDistance(emitter.GetMinDistance()); SetPitch(emitter.GetPitch()); // No copy for position or velocity SetVolume(emitter.GetVolume()); } else m_source = InvalidSource; } /*! * \brief Constructs a SoundEmitter object by moving another * * \param emitter SoundEmitter to move * * \remark The moved sound emitter cannot be used after being moved */ SoundEmitter::SoundEmitter(SoundEmitter&& emitter) noexcept : m_source(emitter.m_source) { emitter.m_source = InvalidSource; } /*! * \brief Destructs the object */ SoundEmitter::~SoundEmitter() { if (m_source != InvalidSource) alDeleteSources(1, &m_source); } /*! * \brief Enables spatialization * * \param spatialization True if spatialization is enabled */ void SoundEmitter::EnableSpatialization(bool spatialization) { NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); alSourcei(m_source, AL_SOURCE_RELATIVE, !spatialization); } /*! * \brief Gets the attenuation * \return Amount that your sound will drop off as by the inverse square law */ float SoundEmitter::GetAttenuation() const { NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); ALfloat attenuation; alGetSourcef(m_source, AL_ROLLOFF_FACTOR, &attenuation); return attenuation; } /*! * \brief Gets the minimum distance to hear * \return Distance to begin to hear */ float SoundEmitter::GetMinDistance() const { NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); ALfloat distance; alGetSourcef(m_source, AL_REFERENCE_DISTANCE, &distance); return distance; } /*! * \brief Gets the pitch * \return Pitch of the sound */ float SoundEmitter::GetPitch() const { NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); ALfloat pitch; alGetSourcef(m_source, AL_PITCH, &pitch); return pitch; } /*! * \brief Gets the position of the emitter * \return Position of the sound */ Vector3f SoundEmitter::GetPosition() const { NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); Vector3f position; alGetSourcefv(m_source, AL_POSITION, &position.x); return position; } /*! * \brief Gets the velocity of the emitter * \return Velocity of the sound */ Vector3f SoundEmitter::GetVelocity() const { NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); Vector3f velocity; alGetSourcefv(m_source, AL_VELOCITY, &velocity.x); return velocity; } /*! * \brief Gets the volume of the emitter * \param volume Float between [0, inf) with 100.f being the default */ float SoundEmitter::GetVolume() const { NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); ALfloat gain; alGetSourcef(m_source, AL_GAIN, &gain); return gain * 100.f; } /*! * \brief Checks whether the sound emitter has spatialization enabled * \return true if it the case */ bool SoundEmitter::IsSpatialized() const { NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); ALint relative; alGetSourcei(m_source, AL_SOURCE_RELATIVE, &relative); return relative == AL_FALSE; } /*! * \brief Sets the attenuation * * \param attenuation Amount that your sound will drop off as by the inverse square law */ void SoundEmitter::SetAttenuation(float attenuation) { NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); alSourcef(m_source, AL_ROLLOFF_FACTOR, attenuation); } /*! * \brief Sets the minimum distance to hear * * \param minDistance to begin to hear */ void SoundEmitter::SetMinDistance(float minDistance) { NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); alSourcef(m_source, AL_REFERENCE_DISTANCE, minDistance); } /*! * \brief Sets the pitch * * \param pitch of the sound */ void SoundEmitter::SetPitch(float pitch) { NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); alSourcef(m_source, AL_PITCH, pitch); } /*! * \brief Sets the position of the emitter * * \param position Position of the sound */ void SoundEmitter::SetPosition(const Vector3f& position) { NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); alSourcefv(m_source, AL_POSITION, &position.x); } /*! * \brief Sets the position of the emitter * * \param position Position of the sound with (x, y, z) */ void SoundEmitter::SetPosition(float x, float y, float z) { NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); alSource3f(m_source, AL_POSITION, x, y, z); } /*! * \brief Sets the velocity of the emitter * * \param velocity Velocity of the sound */ void SoundEmitter::SetVelocity(const Vector3f& velocity) { NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); alSourcefv(m_source, AL_VELOCITY, &velocity.x); } /*! * \brief Sets the velocity of the emitter * * \param velocity Velocity with (velX, velY, velZ) */ void SoundEmitter::SetVelocity(float velX, float velY, float velZ) { NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); alSource3f(m_source, AL_VELOCITY, velX, velY, velZ); } /*! * \brief Sets the volume of the emitter * * \param volume Float between [0, inf) with 100.f being the default */ void SoundEmitter::SetVolume(float volume) { NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); alSourcef(m_source, AL_GAIN, volume * 0.01f); } /*! * \brief Assign a sound emitter by moving it * * \param emitter SoundEmitter to move * * \return *this */ SoundEmitter& SoundEmitter::operator=(SoundEmitter&& emitter) noexcept { std::swap(m_source, emitter.m_source); return *this; } /*! * \brief Gets the status of the sound emitter * \return Enumeration of type SoundStatus (Playing, Stopped, ...) */ SoundStatus SoundEmitter::GetInternalStatus() const { NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); ALint state; alGetSourcei(m_source, AL_SOURCE_STATE, &state); switch (state) { case AL_INITIAL: case AL_STOPPED: return SoundStatus_Stopped; case AL_PAUSED: return SoundStatus_Paused; case AL_PLAYING: return SoundStatus_Playing; default: NazaraInternalError("Source state unrecognized"); } return SoundStatus_Stopped; } }