Click here to Skip to main content
6,629,377 members and growing! (18,600 online)
Email Password   helpLost your password?
Multimedia » Audio and Video » Audio     Intermediate

Playing MP3s using MCI

By krazymir

An article on how to use MCI command strings to handle audio files. I have made a wrapper class for easier use.
C#, Windows, .NET 2.0VS2005, Dev
Posted:7 Jul 2006
Views:129,341
Bookmarked:81 times
Announcements
Loading...
 
Search    
Advanced Search
Add to IE Search
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
25 votes for this article.
Popularity: 6.15 Rating: 4.40 out of 5

1
1 vote, 4.0%
2
1 vote, 4.0%
3
6 votes, 24.0%
4
17 votes, 68.0%
5

Sample Image

Introduction

Although the .NET FCL is an excellent tool for developing web/XML services and Windows applications, and has outstanding capabilities in many ways, unfortunately, it lacks multimedia capabilities. This problem is solved by using DirectX's DirectSound for complicated sound tasks (surround systems, 3D sound, etc.), and MCI for more simple tasks. MCI stands for Media Control Interface, and it exists in Windows since the first Win3.11 with 32 bit code execution abilities (according to Microsoft). The functions that enable developers to benefit from this interface are compiled in the winmm.dll which is situated in the %windir%\system32 directory. By importing functions from this library, we get access to a variety of functions for playing Wav sounds, controlling the PC speaker, and of course, for using the MCI. The most important of all these functions is MCIERROR mciSendString(LPCTSTR lpszCommand,LPTSTR lpszReturnString,UINT cchReturn, HANDLE hwndCallback);. By using it, you can send/receive control strings for interacting with MCI, and in that way play virtually any kind of media - analog/digital video/audio, control multimedia devices, and much more.

As you can see, the MCI is very useful and is commonly used in Windows, but it has its down sides too. Its complicated to use, and is not object oriented. In case of errors, the mciSendString method returns an integer number corresponding to the error number. If everything goes well, it returns zero. Also, any return information is dumped into a buffer, the address of which is specified as the second argument of the function, and the length of the buffer is specified as the third argument. A wrapper class makes the job of opening/playing audio through MCI much more simple. I also added events that are fired on certain occasions, to improve the efficiency of the player.

Background

The original code of this class was downloaded form the net, and then I read the links below and extended it to have the full functionality of a MP3 player (the original class could only open and play files).

There are a few good articles on using MCI, but if you want to study it in depth, there is no better way than from MSDN.

Using the code

You can create an instance of the MP3Player quite simply:

Media.MP3Player mplayer = new MP3Player();

After that, we can open, play, pause, stop, and close a file like this:

mplayer.Open(@"C:\something.mp3");
mplayer.Play();
mplayer.Pause();
mplayer.Stop();
mplayer.Close();

You can register for a certain event that the class exposes, for example:

mplayer.OpenFile+=new MP3Player.OpenFileEventHandler(mplayer_OpenFile);

And then, write a method to handle the event. The Open event has a file name in its EventArgs, so you can get the name of the file that is being opened.

void mplayer_OpenFile(Object sender, OpenFileEventArgs e)
{
    trackBar1.Maximum = (int)(mplayer.AudioLength/1000);
    this.Text = e.FileName;
    trackBar1.Value = 0;
    timer1.Enabled = false;
}

Here is the complete code of the class:

using System;
using System.Text;
using System.Runtime.InteropServices;

namespace Media
{

    public class OpenFileEventArgs : EventArgs
    {
        public OpenFileEventArgs(string filename)
        {
            this.FileName = filename;
        }
        public readonly string FileName;
    }

    public class PlayFileEventArgs : EventArgs
    {
        public PlayFileEventArgs()
        {
        }
    }

    public class PauseFileEventArgs : EventArgs
    {
        public PauseFileEventArgs()
        {
        }
    }

    public class StopFileEventArgs : EventArgs
    {
        public StopFileEventArgs()
        {
        }
    }

    public class CloseFileEventArgs : EventArgs
    {
        public CloseFileEventArgs()
        {
        }
    }

    public class ErrorEventArgs : EventArgs
    {
        public ErrorEventArgs(long Err)
        {
            this.ErrNum = Err;
        }

        public readonly long ErrNum;
    }


