Files
UmaViewer/Assets/Scripts/Audio/CriWareFormats/AwbReader.cs
T
1605296300@qq.com 7607c8b4d2 add acb&awb support
2022-09-07 01:22:44 +08:00

139 lines
4.1 KiB
C#

using CriWareFormats.Common;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace CriWareFormats
{
internal class Row
{
public string Name { get; set; }
public ushort Id { get; set; }
}
public struct Wave
{
public int WaveId { get; set; }
public long Offset { get; set; }
public long Length { get; set; }
}
public sealed class AwbReader : IDisposable
{
private readonly BinaryReader binaryReader;
private readonly byte offsetSize;
private readonly int totalSubsongs;
private readonly ushort alignment;
private readonly ushort subkey;
private readonly List<Row> cueNames;
private readonly List<Wave> waves;
public AwbReader(Stream awbStream, bool isEmbedded) : this(awbStream, 0)
{
IsEmbedded = isEmbedded;
}
public AwbReader(Stream awbStream) : this(awbStream, 0) { }
public AwbReader(Stream awbStream, long positionOffset)
{
binaryReader = new BinaryReader(awbStream);
binaryReader.BaseStream.Position = positionOffset;
if (!binaryReader.ReadChars(4).SequenceEqual("AFS2".ToCharArray()))
throw new InvalidDataException("Incorrect magic.");
binaryReader.BaseStream.Position += 0x1;
offsetSize = binaryReader.ReadByte();
binaryReader.BaseStream.Position += 0x2;
totalSubsongs = binaryReader.ReadInt32();
alignment = binaryReader.ReadUInt16();
subkey = binaryReader.ReadUInt16();
waves = new List<Wave>(totalSubsongs);
for (int subsong = 1; subsong <= totalSubsongs; subsong++)
{
long offset = 0x10;
long waveIdOffset = offset + (subsong - 1) * 0x2;
binaryReader.BaseStream.Position = waveIdOffset;
int waveId = binaryReader.ReadUInt16();
offset += totalSubsongs * 0x2;
long subfileOffset = 0;
long subfileNext = 0;
long fileSize = binaryReader.BaseStream.Length;
offset += (subsong - 1) * offsetSize;
binaryReader.BaseStream.Position = offset;
switch (offsetSize)
{
case 0x4:
subfileOffset = binaryReader.ReadUInt32();
subfileNext = binaryReader.ReadUInt32();
break;
case 0x2:
subfileOffset = binaryReader.ReadUInt16();
subfileNext = binaryReader.ReadUInt16();
break;
default:
Fail();
break;
}
subfileOffset += subfileOffset % alignment > 0 ?
alignment - subfileOffset % alignment : 0;
subfileNext += subfileNext % alignment > 0 && subfileNext < fileSize ?
alignment - subfileNext % alignment : 0;
long subfileSize = subfileNext - subfileOffset;
waves.Add(new Wave()
{
WaveId = waveId,
Offset = subfileOffset,
Length = subfileSize
});
//if (CueNames.Count > 0) Console.Write("{0,-36}", CueNames.Where(row => row.Index == waveId).First().Name);
//else Console.Write(waveId);
//Console.WriteLine(subfileOffset);
}
cueNames = new List<Row>();
}
public ushort Subkey => subkey;
public bool IsEmbedded { get; }
public List<Wave> Waves => waves;
public Stream GetWaveSubfileStream(Wave wave)
{
return new SpliceStream(binaryReader.BaseStream, wave.Offset, wave.Length);
}
private static void Fail()
{
throw new Exception("Failure reading AWB file.");
}
public void Dispose()
{
binaryReader.Dispose();
}
}
}