2026-03-18 00:09:06 +08:00
|
|
|
#include <gtest/gtest.h>
|
|
|
|
|
#include <XCEngine/Resources/AudioLoader.h>
|
|
|
|
|
#include <XCEngine/Resources/ResourceTypes.h>
|
|
|
|
|
#include <XCEngine/Containers/Array.h>
|
2026-03-22 02:03:51 +08:00
|
|
|
#include <XCEngine/Resources/ResourceManager.h>
|
|
|
|
|
#include <fstream>
|
|
|
|
|
#include <cstring>
|
2026-03-18 00:09:06 +08:00
|
|
|
|
|
|
|
|
using namespace XCEngine::Resources;
|
|
|
|
|
using namespace XCEngine::Containers;
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
2026-03-22 02:03:51 +08:00
|
|
|
#pragma pack(push, 1)
|
|
|
|
|
struct WAVFileHeader {
|
|
|
|
|
char riff[4];
|
|
|
|
|
uint32_t fileSize;
|
|
|
|
|
char wave[4];
|
|
|
|
|
char fmt[4];
|
|
|
|
|
uint32_t fmtSize;
|
|
|
|
|
uint16_t audioFormat;
|
|
|
|
|
uint16_t numChannels;
|
|
|
|
|
uint32_t sampleRate;
|
|
|
|
|
uint32_t byteRate;
|
|
|
|
|
uint16_t blockAlign;
|
|
|
|
|
uint16_t bitsPerSample;
|
|
|
|
|
char data[4];
|
|
|
|
|
uint32_t dataSize;
|
|
|
|
|
};
|
|
|
|
|
#pragma pack(pop)
|
|
|
|
|
|
|
|
|
|
void CreateTestWAVFile(const char* filepath, uint16_t channels, uint32_t sampleRate, uint16_t bitsPerSample, uint32_t numSamples) {
|
|
|
|
|
WAVFileHeader header = {};
|
|
|
|
|
header.riff[0] = 'R'; header.riff[1] = 'I'; header.riff[2] = 'F'; header.riff[3] = 'F';
|
|
|
|
|
header.wave[0] = 'W'; header.wave[1] = 'A'; header.wave[2] = 'V'; header.wave[3] = 'E';
|
|
|
|
|
header.fmt[0] = 'f'; header.fmt[1] = 'm'; header.fmt[2] = 't'; header.fmt[3] = ' ';
|
|
|
|
|
header.fmtSize = 16;
|
|
|
|
|
header.audioFormat = 1;
|
|
|
|
|
header.numChannels = channels;
|
|
|
|
|
header.sampleRate = sampleRate;
|
|
|
|
|
header.bitsPerSample = bitsPerSample;
|
|
|
|
|
header.blockAlign = channels * bitsPerSample / 8;
|
|
|
|
|
header.byteRate = sampleRate * header.blockAlign;
|
|
|
|
|
header.data[0] = 'd'; header.data[1] = 'a'; header.data[2] = 't'; header.data[3] = 'a';
|
|
|
|
|
header.dataSize = numSamples * header.blockAlign;
|
|
|
|
|
header.fileSize = 36 + header.dataSize;
|
|
|
|
|
|
|
|
|
|
std::vector<uint8_t> wavData(sizeof(WAVFileHeader) + header.dataSize, 0);
|
|
|
|
|
std::memcpy(wavData.data(), &header, sizeof(WAVFileHeader));
|
|
|
|
|
|
|
|
|
|
std::ofstream file(filepath, std::ios::binary);
|
|
|
|
|
file.write(reinterpret_cast<const char*>(wavData.data()), wavData.size());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(AudioLoader, ParseWAV_Mono44100_16bit) {
|
|
|
|
|
const char* testPath = "test_mono_44100.wav";
|
|
|
|
|
CreateTestWAVFile(testPath, 1, 44100, 16, 44100);
|
|
|
|
|
|
|
|
|
|
AudioLoader loader;
|
|
|
|
|
LoadResult result = loader.Load(testPath);
|
|
|
|
|
|
|
|
|
|
EXPECT_TRUE(result);
|
|
|
|
|
if (result) {
|
|
|
|
|
AudioClip* clip = static_cast<AudioClip*>(result.resource);
|
|
|
|
|
EXPECT_EQ(clip->GetSampleRate(), 44100u);
|
|
|
|
|
EXPECT_EQ(clip->GetChannels(), 1u);
|
|
|
|
|
EXPECT_EQ(clip->GetBitsPerSample(), 16u);
|
|
|
|
|
EXPECT_GT(clip->GetDuration(), 0.0f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::remove(testPath);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(AudioLoader, ParseWAV_Stereo48000_16bit) {
|
|
|
|
|
const char* testPath = "test_stereo_48000.wav";
|
|
|
|
|
CreateTestWAVFile(testPath, 2, 48000, 16, 4800);
|
|
|
|
|
|
|
|
|
|
AudioLoader loader;
|
|
|
|
|
LoadResult result = loader.Load(testPath);
|
|
|
|
|
|
|
|
|
|
EXPECT_TRUE(result);
|
|
|
|
|
if (result) {
|
|
|
|
|
AudioClip* clip = static_cast<AudioClip*>(result.resource);
|
|
|
|
|
EXPECT_EQ(clip->GetSampleRate(), 48000u);
|
|
|
|
|
EXPECT_EQ(clip->GetChannels(), 2u);
|
|
|
|
|
EXPECT_EQ(clip->GetBitsPerSample(), 16u);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::remove(testPath);
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-18 00:09:06 +08:00
|
|
|
TEST(AudioLoader, GetResourceType) {
|
|
|
|
|
AudioLoader loader;
|
|
|
|
|
EXPECT_EQ(loader.GetResourceType(), ResourceType::AudioClip);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(AudioLoader, GetSupportedExtensions) {
|
|
|
|
|
AudioLoader loader;
|
|
|
|
|
auto extensions = loader.GetSupportedExtensions();
|
|
|
|
|
EXPECT_GE(extensions.Size(), 1u);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(AudioLoader, CanLoad) {
|
|
|
|
|
AudioLoader loader;
|
|
|
|
|
EXPECT_TRUE(loader.CanLoad("test.wav"));
|
|
|
|
|
EXPECT_TRUE(loader.CanLoad("test.mp3"));
|
|
|
|
|
EXPECT_TRUE(loader.CanLoad("test.ogg"));
|
|
|
|
|
EXPECT_FALSE(loader.CanLoad("test.txt"));
|
|
|
|
|
EXPECT_FALSE(loader.CanLoad("test.png"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(AudioLoader, LoadInvalidPath) {
|
|
|
|
|
AudioLoader loader;
|
|
|
|
|
LoadResult result = loader.Load("invalid/path/audio.wav");
|
|
|
|
|
EXPECT_FALSE(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace
|