    public class MP3Player
    {
        private string Pcommand,FName;
        private bool Opened, Playing, Paused, Loop, 
                     MutedAll, MutedLeft, MutedRight;
        private int rVolume, lVolume, aVolume, 
                    tVolume, bVolume, VolBalance;
        private ulong Lng;
        private long Err;

        [DllImport("winmm.dll")]
        private static extern long mciSendString(string strCommand, 
                StringBuilder strReturn, int iReturnLength, 
                IntPtr hwndCallback);

        public MP3Player()
        {
            Opened = false;
            Pcommand = "";
            FName = "";
            Playing = false;
            Paused = false;
            Loop = false;
            MutedAll = MutedLeft = MutedRight = false;
            rVolume = lVolume = aVolume = 
                      tVolume = bVolume = 1000;
            Lng = 0;
            VolBalance = 0;
            Err = 0;
        }

        #region Volume
        public bool MuteAll
        {
            get
            {
                return MutedAll;
            }
            set
            {
                MutedAll = value;
                if (MutedAll)
                {
                    Pcommand = "setaudio MediaFile off";
                    if((Err=mciSendString(Pcommand, null, 0, IntPtr.Zero))!=0)
                        OnError(new ErrorEventArgs(Err));
                }
                else
                {
                    Pcommand = "setaudio MediaFile on";
                    if((Err=mciSendString(Pcommand, null, 0, IntPtr.Zero))!=0)
                        OnError(new ErrorEventArgs(Err));
                }
            }

        }

        public bool MuteLeft
        {
            get
            {
                return MutedLeft;
            }
            set
            {
                MutedLeft = value;
                if (MutedLeft)
                {
                    Pcommand = "setaudio MediaFile left off";
                    if((Err=mciSendString(Pcommand, null, 0, IntPtr.Zero))!=0)
                        OnError(new ErrorEventArgs(Err));
                }
                else
                {
                    Pcommand = "setaudio MediaFile left on";
                    if((Err=mciSendString(Pcommand, null, 0, IntPtr.Zero))!=0)
                        OnError(new ErrorEventArgs(Err));
                }
            }

        }

        public bool MuteRight
        {
            get
            {
                return MutedRight;
            }
            set
            {
                MutedRight = value;
                if (MutedRight)
                {
                    Pcommand = "setaudio MediaFile right off";
                    if((Err=mciSendString(Pcommand, null, 0, IntPtr.Zero))!=0)
                        OnError(new ErrorEventArgs(Err));
                }
                else
                {
                    Pcommand = "setaudio MediaFile right on";
                    if((Err=mciSendString(Pcommand, null, 0, IntPtr.Zero))!=0)
                        OnError(new ErrorEventArgs(Err));
                }
            }

        }

        public int VolumeAll
        {
            get
            {
                return aVolume;
            }
            set
            {
                if (Opened && (value >= 0 && value <= 1000))
                {
                    aVolume = value;
                    Pcommand = String.Format("setaudio MediaFile" + 
                               " volume to {0}", aVolume);
                    if((Err=mciSendString(Pcommand, null, 0, 
                                          IntPtr.Zero))!=0)
                        OnError(new ErrorEventArgs(Err));
                }
            }
        }

        public int VolumeLeft
        {
            get
            {
                return lVolume;
            }
            set
            {
                if (Opened && (value >= 0 && value <= 1000))
                {
                    lVolume = value;
                    Pcommand = String.Format("setaudio MediaFile" + 
                               " left volume to {0}", lVolume);
                    if((Err=mciSendString(Pcommand, null, 0, 
                                           IntPtr.Zero))!=0)
                        OnError(new ErrorEventArgs(Err));
                }
            }
        }

        public int VolumeRight
        {
            get
            {
                return rVolume;
            }
            set
            {
                if (Opened && (value >= 0 && value <= 1000))
                {
                    rVolume = value;
                    Pcommand = String.Format("setaudio" + 
                               " MediaFile right volume to {0}", rVolume);
                    if((Err=mciSendString(Pcommand, null, 0, IntPtr.Zero))!=0)
                        OnError(new ErrorEventArgs(Err));
                }
            }
        }

