|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionAlthough 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 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 BackgroundThe 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 codeYou can create an instance of the 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 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 interestThe best thing about this class is that it implements events for everything including errors. In this way, we gain much efficiency. HistoryThis 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.
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||