Skip to content

Commit

Permalink
Support for .wav files
Browse files Browse the repository at this point in the history
  • Loading branch information
Odex64 committed May 31, 2024
1 parent 6826680 commit 7375f15
Show file tree
Hide file tree
Showing 13 changed files with 244 additions and 57 deletions.
Binary file modified Content/Data/Sounds/Weapons/GLFire.xnb
Binary file not shown.
Binary file modified Content/Data/Sounds/Weapons/Gatling_spin.xnb
Binary file not shown.
Binary file modified Content/Data/Sounds/Weapons/Gatling_wind_down.xnb
Binary file not shown.
Binary file modified Content/Data/Sounds/Weapons/Gatling_wind_up.xnb
Binary file not shown.
Binary file modified Content/Data/Sounds/Weapons/HeavyCharge.xnb
Binary file not shown.
Binary file modified Content/Data/Sounds/Weapons/LightCharge.xnb
Binary file not shown.
Binary file modified Content/Data/Sounds/Weapons/Sledgehammer.xnb
Binary file not shown.
5 changes: 5 additions & 0 deletions Editor/Binary/BinaryReader.ixx
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,9 @@ public:
{
return std::string{};
}

void Seek(std::streamsize count) const noexcept
{
Stream->ignore(count);
}
};
1 change: 1 addition & 0 deletions Editor/Editor.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@
<ClCompile Include="Main.ixx" />
<ClCompile Include="Parser\Converter.ixx" />
<ClCompile Include="Parser\FlagBits.ixx" />
<ClCompile Include="Parser\Sound.ixx" />
<ClCompile Include="Parser\TargetPlatform.ixx" />
<ClCompile Include="Parser\Texture.ixx" />
<ClCompile Include="Parser\XCompress.ixx" />
Expand Down
17 changes: 9 additions & 8 deletions Editor/Main.ixx
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import std;
import Xnb;
import Texture;
import Sound;

int main()
{
//std::expected<Xnb, std::string> file{ Xnb::Read("profile_bg.xnb") };
//std::expected<Xnb, std::string> file{ Xnb::Read("MenuMove.xnb") };
//if (!file.has_value()) return 1;
//file.value().Type->Export("profile_bg.png");
std::expected<Xnb, std::string> file{ Xnb::Write<Texture>("profile_bg.png") };
//file.value().Type->Export("MenuMove.wav");
//std::expected<Xnb, std::string> file{ Xnb::Write<Sound>("MenuMove.wav") };

//for (const auto& entry : std::filesystem::recursive_directory_iterator("Images/Misc/SFDLogo")) {
// if (entry.is_regular_file() && entry.path().extension() == ".png") {
// std::expected<Xnb, std::string> file{ Xnb::Write<Texture>(entry.path()) };
// }
//}
for (const auto& entry : std::filesystem::recursive_directory_iterator("Weapons")) {
if (entry.is_regular_file() && entry.path().extension() == ".wav") {
std::expected<Xnb, std::string> file{ Xnb::Write<Sound>(entry.path()) };
}
}

return 0;
}
158 changes: 158 additions & 0 deletions Editor/Parser/Sound.ixx
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
export module Sound;

import Converter;
import BinaryReader;
import BinaryWriter;

