Example #1
0
 /// <summary>
 /// Calculates WAV file duration (in minutes and seconds).
 /// </summary>
 /// <param name="WAVheader">WAV file header to read info from.</param>
 /// <param name="durationMinutes">Output parameter for duration in minutes.</param>
 /// <param name="durationSeconds">Output parameter for duration in seconds.</param>
 public void GetWAVFileDuration(WAVHeader WAVheader, out int durationMinutes, out double durationSeconds)
 {
     // We get duration from header data, data size / bytes per sample / number of channels / sample rate
     durationSeconds  = (double)WAVheader.Subchunk2Size / (WAVheader.BitsPerSample / 8) / WAVheader.NumChannels / WAVheader.SampleRate;
     durationMinutes  = (int)Math.Floor(durationSeconds / 60);
     durationSeconds -= durationMinutes * 60;
 }
Example #2
0
 /// <summary>
 /// Create a new WAV file from data. Used mainly in the conversion methods.
 /// </summary>
 /// <param name="header">The header</param>
 /// <param name="fmtChunk">The format info</param>
 /// <param name="data">The data</param>
 public WAVFile(WAVHeader header, WAVFormatChunk fmtChunk, WAVDataChunk data)
 {
     Header           = header;
     Format           = fmtChunk;
     Data             = data;
     Header.DataChunk = Data;
     Data.FormatChunk = Format;
 }
Example #3
0
        /// <summary>
        /// Create a new WEM file from the specified path.
        /// </summary>
        /// <param name="path">The WEM file.</param>
        public WAVFile(string path)
        {
            using (FileStream inputStream = new FileStream(path, FileMode.Open)) {
                BinaryReader reader = new BinaryReader(inputStream);

                Header           = WAVHeader.CreateFromStream(reader);
                Format           = WAVFormatChunk.CreateFromStream(reader);
                Data             = WAVDataChunk.CreateFromStream(reader, Format);
                Header.DataChunk = Data;

                reader.Dispose();
            }
        }
Example #4
0
        /// <summary>
        /// "Fixes" WAV header for decrypted files. Decrypted file contains one sample less.
        /// We change WAV header to supply correct data.
        /// </summary>
        public void CreateDecryptedWAVFile()
        {
            WAVHeader header = this.Header;

            // 2 last encrypted samples won't be decrypted because reverse calculation requires 3 consequent values
            // But we inserted 1 extra sample in the beginning (x1prev) while encrypting, so we'll lose only 1 sample instead of 2
            header.Subchunk2Size -= sizeof(short);
            // ChunkSize has to be changed as well as its value should always be 36 (bytes) greater than Subchunk2Size
            header.ChunkSize = Header.Subchunk2Size + 36;

            this.Header = header;

            // Create a WAV file and write modified header to it
            CreateWAVFile();
        }
Example #5
0
        /// <summary>
        /// "Fixes" WAV header for decrypted files. Decrypted file contains one sample less.
        /// We change WAV header to supply correct data.
        /// </summary>
        public void CreateDecryptedWAVFile()
        {
            WAVHeader header = this.Header;

            // 2 last encrypted samples won't be decrypted because reverse calculation requires 3 consequent values
            // But we inserted 1 extra sample in the beginning (x1prev) while encrypting, so we'll lose only 1 sample instead of 2
            header.Subchunk2Size -= sizeof(short);
            // ChunkSize has to be changed as well as its value should always be 36 (bytes) greater than Subchunk2Size
            header.ChunkSize = Header.Subchunk2Size + 36;

            this.Header = header;

            // Create a WAV file and write modified header to it
            CreateWAVFile();
        }
Example #6
0
        /// <summary>
        /// "Fixes" WAV header for encrypted files. Original file contains short values, encrypted - double.
        /// We change WAV header to supply correct data as if it contains more samples.
        /// Because of this encrypted file duration seems to be 4 times longer and file is ~4 bigger.
        /// </summary>
        public void CreateEncryptedWAVFile()
        {
            WAVHeader header = this.Header;

            // Fix difference between short and double
            header.Subchunk2Size *= sizeof(double) / sizeof(short);
            // And we also have one extra sample at the beginning (x1prev)
            header.Subchunk2Size += sizeof(double);
            // ChunkSize has to be changed as well as its value should always be 36 (bytes) greater than Subchunk2Size
            header.ChunkSize = Header.Subchunk2Size + 36;

            this.Header = header;

            // Create a WAV file and write modified header to it
            CreateWAVFile();
        }
