Audio: Add dummy device (in case OpenAL fails to load) and unifiate unit tests
This commit is contained in:
parent
efa2c0a253
commit
82641c6653
|
|
@ -24,7 +24,10 @@ int main()
|
|||
if (!std::filesystem::is_directory(resourceDir) && std::filesystem::is_directory(".." / resourceDir))
|
||||
resourceDir = ".." / resourceDir;
|
||||
|
||||
Nz::Modules<Nz::Audio, Nz::Platform> audio;
|
||||
Nz::Audio::Config config;
|
||||
config.noAudio = true;
|
||||
|
||||
Nz::Modules<Nz::Audio, Nz::Platform> audio(config);
|
||||
|
||||
Nz::Sound sound;
|
||||
if (!sound.LoadFromFile(resourceDir / "siren.wav"))
|
||||
|
|
|
|||
|
|
@ -18,7 +18,10 @@ int main()
|
|||
if (!std::filesystem::is_directory(resourceDir) && std::filesystem::is_directory(".." / resourceDir))
|
||||
resourceDir = ".." / resourceDir;
|
||||
|
||||
Nz::Modules<Nz::Audio> audio;
|
||||
Nz::Audio::Config config;
|
||||
config.noAudio = true;
|
||||
|
||||
Nz::Modules<Nz::Audio> audio(config);
|
||||
|
||||
Nz::SoundStreamParams streamParams;
|
||||
streamParams.forceMono = false;
|
||||
|
|
|
|||
|
|
@ -23,9 +23,9 @@ namespace Nz
|
|||
public:
|
||||
using Dependencies = TypeList<Core>;
|
||||
|
||||
struct Config {};
|
||||
struct Config;
|
||||
|
||||
Audio(Config /*config*/);
|
||||
Audio(Config config);
|
||||
Audio(const Audio&) = delete;
|
||||
Audio(Audio&&) = delete;
|
||||
~Audio();
|
||||
|
|
@ -45,10 +45,17 @@ namespace Nz
|
|||
Audio& operator=(const Audio&) = delete;
|
||||
Audio& operator=(Audio&&) = delete;
|
||||
|
||||
struct Config
|
||||
{
|
||||
bool allowDummyDevice = true;
|
||||
bool noAudio = false;
|
||||
};
|
||||
|
||||
private:
|
||||
std::shared_ptr<AudioDevice> m_defaultDevice;
|
||||
SoundBufferLoader m_soundBufferLoader;
|
||||
SoundStreamLoader m_soundStreamLoader;
|
||||
bool m_hasDummyDevice;
|
||||
|
||||
static Audio* s_instance;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ namespace Nz
|
|||
virtual ~AudioBuffer();
|
||||
|
||||
inline const std::shared_ptr<AudioDevice>& GetAudioDevice() const;
|
||||
virtual UInt32 GetSampleCount() const = 0;
|
||||
virtual UInt32 GetSize() const = 0;
|
||||
virtual UInt64 GetSampleCount() const = 0;
|
||||
virtual UInt64 GetSize() const = 0;
|
||||
virtual UInt32 GetSampleRate() const = 0;
|
||||
|
||||
virtual bool IsCompatibleWith(const AudioDevice& device) const = 0;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||
// 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_DUMMYAUDIOBUFFER_HPP
|
||||
#define NAZARA_AUDIO_DUMMYAUDIOBUFFER_HPP
|
||||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Audio/AudioBuffer.hpp>
|
||||
#include <Nazara/Audio/Config.hpp>
|
||||
#include <Nazara/Audio/Enums.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class NAZARA_AUDIO_API DummyAudioBuffer final : public AudioBuffer
|
||||
{
|
||||
public:
|
||||
using AudioBuffer::AudioBuffer;
|
||||
DummyAudioBuffer(const DummyAudioBuffer&) = delete;
|
||||
DummyAudioBuffer(DummyAudioBuffer&&) = delete;
|
||||
~DummyAudioBuffer() = default;
|
||||
|
||||
AudioFormat GetAudioFormat() const;
|
||||
UInt32 GetDuration() const;
|
||||
UInt64 GetSampleCount() const override;
|
||||
UInt64 GetSize() const override;
|
||||
UInt32 GetSampleRate() const override;
|
||||
|
||||
bool IsCompatibleWith(const AudioDevice& device) const override;
|
||||
|
||||
bool Reset(AudioFormat format, UInt64 sampleCount, UInt32 sampleRate, const void* samples) override;
|
||||
|
||||
DummyAudioBuffer& operator=(const DummyAudioBuffer&) = delete;
|
||||
DummyAudioBuffer& operator=(DummyAudioBuffer&&) = delete;
|
||||
|
||||
private:
|
||||
AudioFormat m_format;
|
||||
UInt64 m_sampleCount;
|
||||
UInt32 m_sampleRate;
|
||||
};
|
||||
}
|
||||
|
||||
#include <Nazara/Audio/DummyAudioBuffer.inl>
|
||||
|
||||
#endif // NAZARA_AUDIO_DUMMYAUDIOBUFFER_HPP
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||
// This file is part of the "Nazara Engine - Audio module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Audio/DummyAudioBuffer.hpp>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
}
|
||||
|
||||
#include <Nazara/Audio/DebugOff.hpp>
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||
// 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_DUMMYAUDIODEVICE_HPP
|
||||
#define NAZARA_AUDIO_DUMMYAUDIODEVICE_HPP
|
||||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Audio/AudioDevice.hpp>
|
||||
#include <Nazara/Audio/Config.hpp>
|
||||
#include <Nazara/Audio/Enums.hpp>
|
||||
#include <array>
|
||||
#include <string>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class NAZARA_AUDIO_API DummyAudioDevice : public AudioDevice
|
||||
{
|
||||
public:
|
||||
DummyAudioDevice();
|
||||
DummyAudioDevice(const DummyAudioDevice&) = delete;
|
||||
DummyAudioDevice(DummyAudioDevice&&) = default;
|
||||
~DummyAudioDevice() = default;
|
||||
|
||||
std::shared_ptr<AudioBuffer> CreateBuffer() override;
|
||||
std::shared_ptr<AudioSource> CreateSource() override;
|
||||
|
||||
float GetDopplerFactor() const override;
|
||||
float GetGlobalVolume() const override;
|
||||
Vector3f GetListenerDirection(Vector3f* up = nullptr) const override;
|
||||
Vector3f GetListenerPosition() const override;
|
||||
Quaternionf GetListenerRotation() const override;
|
||||
Vector3f GetListenerVelocity() const override;
|
||||
float GetSpeedOfSound() const override;
|
||||
const void* GetSubSystemIdentifier() const override;
|
||||
|
||||
bool IsFormatSupported(AudioFormat format) const override;
|
||||
|
||||
void SetDopplerFactor(float dopplerFactor) override;
|
||||
void SetGlobalVolume(float volume) override;
|
||||
void SetListenerDirection(const Vector3f& direction, const Vector3f& up = Vector3f::Up()) override;
|
||||
void SetListenerPosition(const Vector3f& position) override;
|
||||
void SetListenerVelocity(const Vector3f& velocity) override;
|
||||
void SetSpeedOfSound(float speed) override;
|
||||
|
||||
DummyAudioDevice& operator=(const DummyAudioDevice&) = delete;
|
||||
DummyAudioDevice& operator=(DummyAudioDevice&&) = default;
|
||||
|
||||
private:
|
||||
Quaternionf m_listenerRotation;
|
||||
Vector3f m_listenerVelocity;
|
||||
Vector3f m_listenerPosition;
|
||||
float m_dopplerFactor;
|
||||
float m_globalVolume;
|
||||
float m_speedOfSound;
|
||||
};
|
||||
}
|
||||
|
||||
#include <Nazara/Audio/DummyAudioDevice.inl>
|
||||
|
||||
#endif // NAZARA_AUDIO_DUMMYAUDIODEVICE_HPP
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||
// This file is part of the "Nazara Engine - Audio module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Audio/DummyAudioDevice.hpp>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
}
|
||||
|
||||
#include <Nazara/Audio/DebugOff.hpp>
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||
// 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_DUMMYAUDIOSOURCE_HPP
|
||||
#define NAZARA_AUDIO_DUMMYAUDIOSOURCE_HPP
|
||||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Audio/AudioSource.hpp>
|
||||
#include <Nazara/Audio/Config.hpp>
|
||||
#include <Nazara/Core/Clock.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class DummyAudioBuffer;
|
||||
|
||||
class NAZARA_AUDIO_API DummyAudioSource final : public AudioSource
|
||||
{
|
||||
public:
|
||||
inline DummyAudioSource(std::shared_ptr<AudioDevice> device);
|
||||
DummyAudioSource(const DummyAudioSource&) = delete;
|
||||
DummyAudioSource(DummyAudioSource&&) = delete;
|
||||
~DummyAudioSource() = default;
|
||||
|
||||
void EnableLooping(bool loop) override;
|
||||
void EnableSpatialization(bool spatialization) override;
|
||||
|
||||
float GetAttenuation() const override;
|
||||
float GetMinDistance() const override;
|
||||
float GetPitch() const override;
|
||||
Vector3f GetPosition() const override;
|
||||
UInt32 GetSampleOffset() const override;
|
||||
Vector3f GetVelocity() const override;
|
||||
SoundStatus GetStatus() const override;
|
||||
float GetVolume() const override;
|
||||
|
||||
bool IsLooping() const override;
|
||||
bool IsSpatializationEnabled() const override;
|
||||
|
||||
void QueueBuffer(std::shared_ptr<AudioBuffer> audioBuffer) override;
|
||||
|
||||
void Pause() override;
|
||||
void Play() override;
|
||||
|
||||
void SetAttenuation(float attenuation) override;
|
||||
void SetBuffer(std::shared_ptr<AudioBuffer> audioBuffer) override;
|
||||
void SetMinDistance(float minDistance) override;
|
||||
void SetPitch(float pitch) override;
|
||||
void SetPosition(const Vector3f& position) override;
|
||||
void SetSampleOffset(UInt32 offset) override;
|
||||
void SetVelocity(const Vector3f& velocity) override;
|
||||
void SetVolume(float volume) override;
|
||||
|
||||
void Stop() override;
|
||||
|
||||
std::shared_ptr<AudioBuffer> TryUnqueueProcessedBuffer() override;
|
||||
|
||||
void UnqueueAllBuffers() override;
|
||||
|
||||
DummyAudioSource& operator=(const DummyAudioSource&) = delete;
|
||||
DummyAudioSource& operator=(DummyAudioSource&&) = delete;
|
||||
|
||||
private:
|
||||
void RequeueBuffers();
|
||||
UInt64 UpdateTime() const;
|
||||
|
||||
mutable std::vector<std::shared_ptr<DummyAudioBuffer>> m_queuedBuffers;
|
||||
mutable std::vector<std::shared_ptr<DummyAudioBuffer>> m_processedBuffers;
|
||||
mutable Clock m_playClock;
|
||||
mutable SoundStatus m_status;
|
||||
Vector3f m_position;
|
||||
Vector3f m_velocity;
|
||||
bool m_isLooping;
|
||||
bool m_isSpatialized;
|
||||
float m_attenuation;
|
||||
float m_minDistance;
|
||||
float m_pitch;
|
||||
float m_volume;
|
||||
};
|
||||
}
|
||||
|
||||
#include <Nazara/Audio/DummyAudioSource.inl>
|
||||
|
||||
#endif // NAZARA_AUDIO_DUMMYAUDIOSOURCE_HPP
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||
// This file is part of the "Nazara Engine - Audio module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Audio/DummyAudioSource.hpp>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
inline DummyAudioSource::DummyAudioSource(std::shared_ptr<AudioDevice> device) :
|
||||
AudioSource(std::move(device)),
|
||||
m_playClock(0, true),
|
||||
m_status(SoundStatus::Stopped),
|
||||
m_position(Vector3f::Zero()),
|
||||
m_velocity(Vector3f::Zero()),
|
||||
m_isLooping(false),
|
||||
m_isSpatialized(true),
|
||||
m_attenuation(1.f),
|
||||
m_minDistance(1.f),
|
||||
m_pitch(1.f),
|
||||
m_volume(1.f)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
#include <Nazara/Audio/DebugOff.hpp>
|
||||
|
|
@ -73,7 +73,8 @@ namespace Nz
|
|||
bool m_looping;
|
||||
|
||||
bool FillAndQueueBuffer(std::shared_ptr<AudioBuffer> buffer);
|
||||
void MusicThread(std::condition_variable& cv, std::mutex& m, std::exception_ptr& err);
|
||||
void MusicThread(std::condition_variable& cv, std::mutex& m, std::exception_ptr& err, bool startPaused);
|
||||
void StartThread(bool startPaused);
|
||||
void StopThread();
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ namespace Nz
|
|||
~OpenALBuffer();
|
||||
|
||||
inline ALuint GetBufferId() const;
|
||||
UInt32 GetSampleCount() const override;
|
||||
UInt32 GetSize() const override;
|
||||
UInt64 GetSampleCount() const override;
|
||||
UInt64 GetSize() const override;
|
||||
UInt32 GetSampleRate() const override;
|
||||
|
||||
bool IsCompatibleWith(const AudioDevice& device) const override;
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@ namespace Nz
|
|||
OpenALLibrary(OpenALLibrary&&) = delete;
|
||||
inline ~OpenALLibrary();
|
||||
|
||||
inline bool IsLoaded() const;
|
||||
|
||||
bool Load();
|
||||
|
||||
std::vector<std::string> QueryInputDevices();
|
||||
|
|
@ -49,6 +51,7 @@ namespace Nz
|
|||
std::vector<std::string> ParseDevices(const char* deviceString);
|
||||
|
||||
DynLib m_library;
|
||||
bool m_hasCaptureSupport;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,11 @@ namespace Nz
|
|||
{
|
||||
Unload();
|
||||
}
|
||||
|
||||
inline bool OpenALLibrary::IsLoaded() const
|
||||
{
|
||||
return m_library.IsLoaded();
|
||||
}
|
||||
}
|
||||
|
||||
#include <Nazara/Audio/DebugOff.hpp>
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ namespace Nz
|
|||
bool IsPaused() const;
|
||||
|
||||
void Pause();
|
||||
UInt64 Restart();
|
||||
UInt64 Restart(UInt64 startingValue = 0, bool paused = false);
|
||||
void Unpause();
|
||||
|
||||
Clock& operator=(const Clock& clock) = default;
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ namespace Nz
|
|||
|
||||
struct Config
|
||||
{
|
||||
Nz::RenderAPI preferredAPI = RenderAPI::Unknown;
|
||||
RenderAPI preferredAPI = RenderAPI::Unknown;
|
||||
};
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <Nazara/Audio/AudioBuffer.hpp>
|
||||
#include <Nazara/Audio/AudioSource.hpp>
|
||||
#include <Nazara/Audio/Config.hpp>
|
||||
#include <Nazara/Audio/DummyAudioDevice.hpp>
|
||||
#include <Nazara/Audio/Enums.hpp>
|
||||
#include <Nazara/Audio/OpenALLibrary.hpp>
|
||||
#include <Nazara/Audio/Formats/drwavLoader.hpp>
|
||||
|
|
@ -32,11 +33,12 @@ namespace Nz
|
|||
* \brief Audio class that represents the module initializer of Audio
|
||||
*/
|
||||
|
||||
Audio::Audio(Config /*config*/) :
|
||||
ModuleBase("Audio", this)
|
||||
Audio::Audio(Config config) :
|
||||
ModuleBase("Audio", this),
|
||||
m_hasDummyDevice(config.allowDummyDevice)
|
||||
{
|
||||
// Load OpenAL
|
||||
if (!s_openalLibrary.Load())
|
||||
if (!config.noAudio && !s_openalLibrary.Load())
|
||||
throw std::runtime_error("failed to load OpenAL");
|
||||
|
||||
// Loaders
|
||||
|
|
@ -49,7 +51,10 @@ namespace Nz
|
|||
m_soundBufferLoader.RegisterLoader(Loaders::GetSoundBufferLoader_minimp3());
|
||||
m_soundStreamLoader.RegisterLoader(Loaders::GetSoundStreamLoader_minimp3());
|
||||
|
||||
m_defaultDevice = s_openalLibrary.OpenDevice();
|
||||
if (s_openalLibrary.IsLoaded())
|
||||
m_defaultDevice = s_openalLibrary.OpenDevice();
|
||||
else
|
||||
m_defaultDevice = std::make_shared<DummyAudioDevice>();
|
||||
}
|
||||
|
||||
Audio::~Audio()
|
||||
|
|
@ -101,17 +106,30 @@ namespace Nz
|
|||
|
||||
std::shared_ptr<AudioDevice> Audio::OpenOutputDevice(const std::string& deviceName)
|
||||
{
|
||||
if (deviceName == "dummy")
|
||||
return std::make_shared<DummyAudioDevice>();
|
||||
|
||||
return s_openalLibrary.OpenDevice(deviceName.c_str());
|
||||
}
|
||||
|
||||
std::vector<std::string> Audio::QueryInputDevices() const
|
||||
{
|
||||
if (!s_openalLibrary.IsLoaded())
|
||||
return {};
|
||||
|
||||
return s_openalLibrary.QueryInputDevices();
|
||||
}
|
||||
|
||||
std::vector<std::string> Audio::QueryOutputDevices() const
|
||||
{
|
||||
return s_openalLibrary.QueryOutputDevices();
|
||||
std::vector<std::string> outputDevices;
|
||||
if (s_openalLibrary.IsLoaded())
|
||||
outputDevices = s_openalLibrary.QueryOutputDevices();
|
||||
|
||||
if (m_hasDummyDevice)
|
||||
outputDevices.push_back("dummy");
|
||||
|
||||
return outputDevices;
|
||||
}
|
||||
|
||||
Audio* Audio::s_instance = nullptr;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||
// This file is part of the "Nazara Engine - Audio module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Audio/DummyAudioBuffer.hpp>
|
||||
#include <Nazara/Audio/Algorithm.hpp>
|
||||
#include <Nazara/Audio/AudioDevice.hpp>
|
||||
#include <Nazara/Core/Algorithm.hpp>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
AudioFormat DummyAudioBuffer::GetAudioFormat() const
|
||||
{
|
||||
return m_format;
|
||||
}
|
||||
|
||||
UInt32 DummyAudioBuffer::GetDuration() const
|
||||
{
|
||||
return SafeCast<UInt32>((1000ULL * m_sampleCount / (GetChannelCount(m_format) * m_sampleRate)));
|
||||
}
|
||||
|
||||
UInt64 DummyAudioBuffer::GetSampleCount() const
|
||||
{
|
||||
return m_sampleCount;
|
||||
}
|
||||
|
||||
UInt64 DummyAudioBuffer::GetSize() const
|
||||
{
|
||||
return m_sampleCount * sizeof(Int16);
|
||||
}
|
||||
|
||||
UInt32 DummyAudioBuffer::GetSampleRate() const
|
||||
{
|
||||
return m_sampleRate;
|
||||
}
|
||||
|
||||
bool DummyAudioBuffer::IsCompatibleWith(const AudioDevice& device) const
|
||||
{
|
||||
return GetAudioDevice()->GetSubSystemIdentifier() == device.GetSubSystemIdentifier();
|
||||
}
|
||||
|
||||
bool DummyAudioBuffer::Reset(AudioFormat format, UInt64 sampleCount, UInt32 sampleRate, const void* /*samples*/)
|
||||
{
|
||||
m_format = format;
|
||||
m_sampleCount = sampleCount;
|
||||
m_sampleRate = sampleRate;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||
// This file is part of the "Nazara Engine - Audio module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Audio/DummyAudioDevice.hpp>
|
||||
#include <Nazara/Audio/DummyAudioBuffer.hpp>
|
||||
#include <Nazara/Audio/DummyAudioSource.hpp>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
DummyAudioDevice::DummyAudioDevice() :
|
||||
m_listenerRotation(Quaternionf::Identity()),
|
||||
m_listenerPosition(Vector3f::Zero()),
|
||||
m_dopplerFactor(1.f),
|
||||
m_globalVolume(1.f),
|
||||
m_speedOfSound(343.3f)
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<AudioBuffer> DummyAudioDevice::CreateBuffer()
|
||||
{
|
||||
return std::make_shared<DummyAudioBuffer>(shared_from_this());
|
||||
}
|
||||
|
||||
std::shared_ptr<AudioSource> DummyAudioDevice::CreateSource()
|
||||
{
|
||||
return std::make_shared<DummyAudioSource>(shared_from_this());
|
||||
}
|
||||
|
||||
float DummyAudioDevice::GetDopplerFactor() const
|
||||
{
|
||||
return m_dopplerFactor;
|
||||
}
|
||||
|
||||
float DummyAudioDevice::GetGlobalVolume() const
|
||||
{
|
||||
return m_globalVolume;
|
||||
}
|
||||
|
||||
Vector3f DummyAudioDevice::GetListenerDirection(Vector3f* up) const
|
||||
{
|
||||
if (up)
|
||||
*up = m_listenerRotation * Vector3f::Up();
|
||||
|
||||
return m_listenerRotation * Vector3f::Forward();
|
||||
}
|
||||
|
||||
Vector3f DummyAudioDevice::GetListenerPosition() const
|
||||
{
|
||||
return m_listenerPosition;
|
||||
}
|
||||
|
||||
Quaternionf DummyAudioDevice::GetListenerRotation() const
|
||||
{
|
||||
return m_listenerRotation;
|
||||
}
|
||||
|
||||
Vector3f DummyAudioDevice::GetListenerVelocity() const
|
||||
{
|
||||
return m_listenerVelocity;
|
||||
}
|
||||
|
||||
float DummyAudioDevice::GetSpeedOfSound() const
|
||||
{
|
||||
return m_speedOfSound;
|
||||
}
|
||||
|
||||
const void* DummyAudioDevice::GetSubSystemIdentifier() const
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
bool DummyAudioDevice::IsFormatSupported(AudioFormat /*format*/) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void DummyAudioDevice::SetDopplerFactor(float dopplerFactor)
|
||||
{
|
||||
m_dopplerFactor = dopplerFactor;
|
||||
}
|
||||
|
||||
void DummyAudioDevice::SetGlobalVolume(float volume)
|
||||
{
|
||||
m_globalVolume = volume;
|
||||
}
|
||||
|
||||
void DummyAudioDevice::SetListenerDirection(const Vector3f& direction, const Vector3f& up)
|
||||
{
|
||||
m_listenerRotation = Quaternionf::LookAt(direction, up);
|
||||
}
|
||||
|
||||
void DummyAudioDevice::SetListenerPosition(const Vector3f& position)
|
||||
{
|
||||
m_listenerPosition = position;
|
||||
}
|
||||
|
||||
void DummyAudioDevice::SetListenerVelocity(const Vector3f& velocity)
|
||||
{
|
||||
m_listenerVelocity = velocity;
|
||||
}
|
||||
|
||||
void DummyAudioDevice::SetSpeedOfSound(float speed)
|
||||
{
|
||||
m_speedOfSound = speed;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,262 @@
|
|||
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||
// This file is part of the "Nazara Engine - Audio module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Audio/DummyAudioSource.hpp>
|
||||
#include <Nazara/Audio/Algorithm.hpp>
|
||||
#include <Nazara/Audio/DummyAudioBuffer.hpp>
|
||||
#include <Nazara/Core/Algorithm.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/Log.hpp>
|
||||
#include <Nazara/Core/StackArray.hpp>
|
||||
#include <algorithm>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
void DummyAudioSource::EnableLooping(bool loop)
|
||||
{
|
||||
m_isLooping = loop;
|
||||
}
|
||||
|
||||
void DummyAudioSource::EnableSpatialization(bool spatialization)
|
||||
{
|
||||
m_isSpatialized = spatialization;
|
||||
}
|
||||
|
||||
float DummyAudioSource::GetAttenuation() const
|
||||
{
|
||||
return m_attenuation;
|
||||
}
|
||||
|
||||
float DummyAudioSource::GetMinDistance() const
|
||||
{
|
||||
return m_minDistance;
|
||||
}
|
||||
|
||||
float DummyAudioSource::GetPitch() const
|
||||
{
|
||||
return m_pitch;
|
||||
}
|
||||
|
||||
Vector3f DummyAudioSource::GetPosition() const
|
||||
{
|
||||
return m_position;
|
||||
}
|
||||
|
||||
UInt32 DummyAudioSource::GetSampleOffset() const
|
||||
{
|
||||
UInt64 bufferTime = UpdateTime();
|
||||
|
||||
UInt64 sampleOffset = 0;
|
||||
// All processed buffers count in sample offset
|
||||
for (const auto& processedBuffer : m_processedBuffers)
|
||||
sampleOffset += processedBuffer->GetSampleCount() / GetChannelCount(processedBuffer->GetAudioFormat());
|
||||
|
||||
if (!m_queuedBuffers.empty())
|
||||
{
|
||||
auto& frontBuffer = m_queuedBuffers.front();
|
||||
UInt64 bufferOffset = bufferTime * frontBuffer->GetSampleRate() / 1000;
|
||||
UInt64 bufferDuration = frontBuffer->GetSampleCount() / GetChannelCount(frontBuffer->GetAudioFormat());
|
||||
|
||||
sampleOffset += std::min(bufferOffset, bufferDuration);
|
||||
}
|
||||
|
||||
return SafeCast<UInt32>(sampleOffset);
|
||||
}
|
||||
|
||||
Vector3f DummyAudioSource::GetVelocity() const
|
||||
{
|
||||
return m_velocity;
|
||||
}
|
||||
|
||||
SoundStatus DummyAudioSource::GetStatus() const
|
||||
{
|
||||
UpdateTime();
|
||||
|
||||
return m_status;
|
||||
}
|
||||
|
||||
float DummyAudioSource::GetVolume() const
|
||||
{
|
||||
return m_volume;
|
||||
}
|
||||
|
||||
bool DummyAudioSource::IsLooping() const
|
||||
{
|
||||
return m_isLooping;
|
||||
}
|
||||
|
||||
bool DummyAudioSource::IsSpatializationEnabled() const
|
||||
{
|
||||
return m_isSpatialized;
|
||||
}
|
||||
|
||||
void DummyAudioSource::QueueBuffer(std::shared_ptr<AudioBuffer> audioBuffer)
|
||||
{
|
||||
NazaraAssert(audioBuffer, "invalid buffer");
|
||||
NazaraAssert(audioBuffer->IsCompatibleWith(*GetAudioDevice()), "incompatible buffer");
|
||||
|
||||
m_queuedBuffers.emplace_back(std::static_pointer_cast<DummyAudioBuffer>(audioBuffer));
|
||||
}
|
||||
|
||||
void DummyAudioSource::Pause()
|
||||
{
|
||||
m_playClock.Pause();
|
||||
m_status = SoundStatus::Paused;
|
||||
}
|
||||
|
||||
void DummyAudioSource::Play()
|
||||
{
|
||||
if (m_status == SoundStatus::Paused)
|
||||
m_playClock.Unpause();
|
||||
else
|
||||
{
|
||||
// playing or stopped, restart
|
||||
RequeueBuffers();
|
||||
m_playClock.Restart();
|
||||
}
|
||||
|
||||
m_status = SoundStatus::Playing;
|
||||
}
|
||||
|
||||
void DummyAudioSource::SetAttenuation(float attenuation)
|
||||
{
|
||||
m_attenuation = attenuation;
|
||||
}
|
||||
|
||||
void DummyAudioSource::SetBuffer(std::shared_ptr<AudioBuffer> audioBuffer)
|
||||
{
|
||||
NazaraAssert(audioBuffer->IsCompatibleWith(*GetAudioDevice()), "incompatible buffer");
|
||||
|
||||
m_queuedBuffers.clear();
|
||||
m_queuedBuffers.emplace_back(std::static_pointer_cast<DummyAudioBuffer>(audioBuffer));
|
||||
m_processedBuffers.clear();
|
||||
}
|
||||
|
||||
void DummyAudioSource::SetMinDistance(float minDistance)
|
||||
{
|
||||
m_minDistance = minDistance;
|
||||
}
|
||||
|
||||
void DummyAudioSource::SetPitch(float pitch)
|
||||
{
|
||||
m_pitch = pitch;
|
||||
}
|
||||
|
||||
void DummyAudioSource::SetPosition(const Vector3f& position)
|
||||
{
|
||||
m_position = position;
|
||||
}
|
||||
|
||||
void DummyAudioSource::SetSampleOffset(UInt32 offset)
|
||||
{
|
||||
RequeueBuffers();
|
||||
|
||||
if (m_queuedBuffers.empty())
|
||||
return;
|
||||
|
||||
std::size_t processedBufferIndex = 0;
|
||||
for (; processedBufferIndex < m_queuedBuffers.size(); ++processedBufferIndex)
|
||||
{
|
||||
UInt32 bufferFrameCount = m_queuedBuffers[processedBufferIndex]->GetSampleCount() / GetChannelCount(m_queuedBuffers[processedBufferIndex]->GetAudioFormat());
|
||||
if (offset < bufferFrameCount)
|
||||
break;
|
||||
|
||||
offset -= bufferFrameCount;
|
||||
m_processedBuffers.emplace_back(std::move(m_queuedBuffers[processedBufferIndex]));
|
||||
}
|
||||
m_queuedBuffers.erase(m_queuedBuffers.begin(), m_queuedBuffers.begin() + processedBufferIndex);
|
||||
|
||||
assert(!m_queuedBuffers.empty());
|
||||
|
||||
UInt64 timeOffset = 1'000'000ULL * offset / m_queuedBuffers.front()->GetSampleRate();
|
||||
m_playClock.Restart(timeOffset, m_playClock.IsPaused());
|
||||
}
|
||||
|
||||
void DummyAudioSource::SetVelocity(const Vector3f& velocity)
|
||||
{
|
||||
m_velocity = velocity;
|
||||
}
|
||||
|
||||
void DummyAudioSource::SetVolume(float volume)
|
||||
{
|
||||
m_volume = volume;
|
||||
}
|
||||
|
||||
void DummyAudioSource::Stop()
|
||||
{
|
||||
m_playClock.Restart(0, true);
|
||||
}
|
||||
|
||||
std::shared_ptr<AudioBuffer> DummyAudioSource::TryUnqueueProcessedBuffer()
|
||||
{
|
||||
UpdateTime();
|
||||
|
||||
if (m_processedBuffers.empty())
|
||||
return {};
|
||||
|
||||
auto processedBuffer = std::move(m_processedBuffers.front());
|
||||
m_processedBuffers.erase(m_processedBuffers.begin());
|
||||
|
||||
return processedBuffer;
|
||||
}
|
||||
|
||||
void DummyAudioSource::UnqueueAllBuffers()
|
||||
{
|
||||
m_processedBuffers.clear();
|
||||
m_queuedBuffers.clear();
|
||||
Stop();
|
||||
}
|
||||
|
||||
void DummyAudioSource::RequeueBuffers()
|
||||
{
|
||||
// Put back all processed buffers in the queued buffer queue (for simplicity)
|
||||
if (!m_processedBuffers.empty())
|
||||
{
|
||||
m_queuedBuffers.resize(m_processedBuffers.size() + m_queuedBuffers.size());
|
||||
std::move(m_queuedBuffers.begin(), m_queuedBuffers.begin() + m_processedBuffers.size(), m_queuedBuffers.begin() + m_processedBuffers.size());
|
||||
std::move(m_processedBuffers.begin(), m_processedBuffers.end(), m_queuedBuffers.begin());
|
||||
m_processedBuffers.clear();
|
||||
}
|
||||
}
|
||||
|
||||
UInt64 DummyAudioSource::UpdateTime() const
|
||||
{
|
||||
UInt64 currentTime = m_playClock.GetMilliseconds();
|
||||
|
||||
while (!m_queuedBuffers.empty() && currentTime >= m_queuedBuffers.front()->GetDuration())
|
||||
{
|
||||
auto processedBuffer = std::move(m_queuedBuffers.front());
|
||||
m_queuedBuffers.erase(m_queuedBuffers.begin());
|
||||
|
||||
currentTime -= processedBuffer->GetDuration();
|
||||
|
||||
m_processedBuffers.emplace_back(std::move(processedBuffer));
|
||||
}
|
||||
|
||||
if (m_queuedBuffers.empty())
|
||||
{
|
||||
// If looping, replay processed buffers
|
||||
if (m_isLooping)
|
||||
{
|
||||
while (!m_processedBuffers.empty())
|
||||
{
|
||||
auto queuedBuffer = std::move(m_processedBuffers.front());
|
||||
m_processedBuffers.erase(m_processedBuffers.begin());
|
||||
|
||||
m_queuedBuffers.emplace_back(std::move(queuedBuffer));
|
||||
if (m_queuedBuffers.back()->GetDuration() > currentTime)
|
||||
break;
|
||||
|
||||
currentTime -= m_queuedBuffers.back()->GetDuration();
|
||||
}
|
||||
}
|
||||
else
|
||||
m_status = SoundStatus::Stopped;
|
||||
}
|
||||
|
||||
m_playClock.Restart(currentTime * 1000, m_playClock.IsPaused()); //< Adjust time
|
||||
return currentTime;
|
||||
}
|
||||
}
|
||||
|
|
@ -133,7 +133,6 @@ namespace Nz
|
|||
std::lock_guard<std::mutex> lock(m_bufferLock);
|
||||
|
||||
UInt32 sampleOffset = m_source->GetSampleOffset();
|
||||
|
||||
return static_cast<UInt32>((1000ULL * (sampleOffset + (m_processedSamples / GetChannelCount(m_stream->GetFormat())))) / m_sampleRate);
|
||||
}
|
||||
|
||||
|
|
@ -173,6 +172,8 @@ namespace Nz
|
|||
{
|
||||
NazaraAssert(m_stream, "Music not created");
|
||||
|
||||
std::lock_guard<std::mutex> lock(m_bufferLock);
|
||||
|
||||
SoundStatus status = m_source->GetStatus();
|
||||
|
||||
// To compensate any delays (or the timelaps between Play() and the thread startup)
|
||||
|
|
@ -250,6 +251,8 @@ namespace Nz
|
|||
*/
|
||||
void Music::Pause()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_bufferLock);
|
||||
|
||||
m_source->Pause();
|
||||
}
|
||||
|
||||
|
|
@ -285,24 +288,7 @@ namespace Nz
|
|||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::mutex mutex;
|
||||
std::condition_variable cv;
|
||||
|
||||
// Starting streaming thread
|
||||
m_streaming = true;
|
||||
|
||||
std::exception_ptr exceptionPtr;
|
||||
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
m_thread = std::thread(&Music::MusicThread, this, std::ref(cv), std::ref(mutex), std::ref(exceptionPtr));
|
||||
|
||||
// Wait until thread signal it has properly started (or an error occurred)
|
||||
cv.wait(lock);
|
||||
|
||||
if (exceptionPtr)
|
||||
std::rethrow_exception(exceptionPtr);
|
||||
}
|
||||
StartThread(false);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -319,9 +305,10 @@ namespace Nz
|
|||
NazaraAssert(m_stream, "Music not created");
|
||||
|
||||
bool isPlaying = m_streaming;
|
||||
bool isPaused = GetStatus() == SoundStatus::Paused;
|
||||
|
||||
if (isPlaying)
|
||||
Stop();
|
||||
StopThread();
|
||||
|
||||
UInt64 sampleOffset = UInt64(offset) * m_sampleRate * GetChannelCount(m_stream->GetFormat()) / 1000ULL;
|
||||
|
||||
|
|
@ -329,7 +316,7 @@ namespace Nz
|
|||
m_streamOffset = sampleOffset;
|
||||
|
||||
if (isPlaying)
|
||||
Play();
|
||||
StartThread(isPaused);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -380,7 +367,7 @@ namespace Nz
|
|||
return sampleRead != sampleCount; // End of stream (Does not happen when looping)
|
||||
}
|
||||
|
||||
void Music::MusicThread(std::condition_variable& cv, std::mutex& m, std::exception_ptr& err)
|
||||
void Music::MusicThread(std::condition_variable& cv, std::mutex& m, std::exception_ptr& err, bool startPaused)
|
||||
{
|
||||
// Allocation of streaming buffers
|
||||
CallOnExit unqueueBuffers([&]
|
||||
|
|
@ -406,8 +393,14 @@ namespace Nz
|
|||
cv.notify_all();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
m_source->Play();
|
||||
if (startPaused)
|
||||
{
|
||||
// little hack to start paused (required by SetPlayingOffset)
|
||||
m_source->Pause();
|
||||
m_source->SetSampleOffset(0);
|
||||
}
|
||||
|
||||
CallOnExit stopSource([&]
|
||||
{
|
||||
|
|
@ -424,6 +417,11 @@ namespace Nz
|
|||
// Reading loop (Filling new buffers as playing)
|
||||
while (m_streaming)
|
||||
{
|
||||
// Wait until buffers are processed
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
|
||||
std::lock_guard<std::mutex> lock(m_bufferLock);
|
||||
|
||||
SoundStatus status = m_source->GetStatus();
|
||||
if (status == SoundStatus::Stopped)
|
||||
{
|
||||
|
|
@ -432,24 +430,37 @@ namespace Nz
|
|||
break;
|
||||
}
|
||||
|
||||
// We treat read buffers
|
||||
while (std::shared_ptr<AudioBuffer> buffer = m_source->TryUnqueueProcessedBuffer())
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_bufferLock);
|
||||
m_processedSamples += buffer->GetSampleCount();
|
||||
|
||||
// We treat read buffers
|
||||
while (std::shared_ptr<AudioBuffer> buffer = m_source->TryUnqueueProcessedBuffer())
|
||||
{
|
||||
m_processedSamples += buffer->GetSampleCount();
|
||||
|
||||
if (FillAndQueueBuffer(std::move(buffer)))
|
||||
break;
|
||||
}
|
||||
if (FillAndQueueBuffer(std::move(buffer)))
|
||||
break;
|
||||
}
|
||||
|
||||
// We go back to sleep
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
}
|
||||
}
|
||||
|
||||
void Music::StartThread(bool startPaused)
|
||||
{
|
||||
std::mutex mutex;
|
||||
std::condition_variable cv;
|
||||
|
||||
// Starting streaming thread
|
||||
m_streaming = true;
|
||||
|
||||
std::exception_ptr exceptionPtr;
|
||||
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
m_thread = std::thread(&Music::MusicThread, this, std::ref(cv), std::ref(mutex), std::ref(exceptionPtr), startPaused);
|
||||
|
||||
// Wait until thread signal it has properly started (or an error occurred)
|
||||
cv.wait(lock);
|
||||
|
||||
if (exceptionPtr)
|
||||
std::rethrow_exception(exceptionPtr);
|
||||
}
|
||||
|
||||
void Music::StopThread()
|
||||
{
|
||||
if (m_streaming)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ namespace Nz
|
|||
m_library.alDeleteBuffers(1, &m_bufferId);
|
||||
}
|
||||
|
||||
UInt32 OpenALBuffer::GetSampleCount() const
|
||||
UInt64 OpenALBuffer::GetSampleCount() const
|
||||
{
|
||||
GetDevice().MakeContextCurrent();
|
||||
|
||||
|
|
@ -25,21 +25,21 @@ namespace Nz
|
|||
m_library.alGetBufferi(m_bufferId, AL_BITS, &bits);
|
||||
m_library.alGetBufferi(m_bufferId, AL_SIZE, &size);
|
||||
|
||||
UInt32 sampleCount = 0;
|
||||
UInt64 sampleCount = 0;
|
||||
if (bits != 0)
|
||||
sampleCount += (8 * SafeCast<UInt32>(size)) / SafeCast<UInt32>(bits);
|
||||
sampleCount += (8 * SafeCast<UInt64>(size)) / SafeCast<UInt64>(bits);
|
||||
|
||||
return sampleCount;
|
||||
}
|
||||
|
||||
UInt32 OpenALBuffer::GetSize() const
|
||||
UInt64 OpenALBuffer::GetSize() const
|
||||
{
|
||||
GetDevice().MakeContextCurrent();
|
||||
|
||||
ALint size;
|
||||
m_library.alGetBufferi(m_bufferId, AL_SIZE, &size);
|
||||
|
||||
return SafeCast<UInt32>(size);
|
||||
return SafeCast<UInt64>(size);
|
||||
}
|
||||
|
||||
UInt32 OpenALBuffer::GetSampleRate() const
|
||||
|
|
@ -49,7 +49,7 @@ namespace Nz
|
|||
ALint sampleRate;
|
||||
m_library.alGetBufferi(m_bufferId, AL_FREQUENCY, &sampleRate);
|
||||
|
||||
return SafeCast<UInt32>(sampleRate);
|
||||
return SafeCast<UInt64>(sampleRate);
|
||||
}
|
||||
|
||||
bool OpenALBuffer::IsCompatibleWith(const AudioDevice& device) const
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ namespace Nz
|
|||
|
||||
/*!
|
||||
* \brief Gets the global volume
|
||||
* \return Float between [0, inf) with 100.f being the default
|
||||
* \return Float between [0, inf) with 1.f being the default
|
||||
*/
|
||||
float OpenALDevice::GetGlobalVolume() const
|
||||
{
|
||||
|
|
@ -109,7 +109,7 @@ namespace Nz
|
|||
ALfloat gain = 0.f;
|
||||
m_library.alGetListenerf(AL_GAIN, &gain);
|
||||
|
||||
return gain * 100.f;
|
||||
return gain;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include <Nazara/Audio/OpenALLibrary.hpp>
|
||||
#include <Nazara/Core/Algorithm.hpp>
|
||||
#include <Nazara/Core/CallOnExit.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
#include <Nazara/Core/Log.hpp>
|
||||
|
|
@ -20,6 +21,8 @@ namespace Nz
|
|||
{
|
||||
Unload();
|
||||
|
||||
CallOnExit unloadOnFailure([this] { Unload(); });
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
std::array libs{
|
||||
"soft_oal.dll",
|
||||
|
|
@ -69,15 +72,21 @@ namespace Nz
|
|||
continue;
|
||||
}
|
||||
|
||||
unloadOnFailure.Reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
m_hasCaptureSupport = alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE");
|
||||
|
||||
NazaraError("failed to load OpenAL library");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::string> OpenALLibrary::QueryInputDevices()
|
||||
{
|
||||
if (!m_hasCaptureSupport)
|
||||
return {};
|
||||
|
||||
return ParseDevices(alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -131,10 +131,10 @@ namespace Nz
|
|||
{
|
||||
GetDevice().MakeContextCurrent();
|
||||
|
||||
ALint relative;
|
||||
m_library.alGetSourcei(m_sourceId, AL_LOOPING, &relative);
|
||||
ALint looping;
|
||||
m_library.alGetSourcei(m_sourceId, AL_LOOPING, &looping);
|
||||
|
||||
return relative == AL_FALSE;
|
||||
return looping == AL_TRUE;
|
||||
}
|
||||
|
||||
bool OpenALSource::IsSpatializationEnabled() const
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ namespace Nz
|
|||
* Restarts the clock, putting it's time counter back to zero (as if the clock got constructed).
|
||||
* It also compute the elapsed microseconds since the last Restart() call without any time loss (a problem that the combination of GetElapsedMicroseconds and Restart have).
|
||||
*/
|
||||
UInt64 Clock::Restart()
|
||||
UInt64 Clock::Restart(UInt64 startingValue, bool paused)
|
||||
{
|
||||
Nz::UInt64 now = GetElapsedMicroseconds();
|
||||
|
||||
|
|
@ -133,9 +133,9 @@ namespace Nz
|
|||
if (!m_paused)
|
||||
elapsedTime += (now - m_refTime);
|
||||
|
||||
m_elapsedTime = 0;
|
||||
m_elapsedTime = startingValue;
|
||||
m_refTime = now;
|
||||
m_paused = false;
|
||||
m_paused = paused;
|
||||
|
||||
return elapsedTime;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,15 +34,24 @@ SCENARIO("Music", "[AUDIO][MUSIC]")
|
|||
Nz::Audio::Instance()->GetDefaultDevice()->SetGlobalVolume(0.f);
|
||||
|
||||
music.Play();
|
||||
CHECK(music.GetStatus() == Nz::SoundStatus::Playing);
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
REQUIRE(music.GetPlayingOffset() >= 950);
|
||||
CHECK(music.GetPlayingOffset() >= 950);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
REQUIRE(music.GetPlayingOffset() <= 1300);
|
||||
CHECK(music.GetPlayingOffset() <= 1300);
|
||||
|
||||
music.SetPlayingOffset(4200);
|
||||
CHECK(music.GetStatus() == Nz::SoundStatus::Playing);
|
||||
CHECK(music.GetPlayingOffset() >= 4150);
|
||||
CHECK(music.GetPlayingOffset() < 4500);
|
||||
CHECK(music.GetStatus() == Nz::SoundStatus::Playing);
|
||||
|
||||
music.Pause();
|
||||
REQUIRE(music.GetStatus() == Nz::SoundStatus::Paused);
|
||||
CHECK(music.GetStatus() == Nz::SoundStatus::Paused);
|
||||
|
||||
music.SetPlayingOffset(3500);
|
||||
REQUIRE(music.GetPlayingOffset() >= 3500);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
CHECK(music.GetPlayingOffset() == 3500);
|
||||
|
||||
Nz::Audio::Instance()->GetDefaultDevice()->SetGlobalVolume(100.f);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#define CATCH_CONFIG_RUNNER
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
#include <Nazara/Audio/Audio.hpp>
|
||||
#include <Nazara/Core/Log.hpp>
|
||||
#include <Nazara/Core/AbstractLogger.hpp>
|
||||
#include <Nazara/Core/Modules.hpp>
|
||||
|
|
@ -12,7 +13,7 @@
|
|||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
Nz::Modules<Nz::Network, Nz::Physics2D, Nz::Shader, Nz::Utility> nazaza;
|
||||
Nz::Modules<Nz::Audio, Nz::Network, Nz::Physics2D, Nz::Shader, Nz::Utility> nazaza;
|
||||
|
||||
if (!glslang::InitializeProcess())
|
||||
return EXIT_FAILURE;
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
#define CATCH_CONFIG_RUNNER
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
#include <Nazara/Audio/Audio.hpp>
|
||||
#include <Nazara/Core/AbstractLogger.hpp>
|
||||
#include <Nazara/Core/Log.hpp>
|
||||
#include <Nazara/Core/Modules.hpp>
|
||||
#include <Nazara/Network/Network.hpp>
|
||||
#include <Nazara/Physics2D/Physics2D.hpp>
|
||||
#include <Nazara/Shader/Shader.hpp>
|
||||
#include <Nazara/Utility/Utility.hpp>
|
||||
#include <glslang/Public/ShaderLang.h>
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
Nz::Modules<Nz::Audio, Nz::Network, Nz::Physics2D, Nz::Shader, Nz::Utility> nazaza;
|
||||
|
||||
if (!glslang::InitializeProcess())
|
||||
return EXIT_FAILURE;
|
||||
|
||||
int result = Catch::Session().run(argc, argv);
|
||||
|
||||
glslang::FinalizeProcess();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@ if has_config("tests") then
|
|||
set_group("Tests")
|
||||
set_kind("binary")
|
||||
|
||||
add_deps("NazaraCore", "NazaraNetwork", "NazaraPhysics2D", "NazaraShader")
|
||||
add_deps("NazaraAudio", "NazaraCore", "NazaraNetwork", "NazaraPhysics2D", "NazaraShader")
|
||||
add_packages("catch2", "entt", "glslang", "spirv-tools")
|
||||
add_headerfiles("Engine/**.hpp")
|
||||
add_files("resources.cpp")
|
||||
|
|
@ -28,18 +28,8 @@ if has_config("tests") then
|
|||
add_rules("c++.unity_build")
|
||||
end
|
||||
|
||||
target("NazaraClientUnitTests")
|
||||
add_deps("NazaraAudio")
|
||||
add_files("main_client.cpp", {unity_ignored = true})
|
||||
|
||||
if has_config("usepch") then
|
||||
set_pcxxheader("Engine/ClientModules.hpp")
|
||||
end
|
||||
|
||||
target("NazaraUnitTests")
|
||||
add_files("main.cpp", {unity_ignored = true})
|
||||
remove_headerfiles("Engine/Audio/**")
|
||||
remove_files("Engine/Audio/**")
|
||||
|
||||
if has_config("usepch") then
|
||||
set_pcxxheader("Engine/Modules.hpp")
|
||||
|
|
|
|||
Loading…
Reference in New Issue