×

First time here?

You are looking at the most recent posts. You may also want to check out older archives. Please leave a comment, ask a question and consider subscribing to the latest posts via RSS or email. Thank you for visiting!

I’m working on a little sample application for music management in Silverlight using WCF RIA Services and some other new Silverlight 4 features.  One thing that I wanted to add to the application was the ability to drag an audio file and either lookup the data and/or add a new album/artist/song to the library automatically.

Audio formats have a ‘tag’ format known as ID3.  It’s a format used for audio file metadata that is used in Windows Media Player, iTunes, and various hardware devices as well.  Over the years there has been an evolution of this format, with the older ID3v1 format basically taking up a header space with fixed character spaces for various things like Album, Artist, Title, Year, Track.  Over time though the ID3v2 format has been adapted more as it is more flexible for things like album art, and longer titles, etc.  There are various implementations of ID3 libraries for .NET that developers can choose from.  All of these implementations don’t take into account Silverlight unfortunately.

Silverlight can only reference Silverlight-compatible libraries.  Most of these libraries were targeted for the full .NET Framework and thus I can’t binary reference them.  Luckily most of them (except one) are Open Source so I could tinker.  I took the step of simply copying the files to a Silverlight project and recompiling.  This did not work 100% in a single task.  Most of the libraries had some form of Serialization attributes/constructors and almost all used some form of ASCII encoding for various string manipulation of byte arrays.

I settled on TagLib# as the library that was the easiest to modify for me.  I had to make the same changes I mentioned above to this library as well.  I created a new Silverlight 4 class library and compiled it as such.  One thing that TagLib# didn’t have was a stream input implementation.  Most of the libraries, in fact, assumed a local file path.  Luckily the library was written using a generic ‘File’ interface, so I just had to create my own StreamFileAbstraction.  I chose to do this within my project rather than the base library.  It was easy since the LocalFileAbstraction actually perfomed an Open on the file as it’s first task and set some public variables.  My abstraction basically just hands the stream already and ready to go.

Now, using the Silverlight 4 drop target feature, I created just a simple test harness to test my theory.  My XAML basically is this (pretty rudimentary just to test my theory):

   1: <Grid x:Name="LayoutRoot" Background="White">
   2:         <StackPanel>
   3:             <Border x:Name="DropZone" Width="700" Height="300" Background="Silver" CornerRadius="8" AllowDrop="True" Drop="DropZone_Drop">
   4:                 <TextBlock TextWrapping="Wrap" Text="drop here" FontSize="64" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="Gray"/>
   5:             </Border>
   6:             <Grid Height="255" Width="700">
   7:                 <Grid.ColumnDefinitions>
   8:                     <ColumnDefinition Width="111"/>
   9:                     <ColumnDefinition Width="*"/>
  10:                 </Grid.ColumnDefinitions>
  11:                 <Grid.RowDefinitions>
  12:                     <RowDefinition Height="Auto"/>
  13:                     <RowDefinition Height="Auto"/>
  14:                     <RowDefinition Height="Auto"/>
  15:                     <RowDefinition Height="Auto" />
  16:                     <RowDefinition Height="50*" />
  17:                 </Grid.RowDefinitions>
  18:                 <dataInput:Label Content="Artist" HorizontalAlignment="Right" VerticalAlignment="Top" FontWeight="Bold" Margin="4" />
  19:                 <dataInput:Label Content="Album" Grid.Row="1" HorizontalAlignment="Right" VerticalAlignment="Top" FontWeight="Bold" Margin="4" />
  20:                 <dataInput:Label Content="Title" Grid.Row="2" HorizontalAlignment="Right" VerticalAlignment="Top" FontWeight="Bold" Margin="4" />
  21:                 <dataInput:Label Grid.Column="1" HorizontalAlignment="Left" Name="Artist" Margin="4" />
  22:                 <dataInput:Label Grid.Column="1" Grid.Row="1" HorizontalAlignment="Left" Name="Album" Margin="4" />
  23:                 <dataInput:Label Grid.Column="1" Grid.Row="2" HorizontalAlignment="Left" VerticalAlignment="Top" Name="Title" Margin="4" />
  24:                 <Image Grid.Column="1" Grid.Row="4" Height="118" HorizontalAlignment="Left" Margin="4,2,0,0" Name="AlbumArt" Stretch="Fill" VerticalAlignment="Top" Width="118" />
  25:             </Grid>
  26:         </StackPanel>
  27:     </Grid>