export class Sound final : public Converter {
public:
inline const static std::string Reader{ "Microsoft.Xna.Framework.Content.SoundEffectReader" };
const std::uint32_t FormatSize;
const std::vector<std::uint8_t> Format;
const std::uint32_t DataSize;
const std::vector<std::uint8_t> Data;
const std::int32_t LoopStart;
const std::int32_t LoopLength;
const std::int32_t Duration;

Sound(const std::uint32_t formatSize, const std::vector<std::uint8_t>& format, const std::uint32_t dataSize, const std::vector<std::uint8_t>& data, const std::int32_t loopStart, const std::int32_t loopLength, const std::int32_t duration) noexcept : FormatSize{ formatSize }, Format{ format }, DataSize{ dataSize }, Data{ data }, LoopStart{ loopStart }, LoopLength{ loopLength }, Duration{ duration } {}
Sound() = delete;

Sound(const Sound&) = delete;
Sound& operator=(const Sound&) = delete;

Sound(Sound&& other) noexcept : FormatSize{ other.FormatSize }, Format{ std::move(other.Format) }, DataSize{ other.DataSize }, Data{ std::move(other.Data) }, LoopStart{ other.LoopStart }, LoopLength{ other.LoopLength }, Duration{ other.Duration } {}
Sound& operator=(Sound&&) = delete;

static [[nodiscard]] std::expected<Sound, std::string> Read(BinaryReader& stream) noexcept
{
const std::uint32_t formatSize{ stream.Read<std::uint32_t>() };
if (formatSize != 18) return std::unexpected("Audio format not supported");

std::vector<std::uint8_t> format{};
for (std::size_t i{ 0 }; i < formatSize; i++) {
format.emplace_back(stream.Read<std::uint8_t>());
}

const std::uint32_t dataSize{ stream.Read<std::uint32_t>() };
std::vector<std::uint8_t> data{};
for (std::size_t i{ 0 }; i < dataSize; i++) {
data.emplace_back(stream.Read<std::uint8_t>());
}

const std::int32_t loopStart{ stream.Read<std::int32_t>() };
const std::int32_t loopLength{ stream.Read<std::int32_t>() };
const std::int32_t duration{ stream.Read<std::int32_t>() };

return std::expected<Sound, std::string>(
std::in_place,
formatSize,
format,
dataSize,
data,
loopStart,
loopLength,
duration
);
}

static [[nodiscard]] std::expected<Sound, std::string> Read(const std::filesystem::path& file) noexcept
{
if (file.extension().string() != ".wav") return std::unexpected("Wrong file format");

BinaryReader stream{ file };

stream.Seek(16);
const std::uint32_t formatSize{ stream.Read<std::uint32_t>() };

std::vector<std::uint8_t> format;
for (std::size_t i{ 0 }; i < formatSize; i++) {
format.emplace_back(stream.Read<std::uint8_t>());
}

stream.Seek(4);
const std::uint32_t dataSize{ stream.Read<std::uint32_t>() };

std::vector<std::uint8_t> data;
for (std::size_t i{ 0 }; i < dataSize; i++) {
data.emplace_back(stream.Read<std::uint8_t>());
}

return std::expected<Sound, std::string>(
std::in_place,
formatSize,
format,
dataSize,
data,
0,
0,
0
);
}

void Export(const std::filesystem::path& file) const noexcept override
{
if (file.extension().string() != ".wav") return;

if (std::filesystem::exists(file)) {
std::filesystem::remove(file);
}

const std::size_t size{ Data.size() + Format.size() + 20 };

BinaryWriter stream{ file };
stream.Write<std::string>("RIFF");
stream.Write<std::int32_t>(static_cast<std::int32_t>(size - 8));
stream.Write<std::string>("WAVE");
stream.Write<std::string>("fmt ");

const std::int16_t wavTypeFormat{ static_cast<std::int16_t>((Format[1] << 8) | Format[0]) };
const std::int16_t flags{ static_cast<std::int16_t>((Format[3] << 8) | Format[2]) };
const std::int32_t sampleRate{ static_cast<std::int32_t>((Format[7] << 24) | (Format[6] << 16) | (Format[5] << 8) | Format[4]) };
const std::int32_t bytesPerSec{ static_cast<std::int32_t>((Format[11] << 24) | (Format[10] << 16) | (Format[9] << 8) | Format[8]) };
const std::int16_t blockAlignment{ static_cast<std::int16_t>((Format[13] << 8) | Format[12]) };
const std::int16_t bitsPerSample{ static_cast<std::int16_t>((Format[15] << 8) | Format[14]) };

stream.Write<std::int32_t>(FormatSize);
stream.Write<std::int16_t>(wavTypeFormat);
stream.Write<std::int16_t>(flags);
stream.Write<std::int32_t>(sampleRate);
stream.Write<std::int32_t>(bytesPerSec);
stream.Write<std::int16_t>(blockAlignment);
stream.Write<std::int16_t>(bitsPerSample);

stream.Write<std::uint8_t>(0);
stream.Write<std::uint8_t>(0);

stream.Write<std::string>("data");
stream.Write<std::int32_t>(DataSize);
for (const std::uint8_t data : Data) {
stream.Write<std::uint8_t>(data);
}
}

[[nodiscard]] std::string Binary() const noexcept override
{
BinaryWriter stream{};
stream.Write<std::uint32_t>(FormatSize);
for (const std::uint8_t format : Format) {
stream.Write<std::uint8_t>(format);
}

stream.Write<std::uint32_t>(DataSize);
for (const std::uint8_t data : Data) {
stream.Write<std::uint8_t>(data);
}

stream.Write<std::int32_t>(LoopStart);
stream.Write<std::int32_t>(LoopLength);
stream.Write<std::int32_t>(Duration);

return stream.ToString();
}

[[nodiscard]] std::string ReaderName() const noexcept override
{
return Sound::Reader;
}
};
2 changes: 2 additions & 0 deletions Editor/Parser/Texture.ixx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ public:

