public bool Read(BinaryReader source, AudioDataManager.SizeInfo sizeInfo, MetaDataIO.ReadTagParams readTagParams) { return(true); }
protected override Boolean read(BinaryReader source, MetaDataIO.ReadTagParams readTagParams) { var result = true; var maxPatterns = -1; Byte nbSamples = 31; String readString; var comment = new StringBuilder(""); Sample sample; IList <IList <Int32> > pattern; IList <Int32> row; resetData(); // == TITLE == readString = Utils.Latin1Encoding.GetString(source.ReadBytes(4)); if (readString.Equals(SIG_POWERPACKER)) { result = false; throw new Exception("MOD files compressed with PowerPacker are not supported yet"); } tagExists = true; // Restart from beginning, else parser might miss empty titles source.BaseStream.Seek(0, SeekOrigin.Begin); // Title = max first 20 chars; null-terminated var title = StreamUtils.ReadNullTerminatedStringFixed(source, System.Text.Encoding.ASCII, 20); if (readTagParams.PrepareForWriting) { structureHelper.AddZone(0, 20, new Byte[20] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, ZONE_TITLE); } tagData.IntegrateValue(TagData.TAG_FIELD_TITLE, title.Trim()); // == SAMPLES == nbSamples = detectNbSamples(source); var charOne = Utils.Latin1Encoding.GetString(new Byte[] { 1 }); for (var i = 0; i < nbSamples; i++) { sample = new Sample(); sample.Name = StreamUtils.ReadNullTerminatedStringFixed(source, System.Text.Encoding.ASCII, 22).Trim(); sample.Name = sample.Name.Replace("\0", ""); sample.Name = sample.Name.Replace(charOne, ""); sample.Size = StreamUtils.ReverseUInt16(source.ReadUInt16()) * 2; sample.Finetune = source.ReadSByte(); sample.Volume = source.ReadByte(); sample.RepeatOffset = StreamUtils.ReverseUInt16(source.ReadUInt16()) * 2; sample.RepeatLength = StreamUtils.ReverseUInt16(source.ReadUInt16()) * 2; FSamples.Add(sample); } // == SONG == nbValidPatterns = source.ReadByte(); source.BaseStream.Seek(1, SeekOrigin.Current); // Controversial byte; no real use here for (var i = 0; i < 128; i++) { FPatternTable.Add(source.ReadByte()); // Pattern table } // File format tag formatTag = Utils.Latin1Encoding.GetString(source.ReadBytes(4)).Trim(); if (modFormats.ContainsKey(formatTag)) { nbChannels = modFormats[formatTag].NbChannels; trackerName = modFormats[formatTag].Name; } else // Default { nbChannels = NB_CHANNELS_DEFAULT; LogDelegator.GetLogDelegate()(Log.LV_WARNING, "MOD format tag '" + formatTag + "'not recognized"); } // == PATTERNS == // Some extra information about the "FLT8" -type MOD's: // // These MOD's have 8 channels, still the format isn't the same as the // other 8 channel formats ("OCTA", "CD81", "8CHN"): instead of storing // ONE 8-track pattern, it stores TWO 4-track patterns per logical pattern. // i.e. The first 4 channels of the first logical pattern are stored in // the first physical 4-channel pattern (size 1kb) whereas channel 5 until // channel 8 of the first logical pattern are stored as the SECOND physical // 4-channel pattern. Got it? ;-). // If you convert all the 4 channel patterns to 8 channel patterns, do not // forget to divide each pattern nr by 2 in the pattern sequence table! foreach (var b in FPatternTable) { maxPatterns = Math.Max(maxPatterns, b); } for (var p = 0; p < maxPatterns + 1; p++) // Patterns loop { FPatterns.Add(new List <IList <Int32> >()); pattern = FPatterns[FPatterns.Count - 1]; // Rows loop for (var l = 0; l < MAX_ROWS; l++) { pattern.Add(new List <Int32>()); row = pattern[pattern.Count - 1]; for (var c = 0; c < nbChannels; c++) // Channels loop { row.Add(StreamUtils.ReverseInt32(source.ReadInt32())); } // end channels loop } // end rows loop } // end patterns loop // == Computing track properties duration = calculateDuration(); foreach (var aSample in FSamples) { if (aSample.Name.Length > 0) { comment.Append(aSample.Name).Append(Settings.InternalValueSeparator); } } if (comment.Length > 0) { comment.Remove(comment.Length - 1, 1); } tagData.IntegrateValue(TagData.TAG_FIELD_COMMENT, comment.ToString()); bitrate = sizeInfo.FileSize / duration; return(result); }
protected override bool read(BinaryReader source, MetaDataIO.ReadTagParams readTagParams) { bool result = true; ushort nbPatterns = 0; ushort nbInstruments = 0; ushort trackerVersion; uint headerSize = 0; uint songLength = 0; StringBuilder comment = new StringBuilder(""); resetData(); BufferedBinaryReader bSource = new BufferedBinaryReader(source.BaseStream); // File format signature if (!XM_SIGNATURE.Equals(Utils.Latin1Encoding.GetString(bSource.ReadBytes(17)))) { result = false; throw new Exception("Invalid XM file (file signature String mismatch)"); } // Title = chars 17 to 37 (length 20) string title = StreamUtils.ReadNullTerminatedStringFixed(bSource, System.Text.Encoding.ASCII, 20); if (readTagParams.PrepareForWriting) { structureHelper.AddZone(17, 20, new byte[20] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, ZONE_TITLE); } tagData.IntegrateValue(TagData.TAG_FIELD_TITLE, title.Trim()); // File format signature if (!0x1a.Equals(bSource.ReadByte())) { result = false; throw new Exception("Invalid XM file (file signature ID mismatch)"); } tagExists = true; trackerName = StreamUtils.ReadNullTerminatedStringFixed(bSource, System.Text.Encoding.ASCII, 20).Trim(); trackerVersion = bSource.ReadUInt16(); // hi-byte major and low-byte minor trackerName += (trackerVersion << 8) + "." + (trackerVersion & 0xFF00); headerSize = bSource.ReadUInt32(); // Calculated FROM THIS OFFSET, not from the beginning of the file songLength = bSource.ReadUInt16(); bSource.Seek(2, SeekOrigin.Current); // Restart position nbChannels = (byte)Math.Min(bSource.ReadUInt16(), (ushort)0xFF); nbPatterns = bSource.ReadUInt16(); nbInstruments = bSource.ReadUInt16(); bSource.Seek(2, SeekOrigin.Current); // Flags for frequency tables; useless for ATL initialSpeed = bSource.ReadUInt16(); initialTempo = bSource.ReadUInt16(); // Pattern table for (int i = 0; i < (headerSize - 20); i++) // 20 being the number of bytes read since the header size marker { if (i < songLength) { FPatternTable.Add(bSource.ReadByte()); } else { bSource.Seek(1, SeekOrigin.Current); } } readPatterns(bSource, nbPatterns); readInstruments(bSource, nbInstruments); // == Computing track properties duration = calculateDuration(); foreach (Instrument i in FInstruments) { if (i.DisplayName.Length > 0) { comment.Append(i.DisplayName).Append(Settings.InternalValueSeparator); } } if (comment.Length > 0) { comment.Remove(comment.Length - 1, 1); } tagData.IntegrateValue(TagData.TAG_FIELD_COMMENT, comment.ToString()); bitrate = sizeInfo.FileSize / duration; return(result); }
// ---------- SUPPORT METHODS /* Unused for now * private double getCompressionRatio() * { * // Get compression ratio * if (isValid) * return (double)sizeInfo.FileSize / ((duration * sampleRate) * (channels * bits / 8) + 44) * 100; * else * return 0; * } */ public Boolean Read(BinaryReader source, SizeInfo sizeInfo, MetaDataIO.ReadTagParams readTagParams) { UInt16 signatureChunk; Byte aByte; this.sizeInfo = sizeInfo; resetData(); var result = false; source.BaseStream.Seek(0, SeekOrigin.Begin); signatureChunk = source.ReadUInt16(); if (30475 == signatureChunk) { aByte = 0; source.BaseStream.Seek(2, SeekOrigin.Current); aByte = source.ReadByte(); switch (aByte & 0xC0) { case 0: sampleRate = 48000; break; case 0x40: sampleRate = 44100; break; case 0x80: sampleRate = 32000; break; default: sampleRate = 0; break; } bitrate = BITRATES[(aByte & 0x3F) >> 1]; aByte = 0; source.BaseStream.Seek(1, SeekOrigin.Current); aByte = source.ReadByte(); /* unused for now * switch (aByte & 0xE0) * { * case 0: channels = 2; break; * case 0x20: channels = 1; break; * case 0x40: channels = 2; break; * case 0x60: channels = 3; break; * case 0x80: channels = 3; break; * case 0xA0: channels = 4; break; * case 0xC0: channels = 4; break; * case 0xE0: channels = 5; break; * default : channels = 0; break; * } * * bits = 16; */ duration = sizeInfo.FileSize * 8.0 / bitrate; result = true; } return(result); }
/**************************************************************************** * * * Public methods * * * ****************************************************************************/ //--------------------------------------------------------------- // Imports Standard MIDI File (type 0 or 1) (and RMID) // (if optional parameter $tn set, only track $tn is imported) //--------------------------------------------------------------- public bool Read(BinaryReader source, AudioDataManager.SizeInfo sizeInfo, MetaDataIO.ReadTagParams readTagParams) { this.sizeInfo = sizeInfo; return(read(source, readTagParams)); }
private bool readFrames(BinaryReader source, TagInfo Tag, MetaDataIO.ReadTagParams readTagParams) { string frameName; string strValue; int frameDataSize; long valuePosition; int frameFlags; source.BaseStream.Seek(Tag.FileSize - Tag.DataShift - Tag.Size, SeekOrigin.Begin); // Read all stored fields for (int iterator = 0; iterator < Tag.FrameCount; iterator++) { frameDataSize = source.ReadInt32(); frameFlags = source.ReadInt32(); frameName = StreamUtils.ReadNullTerminatedString(source, Utils.Latin1Encoding); // Slightly more permissive than what APE specs indicate in terms of allowed characters ("Space(0x20), Slash(0x2F), Digits(0x30...0x39), Letters(0x41...0x5A, 0x61...0x7A)") valuePosition = source.BaseStream.Position; if (frameDataSize < 0 || valuePosition + frameDataSize > Tag.FileSize) { LogDelegator.GetLogDelegate()(Log.LV_ERROR, "Invalid value found while reading APEtag frame"); return(false); } if ((frameDataSize > 0) && (frameDataSize <= 1000)) { /* * According to spec : "Items are not zero-terminated like in C / C++. * If there's a zero character, multiple items are stored under the key and the items are separated by zero characters." * * => Values have to be splitted */ strValue = Utils.StripEndingZeroChars(Encoding.UTF8.GetString(source.ReadBytes(frameDataSize))); strValue = strValue.Replace('\0', Settings.InternalValueSeparator).Trim(); SetMetaField(frameName.Trim().ToUpper(), strValue, readTagParams.ReadAllMetaFrames); } else if (frameDataSize > 0 && !frameName.ToLower().Contains("lyrics")) // Size > 1000 => Probably an embedded picture { int picturePosition; PictureInfo.PIC_TYPE picType = decodeAPEPictureType(frameName); if (picType.Equals(PictureInfo.PIC_TYPE.Unsupported)) { addPictureToken(getImplementedTagType(), frameName); picturePosition = takePicturePosition(getImplementedTagType(), frameName); } else { addPictureToken(picType); picturePosition = takePicturePosition(picType); } if (readTagParams.ReadPictures) { // Description seems to be a null-terminated ANSI string containing // * The frame name // * A byte (0x2E) // * The picture type (3 characters; similar to the 2nd part of the mime-type) string description = StreamUtils.ReadNullTerminatedString(source, Utils.Latin1Encoding); PictureInfo picInfo = PictureInfo.fromBinaryData(source.BaseStream, frameDataSize - description.Length - 1, picType, getImplementedTagType(), frameName, picturePosition); picInfo.Description = description; tagData.Pictures.Add(picInfo); } } source.BaseStream.Seek(valuePosition + frameDataSize, SeekOrigin.Begin); } return(true); }
private void readFrames(BinaryReader source, TagInfo Tag, MetaDataIO.ReadTagParams readTagParams) { String frameName; String strValue; Int32 frameDataSize; Int64 valuePosition; Int32 frameFlags; source.BaseStream.Seek(Tag.FileSize - Tag.DataShift - Tag.Size, SeekOrigin.Begin); // Read all stored fields for (var iterator = 0; iterator < Tag.FrameCount; iterator++) { frameDataSize = source.ReadInt32(); frameFlags = source.ReadInt32(); frameName = StreamUtils.ReadNullTerminatedString(source, Utils.Latin1Encoding); // Slightly more permissive than what APE specs indicate in terms of allowed characters ("Space(0x20), Slash(0x2F), Digits(0x30...0x39), Letters(0x41...0x5A, 0x61...0x7A)") valuePosition = source.BaseStream.Position; if ((frameDataSize > 0) && (frameDataSize <= 500)) { /* * According to spec : "Items are not zero-terminated like in C / C++. * If there's a zero character, multiple items are stored under the key and the items are separated by zero characters." * * => Values have to be splitted */ strValue = Utils.StripEndingZeroChars(Encoding.UTF8.GetString(source.ReadBytes(frameDataSize))); strValue = strValue.Replace('\0', Settings.InternalValueSeparator).Trim(); SetMetaField(frameName.Trim().ToUpper(), strValue, readTagParams.ReadAllMetaFrames); } else if (frameDataSize > 0) // Size > 500 => Probably an embedded picture { Int32 picturePosition; var picType = decodeAPEPictureType(frameName); if (picType.Equals(PictureInfo.PIC_TYPE.Unsupported)) { addPictureToken(getImplementedTagType(), frameName); picturePosition = takePicturePosition(getImplementedTagType(), frameName); } else { addPictureToken(picType); picturePosition = takePicturePosition(picType); } if (readTagParams.ReadPictures || readTagParams.PictureStreamHandler != null) { // Description seems to be a null-terminated ANSI string containing // * The frame name // * A byte (0x2E) // * The picture type (3 characters; similar to the 2nd part of the mime-type) var description = StreamUtils.ReadNullTerminatedString(source, Utils.Latin1Encoding); var imgFormat = ImageUtils.GetImageFormatFromMimeType(description.Substring(description.Length - 3, 3)); var picInfo = new PictureInfo(imgFormat, picType, getImplementedTagType(), frameName, picturePosition); picInfo.Description = description; picInfo.PictureData = new Byte[frameDataSize - description.Length - 1]; source.BaseStream.Read(picInfo.PictureData, 0, frameDataSize - description.Length - 1); tagData.Pictures.Add(picInfo); if (readTagParams.PictureStreamHandler != null) { var mem = new MemoryStream(picInfo.PictureData); readTagParams.PictureStreamHandler(ref mem, picInfo.PicType, picInfo.NativeFormat, picInfo.TagType, picInfo.NativePicCode, picInfo.Position); mem.Close(); } } } source.BaseStream.Seek(valuePosition + frameDataSize, SeekOrigin.Begin); } }
protected override bool read(BinaryReader source, MetaDataIO.ReadTagParams readTagParams) { bool result = true; ushort nbOrders = 0; ushort nbPatterns = 0; ushort nbInstruments = 0; ushort flags; ushort trackerVersion; StringBuilder comment = new StringBuilder(""); IList <ushort> patternPointers = new List <ushort>(); IList <ushort> instrumentPointers = new List <ushort>(); resetData(); BufferedBinaryReader bSource = new BufferedBinaryReader(source.BaseStream); // Title = first 28 chars string title = StreamUtils.ReadNullTerminatedStringFixed(bSource, System.Text.Encoding.ASCII, 28); if (readTagParams.PrepareForWriting) { structureHelper.AddZone(0, 28, new byte[28] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, ZONE_TITLE); } tagData.IntegrateValue(TagData.TAG_FIELD_TITLE, title.Trim()); bSource.Seek(4, SeekOrigin.Current); nbOrders = bSource.ReadUInt16(); nbInstruments = bSource.ReadUInt16(); nbPatterns = bSource.ReadUInt16(); flags = bSource.ReadUInt16(); trackerVersion = bSource.ReadUInt16(); trackerName = getTrackerName(trackerVersion); bSource.Seek(2, SeekOrigin.Current); // sampleType (16b) if (!S3M_SIGNATURE.Equals(Utils.Latin1Encoding.GetString(bSource.ReadBytes(4)))) { result = false; throw new Exception("Invalid S3M file (file signature mismatch)"); } bSource.Seek(1, SeekOrigin.Current); // globalVolume (8b) tagExists = true; initialSpeed = bSource.ReadByte(); initialTempo = bSource.ReadByte(); bSource.Seek(1, SeekOrigin.Current); // masterVolume (8b) bSource.Seek(1, SeekOrigin.Current); // ultraClickRemoval (8b) bSource.Seek(1, SeekOrigin.Current); // defaultPan (8b) bSource.Seek(8, SeekOrigin.Current); // defaultPan (64b) bSource.Seek(2, SeekOrigin.Current); // ptrSpecial (16b) // Channel table for (int i = 0; i < 32; i++) { FChannelTable.Add(bSource.ReadByte()); if (FChannelTable[FChannelTable.Count - 1] < 30) { nbChannels++; } } // Pattern table for (int i = 0; i < nbOrders; i++) { FPatternTable.Add(bSource.ReadByte()); } // Instruments pointers for (int i = 0; i < nbInstruments; i++) { instrumentPointers.Add(bSource.ReadUInt16()); } // Patterns pointers for (int i = 0; i < nbPatterns; i++) { patternPointers.Add(bSource.ReadUInt16()); } readInstruments(bSource, instrumentPointers); readPatterns(bSource, patternPointers); // == Computing track properties duration = calculateDuration() * 1000.0; foreach (Instrument i in FInstruments) { string displayName = i.DisplayName.Trim(); if (displayName.Length > 0) { comment.Append(displayName).Append(Settings.InternalValueSeparator); } } if (comment.Length > 0) { comment.Remove(comment.Length - 1, 1); } tagData.IntegrateValue(TagData.TAG_FIELD_COMMENT, comment.ToString()); bitrate = sizeInfo.FileSize / duration; return(result); }
public bool Read(BinaryReader source, SizeInfo sizeInfo, MetaDataIO.ReadTagParams readTagParams) { uint signatureChunk; ushort aWord; byte[] specDTS; bool result = false; this.sizeInfo = sizeInfo; resetData(); signatureChunk = source.ReadUInt32(); if (/*0x7FFE8001*/ 25230975 == signatureChunk) { source.BaseStream.Seek(3, SeekOrigin.Current); specDTS = source.ReadBytes(8); isValid = true; aWord = (ushort)(specDTS[1] | (specDTS[0] << 8)); switch ((aWord & 0x0FC0) >> 6) { case 0: channels = 1; break; case 1: case 2: case 3: case 4: channels = 2; break; case 5: case 6: channels = 3; break; case 7: case 8: channels = 4; break; case 9: channels = 5; break; case 10: case 11: case 12: channels = 6; break; case 13: channels = 7; break; case 14: case 15: channels = 8; break; default: channels = 0; break; } switch ((aWord & 0x3C) >> 2) { case 1: sampleRate = 8000; break; case 2: sampleRate = 16000; break; case 3: sampleRate = 32000; break; case 6: sampleRate = 11025; break; case 7: sampleRate = 22050; break; case 8: sampleRate = 44100; break; case 11: sampleRate = 12000; break; case 12: sampleRate = 24000; break; case 13: sampleRate = 48000; break; default: sampleRate = 0; break; } aWord = 0; aWord = (ushort)(specDTS[2] | (specDTS[1] << 8)); bitrate = (ushort)BITRATES[(aWord & 0x03E0) >> 5] * 1000; aWord = 0; aWord = (ushort)(specDTS[7] | (specDTS[6] << 8)); switch ((aWord & 0x01C0) >> 6) { case 0: case 1: bits = 16; break; case 2: case 3: bits = 20; break; case 4: case 5: bits = 24; break; default: bits = 16; break; } duration = sizeInfo.FileSize * 8.0 / bitrate; result = true; } return(result); }
public bool Read(BinaryReader source, SizeInfo sizeInfo, MetaDataIO.ReadTagParams readTagParams) { bool result = false; bool doLoop = true; long position; UInt16 readData16; UInt32 readData32; UInt32 metaType; UInt32 metaSize; long sampleCount = 0; int frameSizeType = -1; this.sizeInfo = sizeInfo; resetData(); source.BaseStream.Seek(sizeInfo.ID3v2Size, SeekOrigin.Begin); if (TAK_ID.Equals(Utils.Latin1Encoding.GetString(source.ReadBytes(4)))) { result = true; position = source.BaseStream.Position; source.BaseStream.Seek(position, SeekOrigin.Begin); do // Loop metadata { readData32 = source.ReadUInt32(); metaType = readData32 & 0x7F; metaSize = readData32 >> 8; position = source.BaseStream.Position; if (0 == metaType) { doLoop = false; // End of metadata } else if (0x01 == metaType) // Stream info { readData16 = source.ReadUInt16(); frameSizeType = readData16 & 0x003C; // bits 11 to 14 readData32 = source.ReadUInt32(); uint restOfData = source.ReadUInt32(); sampleCount = (readData16 >> 14) + (readData32 << 2) + ((restOfData & 0x00000080) << 34); sampleRate = ((restOfData >> 4) & 0x03ffff) + 6000; // bits 4 to 21 channelsArrangement = ChannelsArrangements.GuessFromChannelNumber((int)((restOfData >> 27) & 0x0F) + 1); // bits 28 to 31 if (sampleCount > 0) { duration = (double)sampleCount * 1000.0 / sampleRate; bitrate = Math.Round(((double)(sizeInfo.FileSize - source.BaseStream.Position)) * 8 / duration); //time to calculate average bitrate } } else if (0x04 == metaType) // Encoder info { readData32 = source.ReadUInt32(); formatVersion = 100 * ((readData32 & 0x00ff0000) >> 16); formatVersion += 10 * ((readData32 & 0x0000ff00) >> 8); formatVersion += (readData32 & 0x000000ff); } source.BaseStream.Seek(position + metaSize, SeekOrigin.Begin); } while (doLoop); // End of metadata loop } return(result); }
public Boolean Read(BinaryReader source, SizeInfo sizeInfo, MetaDataIO.ReadTagParams readTagParams) { this.sizeInfo = sizeInfo; var result = false; resetData(); source.BaseStream.Seek(0, SeekOrigin.Begin); if (DSD_ID.Equals(Utils.Latin1Encoding.GetString(source.ReadBytes(4)))) { source.BaseStream.Seek(16, SeekOrigin.Current); // Chunk size and file size id3v2Offset = source.ReadInt64(); if (FMT_ID.Equals(Utils.Latin1Encoding.GetString(source.ReadBytes(4)))) { source.BaseStream.Seek(8, SeekOrigin.Current); // Chunk size formatVersion = source.ReadInt32(); if (formatVersion > 1) { LogDelegator.GetLogDelegate()(Log.LV_ERROR, "DSF format version " + formatVersion + " not supported"); return(result); } isValid = true; source.BaseStream.Seek(8, SeekOrigin.Current); // Format ID (4), Channel type (4) channels = source.ReadUInt32(); sampleRate = source.ReadUInt32(); bits = source.ReadUInt32(); var sampleCount = source.ReadUInt64(); duration = (Double)sampleCount * 1000.0 / sampleRate; bitrate = Math.Round(((Double)(sizeInfo.FileSize - source.BaseStream.Position)) * 8 / duration); //time to calculate average bitrate result = true; } // Load tag if exists if (id3v2Offset > 0) { if (readTagParams.PrepareForWriting) { id3v2StructureHelper.AddZone(id3v2Offset, (Int32)(source.BaseStream.Length - id3v2Offset)); id3v2StructureHelper.AddSize(12, source.BaseStream.Length); id3v2StructureHelper.AddIndex(20, id3v2Offset); } } else { id3v2Offset = 0; // Switch status to "tried to read, but nothing found" if (readTagParams.PrepareForWriting) { // Add EOF zone for future tag writing id3v2StructureHelper.AddZone(source.BaseStream.Length, 0); id3v2StructureHelper.AddSize(12, source.BaseStream.Length); id3v2StructureHelper.AddIndex(20, source.BaseStream.Length); } } } return(result); }
private void readHeaderExtended(BinaryReader source, long sizePosition1, ulong size1, long sizePosition2, ulong size2, MetaDataIO.ReadTagParams readTagParams) { byte[] headerExtensionObjectId; ulong headerExtensionObjectSize = 0; long position, framePosition, sizePosition3, dataPosition; ulong limit; ushort streamNumber, languageIndex; source.BaseStream.Seek(16, SeekOrigin.Current); // Reserved field 1 source.BaseStream.Seek(2, SeekOrigin.Current); // Reserved field 2 sizePosition3 = source.BaseStream.Position; uint headerExtendedSize = source.ReadUInt32(); // Size of actual data // Looping through header extension objects position = source.BaseStream.Position; limit = (ulong)position + headerExtendedSize; while ((ulong)position < limit) { framePosition = source.BaseStream.Position; headerExtensionObjectId = source.ReadBytes(16); headerExtensionObjectSize = source.ReadUInt64(); // Additional metadata (Optional frames) if (StreamUtils.ArrEqualsArr(WMA_METADATA_OBJECT_ID, headerExtensionObjectId) || StreamUtils.ArrEqualsArr(WMA_METADATA_LIBRARY_OBJECT_ID, headerExtensionObjectId)) { ushort nameSize; // Length (in bytes) of Name field ushort fieldDataType; // Type of data stored in current field int fieldDataSize; // Size of data stored in current field string fieldName; // Name of current field ushort nbObjects = source.ReadUInt16(); bool isLibraryObject = StreamUtils.ArrEqualsArr(WMA_METADATA_LIBRARY_OBJECT_ID, headerExtensionObjectId); string zoneCode = isLibraryObject ? ZONE_EXTENDED_HEADER_METADATA_LIBRARY : ZONE_EXTENDED_HEADER_METADATA; structureHelper.AddZone(framePosition, (int)headerExtensionObjectSize, zoneCode); // Store frame information for future editing, since current frame is optional if (readTagParams.PrepareForWriting) { structureHelper.AddSize(sizePosition1, size1, zoneCode); structureHelper.AddSize(sizePosition2, size2, zoneCode); structureHelper.AddSize(sizePosition3, headerExtendedSize, zoneCode); } for (int i = 0; i < nbObjects; i++) { languageIndex = source.ReadUInt16(); streamNumber = source.ReadUInt16(); nameSize = source.ReadUInt16(); fieldDataType = source.ReadUInt16(); fieldDataSize = source.ReadInt32(); fieldName = Utils.StripEndingZeroChars(Encoding.Unicode.GetString(source.ReadBytes(nameSize))); dataPosition = source.BaseStream.Position; readTagField(source, zoneCode, fieldName, fieldDataType, fieldDataSize, readTagParams, true, languageIndex, streamNumber); source.BaseStream.Seek(dataPosition + fieldDataSize, SeekOrigin.Begin); } } source.BaseStream.Seek(position + (long)headerExtensionObjectSize, SeekOrigin.Begin); position = source.BaseStream.Position; } // Add absent zone definitions for further editing if (readTagParams.PrepareForWriting) { if (!structureHelper.ZoneNames.Contains(ZONE_EXTENDED_HEADER_METADATA)) { structureHelper.AddZone(source.BaseStream.Position, 0, ZONE_EXTENDED_HEADER_METADATA); structureHelper.AddSize(sizePosition1, size1, ZONE_EXTENDED_HEADER_METADATA); structureHelper.AddSize(sizePosition2, size2, ZONE_EXTENDED_HEADER_METADATA); structureHelper.AddSize(sizePosition3, headerExtendedSize, ZONE_EXTENDED_HEADER_METADATA); } if (!structureHelper.ZoneNames.Contains(ZONE_EXTENDED_HEADER_METADATA_LIBRARY)) { structureHelper.AddZone(source.BaseStream.Position, 0, ZONE_EXTENDED_HEADER_METADATA_LIBRARY); structureHelper.AddSize(sizePosition1, size1, ZONE_EXTENDED_HEADER_METADATA_LIBRARY); structureHelper.AddSize(sizePosition2, size2, ZONE_EXTENDED_HEADER_METADATA_LIBRARY); structureHelper.AddSize(sizePosition3, headerExtendedSize, ZONE_EXTENDED_HEADER_METADATA_LIBRARY); } } }
public Boolean Read(BinaryReader source, SizeInfo sizeInfo, MetaDataIO.ReadTagParams readTagParams) { this.sizeInfo = sizeInfo; return(read(source, readTagParams)); }
// ---------- SUPPORT METHODS /* Unused for now * private double getCompressionRatio() * { * // Get compression ratio * if (isValid) * return (double)sizeInfo.FileSize / ((duration * sampleRate) * (channels * bits / 8) + 44) * 100; * else * return 0; * } */ public bool Read(BinaryReader source, SizeInfo sizeInfo, MetaDataIO.ReadTagParams readTagParams) { ushort signatureChunk; byte aByte; this.sizeInfo = sizeInfo; resetData(); bool result = false; source.BaseStream.Seek(0, SeekOrigin.Begin); signatureChunk = source.ReadUInt16(); if (30475 == signatureChunk) { aByte = 0; source.BaseStream.Seek(2, SeekOrigin.Current); aByte = source.ReadByte(); switch (aByte & 0xC0) { case 0: sampleRate = 48000; break; case 0x40: sampleRate = 44100; break; case 0x80: sampleRate = 32000; break; default: sampleRate = 0; break; } bitrate = BITRATES[(aByte & 0x3F) >> 1]; aByte = 0; source.BaseStream.Seek(1, SeekOrigin.Current); aByte = source.ReadByte(); switch (aByte & 0xE0) { case 0: channelsArrangement = DUAL_MONO; break; case 0x20: channelsArrangement = MONO; break; case 0x40: channelsArrangement = STEREO; break; case 0x60: channelsArrangement = ISO_3_0_0; break; case 0x80: channelsArrangement = ISO_2_1_0; break; case 0xA0: channelsArrangement = ISO_3_1_0; break; case 0xC0: channelsArrangement = ISO_2_2_0; break; case 0xE0: channelsArrangement = ISO_3_2_0; break; default: channelsArrangement = UNKNOWN; break; } // bits = 16; duration = sizeInfo.FileSize * 8.0 / bitrate; result = true; } return(result); }
protected override bool read(BinaryReader source, MetaDataIO.ReadTagParams readTagParams) { bool result = false; long position; resetData(); source.BaseStream.Seek(0, SeekOrigin.Begin); if (AIFF_CONTAINER_ID.Equals(Utils.Latin1Encoding.GetString(source.ReadBytes(4)))) { // Container chunk size long containerChunkPos = source.BaseStream.Position; int containerChunkSize = StreamUtils.DecodeBEInt32(source.ReadBytes(4)); if (containerChunkPos + containerChunkSize + 4 != source.BaseStream.Length) { LogDelegator.GetLogDelegate()(Log.LV_WARNING, "Header size is incoherent with file size"); } // Form type format = Utils.Latin1Encoding.GetString(source.ReadBytes(4)); if (format.Equals(FORMTYPE_AIFF) || format.Equals(FORMTYPE_AIFC)) { isValid = true; StringBuilder commentStr = new StringBuilder(""); long soundChunkPosition = 0; long soundChunkSize = 0; // Header size included bool nameFound = false; bool authorFound = false; bool copyrightFound = false; bool commentsFound = false; long limit = Math.Min(containerChunkPos + containerChunkSize + 4, source.BaseStream.Length); int annotationIndex = 0; int commentIndex = 0; while (source.BaseStream.Position < limit) { ChunkHeader header = seekNextChunkHeader(source, limit); position = source.BaseStream.Position; if (header.ID.Equals(CHUNKTYPE_COMMON)) { short channels = StreamUtils.DecodeBEInt16(source.ReadBytes(2)); switch (channels) { case 1: channelsArrangement = MONO; break; case 2: channelsArrangement = STEREO; break; case 3: channelsArrangement = ISO_3_0_0; break; case 4: channelsArrangement = ISO_2_2_0; break; // Specs actually allow both 2/2.0 and LRCS case 6: channelsArrangement = LRLcRcCS; break; default: channelsArrangement = UNKNOWN; break; } numSampleFrames = StreamUtils.DecodeBEUInt32(source.ReadBytes(4)); sampleSize = (uint)StreamUtils.DecodeBEInt16(source.ReadBytes(2)); // This sample size is for uncompressed data only byte[] byteArray = source.ReadBytes(10); Array.Reverse(byteArray); double aSampleRate = StreamUtils.ExtendedToDouble(byteArray); if (format.Equals(FORMTYPE_AIFC)) { compression = Utils.Latin1Encoding.GetString(source.ReadBytes(4)); } else // AIFF <=> no compression { compression = COMPRESSION_NONE; } if (aSampleRate > 0) { sampleRate = (int)Math.Round(aSampleRate); duration = (double)numSampleFrames * 1000.0 / sampleRate; if (!compression.Equals(COMPRESSION_NONE)) // Sample size is specific to selected compression method { if (compression.ToLower().Equals("fl32")) { sampleSize = 32; } else if (compression.ToLower().Equals("fl64")) { sampleSize = 64; } else if (compression.ToLower().Equals("alaw")) { sampleSize = 8; } else if (compression.ToLower().Equals("ulaw")) { sampleSize = 8; } } if (duration > 0) { bitrate = sampleSize * numSampleFrames * channelsArrangement.NbChannels / duration; } } } else if (header.ID.Equals(CHUNKTYPE_SOUND)) { soundChunkPosition = source.BaseStream.Position - 8; soundChunkSize = header.Size + 8; } else if (header.ID.Equals(CHUNKTYPE_NAME) || header.ID.Equals(CHUNKTYPE_AUTHOR) || header.ID.Equals(CHUNKTYPE_COPYRIGHT)) { structureHelper.AddZone(source.BaseStream.Position - 8, header.Size + 8, header.ID); structureHelper.AddSize(containerChunkPos, containerChunkSize, header.ID); tagExists = true; if (header.ID.Equals(CHUNKTYPE_NAME)) { nameFound = true; } if (header.ID.Equals(CHUNKTYPE_AUTHOR)) { authorFound = true; } if (header.ID.Equals(CHUNKTYPE_COPYRIGHT)) { copyrightFound = true; } SetMetaField(header.ID, Utils.Latin1Encoding.GetString(source.ReadBytes(header.Size)), readTagParams.ReadAllMetaFrames); } else if (header.ID.Equals(CHUNKTYPE_ANNOTATION)) { annotationIndex++; structureHelper.AddZone(source.BaseStream.Position - 8, header.Size + 8, header.ID + annotationIndex); structureHelper.AddSize(containerChunkPos, containerChunkSize, header.ID + annotationIndex); if (commentStr.Length > 0) { commentStr.Append(Settings.InternalValueSeparator); } commentStr.Append(Utils.Latin1Encoding.GetString(source.ReadBytes(header.Size))); tagExists = true; } else if (header.ID.Equals(CHUNKTYPE_COMMENTS)) { commentIndex++; structureHelper.AddZone(source.BaseStream.Position - 8, header.Size + 8, header.ID + commentIndex); structureHelper.AddSize(containerChunkPos, containerChunkSize, header.ID + commentIndex); tagExists = true; commentsFound = true; ushort numComs = StreamUtils.DecodeBEUInt16(source.ReadBytes(2)); for (int i = 0; i < numComs; i++) { CommentData cmtData = new CommentData(); cmtData.Timestamp = StreamUtils.DecodeBEUInt32(source.ReadBytes(4)); cmtData.MarkerId = StreamUtils.DecodeBEInt16(source.ReadBytes(2)); // Comments length ushort comLength = StreamUtils.DecodeBEUInt16(source.ReadBytes(2)); MetaFieldInfo comment = new MetaFieldInfo(getImplementedTagType(), header.ID + commentIndex); comment.Value = Utils.Latin1Encoding.GetString(source.ReadBytes(comLength)); comment.SpecificData = cmtData; tagData.AdditionalFields.Add(comment); // Only read general purpose comments, not those linked to a marker if (0 == cmtData.MarkerId) { if (commentStr.Length > 0) { commentStr.Append(Settings.InternalValueSeparator); } commentStr.Append(comment.Value); } } } else if (header.ID.Equals(CHUNKTYPE_ID3TAG)) { id3v2Offset = source.BaseStream.Position; // Zone is already added by Id3v2.Read id3v2StructureHelper.AddZone(id3v2Offset - 8, header.Size + 8, CHUNKTYPE_ID3TAG); id3v2StructureHelper.AddSize(containerChunkPos, containerChunkSize, CHUNKTYPE_ID3TAG); } source.BaseStream.Position = position + header.Size; if (header.ID.Equals(CHUNKTYPE_SOUND) && header.Size % 2 > 0) { source.BaseStream.Position += 1; // Sound chunk size must be even } } tagData.IntegrateValue(TagData.TAG_FIELD_COMMENT, commentStr.ToString().Replace("\0", " ").Trim()); if (-1 == id3v2Offset) { id3v2Offset = 0; // Switch status to "tried to read, but nothing found" if (readTagParams.PrepareForWriting) { id3v2StructureHelper.AddZone(soundChunkPosition + soundChunkSize, 0, CHUNKTYPE_ID3TAG); id3v2StructureHelper.AddSize(containerChunkPos, containerChunkSize, CHUNKTYPE_ID3TAG); } } // Add zone placeholders for future tag writing if (readTagParams.PrepareForWriting) { if (!nameFound) { structureHelper.AddZone(soundChunkPosition, 0, CHUNKTYPE_NAME); structureHelper.AddSize(containerChunkPos, containerChunkSize, CHUNKTYPE_NAME); } if (!authorFound) { structureHelper.AddZone(soundChunkPosition, 0, CHUNKTYPE_AUTHOR); structureHelper.AddSize(containerChunkPos, containerChunkSize, CHUNKTYPE_AUTHOR); } if (!copyrightFound) { structureHelper.AddZone(soundChunkPosition, 0, CHUNKTYPE_COPYRIGHT); structureHelper.AddSize(containerChunkPos, containerChunkSize, CHUNKTYPE_COPYRIGHT); } if (!commentsFound) { structureHelper.AddZone(soundChunkPosition, 0, CHUNKTYPE_COMMENTS); structureHelper.AddSize(containerChunkPos, containerChunkSize, CHUNKTYPE_COMMENTS); } } result = true; } } return(result); }
public bool Read(BinaryReader source, SizeInfo sizeInfo, MetaDataIO.ReadTagParams readTagParams) { uint signatureChunk; ushort aWord; byte[] specDTS; bool result = false; this.sizeInfo = sizeInfo; resetData(); signatureChunk = source.ReadUInt32(); if (/*0x7FFE8001*/ 25230975 == signatureChunk) { AudioDataOffset = source.BaseStream.Position - 4; AudioDataSize = sizeInfo.FileSize - sizeInfo.APESize - sizeInfo.ID3v1Size - AudioDataOffset; source.BaseStream.Seek(3, SeekOrigin.Current); specDTS = source.ReadBytes(8); isValid = true; aWord = (ushort)(specDTS[1] | (specDTS[0] << 8)); switch ((aWord & 0x0FC0) >> 6) { case 0: channelsArrangement = MONO; break; case 1: channelsArrangement = DUAL_MONO; break; case 2: channelsArrangement = STEREO; break; case 3: channelsArrangement = STEREO_SUM_DIFFERENCE; break; case 4: channelsArrangement = STEREO_LEFT_RIGHT_TOTAL; break; case 5: channelsArrangement = ISO_3_0_0; break; case 6: channelsArrangement = ISO_2_1_0; break; case 7: channelsArrangement = LRCS; break; case 8: channelsArrangement = QUAD; break; case 9: channelsArrangement = ISO_3_2_0; break; case 10: channelsArrangement = CLCRLRSLSR; break; case 11: channelsArrangement = CLRLRRRO; break; case 12: channelsArrangement = CFCRLFRFLRRR; break; case 13: channelsArrangement = CLCCRLRSLSR; break; case 14: channelsArrangement = CLCRLRSL1SL2SR1SR2; break; case 15: channelsArrangement = CLCCRLRSLSSR; break; default: channelsArrangement = UNKNOWN; break; } switch ((aWord & 0x3C) >> 2) { case 1: sampleRate = 8000; break; case 2: sampleRate = 16000; break; case 3: sampleRate = 32000; break; case 6: sampleRate = 11025; break; case 7: sampleRate = 22050; break; case 8: sampleRate = 44100; break; case 11: sampleRate = 12000; break; case 12: sampleRate = 24000; break; case 13: sampleRate = 48000; break; default: sampleRate = 0; break; } aWord = (ushort)(specDTS[2] | (specDTS[1] << 8)); bitrate = (ushort)BITRATES[(aWord & 0x03E0) >> 5]; aWord = (ushort)(specDTS[7] | (specDTS[6] << 8)); switch ((aWord & 0x01C0) >> 6) { case 0: case 1: bits = 16; break; case 2: case 3: bits = 20; break; case 4: case 5: bits = 24; break; default: bits = 16; break; } duration = sizeInfo.FileSize * 8.0 / bitrate; result = true; } return(result); }
/// <inheritdoc/> public bool Read(BinaryReader source, MetaDataIO.ReadTagParams readTagParams) { throw new NotImplementedException(); }
protected override bool read(BinaryReader source, MetaDataIO.ReadTagParams readTagParams) { bool result = true; ushort nbOrders = 0; ushort nbPatterns = 0; ushort nbSamples = 0; ushort nbInstruments = 0; ushort flags; ushort special; ushort trackerVersion; ushort trackerVersionCompatibility; bool useSamplesAsInstruments = false; ushort messageLength; uint messageOffset; String message = ""; IList <UInt32> patternPointers = new List <UInt32>(); IList <UInt32> instrumentPointers = new List <UInt32>(); IList <UInt32> samplePointers = new List <UInt32>(); resetData(); BufferedBinaryReader bSource = new BufferedBinaryReader(source.BaseStream); if (!IT_SIGNATURE.Equals(Utils.Latin1Encoding.GetString(bSource.ReadBytes(4)))) { result = false; throw new Exception(sizeInfo.FileSize + " : Invalid IT file (file signature mismatch)"); // TODO - might be a compressed file -> PK header } tagExists = true; // Title = max first 26 chars after file signature; null-terminated string title = StreamUtils.ReadNullTerminatedStringFixed(bSource, Utils.Latin1Encoding, 26); if (readTagParams.PrepareForWriting) { structureHelper.AddZone(4, 26, new byte[26] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, ZONE_TITLE); } tagData.IntegrateValue(TagData.TAG_FIELD_TITLE, title.Trim()); bSource.Seek(2, SeekOrigin.Current); // Pattern row highlight information nbOrders = bSource.ReadUInt16(); nbInstruments = bSource.ReadUInt16(); nbSamples = bSource.ReadUInt16(); nbPatterns = bSource.ReadUInt16(); trackerVersion = bSource.ReadUInt16(); trackerVersionCompatibility = bSource.ReadUInt16(); flags = bSource.ReadUInt16(); useSamplesAsInstruments = !((flags & 0x04) > 0); special = bSource.ReadUInt16(); // trackerName = "Impulse tracker"; // TODO use TrackerVersion to add version bSource.Seek(2, SeekOrigin.Current); // globalVolume (8b), masterVolume (8b) initialSpeed = bSource.ReadByte(); initialTempo = bSource.ReadByte(); bSource.Seek(2, SeekOrigin.Current); // panningSeparation (8b), pitchWheelDepth (8b) messageLength = bSource.ReadUInt16(); messageOffset = bSource.ReadUInt32(); bSource.Seek(132, SeekOrigin.Current); // reserved (32b), channel Pan (64B), channel Vol (64B) // Orders table for (int i = 0; i < nbOrders; i++) { patternTable.Add(bSource.ReadByte()); } // Instruments pointers for (int i = 0; i < nbInstruments; i++) { instrumentPointers.Add(bSource.ReadUInt32()); } // Samples pointers for (int i = 0; i < nbSamples; i++) { samplePointers.Add(bSource.ReadUInt32()); } // Patterns pointers for (int i = 0; i < nbPatterns; i++) { patternPointers.Add(bSource.ReadUInt32()); } if ((!useSamplesAsInstruments) && (instrumentPointers.Count > 0)) { if (trackerVersionCompatibility < 0x200) { readInstrumentsOld(bSource, instrumentPointers); } else { readInstruments(bSource, instrumentPointers); } } else { readSamples(bSource, samplePointers); } readPatterns(bSource, patternPointers); // IT Message if ((special & 0x1) > 0) { bSource.Seek(messageOffset, SeekOrigin.Begin); //message = new String( StreamUtils.ReadOneByteChars(source, messageLength) ); message = StreamUtils.ReadNullTerminatedStringFixed(bSource, Utils.Latin1Encoding, messageLength); } // == Computing track properties duration = calculateDuration() * 1000.0; string commentStr; if (messageLength > 0) // Get Comment from the "IT message" field { commentStr = message; } else // Get Comment from all the instrument names (common practice in the tracker community) { StringBuilder comment = new StringBuilder(""); // NB : Whatever the value of useSamplesAsInstruments, FInstruments contain the right data foreach (Instrument i in instruments) { if (i.DisplayName.Length > 0) { comment.Append(i.DisplayName).Append(Settings.InternalValueSeparator); } } if (comment.Length > 0) { comment.Remove(comment.Length - 1, 1); } commentStr = comment.ToString(); } tagData.IntegrateValue(TagData.TAG_FIELD_COMMENT, commentStr); bitrate = (double)sizeInfo.FileSize / duration; return(result); }
public bool Read(BinaryReader source, AudioDataManager.SizeInfo sizeInfo, MetaDataIO.ReadTagParams readTagParams) { this.sizeInfo = sizeInfo; bool result = false; resetData(); source.BaseStream.Seek(0, SeekOrigin.Begin); if (DSD_ID.Equals(Utils.Latin1Encoding.GetString(source.ReadBytes(4)))) { source.BaseStream.Seek(16, SeekOrigin.Current); // Chunk size and file size id3v2Offset = source.ReadInt64(); if (FMT_ID.Equals(Utils.Latin1Encoding.GetString(source.ReadBytes(4)))) { source.BaseStream.Seek(8, SeekOrigin.Current); // Chunk size formatVersion = source.ReadInt32(); if (formatVersion > 1) { LogDelegator.GetLogDelegate()(Log.LV_ERROR, "DSF format version " + formatVersion + " not supported"); return(result); } isValid = true; source.BaseStream.Seek(8, SeekOrigin.Current); // Format ID (4), Channel type (4) uint channels = source.ReadUInt32(); switch (channels) { case 1: channelsArrangement = MONO; break; case 2: channelsArrangement = STEREO; break; case 3: channelsArrangement = ISO_3_0_0; break; case 4: channelsArrangement = QUAD; break; case 5: channelsArrangement = LRCLFE; break; case 6: channelsArrangement = ISO_3_2_0; break; case 7: channelsArrangement = ISO_3_2_1; break; default: channelsArrangement = UNKNOWN; break; } sampleRate = source.ReadUInt32(); bits = source.ReadUInt32(); ulong sampleCount = source.ReadUInt64(); duration = (double)sampleCount * 1000.0 / sampleRate; bitrate = Math.Round(((double)(sizeInfo.FileSize - source.BaseStream.Position)) * 8 / duration); //time to calculate average bitrate result = true; } // Load tag if exists if (id3v2Offset > 0) { if (readTagParams.PrepareForWriting) { id3v2StructureHelper.AddZone(id3v2Offset, (int)(source.BaseStream.Length - id3v2Offset)); id3v2StructureHelper.AddSize(12, source.BaseStream.Length); id3v2StructureHelper.AddIndex(20, id3v2Offset); } } else { id3v2Offset = 0; // Switch status to "tried to read, but nothing found" if (readTagParams.PrepareForWriting) { // Add EOF zone for future tag writing id3v2StructureHelper.AddZone(source.BaseStream.Length, 0); id3v2StructureHelper.AddSize(12, source.BaseStream.Length); id3v2StructureHelper.AddIndex(20, source.BaseStream.Length); } } } return(result); }
/// <inheritdoc/> protected override bool read(BinaryReader source, MetaDataIO.ReadTagParams readTagParams) { byte[] header; string trigger; IList <MidiTrack> tracks = new List <MidiTrack>(); resetData(); // Ignores everything (comments) written before the MIDI header StreamUtils.FindSequence(source.BaseStream, Utils.Latin1Encoding.GetBytes(MIDI_FILE_HEADER)); // Ready to read header data... header = source.ReadBytes(10); if ((header[0] != 0) || (header[1] != 0) || (header[2] != 0) || (header[3] != 6) ) { Logging.LogDelegator.GetLogDelegate()(Log.LV_ERROR, "Wrong MIDI header"); return(false); } type = header[5]; // MIDI STRUCTURE TYPE // 0 - single-track // 1 - multiple tracks, synchronous // 2 - multiple tracks, asynchronous if (type > 1) { Logging.LogDelegator.GetLogDelegate()(Log.LV_WARNING, "SMF type 2 MIDI files are partially supported; results may be approximate"); } tagExists = true; timebase = (header[8] << 8) + header[9]; tempo = 0; // maybe (hopefully!) overwritten by parseTrack int trackSize; int nbTrack = 0; comment = new StringBuilder(""); AudioDataOffset = source.BaseStream.Position; AudioDataSize = sizeInfo.FileSize - AudioDataOffset; // Ready to read track data... while (source.BaseStream.Position < sizeInfo.FileSize - 4) { trigger = Utils.Latin1Encoding.GetString(source.ReadBytes(4)); if (trigger != MIDI_TRACK_HEADER) { source.BaseStream.Seek(-3, SeekOrigin.Current); if (!StreamUtils.FindSequence(source.BaseStream, Utils.Latin1Encoding.GetBytes(MIDI_TRACK_HEADER))) { break; } } // trackSize is stored in big endian -> needs inverting trackSize = StreamUtils.DecodeBEInt32(source.ReadBytes(4)); tracks.Add(parseTrack(source.ReadBytes(trackSize), nbTrack)); nbTrack++; } this.tracks = tracks; if (comment.Length > 0) { comment.Remove(comment.Length - 1, 1); } tagData.IntegrateValue(TagData.TAG_FIELD_COMMENT, comment.ToString()); duration = getDuration(); bitrate = (double)sizeInfo.FileSize / duration; return(true); }
public bool Read(BinaryReader source, SizeInfo sizeInfo, MetaDataIO.ReadTagParams readTagParams) { ApeHeaderOld APE_OLD = new ApeHeaderOld(); // old header <= 3.97 ApeHeaderNew APE_NEW = new ApeHeaderNew(); // new header >= 3.98 ApeDescriptor APE_DESC = new ApeDescriptor(); // extra header >= 3.98 int BlocksPerFrame; bool LoadSuccess; bool result = false; this.sizeInfo = sizeInfo; resetData(); // Read data from file readCommonHeader(source); if (StreamUtils.StringEqualsArr("MAC ", header.cID)) { isValid = true; version = header.nVersion; AudioDataOffset = source.BaseStream.Position - 6; AudioDataSize = sizeInfo.FileSize - sizeInfo.APESize - sizeInfo.ID3v1Size - AudioDataOffset; versionStr = ((double)version / 1000).ToString().Substring(0, 4); //Str(FVersion / 1000 : 4 : 2, FVersionStr); // Load New Monkey's Audio Header for version >= 3.98 if (header.nVersion >= 3980) { APE_DESC.padded = 0; APE_DESC.nDescriptorBytes = 0; APE_DESC.nHeaderBytes = 0; APE_DESC.nSeekTableBytes = 0; APE_DESC.nHeaderDataBytes = 0; APE_DESC.nAPEFrameDataBytes = 0; APE_DESC.nAPEFrameDataBytesHigh = 0; APE_DESC.nTerminatingDataBytes = 0; Array.Clear(APE_DESC.cFileMD5, 0, APE_DESC.cFileMD5.Length); APE_DESC.padded = source.ReadUInt16(); APE_DESC.nDescriptorBytes = source.ReadUInt32(); APE_DESC.nHeaderBytes = source.ReadUInt32(); APE_DESC.nSeekTableBytes = source.ReadUInt32(); APE_DESC.nHeaderDataBytes = source.ReadUInt32(); APE_DESC.nAPEFrameDataBytes = source.ReadUInt32(); APE_DESC.nAPEFrameDataBytesHigh = source.ReadUInt32(); APE_DESC.nTerminatingDataBytes = source.ReadUInt32(); APE_DESC.cFileMD5 = source.ReadBytes(16); // seek past description header if (APE_DESC.nDescriptorBytes != 52) { source.BaseStream.Seek(APE_DESC.nDescriptorBytes - 52, SeekOrigin.Current); } // load new ape_header if (APE_DESC.nHeaderBytes > 24 /*sizeof(APE_NEW)*/) { APE_DESC.nHeaderBytes = 24 /*sizeof(APE_NEW)*/; } APE_NEW.nCompressionLevel = 0; APE_NEW.nFormatFlags = 0; APE_NEW.nBlocksPerFrame = 0; APE_NEW.nFinalFrameBlocks = 0; APE_NEW.nTotalFrames = 0; APE_NEW.nBitsPerSample = 0; APE_NEW.nChannels = 0; APE_NEW.nSampleRate = 0; APE_NEW.nCompressionLevel = source.ReadUInt16(); APE_NEW.nFormatFlags = source.ReadUInt16(); APE_NEW.nBlocksPerFrame = source.ReadUInt32(); APE_NEW.nFinalFrameBlocks = source.ReadUInt32(); APE_NEW.nTotalFrames = source.ReadUInt32(); APE_NEW.nBitsPerSample = source.ReadUInt16(); APE_NEW.nChannels = source.ReadUInt16(); APE_NEW.nSampleRate = source.ReadUInt32(); // based on MAC SDK 3.98a1 (APEinfo.h) sampleRate = (int)APE_NEW.nSampleRate; channelsArrangement = ChannelsArrangements.GuessFromChannelNumber(APE_NEW.nChannels); formatFlags = APE_NEW.nFormatFlags; bits = APE_NEW.nBitsPerSample; compressionMode = APE_NEW.nCompressionLevel; // calculate total uncompressed samples if (APE_NEW.nTotalFrames > 0) { totalSamples = (long)(APE_NEW.nBlocksPerFrame) * (long)(APE_NEW.nTotalFrames - 1) + (long)(APE_NEW.nFinalFrameBlocks); } LoadSuccess = true; } else { // Old Monkey <= 3.97 APE_OLD.nCompressionLevel = 0; APE_OLD.nFormatFlags = 0; APE_OLD.nChannels = 0; APE_OLD.nSampleRate = 0; APE_OLD.nHeaderBytes = 0; APE_OLD.nTerminatingBytes = 0; APE_OLD.nTotalFrames = 0; APE_OLD.nFinalFrameBlocks = 0; APE_OLD.nInt = 0; APE_OLD.nCompressionLevel = source.ReadUInt16(); APE_OLD.nFormatFlags = source.ReadUInt16(); APE_OLD.nChannels = source.ReadUInt16(); APE_OLD.nSampleRate = source.ReadUInt32(); APE_OLD.nHeaderBytes = source.ReadUInt32(); APE_OLD.nTerminatingBytes = source.ReadUInt32(); APE_OLD.nTotalFrames = source.ReadUInt32(); APE_OLD.nFinalFrameBlocks = source.ReadUInt32(); APE_OLD.nInt = source.ReadInt32(); compressionMode = APE_OLD.nCompressionLevel; sampleRate = (int)APE_OLD.nSampleRate; channelsArrangement = ChannelsArrangements.GuessFromChannelNumber(APE_OLD.nChannels); formatFlags = APE_OLD.nFormatFlags; bits = 16; if ((APE_OLD.nFormatFlags & MONKEY_FLAG_8_BIT) != 0) { bits = 8; } if ((APE_OLD.nFormatFlags & MONKEY_FLAG_24_BIT) != 0) { bits = 24; } hasSeekElements = ((APE_OLD.nFormatFlags & MONKEY_FLAG_PEAK_LEVEL) != 0); wavNotStored = ((APE_OLD.nFormatFlags & MONKEY_FLAG_SEEK_ELEMENTS) != 0); hasPeakLevel = ((APE_OLD.nFormatFlags & MONKEY_FLAG_WAV_NOT_STORED) != 0); if (hasPeakLevel) { peakLevel = (uint)APE_OLD.nInt; peakLevelRatio = (peakLevel / (1 << bits) / 2.0) * 100.0; } // based on MAC_SDK_397 (APEinfo.cpp) if (version >= 3950) { BlocksPerFrame = 73728 * 4; } else if ((version >= 3900) || ((version >= 3800) && (MONKEY_COMPRESSION_EXTRA_HIGH == APE_OLD.nCompressionLevel))) { BlocksPerFrame = 73728; } else { BlocksPerFrame = 9216; } // calculate total uncompressed samples if (APE_OLD.nTotalFrames > 0) { totalSamples = (APE_OLD.nTotalFrames - 1) * BlocksPerFrame + APE_OLD.nFinalFrameBlocks; } LoadSuccess = true; } if (LoadSuccess) { // compression profile name if ((0 == (compressionMode % 1000)) && (compressionMode <= 6000)) { compressionModeStr = MONKEY_COMPRESSION[compressionMode / 1000]; // int division } else { compressionModeStr = compressionMode.ToString(); } // length if (sampleRate > 0) { duration = totalSamples * 1000.0 / sampleRate; } // average bitrate if (duration > 0) { bitrate = 8 * (sizeInfo.FileSize - sizeInfo.TotalTagSize) / (duration); } // some extra sanity checks isValid = ((bits > 0) && (sampleRate > 0) && (totalSamples > 0) && (channelsArrangement.NbChannels > 0)); result = isValid; } } return(result); }