Logo Search packages:      
Sourcecode: f-spot version File versions  Download package

SynchronizedLyricsFrame.cs

//
// SynchronizedLyricsFrame.cs:
//
// Author:
//   Brian Nickel (brian.nickel@gmail.com)
//
// Copyright (C) 2007 Brian Nickel
//
// This library is free software; you can redistribute it and/or modify
// it  under the terms of the GNU Lesser General Public License version
// 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
// USA
//

using System;
using System.Collections.Generic;
using System.Text;

namespace TagLib.Id3v2
{
      /// <summary>
      ///    Specifies the timestamp format used by a <see
      ///    cref="SynchronisedLyricsFrame" />.
      /// </summary>
00034       public enum TimestampFormat
      {
            /// <summary>
            ///    The timestamp is of unknown format.
            /// </summary>
            Unknown              = 0x00,
            
            /// <summary>
            ///    The timestamp represents the number of MPEG frames since
            ///    the beginning of the audio stream.
            /// </summary>
            AbsoluteMpegFrames   = 0x01,
            
            /// <summary>
            ///    The timestamp represents the number of milliseconds since
            ///    the beginning of the audio stream.
            /// </summary>
            AbsoluteMilliseconds = 0x02
      }
      
      /// <summary>
      ///    Specifies the type of text contained in a <see
      ///    cref="SynchronisedLyricsFrame" />.
      /// </summary>
00058       public enum SynchedTextType
      {
            /// <summary>
            ///    The text is some other type of text.
            /// </summary>
            Other             = 0x00,
            
            /// <summary>
            ///    The text contains lyrical data.
            /// </summary>
            Lyrics            = 0x01,
            
            /// <summary>
            ///    The text contains a transcription.
            /// </summary>
            TextTranscription = 0x02,
            
            /// <summary>
            ///    The text lists the movements in the piece.
            /// </summary>
            Movement          = 0x03,
            
            /// <summary>
            ///    The text describes events that occur.
            /// </summary>
            Events            = 0x04,
            
            /// <summary>
            ///    The text contains chord changes that occur in the music.
            /// </summary>
            Chord             = 0x05,
            
            /// <summary>
            ///    The text contains trivia or "pop up" information about
            ///    the media.
            /// </summary>
            Trivia            = 0x06,
            
            /// <summary>
            ///    The text contains URL's for relevant webpages.
            /// </summary>
            WebpageUrls       = 0x07,
            
            /// <summary>
            ///     The text contains URL's for relevant images.
            /// </summary>
            ImageUrls         = 0x08
      }
      
