fix(audio): 修复音频系统初始化及资源加载问题

- 修改音频系统初始化逻辑,增加备用初始化参数
- 优化音乐和音效加载方式,直接加载文件而非内存
- 增加错误日志输出,便于排查问题
- 更新MingW平台构建脚本,完善依赖DLL复制
This commit is contained in:
2026-03-20 02:36:11 +08:00
parent 9ce47cc501
commit 6c11e4d8be
7 changed files with 63 additions and 39 deletions

View File

@@ -12,7 +12,7 @@ struct AudioConfig {
int frequency = 44100;
uint16_t format = 0x8010;
int channels = 2;
int chunksize = 2048;
int chunksize = 4096;
int maxSoundChannels = 32;
};

View File

@@ -24,10 +24,16 @@ bool AudioSystem::init(const AudioConfig& config) {
return false;
}
if (Mix_OpenAudio(config.frequency, config.format, config.channels, config.chunksize) < 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to open audio: %s", Mix_GetError());
SDL_QuitSubSystem(SDL_INIT_AUDIO);
return false;
int frequency = config.frequency;
uint16_t format = config.format;
int channels = config.channels;
if (Mix_OpenAudio(frequency, format, channels, config.chunksize) < 0) {
if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, config.chunksize) < 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to open audio: %s", Mix_GetError());
SDL_QuitSubSystem(SDL_INIT_AUDIO);
return false;
}
}
maxChannels_ = config.maxSoundChannels;
@@ -36,7 +42,6 @@ bool AudioSystem::init(const AudioConfig& config) {
initialized_ = true;
updateVolumes();
SDL_Log("Audio system initialized");
return true;
}
@@ -51,7 +56,6 @@ void AudioSystem::shutdown() {
SDL_QuitSubSystem(SDL_INIT_AUDIO);
initialized_ = false;
SDL_Log("Audio system shutdown");
}
void AudioSystem::setMasterVolume(float volume) {

View File

@@ -9,17 +9,15 @@ namespace frostbite2D {
Ptr<Music> Music::loadFromFile(const std::string& path) {
auto& asset = Asset::get();
auto data = asset.readFileToBytes(path);
if (!data) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to read music file: %s", path.c_str());
std::string fullPath = asset.resolvePath(path);
Mix_Music* music = Mix_LoadMUS(fullPath.c_str());
if (!music) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to load music from file %s: %s", fullPath.c_str(), Mix_GetError());
return nullptr;
}
auto music = loadFromMemory(data->data(), data->size());
if (music) {
music->path_ = path;
}
return music;
return Ptr<Music>(new Music(music, path));
}
Ptr<Music> Music::loadFromMemory(const uint8* data, size_t size) {
@@ -51,6 +49,7 @@ Music::~Music() {
bool Music::play(int loops) {
if (!music_) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Music is null");
return false;
}
@@ -62,7 +61,12 @@ bool Music::play(int loops) {
int vol = static_cast<int>(volume_ * AudioSystem::get().getMusicVolume() * AudioSystem::get().getMasterVolume() * MIX_MAX_VOLUME);
Mix_VolumeMusic(vol);
return Mix_PlayMusic(music_, loops) == 0;
if (Mix_PlayMusic(music_, loops) == 0) {
return true;
} else {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to play music: %s", Mix_GetError());
return false;
}
}
bool Music::fadeIn(int ms, int loops) {

View File

@@ -9,17 +9,15 @@ namespace frostbite2D {
Ptr<Sound> Sound::loadFromFile(const std::string& path) {
auto& asset = Asset::get();
auto data = asset.readFileToBytes(path);
if (!data) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to read sound file: %s", path.c_str());
std::string fullPath = asset.resolvePath(path);
Mix_Chunk* chunk = Mix_LoadWAV(fullPath.c_str());
if (!chunk) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to load sound from file %s: %s", fullPath.c_str(), Mix_GetError());
return nullptr;
}
auto sound = loadFromMemory(data->data(), data->size());
if (sound) {
sound->path_ = path;
}
return sound;
return Ptr<Sound>(new Sound(chunk, path));
}
Ptr<Sound> Sound::loadFromMemory(const uint8* data, size_t size) {
@@ -51,6 +49,7 @@ Sound::~Sound() {
int Sound::play(int loops, int channel) {
if (!chunk_) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Sound chunk is null");
return -1;
}
@@ -62,7 +61,11 @@ int Sound::play(int loops, int channel) {
int vol = static_cast<int>(volume_ * AudioSystem::get().getSoundVolume() * AudioSystem::get().getMasterVolume() * MIX_MAX_VOLUME);
Mix_VolumeChunk(chunk_, vol);
return Mix_PlayChannel(channel, chunk_, loops);
int result = Mix_PlayChannel(channel, chunk_, loops);
if (result == -1) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to play sound: %s", Mix_GetError());
}
return result;
}
void Sound::setVolume(float volume) {

View File

@@ -103,7 +103,9 @@ int main(int argc, char **argv) {
auto bgMusic = Music::loadFromFile("assets/BackgroundMusic.mp3");
if (bgMusic) {
bgMusic->play();
bgMusic->play();
} else {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to load background music!");
}
app.run();

View File

@@ -33,15 +33,16 @@ target("Frostbite2D")
print("Copy assets directory: " .. assets_dir .. " -> " .. target_assets_dir)
end
-- 复制 SDL2 和 SDL2_mixer DLL (Windows 平台)
-- 复制所有依赖的 DLL (Windows 平台)
if is_plat("mingw") or is_plat("windows") then
for _, pkg_name in ipairs({"libsdl2", "libsdl2_mixer"}) do
-- 复制所有包的 DLL 文件
local all_pkgs = {"libsdl2", "libsdl2_image", "libsdl2_mixer"}
for _, pkg_name in ipairs(all_pkgs) do
local pkg = target:pkg(pkg_name)
if pkg then
local libfiles = pkg:get("libfiles")
if libfiles then
for _, libfile in ipairs(libfiles) do
-- 查找 DLL 文件
if libfile:endswith(".dll") then
local target_dll = path.join(output_dir, path.filename(libfile))
os.cp(libfile, target_dll)
@@ -52,21 +53,31 @@ target("Frostbite2D")
end
end
-- 尝试从 xmake 包目录复制 SDL2 和 SDL2_mixer DLL
local dll_paths = {
path.join(os.getenv("USERPROFILE") or "", ".xmake/packages/l/libsdl2/**/bin/SDL2.dll"),
path.join(os.getenv("USERPROFILE") or "", ".xmake/packages/l/libsdl2/**/lib/SDL2.dll"),
path.join(os.getenv("USERPROFILE") or "", ".xmake/packages/l/libsdl2_mixer/**/bin/SDL2_mixer.dll"),
path.join(os.getenv("USERPROFILE") or "", ".xmake/packages/l/libsdl2_mixer/**/lib/SDL2_mixer.dll"),
-- 从 xmake 包目录复制所有可能的依赖 DLL
local user_profile = os.getenv("USERPROFILE") or ""
local packages_dir = path.join(user_profile, ".xmake/packages/l")
local common_dll_patterns = {
path.join(packages_dir, "libogg/**/*.dll"),
path.join(packages_dir, "libvorbis/**/*.dll"),
path.join(packages_dir, "libvorbisfile/**/*.dll"),
path.join(packages_dir, "libmpg123/**/*.dll"),
path.join(packages_dir, "libflac/**/*.dll"),
path.join(packages_dir, "libsndfile/**/*.dll"),
path.join(packages_dir, "libmodplug/**/*.dll"),
path.join(packages_dir, "opus/**/*.dll"),
path.join(packages_dir, "opusfile/**/*.dll"),
path.join(packages_dir, "**/*.dll")
}
for _, dll_pattern in ipairs(dll_paths) do
for _, dll_pattern in ipairs(common_dll_patterns) do
local dll_files = os.files(dll_pattern)
for _, dll_file in ipairs(dll_files) do
local target_dll = path.join(output_dir, path.filename(dll_file))
local dll_name = path.filename(dll_file)
local target_dll = path.join(output_dir, dll_name)
if not os.isfile(target_dll) then
os.cp(dll_file, target_dll)
print("Copy DLL from: " .. dll_file)
print("Copy dependency DLL: " .. dll_name)
end
end
end

View File

@@ -8,7 +8,7 @@ set_encodings("utf-8")
add_rules("mode.debug", "mode.release")
local host_plat = os.host()
local host_plat = "mingw"
local target_plat = get_config("plat") or host_plat
if target_plat == "windows" then
target_plat = "mingw"