static [[nodiscard]] std::expected<Texture, std::string> Read(const std::filesystem::path& file) noexcept
{
if (file.extension().string() != ".png") return std::unexpected("Wrong file format");

std::int32_t width{};
std::int32_t height{};
std::int32_t comp{};
Expand Down
118 changes: 69 additions & 49 deletions Editor/Parser/Xnb.ixx
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ import FlagBits;
import XCompress;
import Converter;
import Texture;
import Sound;

export class Xnb final {
private:
inline constexpr static std::uint8_t _headerSize{ 14 };
constexpr static std::uint8_t _headerSize{ 14 };

public:
const TargetPlatform Platform;
Expand Down Expand Up @@ -76,65 +77,37 @@ public:

std::size_t compressedSize{ stream.Read<std::uint32_t>() };
std::size_t decompressedSize{ 0 };

if (flagBits == FlagBits::Compressed) {
decompressedSize = stream.Read<std::uint32_t>();
}

std::string compressedData{ stream.Read(static_cast<std::size_t>(compressedSize) - _headerSize) };
std::string compressedData{ stream.Read(static_cast<std::size_t>(compressedSize) - _headerSize) };

XMEMDECOMPRESSION_CONTEXT decompressionContext{ 0 };
XMEMDECOMPRESSION_CONTEXT decompressionContext{ 0 };

XMEMCODEC_PARAMETERS_LZX codecParams{};
codecParams.Flags = 0;
codecParams.WindowSize = 64 * 1024;
codecParams.CompressionPartitionSize = 256 * 1024;

if (XMemCreateDecompressionContext(XMEMCODEC_TYPE::XMEMCODEC_LZX, &codecParams, 0, &decompressionContext) != 0) {
return std::unexpected("Could not create decompression context");
}
XMEMCODEC_PARAMETERS_LZX codecParams{};
codecParams.Flags = 0;
codecParams.WindowSize = 64 * 1024;
codecParams.CompressionPartitionSize = 256 * 1024;

std::string decompressedData{};
decompressedData.resize(decompressedSize);
if (XMemDecompress(decompressionContext, &decompressedData[0], &decompressedSize, &compressedData[0], compressedData.size()) != 0) {
XMemDestroyDecompressionContext(decompressionContext);
return std::unexpected("Failed decompression");
}

XMemDestroyDecompressionContext(decompressionContext);

BinaryReader memoryStream{ decompressedData };

const std::uint8_t readersCount{ memoryStream.Read7BitEncodedInteger() };
if (readersCount > 1) return std::unexpected("Only 1 reader supported");

const std::uint8_t typeLength{ memoryStream.Read7BitEncodedInteger() };
const std::string typeName{ memoryStream.Read(typeLength) };
const std::int32_t version{ memoryStream.Read<std::int32_t>() };
if (XMemCreateDecompressionContext(XMEMCODEC_TYPE::XMEMCODEC_LZX, &codecParams, 0, &decompressionContext) != 0) {
return std::unexpected("Could not create decompression context");
}

const std::uint8_t resourcesCount{ memoryStream.Read7BitEncodedInteger() };
if (resourcesCount != 0) std::unexpected("Invalid resources count");
std::string decompressedData{};
decompressedData.resize(decompressedSize);
if (XMemDecompress(decompressionContext, &decompressedData[0], &decompressedSize, &compressedData[0], compressedData.size()) != 0) {
XMemDestroyDecompressionContext(decompressionContext);
return std::unexpected("Failed decompression");
}

const std::uint8_t index{ memoryStream.Read7BitEncodedInteger() };
if (index > readersCount) std::unexpected("Resources count and readers count do not match");
XMemDestroyDecompressionContext(decompressionContext);

std::unique_ptr<Converter> type{ nullptr };
if (typeName == Texture::Reader) {
if (std::expected<Texture, std::string> texture = Texture::Read(memoryStream); texture.has_value()) {
type = std::make_unique<Texture>(std::move(texture.value()));
}
BinaryReader memoryStream{ decompressedData };
return Xnb::FinishReading(memoryStream, targetPlatform, formatVersion, flagBits, compressedData, decompressedData);
}

if (type == nullptr) return std::unexpected("File type not supported or there was an error while reading it");

return std::expected<Xnb, std::string>(
std::in_place,
targetPlatform,
formatVersion,
flagBits,
compressedData,
decompressedData,
std::move(type)
);
return Xnb::FinishReading(stream, targetPlatform, formatVersion, flagBits, {}, {});
}

template<Convertible T>
Expand All @@ -156,6 +129,12 @@ public:
type = std::make_unique<Texture>(std::move(texture.value()));
}
}
else if constexpr (std::is_same<T, Sound>::value) {
if (extension != ".wav") return std::unexpected("Wrong file extension");
if (std::expected<Sound, std::string> sound = Sound::Read(file); sound.has_value()) {
type = std::make_unique<Sound>(std::move(sound.value()));
}
}

