//Coverted from C (ima_rejigger2) //https://bitbucket.org/anders/wwiseconv/wiki/WWise_format public static byte[] IMA_ADPCM(byte[] a, out string xex, bool pcm) { xex = "stream"; Binboy bb = new Binboy(a); if(!bb.Open()) return a; if (bb.GetEncoding().GetString(bb.ReadBytes(4), 0, 4) != "RIFF") return a; int riffSize = bb.ReadInt32(); if (bb.GetEncoding().GetString(bb.ReadBytes(4), 0, 4) != "WAVE") return a; int waveChunkStart = 12; int waveChunkEnd = 8 + riffSize; int chunkOffset = waveChunkStart; int channels = -1; int blockSize = -1; int samples = -1; int dataSize = -1; int dataPos = -1; bb.SetPosition(0); MemoryStream ms = new MemoryStream(bb.ReadAllBytes()); BinaryWriter bw = new BinaryWriter(ms); while (chunkOffset < waveChunkEnd) { bb.SetPosition((int)chunkOffset); string chunkType = Encoding.ASCII.GetString(bb.ReadBytes(4), 0, 4); int chunkSize = bb.ReadInt32(); if (chunkOffset + 8 + chunkSize < chunkOffset + 8 || chunkOffset + 8 + chunkSize > waveChunkEnd) return a; switch (chunkType) { case "fmt ": Bandaid.Debug("fmt"); if ((int)0xE > chunkSize) return a; Bandaid.Debug("ChunkSize is correct"); ushort codec = bb.ReadUInt16(chunkOffset + 8); if (codec == 0xFFFF) { xex = "stream"; return a; } if (0x2 != codec) return a; Bandaid.Debug("Codec is correct"); channels = bb.ReadUInt16(); Bandaid.Debug("chunkOffset", chunkOffset); samples = bb.ReadInt32(); bb.ReadUInt32(); ushort sblockSize = bb.ReadUInt16(); Bandaid.Debug("Channels", channels, "BlockSize", sblockSize); blockSize = sblockSize; bw.BaseStream.Position = chunkOffset + 8; bw.Write((ushort)0x11); break; case "data": Bandaid.Debug("Data"); if (channels < 1 || blockSize < 1) return a; dataSize = chunkSize; dataPos = chunkOffset + 8; reinterleaveMS_IMA(bw, bb, dataPos, chunkSize, channels, blockSize); break; } chunkOffset += 8 + chunkSize; } if (!pcm) return ms.ToArray(); ms.Position = 0; IMA_ADPCM decode = new IMA_ADPCM(ms); xex = "wav"; return decode.Decode(); }
//https://bitbucket.org/anders/wwiseconv/wiki/WWise_format private static void reinterleaveMS_IMA(BinaryWriter bw, Binboy bb, int offset, int chunkSize, int channels, int blockSize) { int bytesPerChannel = blockSize / channels; if (chunkSize % blockSize > 0) return; if (blockSize % channels > 0) return; if (bytesPerChannel % 4 > 0) return; bb.SetPosition(offset); byte[] buf = new byte[blockSize+1]; bw.BaseStream.Position = offset; while (chunkSize > 0) { bb.SetPosition(offset); bb.Stream.Read(buf, 0, blockSize); bb.SetPosition(offset); for (int i = 0; i < channels; ++i) { bw.Write(buf, i * bytesPerChannel, 4); } for (int j = 0; j < bytesPerChannel - 4; j += 4) { for (int i = 0; i < channels; ++i) { bw.Write(buf, (i * bytesPerChannel + 4) + j, 4); } } chunkSize -= blockSize; offset += blockSize; } }