This commit is contained in:
@@ -1,73 +1,119 @@
|
||||
#include "audio.h"
|
||||
#include "audio.hpp"
|
||||
|
||||
#include <SDL3/SDL_properties.h>
|
||||
|
||||
#include <iostream>
|
||||
#include "../log.hpp"
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
using namespace game::util;
|
||||
|
||||
namespace game::resource
|
||||
{
|
||||
static std::shared_ptr<MIX_Audio> audio_make(MIX_Audio* audio)
|
||||
{
|
||||
return std::shared_ptr<MIX_Audio>(audio,
|
||||
[](MIX_Audio* a)
|
||||
{
|
||||
if (a) MIX_DestroyAudio(a);
|
||||
});
|
||||
}
|
||||
|
||||
static std::unordered_map<std::string, std::weak_ptr<MIX_Audio>> audioCache{};
|
||||
|
||||
static std::shared_ptr<MIX_Audio> cache_get(const std::string& key)
|
||||
{
|
||||
auto it = audioCache.find(key);
|
||||
if (it == audioCache.end()) return {};
|
||||
|
||||
auto cached = it->second.lock();
|
||||
if (!cached) audioCache.erase(it);
|
||||
return cached;
|
||||
}
|
||||
|
||||
static void cache_set(const std::string& key, const std::shared_ptr<MIX_Audio>& audio)
|
||||
{
|
||||
if (!audio) return;
|
||||
audioCache[key] = audio;
|
||||
}
|
||||
|
||||
MIX_Mixer* Audio::mixer_get()
|
||||
{
|
||||
static auto mixer = MIX_CreateMixerDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, nullptr);
|
||||
return mixer;
|
||||
}
|
||||
|
||||
void Audio::set_gain(float gain)
|
||||
void Audio::volume_set(float volume)
|
||||
{
|
||||
auto mixer = mixer_get();
|
||||
MIX_SetMasterGain(mixer, gain);
|
||||
}
|
||||
|
||||
void Audio::retain()
|
||||
{
|
||||
if (refCount) ++(*refCount);
|
||||
}
|
||||
|
||||
void Audio::release()
|
||||
{
|
||||
if (refCount)
|
||||
{
|
||||
if (--(*refCount) == 0)
|
||||
{
|
||||
if (internal) MIX_DestroyAudio(internal);
|
||||
delete refCount;
|
||||
}
|
||||
refCount = nullptr;
|
||||
}
|
||||
internal = nullptr;
|
||||
MIX_SetMasterGain(mixer, volume);
|
||||
}
|
||||
|
||||
Audio::Audio(const std::filesystem::path& path)
|
||||
{
|
||||
internal = MIX_LoadAudio(mixer_get(), path.c_str(), true);
|
||||
auto key = std::string("fs:") + path.string();
|
||||
internal = cache_get(key);
|
||||
if (internal)
|
||||
{
|
||||
refCount = new int(1);
|
||||
std::cout << "Initialized audio: '" << path.string() << "'\n";
|
||||
logger.info(std::format("Using cached audio: {}", path.string()));
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
internal = audio_make(MIX_LoadAudio(mixer_get(), path.c_str(), true));
|
||||
cache_set(key, internal);
|
||||
if (internal) logger.info(std::format("Initialized audio: {}", path.string()));
|
||||
|
||||
if (!internal) logger.info(std::format("Failed to intialize audio: {} ({})", path.string(), SDL_GetError()));
|
||||
}
|
||||
|
||||
Audio::Audio(const physfs::Path& path)
|
||||
{
|
||||
if (!path.is_valid())
|
||||
{
|
||||
std::cout << "Failed to initialize audio: '" << path.string() << "'\n";
|
||||
logger.error(
|
||||
std::format("Failed to initialize audio from PhysicsFS path: {}", path.c_str(), physfs::error_get()));
|
||||
return;
|
||||
}
|
||||
|
||||
auto key = std::string("physfs:") + path.c_str();
|
||||
internal = cache_get(key);
|
||||
if (internal)
|
||||
{
|
||||
logger.info(std::format("Using cached audio: {}", path.c_str()));
|
||||
return;
|
||||
}
|
||||
|
||||
auto buffer = path.read();
|
||||
|
||||
if (buffer.empty())
|
||||
{
|
||||
logger.error(
|
||||
std::format("Failed to initialize audio from PhysicsFS path: {} ({})", path.c_str(), physfs::error_get()));
|
||||
return;
|
||||
}
|
||||
|
||||
auto ioStream = SDL_IOFromConstMem(buffer.data(), buffer.size());
|
||||
|
||||
internal = audio_make(MIX_LoadAudio_IO(mixer_get(), ioStream, false, true));
|
||||
cache_set(key, internal);
|
||||
if (internal)
|
||||
logger.info(std::format("Initialized audio: {}", path.c_str()));
|
||||
else
|
||||
logger.info(std::format("Failed to intialize audio: {} ({})", path.c_str(), SDL_GetError()));
|
||||
}
|
||||
|
||||
Audio::Audio(const Audio& other)
|
||||
{
|
||||
internal = other.internal;
|
||||
refCount = other.refCount;
|
||||
retain();
|
||||
track = nullptr;
|
||||
}
|
||||
|
||||
Audio::Audio(Audio&& other) noexcept
|
||||
{
|
||||
internal = other.internal;
|
||||
internal = std::move(other.internal);
|
||||
track = other.track;
|
||||
refCount = other.refCount;
|
||||
|
||||
other.internal = nullptr;
|
||||
other.track = nullptr;
|
||||
other.refCount = nullptr;
|
||||
}
|
||||
|
||||
Audio& Audio::operator=(const Audio& other)
|
||||
@@ -76,8 +122,7 @@ namespace game::resource
|
||||
{
|
||||
unload();
|
||||
internal = other.internal;
|
||||
refCount = other.refCount;
|
||||
retain();
|
||||
track = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@@ -87,13 +132,10 @@ namespace game::resource
|
||||
if (this != &other)
|
||||
{
|
||||
unload();
|
||||
internal = other.internal;
|
||||
internal = std::move(other.internal);
|
||||
track = other.track;
|
||||
refCount = other.refCount;
|
||||
|
||||
other.internal = nullptr;
|
||||
other.track = nullptr;
|
||||
other.refCount = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@@ -105,7 +147,7 @@ namespace game::resource
|
||||
MIX_DestroyTrack(track);
|
||||
track = nullptr;
|
||||
}
|
||||
release();
|
||||
internal.reset();
|
||||
}
|
||||
|
||||
void Audio::play(bool isLoop)
|
||||
@@ -126,7 +168,7 @@ namespace game::resource
|
||||
if (!track) return;
|
||||
}
|
||||
|
||||
MIX_SetTrackAudio(track, internal);
|
||||
MIX_SetTrackAudio(track, internal.get());
|
||||
|
||||
SDL_PropertiesID options = 0;
|
||||
|
||||
@@ -149,5 +191,5 @@ namespace game::resource
|
||||
bool Audio::is_playing() const { return track && MIX_TrackPlaying(track); }
|
||||
|
||||
Audio::~Audio() { unload(); }
|
||||
bool Audio::is_valid() const { return internal != nullptr; }
|
||||
bool Audio::is_valid() const { return (bool)internal; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user