This commit is contained in:
2026-02-08 16:20:50 +08:00
parent 0ae47e5d6a
commit 8b88904ef7
72 changed files with 5963 additions and 2038 deletions

View File

@@ -0,0 +1,233 @@
#include "Asset_SoundPack.h"
Asset_SoundPack::Asset_SoundPack()
{
int device = -1; // 使用默认设备
unsigned long freq = 44100; // 采样频率PCM常用的采样率之一可以按需调整
// 构造NPK信息
InitNpkList();
// 解析audio.xml
XmlConfig.LoadFromFile("audio.xml");
// 初始化SDL_mixer支持OGG格式
// 44100: 采样率, MIX_DEFAULT_FORMAT: 音频格式, 2: 声道数(立体声), 4096: 缓冲区大小
if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 8192) < 0)
{
SDL_LogError(0, "SDL_mixer初始化失败! Mix_Error: %s\n", Mix_GetError());
}
if (Mix_Init(MIX_INIT_MP3 | MIX_INIT_OGG) < 0)
{
SDL_LogError(0, "Mix_Init failed: %s\n", Mix_GetError());
}
// 分配通道
ChannelCount = Mix_AllocateChannels(64);
SetAllChannelVolume(0);
}
Asset_SoundPack::~Asset_SoundPack()
{
}
void Asset_SoundPack::InitNpkList()
{
DIR *dir;
struct dirent *ent;
std::string path = "SoundPacks/";
dir = opendir(path.c_str());
while ((ent = readdir(dir)))
{
// 跳过.和..目录
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
continue;
std::string RealPath = path + ent->d_name;
Ifstream_NPK Fs;
Fs.open(RealPath.c_str(), std::ios::in | std::ios::binary);
if (Fs.is_open())
{
std::string Header = Fs.ReadString();
// 如果是NPK
if (Header == "NeoplePack_Bill")
{
// 读取img数量
int ImageCount = Fs.ReadInt();
for (int i = 0; i < ImageCount; ++i)
{
// 直接读取当前项的偏移、长度和路径
auto offset = Fs.ReadUnsignedInt();
auto length = Fs.ReadUnsignedInt();
auto path = Fs.ReadInfo();
// 构造 WAV 并插入映射表
lp_arr[path] = WAV{
offset, // offset
length, // size
path, // lpWavName直接复用读取的path
RealPath, // lpBelongsFile
i // img_index
};
}
}
}
}
closedir(dir);
}
void Asset_SoundPack::Reclaims()
{
}
Mix_Chunk *Asset_SoundPack::GetOgg(const std::string &lpWavName)
{
if (map_sound.find(lpWavName) != map_sound.end())
{
map_sound[lpWavName].LastUseTime = SDL_GetTicks64();
return map_sound[lpWavName].lpMusic;
}
// 在NPK映射表中找到
if (lp_arr.find(lpWavName) != lp_arr.end())
{
WAV &wav = lp_arr[lpWavName];
if (wav.lpBelongsFile.empty())
return nullptr;
Ifstream_NPK Fs;
Fs.open(wav.lpBelongsFile.c_str(), std::ios::in | std::ios::binary);
if (Fs.is_open())
{
Fs.seekg(wav.offset, std::ios::beg);
auto buffer = Fs.ReadCustomSize(wav.size);
SDL_RWops *rw = SDL_RWFromConstMem(buffer, wav.size);
if (!rw)
{
SDL_Log("创建内存流失败: %s\n", SDL_GetError());
Mix_CloseAudio();
SDL_Quit();
return nullptr;
}
Mix_Chunk *music = Mix_LoadWAV_RW(rw, 0);
if (!music)
{
SDL_Log("加载OGG失败: %s\n", Mix_GetError());
SDL_RWclose(rw); // 手动关闭流
Mix_CloseAudio();
SDL_Quit();
return nullptr;
}
map_sound[lpWavName].lpMusic = music;
map_sound[lpWavName].LastUseTime = SDL_GetTicks64();
return music;
}
}
// 去Music文件夹中寻找
else
{
Mix_Chunk *music = Mix_LoadWAV(lpWavName.c_str());
if (!music)
{
SDL_Log("加载OGG失败: %s\n", Mix_GetError());
Mix_CloseAudio();
SDL_Quit();
return nullptr;
}
map_sound[lpWavName].lpMusic = music;
map_sound[lpWavName].LastUseTime = SDL_GetTicks64();
return music;
}
}
void Asset_SoundPack::PlayAudio(const std::string Key)
{
std::string RealKey = Key;
// 先判断是不是随机组 如果是随机组去里面调出真正要播放的Key
if (XmlConfig.HasRandomGroup(Key))
{
auto Group = XmlConfig.GetRandomGroup(Key);
int RandNum = rand() % 100;
for (auto &item : Group.items)
{
if (RandNum <= item.prob)
{
RealKey = item.tag;
}
}
}
// 如果是特效音频
if (XmlConfig.HasEffect(Key))
{
std::string oggPath = XmlConfig.GetEffect(Key).file_path;
int volume = XmlConfig.GetEffect(Key).volume_adjust;
PlayEffect(oggPath, volume);
}
// 如果是背景音乐
else if (XmlConfig.HasMusic(Key))
{
std::string oggPath = XmlConfig.GetMusic(Key).file_path;
PlayMusic(Key, oggPath);
}
else
{
SDL_LogError(0, "找不到音频: %s\n", Key.c_str());
}
}
void Asset_SoundPack::StopAudio(const std::string Key)
{
StopChannel(backgroud_music_map[Key]);
backgroud_music_map.erase(Key);
}
void Asset_SoundPack::PlayMusic(const std::string Key, const std::string oggpath)
{
auto ogg = GetOgg(oggpath);
if (ogg)
{
int channel = FindFreeChannelInRange(0, 4);
backgroud_music_map[Key] = Mix_PlayChannel(channel, ogg, -1);
}
}
void Asset_SoundPack::PlayEffect(const std::string Key, int Volume)
{
auto ogg = GetOgg(Key);
if (ogg)
{
int channel = FindFreeChannelInRange(4, ChannelCount - 1);
Mix_VolumeChunk(ogg, Volume);
Mix_PlayChannel(channel, ogg, 0);
}
}
void Asset_SoundPack::StopChannel(int Channel)
{
Mix_HaltChannel(Channel); // 停止指定通道的音效
}
void Asset_SoundPack::SetAllChannelVolume(int Volume)
{
Mix_Volume(-1, Volume);
}
std::map<std::string, int> Asset_SoundPack::GetBackgroudMusicVector()
{
return backgroud_music_map;
}
int Asset_SoundPack::FindFreeChannelInRange(int startChannel, int endChannel)
{
// 遍历通道若总通道数小于32则只检查到最后一个通道
for (int channel = startChannel; channel <= endChannel; channel++)
{
// 检查通道是否空闲Mix_Playing返回0表示空闲
if (Mix_Playing(channel) == 0)
{
return channel; // 返回第一个空闲通道
}
}
// 若所有通道都在使用中
return -1;
}