mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-04-21 00:25:44 +00:00
add flac decoding to correctly add flac sounds to sound banks
This commit is contained in:
parent
aa2bebedde
commit
42c4068d2a
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -13,3 +13,6 @@
|
|||||||
[submodule "thirdparty/json"]
|
[submodule "thirdparty/json"]
|
||||||
path = thirdparty/json
|
path = thirdparty/json
|
||||||
url = https://github.com/nlohmann/json.git
|
url = https://github.com/nlohmann/json.git
|
||||||
|
[submodule "thirdparty/flac"]
|
||||||
|
path = thirdparty/flac
|
||||||
|
url = https://github.com/astoeckel/libfoxenflac.git
|
||||||
|
@ -83,6 +83,7 @@ workspace "OpenAssetTools"
|
|||||||
-- ThirdParty
|
-- ThirdParty
|
||||||
-- ========================
|
-- ========================
|
||||||
include "thirdparty/catch2.lua"
|
include "thirdparty/catch2.lua"
|
||||||
|
include "thirdparty/flac.lua"
|
||||||
include "thirdparty/libtomcrypt.lua"
|
include "thirdparty/libtomcrypt.lua"
|
||||||
include "thirdparty/libtommath.lua"
|
include "thirdparty/libtommath.lua"
|
||||||
include "thirdparty/json.lua"
|
include "thirdparty/json.lua"
|
||||||
@ -94,6 +95,7 @@ include "thirdparty/zlib.lua"
|
|||||||
-- ThirdParty group: All projects that are external dependencies
|
-- ThirdParty group: All projects that are external dependencies
|
||||||
group "ThirdParty"
|
group "ThirdParty"
|
||||||
catch2:project()
|
catch2:project()
|
||||||
|
flac:project()
|
||||||
libtommath:project()
|
libtommath:project()
|
||||||
libtomcrypt:project()
|
libtomcrypt:project()
|
||||||
json:project()
|
json:project()
|
||||||
|
@ -15,6 +15,7 @@ function ObjCommon:link(links)
|
|||||||
links:linkto(Utils)
|
links:linkto(Utils)
|
||||||
links:linkto(Common)
|
links:linkto(Common)
|
||||||
links:linkto(minizip)
|
links:linkto(minizip)
|
||||||
|
links:linkto(flac)
|
||||||
end
|
end
|
||||||
|
|
||||||
function ObjCommon:use()
|
function ObjCommon:use()
|
||||||
@ -48,4 +49,5 @@ function ObjCommon:project()
|
|||||||
|
|
||||||
self:include(includes)
|
self:include(includes)
|
||||||
Utils:include(includes)
|
Utils:include(includes)
|
||||||
|
flac:include(includes)
|
||||||
end
|
end
|
||||||
|
77
src/ObjCommon/Sound/FlacDecoder.cpp
Normal file
77
src/ObjCommon/Sound/FlacDecoder.cpp
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
#include <foxen/flac.h>
|
||||||
|
#include "FlacDecoder.h"
|
||||||
|
|
||||||
|
class fx_flac_raii
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
fx_flac_raii()
|
||||||
|
{
|
||||||
|
ptr = FX_FLAC_ALLOC_DEFAULT();
|
||||||
|
}
|
||||||
|
|
||||||
|
~fx_flac_raii()
|
||||||
|
{
|
||||||
|
free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fx_flac_t* ()
|
||||||
|
{
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
fx_flac_t* ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FlacDecoderImpl : public FlacDecoder
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
void* m_data;
|
||||||
|
size_t m_length;
|
||||||
|
std::unique_ptr<fx_flac_raii> m_flac;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit FlacDecoderImpl(void* data, size_t length)
|
||||||
|
: m_data(data),
|
||||||
|
m_length(length)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int GetFrameCount() override
|
||||||
|
{
|
||||||
|
return static_cast<unsigned int>(fx_flac_get_streaminfo(*m_flac.get(), FLAC_KEY_N_SAMPLES));
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int GetFrameRate() override
|
||||||
|
{
|
||||||
|
return static_cast<unsigned int>(fx_flac_get_streaminfo(*m_flac.get(), FLAC_KEY_SAMPLE_RATE));
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int GetNumChannels() override
|
||||||
|
{
|
||||||
|
return static_cast<unsigned int>(fx_flac_get_streaminfo(*m_flac.get(), FLAC_KEY_N_CHANNELS));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Decode() override
|
||||||
|
{
|
||||||
|
m_flac = std::make_unique<fx_flac_raii>();
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
auto res = fx_flac_process(*m_flac.get(), reinterpret_cast<uint8_t*>(m_data), &m_length, nullptr, nullptr);
|
||||||
|
if (res == FLAC_ERR)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (res == FLAC_END_OF_METADATA)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<FlacDecoder> FlacDecoder::Create(void* data, size_t length)
|
||||||
|
{
|
||||||
|
return std::make_unique<FlacDecoderImpl>(data, length);
|
||||||
|
}
|
21
src/ObjCommon/Sound/FlacDecoder.h
Normal file
21
src/ObjCommon/Sound/FlacDecoder.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <istream>
|
||||||
|
|
||||||
|
class FlacDecoder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FlacDecoder() = default;
|
||||||
|
virtual ~FlacDecoder() = default;
|
||||||
|
|
||||||
|
FlacDecoder(const FlacDecoder& other) = default;
|
||||||
|
FlacDecoder(FlacDecoder&& other) noexcept = default;
|
||||||
|
FlacDecoder& operator=(const FlacDecoder& other) = default;
|
||||||
|
FlacDecoder& operator=(FlacDecoder&& other) noexcept = default;
|
||||||
|
|
||||||
|
virtual bool Decode() = 0;
|
||||||
|
virtual unsigned int GetFrameCount() = 0;
|
||||||
|
virtual unsigned int GetFrameRate() = 0;
|
||||||
|
virtual unsigned int GetNumChannels() = 0;
|
||||||
|
|
||||||
|
static std::unique_ptr<FlacDecoder> Create(void* data, size_t length);
|
||||||
|
};
|
@ -3,9 +3,11 @@
|
|||||||
#include "Crypto.h"
|
#include "Crypto.h"
|
||||||
#include "ObjContainer/SoundBank/SoundBankTypes.h"
|
#include "ObjContainer/SoundBank/SoundBankTypes.h"
|
||||||
#include "Sound/WavTypes.h"
|
#include "Sound/WavTypes.h"
|
||||||
|
#include "Sound/FlacDecoder.h"
|
||||||
#include "Utils/Alignment.h"
|
#include "Utils/Alignment.h"
|
||||||
#include "Utils/FileUtils.h"
|
#include "Utils/FileUtils.h"
|
||||||
|
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@ -128,13 +130,6 @@ public:
|
|||||||
|
|
||||||
soundSize = static_cast<size_t>(wavFile.m_length - sizeof(WavHeader));
|
soundSize = static_cast<size_t>(wavFile.m_length - sizeof(WavHeader));
|
||||||
auto frameCount = soundSize / (header.formatChunk.nChannels * (header.formatChunk.wBitsPerSample / 8));
|
auto frameCount = soundSize / (header.formatChunk.nChannels * (header.formatChunk.wBitsPerSample / 8));
|
||||||
|
|
||||||
if (!sound.streamed && header.formatChunk.nSamplesPerSec != 48000)
|
|
||||||
{
|
|
||||||
std::cout << "WARNING: \"" << soundFilePath << "\" has a framerate of " << header.formatChunk.nSamplesPerSec
|
|
||||||
<< ". Loaded sounds are recommended to have a framerate of 48000. This sound may not work on all games!" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto frameRateIndex = INDEX_FOR_FRAMERATE[header.formatChunk.nSamplesPerSec];
|
auto frameRateIndex = INDEX_FOR_FRAMERATE[header.formatChunk.nSamplesPerSec];
|
||||||
|
|
||||||
SoundAssetBankEntry entry{
|
SoundAssetBankEntry entry{
|
||||||
@ -161,21 +156,31 @@ public:
|
|||||||
{
|
{
|
||||||
soundSize = static_cast<size_t>(flacFile.m_length);
|
soundSize = static_cast<size_t>(flacFile.m_length);
|
||||||
|
|
||||||
|
soundData = std::make_unique<char[]>(soundSize);
|
||||||
|
flacFile.m_stream->read(soundData.get(), soundSize);
|
||||||
|
|
||||||
|
auto decoder = FlacDecoder::Create(soundData.get(), soundSize);
|
||||||
|
if (decoder->Decode())
|
||||||
|
{
|
||||||
|
auto frameRateIndex = INDEX_FOR_FRAMERATE[decoder->GetFrameRate()];
|
||||||
SoundAssetBankEntry entry{
|
SoundAssetBankEntry entry{
|
||||||
soundId,
|
soundId,
|
||||||
soundSize,
|
soundSize,
|
||||||
static_cast<size_t>(m_current_offset),
|
static_cast<size_t>(m_current_offset),
|
||||||
0,
|
decoder->GetFrameCount(),
|
||||||
0,
|
frameRateIndex,
|
||||||
0,
|
decoder->GetNumChannels(),
|
||||||
0,
|
sound.looping,
|
||||||
8,
|
8,
|
||||||
};
|
};
|
||||||
|
|
||||||
m_entries.push_back(entry);
|
m_entries.push_back(entry);
|
||||||
|
}
|
||||||
soundData = std::make_unique<char[]>(soundSize);
|
else
|
||||||
flacFile.m_stream->read(soundData.get(), soundSize);
|
{
|
||||||
|
std::cerr << "Unable to decode .flac file for sound " << soundFilePath << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -184,6 +189,12 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto lastEntry = m_entries.rbegin();
|
||||||
|
if (!sound.streamed && lastEntry->frameRateIndex != 6)
|
||||||
|
{
|
||||||
|
std::cout << "WARNING: Loaded sound \"" << soundFilePath << "\" should have a framerate of 48000 but doesn't. This sound may not work on all games!" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
// calculate checksum
|
// calculate checksum
|
||||||
SoundAssetBankChecksum checksum{};
|
SoundAssetBankChecksum checksum{};
|
||||||
|
|
||||||
|
1
thirdparty/flac
vendored
Submodule
1
thirdparty/flac
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 1b04fafb51aac0c3b7f0118a7bf7c93f6a60d824
|
47
thirdparty/flac.lua
vendored
Normal file
47
thirdparty/flac.lua
vendored
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
flac = {}
|
||||||
|
|
||||||
|
function flac:include(includes)
|
||||||
|
if includes:handle(self:name()) then
|
||||||
|
includedirs {
|
||||||
|
path.join(ThirdPartyFolder(), "flac")
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function flac:link(links)
|
||||||
|
links:add(self:name())
|
||||||
|
end
|
||||||
|
|
||||||
|
function flac:use()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function flac:name()
|
||||||
|
return "flac"
|
||||||
|
end
|
||||||
|
|
||||||
|
function flac:project()
|
||||||
|
local folder = ThirdPartyFolder()
|
||||||
|
local includes = Includes:create()
|
||||||
|
|
||||||
|
project(self:name())
|
||||||
|
targetdir(TargetDirectoryLib)
|
||||||
|
location "%{wks.location}/thirdparty/%{prj.name}"
|
||||||
|
kind "StaticLib"
|
||||||
|
language "C"
|
||||||
|
|
||||||
|
files {
|
||||||
|
path.join(folder, "flac/foxen/*.h"),
|
||||||
|
path.join(folder, "flac/foxen/*.c")
|
||||||
|
}
|
||||||
|
|
||||||
|
defines {
|
||||||
|
"_CRT_SECURE_NO_WARNINGS",
|
||||||
|
"_CRT_NONSTDC_NO_DEPRECATE"
|
||||||
|
}
|
||||||
|
|
||||||
|
self:include(includes)
|
||||||
|
|
||||||
|
-- Disable warnings. They do not have any value to us since it is not our code.
|
||||||
|
warnings "off"
|
||||||
|
end
|
Loading…
x
Reference in New Issue
Block a user