mirror of
https://mirror.ghproxy.com/https://github.com/dexyfex/CodeWalker
synced 2024-11-26 17:02:53 +08:00
AwcFile parsing improvements
This commit is contained in:
parent
1194334acb
commit
4020327e64
@ -23,8 +23,9 @@ namespace CodeWalker.GameFiles
|
||||
public int StreamCount { get; set; }
|
||||
public int InfoOffset { get; set; }
|
||||
|
||||
public ushort[] UnkUshorts { get; set; } //offsets of some sort?
|
||||
|
||||
public bool MultiChannel { get; set; }
|
||||
public byte[] MultiChannelData { get; set; }
|
||||
|
||||
public AwcStreamInfo[] StreamInfos { get; set; }
|
||||
public uint[] AudioIds { get; set; }
|
||||
@ -79,9 +80,12 @@ namespace CodeWalker.GameFiles
|
||||
{
|
||||
Decrypt_RSXXTEA(data, GTA5Keys.PC_AWC_KEY);
|
||||
Magic = BitConverter.ToUInt32(data, 0);
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
ErrorMessage = "Corrupted data!";
|
||||
}
|
||||
}
|
||||
|
||||
switch (Magic)
|
||||
{
|
||||
@ -127,14 +131,24 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
|
||||
var flag0 = ((Flags & 1) == 1);
|
||||
var infoStart = 16 + (flag0 ? (StreamCount * 2) : 0);
|
||||
if (flag0)
|
||||
{
|
||||
UnkUshorts = new ushort[StreamCount]; //offsets of some sort?
|
||||
for (int i = 0; i < StreamCount; i++)
|
||||
{
|
||||
UnkUshorts[i] = r.ReadUInt16();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var infoStart = 16 + (flag0 ? (StreamCount * 2) : 0);
|
||||
if (ms.Position != infoStart)
|
||||
{ }
|
||||
ms.Position = infoStart;
|
||||
|
||||
|
||||
List<AwcStreamInfo> infos = new List<AwcStreamInfo>();
|
||||
Dictionary<uint, AwcStreamInfo> infoDict = new Dictionary<uint, AwcStreamInfo>();
|
||||
List<uint> audioIds = new List<uint>();
|
||||
List<AwcAudio> audios = new List<AwcAudio>();
|
||||
|
||||
for (int i = 0; i < StreamCount; i++)
|
||||
{
|
||||
@ -145,76 +159,103 @@ namespace CodeWalker.GameFiles
|
||||
for (int i = 0; i < StreamCount; i++)
|
||||
{
|
||||
var info = infos[i];
|
||||
for (int j = 0; j < info.TagCount; j++)
|
||||
for (int j = 0; j < info.ChunkCount; j++)
|
||||
{
|
||||
var chunk = new AwcChunkInfo(r);
|
||||
info.Chunks[chunk.Tag] = chunk;
|
||||
info.ChunkList.Add(chunk);
|
||||
info.ChunkDict[chunk.Tag] = chunk;
|
||||
}
|
||||
}
|
||||
|
||||
StreamInfos = infos.ToArray();
|
||||
|
||||
|
||||
|
||||
byte hformat = 0xFA;// 250 0x6061D4FA & 0xFF; //JenkHash.GenHash("format");
|
||||
byte hdata = 0x55;// 85 0x5EB5E655 & 0xFF; //JenkHash.GenHash("data");
|
||||
byte hycd = 0x5C;// 92 YCD resource chunk... lip sync anims?
|
||||
byte hunk = 0x36;// 54 unk chunk? small number of bytes (2+)
|
||||
|
||||
|
||||
|
||||
if (MultiChannel)
|
||||
{
|
||||
AwcStreamInfo stream0 = null;
|
||||
if (!infoDict.TryGetValue(0, out stream0))
|
||||
{
|
||||
ErrorMessage = "Couldn't find MultiChannel stream0";
|
||||
return;
|
||||
//ReadAudiosOrig(infoDict, r);
|
||||
ReadAudios(r);
|
||||
}
|
||||
}
|
||||
|
||||
AwcChunkInfo chunk72 = null;
|
||||
if (!stream0.Chunks.TryGetValue(72, out chunk72))
|
||||
private void ReadAudios(DataReader r)
|
||||
{
|
||||
ErrorMessage = "Couldn't find MultiChannel chunk72";
|
||||
return;
|
||||
|
||||
List<uint> audioIds = new List<uint>();
|
||||
List<AwcAudio> audios = new List<AwcAudio>();
|
||||
|
||||
for (int i = 0; i < StreamCount; i++)
|
||||
{
|
||||
var info = StreamInfos[i];
|
||||
var audio = new AwcAudio();
|
||||
audio.StreamInfo = info;
|
||||
|
||||
for (int j = 0; j < info.ChunkList.Count; j++)
|
||||
{
|
||||
var chunk = info.ChunkList[j];
|
||||
r.Position = chunk.Offset;
|
||||
switch (chunk.Tag)
|
||||
{
|
||||
case 85: //data
|
||||
audio.DataInfo = chunk;
|
||||
audio.Data = r.ReadBytes(chunk.Size);
|
||||
break;
|
||||
case 250://format
|
||||
audio.Format = new AwcFormatChunk(r, chunk);
|
||||
break;
|
||||
case 92: //animation - YCD resource chunk
|
||||
audio.ClipDict = new AwcAudioAnimClipDict(r, chunk);
|
||||
break;
|
||||
case 43: //unk2B
|
||||
audio.UnkData2B = new AwcAudioUnk(r, chunk);
|
||||
break;
|
||||
case 54: //unk36 - small number of bytes (2+)
|
||||
audio.UnkData36 = new AwcAudioUnk(r, chunk);
|
||||
break;
|
||||
case 90: //unk5A
|
||||
audio.UnkData5A = new AwcAudioUnk(r, chunk);
|
||||
break;
|
||||
case 104://unk68
|
||||
audio.UnkData68 = new AwcAudioUnk(r, chunk);
|
||||
break;
|
||||
case 217://unkD9 - length 200+
|
||||
audio.UnkDataD9 = new AwcAudioUnk(r, chunk);
|
||||
break;
|
||||
case 72: //multi channel info
|
||||
audio.MultiChannelInfo = new AwcChannelChunkInfo(r);
|
||||
break;
|
||||
case 163://multi unkA3
|
||||
audio.MultiChannelOffsets = new AwcChannelOffsetsInfo(r, chunk);
|
||||
break;
|
||||
case 189://multi unkBD
|
||||
audio.UnkDataBD = new AwcAudioUnk(r, chunk);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if ((r.Position - chunk.Offset) != chunk.Size)
|
||||
{ }//make sure everything was read!
|
||||
}
|
||||
|
||||
ms.Position = chunk72.Offset;
|
||||
|
||||
AwcChannelChunkInfo chanInfo = new AwcChannelChunkInfo(r);
|
||||
if (chanInfo.ChannelCount != StreamCount - 1)
|
||||
{
|
||||
ErrorMessage = "Channel Count did not match Stream Count";
|
||||
return;
|
||||
audios.Add(audio);
|
||||
audioIds.Add(info.Id);
|
||||
}
|
||||
|
||||
List<AwcChannelChunkItemInfo> chunkItems = new List<AwcChannelChunkItemInfo>();
|
||||
for (int i = 0; i < chanInfo.ChannelCount; i++)
|
||||
{
|
||||
var itemInfo = new AwcChannelChunkItemInfo(r);
|
||||
chunkItems.Add(itemInfo);
|
||||
audioIds.Add(infos[i + 1].Id);
|
||||
Audios = audios.ToArray();
|
||||
AudioIds = audioIds.ToArray();
|
||||
|
||||
}
|
||||
|
||||
//AudioStreams.Add(new MultiChannelAudio(new ChunkStream(this.Stream, streamsChunks[0][Tag("data")]), channelsInfoHeader, streamsInfo, header.BigEndian));
|
||||
|
||||
AwcChunkInfo cdata = null;
|
||||
if (!stream0.Chunks.TryGetValue(hdata, out cdata))
|
||||
private void ReadAudiosOrig(Dictionary<uint, AwcStreamInfo> infoDict, DataReader r)
|
||||
{
|
||||
ErrorMessage = "Couldn't find Stream 0 data chunk";
|
||||
return;
|
||||
}
|
||||
|
||||
ms.Position = cdata.Offset;
|
||||
var lastPos = cdata.Offset + cdata.Size;
|
||||
//int chunkSize = 0x800;
|
||||
uint bigChunkSize = chanInfo.ChunkSize;
|
||||
var chanCount = chanInfo.ChannelCount;
|
||||
//just leaving this here temporarily for reference about how libertyV parsed multichannel data
|
||||
|
||||
MultiChannelData = r.ReadBytes(cdata.Size);
|
||||
ms.Position = cdata.Offset;
|
||||
|
||||
//var d = data;//temporary
|
||||
//r.Position = cdata.Offset;
|
||||
//var lastPos = cdata.Offset + cdata.Size;
|
||||
////int chunkSize = 0x800;
|
||||
//uint bigChunkSize = chanInfo.ChunkSize;
|
||||
//var chanCount = chanInfo.ChannelCount;
|
||||
|
||||
//MultiChannelData = r.ReadBytes(cdata.Size);
|
||||
//r.Position = cdata.Offset;
|
||||
|
||||
////this doesn't seem to work :(
|
||||
//while (ms.Position < lastPos)
|
||||
@ -257,67 +298,6 @@ namespace CodeWalker.GameFiles
|
||||
//}
|
||||
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
for (int i = 0; i < StreamCount; i++)
|
||||
{
|
||||
var info = infos[i];
|
||||
|
||||
AwcChunkInfo cformat = null;
|
||||
if (!info.Chunks.TryGetValue(hformat, out cformat))
|
||||
{
|
||||
ErrorMessage = "Couldn't find Stream " + i.ToString() + " format chunk";
|
||||
continue;
|
||||
}
|
||||
|
||||
AwcChunkInfo cdata = null;
|
||||
if (!info.Chunks.TryGetValue(hdata, out cdata))
|
||||
{
|
||||
ErrorMessage = "Couldn't find Stream " + i.ToString() + " data chunk";
|
||||
continue;
|
||||
}
|
||||
|
||||
AwcChunkInfo cycd = null;
|
||||
AwcAudioAnimClipDict oycd = null;
|
||||
if (info.Chunks.TryGetValue(hycd, out cycd))
|
||||
{
|
||||
ms.Position = cycd.Offset;
|
||||
oycd = new AwcAudioAnimClipDict(r, cycd);
|
||||
}
|
||||
|
||||
AwcChunkInfo cunk = null;
|
||||
AwcAudioUnk ounk = null;
|
||||
if (info.Chunks.TryGetValue(hunk, out cunk))
|
||||
{
|
||||
ms.Position = cunk.Offset;
|
||||
ounk = new AwcAudioUnk(r, cunk);
|
||||
}
|
||||
|
||||
|
||||
ms.Position = cformat.Offset;
|
||||
AwcFormatChunk formatChunk = new AwcFormatChunk(r);
|
||||
|
||||
ms.Position = cdata.Offset;
|
||||
AwcAudio audio = new AwcAudio(r, info, formatChunk, cdata);
|
||||
|
||||
audio.ClipDict = oycd;
|
||||
audio.UnkData = ounk;
|
||||
|
||||
audios.Add(audio);
|
||||
audioIds.Add(info.Id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Audios = audios.ToArray();
|
||||
AudioIds = audioIds.ToArray();
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -326,21 +306,22 @@ namespace CodeWalker.GameFiles
|
||||
[TC(typeof(EXP))] public class AwcStreamInfo
|
||||
{
|
||||
public uint RawVal { get; set; }
|
||||
public uint TagCount { get; set; }
|
||||
public uint ChunkCount { get; set; }
|
||||
public uint Id { get; set; }
|
||||
|
||||
public Dictionary<byte, AwcChunkInfo> Chunks { get; set; } = new Dictionary<byte, AwcChunkInfo>();
|
||||
public List<AwcChunkInfo> ChunkList { get; set; } = new List<AwcChunkInfo>();
|
||||
public Dictionary<byte, AwcChunkInfo> ChunkDict { get; set; } = new Dictionary<byte, AwcChunkInfo>();
|
||||
|
||||
public AwcStreamInfo(DataReader r)
|
||||
{
|
||||
RawVal = r.ReadUInt32();
|
||||
TagCount = (RawVal >> 29);
|
||||
ChunkCount = (RawVal >> 29);
|
||||
Id = (RawVal & 0x1FFFFFFF);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Id.ToString("X") + ": " + TagCount.ToString() + " tags";
|
||||
return Id.ToString("X") + ": " + ChunkCount.ToString() + " chunks";
|
||||
}
|
||||
}
|
||||
|
||||
@ -367,20 +348,32 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
[TC(typeof(EXP))] public class AwcChannelChunkInfo
|
||||
{
|
||||
public uint Unk0 { get; set; }
|
||||
public uint ChunkCount { get; set; }
|
||||
public uint ChunkSize { get; set; }
|
||||
public uint ChannelCount { get; set; }
|
||||
public AwcChannelChunkItemInfo[] Channels { get; set; }
|
||||
|
||||
public uint TotalSize { get { return ChunkCount * ChunkSize; } }
|
||||
|
||||
public AwcChannelChunkInfo(DataReader r)
|
||||
{
|
||||
Unk0 = r.ReadUInt32();
|
||||
ChunkCount = r.ReadUInt32();
|
||||
ChunkSize = r.ReadUInt32();
|
||||
ChannelCount = r.ReadUInt32();
|
||||
|
||||
List<AwcChannelChunkItemInfo> channels = new List<AwcChannelChunkItemInfo>();
|
||||
for (int i = 0; i < ChannelCount; i++)
|
||||
{
|
||||
var itemInfo = new AwcChannelChunkItemInfo(r);
|
||||
channels.Add(itemInfo);
|
||||
}
|
||||
Channels = channels.ToArray();
|
||||
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Unk0.ToString() + ": " + ChunkSize.ToString() + ", " + ChannelCount.ToString() + " channels";
|
||||
return ChunkCount.ToString() + ": " + ChunkSize.ToString() + ", " + ChannelCount.ToString() + " channels";
|
||||
}
|
||||
}
|
||||
|
||||
@ -421,14 +414,16 @@ namespace CodeWalker.GameFiles
|
||||
public ushort LoopEnd { get; set; }
|
||||
public ushort PlayEnd { get; set; }
|
||||
public byte PlayBegin { get; set; }
|
||||
public uint UnkExtra { get; set; }
|
||||
|
||||
public enum CodecFormat {
|
||||
public enum CodecFormat
|
||||
{
|
||||
PCM = 0,
|
||||
ADPCM = 4
|
||||
}
|
||||
public CodecFormat Codec { get; set; }
|
||||
|
||||
public AwcFormatChunk(DataReader r)
|
||||
public AwcFormatChunk(DataReader r, AwcChunkInfo info)
|
||||
{
|
||||
Samples = r.ReadUInt32();
|
||||
LoopPoint = r.ReadInt32();
|
||||
@ -440,9 +435,17 @@ namespace CodeWalker.GameFiles
|
||||
PlayBegin = r.ReadByte();
|
||||
Codec = (CodecFormat)r.ReadByte();
|
||||
|
||||
//Apparently sometimes this struct is longer? TODO: fix??
|
||||
//r.ReadUInt16();
|
||||
//r.ReadUInt16();
|
||||
switch (info.Size) //Apparently sometimes this struct is longer?
|
||||
{
|
||||
case 20:
|
||||
break;
|
||||
case 24:
|
||||
UnkExtra = r.ReadUInt32();
|
||||
break;
|
||||
default:
|
||||
break;//no hit
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -460,8 +463,14 @@ namespace CodeWalker.GameFiles
|
||||
public byte[] Data { get; set; }
|
||||
|
||||
public AwcAudioAnimClipDict ClipDict { get; set; }
|
||||
public AwcAudioUnk UnkData { get; set; }
|
||||
|
||||
public AwcAudioUnk UnkData2B { get; set; }
|
||||
public AwcAudioUnk UnkData36 { get; set; }
|
||||
public AwcAudioUnk UnkData5A { get; set; }
|
||||
public AwcAudioUnk UnkData68 { get; set; }
|
||||
public AwcAudioUnk UnkDataD9 { get; set; }
|
||||
public AwcChannelChunkInfo MultiChannelInfo { get; set; }
|
||||
public AwcChannelOffsetsInfo MultiChannelOffsets { get; set; }
|
||||
public AwcAudioUnk UnkDataBD { get; set; }
|
||||
|
||||
public short Channels = 1;
|
||||
public short BitsPerSample = 16;
|
||||
@ -530,6 +539,9 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
}
|
||||
|
||||
public AwcAudio()
|
||||
{
|
||||
}
|
||||
public AwcAudio(DataReader r, AwcStreamInfo s, AwcFormatChunk f, AwcChunkInfo d)
|
||||
{
|
||||
StreamInfo = s;
|
||||
@ -716,10 +728,12 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
[TC(typeof(EXP))] public class AwcAudioUnk
|
||||
{
|
||||
public AwcChunkInfo ChunkInfo { get; set; }
|
||||
public byte[] Data { get; set; }
|
||||
|
||||
public AwcAudioUnk(DataReader r, AwcChunkInfo info)
|
||||
{
|
||||
ChunkInfo = info;
|
||||
Data = r.ReadBytes(info.Size);
|
||||
}
|
||||
|
||||
@ -736,6 +750,32 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
}
|
||||
|
||||
[TC(typeof(EXP))] public class AwcChannelOffsetsInfo
|
||||
{
|
||||
public AwcChunkInfo ChunkInfo { get; set; }
|
||||
public uint[] Offsets { get; set; }
|
||||
|
||||
public AwcChannelOffsetsInfo(DataReader r, AwcChunkInfo info)
|
||||
{
|
||||
ChunkInfo = info;
|
||||
var count = info.Size / 4;
|
||||
var rem = info.Size % 4;
|
||||
if (rem != 0)
|
||||
{ }
|
||||
Offsets = new uint[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
Offsets[i] = r.ReadUInt32();
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return (Offsets?.Length ?? 0).ToString() + " items";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
[TC(typeof(EXP))] public class AwcChannelChunkHeader
|
||||
{
|
||||
|
@ -180,6 +180,7 @@ namespace CodeWalker.GameFiles
|
||||
//RE test area!
|
||||
//TestAudioRels();
|
||||
//TestAudioYmts();
|
||||
//TestAudioAwcs();
|
||||
//TestMetas();
|
||||
//TestPsos();
|
||||
//TestRbfs();
|
||||
@ -2831,6 +2832,35 @@ namespace CodeWalker.GameFiles
|
||||
{ }
|
||||
|
||||
|
||||
}
|
||||
public void TestAudioAwcs()
|
||||
{
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
Dictionary<uint, int> allids = new Dictionary<uint, int>();
|
||||
|
||||
foreach (RpfFile file in AllRpfs)
|
||||
{
|
||||
foreach (RpfEntry entry in file.AllEntries)
|
||||
{
|
||||
try
|
||||
{
|
||||
var n = entry.NameLower;
|
||||
if (n.EndsWith(".awc"))
|
||||
{
|
||||
UpdateStatus(string.Format(entry.Path));
|
||||
var awcfile = RpfMan.GetFile<AwcFile>(entry);
|
||||
if (awcfile != null)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UpdateStatus("Error! " + ex.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public void TestMetas()
|
||||
{
|
||||
|
@ -71,7 +71,7 @@ namespace CodeWalker.Forms
|
||||
var item = PlayListView.Items.Add(audio.Name);
|
||||
item.SubItems.Add(audio.Type);
|
||||
item.SubItems.Add(audio.LengthStr);
|
||||
item.SubItems.Add(TextUtil.GetBytesReadable(audio.Data.Length));
|
||||
item.SubItems.Add(TextUtil.GetBytesReadable(audio.Data?.Length ?? 0));
|
||||
item.Tag = audio;
|
||||
totalLength += audio.Length;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user