Example #7
0
        /// <summary>
        /// "Fixes" WAV header for encrypted files. Original file contains short values, encrypted - double.
        /// We change WAV header to supply correct data as if it contains more samples.
        /// Because of this encrypted file duration seems to be 4 times longer and file is ~4 bigger.
        /// </summary>
        public void CreateEncryptedWAVFile()
        {
            WAVHeader header = this.Header;

            // Fix difference between short and double
            header.Subchunk2Size *= sizeof(double) / sizeof(short);
            // And we also have one extra sample at the beginning (x1prev)
            header.Subchunk2Size += sizeof(double);
            // ChunkSize has to be changed as well as its value should always be 36 (bytes) greater than Subchunk2Size
            header.ChunkSize = Header.Subchunk2Size + 36;

            this.Header = header;

            // Create a WAV file and write modified header to it
            CreateWAVFile();
        }
Example #8
0
        /// <summary>
        /// Opens existing WAV file and reads header info.
        /// </summary>
        public void ReadWAVHeader()
        {
            using (FileStream fs = new FileStream(FileName, FileMode.Open, FileAccess.Read))
                using (BinaryReader br = new BinaryReader(fs))
                {
                    WAVHeader header = new WAVHeader();

                    header.ChunkID       = br.ReadBytes(4);
                    header.ChunkSize     = br.ReadUInt32();
                    header.Format        = br.ReadBytes(4);
                    header.Subchunk1ID   = br.ReadBytes(4);
                    header.Subchunk1Size = br.ReadUInt32();
                    header.AudioFormat   = br.ReadUInt16();
                    header.NumChannels   = br.ReadUInt16();
                    header.SampleRate    = br.ReadUInt32();
                    header.ByteRate      = br.ReadUInt32();
                    header.BlockAlign    = br.ReadUInt16();
                    header.BitsPerSample = br.ReadUInt16();
                    header.Subchunk2ID   = br.ReadBytes(4);
                    header.Subchunk2Size = br.ReadUInt32();

                    this.Header = header;
                }
        }
Example #9
0
        public static byte[] DecodeMCAtoWAV(string mcaFile)
        {
            using (var br = new BinaryReaderX(File.OpenRead(mcaFile)))
            {
                //Header
                var header = br.ReadStruct <Header>();

                //check info
                if (header.magic != "MADP")
                {
                    Console.WriteLine("This is no mca file.");
                    Environment.Exit(0);
                }
                if (header.channelCount > 2)
                {
                    Console.WriteLine("Only mca's with 1 or 2 channels are supported.");
                    Environment.Exit(0);
                }

                //Output meta
                Console.WriteLine($"\nMeta:\n" +
                                  $"  Version: {header.version}\n" +
                                  $"\n" +
                                  $"  Channels: {header.channelCount}\n" +
                                  $"  SampleRate: {header.sampleRate}\n" +
                                  $"  Samples: {header.numSamples}\n" +
                                  $"\n" +
                                  $"  LoopStart: {header.loopStart}\n" +
                                  $"  LoopEnd: {header.loopEnd}");

                //Version specifics
                int headSize, coefShift, coefStart, startOffset, coefOffset;
                int coefSpacing = 0x30;
                if (header.version <= 3)
                {
                    headSize  = (int)br.BaseStream.Length - header.dataSize;
                    coefShift = 0x0;
                    coefStart = headSize - coefSpacing * header.channelCount;

                    startOffset = headSize;
                    coefOffset  = coefStart + coefShift * 0x14;
                }
                else if (header.version == 4)
                {
                    headSize  = header.headSize;
                    coefShift = header.coefShift;
                    coefStart = headSize - coefSpacing * header.channelCount;

                    startOffset = (int)br.BaseStream.Length - header.dataSize;
                    coefOffset  = coefStart + coefShift * 0x14;
                }
                else
                {
                    headSize  = header.headSize;
                    coefShift = header.coefShift;
                    coefStart = headSize - coefSpacing * header.channelCount;

                    var tmpOff = br.BaseStream.Position;
                    br.BaseStream.Position = coefStart - 0x4;
                    startOffset            = br.ReadInt32();
                    coefOffset             = coefStart + coefShift * 0x14;
                    br.BaseStream.Position = tmpOff;
                }

                //sanity check (for bad rips with the header manually truncated to in attempt to "fix" v5 headers)
                var fileSize = br.BaseStream.Length;

                if (startOffset + header.dataSize > fileSize)
                {
                    if (headSize + header.dataSize > fileSize)
                    {
                        throw new Exception("Mismatching information. headSize + dataSize don't correlate with fileSize.\nPlease check the header.");
                    }

                    startOffset = (int)fileSize - header.dataSize;
                }

                //Setup coefs
                var channels = SetupCoefs(br.BaseStream, coefOffset, header.channelCount, coefSpacing);

                //Decode NGC_DSP
                br.BaseStream.Position = startOffset;
                byte[] decode;
                int    channelDataSize = header.dataSize;
                if (header.channelCount == 1)
                {
                    //No interleave
                    decode = DecodeNGCDSP(br.ReadBytes(header.dataSize), header, channels[0]);
                }
                else
                {
                    //Interleave

                    //Get channelData
                    var soundData   = br.ReadBytes(header.dataSize);
                    var channelData = new List <List <byte> >();
                    for (int i = 0; i < header.channelCount; i++)
                    {
                        channelData.Add(new List <byte>());
                    }
                    using (var soundBr = new BinaryReaderX(new MemoryStream(soundData)))
                    {
                        while (soundBr.BaseStream.Position < soundBr.BaseStream.Length)
                        {
                            for (int i = 0; i < header.channelCount; i++)
                            {
                                channelData[i].AddRange(soundBr.ReadBytes(header.interleaveBlockSize));
                            }
                        }
                    }

                    //Decode channelData
                    var tmpDec = new List <byte>();
                    for (int i = 0; i < header.channelCount; i++)
                    {
                        tmpDec.AddRange(DecodeNGCDSP(channelData[i].ToArray(), header, channels[i]));
                    }
                    decode = tmpDec.ToArray();

                    channelDataSize = decode.Length / header.channelCount;
                }

                //Create WAV
                var wavHeader = new WAVHeader
                {
                    fileSize       = decode.Length + 0x28 - 0x8,
                    channelCount   = header.channelCount,
                    sampleRate     = header.sampleRate,
                    avgBytesPerSec = header.sampleRate * 0x2,
                    blockAlign     = (short)(0x2 * header.channelCount)
                };
                var wavStream = new MemoryStream();
                using (var bw = new BinaryWriterX(wavStream, true))
                {
                    bw.WriteStruct(wavHeader);
                    bw.WriteASCII("data");
                    bw.Write(decode.Length);

                    if (header.channelCount == 1)
                    {
                        bw.Write(decode);
                    }
                    else
                    {
                        int sampleInChannel = 0;
                        using (var decBr = new BinaryReaderX(new MemoryStream(decode)))
                        {
                            while (sampleInChannel < channelDataSize / 2)
                            {
                                for (int i = 0; i < header.channelCount; i++)
                                {
                                    decBr.BaseStream.Position = i * channelDataSize + sampleInChannel * 2;
                                    bw.Write(decBr.ReadInt16());
                                }
                                sampleInChannel++;
                            }
                        }
                    }
                }

                return(wavStream.ToArray());
            }
        }