      /// <summary>
      ///    This class extends <see cref="Frame" />, implementing support for
      ///    ID3v2 Synchronised Lyrics and Text (SYLT) Frames.
      /// </summary>
00111       public class SynchronisedLyricsFrame : Frame
      {
#region Private Properties
            
            /// <summary>
            ///    Contains the text encoding to use when rendering the
            ///    current instance.
            /// </summary>
00119             private StringType encoding = Tag.DefaultEncoding;
            
            /// <summary>
            ///    Contains the ISO-639-2 language code.
            /// </summary>
00124             private string language = null;
            
            /// <summary>
            ///    Contains the description.
            /// </summary>
00129             private string description = null;
            
            /// <summary>
            ///    Contains the timestamp format.
            /// </summary>
00134             private TimestampFormat timestamp_format =
                  TimestampFormat.Unknown;
            
            /// <summary>
            ///    Contains the text type.
            /// </summary>
00140             private SynchedTextType lyrics_type = SynchedTextType.Other;
            
            /// <summary>
            ///    Contains the text.
            /// </summary>
00145             private SynchedText [] text = new SynchedText [0];
            
#endregion
            
            
            
#region Constructors
            
            /// <summary>
            ///    Constructs and initializes a new instance of <see
            ///    cref="SynchronisedLyricsFrame" /> with a specified
            ///    description, ISO-639-2 language code, text type, and text
            ///    encoding.
            /// </summary>
            /// <param name="description">
            ///    A <see cref="string" /> object containing the description
            ///    of the new instnace.
            /// </param>
            /// <param name="language">
            ///    A <see cref="string" /> object containing the ISO-639-2
            ///    language code of the new instance.
            /// </param>
            /// <param name="type">
            ///    A <see cref="SynchedTextType" /> containing the type of
            ///    text to be stored in the new instance.
            /// </param>
            /// <param name="encoding">
            ///    A <see cref="StringType" /> containing the text encoding
            ///    to use when rendering the new instance.
            /// </param>
            /// <remarks>
            ///    When a frame is created, it is not automatically added to
            ///    the tag. Consider using <see cref="Get" /> for more
            ///    integrated frame creation.
            /// </remarks>
00180             public SynchronisedLyricsFrame (string description,
                                            string language,
                                            SynchedTextType type,
                                            StringType encoding)
                  : base (FrameType.SYLT, 4)
            {
                  this.encoding = encoding;
                  this.language = language;
                  this.description = description;
                  this.lyrics_type = type;
            }

            /// <summary>
            ///    Constructs and initializes a new instance of <see
            ///    cref="SynchronisedLyricsFrame" /> with a specified
            ///    description, ISO-639-2 language code, and text type.
            /// </summary>
            /// <param name="description">
            ///    A <see cref="string" /> object containing the description
            ///    of the new instnace.
            /// </param>
            /// <param name="language">
            ///    A <see cref="string" /> object containing the ISO-639-2
            ///    language code of the new instance.
            /// </param>
            /// <param name="type">
            ///    A <see cref="SynchedTextType" /> containing the type of
            ///    text to be stored in the new instance.
            /// </param>
            /// <remarks>
            ///    When a frame is created, it is not automatically added to
            ///    the tag. Consider using <see cref="Get" /> for more
            ///    integrated frame creation.
            /// </remarks>
00214             public SynchronisedLyricsFrame (string description,
                                            string language,
                                            SynchedTextType type)
                  : this (description, language, type,
                        TagLib.Id3v2.Tag.DefaultEncoding)
            {
            }

            /// <summary>
            ///    Constructs and initializes a new instance of <see
            ///    cref="SynchronisedLyricsFrame" /> by reading its raw data
            ///    in a specified ID3v2 version.
            /// </summary>
            /// <param name="data">
            ///    A <see cref="ByteVector" /> object starting with the raw
            ///    representation of the new instance.
            /// </param>
            /// <param name="version">
            ///    A <see cref="byte" /> indicating the ID3v2 version the
            ///    raw frame is encoded in.
            /// </param>
00235             public SynchronisedLyricsFrame (ByteVector data, byte version)
                  : base(data, version)
            {
                  SetData (data, 0, version, true);
            }

            /// <summary>
            ///    Constructs and initializes a new instance of <see
            ///    cref="SynchronisedLyricsFrame" /> by reading its raw data
            ///    in a specified ID3v2 version.
            /// </summary>
            /// <param name="data">
            ///    A <see cref="ByteVector" /> object containing the raw
            ///    representation of the new instance.
            /// </param>
            /// <param name="offset">
            ///    A <see cref="int" /> indicating at what offset in
            ///    <paramref name="data" /> the frame actually begins.
            /// </param>
            /// <param name="header">
            ///    A <see cref="FrameHeader" /> containing the header of the
            ///    frame found at <paramref name="offset" /> in the data.
            /// </param>
            /// <param name="version">
            ///    A <see cref="byte" /> indicating the ID3v2 version the
            ///    raw frame is encoded in.
            /// </param>
00262             protected internal SynchronisedLyricsFrame (ByteVector data,
                                                        int offset,
                                                        FrameHeader header,
                                                        byte version)
                  : base (header)
            {
                  SetData (data, offset, version, false);
            }
            
#endregion
            
            
            
#region Public Properties
            
            /// <summary>
            ///    Gets and sets the text encoding to use when storing the
            ///    current instance.
            /// </summary>
            /// <value>
            ///    A <see cref="string" /> containing the text encoding to
            ///    use when storing the current instance.
            /// </value>
            /// <remarks>
            ///    This encoding is overridden when rendering if <see
            ///    cref="Tag.ForceDefaultEncoding" /> is <see
            ///    langword="true" /> or the render version does not support
            ///    it.
            /// </remarks>
00291             public StringType TextEncoding {
                  get {return encoding;}
                  set {encoding = value;}
            }

            /// <summary>
            ///    Gets and sets the ISO-639-2 language code stored in the
            ///    current instance.
            /// </summary>
            /// <value>
            ///    A <see cref="string" /> containing the ISO-639-2 language
            ///    code stored in the current instance.
            /// </value>
            /// <remarks>
            ///    There should only be one frame with a matching
            ///    description, type, and ISO-639-2 language code per tag.
            /// </remarks>
00308             public string Language {
                  get {
                        return (language != null && language.Length > 2)
                              ? language.Substring (0, 3) : "XXX";
                  }
                  set {language = value;}
            }

            /// <summary>
            ///    Gets and sets the description stored in the current
            ///    instance.
            /// </summary>
            /// <value>
            ///    A <see cref="string" /> containing the description
            ///    stored in the current instance.
            /// </value>
            /// <remarks>
            ///    There should only be one frame with a matching
            ///    description, type, and ISO-639-2 language code per tag.
            /// </remarks>
00328             public string Description {
                  get {return description;}
                  set {description = value;}
            }
            
            /// <summary>
            ///    Gets and sets the timestamp format used by the current
            ///    instance.
            /// </summary>
            /// <value>
            ///    A <see cref="TimestampFormat" /> value describing the
            ///    timestamp format used by the current instance.
            /// </value>
00341             public TimestampFormat Format {
                  get {return timestamp_format;}
                  set {timestamp_format = value;}
            }
            
            /// <summary>
            ///    Gets and sets the type of text contained in the current
            ///    instance.
            /// </summary>
            /// <value>
            ///    A <see cref="TimestampFormat" /> value describing the
            ///    type of text contained in the current instance.
            /// </value>
00354             public SynchedTextType Type {
                  get {return lyrics_type;}
                  set {lyrics_type = value;}
            }
            
            /// <summary>
            ///    Gets and sets the text contained in the current
            ///    instance.
            /// </summary>
            /// <value>
            ///    A <see cref="SynchedText[]" /> containing the text
            ///    contained in the current instance.
            /// </value>
00367             public SynchedText [] Text {
                  get {return text;}
                  set {
                        text = value == null ? new SynchedText [0] :
                              value;
                  }
            }
            
#endregion
            
            
            
#region Public Static Methods
            
            /// <summary>
            ///    Gets a specified lyrics frame from the specified tag,
            ///    optionally creating it if it does not exist.
            /// </summary>
            /// <param name="tag">
            ///    A <see cref="Tag" /> object to search in.
            /// </param>
            /// <param name="description">
            ///    A <see cref="string" /> object specifying the description
            ///    to match.
            /// </param>
            /// <param name="language">
            ///    A <see cref="string" /> object specifying the ISO-639-2
            ///    language code to match.
            /// </param>
            /// <param name="type">
            ///    A <see cref="SynchedTextType" /> value specifying the
            ///    text type to match.
            /// </param>
            /// <param name="create">
            ///    A <see cref="bool" /> specifying whether or not to create
            ///    and add a new frame to the tag if a match is not found.
            /// </param>
            /// <returns>
            ///    A <see cref="SynchronisedLyricsFrame" /> object
            ///    containing the matching frame, or <see langword="null" />
            ///    if a match wasn't found and <paramref name="create" /> is
            ///    <see langword="false" />.
            /// </returns>
00410             public static SynchronisedLyricsFrame Get (Tag tag,
                                                       string description,
                                                       string language,
                                                       SynchedTextType type,
                                                       bool create)
            {
                  foreach (Frame f in tag) {
                        SynchronisedLyricsFrame lyr =
                              f as SynchronisedLyricsFrame;
                        
                        if (lyr == null)
                              continue;
                        
                        if (lyr.Description == description &&
                              (language == null ||
                                    language == lyr.Language) &&
                              type == lyr.Type)
                              return lyr;
                  }

                  if (!create)
                        return null;

                  SynchronisedLyricsFrame frame =
                        new SynchronisedLyricsFrame (description,
                              language, type);
                  tag.AddFrame (frame);
                  return frame;
            }

            /// <summary>
            ///    Gets a specified lyrics frame from the specified tag,
            ///    trying to to match the description and language but
            ///    accepting an incomplete match.
            /// </summary>
            /// <param name="tag">
            ///    A <see cref="Tag" /> object to search in.
            /// </param>
            /// <param name="description">
            ///    A <see cref="string" /> object specifying the description
            ///    to match.
            /// </param>
            /// <param name="language">
            ///    A <see cref="string" /> object specifying the ISO-639-2
            ///    language code to match.
            /// </param>
            /// <param name="type">
            ///    A <see cref="SynchedTextType" /> value specifying the
            ///    text type to match.
            /// </param>
            /// <returns>
            ///    A <see cref="SynchronisedLyricsFrame" /> object
            ///    containing the matching frame, or <see langword="null" />
            ///    if a match wasn't found.
            /// </returns>
            /// <remarks>
            ///    <para>The method tries matching with the following order
            ///    of precidence:</para>
            ///    <list type="number">
            ///       <item><term>The first frame with a matching
            ///       description, language, and type.</term></item>
            ///       <item><term>The first frame with a matching
            ///       description and language.</term></item>
            ///       <item><term>The first frame with a matching
            ///       language.</term></item>
            ///       <item><term>The first frame with a matching
            ///       description.</term></item>
            ///       <item><term>The first frame with a matching
            ///       type.</term></item>
            ///       <item><term>The first frame.</term></item>
            ///    </list>
            /// </remarks>
00482             public static SynchronisedLyricsFrame GetPreferred (Tag tag,
                                                                string description,
                                                                string language,
                                                                SynchedTextType type)
            {
                  // This is weird, so bear with me. The best thing we can
                  // have is something straightforward and in our own
                  // language. If it has a description, then it is
                  // probably used for something other than an actual
                  // comment. If that doesn't work, we'd still rather have
                  // something in our language than something in another.
                  // After that all we have left are things in other
                  // languages, so we'd rather have one with actual
                  // content, so we try to get one with no description
                  // first.

                  int best_value = -1;
                  SynchronisedLyricsFrame best_frame = null;
                  
                  foreach (Frame f in tag) {
                        SynchronisedLyricsFrame cf =
                              f as SynchronisedLyricsFrame;
                        
                        if (cf == null)
                              continue;
                        
                        int value = 0;
                        if (cf.Language == language)
                              value += 4;
                        if (cf.Description == description)
                              value += 2;
                        if (cf.Type == type)
                              value += 1;
                        
                        if (value == 7)
                              return cf;
                        
                        if (value <= best_value)
                              continue;
                        
                        best_value = value;
                        best_frame = cf;
                  }
                  
                  return best_frame;
            }
            
#endregion
            
            
            
#region Protected Methods
            
            /// <summary>
            ///    Populates the values in the current instance by parsing
            ///    its field data in a specified version.
            /// </summary>
            /// <param name="data">
            ///    A <see cref="ByteVector" /> object containing the
            ///    extracted field data.
            /// </param>
            /// <param name="version">
            ///    A <see cref="byte" /> indicating the ID3v2 version the
            ///    field data is encoded in.
            /// </param>
00547             protected override void ParseFields (ByteVector data,
                                                 byte version)
            {
                  if (data.Count < 6)
                        throw new CorruptFileException (
                              "Not enough bytes in field.");

                  encoding = (StringType) data [0];
                  language = data.ToString (StringType.Latin1, 1, 3);
                  timestamp_format = (TimestampFormat) data [4];
                  lyrics_type = (SynchedTextType) data [5];

                  ByteVector delim = ByteVector.TextDelimiter (
                        encoding);
                  int delim_index = data.Find (delim, 6, delim.Count);

                  if (delim_index < 0)
                        throw new CorruptFileException (
                              "Text delimiter expected.");

                  description = data.ToString (encoding, 6,
                        delim_index - 6);

                  int offset = delim_index + delim.Count;
                  List<SynchedText> l = new List<SynchedText> ();

                  while (offset + delim.Count + 4 < data.Count) {
                        delim_index = data.Find (delim, offset,
                              delim.Count);
                        
                        if (delim_index < offset)
                              throw new CorruptFileException (
                                    "Text delimiter expected.");
                        
                        string text = data.ToString (encoding, offset,
                              delim_index - offset);
                        offset = delim_index + delim.Count;
                        
                        if (offset + 4 > data.Count)
                              break;
                        
                        l.Add (new SynchedText (data.Mid (offset, 4)
                              .ToUInt (), text));
                        offset += 4;
                  }
                  
                  this.text = l.ToArray ();
            }

            /// <summary>
            ///    Renders the values in the current instance into field
            ///    data for a specified version.
            /// </summary>
            /// <param name="version">
            ///    A <see cref="byte" /> indicating the ID3v2 version the
            ///    field data is to be encoded in.
            /// </param>
            /// <returns>
            ///    A <see cref="ByteVector" /> object containing the
            ///    rendered field data.
            /// </returns>
00608             protected override ByteVector RenderFields (byte version)
            {
                  StringType encoding = CorrectEncoding(TextEncoding,
                        version);
                  ByteVector delim = ByteVector.TextDelimiter (encoding);
                  ByteVector v = new ByteVector ();
                  
                  v.Add ((byte) encoding);
                  v.Add (ByteVector.FromString (Language,
                        StringType.Latin1));
                  v.Add ((byte) timestamp_format);
                  v.Add ((byte) lyrics_type);
                  v.Add (ByteVector.FromString (description, encoding));
                  v.Add (delim);
                  
                  foreach (SynchedText t in text) {
                        v.Add (ByteVector.FromString (t.Text, encoding));
                        v.Add (delim);
                        v.Add (ByteVector.FromUInt ((uint)t.Time));
                  }
                  
                  return v;
            }
            
            #endregion
            
            
            
#region ICloneable
            
            /// <summary>
            ///    Creates a deep copy of the current instance.
            /// </summary>
            /// <returns>
            ///    A new <see cref="Frame" /> object identical to the
            ///    current instance.
            /// </returns>
00645             public override Frame Clone ()
            {
                  SynchronisedLyricsFrame frame =
                        new SynchronisedLyricsFrame (description,
                              language, lyrics_type, encoding);
                  frame.timestamp_format = timestamp_format;
                  frame.text = (SynchedText[]) text.Clone ();
                  return frame;
            }

#endregion
      }
      
      
      /// <summary>
      ///    This structure contains a single entry in a <see
      ///    cref="SynchronisedLyricsFrame" /> object.
      /// </summary>
00663       public struct SynchedText
      {
            /// <summary>
            ///    Contains the time offset.
            /// </summary>
00668             private long time;
            
            /// <summary>
            ///    Contains the text.
            /// </summary>
00673             private string text;
            
            /// <summary>
            ///    Constructs and initializes a new instance of <see
            ///    cref="SynchedText" /> with a specified time and text.
            /// </summary>
            /// <param name="time">
            ///    A <see cref="long" /> value representing an amount of
            ///    time in a format define in the class using it. The
            ///    specific format is specified in <see
            ///    cref="SynchronisedLyricsFrame.Format" />.
            /// </param>
            /// <param name="text">
            ///    A <see cref="string" /> object containing the text
            ///    for the point in time.
            /// </param>
00689             public SynchedText (long time, string text)
            {
                  this.time = time;
                  this.text = text;
            }
            
            /// <summary>
            ///    Gets and sets the time offset of the current instance.
            /// </summary>
            /// <value>
            ///    A <see cref="long" /> value representing an amount of
            ///    time in a format define in the class using it. The
            ///    specific format is specified in <see
            ///    cref="SynchronisedLyricsFrame.Format" />.
            /// </value>
00704             public long Time {
                  get {return time;}
                  set {time = value;}
            }
            
            /// <summary>
            ///    Gets and sets the text for the point in time represented
            ///    by the current instance.
            /// </summary>
            /// <value>
            ///    A <see cref="string" /> object containing the text
            ///    for the point in time.
            /// </value>
00717             public string Text {
                  get {return text;}
                  set {text = value;}
            }
      }
}

Generated by  Doxygen 1.6.0   Back to index