mirror of
https://github.com/rwengine/openrw.git
synced 2024-09-15 15:02:34 +02:00
Introduce LoaderSDT for SDT/RAW audio files
This commit is contained in:
parent
4df20821e7
commit
727de03eb5
@ -29,6 +29,8 @@ SET(RWLIB_SOURCES
|
||||
"source/loaders/RWBinaryStream.hpp"
|
||||
"source/loaders/LoaderDFF.hpp"
|
||||
"source/loaders/LoaderDFF.cpp"
|
||||
"source/loaders/LoaderSDT.hpp"
|
||||
"source/loaders/LoaderSDT.cpp"
|
||||
"source/loaders/LoaderTXD.hpp"
|
||||
"source/loaders/LoaderTXD.cpp"
|
||||
|
||||
|
156
rwlib/source/loaders/LoaderSDT.cpp
Normal file
156
rwlib/source/loaders/LoaderSDT.cpp
Normal file
@ -0,0 +1,156 @@
|
||||
#include <loaders/LoaderSDT.hpp>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
LoaderSDT::LoaderSDT()
|
||||
: m_version(GTAIIIVC)
|
||||
, m_assetCount(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char chunkId[4];
|
||||
uint32_t chunkSize;
|
||||
char format[4];
|
||||
struct {
|
||||
char id[4];
|
||||
uint32_t size;
|
||||
uint16_t audioFormat;
|
||||
uint16_t numChannels;
|
||||
uint32_t sampleRate;
|
||||
uint32_t byteRate;
|
||||
uint16_t blockAlign;
|
||||
uint16_t bitsPerSample;
|
||||
} fmt;
|
||||
struct {
|
||||
char id[4];
|
||||
uint32_t size;
|
||||
} data;
|
||||
} WaveHeader;
|
||||
|
||||
bool LoaderSDT::load(const std::string& filename)
|
||||
{
|
||||
auto baseName = filename;
|
||||
auto sdtName = baseName + ".SDT";
|
||||
auto rawName = baseName + ".RAW";
|
||||
|
||||
FILE* fp = fopen(sdtName.c_str(), "rb");
|
||||
if (fp) {
|
||||
fseek(fp, 0, SEEK_END);
|
||||
unsigned long fileSize = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
m_assetCount = fileSize / 20;
|
||||
m_assets.resize(m_assetCount);
|
||||
|
||||
if ((m_assetCount = fread(&m_assets[0], sizeof(LoaderSDTFile), m_assetCount, fp)) != fileSize / 20) {
|
||||
m_assets.resize(m_assetCount);
|
||||
std::cout << "Error reading records in SDT archive" << std::endl;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
m_archive = rawName;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the information of a asset in the examining archive
|
||||
bool LoaderSDT::findAssetInfo(size_t index, LoaderSDTFile& out)
|
||||
{
|
||||
if (index < m_assets.size()) {
|
||||
out = m_assets[index];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
char* LoaderSDT::loadToMemory(size_t index, bool asWave)
|
||||
{
|
||||
LoaderSDTFile assetInfo;
|
||||
bool found = findAssetInfo(index, assetInfo);
|
||||
|
||||
if(!found) {
|
||||
std::cerr << "Asset " << std::to_string(index) << " not found!" << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string rawName = m_archive;
|
||||
|
||||
FILE* fp = fopen(rawName.c_str(), "rb");
|
||||
if (fp) {
|
||||
char* raw_data;
|
||||
char* sample_data;
|
||||
if (asWave) {
|
||||
raw_data = new char[sizeof(WaveHeader) + assetInfo.size];
|
||||
|
||||
WaveHeader* header = reinterpret_cast<WaveHeader*>(raw_data);
|
||||
memcpy(header->chunkId, "RIFF", 4);
|
||||
header->chunkSize = sizeof(WaveHeader) - 8 + assetInfo.size;
|
||||
memcpy(header->format, "WAVE", 4);
|
||||
memcpy(header->fmt.id, "fmt ", 4);
|
||||
header->fmt.size = sizeof(WaveHeader::fmt) - 8;
|
||||
header->fmt.audioFormat = 1; // PCM
|
||||
header->fmt.numChannels = 1; // Mono
|
||||
header->fmt.sampleRate = assetInfo.sampleRate;
|
||||
header->fmt.byteRate = assetInfo.sampleRate * 2;
|
||||
header->fmt.blockAlign = 2;
|
||||
header->fmt.bitsPerSample = 16;
|
||||
memcpy(header->data.id, "data", 4);
|
||||
header->data.size = assetInfo.size;
|
||||
|
||||
sample_data = raw_data + sizeof(WaveHeader);
|
||||
} else {
|
||||
raw_data = new char[assetInfo.size];
|
||||
sample_data = raw_data;
|
||||
}
|
||||
|
||||
fseek(fp, assetInfo.offset, SEEK_SET);
|
||||
if (fread(sample_data, 1, assetInfo.size, fp) != assetInfo.size) {
|
||||
std::cerr << "Error reading asset " << std::to_string(index) << std::endl;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return raw_data;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Writes the contents of assetname to filename
|
||||
bool LoaderSDT::saveAsset(size_t index, const std::string& filename, bool asWave)
|
||||
{
|
||||
char* raw_data = loadToMemory(index, asWave);
|
||||
if(!raw_data)
|
||||
return false;
|
||||
|
||||
FILE* dumpFile = fopen(filename.c_str(), "wb");
|
||||
if(dumpFile) {
|
||||
LoaderSDTFile asset;
|
||||
if(findAssetInfo(index, asset)) {
|
||||
fwrite(raw_data, 1, asset.size + (asWave ? sizeof(WaveHeader) : 0), dumpFile);
|
||||
printf("=> SDT: Saved %zu to disk with filename %s\n", index, filename.c_str());
|
||||
}
|
||||
fclose(dumpFile);
|
||||
|
||||
delete[] raw_data;
|
||||
return true;
|
||||
} else {
|
||||
delete[] raw_data;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the information of an asset by its index
|
||||
const LoaderSDTFile &LoaderSDT::getAssetInfoByIndex(size_t index) const
|
||||
{
|
||||
return m_assets[index];
|
||||
}
|
||||
|
||||
|
||||
uint32_t LoaderSDT::getAssetCount() const
|
||||
{
|
||||
return m_assetCount;
|
||||
}
|
67
rwlib/source/loaders/LoaderSDT.hpp
Normal file
67
rwlib/source/loaders/LoaderSDT.hpp
Normal file
@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
#ifndef _LOADERSDT_HPP_
|
||||
#define _LOADERSDT_HPP_
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
|
||||
/// \brief Points to one file within the archive
|
||||
class LoaderSDTFile
|
||||
{
|
||||
public:
|
||||
uint32_t offset; // offset of audio file in sfx.raw
|
||||
uint32_t size; // size of audio file in bytes
|
||||
uint32_t sampleRate; // the speed of audio
|
||||
uint32_t loopStart; /// loop start, where looping would begin relative to audio file's position, 0 for beginning of audio file
|
||||
uint32_t loopEnd; /// where looping would end relative to audio file's position, -1 for end of audio file
|
||||
};
|
||||
|
||||
/**
|
||||
\class LoaderSDT
|
||||
\brief Parses the structure of GTA .SDT archives and loads the files in it
|
||||
*/
|
||||
class LoaderSDT
|
||||
{
|
||||
public:
|
||||
/// Multiple versions of .SDT files
|
||||
enum Versions
|
||||
{
|
||||
GTA2,
|
||||
GTAIIIVC ///< GTA III and GTA VC archives -- only this one is implemented
|
||||
};
|
||||
|
||||
/// Construct
|
||||
LoaderSDT();
|
||||
|
||||
/// Load the structure of the archive
|
||||
/// Omit the extension in filename
|
||||
bool load(const std::string& filename);
|
||||
|
||||
/// Load a file from the archive to memory and pass a pointer to it
|
||||
/// Warning: Please delete[] the memory in the end.
|
||||
/// Warning: Returns NULL (0) if by any reason it can't load the file
|
||||
char* loadToMemory(size_t index, bool asWave = true);
|
||||
|
||||
/// Writes the contents of index to filename
|
||||
bool saveAsset(size_t index, const std::string& filename, bool asWave = true);
|
||||
|
||||
/// Get the information of an asset in the examining archive
|
||||
bool findAssetInfo(size_t index, LoaderSDTFile& out);
|
||||
|
||||
/// Get the information of an asset by its index
|
||||
const LoaderSDTFile &getAssetInfoByIndex(size_t index) const;
|
||||
|
||||
/// Returns the number of asset files in the archive
|
||||
uint32_t getAssetCount() const;
|
||||
|
||||
private:
|
||||
Versions m_version; ///< Version of this SDT archive
|
||||
uint32_t m_assetCount; ///< Number of assets in the current archive
|
||||
std::string m_archive; ///< Path to the archive being used (no extension)
|
||||
|
||||
std::vector<LoaderSDTFile> m_assets; ///< Asset info of the archive
|
||||
};
|
||||
|
||||
|
||||
#endif // LoaderSDT_h__
|
Loading…
Reference in New Issue
Block a user