Commit dbb2d402 authored by PoroCYon's avatar PoroCYon

Fix #31

parent d579374c
Pipeline #35287786 passed with stages
in 1 minute and 49 seconds
......@@ -430,21 +430,37 @@ namespace Altar
[DebuggerStepThrough]
public static bool IsEmpty( SectionHeader header) => header. Size <= 4;
}
// TODO: make GMFile not depend on the general data anymore, so we can just
// use that code to export detached agrps, too
public unsafe class AGRPFile : IDisposable
{
public AGRPFileContent Content{get;private set;}
public AGRPFileContent Content
{
get;
private set;
}
public uint NameOffset{get;internal set;}
public byte[][] Waves{get;internal set;}
public uint NameOffset
{
get;
internal set;
}
public byte[][] Waves
{
get;
internal set;
}
internal AGRPFile() {
Waves=new byte[0][];
internal AGRPFile()
{
Waves = new byte[0][];
}
internal AGRPFile(AGRPFileContent f) {
internal AGRPFile(AGRPFileContent f)
{
Content = f;
Waves=GMFile.TryReadMany(f.Audo, i=>SectionReader.GetAgrpAudo(f, i));
Waves = GMFile.TryReadMany(f.Audo, i => SectionReader.GetAgrpAudo(f, i));
}
public void Dispose()
......@@ -456,28 +472,31 @@ namespace Altar
}
}
public static AGRPFile GetFile(byte[] data) {
var ret =new AGRPFileContent();
var hdr_bp=new UniquePtr(data);
byte* hdr_b=hdr_bp.BPtr;
public static AGRPFile GetFile(byte[] data)
{
var ret = new AGRPFileContent();
var hdr_bp = new UniquePtr(data);
byte* hdr_b = hdr_bp.BPtr;
var basePtr= (SectionHeader*)hdr_b;
var basePtr = (SectionHeader*)hdr_b;
ret.Form=basePtr;
ret.Form = basePtr;
if (ret.Form->Identity!=SectionHeaders.Form)
throw new InvalidDataException(ERR_NO_FORM);
SectionHeader*
hdr=basePtr+1,
hdrEnd=(SectionHeader*)((IntPtr)basePtr+(int)ret.Form->Size);
hdr = basePtr + 1,
hdrEnd = (SectionHeader*)((IntPtr)basePtr + (int)ret.Form->Size);
int headersMet=0;
int headersMet = 0;
while(hdr<hdrEnd) {
switch(hdr->Identity) {
while (hdr < hdrEnd)
{
switch (hdr->Identity)
{
case SectionHeaders.Audio:
ret.Audo=(SectionCountOffsets*)hdr;
ret.Audo = (SectionCountOffsets*)hdr;
break;
default:
Console.WriteLine("Unexpected chunk in audiogroup.dat: "
......@@ -486,10 +505,10 @@ namespace Altar
}
headersMet++;
hdr=unchecked((SectionHeader*)((IntPtr)hdr+(int)hdr->Size)+1);
hdr = unchecked((SectionHeader*)((IntPtr)hdr + (int)hdr->Size) + 1);
}
ret.RawData=hdr_bp;
ret.RawData = hdr_bp;
return new AGRPFile(ret);
}
public static AGRPFile GetFile(string path) => GetFile(File.ReadAllBytes(path));
......
......@@ -5,10 +5,18 @@ namespace Altar
{
public class ExportAgrpOptions
{
[Option('f', "file", Required=true,DefaultValue="audiogroup1.dat",HelpText="Input file (default: 'audiogroup1.dat')")]
public string File{get;set;}
[Option('o',"out",Required=true,DefaultValue=".",HelpText="Output directory (default: current)")]
public string OutputDirectory{get;set;}
[Option('f', "file", Required = true, DefaultValue = "audiogroup1.dat", HelpText="Input file (default: 'audiogroup1.dat')")]
public string File
{
get;
set;
}
[Option('o', "out", Required = true, DefaultValue = ".", HelpText = "Output directory (default: current)")]
public string OutputDirectory
{
get;
set;
}
}
public class ExportOptions
{
......@@ -194,6 +202,13 @@ namespace Altar
set;
}
[Option("detachedagrp", HelpText = "Export data from detached audio group files, too. These files must reside in the same directory as the input file, and must be called 'audiogroup${n}.dat'.")]
public bool DetachedAgrp
{
get;
set;
}
[HelpOption]
public string GetUsage() => HelpText.AutoBuild(this, current => HelpText.DefaultParsingErrorsHandler(this, current));
}
......
......@@ -171,6 +171,7 @@ namespace Altar
File.WriteAllText(od + "functions.json", JsonMapper.ToJson(Serialize.SerializeFuncs(f)));
}
#endregion
int cl = 0, ct = 0;
#region AGRP
if (eo.AudioGroups && f.AudioGroups != null)
{
......@@ -178,9 +179,50 @@ namespace Altar
File.WriteAllText(od+"audiogroups.json", JsonMapper.ToJson(Serialize.SerializeAudioGroups(f)));
}
if (eo.DetachedAgrp && f.AudioGroups != null)
{
WriteLine("Dumping audio from detached audio groups...");
for (int i = 1; i < f.AudioGroups.Length; ++i)
{
WrAndGetC(DASH_ + f.AudioGroups[i] + O_PAREN + i +
SLASH + f.AudioGroups.Length + C_PAREN + SPACE_S,
out cl, out ct);
var agrpfn = Path.GetDirectoryName(file) + Path.DirectorySeparatorChar
+ AGRPF + i + D_DAT;
if (!File.Exists(agrpfn))
{
Console.Error.WriteLine("Eep: file '" + agrpfn + "' doesn't exist, skipping...");
continue;
}
var infoTable = new Dictionary<int, SoundInfo>();
foreach (var s in f.Sound)
if ((s.IsEmbedded || s.IsCompressed) && s.AudioID != -1
&& s.GroupID == i)
infoTable[s.AudioID] = s;
var odgrp = od + DIR_AGRP + f.AudioGroups[i];
if (!Directory.Exists(odgrp))
Directory.CreateDirectory(odgrp);
using (var af = AGRPFile.GetFile(agrpfn))
{
for (int j = 0; j < af.Waves.Length; ++j)
{
SetCAndWr(cl, ct, O_PAREN + (j + 1) + SLASH +
(af.Waves.Length - 1) + C_PAREN);
File.WriteAllBytes(odgrp + Path.DirectorySeparatorChar
+ infoTable[j].Name + SR.EXT_WAV, af.Waves[j]);
}
}
Console.WriteLine();
}
}
#endregion
int cl = 0, ct = 0;
#region TXTR
if (eo.Texture && f.Textures != null)
{
......@@ -193,7 +235,7 @@ namespace Altar
{
if (f.Textures[i].PngData == null)
continue;
SetCAndWr(cl, ct, O_PAREN + (i + 1) + SLASH + f.Textures.Length + C_PAREN);
File.WriteAllBytes(od + DIR_TEX + i + EXT_PNG, f.Textures[i].PngData);
......@@ -209,7 +251,8 @@ namespace Altar
var infoTable = new Dictionary<int, SoundInfo>();
foreach (var s in f.Sound)
if ((s.IsEmbedded || s.IsCompressed) && s.AudioID != -1)
if ((s.IsEmbedded || s.IsCompressed) && s.AudioID != -1
&& s.GroupID == 0) // not from audiogroup$n.dat
infoTable[s.AudioID] = s;
if (!Directory.Exists(od + DIR_WAV))
......@@ -453,7 +496,7 @@ namespace Altar
var len = unk->Header.Size;
byte[] buf = new byte[len];
uint* src = &unk->Unknown;
if (len != 0)
ILHacks.Cpblk<byte>((void*)src, buf, 0, (int)len);
......@@ -475,7 +518,7 @@ namespace Altar
chunks.Add((IntPtr)c.Fonts );
chunks.Add((IntPtr)c.Objects );
chunks.Add((IntPtr)c.Rooms );
chunks.Add((IntPtr)c.TexturePages);
chunks.Add((IntPtr)c.Code );
chunks.Add((IntPtr)c.Variables );
......@@ -756,18 +799,24 @@ namespace Altar
return writer.Buffer.ReadBytes(writer.Buffer.Size);
}
static void ExportAgrp(ExportAgrpOptions opt) {
var file=Path.GetFullPath(opt.File);
var outd=Path.GetFullPath(opt.OutputDirectory);
static void ExportAgrp(ExportAgrpOptions opt)
{
var file = Path.GetFullPath(opt.File);
var outd = Path.GetFullPath(opt.OutputDirectory);
if (!Directory.Exists(outd))Directory.CreateDirectory(outd);
if (!File.Exists(file))throw new ParserException("File \"" + file + "\" doesn't exist.");
if (!Directory.Exists(outd))
Directory.CreateDirectory(outd);
if (!File.Exists(file))
throw new ParserException("File \"" + file + "\" doesn't exist.");
nopp=quiet=false;
using (var f=AGRPFile.GetFile(file)){
nopp = quiet = false; // TODO: add these flags
// or better yet, make agrps work with `export`
using (var f = AGRPFile.GetFile(file))
{
int cl = 0, ct = 0;
WrAndGetC("Exporting AGRP audio... ", out cl, out ct);
for (int i =0; i<f.Waves.Length;++i){
for (int i = 0; i < f.Waves.Length; ++i)
{
SetCAndWr(cl, ct, O_PAREN + (i + 1) + SLASH + f.Waves.Length + C_PAREN);
File.WriteAllBytes("audo" + i.ToString("D3") + ".wav", f.Waves[i]);
}
......
......@@ -17,6 +17,7 @@
O_PAREN = "(" ,
TILDE = "~" ,
DASH = "-" ,
DASH_ = "- ",
PLUS = "+" ,
AMP = "&" ,
SLASH = "/" ,
......@@ -81,6 +82,7 @@
DIR_SPR = "sprite/" ,
DIR_FNT = "font/" ,
DIR_PATH = "path/" ,
DIR_AGRP = "agrp/" ,
VAR = "var" ,
INST = "inst",
......@@ -101,6 +103,8 @@
EXIT = "exit" ,
MAGIC = "!magic" ,
SET_S = "set " ,
AGRPF = "audiogroup",
D_DAT = ".dat",
REMAIN = "rem" ,
ASSERT = "assert_neq:",
......
......@@ -76,10 +76,11 @@ namespace Altar
public float VolumeMod ;
public float PitchMod ;
public string Group ;
public int GroupID ;
/// <summary>
/// -1 if unused? Only makes sense when embedded or compressed?
/// </summary>
public int AudioID;
public int AudioID ;
}
[StructLayout(LayoutKind.Sequential)]
public struct SpriteInfo
......
......@@ -252,6 +252,7 @@ namespace Altar.Unpack
? String.Empty
: GetAudioGroupInfo(content, (uint)se->GroupID);
ret.GroupID = se->GroupID;
ret.AudioID = se->AudioID;
ret.IsEmbedded = (se->Flags & SoundEntryFlags.Embedded ) != 0;
ret.IsCompressed = (se->Flags & SoundEntryFlags.Compressed) != 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment