/// <summary>
 /// Extracts an xWMA sound and converts it to another format.
 /// </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. The file extension will determine the output format.</param>
 public static void ExtractAndConvertXWMA(EndianReader reader, int offset, RIFX rifx, string outPath)
 {
     // Extract a WAV to a temporary file and then convert it
     string tempPath = Path.GetTempFileName();
     try
     {
         ExtractXWMAToWAV(reader, offset, rifx, tempPath);
         ConvertFile(tempPath, outPath);
     }
     finally
     {
         // Delete the temporary file
         if (File.Exists(tempPath))
             File.Delete(tempPath);
     }
 }
 /// <summary>
 /// Identifies the format of a Wwise sound based upon RIFX header information.
 /// </summary>
 /// <param name="rifx">The RIFX header information for the sound.</param>
 /// <returns>A SoundFormat value indicating the type of the sound, or SoundFormat.Unknown if identification failed.</returns>
 public static SoundFormat IdentifyFormat(RIFX rifx)
 {
     if (rifx.FormatMagic == RIFFFormat.XWMA)
     {
         if (rifx.Codec == RIFXCodec.WMA || rifx.Codec == RIFXCodec.WMAPro)
             return SoundFormat.XWMA;
     }
     else if (rifx.FormatMagic == RIFFFormat.WAVE)
     {
         switch (rifx.Codec)
         {
             case RIFXCodec.WwiseOGG:
                 return SoundFormat.WwiseOGG;
             case RIFXCodec.XMA:
                 return SoundFormat.XMA;
         }
     }
     return SoundFormat.Unknown;
 }
        /// <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);
            }
        }
        /// <summary>
        /// Extracts an XMA sound and converts it to a 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 ExtractXMAToWAV(EndianReader reader, int offset, RIFX rifx, string outPath)
        {
            // Create a temporary file to write an XMA to
            string tempFile = Path.GetTempFileName();

            try
            {
                using (EndianWriter output = new EndianWriter(File.OpenWrite(tempFile), EndianFormat.BigEndian))
                {
                    // Generate an XMA header
                    // ADAPTED FROM wwisexmabank - I DO NOT TAKE ANY CREDIT WHATSOEVER FOR THE FOLLOWING CODE.
                    // See http://hcs64.com/vgm_ripping.html for more information
                    output.Write(0x52494646); // 'RIFF'
                    output.EndianType = EndianFormat.LittleEndian;
                    output.Write(rifx.DataSize + 0x34);
                    output.EndianType = EndianFormat.BigEndian;
                    output.Write(RIFFFormat.WAVE);

                    // Generate the 'fmt ' chunk
                    output.Write(0x666D7420); // 'fmt '
                    output.EndianType = EndianFormat.LittleEndian;
                    output.Write(0x20);
                    output.Write((short)0x165); // WAVE_FORMAT_XMA
                    output.Write((short)16);    // 16 bits per sample
                    output.Write((short)0);     // encode options **
                    output.Write((short)0);     // largest skip
                    output.Write((short)1);     // # streams
                    output.Write((byte)0);      // loops
                    output.Write((byte)3);      // encoder version
                    output.Write(0);            // bytes per second **
                    output.Write(rifx.SampleRate); // sample rate
                    output.Write(0);            // loop start
                    output.Write(0);            // loop end
                    output.Write((byte)0);      // subframe loop data
                    output.Write((byte)rifx.ChannelCount); // channels
                    output.Write((short)0x0002);// channel mask

                    // '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);

                    // END ADAPTED CODE
                }

                // Convert it with towav
                RunProgramSilently("Helpers/towav.exe", "\"" + Path.GetFileName(tempFile) + "\"", Path.GetDirectoryName(tempFile));

                // Move the WAV to the destination path
                if (File.Exists(outPath))
                    File.Delete(outPath);
                File.Move(Path.ChangeExtension(tempFile, "wav"), outPath);
            }
            finally
            {
                // Delete the temporary XMA file
                if (File.Exists(tempFile))
                    File.Delete(tempFile);
            }
        }