Example #1
0
        /// <summary>
        /// Reads the SV8 metadata from a MPC (MusePack) audio file.        
        /// </summary>
        /// <param name="filePath">Audio file path</param>        
        /// <returns>SV8 data structure</returns>
        public static SV8Tag Read(string filePath)
        {
            SV8Tag data = new SV8Tag();

            // Check for nulls or empty
            if (String.IsNullOrEmpty(filePath))
                throw new Exception("The file path cannot be null or empty!");

            #if WINDOWSSTORE
            #else

            BinaryReader reader = null;
            FileStream stream = null;

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

                // Get file length
                long fileLength = reader.BaseStream.Length;
                long headerOffset = 0;

                // Read "File magic number"                
                byte[] bytesMagicNumber = reader.ReadBytes(4);
                string magicNumber = Encoding.UTF8.GetString(bytesMagicNumber, 0, bytesMagicNumber.Length);

                // Validate number
                if (magicNumber.ToUpper() != "MPCK")
                {
                    throw new SV8TagNotFoundException("The file is not in MPC/SV8 format!", null);
                }

                // Loop through header keys
                while (true)
                {
                    // Read key (16-bits)                    
                    byte[] bytesKey = reader.ReadBytes(2);
                    string key = Encoding.UTF8.GetString(bytesKey, 0, bytesKey.Length);

                    // Read variable integer
                    int intSize = 0;
                    long size = SV8Metadata.ReadVariableLengthInteger(ref reader, ref intSize);

                    // Check key
                    if (key.ToUpper() == "SH")
                    {
                        // Read value (size - 3 bytes)
                        byte[] bytesValue = reader.ReadBytes((int)size - 3);

                        // Stream header
                        byte[] bytesCRC = new byte[4] { bytesValue[0], bytesValue[1], bytesValue[2], bytesValue[3] };
                        byte byteStreamVersion = bytesValue[4];

                        // Check if the header version is 8
                        if (byteStreamVersion != 8)
                        {
                            throw new SV8TagNotFoundException("This file header version is not SV8!", null);
                        }

                        // Get sample count (variable integer)
                        int intLength = 0;
                        byte[] bytesRemainingSampleCount = new byte[bytesValue.Length - 5];
                        Array.Copy(bytesValue, 5, bytesRemainingSampleCount, 0, bytesValue.Length - 5);
                        long sampleCount = SV8Metadata.GetVariableLengthInteger(bytesRemainingSampleCount, ref intLength);

                        // Get beginning silence (variable integer)                            
                        byte[] bytesRemainingBeginSilence = new byte[bytesRemainingSampleCount.Length - intLength];
                        Array.Copy(bytesRemainingSampleCount, intLength, bytesRemainingBeginSilence, 0, bytesRemainingSampleCount.Length - intLength);
                        long beginSilence = SV8Metadata.GetVariableLengthInteger(bytesRemainingBeginSilence, ref intLength);

                        byte[] bytesRemaining = new byte[bytesRemainingBeginSilence.Length - intLength];
                        Array.Copy(bytesRemainingBeginSilence, intLength, bytesRemaining, 0, bytesRemainingBeginSilence.Length - intLength);

                        // There should be 3 bytes left, but only the first two seem useful.
                        // Convert to big endian
                        int bigEndian = GetInt32(bytesRemaining, 0, false);
                        int sampleFrequency = ((bigEndian & 0xE000) >> 13);
                        data.MaxUsedBands = ((bigEndian & 0x1F00) >> 8);
                        data.AudioChannels = ((bigEndian & 0x00F0) >> 4) + 1;
                        int midSideStereoUsed = ((bigEndian & 0x0008) >> 3);
                        data.AudioBlockFrames = ((bigEndian & 0x0007) >> 0);

                        // Set metadata
                        // Sample rate
                        if (sampleFrequency == 0)
                        {
                            data.SampleRate = 44100;
                        }
                        else if (sampleFrequency == 1)
                        {
                            data.SampleRate = 48000;
                        }
                        else if (sampleFrequency == 2)
                        {
                            data.SampleRate = 37800;
                        }
                        else if (sampleFrequency == 3)
                        {
                            data.SampleRate = 32000;
                        }

                        // Set other metadata
                        data.LengthSamples = sampleCount;
                        data.BeginningSilence = beginSilence;
                        data.MidSideStereoEnabled = (midSideStereoUsed == 1) ? true : false;
                    }
                    else if (key.ToUpper() == "RG")
                    {
                        // Replay Gain                            
                        byte byteReplayGainVersion = reader.ReadByte();
                        byte[] bytesTitleGain = reader.ReadBytes(2);
                        byte[] bytesTitlePeak = reader.ReadBytes(2);
                        byte[] bytesAlbumGain = reader.ReadBytes(2);
                        byte[] bytesAlbumPeak = reader.ReadBytes(2);

                        // Read dummy byte (I don't know its use)
                        //reader.ReadByte();

                        // Set metadata
                        data.ReplayGainVersion = (int)byteReplayGainVersion;
                        data.TitleGain = BitConverter.ToInt16(bytesTitleGain, 0);
                        data.TitlePeak = BitConverter.ToInt16(bytesTitlePeak, 0);
                        data.AlbumGain = BitConverter.ToInt16(bytesAlbumGain, 0);
                        data.AlbumPeak = BitConverter.ToInt16(bytesAlbumPeak, 0);
                    }
                    else if (key.ToUpper() == "EI")
                    {
                        // Encoder Info
                        // Profile
                        // 0 = NA
                        // 1 = Unstable
                        // 2 = NA
                        // 3 = NA
                        // 4 = NA
                        // 5 = Quality 0
                        // 6 = Quality 1
                        // 7 = Telephone
                        // 8 = Thumb (Q3)
                        // 9 = Radio (Q4)
                        // 10 = Standard (Q5)
                        // 11 = Extreme (Q6)
                        // 12 = Insane (Q7)
                        // 13 = BrainDead (Q8)
                        // 14 = Quality 9 (Q9)
                        // 15 = Quality 10 (Q10)
                        short intProfile_PNS = (short)reader.ReadByte();
                        data.EncoderProfile = (intProfile_PNS >> 1) / 8;
                        data.EncoderPNSTool = ((intProfile_PNS & 0x01) >> 0) == 1 ? true : false;

                        // Encoder version
                        data.EncoderMajor = reader.ReadByte();
                        data.EncoderMinor = reader.ReadByte();
                        data.EncoderBuild = reader.ReadByte();
                    }
                    else if (key.ToUpper() == "SO")
                    {
                        // Read variable integer and byte. We don't actually store this 
                        int offsetSize = 0;
                        data.SeekTableOffset = SV8Metadata.ReadVariableLengthInteger(ref reader, ref offsetSize);
                        reader.ReadByte();
                    }
                    else if (key.ToUpper() == "AP")
                    {
                        // This is an audio packet; no more header information
                        headerOffset = reader.BaseStream.Position;
                        break;
                    }
                }

                // Calculate length
                data.LengthMS = ConvertAudio.ToMS(data.LengthSamples, (uint)data.SampleRate);
                data.Length = Conversion.MillisecondsToTimeString((ulong)data.LengthMS);
                long audioLengthBytes = fileLength - headerOffset;
                data.Bitrate = (int)(audioLengthBytes / data.LengthMS) * 8;
            }
            catch
            {
                throw;
            }
            finally
            {
                // Dispose stream (reader will be automatically disposed too)                
                stream.Close();   
            }

            #endif

            return data;
        }
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";
			}
		}