ForeverZer0

MciPlayer

May 5th, 2012
419
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 32.37 KB | None | 0 0
  1. using System;
  2. using System.Diagnostics;
  3. using System.IO;
  4. using System.Runtime.CompilerServices;
  5. using System.Runtime.InteropServices;
  6. using System.Text;
  7.  
  8. namespace ForeverZer0.Audio
  9. {  
  10.     public class MciPlayer : IDisposable, IComparable<MciPlayer>
  11.     {
  12.         #region DLL Imports
  13.  
  14.         /// <summary>
  15.         /// Hook for sending MCI commands
  16.         /// </summary>
  17.         /// <param name="strCommand">The command to make</param>
  18.         /// <param name="strReturn">Any data returned by the command</param>
  19.         /// <param name="iReturnLength">The maximum size of the return data</param>
  20.         /// <param name="hwndCallback">A handle to a window that will recieve notifications</param>
  21.         /// <returns>The error code from the command</returns>
  22.         [DllImport("winmm.dll")]
  23.         private static extern long mciSendString(string strCommand, StringBuilder strReturn,
  24.             int iReturnLength, IntPtr hwndCallback);
  25.  
  26.         /// <summary>
  27.         /// Gets error messages associated with MCI error codes
  28.         /// </summary>
  29.         /// <param name="errCode">The MCI error code</param>
  30.         /// <param name="strReturn">Any data returned by the command</param>
  31.         /// <param name="iReturnLength">The maximum size of the return data</param>
  32.         /// <returns>Integer that represents true/false if call was successful</returns>
  33.         [DllImport("winmm.dll")]
  34.         public static extern int mciGetErrorString(int errCode, StringBuilder strReturn,
  35.             int iReturnLength);
  36.  
  37.         #endregion
  38.  
  39.         #region Constants
  40.  
  41.         /// <summary>
  42.         /// The size of the buffer to use for return values
  43.         /// </summary>
  44.         public const int BUFFER_SIZE = 128;
  45.  
  46.         #endregion
  47.  
  48.         #region Private Properties
  49.  
  50.         private string _name, _filename, _cmd, _errorMessage;
  51.         private StringBuilder _buffer, _errorBuffer, _log;
  52.         private IntPtr _windowHandle;
  53.         private bool _disposed;
  54.  
  55.         #endregion
  56.  
  57.         #region Public Properties
  58.  
  59.         /// <summary>
  60.         /// Gets or sets the master volume. Values outside of 0 to 1000 will be automatically corrected.
  61.         /// </summary>
  62.         public int Volume { get { return GetVolume(); } set { SetVolume(value); } }
  63.  
  64.         /// <summary>
  65.         /// Gets or sets the left volume. Values outside of 0 to 1000 will be automatically corrected.
  66.         /// </summary>
  67.         public int VolumeLeft { get { return GetVolumeLeft(); } set { SetVolumeLeft(value); } }
  68.  
  69.         /// <summary>
  70.         /// Gets or sets the right volume. Values outside of 0 to 1000 will be automatically corrected.
  71.         /// </summary>
  72.         public int VolumeRight { get { return GetVolumeRight(); } set { SetVolumeRight(value); } }
  73.  
  74.         /// <summary>
  75.         /// Gets or sets the speed of playaback. Values outside of 0 to 2000 will be automatically corrected.
  76.         /// </summary>
  77.         public int Speed { get { return GetSpeed(); } set { SetSpeed(value); } }
  78.  
  79.         /// <summary>
  80.         /// Gets or sets the treble. Values outside of 0 to 2000 will be automatically corrected.
  81.         /// </summary>
  82.         public int Treble { get { return GetTreble(); } set { SetTreble(value); } }
  83.  
  84.         /// <summary>
  85.         /// Gets or sets the bass. Values outside of 0 to 2000 will be automatically corrected.
  86.         /// </summary>
  87.         public int Bass { get { return GetBass(); } set { SetBass(value); } }
  88.  
  89.         /// <summary>
  90.         /// Gets or sets the current millisecond position of playback
  91.         /// </summary>
  92.         public long Position { get { return GetPosition(); } set { SetPosition(value); } }
  93.  
  94.         /// <summary>
  95.         /// Gets the length of the file in milliseconds
  96.         /// </summary>
  97.         public long Length { get { return GetLength(); } }
  98.  
  99.         /// <summary>
  100.         /// Gets or sets the path of the current file.
  101.         /// </summary>
  102.         public string Filename { get { return _filename; } set { Load(value); } }
  103.  
  104.         /// <summary>
  105.         /// Gets or sets repeat mode
  106.         /// </summary>
  107.         public bool Repeat { get; set; }
  108.  
  109.         /// <summary>
  110.         /// Gets the status of the mixer as a string
  111.         /// </summary>
  112.         public MciStatus Status { get { return GetStatus(); } }
  113.  
  114.         /// <summary>
  115.         /// Gets or sets the window handle that will receive notifications
  116.         /// </summary>
  117.         public IntPtr WindowHandle { get { return _windowHandle; } set { _windowHandle = value; } }
  118.  
  119.         /// <summary>
  120.         /// Enables logging functions for the mixer.
  121.         /// </summary>
  122.         /// <remarks>Having logging enabled can degrade performance</remarks>
  123.         public bool LoggingEnabled { get; set; }
  124.  
  125.         /// <summary>
  126.         /// Gets the log buffer as a string
  127.         /// </summary>
  128.         public string Log { get { return _log.ToString(); } }
  129.  
  130.         #endregion
  131.  
  132.         #region Construction
  133.  
  134.         /// <summary>
  135.         /// Creates and returns a new instance of the mixer
  136.         /// </summary>
  137.         /// <param name="name">The alias name of the mixer</param>
  138.         /// <param name="handle">The handle of the window to recieve notifications from the player</param>
  139.         public MciPlayer(string name, IntPtr handle)
  140.         {
  141.             _name = name;
  142.             _buffer = new StringBuilder(BUFFER_SIZE);
  143.             _errorBuffer = new StringBuilder(BUFFER_SIZE);
  144.             _windowHandle = handle;
  145.             _disposed = false;
  146.             _log = new StringBuilder();
  147.         }
  148.  
  149.         /// <summary>
  150.         /// Creates and returns a new instance of the mixer
  151.         /// </summary>
  152.         /// <param name="name">The alias name of the mixer</param>
  153.         public MciPlayer(string name) : this(name, IntPtr.Zero) { }
  154.  
  155.         #endregion
  156.  
  157.         #region Playback Control
  158.  
  159.         /// <summary>
  160.         /// Loads a file and readies it for playback
  161.         /// </summary>
  162.         /// <param name="filename">The path to the file</param>
  163.         public void Load(string filename)
  164.         {
  165.             if (_disposed)
  166.                 throw new ObjectDisposedException(_name);
  167.             this.Close();
  168.             _filename = filename;
  169.             _cmd = String.Format("open \"{0}\" type mpegvideo alias {1} notify", _filename, _name);
  170.             LogError(mciSendString(_cmd, null, 0, WindowHandle));
  171.             OnOpen(new OnOpenEventArgs(_filename));
  172.         }
  173.  
  174.         /// <summary>
  175.         /// Begins playback of a loaded file
  176.         /// </summary>
  177.         /// <param name="repeat">Flag to repeat playback when file is done playing</param>
  178.         /// <param name="position">The millisecond to begin playback at</param>
  179.         public void Play(bool repeat, int position)
  180.         {
  181.             if (_disposed)
  182.                 throw new ObjectDisposedException(_name);
  183.             if (!File.Exists(_filename))
  184.                 return;
  185.             Repeat = repeat;
  186.             _cmd = String.Format("seek {0} to {1} notify", _name, position == 0 ? "start" : position.ToString());
  187.             LogError(mciSendString(_cmd, null, 0, WindowHandle));
  188.             _cmd = String.Format("play {0} notify{1}", _name, repeat ? " repeat" : "");
  189.             LogError(mciSendString(_cmd, null, 0, WindowHandle));
  190.             OnPlay(new OnPlayEventArgs(_filename, GetLength()));
  191.         }
  192.  
  193.         /// <summary>
  194.         /// Begins playback of a loaded file
  195.         /// </summary>
  196.         /// <param name="repeat">Flag to repeat playback when file is done playing</param>
  197.         public void Play(bool repeat) { Play(repeat, 0); }
  198.  
  199.         /// <summary>
  200.         /// Begins playback of a loaded file
  201.         /// </summary>
  202.         public void Play() { Play(false, 0); }
  203.  
  204.         /// <summary>
  205.         /// Pause playback while maintaining current position
  206.         /// </summary>
  207.         public void Pause()
  208.         {
  209.             _cmd = String.Format("pause {0} notify", _name);
  210.             LogError(mciSendString(_cmd, null, 0, WindowHandle));
  211.             OnPause(new OnPauseEventArgs(GetPosition(), false));
  212.         }
  213.  
  214.         /// <summary>
  215.         /// Resume playback on a paused mixer
  216.         /// </summary>
  217.         public void Resume()
  218.         {
  219.             _cmd = String.Format("resume {0} notify", _name);
  220.             LogError(mciSendString(_cmd, null, 0, WindowHandle));
  221.             OnPause(new OnPauseEventArgs(GetPosition(), true));
  222.         }
  223.  
  224.         /// <summary>
  225.         /// Sets the millisecond of the current playback position
  226.         /// </summary>
  227.         /// <param name="millisecond">The millisecond position</param>
  228.         public void Seek(long millisecond)
  229.         {
  230.             SetPosition(millisecond);
  231.         }
  232.  
  233.         /// <summary>
  234.         /// Stops playback and moves the current position back to the beginning of the file
  235.         /// </summary>
  236.         public void Stop()
  237.         {
  238.             _cmd = String.Format("seek {0} to start notify", _name);
  239.             LogError(mciSendString(_cmd, null, 0, WindowHandle));
  240.             _cmd = String.Format("stop {0} notify", _name);
  241.             LogError(mciSendString(_cmd, null, 0, WindowHandle));
  242.             OnStop(new EventArgs());
  243.         }
  244.  
  245.         /// <summary>
  246.         /// Stops playback and destroys the player
  247.         /// </summary>
  248.         public void Close()
  249.         {
  250.             _cmd = String.Format("close {0} notify", _name);
  251.             LogError(mciSendString(_cmd, null, 0, WindowHandle));
  252.             _filename = null;
  253.             OnClose(new EventArgs());
  254.         }
  255.  
  256.         /// <summary>
  257.         /// Closes any files opened in the mixer
  258.         /// </summary>
  259.         public void Dispose()
  260.         {
  261.             if (!_disposed)
  262.             {
  263.                 this.Close();
  264.                 _disposed = true;
  265.                 GC.SuppressFinalize(this);
  266.             }
  267.         }
  268.  
  269.         /// <summary>
  270.         /// Begins recording from the input
  271.         /// </summary>
  272.         /// <param name="bits">The bits per sample for the recording</param>
  273.         /// <param name="sampleRate">The sample rate of the recording</param>
  274.         /// <param name="channels">The number of channels of the recording</param>
  275.         public void Record(int bits, int sampleRate, int channels)
  276.         {
  277.             this.Close();
  278.             _cmd = String.Format("open new type waveaudio alias {0}", _name);
  279.             LogError(mciSendString(_cmd, null, 0, WindowHandle));
  280.             _cmd = String.Format("set {0} bitspersample {1}", _name, bits);
  281.             LogError(mciSendString(_cmd, null, 0, WindowHandle));
  282.             _cmd = String.Format("set {0} samplespersec {1}", _name, sampleRate);
  283.             LogError(mciSendString(_cmd, null, 0, WindowHandle));
  284.             _cmd = String.Format("set {0} channels {1}", _name, channels);
  285.             LogError(mciSendString(_cmd, null, 0, WindowHandle));
  286.             _cmd = String.Format("record {0} notify", _name);
  287.             LogError(mciSendString(_cmd, null, 0, WindowHandle));
  288.             OnRecord(new OnRecordEventArgs(bits, sampleRate, channels));
  289.         }
  290.  
  291.         /// <summary>
  292.         /// Begins recording from the input
  293.         /// </summary>
  294.         /// <param name="bits">The bits per sample for the recording</param>
  295.         /// <param name="sampleRate">The sample rate of the recording</param>
  296.         public void Record(int bits, int sampleRate) { Record(bits, sampleRate, 2); }
  297.  
  298.         /// <summary>
  299.         /// Begins recording from the input
  300.         /// </summary>
  301.         /// <param name="bits">The bits per sample for the recording</param>
  302.         public void Record(int bits) { Record(bits, 44100, 2); }
  303.  
  304.         /// <summary>
  305.         /// Begins recording from the input
  306.         /// </summary>
  307.         public void Record() { Record(16, 44100, 2); }
  308.  
  309.         /// <summary>
  310.         /// Saves a recorded file to disk in WAV format
  311.         /// </summary>
  312.         /// <param name="filename">The path of the file to save</param>
  313.         /// <remarks>The WAV extension will be added if path does not have it</remarks>
  314.         public void SaveRecording(string filename)
  315.         {
  316.             if (IsRecording())
  317.                 this.Stop();
  318.             string ext = Path.GetExtension(filename);
  319.             if (ext != ".wav")
  320.             {
  321.                 filename = Path.Combine(Path.GetDirectoryName(filename),
  322.                     Path.GetFileNameWithoutExtension(filename) + ".wav");
  323.             }
  324.             _cmd = String.Format("save {0} {1}", _name, filename);
  325.             LogError(mciSendString(_cmd, null, 0, WindowHandle));
  326.             _cmd = String.Format("close {0}", _name);
  327.             LogError(mciSendString(_cmd, null, 0, WindowHandle));
  328.         }
  329.  
  330.         /// <summary>
  331.         /// Mutes/unmutes all sound while continuing to play
  332.         /// </summary>
  333.         /// <param name="on">Flag to enable/disable sound</param>
  334.         public void Mute(bool on)
  335.         {
  336.             _cmd = String.Format("setaudio {0} {1}", _name, on ? "off" : "on");
  337.             LogError(mciSendString(_cmd, null, 0, WindowHandle));
  338.         }
  339.  
  340.         /// <summary>
  341.         /// Mutes/unmutes all sound on the left channel while continuing to play
  342.         /// </summary>
  343.         /// <param name="on">Flag to enable/disable sound</param>
  344.         public void MuteLeft(bool on)
  345.         {
  346.             _cmd = String.Format("setaudio {0} left {1}", _name, on ? "off" : "on");
  347.             LogError(mciSendString(_cmd, null, 0, WindowHandle));
  348.         }
  349.  
  350.         /// <summary>
  351.         /// Mutes/unmutes all sound on the right channel while continuing to play
  352.         /// </summary>
  353.         /// <param name="on">Flag to enable/disable sound</param>
  354.         public void MuteRight(bool on)
  355.         {
  356.             _cmd = String.Format("setaudio {0} right {1}", _name, on ? "off" : "on");
  357.             LogError(mciSendString(_cmd, null, 0, WindowHandle));
  358.         }
  359.  
  360.         #endregion
  361.  
  362.         #region Setters
  363.  
  364.         /// <summary>
  365.         /// Sets the master volume of the mixer
  366.         /// </summary>
  367.         /// <param name="volume">The volume to set. A value between 0 and 1000.
  368.         /// Values outside this range will be automatically corrected</param>
  369.         public void SetVolume(int volume)
  370.         {
  371.             volume = Clamp<int>(volume, 0, 1000);
  372.             _cmd = String.Format("setaudio {0} volume to {1} notify", _name, volume);
  373.             LogError(mciSendString(_cmd, null, 0, WindowHandle));  
  374.         }
  375.  
  376.         /// <summary>
  377.         /// Sets the left volume of the mixer
  378.         /// </summary>
  379.         /// <param name="volume">The volume to set. A value between 0 and 1000.
  380.         /// Values outside this range will be automatically corrected</param>
  381.         public void SetVolumeLeft(int volume)
  382.         {
  383.             volume = Clamp<int>(volume, 0, 1000);
  384.             _cmd = String.Format("setaudio {0} left volume to {1} notify", _name, volume);
  385.             LogError(mciSendString(_cmd, null, 0, WindowHandle));
  386.         }
  387.  
  388.         /// <summary>
  389.         /// Sets the right volume of the mixer
  390.         /// </summary>
  391.         /// <param name="volume">The volume to set. A value between 0 and 1000.
  392.         /// Values outside this range will be automatically corrected</param>
  393.         public void SetVolumeRight(int volume)
  394.         {
  395.             volume = Clamp<int>(volume, 0, 1000);
  396.             _cmd = String.Format("setaudio {0} right volume to {1} notify", _name, volume);
  397.             LogError(mciSendString(_cmd, null, 0, WindowHandle));
  398.         }
  399.  
  400.         /// <summary>
  401.         /// Sets the playback speed of the mixer
  402.         /// </summary>
  403.         /// <param name="volume">The speed ratio to set. A value between 0 and 2000, where 1000 is normal.
  404.         /// Values outside this range will be automatically corrected</param>
  405.         public void SetSpeed(int speed)
  406.         {
  407.             speed = Clamp<int>(speed, 0, 2000);
  408.             _cmd = String.Format("set {0} speed {1} notify", _name, speed);
  409.             LogError(mciSendString(_cmd, null, 0, WindowHandle));
  410.         }
  411.  
  412.         /// <summary>
  413.         /// Sets the treble of the mixer
  414.         /// </summary>
  415.         /// <param name="volume">The treble value to set. A value between 0 and 2000, where 1000 is normal.
  416.         /// Values outside this range will be automatically corrected</param>
  417.         public void SetTreble(int treble)
  418.         {
  419.             treble = Clamp<int>(treble, 0, 1000);
  420.             _cmd = String.Format("setaudio {0} treble to {1} notify", _name, treble);
  421.             LogError(mciSendString(_cmd, null, 0, WindowHandle));
  422.         }
  423.  
  424.         /// <summary>
  425.         /// Sets the bass of the mixer
  426.         /// </summary>
  427.         /// <param name="volume">The bass value to set. A value between 0 and 2000, where 1000 is normal.
  428.         /// Values outside this range will be automatically corrected</param>
  429.         public void SetBass(int bass)
  430.         {
  431.             bass = Clamp<int>(bass, 0, 1000);
  432.             _cmd = String.Format("setaudio {0} bass to {1} notify", _name, bass);
  433.             LogError(mciSendString(_cmd, null, 0,  WindowHandle));
  434.         }
  435.  
  436.         /// <summary>
  437.         /// Sets the millisecond of the current playback position
  438.         /// </summary>
  439.         /// <param name="position">The millisecond position</param>
  440.         public void SetPosition(long position)
  441.         {
  442.             long current = GetPosition();
  443.             position = Clamp<long>(position, 0, this.GetLength());
  444.             _cmd = String.Format("{0} {1} from {2} notify", IsPlaying() ? "play" : "seek", _name, position);
  445.             LogError(mciSendString(_cmd, null, 0, WindowHandle));
  446.             OnSeek(new OnSeekEventArgs(current, position));
  447.         }
  448.  
  449.         #endregion
  450.  
  451.         #region Getters
  452.  
  453.         /// <summary>
  454.         /// Gets the master volume (0 - 1000)
  455.         /// </summary>
  456.         /// <returns>The master volume</returns>
  457.         public int GetVolume()
  458.         {
  459.             _buffer.Clear();
  460.             _cmd = String.Format("status {0} volume", _name);
  461.             LogError(mciSendString(_cmd, _buffer, BUFFER_SIZE, IntPtr.Zero));
  462.             string value = _buffer.ToString();
  463.             if (String.IsNullOrEmpty(value))
  464.                 return 0;
  465.             return Convert.ToInt32(value);
  466.         }
  467.  
  468.         /// <summary>
  469.         /// Gets the volume of the left channel only (0 - 1000)
  470.         /// </summary>
  471.         /// <returns>The left channel volume</returns>
  472.         public int GetVolumeLeft()
  473.         {
  474.             _buffer.Clear();
  475.             _cmd = String.Format("status {0} volume left", _name);
  476.             LogError(mciSendString(_cmd, _buffer, BUFFER_SIZE, IntPtr.Zero));
  477.             string value = _buffer.ToString();
  478.             if (String.IsNullOrEmpty(value))
  479.                 return 0;
  480.             return Convert.ToInt32(value);
  481.         }
  482.  
  483.         /// <summary>
  484.         /// Gets the volume of the right channel only (0 - 1000)
  485.         /// </summary>
  486.         /// <returns>The right channel volume</returns>
  487.         public int GetVolumeRight()
  488.         {
  489.             _buffer.Clear();
  490.             _cmd = String.Format("status {0} volume right", _name);
  491.             LogError(mciSendString(_cmd, _buffer, BUFFER_SIZE, IntPtr.Zero));
  492.             string value = _buffer.ToString();
  493.             if (String.IsNullOrEmpty(value))
  494.                 return 0;
  495.             return Convert.ToInt32(value);
  496.         }
  497.  
  498.         /// <summary>
  499.         /// Gets the speed of playback (1000 = normal speed)(0 - 2000)
  500.         /// </summary>
  501.         /// <returns>The speed of playback</returns>
  502.         public int GetSpeed()
  503.         {
  504.             _buffer.Clear();
  505.             _cmd = String.Format("status {0} speed", _name);
  506.             LogError(mciSendString(_cmd, _buffer, BUFFER_SIZE, IntPtr.Zero));
  507.             string value = _buffer.ToString();
  508.             if (String.IsNullOrEmpty(value))
  509.                 return 0;
  510.             return Convert.ToInt32(value);
  511.         }
  512.  
  513.         /// <summary>
  514.         /// Gets the treble volume (0 - 2000)
  515.         /// </summary>
  516.         /// <returns>The treble volume</returns>
  517.         public int GetTreble()
  518.         {
  519.             _buffer.Clear();
  520.             _cmd = String.Format("status {0} treble", _name);
  521.             LogError(mciSendString(_cmd, _buffer, BUFFER_SIZE, IntPtr.Zero));
  522.             string value = _buffer.ToString();
  523.             if (String.IsNullOrEmpty(value))
  524.                 return 0;
  525.             return Convert.ToInt32(value);
  526.         }
  527.  
  528.         /// <summary>
  529.         /// Gets the bass volume (0 - 2000)
  530.         /// </summary>
  531.         /// <returns>The bass volume</returns>
  532.         public int GetBass()
  533.         {
  534.             _buffer.Clear();
  535.             _cmd = String.Format("status {0} bass", _name);
  536.             LogError(mciSendString(_cmd, _buffer, BUFFER_SIZE, IntPtr.Zero));
  537.             string value = _buffer.ToString();
  538.             if (String.IsNullOrEmpty(value))
  539.                 return 0;
  540.             return Convert.ToInt32(value);
  541.         }
  542.  
  543.         /// <summary>
  544.         /// Gets the current position of playback in milliseconds
  545.         /// </summary>
  546.         /// <returns>The current position</returns>
  547.         public long GetPosition()
  548.         {
  549.             _buffer.Clear();
  550.             if (IsPlaying() || IsPaused())
  551.             {
  552.                 _cmd = String.Format("status {0} position", _name);
  553.                 LogError(mciSendString(_cmd, _buffer, BUFFER_SIZE, IntPtr.Zero));
  554.                 string value = _buffer.ToString();
  555.                 if (String.IsNullOrEmpty(value))
  556.                     return 0L;
  557.                 return Convert.ToInt64(value);
  558.             }
  559.             return 0L;
  560.         }
  561.  
  562.         /// <summary>
  563.         /// Gets the length of the currently opened file in milliseconds
  564.         /// </summary>
  565.         /// <returns>The number of milliseconds of the file as <paramref name="System.Int64"/></returns>
  566.         public long GetLength()
  567.         {
  568.             _buffer.Clear();
  569.             _cmd = String.Format("status {0} length", _name);
  570.             LogError(mciSendString(_cmd, _buffer, BUFFER_SIZE, IntPtr.Zero));
  571.             string value = _buffer.ToString();
  572.             if (String.IsNullOrEmpty(value))
  573.                 return 0L;
  574.             return Convert.ToInt64(value);
  575.         }
  576.  
  577.         /// <summary>
  578.         /// Gets the volume of the left channel
  579.         /// </summary>
  580.         /// <returns>The volume of the left channel as a <paramref name="System.Int32"/></returns>
  581.         public int GetLeftVolume()
  582.         {
  583.             _buffer.Clear();
  584.             _cmd = String.Format("status {0} left volume", _name);
  585.             LogError(mciSendString(_cmd, _buffer, BUFFER_SIZE, IntPtr.Zero));
  586.             string value = _buffer.ToString();
  587.             if (String.IsNullOrEmpty(value))
  588.                 return 0;
  589.             return Convert.ToInt32(value);
  590.         }
  591.  
  592.         /// <summary>
  593.         /// Gets the volume of the right channel
  594.         /// </summary>
  595.         /// <returns>The volume of the right channel as a <paramref name="System.Int32"/></returns>
  596.         public int GetRightVolume()
  597.         {
  598.             _buffer.Clear();
  599.             _cmd = String.Format("status {0} right volume", _name);
  600.             LogError(mciSendString(_cmd, _buffer, BUFFER_SIZE, IntPtr.Zero));
  601.             string value = _buffer.ToString();
  602.             if (String.IsNullOrEmpty(value))
  603.                 return 0;
  604.             return Convert.ToInt32(value);
  605.         }
  606.  
  607.         #endregion
  608.  
  609.         #region Status
  610.  
  611.         /// <summary>
  612.         /// Gets the "playing" state of the mixer
  613.         /// </summary>
  614.         /// <returns>The "plaing" state of the mixer as <paramref name="System.Bool"/></returns>
  615.         public bool IsPlaying()
  616.         {
  617.             return this.GetStatus() == MciStatus.Playing;
  618.         }
  619.  
  620.         /// <summary>
  621.         /// Gets the "pause" state of the mixer
  622.         /// </summary>
  623.         /// <returns>The "pause" state of the mixer as <paramref name="System.Bool"/></returns>
  624.         public bool IsPaused()
  625.         {
  626.             return this.GetStatus() == MciStatus.Paused;
  627.         }
  628.  
  629.         /// <summary>
  630.         /// Gets the "recording" state of the mixer
  631.         /// </summary>
  632.         /// <returns>The "recording" state of the mixer as <paramref name="System.Bool"/></returns>
  633.         public bool IsRecording()
  634.         {
  635.             return this.GetStatus() == MciStatus.Recording;
  636.         }
  637.  
  638.         /// <summary>
  639.         /// Gets the current status of the mixer
  640.         /// </summary>
  641.         /// <returns>The current state of the mixer as a <paramref name="MCI_Player.MciStatus"/></returns>
  642.         public MciStatus GetStatus()
  643.         {
  644.             _buffer.Clear();
  645.             _cmd = String.Format("status {0} mode", _name);
  646.             LogError(mciSendString(_cmd, _buffer, BUFFER_SIZE, IntPtr.Zero));
  647.             switch (_buffer.ToString().Trim())
  648.             {
  649.                 case "playing": return MciStatus.Playing;
  650.                 case "not ready": return MciStatus.NotReady;
  651.                 case "paused": return MciStatus.Paused;
  652.                 case "recording": return MciStatus.Recording;
  653.                 case "seeking": return MciStatus.Seeking;
  654.                 case "parked": return MciStatus.Parked;
  655.                 case "open": return MciStatus.Open;
  656.                 default: return MciStatus.Stopped;
  657.             }
  658.         }
  659.  
  660.         #endregion
  661.  
  662.         #region Utilities
  663.  
  664.         /// <summary>
  665.         /// IComparable interface. Simply compares alias names used by MCI
  666.         /// </summary>
  667.         /// <param name="other">MCIPlayer to compare to</param>
  668.         /// <returns>Result of comparison</returns>
  669.         public int CompareTo(MciPlayer other)
  670.         {
  671.             return _name.CompareTo(other._name);
  672.         }
  673.  
  674.         /// <summary>
  675.         /// Clamp to values of type T within a defined range
  676.         /// </summary>
  677.         /// <typeparam name="T">The <see cref="System.Type"/> of the that will be passed and returned. Must implement the <see cref="System.IComparable"/> interface</typeparam>
  678.         /// <param name="val">The value to clamp</param>
  679.         /// <param name="min">The minimum allowed value</param>
  680.         /// <param name="max">The maximum allowed value</param>
  681.         /// <returns>The value clamped between the minimum and maximum</returns>
  682.         public static T Clamp<T>(T val, T min, T max) where T : IComparable<T>
  683.         {
  684.             if (val.CompareTo(min) < 0) return min;
  685.             else if (val.CompareTo(max) > 0) return max;
  686.             else return val;
  687.         }
  688.  
  689.         /// <summary>
  690.         /// Returns the length of the file as a string formatted as M:SS.
  691.         /// </summary>
  692.         /// <returns>The formatted string</returns>
  693.         public string FormattedLength()
  694.         {
  695.             long length = GetLength() / 1000;
  696.             return String.Format("{0}:{1:d2}", length / 60, length % 60);
  697.         }
  698.  
  699.         /// <summary>
  700.         /// Returns the current postion of playback as a string formatted as M:SS.
  701.         /// </summary>
  702.         /// <returns>The formatted string</returns>
  703.         public string FormattedPosition()
  704.         {
  705.             long pos = GetPosition() / 1000;
  706.             return String.Format("{0}:{1:d2}", pos / 60, pos % 60);
  707.         }
  708.  
  709.         /// <summary>
  710.         /// Evaluates an MCI command and returns any data received
  711.         /// </summary>
  712.         /// <param name="command">The <paramref name="System.String"/> MCI command</param>
  713.         /// <returns>Any data that is returned by result of the command, else an empty string</returns>
  714.         public string MciEvaluate(string command)
  715.         {
  716.             _buffer.Clear();
  717.             LogError(mciSendString(command, _buffer, BUFFER_SIZE, WindowHandle));
  718.             return _buffer.ToString();
  719.         }
  720.  
  721.         #endregion
  722.  
  723.         #region Logging
  724.  
  725.         /// <summary>
  726.         /// Clears the log buffer.
  727.         /// </summary>
  728.         public void ClearLog()
  729.         {
  730.             _log.Clear();
  731.         }
  732.  
  733.         /// <summary>
  734.         /// Saves the log to disk
  735.         /// </summary>
  736.         /// <param name="filename">The path to the file to writw</param>
  737.         /// <returns>Flag if save was successful</returns>
  738.         public bool SaveLog(string filename)
  739.         {
  740.             try
  741.             {
  742.                 File.WriteAllText(filename, _log.ToString());
  743.                 return true;
  744.             }
  745.             catch { return false; }
  746.         }
  747.  
  748.         /// <summary>
  749.         /// Evaluates and adds an entry to the log
  750.         /// </summary>
  751.         /// <param name="error">The MCI error code to evaluate</param>
  752.         [MethodImpl(MethodImplOptions.NoInlining)]
  753.         private void LogError(long error)
  754.         {
  755.             if (LoggingEnabled && error != 0)
  756.             {
  757.                 _errorBuffer.Clear();
  758.                 mciGetErrorString((int)error, _errorBuffer, BUFFER_SIZE);
  759.                 _errorMessage = _errorBuffer.ToString();
  760.                 if (_errorMessage != "The specified command was carried out.")
  761.                 {
  762.                     string function = new StackFrame(1, true).GetMethod().Name;
  763.                     _log.AppendFormat("{0} in \"{1}\"\n{2}\n\n", DateTime.Now, function, _errorMessage);
  764.                     Console.WriteLine(_errorBuffer.ToString());
  765.                 }
  766.             }
  767.         }
  768.  
  769.         #endregion
  770.  
  771.         #region Delegates
  772.  
  773.         public delegate void OnOpenEventHandler(object sender, OnOpenEventArgs e);
  774.  
  775.         public delegate void OnPlayEventHandler(object sender, OnPlayEventArgs e);
  776.  
  777.         public delegate void OnPauseEventHandler(object sender, EventArgs e);
  778.  
  779.         public delegate void OnStopEventHandler(object sender, EventArgs e);
  780.  
  781.         public delegate void OnCloseEventHandler(object sender, EventArgs e);
  782.  
  783.         public delegate void OnSeekEventHandler(object sender, OnSeekEventArgs e);
  784.  
  785.         public delegate void OnRecordEventHandler(object sender, OnRecordEventArgs e);
  786.  
  787.         #endregion
  788.  
  789.         #region Events
  790.  
  791.         /// <summary>
  792.         /// Occurs when a file is opened by the player
  793.         /// </summary>
  794.         public event OnOpenEventHandler OnOpenEvent;
  795.  
  796.         /// <summary>
  797.         /// Occurs when playback begins
  798.         /// </summary>
  799.         public event OnPlayEventHandler OnPlayEvent;
  800.  
  801.         /// <summary>
  802.         /// Occurs when playback is paused or resumed
  803.         /// </summary>
  804.         public event OnPauseEventHandler OnPauseEvent;
  805.  
  806.         /// <summary>
  807.         /// Occurs when the player is stopped
  808.         /// </summary>
  809.         public event OnStopEventHandler OnStopEvent;
  810.  
  811.         /// <summary>
  812.         /// Occurs when the player is closed
  813.         /// </summary>
  814.         public event OnCloseEventHandler OnCloseEvent;
  815.  
  816.         /// <summary>
  817.         /// Occurs when the seek function is used
  818.         /// </summary>
  819.         public event OnSeekEventHandler OnSeekEvent;
  820.  
  821.         /// <summary>
  822.         /// Occurs when the player begins recording
  823.         /// </summary>
  824.         public event OnRecordEventHandler OnRecordEvent;
  825.  
  826.         protected virtual void OnOpen(OnOpenEventArgs e)
  827.         {
  828.             if (OnOpenEvent != null) OnOpenEvent(this, e);
  829.         }
  830.  
  831.         protected virtual void OnPlay(OnPlayEventArgs e)
  832.         {
  833.             if (OnPlayEvent != null) OnPlayEvent(this, e);
  834.         }
  835.  
  836.         protected virtual void OnPause(EventArgs e)
  837.         {
  838.             if (OnPauseEvent != null) OnPauseEvent(this, e);
  839.         }
  840.  
  841.         protected virtual void OnStop(EventArgs e)
  842.         {
  843.             if (OnStopEvent != null) OnStopEvent(this, e);
  844.         }
  845.  
  846.         protected virtual void OnClose(EventArgs e)
  847.         {
  848.             if (OnCloseEvent != null) OnCloseEvent(this, e);
  849.         }
  850.  
  851.         protected virtual void OnSeek(OnSeekEventArgs e)
  852.         {
  853.             if (OnSeekEvent != null) OnSeekEvent(this, e);
  854.         }
  855.  
  856.         protected virtual void OnRecord(OnRecordEventArgs e)
  857.         {
  858.             if (OnRecordEvent != null) OnRecordEvent(this, e);
  859.         }
  860.  
  861.         #endregion
  862.     }
  863.  
  864.     #region Event Arguments
  865.  
  866.     public class OnOpenEventArgs : EventArgs
  867.     {
  868.         /// <summary>
  869.         /// Gets the full path to the opened file
  870.         /// </summary>
  871.         public string Filepath { get { return _filename; } }
  872.         /// <summary>
  873.         /// Gets the name of the file opened
  874.         /// </summary>
  875.         public string Filename { get { return Path.GetFileName(_filename); } }
  876.         /// <summary>
  877.         /// Gets the name of the file opened without file extension
  878.         /// </summary>
  879.         public string FilenameWithouExtension
  880.         {
  881.             get { return Path.GetFileNameWithoutExtension(_filename); }
  882.         }
  883.         /// <summary>
  884.         /// Gets the file extension of the opened file
  885.         /// </summary>
  886.         public string Extension { get { return Path.GetExtension(_filename); } }
  887.         /// <summary>
  888.         /// Gets the directory of the opened file
  889.         /// </summary>
  890.         public string Directory { get { return Path.GetDirectoryName(_filename); } }
  891.  
  892.         private string _filename;
  893.  
  894.         /// <summary>
  895.         /// Event arguments for opening a file
  896.         /// </summary>
  897.         /// <param name="filename">The path to the file</param>
  898.         public OnOpenEventArgs(string filename)
  899.         {
  900.             _filename = filename;
  901.         }
  902.     }
  903.  
  904.     public class OnPlayEventArgs : EventArgs
  905.     {
  906.         /// <summary>
  907.         /// The path to the file being played
  908.         /// </summary>
  909.         public string Filename { get { return _filename; } }
  910.         /// <summary>
  911.         /// The length of the file in milliseconds
  912.         /// </summary>
  913.         public long Length { get { return _length; } }
  914.  
  915.         private string _filename;
  916.         private long _length;
  917.  
  918.         /// <summary>
  919.         /// Event arguments for playing
  920.         /// </summary>
  921.         /// <param name="filename">The path to the file being played</param>
  922.         /// <param name="length">The length of the file in milliseconds</param>
  923.         public OnPlayEventArgs(string filename, long length)
  924.         {
  925.             _filename = filename;
  926.             _length = length;
  927.         }
  928.     }
  929.  
  930.     public class OnPauseEventArgs : EventArgs
  931.     {
  932.         /// <summary>
  933.         /// The current position in milliseconds of playback
  934.         /// </summary>
  935.         public long Position { get { return _position; } }
  936.         /// <summary>
  937.         /// Flag if file is being paused or resumed
  938.         /// </summary>
  939.         public bool Resuming { get { return _resuming; } }
  940.  
  941.         private long _position;
  942.         private bool _resuming;
  943.  
  944.         /// <summary>
  945.         /// Event arguments for pausing and resuming
  946.         /// </summary>
  947.         /// <param name="position">The current position in milliseconds of playback</param>
  948.         /// <param name="resuming">Flag if file is being paused or resumed</param>
  949.         public OnPauseEventArgs(long position, bool resuming)
  950.         {
  951.             _position = position;
  952.             _resuming = resuming;
  953.         }
  954.     }
  955.  
  956.     public class OnSeekEventArgs : EventArgs
  957.     {
  958.         /// <summary>
  959.         /// Gets the position in milliseconds of playback before the change
  960.         /// </summary>
  961.         public long CurrentPosition { get { return _current; } }
  962.         /// <summary>
  963.         /// Gets the position in milliseconds of playback after the change
  964.         /// </summary>
  965.         public long TargetPosition { get { return _target; } }
  966.  
  967.         private long _current;
  968.         private long _target;
  969.  
  970.         /// <summary>
  971.         /// Event arguments for seeking
  972.         /// </summary>
  973.         /// <param name="current">The position in milliseconds of playback before the change</param>
  974.         /// <param name="target">The position in milliseconds of playback after the change</param>
  975.         public OnSeekEventArgs(long current, long target)
  976.         {
  977.             _current = current;
  978.             _target = target;
  979.         }
  980.     }
  981.  
  982.     public class OnRecordEventArgs : EventArgs
  983.     {
  984.         /// <summary>
  985.         /// Gets the number of bits per sample of the recording
  986.         /// </summary>
  987.         public int BitsPerSample { get { return _bitsPerSample; } }
  988.         /// <summary>
  989.         /// Gets the samplerate of the recording
  990.         /// </summary>
  991.         public int SampleRate { get { return _sampleRate; } }
  992.         /// <summary>
  993.         /// Gets the number of channels used for the recording
  994.         /// </summary>
  995.         public int Channels { get { return _channels; } }
  996.  
  997.         private int _bitsPerSample;
  998.         private int _sampleRate;
  999.         private int _channels;
  1000.  
  1001.         /// <summary>
  1002.         /// Event arguments for recording
  1003.         /// </summary>
  1004.         /// <param name="bitsPerSample">The number of bits used per sample</param>
  1005.         /// <param name="sampleRate">The sample rate</param>
  1006.         /// <param name="channels">The number of channels used for recording</param>
  1007.         public OnRecordEventArgs(int bitsPerSample, int sampleRate, int channels)
  1008.         {
  1009.             _bitsPerSample = bitsPerSample;
  1010.             _sampleRate = sampleRate;
  1011.             _channels = channels;
  1012.         }
  1013.     }
  1014.  
  1015.     #endregion
  1016.  
  1017.     # region Enums
  1018.  
  1019.     public enum MciNotify
  1020.     {
  1021.         Notify = 0x03b9,
  1022.         Success = 0x01,
  1023.         Superseded = 0x02,
  1024.         Aborted = 0x04,
  1025.         Failure = 0x08
  1026.     }
  1027.  
  1028.     public enum MciStatus
  1029.     {
  1030.         Playing,
  1031.         Stopped,
  1032.         Paused,
  1033.         Recording,
  1034.         NotReady,
  1035.         Open,
  1036.         Parked,
  1037.         Seeking
  1038.     }
  1039.  
  1040.     #endregion
  1041. }
Advertisement
Add Comment
Please, Sign In to add comment