/// <summary> /// Creates a cue list from the cue RIFF chunk and the list RIFF chunk /// </summary> /// <param name="cueChunkData">The data contained in the cue chunk</param> /// <param name="listChunkData">The data contained in the list chunk</param> internal CueList(byte[] cueChunkData, byte[] listChunkData) { int cueCount = BitConverter.ToInt32(cueChunkData, 0); Dictionary <int, int> cueIndex = new Dictionary <int, int>(); int[] positions = new int[cueCount]; int cue = 0; for (int p = 4; cueChunkData.Length - p >= 24; p += 24, cue++) { cueIndex[BitConverter.ToInt32(cueChunkData, p)] = cue; positions[cue] = BitConverter.ToInt32(cueChunkData, p + 20); } string[] labels = new string[cueCount]; int labelLength = 0; var labelChunkId = ChunkIdentifier.ChunkIdentifierToInt32("labl"); for (int p = 4; listChunkData.Length - p >= 16; p += labelLength + labelLength % 2 + 12) { if (BitConverter.ToInt32(listChunkData, p) == labelChunkId) { labelLength = BitConverter.ToInt32(listChunkData, p + 4) - 4; var cueId = BitConverter.ToInt32(listChunkData, p + 8); cue = cueIndex[cueId]; labels[cue] = Encoding.Default.GetString(listChunkData, p + 12, labelLength - 1); } } for (int i = 0; i < cueCount; i++) { cues.Add(new Cue(positions[i], labels[i])); } }
internal byte[] GetRiffChunks() { if (this.Count == 0) { return(null); } int num = 12 + 24 * this.Count; int num2 = 12; for (int i = 0; i < this.Count; i++) { int num3 = this[i].Label.Length + 1; num2 += num3 + num3 % 2 + 12; } byte[] array = new byte[num + num2]; int value = ChunkIdentifier.ChunkIdentifierToInt32("cue "); int value2 = ChunkIdentifier.ChunkIdentifierToInt32("data"); int value3 = ChunkIdentifier.ChunkIdentifierToInt32("LIST"); int value4 = ChunkIdentifier.ChunkIdentifierToInt32("adtl"); int value5 = ChunkIdentifier.ChunkIdentifierToInt32("labl"); using (MemoryStream memoryStream = new MemoryStream(array)) { using (BinaryWriter binaryWriter = new BinaryWriter(memoryStream)) { binaryWriter.Write(value); binaryWriter.Write(num - 8); binaryWriter.Write(this.Count); for (int j = 0; j < this.Count; j++) { int position = this[j].Position; binaryWriter.Write(j); binaryWriter.Write(position); binaryWriter.Write(value2); binaryWriter.Seek(8, SeekOrigin.Current); binaryWriter.Write(position); } binaryWriter.Write(value3); binaryWriter.Write(num2 - 8); binaryWriter.Write(value4); for (int k = 0; k < this.Count; k++) { binaryWriter.Write(value5); binaryWriter.Write(this[k].Label.Length + 1 + 4); binaryWriter.Write(k); binaryWriter.Write(Encoding.Default.GetBytes(this[k].Label.ToCharArray())); if (this[k].Label.Length % 2 == 0) { binaryWriter.Seek(2, SeekOrigin.Current); } else { binaryWriter.Seek(1, SeekOrigin.Current); } } } } return(array); }
private void ReadRiffHeader(BinaryReader br) { int header = br.ReadInt32(); if (header == ChunkIdentifier.ChunkIdentifierToInt32("RF64")) { this.isRf64 = true; } else if (header != ChunkIdentifier.ChunkIdentifierToInt32("RIFF")) { throw new FormatException("Not a WAVE file - no RIFF header"); } }
private void ReadDs64Chunk(BinaryReader reader) { int num = ChunkIdentifier.ChunkIdentifierToInt32("ds64"); if (reader.ReadInt32() != num) { throw new FormatException("Invalid RF64 WAV file - No ds64 chunk found"); } int num2 = reader.ReadInt32(); this.riffSize = reader.ReadInt64(); this.dataChunkLength = reader.ReadInt64(); reader.ReadInt64(); reader.ReadBytes(num2 - 24); }
/// <summary> /// http://tech.ebu.ch/docs/tech/tech3306-2009.pdf /// </summary> private void ReadDs64Chunk(BinaryReader reader) { int ds64ChunkId = ChunkIdentifier.ChunkIdentifierToInt32("ds64"); int chunkId = reader.ReadInt32(); if (chunkId != ds64ChunkId) { throw new FormatException("Invalid RF64 WAV file - No ds64 chunk found"); } int chunkSize = reader.ReadInt32(); this.riffSize = reader.ReadInt64(); this.dataChunkLength = reader.ReadInt64(); long sampleCount = reader.ReadInt64(); // replaces the value in the fact chunk reader.ReadBytes(chunkSize - 24); // get to the end of this chunk (should parse extra stuff later) }
internal CueList(byte[] cueChunkData, byte[] listChunkData) { int num = BitConverter.ToInt32(cueChunkData, 0); Dictionary <int, int> dictionary = new Dictionary <int, int>(); int[] array = new int[num]; int num2 = 0; int num3 = 4; while (cueChunkData.Length - num3 >= 24) { dictionary[BitConverter.ToInt32(cueChunkData, num3)] = num2; array[num2] = BitConverter.ToInt32(cueChunkData, num3 + 20); num3 += 24; num2++; } string[] array2 = new string[num]; int num4 = 0; int num5 = ChunkIdentifier.ChunkIdentifierToInt32("labl"); int num6 = 4; while (listChunkData.Length - num6 >= 16) { if (BitConverter.ToInt32(listChunkData, num6) == num5) { num4 = BitConverter.ToInt32(listChunkData, num6 + 4) - 4; int key = BitConverter.ToInt32(listChunkData, num6 + 8); num2 = dictionary[key]; array2[num2] = Encoding.Default.GetString(listChunkData, num6 + 12, num4 - 1); } num6 += num4 + num4 % 2 + 12; } for (int i = 0; i < num; i++) { this.cues.Add(new Cue(array[i], array2[i])); } }
/// <summary> /// Gets the cues as the concatenated cue and list RIFF chunks. /// </summary> /// <returns>RIFF chunks containing the cue data</returns> internal byte[] GetRiffChunks() { if (Count == 0) { return(null); } var cueChunkLength = 12 + 24 * Count; var listChunkLength = 12; for (int i = 0; i < Count; i++) { var labelChunkLength = this[i].Label.Length + 1; listChunkLength += labelChunkLength + labelChunkLength % 2 + 12; } byte[] chunks = new byte[cueChunkLength + listChunkLength]; var cueChunkId = ChunkIdentifier.ChunkIdentifierToInt32("cue "); int dataChunkId = ChunkIdentifier.ChunkIdentifierToInt32("data"); int listChunkId = ChunkIdentifier.ChunkIdentifierToInt32("LIST"); int adtlTypeId = ChunkIdentifier.ChunkIdentifierToInt32("adtl"); int labelChunkId = ChunkIdentifier.ChunkIdentifierToInt32("labl"); using (var stream = new MemoryStream(chunks)) { using (var writer = new BinaryWriter(stream)) { writer.Write(cueChunkId); writer.Write(cueChunkLength - 8); writer.Write(Count); for (int cue = 0; cue < Count; cue++) { int position = this[cue].Position; writer.Write(cue); writer.Write(position); writer.Write(dataChunkId); writer.Seek(8, SeekOrigin.Current); writer.Write(position); } writer.Write(listChunkId); writer.Write(listChunkLength - 8); writer.Write(adtlTypeId); for (int cue = 0; cue < Count; cue++) { writer.Write(labelChunkId); writer.Write(this[cue].Label.Length + 1 + 4); writer.Write(cue); writer.Write(Encoding.Default.GetBytes(this[cue].Label.ToCharArray())); if (this[cue].Label.Length % 2 == 0) { writer.Seek(2, SeekOrigin.Current); } else { writer.Seek(1, SeekOrigin.Current); } } } } return(chunks); }
public WaveFormat ReadWaveHeader(Stream stream) { this.dataChunkPosition = -1; this.riffChunks = new List <RiffChunk>(); this.dataChunkLength = 0; var br = new BinaryReader(stream); ReadRiffHeader(br); this.riffSize = br.ReadUInt32(); // read the file size (minus 8 bytes) if (br.ReadInt32() != ChunkIdentifier.ChunkIdentifierToInt32("WAVE")) { throw new FormatException("Not a WAVE file - no WAVE header"); } if (isRf64) { ReadDs64Chunk(br); } long length = stream.Length; int dataChunkId = ChunkIdentifier.ChunkIdentifierToInt32("data"); int formatChunkId = ChunkIdentifier.ChunkIdentifierToInt32("fmt "); // sometimes a file has more data than is specified after the RIFF header long stopPosition = Math.Min(riffSize + 8, length); // this -8 is so we can be sure that there are at least 8 bytes for a chunk id and length while (stream.Position <= stopPosition - 8) { Int32 chunkIdentifier = br.ReadInt32(); var chunkLength = br.ReadUInt32(); if (chunkIdentifier == dataChunkId) { dataChunkPosition = stream.Position; if (!isRf64) // we already know the dataChunkLength if this is an RF64 file { dataChunkLength = chunkLength; } stream.Position += chunkLength; } else if (chunkIdentifier == formatChunkId) { if (chunkLength > Int32.MaxValue) { throw new InvalidDataException(string.Format("Format chunk length must be between 0 and {0}.", Int32.MaxValue)); } return(WaveFormat.FromFormatChunk(br, (int)chunkLength)); } else { // check for invalid chunk length if (chunkLength > length - stream.Position) { if (strictMode) { Debug.Assert(false, String.Format("Invalid chunk length {0}, pos: {1}. length: {2}", chunkLength, stream.Position, length)); } // an exception will be thrown further down if we haven't got a format and data chunk yet, // otherwise we will tolerate this file despite it having corrupt data at the end break; } /*if (storeAllChunks) * { * if (chunkLength > Int32.MaxValue) * throw new InvalidDataException(string.Format("RiffChunk chunk length must be between 0 and {0}.", Int32.MaxValue)); * riffChunks.Add(GetRiffChunk(stream, chunkIdentifier, (int)chunkLength)); * }*/ stream.Position += chunkLength; } } throw new FormatException("Invalid WAV file - No fmt chunk found"); }
public void CanConvertChunkIndentiferToInt(string chunkIdentifier) { var x = WaveInterop.mmioStringToFOURCC(chunkIdentifier, 0); Assert.AreEqual(x, ChunkIdentifier.ChunkIdentifierToInt32(chunkIdentifier)); }
public void ReadWaveHeader(Stream stream) { this.dataChunkPosition = -1; this.waveFormat = null; this.riffChunks = new List <RiffChunk>(); this.dataChunkLength = 0; var br = new BinaryReader(stream); ReadRiffHeader(br); this.riffSize = br.ReadUInt32(); // read the file size (minus 8 bytes) if (br.ReadInt32() != ChunkIdentifier.ChunkIdentifierToInt32("WAVE")) { throw new FormatException("Not a WAVE file - no WAVE header"); } if (isRf64) { ReadDs64Chunk(br); } int dataChunkId = ChunkIdentifier.ChunkIdentifierToInt32("data"); int formatChunkId = ChunkIdentifier.ChunkIdentifierToInt32("fmt "); // sometimes a file has more data than is specified after the RIFF header long stopPosition = Math.Min(riffSize + 8, stream.Length); // this -8 is so we can be sure that there are at least 8 bytes for a chunk id and length while (stream.Position <= stopPosition - 8) { Int32 chunkIdentifier = br.ReadInt32(); var chunkLength = br.ReadUInt32(); if (chunkIdentifier == dataChunkId) { dataChunkPosition = stream.Position; if (!isRf64) // we already know the dataChunkLength if this is an RF64 file { dataChunkLength = chunkLength; } stream.Position += chunkLength; } else if (chunkIdentifier == formatChunkId) { if (chunkLength > Int32.MaxValue) { throw new InvalidDataException(string.Format("Format chunk length must be between 0 and {0}.", Int32.MaxValue)); } waveFormat = WaveFormat.FromFormatChunk(br, (int)chunkLength); } else { // check for invalid chunk length if (chunkLength > stream.Length - stream.Position) { if (strictMode) { Debug.Assert(false, String.Format("Invalid chunk length {0}, pos: {1}. length: {2}", chunkLength, stream.Position, stream.Length)); } // an exception will be thrown further down if we haven't got a format and data chunk yet, // otherwise we will tolerate this file despite it having corrupt data at the end break; } if (storeAllChunks) { if (chunkLength > Int32.MaxValue) { throw new InvalidDataException(string.Format("RiffChunk chunk length must be between 0 and {0}.", Int32.MaxValue)); } riffChunks.Add(GetRiffChunk(stream, chunkIdentifier, (int)chunkLength)); } stream.Position += chunkLength; } // All Chunks have to be word aligned. // https://www.tactilemedia.com/info/MCI_Control_Info.html // "If the chunk size is an odd number of bytes, a pad byte with value zero is // written after ckData. Word aligning improves access speed (for chunks resident in memory) // and maintains compatibility with EA IFF. The ckSize value does not include the pad byte." if (((chunkLength % 2) != 0) && (br.PeekChar() == 0)) { stream.Position++; } } if (waveFormat == null) { throw new FormatException("Invalid WAV file - No fmt chunk found"); } if (dataChunkPosition == -1) { throw new FormatException("Invalid WAV file - No data chunk found"); } }
public void ReadWaveHeader(Stream stream) { this.dataChunkPosition = -1L; this.waveFormat = null; this.riffChunks = new List <RiffChunk>(); this.dataChunkLength = 0L; BinaryReader binaryReader = new BinaryReader(stream); this.ReadRiffHeader(binaryReader); this.riffSize = (long)((ulong)binaryReader.ReadUInt32()); if (binaryReader.ReadInt32() != ChunkIdentifier.ChunkIdentifierToInt32("WAVE")) { throw new FormatException("Not a WAVE file - no WAVE header"); } if (this.isRf64) { this.ReadDs64Chunk(binaryReader); } int num = ChunkIdentifier.ChunkIdentifierToInt32("data"); int num2 = ChunkIdentifier.ChunkIdentifierToInt32("fmt "); long num3 = Math.Min(this.riffSize + 8L, stream.Length); while (stream.Position <= num3 - 8L) { int num4 = binaryReader.ReadInt32(); uint num5 = binaryReader.ReadUInt32(); if (num4 == num) { this.dataChunkPosition = stream.Position; if (!this.isRf64) { this.dataChunkLength = (long)((ulong)num5); } stream.Position += (long)((ulong)num5); } else if (num4 == num2) { if (num5 > 2147483647u) { throw new InvalidDataException(string.Format("Format chunk length must be between 0 and {0}.", int.MaxValue)); } this.waveFormat = WaveFormat.FromFormatChunk(binaryReader, (int)num5); } else if ((ulong)num5 > (ulong)(stream.Length - stream.Position)) { if (this.strictMode) { break; } break; } else { if (this.storeAllChunks) { if (num5 > 2147483647u) { throw new InvalidDataException(string.Format("RiffChunk chunk length must be between 0 and {0}.", int.MaxValue)); } this.riffChunks.Add(WaveFileChunkReader.GetRiffChunk(stream, num4, (int)num5)); } stream.Position += (long)((ulong)num5); } } if (this.waveFormat == null) { throw new FormatException("Invalid WAV file - No fmt chunk found"); } if (this.dataChunkPosition == -1L) { throw new FormatException("Invalid WAV file - No data chunk found"); } }
public void ReadWaveHeader(Stream stream) { this.dataChunkPosition = -1; this.waveFormat = null; this.riffChunks = new List <RiffChunk>(); this.dataChunkLength = 0; var br = new BinaryReader(stream); ReadRiffHeader(br); this.riffSize = br.ReadUInt32(); // read the file size (minus 8 bytes) if (br.ReadInt32() != ChunkIdentifier.ChunkIdentifierToInt32("WAVE")) { throw new FormatException("Not a WAVE file - no WAVE header"); } if (isRf64) { ReadDs64Chunk(br); } HashSet <int> knownChunkIds = new HashSet <int>(ChunkIdentifier.KnownChunkIdentifiers()); int dataChunkId = ChunkIdentifier.ChunkIdentifierToInt32("data"); int formatChunkId = ChunkIdentifier.ChunkIdentifierToInt32("fmt "); // sometimes a file has more data than is specified after the RIFF header long stopPosition = Math.Min(riffSize + 8, stream.Length); // this -8 is so we can be sure that there are at least 8 bytes for a chunk id and length while (stream.Position <= stopPosition - 8) { Int32 chunkIdentifier = br.ReadInt32(); if (knownChunkIds.Contains(chunkIdentifier) == false) { //this chunk id isn't known, perhaps the previous chunk length was incorrect, lets look in nearby offsets chunkIdentifier = LocalSeekForChunkIdentifier(stream, br, knownChunkIds); } var chunkLength = br.ReadUInt32(); if (chunkIdentifier == dataChunkId) { dataChunkPosition = stream.Position; if (!isRf64) // we already know the dataChunkLength if this is an RF64 file { dataChunkLength = chunkLength; } stream.Position += chunkLength; } else if (chunkIdentifier == formatChunkId) { if (chunkLength > Int32.MaxValue) { throw new InvalidDataException(string.Format("Format chunk length must be between 0 and {0}.", Int32.MaxValue)); } waveFormat = WaveFormat.FromFormatChunk(br, (int)chunkLength); } else { // check for invalid chunk length if (chunkLength > stream.Length - stream.Position) { if (strictMode) { Debug.Assert(false, String.Format("Invalid chunk length {0}, pos: {1}. length: {2}", chunkLength, stream.Position, stream.Length)); } // an exception will be thrown further down if we haven't got a format and data chunk yet, // otherwise we will tolerate this file despite it having corrupt data at the end break; } if (storeAllChunks) { if (chunkLength > Int32.MaxValue) { throw new InvalidDataException(string.Format("RiffChunk chunk length must be between 0 and {0}.", Int32.MaxValue)); } riffChunks.Add(GetRiffChunk(stream, chunkIdentifier, (int)chunkLength)); } stream.Position += chunkLength; } } if (waveFormat == null) { throw new FormatException("Invalid WAV file - No fmt chunk found"); } if (dataChunkPosition == -1) { throw new FormatException("Invalid WAV file - No data chunk found"); } }