Example #1
0
 /// <summary>
 /// Fills the AudioFile properties from the APETag structure.
 /// </summary>
 /// <param name="tag">APETag structure</param>
 private void FillProperties(APETag tag)
 {
     ArtistName = tag.Artist;
     AlbumTitle = tag.Album;
     Title = tag.Title;
     Genre = tag.Genre;
     //DiscNumber = tag
     TrackNumber = (uint)tag.Track;
     //TrackCount = tag.tr
     //Lyrics = tag.ly
     Year = (uint)tag.Year.Year;
 }
Example #2
0
		/// <summary>
		/// Refreshes the metadata of the audio file.
		/// </summary>
		public void RefreshMetadata()
		{
            // Get file size
            #if WINDOWSSTORE
		    fileSize = 0;
            #else
            var fileInfo = new FileInfo(filePath);
            fileSize = fileInfo.Length;
            #endif

            // Check what is the type of the audio file
            if (fileType == AudioFileFormat.MP3)
			{
                // Declare variables
                TagLib.Mpeg.AudioFile file = null;

                try
                {
                    // Create a more specific type of class for MP3 files
                    file = new TagLib.Mpeg.AudioFile(filePath);                    

                    // Get the position of the first and last block
                    firstBlockPosition = file.InvariantStartPosition;
                    lastBlockPosition = file.InvariantEndPosition;

                    // Copy tags
                    FillProperties(file.Tag);

                    // Loop through codecs (usually just one)
                    foreach (TagLib.ICodec codec in file.Properties.Codecs)
                    {
                        // Convert codec into a header 
                        TagLib.Mpeg.AudioHeader header = (TagLib.Mpeg.AudioHeader)codec;

                        // Copy properties						
                        audioChannels = header.AudioChannels;
                        frameLength = header.AudioFrameLength;
                        audioLayer = header.AudioLayer;
                        sampleRate = header.AudioSampleRate;
                        bitsPerSample = 16; // always 16-bit
                        channelMode = header.ChannelMode;
                        bitrate = header.AudioBitrate;
                        length = Conversion.TimeSpanToTimeString(header.Duration);
                    }
                }
                catch (Exception ex)
                {
                    // Throw exception TODO: Check if file exists when catching the exception (to make a better error description)
                    throw new Exception("An error occured while reading the tags and properties of the file (" + filePath + ").", ex);
                }
                finally
                {
                    // Dispose file (if needed)
                    if (file != null)
                        file.Dispose();
                }

                try
                {
//                    // Check if there's a Xing header
//                    XingInfoHeaderData xingHeader = XingInfoHeaderReader.ReadXingInfoHeader(filePath, firstBlockPosition);
//
//                    // Check if the read was successful
//                    if (xingHeader.Status == XingInfoHeaderStatus.Successful)
//                    {
//                        // Set property value
//                        //m_xingInfoHeader = xingHeader;
//                        mp3EncoderDelay = xingHeader.EncoderDelay;
//                        mp3EncoderPadding = xingHeader.EncoderPadding;
//                        mp3EncoderVersion = xingHeader.EncoderVersion;
//                        mp3HeaderType = xingHeader.HeaderType;
//                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }
			}
            else if (fileType == AudioFileFormat.FLAC)
			{
                // Declare variables 
                TagLib.Flac.File file = null;

                try
                {
                    // Read VorbisComment in FLAC file
                    file = new TagLib.Flac.File(filePath);

                    // Get the position of the first and last block
                    firstBlockPosition = file.InvariantStartPosition;
                    lastBlockPosition = file.InvariantEndPosition;

                    // Copy tags
                    FillProperties(file.Tag);

                    // Loop through codecs (usually just one)
                    foreach (TagLib.ICodec codec in file.Properties.Codecs)
                    {
                        // Convert codec into a header 
                        TagLib.Flac.StreamHeader header = (TagLib.Flac.StreamHeader)codec;

                        // Copy properties
                        bitrate = header.AudioBitrate;
                        audioChannels = header.AudioChannels;
                        sampleRate = header.AudioSampleRate;
                        bitsPerSample = header.BitsPerSample;
                        length = Conversion.TimeSpanToTimeString(header.Duration);
                    }
                }
                catch (Exception ex)
                {
                    // Throw exception
                    throw new Exception("An error occured while reading the tags and properties of the file (" + filePath + ").", ex);
                }
                finally
                {
                    // Dispose file (if needed)
                    if (file != null)
                        file.Dispose();
                }
			}
            else if (fileType == AudioFileFormat.OGG)
			{
                // Declare variables 
                TagLib.Ogg.File file = null;

                try
                {
                    // Read VorbisComment in OGG file
                    file = new TagLib.Ogg.File(filePath);

                    // Get the position of the first and last block
                    firstBlockPosition = file.InvariantStartPosition;
                    lastBlockPosition = file.InvariantEndPosition;

                    // Copy tags
                    FillProperties(file.Tag);

                    // Loop through codecs (usually just one)
                    foreach (TagLib.ICodec codec in file.Properties.Codecs)
                    {
                        // Check what kind of codec is used 
                        if (codec is TagLib.Ogg.Codecs.Theora)
                        {
                            // Do nothing, this is useless for audio.
                        }
                        else if (codec is TagLib.Ogg.Codecs.Vorbis)
                        {
                            // Convert codec into a header 
                            TagLib.Ogg.Codecs.Vorbis header = (TagLib.Ogg.Codecs.Vorbis)codec;

                            // Copy properties
                            bitrate = header.AudioBitrate;
                            audioChannels = header.AudioChannels;
                            sampleRate = header.AudioSampleRate;
                            bitsPerSample = 16;
                            length = Conversion.TimeSpanToTimeString(header.Duration);
                        }
                    }
                }
                catch (Exception ex)
                {
                    // Throw exception
                    throw new Exception("An error occured while reading the tags and properties of the file (" + filePath + ").", ex);
                }
                finally
                {
                    // Dispose file (if needed)
                    if (file != null)
                        file.Dispose();
                }
			}
            else if (fileType == AudioFileFormat.APE)
            {
                // Monkey's Audio (APE) supports APEv2 tags.
                // http://en.wikipedia.org/wiki/Monkey's_Audio

                // Declare variables
                TagLib.Ape.File file = null;

                try
                {
                    // Read APE metadata
                    apeTag = APEMetadata.Read(filePath);

                    // Get APEv1/v2 tags from APE file
                    file = new TagLib.Ape.File(filePath);

                    // Get the position of the first and last block
                    firstBlockPosition = file.InvariantStartPosition;
                    lastBlockPosition = file.InvariantEndPosition;

                    // Copy tags
                    FillProperties(file.Tag);

                    // Loop through codecs (usually just one)
                    foreach (TagLib.ICodec codec in file.Properties.Codecs)
                    {
                        // Check what kind of codec is used 
                        if (codec is TagLib.Ape.StreamHeader)
                        {
                            // Convert codec into a header 
                            TagLib.Ape.StreamHeader header = (TagLib.Ape.StreamHeader)codec;

                            // Copy properties
                            bitrate = header.AudioBitrate;
                            audioChannels = header.AudioChannels;
                            sampleRate = header.AudioSampleRate;
                            bitsPerSample = 16;
                            length = Conversion.TimeSpanToTimeString(header.Duration);
                        }
                    }
                }
                catch (Exception ex)
                {
                    // Throw exception
                    throw new Exception("An error occured while reading the tags and properties of the file (" + filePath + ").", ex);
                }
                finally
                {
                    // Dispose file (if needed)
                    if (file != null)
                        file.Dispose();
                }
            }
            else if (fileType == AudioFileFormat.MPC)
            {                
                // MusePack (MPC) supports APEv2 tags.
                // http://en.wikipedia.org/wiki/Musepack
                try
                {
                    // Try to read SV8 header
                    sv8Tag = SV8Metadata.Read(filePath);

                    // Set audio properties
                    audioChannels = sv8Tag.AudioChannels;
                    sampleRate = sv8Tag.SampleRate;
                    bitsPerSample = 16;
                    length = sv8Tag.Length;
                    bitrate = sv8Tag.Bitrate;
                }
                catch (SV8TagNotFoundException exSV8)
                {
                    try
                    {
                        // Try to read the SV7 header
                        sv7Tag = SV7Metadata.Read(filePath);

                        // Set audio properties
                        audioChannels = sv7Tag.AudioChannels;
                        sampleRate = sv7Tag.SampleRate;
                        bitsPerSample = 16;
                        length = sv7Tag.Length;
                        bitrate = sv7Tag.Bitrate;
                    }
                    catch (SV7TagNotFoundException exSV7)
                    {
                        // No headers have been found!
                        SV8TagNotFoundException finalEx = new SV8TagNotFoundException(exSV8.Message, exSV7);
                        throw new Exception("Error: The file is not in SV7/MPC or SV8/MPC format!",  finalEx);
                    }
                }

                try
                {
                    // Read APE tag
                    apeTag = APEMetadata.Read(filePath);

                    // Copy tags
                    FillProperties(apeTag);
                }
                catch (Exception ex)
                {
                    // Check exception
                    if (ex is APETagNotFoundException)
                    {
                        // Skip file
                    }
                    else
                    {
                        throw;
                    }
                }
            }
            else if (fileType == AudioFileFormat.OFR)
            {
                // TagLib does not support OFR files...
                // OptimFROG (OFR) supports APEv2 tags.
                // http://en.wikipedia.org/wiki/OptimFROG                
            }
            else if (fileType == AudioFileFormat.WV)
            {
                // WavPack supports APEv2 and ID3v1 tags.
                // http://www.wavpack.com/wavpack_doc.html

                // Declare variables
                TagLib.WavPack.File file = null;

                try
                {
                    // Read WavPack tags
                    file = new TagLib.WavPack.File(filePath);

                    // Get the position of the first and last block
                    firstBlockPosition = file.InvariantStartPosition;
                    lastBlockPosition = file.InvariantEndPosition;

                    // Copy tags
                    FillProperties(file.Tag);

                    // Loop through codecs (usually just one)
                    foreach (TagLib.ICodec codec in file.Properties.Codecs)
                    {
                        // Check what kind of codec is used 
                        if (codec is TagLib.WavPack.StreamHeader)
                        {
                            // Convert codec into a header 
                            TagLib.WavPack.StreamHeader header = (TagLib.WavPack.StreamHeader)codec;

                            // Copy properties
                            bitrate = header.AudioBitrate;
                            audioChannels = header.AudioChannels;
                            sampleRate = header.AudioSampleRate;
                            bitsPerSample = 16;
                            length = Conversion.TimeSpanToTimeString(header.Duration);
                        }
                    }
                }
                catch (Exception ex)
                {
                    // Throw exception
                    throw new Exception("An error occured while reading the tags and properties of the file (" + filePath + ").", ex);
                }
                finally
                {
                    // Dispose file (if needed)
                    if (file != null)
                        file.Dispose();
                }
            }
            else if (fileType == AudioFileFormat.TTA)
            {
                // The True Audio (TTA) format supports ID3v1, ID3v2 and APEv2 tags.
                // http://en.wikipedia.org/wiki/TTA_(codec)

                audioChannels = 2;
                sampleRate = 44100;
                bitsPerSample = 16;

                // TagLib doesn't work.
            }
            else if (fileType == AudioFileFormat.WAV)
            {
                // Declare variables
                TagLib.Riff.File file = null;

                try
                {
                    // Get WAV file
                    file = new TagLib.Riff.File(filePath);                    

                    // Get the position of the first and last block
                    firstBlockPosition = file.InvariantStartPosition;
                    lastBlockPosition = file.InvariantEndPosition;

                    // Copy tags
                    FillProperties(file.Tag);

                    // Loop through codecs (usually just one)
                    foreach (TagLib.ICodec codec in file.Properties.Codecs)
                    {
                        // Check what kind of codec is used 
                        if (codec is TagLib.Riff.WaveFormatEx)
                        {
                            // Convert codec into a header 
                            TagLib.Riff.WaveFormatEx header = (TagLib.Riff.WaveFormatEx)codec;

                            // Copy properties
                            bitrate = header.AudioBitrate;
                            audioChannels = header.AudioChannels;
                            sampleRate = header.AudioSampleRate;
                            bitsPerSample = 16;
                            length = Conversion.TimeSpanToTimeString(header.Duration);
                        }
                    }
                }
                catch (Exception ex)
                {
                    // Throw exception
                    throw new Exception("An error occured while reading the tags and properties of the file (" + filePath + ").", ex);
                }
                finally
                {
                    // Dispose file (if needed)
                    if (file != null)
                        file.Dispose();
                }
            }
            else if (fileType == AudioFileFormat.WMA)
            {
                // Declare variables
                TagLib.Asf.File file = null;

                try
                {
                    // Read ASF/WMA tags
                    file = new TagLib.Asf.File(filePath);

                    // Get the position of the first and last block
                    firstBlockPosition = file.InvariantStartPosition;
                    lastBlockPosition = file.InvariantEndPosition;

                    // Copy tags
                    FillProperties(file.Tag);

                    // The right length is here, not in the codec data structure
                    length = Conversion.TimeSpanToTimeString(file.Properties.Duration);

                    // Loop through codecs (usually just one)
                    foreach (TagLib.ICodec codec in file.Properties.Codecs)
                    {
                        // Check what kind of codec is used 
                        if (codec is TagLib.Riff.WaveFormatEx)
                        {
                            // Convert codec into a header 
                            TagLib.Riff.WaveFormatEx header = (TagLib.Riff.WaveFormatEx)codec;

                            // Copy properties
                            bitrate = header.AudioBitrate;
                            audioChannels = header.AudioChannels;
                            sampleRate = header.AudioSampleRate;
                            bitsPerSample = 16;                            
                        }
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
                    // Dispose file (if needed)
                    if (file != null)
                        file.Dispose();
                }
            }
            else if (fileType == AudioFileFormat.AAC)
            {
                // Declare variables
                TagLib.Aac.File file = null;

                try
                {
                    // Read AAC tags
                    file = new TagLib.Aac.File(filePath);

                    // Doesn't seem to work very well...
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
                    // Dispose file (if needed)
                    if (file != null)
                        file.Dispose();
                }
            }              
            
			// If the song has no name, give filename as the name                
			if (String.IsNullOrEmpty(Title))
			{
				Title = Path.GetFileNameWithoutExtension(filePath);
			}

			// If the artist has no name, give it "Unknown Artist"
			if (String.IsNullOrEmpty(ArtistName))
			{
				ArtistName = "Unknown Artist";
			}

			// If the song has no album title, give it "Unknown Album"
			if (String.IsNullOrEmpty(AlbumTitle))
			{
				AlbumTitle = "Unknown Album";
			}
		}
Example #3
0
        /// <summary>
        /// Reads the APEv1/APEv2 metadata from an audio file.
        /// Supports the following audio formats: APE.
        /// </summary>
        /// <param name="filePath">Audio file path</param>        
        /// <returns>APE data structure</returns>
        public static APETag Read(string filePath)
        {            
            if (String.IsNullOrEmpty(filePath))
                throw new Exception("The file path cannot be null or empty!");

            APETag data = new APETag();

            #if WINDOWSSTORE
            #else
            BinaryReader reader = null;
            FileStream stream = null;

            try
            {
                // Open binary reader             
                stream = File.OpenRead(filePath);
                reader = new BinaryReader(stream);

                // APEv1/APEv2 have footers, but only APEv2 has a header. 
                // In fact, the header and footer contain the exact same information.
                // http://wiki.hydrogenaudio.org/index.php?title=APE_Tags_Header

                // APE metadata can always be found at the very end of the file.
                // TODO: maybe seek the reader near the end of file?
                //byte[] bytes = reader.ReadBytes(4);

                // The header/footer structure is as followed:
                // 1) Preamble (64-bits) APETAGEX
                // 2) Version number (32-bits) 1000 or 2000
                // 3) Tag size (32-bits)
                // 4) Item count (32-bits)
                // 5) Tags flags (32-bits)
                // 6) Reserved (64-bits) Must be zero
                // Total: 32 bytes

                // Seek at the end of the file (length - 32 bytes)
                reader.BaseStream.Seek(-32, SeekOrigin.End);

                // Read Preamble (64-bits)
                byte[] bytesPreamble = reader.ReadBytes(8);
                string preamble = Encoding.UTF8.GetString(bytesPreamble, 0, bytesPreamble.Length);

                // Validate preamble
                if (preamble != "APETAGEX")
                {
                    throw new APETagNotFoundException("The APE tag was not found.");
                }

                // Read Version number (32-bits)
                byte[] bytesVersionNumber = reader.ReadBytes(4);
                int versionNumber = BitConverter.ToInt32(bytesVersionNumber, 0);

                // Check version number
                if (versionNumber == 1000)
                {
                    data.Version = APETagVersion.APEv1;
                }
                else if (versionNumber == 2000)
                {
                    data.Version = APETagVersion.APEv2;
                }
                else
                {
                    throw new APETagNotFoundException("The APE tag version is unknown (" + versionNumber.ToString() + ").");
                }

                // Read Tag size (32-bits)
                // This is the total size of the items + header (if APEv2)
                byte[] bytesTagSize = reader.ReadBytes(4);
                data.TagSize = BitConverter.ToInt32(bytesTagSize, 0);

                // Read Item count (32-bits)
                byte[] bytesItemCount = reader.ReadBytes(4);
                int itemCount = BitConverter.ToInt32(bytesItemCount, 0);

                // Read Tags flags (32-bits)
                // http://wiki.hydrogenaudio.org/index.php?title=Ape_Tags_Flags
                byte[] bytesTagsFlags = reader.ReadBytes(4);

                // Read reserved (64-bits)
                byte[] bytesReserved = reader.ReadBytes(8);

                // Seek back to the start of the APE metadata (32 bytes - tag size)
                reader.BaseStream.Seek(-32 - data.TagSize, SeekOrigin.End);

                // Is this APEv2?
                if (data.Version == APETagVersion.APEv2)
                {
                    // Skip header (32 bytes)
                    reader.BaseStream.Seek(32, SeekOrigin.Current);
                }

                // Read items
                for (int a = 0; a < itemCount; a++)
                {
                    // Read item value size
                    byte[] bytesItemValueSize = reader.ReadBytes(4);
                    int itemValueSize = BitConverter.ToInt32(bytesItemValueSize, 0);

                    // Read item flags
                    byte[] bytesItemFlags = reader.ReadBytes(4);

                    // The key size is variable but always ends by a key terminator (0x00).
                    // The key characters vary from 0x20 (space) to 0x7E (tilde).

                    // Read key
                    List<byte> bytesKey = new List<byte>();
                    while (true)
                    {
                        // Read characters until the terminator is found (0x00)
                        byte byteChar = reader.ReadByte();
                        if (byteChar == 0x00)
                        {
                            // Exit loop
                            break;
                        }
                        else
                        {
                            bytesKey.Add(byteChar);
                        }
                    }

                    // Read value
                    byte[] bytesValue = reader.ReadBytes(itemValueSize);

                    // Cast key and value into UTF8 strings             
                    var bytesKeyArray = bytesKey.ToArray();
                    string key = Encoding.UTF8.GetString(bytesKeyArray, 0, bytesKeyArray.Length);
                    string value = Encoding.UTF8.GetString(bytesValue, 0, bytesValue.Length);

                    // Add key/value to dictionary
                    data.Dictionary.Add(key, value);
                }

                // Go through dictionary items
                foreach (KeyValuePair<string, string> keyValue in data.Dictionary)
                {
                    string key = keyValue.Key.ToUpper().Trim();
                    if (key == "TITLE")
                    {
                        data.Title = keyValue.Value;
                    }
                    else if (key == "SUBTITLE")
                    {
                        data.Subtitle = keyValue.Value;
                    }
                    else if (key == "ARTIST")
                    {
                        data.Artist = keyValue.Value;
                    }
                    else if (key == "ALBUM")
                    {
                        data.Album = keyValue.Value;
                    }
                    else if (key == "DEBUT ALBUM")
                    {
                        data.DebutAlbum = keyValue.Value;
                    }
                    else if (key == "PUBLISHER")
                    {
                        data.Publisher = keyValue.Value;
                    }
                    else if (key == "CONDUCTOR")
                    {
                        data.Conductor = keyValue.Value;
                    }
                    else if (key == "TRACK")
                    {
                        int value = 0;
                        int.TryParse(keyValue.Value, out value);
                        data.Track = value;
                    }
                    else if (key == "COMPOSER")
                    {
                        data.Composer = keyValue.Value;
                    }
                    else if (key == "COMMENT")
                    {
                        data.Comment = keyValue.Value;
                    }
                    else if (key == "COPYRIGHT")
                    {
                        data.Copyright = keyValue.Value;
                    }
                    else if (key == "PUBLICATIONRIGHT")
                    {
                        data.PublicationRight = keyValue.Value;
                    }
                    else if (key == "EAN/UPC")
                    {
                        int value = 0;
                        int.TryParse(keyValue.Value, out value);
                        data.EAN_UPC = value;
                    }
                    else if (key == "ISBN")
                    {
                        int value = 0;
                        int.TryParse(keyValue.Value, out value);
                        data.ISBN = value;
                    }
                    else if (key == "LC")
                    {
                        data.LC = keyValue.Value;
                    }
                    else if (key == "YEAR")
                    {
                        DateTime value = DateTime.MinValue;
                        DateTime.TryParse(keyValue.Value, out value);
                        data.Year = value;
                    }
                    else if (key == "RECORD DATE")
                    {
                        DateTime value = DateTime.MinValue;
                        DateTime.TryParse(keyValue.Value, out value);
                        data.RecordDate = value;
                    }
                    else if (key == "RECORD LOCATION")
                    {
                        data.RecordLocation = keyValue.Value;
                    }
                    else if (key == "GENRE")
                    {
                        data.Genre = keyValue.Value;
                    }
                    else if (key == "INDEX")
                    {
                        data.Index = keyValue.Value;
                    }
                    else if (key == "RELATED")
                    {
                        data.Related = keyValue.Value;
                    }
                    else if (key == "ABSTRACT")
                    {
                        data.Abstract = keyValue.Value;
                    }
                    else if (key == "LANGUAGE")
                    {
                        data.Language = keyValue.Value;
                    }
                    else if (key == "BIBLIOGRAPHY")
                    {
                        data.Bibliography = keyValue.Value;
                    }
                }

            }
            catch
            {
                // Leave metadata empty
            }
            finally
            {
                // Dispose stream (reader will be automatically disposed too)                
                stream.Close();   
            }

            #endif

            return data;
        }