implemented zlib-compressed XPCM audio.

This commit is contained in:
morkt 2016-02-07 04:30:31 +04:00
parent 81e4637750
commit 9eeec45c0f

View File

@ -2,7 +2,7 @@
//! \date Mon Jun 15 16:30:24 2015 //! \date Mon Jun 15 16:30:24 2015
//! \brief Circus PCM audio format. //! \brief Circus PCM audio format.
// //
// Copyright (C) 2015 by morkt // Copyright (C) 2015-2016 by morkt
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to // of this software and associated documentation files (the "Software"), to
@ -102,50 +102,60 @@ namespace GameRes.Formats.Circus
{ {
this.Source = new StreamRegion (file, file.Position, src_size); this.Source = new StreamRegion (file, file.Position, src_size);
} }
else if (1 == mode) else if (1 == mode || 3 == mode)
{ {
var decoder = new PcmDecoder (input, src_size, extra); var decoder = new PcmDecoder (input, src_size, extra, (XpcmCompression)mode);
this.Source = new MemoryStream (decoder.Unpack(), 0, src_size); this.Source = new MemoryStream (decoder.Unpack(), 0, src_size);
file.Dispose(); file.Dispose();
} }
else if (3 == mode)
{
uint packed_size = input.ReadUInt32();
this.Source = ZLibCompressor.DeCompress (file);
file.Dispose();
}
else else
throw new NotSupportedException ("Not supported Circus PCM audio compression"); throw new NotSupportedException ("Not supported Circus PCM audio compression");
} }
} }
} }
public enum XpcmCompression
{
None = 0,
Lzss = 1,
Zlib = 3,
}
internal class PcmDecoder internal class PcmDecoder
{ {
byte[] m_pcm_data; byte[] m_pcm_data;
byte[] m_encoded; byte[] m_encoded;
int m_pcm_size; int m_pcm_size;
int m_packed_size;
int m_extra; int m_extra;
public byte[] Data { get { return m_pcm_data; } } public byte[] Data { get { return m_pcm_data; } }
public PcmDecoder (BinaryReader input, int pcm_size, int extra) public PcmDecoder (BinaryReader input, int pcm_size, int extra, XpcmCompression mode)
{ {
if (extra < 0 || extra > 3) if (extra < 0 || extra > 3)
throw new InvalidFormatException(); throw new InvalidFormatException();
m_packed_size = input.ReadInt32(); int packed_size = input.ReadInt32();
m_extra = extra; m_extra = extra;
m_pcm_size = pcm_size; m_pcm_size = pcm_size;
m_pcm_data = new byte[pcm_size + 8192]; m_pcm_data = new byte[pcm_size + 8192];
m_encoded = new byte[(pcm_size / 0xFE0 << 12) + 16386]; m_encoded = new byte[(pcm_size / 0xFE0 << 12) + 16386];
if (m_packed_size != input.Read (m_pcm_data, 0, m_packed_size)) if (XpcmCompression.Lzss == mode)
throw new InvalidFormatException ("Unexpected end of file"); {
if (packed_size != input.Read (m_pcm_data, 0, packed_size))
throw new InvalidFormatException ("Unexpected end of file");
UnpackV1 (m_pcm_data, packed_size, m_encoded);
}
else if (XpcmCompression.Zlib == mode)
{
using (var z = new ZLibStream (input.BaseStream, CompressionMode.Decompress, true))
z.Read (m_encoded, 0, m_encoded.Length);
}
else
throw new InvalidFormatException ("Unknown PCM compression mode");
} }
public byte[] Unpack () public byte[] Unpack ()
{ {
UnpackV1 (m_pcm_data, m_packed_size, m_encoded);
Buffer.BlockCopy (unk_43A254, m_extra*0x40, dword_43A214, 0, 0x40); Buffer.BlockCopy (unk_43A254, m_extra*0x40, dword_43A214, 0, 0x40);
DecodeV1 (m_pcm_data, m_encoded, m_pcm_size); DecodeV1 (m_pcm_data, m_encoded, m_pcm_size);
return m_pcm_data; return m_pcm_data;