1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-11-07 03:12:36 +01:00

Introduce LoaderSDT for SDT/RAW audio files

This commit is contained in:
Jannik Vogel 2016-05-30 23:06:28 +02:00
parent 4df20821e7
commit 727de03eb5
3 changed files with 225 additions and 0 deletions

View File

@ -29,6 +29,8 @@ SET(RWLIB_SOURCES
"source/loaders/RWBinaryStream.hpp" "source/loaders/RWBinaryStream.hpp"
"source/loaders/LoaderDFF.hpp" "source/loaders/LoaderDFF.hpp"
"source/loaders/LoaderDFF.cpp" "source/loaders/LoaderDFF.cpp"
"source/loaders/LoaderSDT.hpp"
"source/loaders/LoaderSDT.cpp"
"source/loaders/LoaderTXD.hpp" "source/loaders/LoaderTXD.hpp"
"source/loaders/LoaderTXD.cpp" "source/loaders/LoaderTXD.cpp"

View 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;
}

View 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__