Changed up how resources import/export files. Added Model codecs.
This commit is contained in:
@@ -57,6 +57,29 @@ namespace ehs
|
||||
AddType("Audio");
|
||||
}
|
||||
|
||||
Audio::Audio(const Str_8& filePath)
|
||||
: Resource(File::ParseName_8(filePath)), sampleRate(0), dataType(DataType::FLOAT), byteDepth(0), channels(0),
|
||||
frames(0), length(0.0f), data(nullptr), peak(nullptr)
|
||||
{
|
||||
AddType("Audio");
|
||||
|
||||
File file(filePath, Mode::READ, Disposition::OPEN);
|
||||
Str_8 ext = file.GetExtension();
|
||||
|
||||
const AudioCodec* codec = GetCodec(ext);
|
||||
if (!codec)
|
||||
{
|
||||
EHS_LOG_INT("Error", 0, "Codec not found for file extension, \"" + ext + "\".");
|
||||
return;
|
||||
}
|
||||
|
||||
Serializer<UInt_64> data = file.ReadSerializer_64(codec->GetEndianness(), file.Size());
|
||||
|
||||
file.Release();
|
||||
|
||||
codec->Decode(data, this);
|
||||
}
|
||||
|
||||
Audio::Audio(Str_8 id, const UInt_64 sampleRate, const DataType dataType, const UInt_8 channels, const UInt_64 frames, const Byte* const data)
|
||||
: Resource((Str_8&&)id), dataType(dataType), byteDepth(ToByteDepth(dataType)), sampleRate(sampleRate),
|
||||
channels(channels), frames(frames), length((float)frames / (float)sampleRate),
|
||||
@@ -105,13 +128,6 @@ namespace ehs
|
||||
AddType("Audio");
|
||||
}
|
||||
|
||||
Audio::Audio(Str_8 id)
|
||||
: Resource((Str_8&&)id), sampleRate(0), dataType(DataType::FLOAT), byteDepth(0), channels(0),
|
||||
frames(0), length(0.0f), data(nullptr), peak(nullptr)
|
||||
{
|
||||
AddType("Audio");
|
||||
}
|
||||
|
||||
Audio::Audio(Audio&& audio) noexcept
|
||||
: Resource((Resource&&)audio), sampleRate(audio.sampleRate), dataType(audio.dataType),
|
||||
byteDepth(audio.byteDepth), channels(audio.channels), frames(audio.frames), length(audio.length),
|
||||
@@ -853,7 +869,7 @@ namespace ehs
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Audio::ToFile(const Str_8& filePath) const
|
||||
bool Audio::Export(const Str_8& filePath) const
|
||||
{
|
||||
Str_8 ext = File::ParseExt_8(filePath);
|
||||
|
||||
@@ -874,96 +890,6 @@ namespace ehs
|
||||
return true;
|
||||
}
|
||||
|
||||
Audio Audio::FromFile(const Str_8& filePath)
|
||||
{
|
||||
File file(filePath, Mode::READ, Disposition::OPEN);
|
||||
Str_8 ext = file.GetExtension();
|
||||
|
||||
Audio result(file.GetName());
|
||||
|
||||
const AudioCodec* codec = GetCodec(ext);
|
||||
if (!codec)
|
||||
{
|
||||
EHS_LOG_INT("Error", 0, "Codec not found for file extension, \"" + ext + "\".");
|
||||
return result;
|
||||
}
|
||||
|
||||
Serializer<UInt_64> data = file.ReadSerializer_64(codec->GetEndianness(), file.Size());
|
||||
|
||||
file.Release();
|
||||
|
||||
if (!codec->Decode(data, &result))
|
||||
return {};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Audio* Audio::FromFile_Heap(const Str_8& filePath)
|
||||
{
|
||||
File file(filePath, Mode::READ, Disposition::OPEN);
|
||||
Str_8 ext = file.GetExtension();
|
||||
|
||||
Audio* result = nullptr;
|
||||
|
||||
const AudioCodec* codec = GetCodec(ext);
|
||||
if (!codec)
|
||||
{
|
||||
EHS_LOG_INT("Error", 0, "Codec not found for file extension, \"" + ext + "\".");
|
||||
return result;
|
||||
}
|
||||
|
||||
result = new Audio(file.GetName());
|
||||
|
||||
Serializer<UInt_64> data = file.ReadSerializer_64(codec->GetEndianness(), file.Size());
|
||||
|
||||
file.Release();
|
||||
|
||||
if (!codec->Decode(data, result))
|
||||
{
|
||||
delete result;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Audio Audio::FromFile(const Str_8& filePath, const DataType required)
|
||||
{
|
||||
Audio result = std::move(FromFile(filePath));
|
||||
if (!result.data)
|
||||
return result;
|
||||
|
||||
result.ToDataType(required);
|
||||
return result;
|
||||
}
|
||||
|
||||
Audio* Audio::FromFile_Heap(const Str_8& filePath, const DataType required)
|
||||
{
|
||||
Audio* result = FromFile_Heap(filePath);
|
||||
if (!result)
|
||||
return result;
|
||||
|
||||
result->ToDataType(required);
|
||||
return result;
|
||||
}
|
||||
|
||||
Audio Audio::FromData(Str_8 id, const Str_8& ext, Serializer<UInt_64>& data)
|
||||
{
|
||||
Audio result((Str_8&&)id);
|
||||
|
||||
const AudioCodec* codec = GetCodec(ext);
|
||||
if (!codec)
|
||||
{
|
||||
EHS_LOG_INT("Error", 0, "Codec not found for file extension, \"" + ext + "\".");
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!codec->Decode(data, &result))
|
||||
return {};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Audio::ToMono(const UInt_64 newFrameCount, Byte* newData, const UInt_64 frameOffset) const
|
||||
{
|
||||
switch (dataType)
|
||||
@@ -1948,4 +1874,213 @@ namespace ehs
|
||||
|
||||
*(SInt_64*)newPeak = (SInt_64)((float)*(SInt_32*)peak / (float)EHS_SINT_32_MAX * (float)EHS_SINT_64_MAX);
|
||||
}
|
||||
|
||||
bool EncodeEHA(const ehs::AudioCodec* const codec, ehs::Serializer<ehs::UInt_64>& out, const ehs::Audio* const in)
|
||||
{
|
||||
Serializer<UInt_64> result(codec->GetEndianness());
|
||||
result.WriteVersion({1, 0, 0});
|
||||
result.Write(in->GetSampleRate());
|
||||
result.Write(in->GetDataType());
|
||||
result.Write(in->GetByteDepth());
|
||||
result.Write(in->GetChannels());
|
||||
result.Write(in->GetFrameCount());
|
||||
|
||||
UInt_64 size = in->GetSize();
|
||||
UInt_8 byteDepth = in->GetByteDepth();
|
||||
|
||||
result.Resize(result.Size() + size + byteDepth);
|
||||
Util::Copy(&result[result.GetOffset()], &in[0], size);
|
||||
result.SetOffset(result.GetOffset() + size);
|
||||
|
||||
Util::Copy(&result[result.GetOffset()], in->GetPeak(), byteDepth);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DecodeEHA(const ehs::AudioCodec* const codec, ehs::Serializer<ehs::UInt_64>& in, ehs::Audio* const out)
|
||||
{
|
||||
Version version = in.ReadVersion();
|
||||
if (version != Version(1, 0, 0))
|
||||
{
|
||||
EHS_LOG_INT("Error", 0, "Incompatible audio file version.");
|
||||
return false;
|
||||
}
|
||||
|
||||
UInt_64 sampleRate = in.Read<UInt_64>();
|
||||
DataType dataType = in.Read<DataType>();
|
||||
UInt_8 byteDepth = in.Read<UInt_8>();
|
||||
UInt_8 channels = in.Read<UInt_8>();
|
||||
UInt_64 frames = in.Read<UInt_64>();
|
||||
|
||||
*out = Audio(out->GetId(), sampleRate, dataType, channels, frames);
|
||||
|
||||
UInt_64 size = out->GetSize();
|
||||
Util::Copy(&(*out)[0], &in[in.GetOffset()], size);
|
||||
in.SetOffset(in.GetOffset() + size);
|
||||
|
||||
out->SetPeak(byteDepth, &in[in.GetOffset()]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DecodeWAV(const ehs::AudioCodec* const codec, ehs::Serializer<ehs::UInt_64>& in, ehs::Audio* out)
|
||||
{
|
||||
RIFF riff(in);
|
||||
|
||||
if (riff.GetType() != "WAVE")
|
||||
{
|
||||
EHS_LOG_INT("Error", 0, "Data is not in WAVE format.");
|
||||
return false;
|
||||
}
|
||||
|
||||
RIFF_Chunk fmt = riff.GetChunk("fmt ");
|
||||
if (!fmt.IsValid())
|
||||
{
|
||||
EHS_LOG_INT("Error", 1, "Wave does not have a format chunk.");
|
||||
return false;
|
||||
}
|
||||
|
||||
Serializer<> fmtSer = fmt.GetData();
|
||||
|
||||
RIFF_Chunk dChunk = riff.GetChunk("data");
|
||||
if (!dChunk.IsValid())
|
||||
{
|
||||
EHS_LOG_INT("Error", 2, "Wave does not have a data chunk.");
|
||||
return false;
|
||||
}
|
||||
|
||||
UInt_16 compression = fmtSer.Read<UInt_16>();
|
||||
if (compression == 0x2)
|
||||
{
|
||||
EHS_LOG_INT("Error", 3, "Microsoft ADPCM compression unsupported.");
|
||||
return false;
|
||||
}
|
||||
else if (compression == 0x6)
|
||||
{
|
||||
EHS_LOG_INT("Error", 4, "ITU G.711 a-law compression unsupported.");
|
||||
return false;
|
||||
}
|
||||
else if (compression == 0x7)
|
||||
{
|
||||
EHS_LOG_INT("Error", 5, "ITU G.711 µ-law compression unsupported.");
|
||||
return false;
|
||||
}
|
||||
else if (compression == 0x11)
|
||||
{
|
||||
EHS_LOG_INT("Error", 6, "IMA ADPCM compression unsupported.");
|
||||
return false;
|
||||
}
|
||||
else if (compression == 0x16)
|
||||
{
|
||||
EHS_LOG_INT("Error", 7, "TU G.723 ADPCM (Yamaha) compression unsupported.");
|
||||
return false;
|
||||
}
|
||||
else if (compression == 0x31)
|
||||
{
|
||||
EHS_LOG_INT("Error", 8, "GSM 6.10 compression unsupported.");
|
||||
return false;
|
||||
}
|
||||
else if (compression == 0x40)
|
||||
{
|
||||
EHS_LOG_INT("Error", 9, "ITU G.721 ADPCM compression unsupported.");
|
||||
return false;
|
||||
}
|
||||
else if (compression == 0x50)
|
||||
{
|
||||
EHS_LOG_INT("Error", 10, "MPEG compression unsupported.");
|
||||
return false;
|
||||
}
|
||||
else if (compression == 0xFFFF)
|
||||
{
|
||||
EHS_LOG_INT("Error", 11, "Experimental compression unsupported.");
|
||||
return false;
|
||||
}
|
||||
else if (compression != 0x1 && compression != 0x3)
|
||||
{
|
||||
EHS_LOG_INT("Error", 12, "Wave has unknown compression of " + Str_8::FromNum(compression) + ".");
|
||||
return false;
|
||||
}
|
||||
|
||||
UInt_16 channels = fmtSer.Read<UInt_16>();
|
||||
UInt_32 sampleRate = fmtSer.Read<UInt_32>();
|
||||
fmtSer.SetOffset(fmtSer.GetOffset() + 6);
|
||||
UInt_8 byteDepth = (UInt_8)(fmtSer.Read<UInt_16>() / 8);
|
||||
|
||||
DataType dataType;
|
||||
if (byteDepth == 1)
|
||||
dataType = DataType::SINT_8;
|
||||
else if (byteDepth == 2)
|
||||
dataType = DataType::SINT_16;
|
||||
else if (byteDepth == 3)
|
||||
dataType = DataType::SINT_24;
|
||||
else if (byteDepth == 4 && compression == 0x3)
|
||||
dataType = DataType::FLOAT;
|
||||
else if (byteDepth == 4)
|
||||
dataType = DataType::SINT_32;
|
||||
else if (byteDepth == 8)
|
||||
dataType = DataType::SINT_64;
|
||||
else
|
||||
return false;
|
||||
|
||||
UInt_64 size = dChunk.GetData().Size();
|
||||
UInt_64 frames = size / byteDepth / channels;
|
||||
|
||||
*out = std::move(Audio(out->GetId(), sampleRate, dataType, channels, frames));
|
||||
|
||||
Serializer<> dataSer = dChunk.GetData();
|
||||
|
||||
for (UInt_32 i = 0; i < dataSer.Size(); i += byteDepth)
|
||||
{
|
||||
if (byteDepth == 1)
|
||||
{
|
||||
*(SInt_8*)&(*out)[i] = dataSer.Read<SInt_8>();
|
||||
if ((*out)[i] > *(SInt_8*)out->GetPeak())
|
||||
out->SetPeak(sizeof(SInt_8), &(*out)[i]);
|
||||
}
|
||||
else if (byteDepth == 2)
|
||||
{
|
||||
*(SInt_16*)&(*out)[i] = dataSer.Read<SInt_16>();
|
||||
if (*(SInt_16*)&(*out)[i] > *(SInt_16*)out->GetPeak())
|
||||
out->SetPeak(sizeof(SInt_16), &(*out)[i]);
|
||||
}
|
||||
else if (byteDepth == 3)
|
||||
{
|
||||
*(SInt_16*)&(*out)[i + 1] = dataSer.Read<SInt_16>();
|
||||
(*out)[i] = dataSer.Read<Byte>();
|
||||
|
||||
SInt_32 signal = 0;
|
||||
signal |= (*out)[i];
|
||||
signal |= (*out)[i + 1] << 8;
|
||||
signal |= (*out)[i + 2] << 16;
|
||||
|
||||
SInt_32 peak = 0;
|
||||
peak |= out->GetPeak()[0];
|
||||
peak |= out->GetPeak()[1] << 8;
|
||||
peak |= out->GetPeak()[2] << 16;
|
||||
|
||||
if (signal > peak)
|
||||
out->SetPeak(3, &(*out)[i]);
|
||||
}
|
||||
else if (byteDepth == 4 && compression == 0x3)
|
||||
{
|
||||
*(float*)&(*out)[i] = dataSer.Read<float>();
|
||||
if (*(float*)&(*out)[i] > *(float*)out->GetPeak())
|
||||
out->SetPeak(sizeof(float), &(*out)[i]);
|
||||
}
|
||||
else if (byteDepth == 4)
|
||||
{
|
||||
*(SInt_32*)&(*out)[i] = dataSer.Read<SInt_32>();
|
||||
if (*(SInt_32*)&(*out)[i] > *(SInt_32*)out->GetPeak())
|
||||
out->SetPeak(sizeof(SInt_32), &(*out)[i]);
|
||||
}
|
||||
else if (byteDepth == 8)
|
||||
{
|
||||
*(SInt_64*)&(*out)[i] = dataSer.Read<SInt_64>();
|
||||
if (*(SInt_64*)&(*out)[i] > *(SInt_64*)out->GetPeak())
|
||||
out->SetPeak(sizeof(SInt_64), &(*out)[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user