Notice on the Border the AllowDrop=”True” attribute.  This tells Silverlight that the element can be used as a drop target (for a file from the file system).  The rendered UI looks like this:

Sample MP3 test UI

You may also notice the Drop attribute on the Border element that maps to the event handler DropZone_Drop.  This event handler basically gives us an event argument that represents the dropped objects on the surface (yes you can drop more than one).  The initial stub of this function looks like this:

   1: private void DropZone_Drop(object sender, DragEventArgs e)
   2: {
   3:     IDataObject drop = e.Data as IDataObject;
   4:  
   5:     object data = drop.GetData(DataFormats.FileDrop);
   6:  
   7:     FileInfo[] files = data as FileInfo[];
   8:  
   9:     FileInfo file = files[0];
  10: }

I’m being a little verbose in the code to show each of the steps.  As you can see you get a FileInfo array and can pull items out of that.  For my sample I’m just assuming one item was dropped.  In the next steps I just need to get the Stream from the file and use my library.  Here is the full function (with a quick check to make sure it is a supported audio file):

   1: private void DropZone_Drop(object sender, DragEventArgs e)
   2: {
   3:     IDataObject drop = e.Data as IDataObject;
   4:  
   5:     object data = drop.GetData(DataFormats.FileDrop);
   6:  
   7:     FileInfo[] files = data as FileInfo[];
   8:  
   9:     FileInfo file = files[0];
  10:  
  11:     if (file.Extension.ToLower() != ".mp3" && file.Extension.ToLower() != ".wma")
  12:     {
  13:         MessageBox.Show("Must be an MP3 file");
  14:     }
  15:     else
  16:     {
  17:         Stream fileStream = file.OpenRead();
  18:  
  19:         TagLib.File.IFileAbstraction fileAbstraction = new StreamFileAbstraction(fileStream, file.Name);
  20:  
  21:         TagLib.File tagFile = TagLib.File.Create(fileAbstraction);
  22:  
  23:         if (tagFile.Tag.TagTypes.HasFlag(TagLib.TagTypes.Id3v2))
  24:         {
  25:             Artist.Content = tagFile.Tag.FirstAlbumArtist;
  26:             Album.Content = string.IsNullOrEmpty(tagFile.Tag.Album) ? "NO ALBUM NAME" : tagFile.Tag.Album;
  27:             Title.Content = tagFile.Tag.Title;
  28:             if (tagFile.Tag.Pictures.Length > 0)
  29:             {
  30:                 IPicture pic = tagFile.Tag.Pictures[0];
  31:                 MemoryStream img = new MemoryStream(pic.Data.Data);
  32:                 BitmapImage bmp = new BitmapImage();
  33:                 bmp.SetSource(img);
  34:  
  35:                 AlbumArt.Source = bmp;
  36:             }
  37:         }
  38:         else
  39:         {
  40:             MessageBox.Show("no id3v2 tag");
  41:         }
  42:     }

Once all the pieces are together you drag an audio file on the drop surface and the items will populate.  Here’s a quick video showing how it all works together.

Get Microsoft Silverlight

So this is just a start – and I’ve got only the tag reading working…didn’t bother looking at the other parts of the library so I know it isn’t fully ported for Silverlight.

What do you think?  Found a better implementation of ID3 tag reading?




This work is licensed under a Creative Commons Attribution By license.


1/30/2010 4:02 PM | # re: Reading MP3 metadata with Silverlight and drag-drop
Nice post, very helpful! especially your work on selecting a decent ID3 lib ;)
1/30/2010 5:41 PM | # re: Reading MP3 metadata with Silverlight and drag-drop
This is great. Thanks Tim!
1/31/2010 4:02 AM | # re: Reading MP3 metadata with Silverlight and drag-drop
That's a good thing, Tim..
1/31/2010 11:46 AM | # re: Reading MP3 metadata with Silverlight and drag-drop
Hi Tim, great post.

