audio::play

This commit is contained in:
MihailRis
2024-02-27 18:58:41 +03:00
parent 58661a94a6
commit acd5d11378
5 changed files with 128 additions and 10 deletions
+8 -1
View File
@@ -61,6 +61,14 @@ void ALSpeaker::setPitch(float pitch) {
AL_CHECK(alSourcef(source, AL_PITCH, pitch)); AL_CHECK(alSourcef(source, AL_PITCH, pitch));
} }
bool ALSpeaker::isLoop() const {
return AL::getSourcei(source, AL_LOOPING) == AL_TRUE;
}
void ALSpeaker::setLoop(bool loop) {
AL_CHECK(alSourcei(source, AL_LOOPING, loop ? AL_TRUE : AL_FALSE));
}
void ALSpeaker::play() { void ALSpeaker::play() {
AL_CHECK(alSourcePlay(source)); AL_CHECK(alSourcePlay(source));
} }
@@ -240,5 +248,4 @@ void ALAudio::setListener(glm::vec3 position, glm::vec3 velocity, glm::vec3 at,
} }
void ALAudio::update(double delta) { void ALAudio::update(double delta) {
} }
+3
View File
@@ -58,6 +58,9 @@ namespace audio {
float getPitch() const override; float getPitch() const override;
void setPitch(float pitch) override; void setPitch(float pitch) override;
bool isLoop() const override;
void setLoop(bool loop) override;
void play() override; void play() override;
void pause() override; void pause() override;
void stop() override; void stop() override;
+74 -9
View File
@@ -6,35 +6,100 @@
#include "NoAudio.h" #include "NoAudio.h"
namespace audio { namespace audio {
extern Backend* backend; static speakerid_t nextId = 1;
static Backend* backend;
static std::unordered_map<speakerid_t, std::unique_ptr<Speaker>> speakers;
} }
audio::Backend* audio::backend = nullptr; using namespace audio;
void audio::initialize(bool enabled) { void audio::initialize(bool enabled) {
if (enabled) { if (enabled) {
audio::backend = ALAudio::create(); backend = ALAudio::create();
} }
if (audio::backend == nullptr) { if (backend == nullptr) {
std::cerr << "could not to initialize audio" << std::endl; std::cerr << "could not to initialize audio" << std::endl;
audio::backend = NoAudio::create(); backend = NoAudio::create();
} }
} }
Sound* audio::createSound(std::shared_ptr<PCM> pcm, bool keepPCM) {
return backend->createSound(pcm, keepPCM);
}
void audio::setListener( void audio::setListener(
glm::vec3 position, glm::vec3 position,
glm::vec3 velocity, glm::vec3 velocity,
glm::vec3 lookAt, glm::vec3 lookAt,
glm::vec3 up glm::vec3 up
) { ) {
audio::backend->setListener(position, velocity, lookAt, up); backend->setListener(position, velocity, lookAt, up);
}
void remove_lower_priority_speaker(int priority) {
for (auto it = speakers.begin(); it != speakers.end();) {
if (it->second->getPriority() < priority && it->second->isPaused()) {
speakers.erase(it);
return;
}
it++;
}
for (auto it = speakers.begin(); it != speakers.end();) {
if (it->second->getPriority() < priority) {
speakers.erase(it);
return;
}
it++;
}
}
speakerid_t audio::play(
Sound* sound,
glm::vec3 position,
float volume,
float pitch,
bool loop,
int priority
) {
Speaker* speaker = sound->newInstance(priority);
if (speaker == nullptr) {
remove_lower_priority_speaker(priority);
speaker = sound->newInstance(priority);
}
if (speaker == nullptr) {
return 0;
}
speakerid_t id = nextId++;
speakers[id].reset(speaker);
speaker->setPosition(position);
speaker->setVolume(volume);
speaker->setPitch(pitch);
speaker->setLoop(loop);
speaker->play();
return id;
}
Speaker* audio::get(speakerid_t id) {
auto found = speakers.find(id);
if (found == speakers.end()) {
return nullptr;
}
return found->second.get();
} }
void audio::update(double delta) { void audio::update(double delta) {
audio::backend->update(delta); backend->update(delta);
for (auto it = speakers.begin(); it != speakers.end();) {
if (it->second->isStopped()) {
speakers.erase(it);
} else {
it++;
}
}
} }
void audio::close() { void audio::close() {
delete audio::backend; delete backend;
audio::backend = nullptr; backend = nullptr;
} }
+41
View File
@@ -11,8 +11,13 @@ namespace audio {
/// @brief duration unit is second /// @brief duration unit is second
using duration_t = float; using duration_t = float;
constexpr inline int PRIORITY_LOW = 0;
constexpr inline int PRIORITY_NORMAL = 5;
constexpr inline int PRIORITY_HIGH = 10;
class Speaker; class Speaker;
/// @brief Audio speaker states
enum class State { enum class State {
playing, playing,
paused, paused,
@@ -84,6 +89,14 @@ namespace audio {
/// @param pitch new pitch multiplier (must be positive) /// @param pitch new pitch multiplier (must be positive)
virtual void setPitch(float pitch) = 0; virtual void setPitch(float pitch) = 0;
/// @brief Check if speaker audio is in loop
/// @return true if audio is in loop
virtual bool isLoop() const = 0;
/// @brief Enable/disable audio loop
/// @param loop loop mode
virtual void setLoop(bool loop) = 0;
/// @brief Play, replay or resume audio /// @brief Play, replay or resume audio
virtual void play() = 0; virtual void play() = 0;
@@ -120,6 +133,14 @@ namespace audio {
/// @brief Get speaker priority /// @brief Get speaker priority
/// @return speaker priority value /// @return speaker priority value
virtual int getPriority() const = 0; virtual int getPriority() const = 0;
inline constexpr bool isPaused() const {
return getState() == State::paused;
}
inline constexpr bool isStopped() const {
return getState() == State::stopped;
}
}; };
class Backend { class Backend {
@@ -161,6 +182,26 @@ namespace audio {
glm::vec3 up glm::vec3 up
); );
/// @brief Play 3D sound in the world
/// @param sound target sound
/// @param position sound world position
/// @param volume sound volume [0.0-1.0]
/// @param pitch sound pitch multiplier [0.0-...]
/// @param loop loop sound
/// @param priority sound priority
/// (PRIORITY_LOW, PRIORITY_NORMAL, PRIORITY_HIGH)
/// @return speaker id or 0
extern speakerid_t play(
Sound* sound,
glm::vec3 position,
float volume,
float pitch,
bool loop,
int priority
);
extern Speaker* get(speakerid_t id);
/// @brief Update audio streams and sound instanced /// @brief Update audio streams and sound instanced
/// @param delta time since the last update (seconds) /// @param delta time since the last update (seconds)
extern void update(double delta); extern void update(double delta);
+2
View File
@@ -122,6 +122,8 @@ void Engine::mainloop() {
updateTimers(); updateTimers();
updateHotkeys(); updateHotkeys();
audio::update(delta);
gui->act(delta); gui->act(delta);
screen->update(delta); screen->update(delta);