public static void WAVFromPCM(Stream input, Stream output, short channels, int samplesPerSec, int bitsPerSample, int samples = 0, IProgressReport writingProgress = null) { short sample_size = (short)((bitsPerSample / 8) * channels); using (BinaryWriter writer = new BinaryWriter(new StreamKeeper(output))) { writer.Write(new char[] { 'R', 'I', 'F', 'F' }); writer.Write((int)0); // Skip size of wave file writer.Write(new char[] { 'W', 'A', 'V', 'E' }); writer.Write(new char[] { 'f', 'm', 't', ' ' }); writer.Write((int)16); // Size of header writer.Write((short)1); // Format tag - PCM writer.Write(channels); writer.Write(samplesPerSec); writer.Write((int)(sample_size * samplesPerSec)); // average bytes per sec writer.Write(sample_size); // full sample size.. writer.Write((short)bitsPerSample); writer.Write(new char[] { 'd', 'a', 't', 'a' }); writer.Write((int)0); // Skip size of data } if (samples != 0) { if (input.CopyToCount(output, samples * sample_size, writingProgress) != samples * sample_size) { // Check output size throw new Exception("Invalid WAV size"); } } else { // Write the pcm input.CopyTo(output); if (writingProgress != null) { writingProgress.SetProgress(writingProgress.GetFullValue()); } } output.Seek(4, SeekOrigin.Begin); // Write the size using (BinaryWriter writer = new BinaryWriter(new StreamKeeper(output))) { writer.Write((int)(output.Length - 8)); } output.Seek(40, SeekOrigin.Begin); // Write the size using (BinaryWriter writer = new BinaryWriter(new StreamKeeper(output))) { writer.Write((int)(output.Length - 44)); } }
public void SetProgress(long value) { Parent.SetProgress((long)(StartProgress + value * Unit)); }
/* TODO: * private void WriteDataInline(Stream stream, List<Entry> entries, Dictionary<Entry, Structs.RPF7EntryInfoTemplate> entriesInfo, int headersEnd) * { * Range<FileEntry> oldFileLayout = new Range<FileEntry>(Math.Max(stream.Length, (long)headersEnd)); * List<FileEntry> emptyEntries = new List<FileEntry>(); * List<FileEntry> moveEntries = new List<FileEntry>(); * List<FileEntry> newEntries = new List<FileEntry>(); * // Entries that should be written to temporary files * List<FileEntry> newSavedEntries = new List<FileEntry>(); * * // A dictionary of the raw data stream that we need to write to the file * Dictionary<FileEntry, Stream> entriesStream = new Dictionary<FileEntry, System.IO.Stream>(); * * // Add the header * oldFileLayout.AddItem(0, headersEnd, null); * * foreach (Entry entry in entries) * { * FileEntry fentry = entry as FileEntry; * if (fentry != null) * { * * // We need to find all the files that depends on the origianl stream first * FileStreamCreator originalStream = fentry.TryGetOriginalFileStreamCreator(); * if (fentry.Data.GetSize() == 0 && fentry.IsRegularFile() && !((RegularFileEntry)fentry).Compressed) * { * emptyEntries.Add(fentry); * } * else if (originalStream != null && originalStream.FileStream == this.Stream) * { * if (originalStream.Offset < headersEnd) { * moveEntries.Add(fentry); * } * if (!oldFileLayout.AddItem(originalStream.Offset, originalStream.Size, fentry, false)) * { * // If failed for some reason.. well it can happen if two entries have the same data. Anyway I don't want that two entries will use the same data. * newSavedEntries.Add(fentry); * } * else * { * entriesStream[fentry] = new PartialStream(this.Stream, originalStream.Offset, originalStream.Size); * } * } * else if (fentry.Data is FileStreamCreator && ((FileStreamCreator)fentry.Data).FileStream == this.Stream) * { * // This file points to the original file, but something about it changed (compression, encryption, ..) * newSavedEntries.Add(fentry); * } * // From here are entries that are not depends on the original strema * else if ((fentry.IsRegularFile() && ((RegularFileEntry)fentry).Compressed) || fentry.IsResource()) * { * newSavedEntries.Add(fentry); * } * else * { * entriesStream[fentry] = fentry.Data.GetStream(); * newEntries.Add(fentry); * } * } * } * * foreach (FileEntry entry in newSavedEntries) * { * string filepath = Path.GetTempFileName(); * // Let's copy the file to temp folder, this file will be deleted on close * FileStream writeStream = new FileStream(filepath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite | FileShare.Delete, 0x1000, FileOptions.DeleteOnClose); * * entry.Data.GetStream().CopyTo(writeStream); * * // Take an handle to the file, so it will be delete only when this handle will be closed. * FileStream readStream = File.Open(filepath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete); * writeStream.Close(); * * entriesStream[entry] = writeStream; * } * * Range<FileEntry> newFileLayout = new Range<FileEntry>(); * } */ public void Write(Stream stream, IProgressReport progressReport = null) { if (progressReport != null) { progressReport.SetMessage("Preparing..."); progressReport.SetProgress(-1); } if (this.Filename == "") { throw new Exception("Can't save"); } // Get all the entries List <Entry> entries = new List <Entry>(); this.Root.AddToList(entries); Dictionary <Entry, Structs.RPF7EntryInfoTemplate> entriesInfo = new Dictionary <Entry, Structs.RPF7EntryInfoTemplate>(); foreach (Entry entry in entries) { Structs.RPF7EntryInfoTemplate entryInfo = new Structs.RPF7EntryInfoTemplate(); // update the is resource field entryInfo.Field1 = (entry is ResourceEntry) ? 1U : 0U; entriesInfo[entry] = entryInfo; } int shiftNameAccessBy; Stream names = WriteNames(entries, entriesInfo, out shiftNameAccessBy); // Fill the header Info.EntriesCount = entries.Count; Info.ShiftNameAccessBy = shiftNameAccessBy; Info.EntriesNamesLength = (int)names.Length; // Go to current position stream.Seek(0x10 + 0x10 * Info.EntriesCount + Info.EntriesNamesLength, SeekOrigin.Begin); // align to 0x200 if (stream.Position % (1 << 9) != 0) { stream.Write(new byte[(1 << 9) - ((int)stream.Position % (1 << 9))], 0, (1 << 9) - ((int)stream.Position % (1 << 9))); } WriteData(stream, entries, entriesInfo, progressReport); long end = stream.Position; using (Stream writer = AES.EncryptStream(new StreamKeeper(stream), sixteenRoundsDecrypt)) { int currentFreeIndex = 1; // Last finish to build and write the file stream.Seek(0, SeekOrigin.Begin); Info.Write(stream); Queue <Entry> entriesToProcess = new Queue <Entry>(); entriesToProcess.Enqueue(this.Root); while (entriesToProcess.Count > 0) { Entry entry = entriesToProcess.Dequeue(); if (entry is DirectoryEntry) { Structs.RPF7EntryInfoTemplate entryInfo = entriesInfo[entry]; IList <Entry> subentries = (entry as DirectoryEntry).GetEntries(); // Update the info on the sub entries entryInfo.Field5 = (uint)currentFreeIndex; entryInfo.Field6 = (uint)subentries.Count; entriesInfo[entry] = entryInfo; // Process the sub entries foreach (Entry subentry in subentries) { entriesToProcess.Enqueue(subentry); } currentFreeIndex += subentries.Count; } // Write the entry info entriesInfo[entry].Write(writer); } // Write names names.Seek(0, SeekOrigin.Begin); names.CopyTo(writer); } // Seek to end stream.Seek(end, SeekOrigin.Begin); // Done! }