Click here to Skip to main content
15,885,757 members
Articles / Programming Languages / C#

Using Winamp input plugins for tagging audio files

Rate me:
Please Sign up or sign in to vote.
4.74/5 (9 votes)
21 Jun 2007CPOL5 min read 68.8K   456   30  
C# Interop with dynamic loaded plug-ins and function pointers
using System;
using System.ComponentModel;
using System.Drawing;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
using OC.Winamp.Metadata;


namespace OC.Winamp.Components
{
    public enum eTagOptions
    {
        Get,
        Set,
        WriteReadOnly
    }

    public partial class WinampTagger : UserControl
    {
        public WinampTagger()
        {
            InitializeComponent();

            txtGenre.AutoCompleteCustomSource = AutoComplete.Default.Genre;
            txtGenre.AutoCompleteSource = AutoCompleteSource.CustomSource;
            txtGenre.AutoCompleteMode = AutoCompleteMode.Suggest;
        }

        #region Fields

        private WinampMetadata winampMetadata;
        private MetaData metaData;
        private eTagOptions _Options;
        private FileInfo _File;
        private bool isReadOnly;
        private bool isInitialized;

        #endregion

        #region Public Properties
        
        [DefaultValue(eTagOptions.Get)]
        public eTagOptions Options
        {
            get { return _Options; }
            set
            {
                _Options = value;

                if (isInitialized && value == eTagOptions.Get && btnWrite.Enabled)
                {
                    // was writable and dirty, yet reset as readonly: -> get original tag
                    fillControls();
                }

                btnWrite.Enabled = false;
                
                switch (value)
                {
                    case eTagOptions.Get:
                        btnWrite.Visible = false;
                        readOnlyControls(true);
                        break;
                    case eTagOptions.Set:
                        btnWrite.Visible = !isReadOnly;
                        readOnlyControls(isReadOnly);
                        break;
                    case eTagOptions.WriteReadOnly:
                        btnWrite.Visible = true;
                        readOnlyControls(false);
                        break;
                    default:
                        throw new ArgumentOutOfRangeException();
                        //break;
                }
            }
        }

        [Browsable(false), DefaultValue(null)]
        public WinampMetadata Engine
        {
            //get { return winampMetadata; }
            set { winampMetadata = value; }
        }

        [Browsable(false), DefaultValue(null)]
        public FileInfo File
        {
            get { return _File; }
            set
            {
                _File = value;

                isInitialized = false;
                isReadOnly = isFileReadOnly(_File);
                Options = _Options;

                if (_File != null && _File.Exists)
                {
                    if (winampMetadata != null && winampMetadata.InitFileInfo(_File))
                    {
                        fillControls();
                        btnWrite.Enabled = false;
                        isInitialized = true;
                        return;
                    }
                }
                clearControls();
            }
        }

        #endregion

        #region Public Methods

        public void RefreshContent()
        {
            if (isInitialized)
            {
                fillControls();
            }
        }

        #endregion

        #region EventHandler

        private void WinampTagger_Load(object sender, EventArgs e)
        {
            metaData = new MetaData();

            if (_File != null)
            {
                this.File = _File;
            }
        }

        private void txt_TextChanged(object sender, EventArgs e)
        {
            if (_Options != eTagOptions.Get)
            {
                btnWrite.Enabled = true;
            }
        }

