UltraID3Lib Release Notes

Date

Version

Notes

 27 Aug 2006

 0.9.5.10

·   Changed the duration calculations to be based on the actual number of total milliseconds instead of dropping the fractional portion of the total seconds.  (This behavior was intended to match that of WinAmp, but conflicted with Windows Media Player and other players that rounded the total seconds up to the nearest seconds.  The user can now decide how to determine the seconds, but rounding or truncating.)

·   Fixed bad format handling in ID3RecordingDayMonthFrame.

·   Fixed bug where extended header flag was left in after the extended header was removed.

·   Calculation of the Duration will now be based on the actual milliseconds and not a "Floor" of the milliseconds to get whole seconds.  It will then be up to the user of the library to round the milliseconds up (Round) or truncate them (Floor) to get whole seconds.

·   Added the ID3v23Tag.MinPaddingSizeBytes property.

·   Added the ID3v23Tag.MaxPaddingSizeBytes property.

·   Added the ID3v2PaddingSizeBytesRelationException class.

3 Aug 2006

0.9.5.9

·   Changed the GenreInfoCollection class ctor from Friend to Public.

·   Changed the LanguageInfoCollection class ctor from Friend to Public.  (The UltraID3 class already creates and instance of the GenreInfoCollection and the LanguageInfoCollection, so in theory a Public ctor is not needed, but in reality there are times when it's need in an area of the code which is removed from that which owns the instance of UltraID3.)

·   Added New() ctor to ID3ComposersFrame.

·   Added New(StringCollection) ctor to ID3ComposersFrame.

·   Corrected reference to incorrect class in documentation for ID3ComposersFrame.

·   Fixed bug where an empty ID3CommentsFrame was getting added when setting the ID3v23Tag.Comments to String.Empty when a Comments frame did not already exist.

·   Added code so that when a bad ID3 frame was encountered, the search for a valid MPEG frame started after the recorded tag length.  Thanks georgex79.

·   Added a ComposerCollection class.  (Implements IBindingList.)

·   Changed the ID3ComposersFrame.Composer from a StringCollection to a ComposerCollection.  It's still just a list of strings, but there is now validation to prevent the entry of a composer with a forward slash, which is a restricted character used in the internal encoding of the ID3 frame.

·   Added the ID3v2ComposerAlreadyExistsException class.

·   Added the ID3v2ComposerNameFormatException classes.

·   Updated the InvolvedPerson classes to more closely match the SynchronizedLyrics classes.

·   InvolvedPersonCollection now implements IBindingList.

·   SynchronizedLyricCollection now implements IBindingList.

18 Jul 2006

0.9.5.8

·   Fixed bug where writing Track Count was getting set to the Track Num value.

·   Added several documentation comments to public methods.

·   Changed the UltraID3Exception class ctorsfrom Public to Friend .

·   Changed the GenreInfo class ctor from Public to Friend.

·   Changed the GenreInfoCollection class ctor from Public to Friend.

·   Changed the ID3WebAddressFrame class ctor from Public to Friend.

·   Changed the LanguageInfo class ctor from Public to Friend.

·   Changed the LanguageInfoCollection class ctor from Public to Friend.

16 Jul 2006

0.9.5.7

·   Fixed bug which caused the tag/file size to increase unnecessarily when multiple writes occurred for a single read.  (Thanks again Mark F.)

9 Jul 2006

0.9.5.6

·   Fixed bug that caused padding to overwrite first frames of the first audio byte in cases where expanding the file length.  (Thanks Mark F.)

8 Jul 2006

0.9.5.5

·   Fixed bug in Composers frame which created larger than necessary frames.

·   Added a ID3v2ExtendedHeaderException to handle situations where the Extended Header bit was on, but there really wasn't an Extended Header.  Which caused the first four-character Frame ID to be read as the Extended Header length bytes, which would cause issues in almost all cases as the resultant size would be greater than the size of the file.

·   Renamed UltraID3v2CreateFrameActionNotSupportedException to ID3v2CreateFrameActionNotSupportedException (to match format of a previous change.)

·   Renamed UltraID3v2UnsupportedUnicodeByteOrderException to ID3v2UnsupportedUnicodeByteOrderException (to match format of a previous change.)

3 Jun 2006

0.9.5.4

·   Changed logic of ID3TextEncodingFrame to account for new format created WinAmp 5.2 which will create text frames that are empty all but for the Text Encoding Type byte.  From a strict reading this appears to be a valid frame, but why bother creating a frame in the first place if there's no data?

·   ID3v2EmptyFrameDataException

·   Renamed the SetNum and the SetCount properties of the ID3PartOfSetFrame class to PartNum and PartCount.  (The Num and the Count are references to the parts within the set, not the set as a whole.)

·   Renamed ID3v2SetNumSetCountRelationException to ID3v2PartNumPartCountRelationException

·   ID3v2SetNumFormatException

·   ID3v2SetCountFormatException

·   Changed the Item Function in the following classes Item to a ReadOnly Property: ID3FrameCollection, GenreInfoCollection, ID3MetaDataExceptionCollection, ID3TagExceptionCollection, InvolvedPersonCollection, LanguageInfoCollection, SynchronizedLyricCollection.

·   Added SynchronizedLyric.ToString

·   UltraID3.GetMPEGTrackInfo now closes the file before throwing the MPEGTrackInfoException.

·   Fixed ID3ComposersFrame.  The IsSet was True when there was a single blank Composer.  Updated ctor to eliminate blank values during the split of the text value.

·   The new version of WinAmp will create corrupt text frames.  They have a header, a text encoding byte, but no actual data bytes, not even the required null terminator for a blank value.  UltraID3Lib will now handle these corrupted frames created by WinAmp.

·   Converted the FrameCountSizeBytes, QualityRating and properties with Nullable versions and removed FrameCountExists, SizeBytesExists, QualityRatingExists properties

·   Changed VBRInfoFieldDoesNotExistException to VBRInfoToCDoesNotExistException

·   Added a GenreNum properth to the ID3InvalidGenreException class.

·   Renamed ID3v1Tag.ClearProperties to just Clear.

·   Renamed ID3v23Tag.ClearProperties to just Clear.

·   Added Clear method to UltraID3

·   Added Clear method to ITag.

·   Replaced ID3v23Tag.GetNewFrame with ID3FrameCollection.Add.  (I couldn't think of a situation where you wanted to create a new instance of a frame where you didn't add it to the collection.  Plus, you had to pass the TextEncoding into the GetNewFrame method even though many of the frame didn't have a TextEncoding.)

·   Added the ID3FrameCollection.SetTextEncoding method.

·   Fixed bug where empty Unicode string caused a false missing BOM exception.

·   Fixed MPEG Bitrate (V2 area) look-up table.

·   Updated license to allow for UltraID3Lib usage notation to be located in a user manual or instructions.

·   Added the ID3FieldValueFormatException.FieldValue property.

·   Added constructor for ID3PlayCounterFrame class which accepts a Counter argument.

29 Jan 2006

0.9.5.3

·   Fixed ID3GenreFrame.ToString.  (Included a Null Char in the string in some cases.)

·   Fixed bug in ID3GenreFrame which decoded frame Text twice, which would cause duplicate exceptions if there was an issue with the frame.

·   For classes inheriting from ID3TextFrame with a numeric value, created a ToString override that would not show quotes around the main value.

·   Changed the ID3FieldValueFormatException to a Warning instead of an Error.

·   Refined new code in the ID3GenreFrame to strip the numeric identifier in sections like "(17)Rock" (after I confirmed that WinAmp still uses the format.)

·   Added a ID3CompactDiscIdentifierFrame.MCDIFrameFormat to indicate whether the frame is in the standard ID3 format or the corrupted Windows Media Player format.  The format will be ID3Standard when ((FrameBytes.Length - 12) Mod 8) = 0.

·   Added a ID3CompactDiscIdentifierFrame.WindowsMediaPlayerCode to allow access to the Unicode string that Windows Media Player uses instead of the ID3 standard format.  This is an accommodation to the corruption of the ID3 standard by WMP, but in practical terms there are so many tracks out there with this invalid format that it does add value to give access to this string.  If the frame is in the proper format, this property will be a garbage string.

·   Changed format of ID3CompactDiscIdentifierFrame.ToString to show the WindowsMediaPlayerCode when the Windows Media Player version of the format is being used.

·   Found version of NDoc that works with Fx 2.0 and compiled a new Help file after doing several updates.  (The one problem is that it can't handle generics, so many of the property types don't show up.  But...I though that this was better than showing the 1.1 version of the Help file.)

·   Altered ID3RelativeVolumeAdjustmentFrame to add a ID3v2UnsupportedRelativeVolumeAdjustmentFormatException to the Exceptions collection rather than throwing it.

·   Changed the ID3v2UnsupportedRelativeVolumeAdjustmentFormatException to inherit from ID3v2InvalidFrameDataException instead of ID3v2FrameException.

·   Added a InvolvedPerson.IsSet property.

·   Changed ID3InvolvedPeopleListFrame.IsSet property to account for not set InvolvedPerson items.

·   Trimmed text frames which contained numeric values so as to avoid warnings about improperly formatted values.

16 Jan 2006

0.9.5.2

·   Fixed bug which improperly set the Tag Length field in the ID3 v2.3 Tag header.  Tag Length was omitting the padding, which had no effect on all tested ID3 editor applications, but because of a weird bug in WinAmp, it would drop the last frame of the ID3 v2.3 Tag.  (The WinAmp bug occurs when there isn't a padding section at least six bytes long.  The padding section is optional, so WinAmp should be able to handle a tag with no padding.  Incidentally, iTunes doesn't add any padding when creating a new ID3 v2.3 tag either, so WinAmp had the same issue with reading iTunes tags.)

·   Fixed bug where setting ID3v23Tag.WriteFlag to False would also not write the ID3v1Tag.  (I know I tested for this at some point, but because I never save just the v1 tag during normal use, I didn't notice when the bug crept in.)

·   Updated ID3GenreFrame to handle the way that ID3-TagIT implements multiple genres.  Given the ambiguous and contradictory nature of the TCON section of the ID3v2.3 spec, ID3-TagIT apparently chose to implement the (better-worded) ID3v2.4 TCON standard in ID3v2.3 tags.  Given the that this spec included the use of NullChars, I had to handle this format or else the Genre text would appear cut-off.  I haven't yet decided whether to fully implement this format for multiple Genres.  Before I accept this apparent deviation from the ID3v2.3 standard, I have a couple of outstanding questions to answer.  More later.

·   Increased the ID3v23 TrackNum from Byte to Short.  Properties changed: UltraID3Lib.TrackNum, ID3TrackNumFrame.TrackNum, ID3TrackNumFrame.TrackCount.  This change required dropping the TrackNum from the ITag interface because the ID3v1.TrackNum property can only be a Byte.  If you attempt to set the UltraID3Lib.TrackNum to a value greater than 255 and an ID3v1Tag was found during the Read, then an ID3v1TrackNumFormatException will be thrown.

·   Added a ToString to InvolvedPerson class

·   Changed format of ID3InvolvedPeopleListFrame.ToString

·   Fixed bug in ID3PlayCounterFrame.Counter property where Set's were ignored.  (Affected ID3PopularimeterFrame.Counter too.)

·   Changed the delimiter in the ID3Frame.ToString sections from a comma to a semicolon.  I started to format some of the numeric properties in the ToString with the thousands separator (i.e. the comma), so I made the switch to avoid confusion with the value and the delimiter.

·   Changed type of UltraID3.SizeBytes from Long to Nullable(Of Long).

1 JAN 2006

0.9.5.1

·   Added support for Synchronized Lyrics Frame (ID3SynchronizedLyricsFrame) including addition of SynchronizedLyric and SynchronizedLyricCollection classes.

·   Changed the ID3v1Tag.Exception and ID3Frame.Exception to ID3v1Tag.Exceptions and ID3Frame.Exceptions respectively.  During a read the v1 tag and the v23 frame could

·   Reformatted ID3SizeBytesFrame.ToString

·   Reformatted ID3DurationMillisecondsFrame.ToString

·   Fixed bug where only one byte was being used for the delimiter for a Unicode text field whereas two bytes should have been used.  Affected frames:  ID3PictureFrame, ID3GeneralEncapsulatedObjectFrame, and ID3InvolvedPeopleListFrame.

·   Changed ExceptionCollection to UltraID3ExceptionCollection.

·   Renamed ID3InvalidFieldDataLengthException to ID3v2InvalidFieldDataLengthException.  (This is an v2-specific exception.)

·   Changed ID3v2InvalidUnicodeByteOrderException to ID3v2MissingUnicodeByteOrderException.  This exception indicates that a valid Byte Order Marker (BOM) was not found at the start of the Unicode string.  Instead of not reading the text at all, the Unicode text will now be read using the default BOM.  The new Warning exception will indicate that the text may be suspect.

·   Added ID3MetaDataExceptionCollection class

·   Added MPEGTrackInfoException.  If there is an exception during the GetMPEGTrackInfo, this exception will be thrown.  Properties of MPEGTrackInfoException include AudioFramePosition (byte position in the audio file of the audio frame which caused the exception), AudioFrameCount (the count of audio frames read before the exception occurred), PartialAverageBitRate (The Average BitRate of the audio frames read before the exception occurred), and InnerException (the exception which caused the read of the MPEGTrackInfo to fail.)

·   Added code in the Comments frame to trim NullChar's off the end of the frame.  This is necessary because iTunes will (inexplicably and incorrectly) add a NullChar terminator to the Comments frame.

20 DEC 2005

0.9.5.0

·   Converted library to .NET Framework 2.0.

·   Converted several value type properties to corresponding Nullable generic, i.e. Integer to Nullable(Of Integer).

·   Removed the "Ultra" or the "UltraID3" prefix from all custom exceptions except UltraID3Exception (the base exception for all custom exceptions in UltraID3Lib.)  (I realized that the non-exception classes didn't follow this convention, so removed the prefix to make the naming more consistent.  Besides, my exception class names are verbose enough as it is without having to add an extra word for no reason.)

·   Added UltraID3TrackCountFormatException

·   Added UltraID3v2InvalidFrameHeaderException class

·   Renamed UltraID3v2NonStandardFrameFormatException class to UltraID3v2InvalidFrameDataException (to match format of UltraID3v2InvalidFrameHeaderException)

·   Added GetCommentsInfo function, used by ID3TextEncodingDescFrame and the ID3TextEncodingLangDescFrame.

·   Changed the logic of the ID3PictureFrame such that whenever the Picture property is set, the MIMEType is set based on the RawFormat of the image.

·   Fixed bug in ID3PictureFrame where the RawFormat of the Picture property was ImageFormat.MemoryBmp.  (This would happen when using the Bitmap class's ctor which accepted an existing Image.)

·   Renamed the ID3FrameCollection.TextEncoding to AddNewFrameTextEncoding to better describe its purpose.

·   Could not update documentation Help file because NDoc does not yet support the 2.0 version of the .NET Framework.  The XML file has been updated, but until NDoc is updated, the CHM is going to be out-of-date.

 23 NOV 2005

0.9.2.12

·   Added error handling for situation when trying to convert byte array to an Int32 where there were less than four bytes in the array.

18 OCT 2005

0.9.2.11

·   Changed error handling in ID3PictureFrame to handle more types of generic errors.

·   Fixed problem with some enumerations not saving as a Byte data type (thus corrupting frame format).

·   Added GetCommentsInfo function, used by ID3TextEncodingDescFrame and the ID3TextEncodingLangDescFrame.

·   Fixed broken links in help file Overview page.

23 SEP 2005

0.9.2.10

·   Added error checking to General Encapsulated Object Frame

22 SEP 2005

0.9.2.9

·   Changed ID3TextFrame.Text from Friend to Protected.  (Non-inherited classes should use specialized properties instead of the generic Text.)

·   Added format validation of the Year property of the ID3YearFrame to the Friend constructor.

·   Added format validate of the BeatsPerMinute property of the ID3BeatsPerMinuteFrame to the Friend constructor.

·   Added the UltraID3InvalidFieldDataLengthException.

·   Changed ID3SizeBytesFrame.SizeBytes from String to Long.

·   Changed ID3DurationMillisecondsFrame.DurationMilliseconds from String to Long.

·   Changed ID3PlaylistDelayMillisecondsFrame.PlaylistDelayMilliseconds from String to Long.

·   Changed ID3BeatsPerMinuteFrame.BeatsPerMinute from String to Long.

·   Changed ID3RecordingDayMonthFrame.Month and ID3RecordingDayMonthFrame.Day from String to Byte.

·   Replaced the UltraID3NotNumericException and UltraID3TrackNumOutOfRangeException with the UltraID3TrackNumOutOfRangeException.  (Values like 2.5 are numeric, but are still invalid, so just created a catchall invalid format exception.)

·   Replaced UltraID3YearNotNumericException and UltraID3YearTooLongException with UltraID3YearFormatException.

·   Replaced UltraID3TrackNumNotNumericException and UltraID3TrackNumOutOfRangeException with UltraID3TrackNumFormatException

·   Replaced UltraID3v2SetCountNotNumericException and UltraID3v2SetCountOutOfRangeException with UltraID3v2SetCountFormatException

·   Replaced UltraID3v2SetNumOutOfRangeException and UltraID3v2SetNumNotNumericException with UltraID3v2SetNumFormatException

·   Replaced UltraID3v2TrackCountOutOfRangeException and UltraID3v2TrackCountNotNumericException with UltraID3v2TrackCountFormatException

·   Replaced UltraID3v2DayNumOutOfRangeException and UltraID3v2DayNumNotNumericException with UltraID3v2DayNumFormatException

·   Replaced UltraID3v2MonthNumOutOfRangeException and UltraID3v2MonthNumNotNumericException with UltraID3v2MonthNumFormatException

·   Replaced UltraID3v2BeatsPerMinuteNotNumericException with UltraID3v2BeatsPerMinuteFormatException

·   Replaced UltraID3v2DurationMillisecondsNotNumericException with UltraID3v2DurationMillisecondsFormatException

·   ReplacedUltraID3v2PlaylistDelayMillisecondsNotNumericException with UltraID3v2PlaylistDelayMillisecondsFormatException

·   Replace UltraID3v2SizeBytesNotNumericException with UltraID3v2SizeBytesFormatException

8 MAY 2005

0.9.2.8

·   Fixed the ID3PopularimeterFrame so that it properly handles invalid frame formats.

·   Fixed the ID3InvolvedPeopleListFrame so that it properly handles invalid frame formats.

27 MAR 2005

0.9.2.7

·   Removed UltraID3ContextMetaDataException and UltraID3MetaDataException.  These two classes were used to give context to the ID3 exceptions.  For example, if you check the Exception property of an ID3Frame, by definition, you already know what frame caused the exception.  But if you instead use the UltraID3.GetExceptions method, you wouldn't have had any context for the exceptions i.e. you wouldn't know if an exception dealt with a particular ID3v2 frame or with the ID3v1 tag.  I used the above exceptions to wrap the original exceptions and gave them the needed context information.  But...this was very confusing to anyone but me...so I rethought the design.  What I came up with, I think, is a simple, more elegant solution.  I now just extend all exceptions from a base UltraID3Exception which has a Parent property.  One can examine the Parent property to get a reference to the instance of the class which caused the exception.  For example, if a UltraID3TrackNumOutOfRangeException is returned by the UltraID3.GetExceptions method, you can look at the exception's Parent to tell what caused this exception.  If the Parent is the ID3v1Tag, well then, the problem is with the ID3v1 Track Number field.  If the Parent is a ID3TrackNumFrame, then you know that the problem is with the Track Number field in the ID3v2 Track Number frame.

·   Changed the GetFrameCount function to GetMPEGTrackInfo which returns not only a FrameCount property, but an AverageBitRate property as well.

·   Added UltraID3UnexpectedException to wrap unexpected exceptions which occur during UltraID3Lib operations.  Reading a Frame ID which is not recognized by the ID3 v2 standard would be an expected exception.  But if something so totally unexpected happens, such as the tag format being very corrupt on non-standard, that I don't yet check for situation, then I can at least wrap it in another this class to give it some context.

·   Renamed UltraID3v2UnknownTextEncodingException to UltraID3v2InvalidTextEncodingException.  (It wasn't that the text encoding code wasn't known.  I knew what it was; it's just that it something other than what it was supposed to be.)  "I lost my job.  Well, I didn't *lose* my job.  I know where it is.  They just don't want me there anymore." - Bobcat Goldthwait

·   Split the UltraID3v2InvolvedPersonException into UltraID3v2InvolvedPersonNameMissingException and UltraID3v2InvolvedPersonInvolvementTypeMissingException.

·   Changed the access modifier of the ID3v1Tag.Delete method from Public to Friend.  This method should only be called from the UltraID3.Write method when the ID3v1Tag.WriteFlag is set to True; not externally.

·   When reading an ID3v2 tag, the UltraID3TrackNumNotNumericException and UltraID3TrackCountNotNumericException are not throw, but instead are just assigned to the Frame.Exception property.  This will allow the rest of the tag to be read.

·   Some of the exceptions that ended in 'TooLongException' were not inheriting from UltraID3ValueTooLongException, but from UltraID3TrackNumOutOfRangeException.  Changed names to end in 'OutOfRangeException'.

·   Changed the UltraID3v1CommentsTooLong28Exception and the UltraID3v1CommentsTooLong30Exception to inherit from UltraID3FieldValueTooLongException.

·   Renamed UltraID3TagException to UltraID3v2TagException as it was being used exclusively for v2 tag exceptions.  In other words, I never threw any v1 tag exceptions; the v1 exceptions were all at the field level.

·   Changed UltraID3v2MissingPictureException to inherit from UltraID3FieldException.

·   Changed UltraID3v2NonStandardFrameException to inherit from UltraID3v2FrameException.

·   Changed UltraID3v2NonStandardFrameFormatException to inherit from UltraID3v2FrameException.

·   Changed UltraID3v2UnableToDecodeFrameYetException to inherit from UltraID3v2FrameException.

·   Changed UltraID3v2UnknownTextEncodingException to inherit from UltraID3FieldException.

·   Changed UltraID3v2UnrecognizedPictureFormatException to inherit from UltraID3FieldException.

·   Changed UltraID3v2InvalidFrameLengthException to inherit from UltraID3v2FrameException.

·   Created UltraID3FileException.

·   Changed UltraID3ReadOnlyFileException to inherit from UltraID3FileException.

·   Changed UltraID3WriteException to inherit from UltraID3FileException.

·   Changed UltraID3ZeroLengthFileException to inherit from UltraID3FileException.

·   Changed UltraID3.MPEGInfo property to Read Only

·   Renamed MPEGInfo to MPEGFrameInfo.  To differentiate it from the MPEGTrackInfo.

·   Renamed UltraID3.MPEGInfo to FirstMPEGFrameInfo to reflect that this class is not based on the entire file, but instead just the first MPEG audio frame found in the file.  An important distinction when considering variable bit rate tracks.

·   Ditched the MS naming standard of dropping the capitol letters in variable names.  For example, MS says that MPEGTrackInfo should be called MpegTrackInfo.  But it's not 'Mpeg' dammit!  It's MPEG!  Mpeg is some kind of screwed up word; MPEG is an abbreviation.  I really want to follow MS naming standards, but anything that removes information is bad.  I supposed they did this to avoid confusion between the last letter in an acronym and the first letter in the following word, but come on!  You're either going to know the acronym or the following word.  Even if you were not familiar with abbreviation MPEG, would you really think that the MPEGTrackInfo was the info about an MPEGT rack?  No!  Give it a rest MS with this silly standard.

·   Changed the name of KeyValuePair to GenreInfo.  (I named it generically thinking that I'd use it for other things, but it turns out I was only using it just for the Genre.)  Also, the "Key" and "Value" properties have changed to "Number" and "Name", respectively.

·   Renamed UltraID3.GenreList to GenreInfos.  (More closely matched the new GenreInfo class name.)

·   Changed the name of NameValuePair to LanguageInfo.  (I named it generically thinking that I'd use it for other things, but it turns out I was only using it just for the Language.)  Also, the "Name" and "Value" properties have changed to "Code" and "Name", respectively.

·   Renamed UltraID3.LanguageList to LanguageInfos.  (More closely matched the new LanguageInfo class name.)

14 MAR 2005

0.9.2.6

(Internal release)

 19 JUN 2004

0.9.2.5

·   Fixed bug with ID3TextEncodingFrame tags with data that caused UltraID3v2UnknownTextEncodingException.  Exception was being caught, but processing of tag would continue causing a null reference exception.  Resolved by changing behavior of UltraID3v2UnknownTextEncodingException to a Warning.  (Changed message appropriately as well.)

·   Fixed bug with numeric genre values, which were falsely interpreted as genre code numbers.

·   Fixed bug with ID3TextEncodingLangDescFrame.  The Description property was defaulted to Nothing instead of String.Empty which was causing problems.

7 MAR 2004

0.9.2.4

·   IsSet property of the ID3UserDefinedTextFrame and ID3UserDefinedWebAddressFrame classes now return true if the Description property is not set.  This will allow, as specified by the ID3v23 standard, for these types of frames to be saved without a Description value.

·   Added the SingleInstanceFrameTypes enumeration, a subset of the FrameTypes enumeration for frames which can only have one instance per tag

·   Added the MultipleInstanceFrameTypes enumeration, a subset of the FrameTypes enumeration for frames which can have multiple instances per tag

·   Changed the ID3FrameCollection.GetFrames(ByVal frameType As FrameTypes) to use MultipleInstanceFrameTypes instead of FrameTypes.  (It stands to reason that the only time you would require a return collection is for frames which can exist multiple times in a tag.)

·   Changed the ID3FrameCollection.GetFrames(ByVal frameType As MultipleInstanceFrameTypes, ByVal returnExceptionsFlag As Boolean) to use MultipleInstanceFrameTypes instead of FrameTypes.

·   Changed ID3FrameCollection.GetFrame(ByVal frameType As FrameTypes, ByVal addNewFrame As Boolean) to use SingleInstanceFrameTypes instead of FrameTypes.

·   ID3FrameCollection.GetFrame(ByVal frameType As FrameTypes) to use SingleInstanceFrameTypes instead of FrameTypes.

·   Removed the ID3FrameCollection.RemoveFirst and the ID3FrameCollection.GetFirstFrame methods.  (With the new, more clear delineation between single and multiple instance frame types, I judged these methods to be unnecessary.)

·   Added Help file comments to all methods of the ID3FrameCollection class.

·   Added generic format exception handling to ID3TextEncodingLangDescFrame class

·   Smarter searching for first MPEG frame increases chances of accurate MPEG information.  Now more closely matches info reported by WinAmp.

·   Updated MPEG duration calculation to more closely match WinAmp.  Thanks to Malcolm Green for spotting this bug.

25 JAN 2004

0.9.2.3

·   Fixed bug with IsSet property of the ID3ComposersFrame, ID3DurationHoursMinutesFrame, ID3GenreFrame, ID3PartOfSetFrame, and ID3TrackNumFrame classes

·   Added extra error handling for invalid tag formats

9 JAN 2004

0.9.2.2

·   Fixed bug which lost ID3v1 Tag which occurred when adding a new ID3v1 Tag while simultaneously expanding the ID3v2 Tag (to fit a picture, for example).  Thanks to Brian Moore for finding this bug.

·   Updated ID3TextEncodingFrame.ToString to show actual FrameName instead of just "Text".

·   Updated ID3TextEncodingDescFrame.ToString to show actual FrameName instead of just "Text".

·   Updated ID3TextEncodingLangFrame.ToString to show actual FrameName instead of just "Text".

·   Renamed UltraID3v2FrameNoDecoderException to UltraID3v2UnableToDecodeFrameYetException (in order to more closely match the corresponding class name.)

·   Renamed UltraID3v2UnrecognizedFrameException to UltraID3v2NonStandardFrameException (in order to more closely match the corresponding class name.)

·   Added a FrameID property to the UltraID3v2UnrecognizedFrameException class.

·   Renamed FrameTypes.AudioCrypto to AudioEncryption

·   Renamed FrameTypes.BPM to AudioEncryption

·   Renamed FrameTypes.Comment to Comments

·   Renamed FrameTypes.SongLen to DurationMilliseconds

·   Renamed FrameTypes.Date to RecordingDayMonth

·   Renamed FrameTypes.Size to SizeBytes

·   Renamed FrameTypes.Encryption to EncryptionMethodRegistration

·   Renamed FrameTypes.GeneralObject to GeneralEncapsulatedObject

·   Renamed FrameTypes.VolumeAdj to RelativeVolumeAdjustment

·   Renamed FrameTypes.Time to DurationHoursMinutes

·   Renamed FrameTypes.MixArtist to InterpretedBy

·   Renamed FrameTypes.UserText to UserDefinedText

·   Renamed FrameTypes.OrigAlbum to OriginalAlbum

·   Renamed FrameTypes.OrigFileName to OriginalFileName

·   Renamed FrameTypes.OrigLyricist to OriginalLyricist 

·   Renamed FrameTypes.OrigArtist to OriginalArtist

·   Renamed FrameTypes.OrigYear to OriginalYear

·   Renamed FrameTypes.WWWCopyright to CopyrightInformationWebAddress

·   Renamed FrameTypes.WWWCommercialInfo to CommercialInformationWebAddressFrame

·   Renamed FrameTypes.WWWAudioFile to OfficialAudioFileWebAddress

·   Renamed FrameTypes.WWWArtist to OfficialArtistWebAddress

·   Renamed FrameTypes.WWWAudioSource to OfficialAudioSourceWebAddress

·   Renamed FrameTypes.WWWRadioPage to OfficialInternetRadioStationWebAddress

·   Renamed FrameTypes.WWWPayment to PaymentWebAddress

·   Renamed FrameTypes.WWWPublisher to PublisherWebAddress

·   Renamed FrameTypes.WWWUser to UserDefinedWebAddress

·   Renamed FrameTypes.PlayListDelay to PlayListDelayMilliseconds

·   CDID to CompactDiscIdentifier

·   ContentDescription to ContentGroupDescription

·   Copyright to CopyrightMessage

·   EventTiming to EventTimingCodes

·   GroupingID to GroupIdentificationRegistration

·   ISRC to InternationalStandardRecordingCode

·   InvolvedPeople to InvolvedPeopleList

·   NetRadioStation to NetRadioStationName

·   NetRadioOwner to InternetRadioStationOwner

·   NetRadioStationName to InternetRadioStationName

·   OfficialArtistWebAddress to OfficialAudioSourceWebAddress

·   LinkedInfo to LinkedInformation

·   MPEGLookup to MpegLocationLookupTable

·   Renamed ID3RecordingDurationMillisecondsFrame to ID3DurationMillisecondsFrame

·   Fixed bug in constructor of ID3DurationMillisecondsFrame

·   Renamed ID3RecordingDurationTimeFrame to ID3DurationHoursMinutesFrame

·   Updated ID3DurationHoursMinutesFrame to have a TimeSpan property instead of a String

·   Added missing FrameType property to ID3RelativeVolumeAdjustmentFrame

·   Added missing FrameType property to ID3OwnershipFrame

·   Added missing FrameType property to ID3PositionSychronizationFrame

·   Added missing FrameType property to ID3RecommendedBufferSizeFrame

·   Added missing FrameType property to ID3SynchronizedLyricsFrame

·   Added missing FrameType property to ID3SynchronizedTempoCodesFrame

·   Added an UltraID3v2DurationMillisecondsNotNumericException to ID3DurationMillisecondsFrame

·   Added an UltraID3v2SizeBytesNotNumericException to ID3SizeBytesFrame

·   The ID3GroupIdentificationRegistrationFrame class incorrectly had the FrameType of GeneralEncapsulatedObject

·   Fixed bug where ID3v23Tag.GetNewFrame returned ID3OriginalYearFrame when OriginalArtist was specified

·   Fixed bug where ID3v23Tag.GetNewFrame returned ID3OfficialAudioFileWebAddressFrame when CopyrightInformationWebAddress was specified

·   Renamed ID3OwnerFrame class to ID3FileOwnerFrame

·   Renamed ID3PlaylistDelayFrame class to ID3PlaylistDelayMillisecondsFrame

·   Split UltraID3ValueTooLongException into UltraID3ValueTooLongException and UltraID3ValueOutOfRangeException.

·   Added UltraID3v2MonthOutOfRangeException

·   Added UltraID3v2DayOutOfRangeException

·   Added UltraID3v2MonthOutOfRangeException and UltraID3v2DayOutOfRangeException checking to ID3RecordingDayMonthFrame.

21 DEC 2003

0.9.2.1

·   Fixed bug with UltraID3ValueTooLongException message (discovered from test scan done by Chris Armogida).  Thanks Chris.

·   Fixed bug with blank Text value in ID3RecordingDayMonthFrame (discovered from test scan done by Chris Armogida).  Thanks again, Chris. I owe you a beer.  ;-)

·   Fixed bug with ID3UserDefinedTextFrame from inheriting from wrong base frame class, thus causing the decode process to fail (discovered from test scan done by Chris Armogida.)  Thank you again, Chris.  I owe you not just any beer, but a genuine Guinness!

·   Changed UltraID3v2InvolvedPersonException to an ExceptionLevel of Warning

·   Fixed bug with exceptions caused during setting an UltraID3 "generic" property.  Would not create UltraID3ContextMetaDataException to give context to the exception i.e. to prepend the exception message with "Exception with ID3 v1 Tag:".

20 DEC 2003

0.9.2.0

·   Big change!  For every one of the seventy-four Frame ID's as described in the ID3 v2.3 standard, there is now a specific class.  This required the addition of quite a few new classes -- most of which simply have a single String property -- but this change will make it much more intuitive to create new instances of a particular Frame. This change will also allow for easier conversion of existing frames to make them specific to their particular Frame data.  For example, the ID3BeatsPerMinuteFrame has a simple Text property (which is a String), where it should be locked down to a numeric value.

·   Removed FrameInfo class and UltraID3.GetFrameInfo method (as they are no longer required because of above change).

·   Added FrameName and FrameDescription properties to ID3Frame class (as a replacement for removed FrameInfo).

·   Renamed ID3Frame.ID to FrameID to match the newly added FrameName and FrameDescription.  The "Frame" prefix of the property name is now used to differentiate properties that apply to the frame class as opposed to the frame instance.  (I had to use the "Frame" for the Description property of the Comments frame because it already had a Description property.  So, to be consistent, I used the prefix for the ID and Name properties as well.)

·   Split the ID3UndecodableFrame into ID3NonStandardFrame (for frames which don't comply to the ID3v23 standard) and ID3UnableToDecodeYetFrame (for frames which are valid, but where I just haven't yet written the code to decode the frame.)

·   Fixed bug when setting the Genre field.  Due to a tragic cut-and-paste accident, the Artist was erroneously getting set.

·   Added OwnerIdentifier property to ID3PrivateFrame class.

·   Added GetNewFrame to UltraID3v23Tag class.

·   Added UltraID3MPEGInvalidHeaderZeroDurationException

28 NOV 2003

0.9.1.4

·   Converted library to .NET Framework version 1.1

·   Added ExceptionType property to UltraID3TagException so as to distinguish between Errors and Warnings.

·   Added UltraID3ZeroLengthFileException class

·   Added ID3CompactDiscIdentifierFrame class

·   Added ID3RecordingDateFrame class

·   Fixed bug with ID3InvolvedPersonListFrame ToString method

·   Fixed bug which disabled the reading of MPEG data when expanding the size of the ID3 header.  (Thanks to Brian Moore for identifying this bug.)

·   Fix incorrect behavior of not removing the space in the padding left when deleting a picture frame.  A too-large padding section was causing Windows Media Player to assume the MP3 was corrupt.  (Thanks to Brian Moore for identifying this bug.)

·   Removed mimeType parameter from the ID3PictureFrame constructor (as the MIIME Type is now determined by the Bitmap.RawFormat.Guid property).

13 APR 2003

0.9.1.3

·   To make setting the values to blank easier, all TrackNum, TrackCount, and Year properties are now String.  Member variables are still numeric and appropriate exceptions will be thrown when values are set to non-numeric data.

·   Added UltraID3TrackCountNotNumericException (which is now properly referenced when setting a non-numeric Track Count i.e. '3/Ten'.)

·   Added checks to track number (which will throw (UltraID3TrackNumNotNumericException,  UltraID3TrackCountNotNumericException, UltraID3TrackNumTooLongException, and UltraID3TrackCountTooLongException) to initial read.

·   Added extra checks to Language codes (to catch instances where there were NullChars in the value)

·   ID3UniqueFileIDFrame.ToString now shows actual byte array length instead of "Byte[]"

·   Changed the constructors of many internally-used classes (such as exceptions inherited from UltraID3Exception) from Public to Protected Friend.  This is so these classes can only be instantiated from within UltraID3Lib or by an inheriting class.

·   Renamed the FrameTypeEnum enum to FrameTypes.  MS and FxCop say to not include the word "enum" in the enum name, so I took it out.

·   Renamed the following enums by adding an "s" (so the plural would be the name of the enum itself and the singular would be the name of a particular instance):  ID3TagVersion, MP3HeaderSections, TextEncodingType, ModeType, EmphasisTypes, LevelType, LayerType, PictureType

5 FEB 2003

0.9.1.2

·   Consolidated duplicate Genre definitions.  All references to Genres now include all 147 valid values.

·   Replaced calls to Chr() in ID3v1.Write with proper ASCII encoding conversion (which might have avoid some problems with saving large Track numbers.)

28 JAN 2003

0.9.1.1

·   Fixed bug where setting the Genre to an empty string would set the ID3v1 Genre code to 0 instead of 255.  Genre 0 is "Blues".  Genre 255 is used by WinAmp to represent "Unknown".

·   Added "missing" Genre codes.  (The ID3v1 standards document at http://www.id3.org/ did not list genres WinAmp 126 to 147.)  Thanks to Cliff Williams for spotting this bug.

·   Fixed sort order of Genres list.

·   Removed ID3v2.Genres property.  The ID3v2 standards states you can have multiple genres stored in a single Genre frame, but is unclear on exactly how this is done.  Besides, the major tag editing tools (WinAmp, MusicMatch, and Windows Media Player) don't support multiple tags either.

20 NOV 2002

0.9.1.0

·   Initial "semi-public" beta release of UltraID3Lib.  Includes fairly detailed documentation.  (Retired the 0.9.0.X alpha version series.)