        public int VolumeTreble
        {
            get
            {
                return tVolume;
            }
            set
            {
                if (Opened && (value >= 0 && value <= 1000))
                {
                    tVolume = value;
                    Pcommand = String.Format("setaudio MediaFile" + 
                                             " treble to {0}", tVolume);
                    if((Err=mciSendString(Pcommand, null, 0, IntPtr.Zero))!=0)
                        OnError(new ErrorEventArgs(Err));
                }
            }
        }

        public int VolumeBass
        {
            get
            {
                return bVolume;
            }
            set
            {
                if (Opened && (value >= 0 && value <= 1000))
                {
                    bVolume = value;
                    Pcommand = String.Format("setaudio MediaFile bass to {0}", 
                                             bVolume);
                    if((Err=mciSendString(Pcommand, null, 0, IntPtr.Zero))!=0)
                        OnError(new ErrorEventArgs(Err));
                }
            }
        }

        public int Balance
        {
            get
            {
                return VolBalance;
            }
            set
            {
                if (Opened && (value >= -1000 && value <= 1000))
                {
                    VolBalance = value;
                    if (value < 0)
                    {
                        Pcommand = "setaudio MediaFile left volume to 1000";
                        if((Err=mciSendString(Pcommand, null, 0, IntPtr.Zero))!=0)
                            OnError(new ErrorEventArgs(Err));
                        Pcommand = String.Format("setaudio MediaFile right" + 
                                                 " volume to {0}", 1000 + value);
                        if((Err=mciSendString(Pcommand, null, 0, IntPtr.Zero))!=0)
                            OnError(new ErrorEventArgs(Err));
                    }
                    else
                    {
                        Pcommand = "setaudio MediaFile right volume to 1000";
                        if((Err=mciSendString(Pcommand, null, 0, IntPtr.Zero))!=0)
                            OnError(new ErrorEventArgs(Err));
                        Pcommand = String.Format("setaudio MediaFile" + 
                                   " left volume to {0}", 1000 - value);
                        if((Err=mciSendString(Pcommand, null, 0, IntPtr.Zero))!=0)
                            OnError(new ErrorEventArgs(Err));
                    }
                }
            }
        }
        #endregion

        #region Main Functions

        public string FileName
        {
            get
            {
                return FName;
            }
        }

        public bool Looping
        {
            get
            {
                return Loop;
            }
            set
            {
                Loop = value;
            }
        }

        public void Seek(ulong Millisecs)
        {
            if (Opened && Millisecs <= Lng)
            {
                if (Playing)
                {
                    if (Paused)
                    {
                        Pcommand = String.Format("seek MediaFile to {0}", Millisecs);
                        if((Err=mciSendString(Pcommand, null, 0, IntPtr.Zero))!=0)
                            OnError(new ErrorEventArgs(Err));
                    }
                    else
                    {
                        Pcommand = String.Format("seek MediaFile to {0}", Millisecs);
                        if((Err=mciSendString(Pcommand, null, 0, IntPtr.Zero))!=0)
                            OnError(new ErrorEventArgs(Err));
                        Pcommand = "play MediaFile";
                        if((Err=mciSendString(Pcommand, null, 0, IntPtr.Zero))!=0)
                            OnError(new ErrorEventArgs(Err));
                    }
                }
            }
        }

        private void CalculateLength()
        {
            StringBuilder str = new StringBuilder(128);
            mciSendString("status MediaFile length", str, 128, IntPtr.Zero);
            Lng = Convert.ToUInt64(str.ToString());
        }

        public ulong AudioLength
        {
            get
            {
                if (Opened) return Lng;
                else return 0;
            }
        }

        public void Close()
        {
            if (Opened)
            {
                Pcommand = "close MediaFile";
                if((Err=mciSendString(Pcommand, null, 0, IntPtr.Zero))!=0)
                    OnError(new ErrorEventArgs(Err));
                Opened = false;
                Playing = false;
                Paused = false;
                OnCloseFile(new CloseFileEventArgs());
            }
        }