        private void txt_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter && btnWrite.Enabled)
            {
                e.SuppressKeyPress = true;
                btnWrite.PerformClick();
            }
        }

        private void txtComment_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter && !e.Shift && !e.Control && !e.Alt && btnWrite.Enabled)
            {
                e.SuppressKeyPress = true;
                btnWrite.PerformClick();
            }
        }

        private void btnWrite_Click(object sender, EventArgs e)
        {
            Debug.Assert(_Options != eTagOptions.Get);

            btnWrite.Enabled = false;

            metaData.Artist = txtArtist.Text;
            metaData.Album = txtAlbum.Text;
            metaData.Title = txtTitle.Text;
            metaData.Track = txtTrack.Text;
            metaData.Year = txtYear.Text;
            metaData.Genre = txtGenre.Text;
            metaData.Comment = txtComment.Text;

            writeTag(metaData);
        }

        #endregion

        #region Private Helpers
        
        private bool fillControls()
        {
            if (winampMetadata.GetFileInfoBatch(out metaData))
            {
                txtArtist.Text = metaData.Artist;
                txtAlbum.Text = metaData.Album;
                txtTitle.Text = metaData.Title;
                txtTrack.Text = metaData.Track;
                txtYear.Text = metaData.Year;
                txtGenre.Text = metaData.Genre;
                txtComment.Text = metaData.Comment;


                MetaData2 metaData2 = new MetaData2();

                if (winampMetadata.GetFileInfoBatch2(out metaData2))
                {
                    lblFixed.Text = string.Format("{0}, {1} kbit{2}{3}",
                        !string.IsNullOrEmpty(metaData2.Length) ? MilliSecondsToMinSec(metaData2.Length) : "FAILED", 
                        metaData2.Bitrate, 
                        metaData2.VBR != "0" ? ", VBR" : null,
                        isReadOnly ? ", ReadOnly" : null);   
                }
                else
                {
                    lblFixed.Text = string.Empty;
                }

                return true;
            }
            else
            {
                clearControls();
            }
            return false;
        }

        private void clearControls()
        {
            txtArtist.Text = string.Empty;
            txtAlbum.Text = string.Empty;
            txtTitle.Text = string.Empty;
            txtTrack.Text = string.Empty;
            txtYear.Text = string.Empty;
            txtGenre.Text = string.Empty;
            txtComment.Text = string.Empty;
            lblFixed.Text = string.Empty;
        }

        private void readOnlyControls(bool isReadOnly)
        {
            txtArtist.ReadOnly = isReadOnly;
            txtAlbum.ReadOnly = isReadOnly;
            txtTitle.ReadOnly = isReadOnly;
            txtTrack.ReadOnly = isReadOnly;
            txtYear.ReadOnly = isReadOnly;
            txtGenre.ReadOnly = isReadOnly;
            txtComment.ReadOnly = isReadOnly;
        }

        private bool writeTag(MetaData metaData)
        {
            if (winampMetadata.SetFileInfoBatch(metaData))
            {
                bool resetReadOnly = false;

                if (_Options == eTagOptions.WriteReadOnly && isReadOnly)
                {
                    setFileReadOnly(_File, false);
                    resetReadOnly = true;
                }

                if (winampMetadata.WriteFileInfo())
                {
                    if (resetReadOnly)
                    {
                        setFileReadOnly(_File, true);
                    }
                    return true;
                }
                else
                {
                    MessageBox.Show("WriteFileInfo failed!");
                }
            }
            else
            {
                Debug.Fail("SetFileInfoBatch failed!");
            }

            return false;
        }

        private bool isFileReadOnly(FileInfo file)
        {
            if (file != null && file.Exists)
            {
                return ((file.Attributes & FileAttributes.ReadOnly) != 0);
            }
            return false;
        }

        private void setFileReadOnly(FileInfo file, bool isReadOnly)
        {
            if (file != null && file.Exists)
            {
                if (isFileReadOnly(file) != isReadOnly)
                {
                    if (isReadOnly)
                    {
                        file.Attributes |= FileAttributes.ReadOnly;
                    }
                    else
                    {
                        file.Attributes ^= FileAttributes.ReadOnly;
                    }

                    Debug.Assert(isFileReadOnly(file) == isReadOnly);
                }
            }
        }

        private string MilliSecondsToMinSec(string s)
        {
            Double milliSecs = 0;

            if (Double.TryParse(s, out milliSecs))
            {
                TimeSpan ts = TimeSpan.FromMilliseconds(milliSecs);

                if (ts.Hours == 0)
                {
                    return string.Format("{0}:{1}.{2}", 
                        ts.Minutes.ToString("#0"),
                        ts.Seconds.ToString("00"),
                        ts.Milliseconds.ToString("000"));
                }
                return string.Format("{0}:{1}:{2}.{3}",
                    ts.Hours.ToString("#0"),
                    ts.Minutes.ToString("00"),
                    ts.Seconds.ToString("00"),
                    ts.Milliseconds.ToString("000"));
            }

            return string.Empty;
        }

        #endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions