99% of what you're going to want to do is in this example. This shows the basic reading and writing of a file with TagLib#.
try
{
TagLib.File file = TagLib.File.Create ("/path/to/music/file.mp3");
// Read some information.
string title = file.Tag.Title;
uint track = file.Tag.Track;
string album = file.Tag.Album;
string [] artists = file.Tag.Artists; // Remember, each song can have more than one artist.
... // Do stuff to title, album, artists.
// Store that information in the tag.
file.Tag.Title = title;
file.Tag.Track = track;
file.Tag.Album = album;
file.Tag.Artists = artists;
file.Save ();
}
catch {...}
Most tag formats support embedded images and TagLib# makes it incredably simple to access them:
try
{
TagLib.File file = TagLib.File.Create ("/path/to/music/file.mp3");
foreach (TagLib.IPicture pic in file.Tag.Pictures)
{
... // Do something fancy with the pictures!
}
}
catch {...}
More advanced features can be accessed by using TagLib.File.GetTag (TagLib.TagTypes) to get a specific tag type and using it's special features.
Below is some code (from MuineTagger) that will get and set a specified text field from any tag type. This is useful for accessing less common features like "Moods" or "Disc Name".
public static string [] GetTextField (TagLib.File file,
TagLib.ByteVector apple_name, TagLib.ByteVector id3v2_name,
string xiph_name, string ape_name)
{
TagLib.Mpeg4.AppleTag apple = (TagLib.Mpeg4.AppleTag) file.GetTag (TagLib.TagTypes.Apple);
TagLib.Id3v2.Tag id3v2 = (TagLib.Id3v2.Tag) file.GetTag (TagLib.TagTypes.Id3v2);
TagLib.Ogg.XiphComment xiph = (TagLib.Ogg.XiphComment) file.GetTag (TagLib.TagTypes.Xiph);
TagLib.Ape.Tag ape = (TagLib.Ape.Tag) file.GetTag (TagLib.TagTypes.Ape);
if (apple != null)
{
string [] text = apple.GetText (apple_name);
if (text.Length != 0)
return text;
}
if (id3v2 != null)
foreach (TagLib.Id3v2.TextIdentificationFrame f in id3v2.GetFrames (id3v2_name))
return f.FieldList.ToArray ();
if (xiph != null)
{
TagLib.StringList l = xiph.GetField (xiph_name);
if (l != null && l.Count != 0)
return l.ToArray ();
}
if (ape != null)
{
TagLib.Ape.Item item = ape.GetItem (ape_name);
if (item != null)
return item.ToStringArray ();
}
return new string [] {};
}
public static void SetTextField (TagLib.File file,
TagLib.ByteVector apple_name, TagLib.ByteVector id3v2_name,
string xiph_name, string ape_name, string [] values)
{
TagLib.Mpeg4.AppleTag apple = (TagLib.Mpeg4.AppleTag) file.GetTag (TagLib.TagTypes.Apple, true);
TagLib.Id3v2.Tag id3v2 = (TagLib.Id3v2.Tag) file.GetTag (TagLib.TagTypes.Id3v2, true);
TagLib.Ogg.XiphComment xiph = (TagLib.Ogg.XiphComment) file.GetTag (TagLib.TagTypes.Xiph, true);
TagLib.Ape.Tag ape = (TagLib.Ape.Tag) file.GetTag (TagLib.TagTypes.Ape, (file is TagLib.Mpc.File));
if (apple != null)
apple.SetText (apple_name, values);
if (id3v2 != null)
id3v2.SetTextFrame (id3v2_name, new TagLib.StringList (values));
if (xiph != null)
xiph.AddFields (xiph_name, values);
if (ape != null)
ape.AddValues (ape_name, values, true);
}
...
string [] moods = GetTextField (file, "mood", "TMOO", "MOOD", "MOOD");
...
SetTextFields (file, "mood", "TMOO", "MOOD", "MOOD", moods);
The first thing you need to set up a file type resolver is a class that extends TagLib.File. This could be one provided by the TagLib# library or one you create yourself. You would most likely use the former if you were using more sophistocated method for reading mime types than file extentions (say Gnome.VFS).
The below example creates two file type resolvers, one for FooFile and the other for BarFile. What a file type resolver does is simply check whether the file at path is is of the right type and send the arguments into the proper constructor, returning null if not found. In order for TagLib# to work with these files, they need to be added to TagLib.File's internal list. This is done through TagLib.File.AddFileTypeResolver (MyResolver);. This line needs to be placed in the code before any call is made to TagLib.File.Create (...), preferably in Main or a similar function.
TagLib.File FooResolver (string path, TagLib.AudioProperties.ReadStyle style)
{
if (/* is foo type */)
return new FooFile (path, style);
return null;
}
TagLib.File BarResolver (string path, TagLib.AudioProperties.ReadStyle style)
{
if (/* is bar type */)
return new BarFile (path, style);
return null;
}
...
TagLib.File.AddFileTypeResolver (BarResolver);
TagLib.File.AddFileTypeResolver (FooResolver); // Foo resolver will be called first.
Special attention should be made to the fact that resolvers are called in the opposite order of which they are added. This is so that if library x creates a resolver and subsequent library y wants to make a better one, the one by y will be called first.
If you're resolving muliple types, there is no reason why you couldn't combine your resolvers into a single function. The below code will behave identically to the example above.
TagLib.File FooBarResolver (string path, bool read_properties, TagLib.AudioProperties.ReadStyle style)
{
if (/* is foo type */)
return new FooFile (path, read_properties, style);
if (/* is bar type */)
return new BarFile (path, read_properties, style);
return null;
}
...
TagLib.File.AddFileTypeResolver (FooBarResolver);
Reading a file from some abitrary file system is simple with TagLib#. The below example shows how to read from Gnome.Vfs.
public class VfsFileAbstraction : TagLib.File.IFileAbstraction
{
private string name;
private FilePermissions permissions;
public VfsFileAbstraction (string file)
{
name = file;
permissions = (new FileInfo (name, FileInfoOptions.FollowLinks | FileInfoOptions.GetAccessRights)).Permissions;
if (!IsReadable)
throw new System.Exception ("File is not readable.");
}
public string Name {get {return name;}}
public System.IO.Stream ReadStream
{
get {return new VfsStream (Name, System.IO.FileMode.Open);}
}
public System.IO.Stream WriteStream
{
get {return new VfsStream (Name, System.IO.FileMode.Open);}
}
public bool IsReadable
{
get {return (permissions | FilePermissions.AccessReadable) != 0;}
}
public bool IsWritable
{
get {return (permissions | FilePermissions.AccessWritable) != 0;}
}
public static TagLib.File.IFileAbstraction CreateFile (string path)
{
return new VfsFileAbstraction (path);
}
}
...
Gnome.Vfs.Vfs.Initialize ();
TagLib.File.SetFileAbstractionCreator (new TagLib.File.FileAbstractionCreator (VfsFileAbstraction.CreateFile));
TagLib.File file = TagLib.File.Create ("smb://WindowsShare/Music/Devil%20Went%20Down%20To%20Georgia.mp3");
// normal tagging operations
Gnome.Vfs.Vfs.Shutdown ();
There's no real reason for this, I just think it's fun.
$ nemish
Welcome to Nemerle interpreter (using ncc 0.9.2.0).
Please enter expressions appended with ";;".
Type "Help;;" for more info.
Please wait while evaluating the config file..
- Ref = "/usr/lib/mono/taglib-sharp/taglib-sharp.dll";;
def it : void
- def file= TagLib.File.Create ("/media/shared/Music/Bon Jovi/Slippery When Wet/03 - Livin' on a Prayer.mp3");;
def file = TagLib.Mpeg.File : TagLib.File
def it : void
- file.Tag.Title;;
def it = Livin' on a Prayer : System.String
- file.Tag.Album;;
def it = Slippery When Wet : System.String
- System.String.Join (", ", file.Tag.AlbumArtists);;
def it = Bon Jovi : System.String
- System.String.Join (", ", file.Tag.Genres);;
def it = : System.String
- file.Tag.Year;;
def it = 1986 : System.UInt32
- file.Tag.Track.ToString () + "/" + file.Tag.TrackCount.ToString ();;
def it = 3/10 : System.String
-
© 2008 Novell, Inc. All Rights Reserved.