Example #10
0
        /// <summary>
        /// Opens existing WAV file and reads header info.
        /// </summary>
        public void ReadWAVHeader()
        {
            using (FileStream fs = new FileStream(FileName, FileMode.Open, FileAccess.Read))
            using (BinaryReader br = new BinaryReader(fs))
            {
                WAVHeader header = new WAVHeader();

                header.ChunkID = br.ReadBytes(4);
                header.ChunkSize = br.ReadUInt32();
                header.Format = br.ReadBytes(4);
                header.Subchunk1ID = br.ReadBytes(4);
                header.Subchunk1Size = br.ReadUInt32();
                header.AudioFormat = br.ReadUInt16();
                header.NumChannels = br.ReadUInt16();
                header.SampleRate = br.ReadUInt32();
                header.ByteRate = br.ReadUInt32();
                header.BlockAlign = br.ReadUInt16();
                header.BitsPerSample = br.ReadUInt16();
                header.Subchunk2ID = br.ReadBytes(4);
                header.Subchunk2Size = br.ReadUInt32();

                this.Header = header;
            }
        }
Example #11
0
 /// <summary>
 /// Calculates WAV file duration (in minutes and seconds).
 /// </summary>
 /// <param name="WAVheader">WAV file header to read info from.</param>
 /// <param name="durationMinutes">Output parameter for duration in minutes.</param>
 /// <param name="durationSeconds">Output parameter for duration in seconds.</param>
 public void GetWAVFileDuration(WAVHeader WAVheader, out int durationMinutes, out double durationSeconds)
 {
     // We get duration from header data, data size / bytes per sample / number of channels / sample rate
     durationSeconds = (double)WAVheader.Subchunk2Size / (WAVheader.BitsPerSample / 8) / WAVheader.NumChannels / WAVheader.SampleRate;
     durationMinutes = (int)Math.Floor(durationSeconds / 60);
     durationSeconds -= durationMinutes * 60;
 }
Example #12
0
 /// <summary>
 /// Constructor to get file name and memory for header.
 /// </summary>
 /// <param name="fileName">File name</param>
 public WAVFile(string fileName)
 {
     this.FileName = fileName;
     this.Header   = new WAVHeader();
 }