I've also played around with Drag'n'Drop in Silverlight 4. One big thing I've missed are the "DragDropEffects".

Your check:
if (file.Extension.ToLower() != ".mp3" && file.Extension.ToLower() != ".wma")

12: {

13: MessageBox.Show("Must be an MP3 file");

14: }

should be in a DragEnter-Event and set the Effects to None. Do you know if such possibilities will be added to the final of Silverlight 4?
2/1/2010 2:07 AM | # re: Reading MP3 metadata with Silverlight and drag-drop
It's possible to download your code ?
2/2/2010 6:35 AM | # re: Reading MP3 metadata with Silverlight and drag-drop
Same as Steo. I am faced with similar scenario. Is it possible to get you customization of the TagLib# library? Can it be downloaded somewhere?

Thanks
6/10/2010 1:36 AM | # re: Reading MP3 metadata with Silverlight and drag-drop
Hi,
is there any chance you could explain how you did that StreamFileAbstraction?
Im stuck at the point where the taglib cant open my mp3 file when I just declare the path of the file as a property (TagLib.File.Create("mp3File.mp3")) Also does not work if the file is in the ClientBin. Thank you very much.

John
5/25/2013 9:26 AM | # re: Reading MP3 metadata with Silverlight and drag-drop
Good one.

Can you pass the taglib-sharp.dll which you used in silverlight application ? Coz the default dll, cannot be added to silverlight apps.

5/30/2013 1:31 PM | # re: Reading MP3 metadata with Silverlight and drag-drop
Hi MusicMan,

Can you send it to me?
4/27/2014 2:53 AM | # re: Reading MP3 metadata with Silverlight and drag-drop
Great Tim, easy to use even when you are less technical.
5/1/2014 5:03 AM | # re: Reading MP3 metadata with Silverlight and drag-drop
If you send it, can you also send it to me?
5/11/2014 12:41 PM | # re: Reading MP3 metadata with Silverlight and drag-drop
Same here. Is it possible to send?
7/3/2014 11:18 AM | # re: Reading MP3 metadata with Silverlight and drag-drop
Reading MP3 metadata with Silverlight and drag-drop
Good one.
7/3/2014 11:36 PM | # re: Reading MP3 metadata with Silverlight and drag-drop
ok, thank you Useful material!
7/4/2014 12:45 AM | # re: Reading MP3 metadata with Silverlight and drag-drop
Tim mag dit ook ?
7/7/2014 7:57 AM | # re: Reading MP3 metadata with Silverlight and drag-drop
I think you might find the information on http://id3.codeplex.com/ supportive to your script. Quote from their site: 'The core library is a portable class library compatible with the .NET Framework 4 and higher, Silverlight 4 and higher, Windows Phone 7.5 and .NET for Metro style apps'.
8/26/2014 4:52 AM | # re: Reading MP3 metadata with Silverlight and drag-drop
Send me a copy please!
9/11/2014 9:26 PM | # re: Reading MP3 metadata with Silverlight and drag-drop
Good content, very helpful.
9/12/2014 6:47 AM | # re: Reading MP3 metadata with Silverlight and drag-drop
Thanks Tim for the great content! It's very helpfull. I can put your code to good use.
9/12/2014 6:50 AM | # re: Reading MP3 metadata with Silverlight and drag-drop
Thanks for the great artikel. I love Silverlight!
9/15/2014 12:50 PM | # re: Reading MP3 metadata with Silverlight and drag-drop
Taxi to airport
Amsterdam taxi amsterdam taxi centrale
Schiphol taxi
9/17/2014 3:14 PM | # re: Reading MP3 metadata with Silverlight and drag-drop
Thanks Tim, can you also send it to me?
9/18/2014 3:51 PM | # re: Reading MP3 metadata with Silverlight and drag-drop
Nice. Needed to edit some old code.
9/30/2014 11:52 PM | # re: Reading MP3 metadata with Silverlight and drag-drop
Thanks Tim! It has been very helpfull.

 
Please add 7 and 7 and type the answer here:

DISCLAIMER:

The opinions/content expressed on this blog are provided "ASIS" with no warranties and are my own personal opinions/content (unless otherwise noted) and do not represent my employer's view in any way.