if (type == nullptr) return std::unexpected("File type not supported or there was an error while reading it");

Expand Down Expand Up @@ -208,4 +187,45 @@ public:
std::move(type)
);
}

private:
[[nodiscard]] static std::expected<Xnb, std::string> FinishReading(BinaryReader& stream, const TargetPlatform targetPlatform, const std::uint8_t formatVersion, const FlagBits flagBits, const std::string& compressedData, const std::string& decompressedData)
{
const std::uint8_t readersCount{ stream.Read7BitEncodedInteger() };
if (readersCount > 1) return std::unexpected("Only 1 reader supported");

const std::uint8_t typeLength{ stream.Read7BitEncodedInteger() };
const std::string typeName{ stream.Read(typeLength) };
const std::int32_t version{ stream.Read<std::int32_t>() };

const std::uint8_t resourcesCount{ stream.Read7BitEncodedInteger() };
if (resourcesCount != 0) std::unexpected("Invalid resources count");

const std::uint8_t index{ stream.Read7BitEncodedInteger() };
if (index > readersCount) std::unexpected("Resources count and readers count do not match");

std::unique_ptr<Converter> type{ nullptr };
if (typeName == Texture::Reader) {
if (std::expected<Texture, std::string> texture = Texture::Read(stream); texture.has_value()) {
type = std::make_unique<Texture>(std::move(texture.value()));
}
}
else if (typeName == Sound::Reader) {
if (std::expected<Sound, std::string> sound = Sound::Read(stream); sound.has_value()) {
type = std::make_unique<Sound>(std::move(sound.value()));
}
}

if (type == nullptr) return std::unexpected("File type not supported or there was an error while reading it");

return std::expected<Xnb, std::string>(
std::in_place,
targetPlatform,
formatVersion,
flagBits,
compressedData,
decompressedData,
std::move(type)
);
}
};

0 comments on commit 7375f15

Please sign in to comment.