        public void Open(string sFileName)
        {
            if (!Opened)
            {
                Pcommand = "open \"" + sFileName + 
                           "\" type mpegvideo alias MediaFile";
                if((Err=mciSendString(Pcommand, null, 0, IntPtr.Zero))!=0)
                    OnError(new ErrorEventArgs(Err));
                FName = sFileName;
                Opened = true;
                Playing = false;
                Paused = false;
                Pcommand = "set MediaFile time format milliseconds";
                if((Err=mciSendString(Pcommand, null, 0, IntPtr.Zero))!=0)
                    OnError(new ErrorEventArgs(Err));
                Pcommand = "set MediaFile seek exactly on";
                if((Err=mciSendString(Pcommand, null, 0, IntPtr.Zero))!=0)
                    OnError(new ErrorEventArgs(Err));
                CalculateLength();
                OnOpenFile(new OpenFileEventArgs(sFileName));
            }
            else
            {
                this.Close();
                this.Open(sFileName);
            }
        }

        public void Play()
        {
            if (Opened)
            {
                if (!Playing)
                {
                    Playing = true;
                    Pcommand = "play MediaFile";
                    if (Loop) Pcommand += " REPEAT";
                    if((Err=mciSendString(Pcommand, null, 0, IntPtr.Zero))!=0)
                        OnError(new ErrorEventArgs(Err));
                    OnPlayFile(new PlayFileEventArgs());
                }
                else
                {
                    if (!Paused)
                    {
                        Pcommand = "seek MediaFile to start";
                        if((Err=mciSendString(Pcommand, null, 0, IntPtr.Zero))!=0)
                            OnError(new ErrorEventArgs(Err));
                        Pcommand = "play MediaFile";
                        if((Err=mciSendString(Pcommand, null, 0, IntPtr.Zero))!=0)
                            OnError(new ErrorEventArgs(Err));
                        OnPlayFile(new PlayFileEventArgs());
                    }
                    else
                    {
                        Paused = false;
                        Pcommand = "play MediaFile";
                        if((Err=mciSendString(Pcommand, null, 0, IntPtr.Zero))!=0)
                            OnError(new ErrorEventArgs(Err));
                        OnPlayFile(new PlayFileEventArgs());
                    }
                }
            }
        }

        public void Pause()
        {
            if (Opened)
            {
                if (!Paused)
                {
                    Paused = true;
                    Pcommand = "pause MediaFile";
                    if((Err=mciSendString(Pcommand, null, 0, IntPtr.Zero))!=0)
                        OnError(new ErrorEventArgs(Err));
                    OnPauseFile(new PauseFileEventArgs());
                }
                else
                {
                    Paused = false;
                    Pcommand = "play MediaFile";
                    if((Err=mciSendString(Pcommand, null, 0, IntPtr.Zero))!=0)
                        OnError(new ErrorEventArgs(Err));
                    OnPlayFile(new PlayFileEventArgs());
                }
            }
        }

        public void Stop()
        {
            if (Opened && Playing)
            {
                Playing = false;
                Paused = false;
                Pcommand = "seek MediaFile to start";
                if((Err=mciSendString(Pcommand, null, 0, IntPtr.Zero))!=0)
                    OnError(new ErrorEventArgs(Err));
                Pcommand = "stop MediaFile";
                if((Err=mciSendString(Pcommand, null, 0, IntPtr.Zero))!=0)
                    OnError(new ErrorEventArgs(Err));
                OnStopFile(new StopFileEventArgs());
            }
        }

        public ulong CurrentPosition
        {
            get
            {
                if (Opened && Playing)
                {
                    StringBuilder s = new StringBuilder(128);
                    Pcommand = "status MediaFile position";
                    if((Err=mciSendString(Pcommand, s, 128, IntPtr.Zero))!=0)
                        OnError(new ErrorEventArgs(Err));
                    return Convert.ToUInt64(s.ToString());
                }
                else return 0;
            }
        }

#endregion

        #region Event Handling

        public delegate void OpenFileEventHandler(Object sender, 
                             OpenFileEventArgs oea);

        public delegate void PlayFileEventHandler(Object sender, 
                             PlayFileEventArgs pea);

        public delegate void PauseFileEventHandler(Object sender, 
                             PauseFileEventArgs paea);

        public delegate void StopFileEventHandler(Object sender, 
                                         StopFileEventArgs sea);

        public delegate void CloseFileEventHandler(Object sender, 
                                         CloseFileEventArgs cea);

        public delegate void ErrorEventHandler(Object sender, 
                                         ErrorEventArgs eea);

        public event OpenFileEventHandler OpenFile;

        public event PlayFileEventHandler PlayFile;

        public event PauseFileEventHandler PauseFile;

        public event StopFileEventHandler StopFile;

