From 3f0bb8a8bbb58df0bea38f460005f6f252171303 Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 29 Nov 2012 17:33:58 +0100 Subject: [PATCH] Added music class Former-commit-id: 5288191ecea17cb81e30a175869a2b4ea29dbc2f --- include/Nazara/Audio.hpp | 2 + include/Nazara/Audio/Music.hpp | 70 +++++++ include/Nazara/Audio/SoundStream.hpp | 28 +++ src/Nazara/Audio/Music.cpp | 278 +++++++++++++++++++++++++++ src/Nazara/Audio/SoundStream.cpp | 7 + 5 files changed, 385 insertions(+) create mode 100644 include/Nazara/Audio/Music.hpp create mode 100644 include/Nazara/Audio/SoundStream.hpp create mode 100644 src/Nazara/Audio/Music.cpp create mode 100644 src/Nazara/Audio/SoundStream.cpp diff --git a/include/Nazara/Audio.hpp b/include/Nazara/Audio.hpp index c1381421f..9b0e7d732 100644 --- a/include/Nazara/Audio.hpp +++ b/include/Nazara/Audio.hpp @@ -32,8 +32,10 @@ #include #include #include +#include #include #include #include +#include #endif // NAZARA_GLOBAL_AUDIO_HPP diff --git a/include/Nazara/Audio/Music.hpp b/include/Nazara/Audio/Music.hpp new file mode 100644 index 000000000..766b23514 --- /dev/null +++ b/include/Nazara/Audio/Music.hpp @@ -0,0 +1,70 @@ +// Copyright (C) 2012 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 + +#pragma once + +#ifndef NAZARA_MUSIC_HPP +#define NAZARA_MUSIC_HPP + +#include +#include +#include +#include + +struct NzMusicParams +{ + bool IsValid() const; +}; + +class NzMusic; +class NzSoundStream; +class NzThread; + +using NzMusicLoader = NzResourceLoader; + +struct NzMusicImpl; + +class NAZARA_API NzMusic : public NzSoundEmitter +{ + friend NzMusicLoader; + + public: + NzMusic() = default; + ~NzMusic(); + + bool Create(NzSoundStream* soundStream); + void Destroy(); + + void EnableLooping(bool loop); + + nzUInt32 GetDuration() const; + nzAudioFormat GetFormat() const; + nzUInt32 GetPlayingOffset() const; + unsigned int GetSampleCount() const; + unsigned int GetSampleRate() const; + nzSoundStatus GetStatus() const; + + bool IsLooping() const; + + bool OpenFromFile(const NzString& filePath, const NzMusicParams& params = NzMusicParams()); + bool OpenFromMemory(const void* data, std::size_t size, const NzMusicParams& params = NzMusicParams()); + bool OpenFromStream(NzInputStream& stream, const NzMusicParams& params = NzMusicParams()); + + void Pause(); + bool Play(); + + void SetPlayingOffset(nzUInt32 offset); + + void Stop(); + + private: + NzMusicImpl* m_impl = nullptr; + + bool FillBuffer(unsigned int buffer); + void MusicThread(); + + static NzMusicLoader::LoaderList s_loaders; +}; + +#endif // NAZARA_MUSIC_HPP diff --git a/include/Nazara/Audio/SoundStream.hpp b/include/Nazara/Audio/SoundStream.hpp new file mode 100644 index 000000000..7a0c98705 --- /dev/null +++ b/include/Nazara/Audio/SoundStream.hpp @@ -0,0 +1,28 @@ +// Copyright (C) 2012 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 + +#pragma once + +#ifndef NAZARA_SOUNDSTREAM_HPP +#define NAZARA_SOUNDSTREAM_HPP + +#include +#include + +class NAZARA_API NzSoundStream +{ + public: + NzSoundStream() = default; + virtual ~NzSoundStream(); + + virtual nzUInt32 GetDuration() const = 0; + virtual nzAudioFormat GetFormat() const = 0; + virtual unsigned int GetSampleCount() const = 0; + virtual unsigned int GetSampleRate() const = 0; + + virtual unsigned int Read(void* buffer, unsigned int sampleCount) = 0; + virtual void Seek(nzUInt32 offset) = 0; +}; + +#endif // NAZARA_SOUNDSTREAM_HPP diff --git a/src/Nazara/Audio/Music.cpp b/src/Nazara/Audio/Music.cpp new file mode 100644 index 000000000..1c4a5b4df --- /dev/null +++ b/src/Nazara/Audio/Music.cpp @@ -0,0 +1,278 @@ +// Copyright (C) 2012 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 + +#include +#include +#include +#include +#include +#include +#include + +bool NzMusicParams::IsValid() const +{ + return true; +} + +struct NzMusicImpl +{ + ALenum audioFormat; + std::vector chunkSamples; + NzSoundStream* stream; + NzThread* thread = nullptr; + bool loop = false; + bool playing = false; + bool paused = false; + unsigned int sampleRate; +}; + +NzMusic::~NzMusic() +{ + Destroy(); +} + +bool NzMusic::Create(NzSoundStream* soundStream) +{ + Destroy(); + + #if NAZARA_AUDIO_SAFE + if (!soundStream) + { + NazaraError("Sound stream must be valid"); + return false; + } + #endif + + nzAudioFormat format = soundStream->GetFormat(); + + m_impl = new NzMusicImpl; + m_impl->sampleRate = soundStream->GetSampleRate(); + m_impl->audioFormat = NzAudio::GetOpenALFormat(format); + m_impl->chunkSamples.resize(format * m_impl->sampleRate); // Une seconde de samples + m_impl->stream = soundStream; + + return true; +} + +void NzMusic::Destroy() +{ + if (m_impl) + { + Stop(); + + delete m_impl; + m_impl = nullptr; + } +} + +void NzMusic::EnableLooping(bool loop) +{ + #if NAZARA_AUDIO_SAFE + if (!m_impl) + { + NazaraError("Music not created"); + return; + } + #endif + + m_impl->loop = loop; +} + +nzUInt32 NzMusic::GetDuration() const +{ + #if NAZARA_AUDIO_SAFE + if (!m_impl) + { + NazaraError("Music not created"); + return 0; + } + #endif + + return m_impl->stream->GetDuration(); +} + +nzUInt32 NzMusic::GetPlayingOffset() const +{ + #if NAZARA_AUDIO_SAFE + if (!m_impl) + { + NazaraError("Music not created"); + return 0; + } + #endif + + return 0; +} + +nzSoundStatus NzMusic::GetStatus() const +{ + #if NAZARA_AUDIO_SAFE + if (!m_impl) + { + NazaraError("Music not created"); + return nzSoundStatus_Stopped; + } + #endif + + nzSoundStatus status = GetInternalStatus(); + + if (m_impl->playing && status == nzSoundStatus_Stopped) + status = nzSoundStatus_Playing; + + return status; +} + +bool NzMusic::IsLooping() const +{ + #if NAZARA_AUDIO_SAFE + if (!m_impl) + { + NazaraError("Music not created"); + return false; + } + #endif + + return m_impl->loop; +} + +bool NzMusic::OpenFromFile(const NzString& filePath, const NzMusicParams& params) +{ + return NzMusicLoader::LoadFromFile(this, filePath, params); +} + +bool NzMusic::OpenFromMemory(const void* data, std::size_t size, const NzMusicParams& params) +{ + return NzMusicLoader::LoadFromMemory(this, data, size, params); +} + +bool NzMusic::OpenFromStream(NzInputStream& stream, const NzMusicParams& params) +{ + return NzMusicLoader::LoadFromStream(this, stream, params); +} + +void NzMusic::Pause() +{ + return; +} + +bool NzMusic::Play() +{ + #if NAZARA_AUDIO_SAFE + if (!m_impl) + { + NazaraError("Music not created"); + return false; + } + #endif + + /*if (m_impl->playing) + { + if (m_impl->paused) + alSourcePlay(m_source); + else + // On repositionne au début + m_impl->stream->Seek(0); + + return true; + }*/ + + m_impl->playing = true; + m_impl->thread = new NzThread(&NzMusic::MusicThread, this); + m_impl->thread->Launch(); + + return true; +} + +void NzMusic::Stop() +{ + #if NAZARA_AUDIO_SAFE + if (!m_impl) + { + NazaraError("Music not created"); + return; + } + #endif + + if (m_impl->playing) + { + m_impl->playing = false; + m_impl->thread->Join(); + delete m_impl->thread; + m_impl->thread = nullptr; + } +} + +bool NzMusic::FillBuffer(unsigned int buffer) +{ + unsigned int sampleRead = m_impl->stream->Read(&m_impl->chunkSamples[0], m_impl->chunkSamples.size()); + if (sampleRead > 0) + alBufferData(buffer, m_impl->audioFormat, &m_impl->chunkSamples[0], sampleRead*sizeof(nzInt16), m_impl->sampleRate); + + return sampleRead != m_impl->chunkSamples.size(); // Fin du fichier +} + +void NzMusic::MusicThread() +{ + ALuint buffers[NAZARA_AUDIO_STREAMEDBUFFERCOUNT]; + alGenBuffers(NAZARA_AUDIO_STREAMEDBUFFERCOUNT, buffers); + + for (unsigned int i = 0; i < NAZARA_AUDIO_STREAMEDBUFFERCOUNT; ++i) + { + FillBuffer(buffers[i]); + alSourceQueueBuffers(m_source, 1, &buffers[i]); + } + + alSourcePlay(m_source); + + while (m_impl->playing) + { + nzSoundStatus status = GetInternalStatus(); + if (status == nzSoundStatus_Stopped) + { + NazaraError("Stopped !"); + if (m_impl->loop) + { + m_impl->stream->Seek(0); + for (unsigned int i = 0; i < NAZARA_AUDIO_STREAMEDBUFFERCOUNT; ++i) + { + FillBuffer(buffers[i]); + alSourceQueueBuffers(m_source, 1, &buffers[i]); + } + + alSourcePlay(m_source); + } + else + m_impl->playing = false; + + break; + } + + ALint processedCount = 0; + alGetSourcei(m_source, AL_BUFFERS_PROCESSED, &processedCount); + + if (processedCount > 0) + NazaraWarning(NzString::Number(processedCount)); + + ALuint buffer; + while (processedCount--) + { + alSourceUnqueueBuffers(m_source, 1, &buffer); + FillBuffer(buffer); + alSourceQueueBuffers(m_source, 1, &buffer); + } + + NzThread::Sleep(NAZARA_AUDIO_STREAMEDBUFFERCOUNT*500); + } + + ALint queuedBufferCount; + alGetSourcei(m_source, AL_BUFFERS_QUEUED, &queuedBufferCount); + + ALuint buffer; + for (ALint i = 0; i < queuedBufferCount; ++i) + alSourceUnqueueBuffers(m_source, 1, &buffer); + + alDeleteBuffers(NAZARA_AUDIO_STREAMEDBUFFERCOUNT, buffers); +} + +NzMusicLoader::LoaderList NzMusic::s_loaders; diff --git a/src/Nazara/Audio/SoundStream.cpp b/src/Nazara/Audio/SoundStream.cpp new file mode 100644 index 000000000..bc56f1d1a --- /dev/null +++ b/src/Nazara/Audio/SoundStream.cpp @@ -0,0 +1,7 @@ +// Copyright (C) 2012 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 + +#include + +NzSoundStream::~NzSoundStream() = default;