public static void Copy(EndianReader input, EndianWriter output) { // http://stackoverflow.com/questions/230128/best-way-to-copy-between-two-stream-instances-c-sharp const int BufferSize = 0x1000; byte[] buffer = new byte[BufferSize]; int read; while ((read = input.ReadBlock(buffer, 0, BufferSize)) > 0) output.WriteBlock(buffer, 0, read); }
public static void Copy(EndianReader input, EndianWriter output, int size) { const int BufferSize = 0x1000; byte[] buffer = new byte[BufferSize]; while (size > 0) { int read = input.ReadBlock(buffer, 0, Math.Min(BufferSize, size)); output.WriteBlock(buffer, 0, read); size -= BufferSize; } }
/// <summary> /// Extracts an xWMA sound and converts it to WAV. /// </summary> /// <param name="reader">The stream to read from.</param> /// <param name="offset">The offset of the data to extract.</param> /// <param name="rifx">The RIFX data for the sound.</param> /// <param name="outPath">The path of the file to save to.</param> public static void ExtractXWMAToWAV(EndianReader reader, int offset, RIFX rifx, string outPath) { // Create a temporary file to write an XWMA to string tempFile = Path.GetTempFileName(); try { using (EndianWriter output = new EndianWriter(File.OpenWrite(tempFile), EndianFormat.BigEndian)) { // Generate a little-endian XWMA header // TODO: move this into a class? output.Write(0x52494646); // 'RIFF' // Recompute the file size because the one Wwise gives us is trash // fileSize = header size (always 0x2C) + dpds data size + data header size (always 0x8) + data size int fileSize = 0x2C + rifx.SeekOffsets.Length * 0x4 + 0x8 + rifx.DataSize; output.EndianType = EndianFormat.LittleEndian; output.Write(fileSize); output.EndianType = EndianFormat.BigEndian; output.Write(RIFFFormat.XWMA); // Generate the 'fmt ' chunk output.Write(0x666D7420); // 'fmt ' output.EndianType = EndianFormat.LittleEndian; output.Write(0x18); // Chunk size output.Write(rifx.Codec); output.Write(rifx.ChannelCount); output.Write(rifx.SampleRate); output.Write(rifx.BytesPerSecond); output.Write(rifx.BlockAlign); output.Write(rifx.BitsPerSample); // Write the extradata // Bytes 4 and 5 have to be flipped because they make up an int16 // TODO: add error checking to make sure the extradata is the correct size (0x6) output.Write((short)0x6); output.WriteBlock(rifx.ExtraData, 0, 4); output.Write(rifx.ExtraData[5]); output.Write(rifx.ExtraData[4]); // Generate the 'dpds' chunk // It's really just the 'seek' chunk from the original data but renamed output.EndianType = EndianFormat.BigEndian; output.Write(0x64706473); // 'dpds' output.EndianType = EndianFormat.LittleEndian; output.Write(rifx.SeekOffsets.Length * 4); // One uint32 per offset foreach (int seek in rifx.SeekOffsets) output.Write(seek); // 'data' chunk output.EndianType = EndianFormat.BigEndian; output.Write(0x64617461); // 'data' output.EndianType = EndianFormat.LittleEndian; output.Write(rifx.DataSize); // Copy the data chunk contents from the original RIFX reader.SeekTo(offset + rifx.DataOffset); StreamUtil.Copy(reader, output, rifx.DataSize); } // Convert it with xWMAEncode RunProgramSilently("Helpers/xWMAEncode.exe", "\"" + tempFile + "\" \"" + outPath + "\"", Directory.GetCurrentDirectory()); } finally { // Delete the temporary XWMA file if (File.Exists(tempFile)) File.Delete(tempFile); } }