        public event CloseFileEventHandler CloseFile;

        public event ErrorEventHandler Error;

        protected virtual void OnOpenFile(OpenFileEventArgs oea)
        {
            if (OpenFile != null) OpenFile(this, oea);
        }

        protected virtual void OnPlayFile(PlayFileEventArgs pea)
        {
            if (PlayFile != null) PlayFile(this, pea);
        }

        protected virtual void OnPauseFile(PauseFileEventArgs paea)
        {
            if (PauseFile != null) PauseFile(this, paea);
        }

        protected virtual void OnStopFile(StopFileEventArgs sea)
        {
            if (StopFile != null) StopFile(this, sea);
        }

        protected virtual void OnCloseFile(CloseFileEventArgs cea)
        {
            if (CloseFile != null) CloseFile(this, cea);
        }

        protected virtual void OnError(ErrorEventArgs eea)
        {
            if (Error != null) Error(this, eea);
        }

        #endregion
    }
}

Points of interest

The best thing about this class is that it implements events for everything including errors. In this way, we gain much efficiency.

History

This is the first version of this class. After debugging and adding some capabilities according to your requests, I hope that it will become a good way to play MP3s using .NET.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

krazymir


Member
I have just graduated from the Technical University of Garbovo, Bulgaria as an Engineer in Computer Science and Technology.
Occupation: Web Developer
Location: Bulgaria Bulgaria

Other popular Audio and Video articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 25 of 51 (Total in Forum: 51) (Refresh)FirstPrevNext
GeneralMy vote of 2 PinmemberOmgffsmlladen14:07 12 Nov '09  
Generalminor fix PinmemberSteven A. Lowe11:28 29 Jun '09  
GeneralUsing mciSendString in thread can not work Pinmembersshawn18:59 17 May '09  
GeneralSome additional bug Pinmemberholymortyr2:15 4 Apr '09  
GeneralUse of MCI_NOTIFY flag Pinmemberluismdelgado15:30 23 Aug '08  
GeneralAdditional Error Reporting - mciGetErrorString PinmemberLnocaSteve6:59 6 Aug '08  
Generalthe Loop doesn't work !! PinmemberFaisalFahd4:14 1 Aug '08  
GeneralPlayer classes Pinmemberfloozen10:54 1 Jul '08  
GeneralIncreese and decreese of Voice files Pinmembersanaz parvizkhani21:15 26 Apr '08  
GeneralYour player does so much more (You may want to change the title of the article) PinmemberMember 47074849:40 9 Mar '08  
GeneralKudos PinmemberMember 47074849:03 9 Mar '08  
GeneralIncorrect Track Length PinmemberLeon Barnard12:26 22 Dec '07  
GeneralRe: Incorrect Track Length PinmemberReza Ghorbani7:29 13 Feb '08  
AnswerRe: Incorrect Track Length (Nasty solution) PinmemberTHE DDDD7:40 16 Mar '08  
QuestionHow can I play two files in at the sametime??? PinmemberIbrahim Dwaikat11:28 23 Oct '07  
AnswerRe: How can I play two files in at the sametime??? Pinmemberkrazymir20:23 23 Oct '07  
GeneralRe: How can I play two files in at the sametime??? PinmemberIbrahim Dwaikat13:30 25 Oct '07  
QuestionRe: How can I play two files in at the sametime??? PinmemberIbrahim Dwaikat9:59 7 Nov '07  
GeneralRe: How can I play two files in at the sametime??? Pinmembermycsharpcorner9:33 26 Nov '07  
GeneralErrors while opening MP3 file PinmemberHJPhilippi3:37 8 Aug '07  
GeneralRe: Errors while opening MP3 file Pinmemberkrazymir3:56 8 Aug '07  
GeneralRe: Errors while opening MP3 file PinmemberHJPhilippi6:43 8 Aug '07  
GeneralMultiple Audio Streams PinmemberHaydeng12:38 26 Jul '07  
GeneralHow to recoding to Mp3 or Wave file PinmemberLe Quoc Do18:53 12 Jul '07  
QuestionStreaming MP3? Pinmemberdfhgesart13:29 21 Jun '07  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 7 Jul 2006
Editor: Smitha Vijayan
Copyright 2006 by krazymir
Everything else Copyright © CodeProject, 1999-2009
Web19 | Advertise on the Code Project