📄 waveout.cs
字号:
catch
{
}
}
/// <summary>
/// Called by the MessageWindow when the buffer currently being played has
/// finished. This method starts the loading of the next block on a
/// separate thread. If the current block is the last one then playback is
/// stopped.
/// </summary>
public void BlockDone()
{
m_curBlock++;
try
{
if (m_curBlock < m_numBlocks)
{
//Debug.Assert((m_whdr[(m_curBlock + 2) % 2].dwFlags & Wave.WAVEHDR.WHDR_INQUEUE) != 0, "ERROR: A sound block finished before the subsequent block was written.");
if(this.m_playing)
{
Thread loadThread = new Thread(new ThreadStart(LoadBuffer));
loadThread.Start();
}
}
else if (m_curBlock == m_numBlocks)
{
Stop();
}
}
catch
{}
}
/// <summary>
/// Stop playing the current file and clean up all resources.
/// </summary>
public void Stop()
{
waveOutReset(m_hwo);
m_playing = false;
if (m_rdr != null)
{
m_rdr.BaseStream.Close();
m_rdr.Close();
m_rdr = null;
}
for (int i = 0; i < 2; i++)
{
if (m_whdr[i] != null)
{
lock(m_whdr[i])
{
if (m_hwo != IntPtr.Zero)
waveOutUnprepareHeader(m_hwo, m_whdr[i], (uint)Marshal.SizeOf(m_whdr[i]));
m_whdr[i].Dispose();
m_whdr[i] = null;
}
}
}
if (m_hwo != IntPtr.Zero)
waveOutClose(m_hwo);
m_hwo = IntPtr.Zero;
m_wfmt = null;
}
/// <summary>
/// Resume the playback of a paused sound.
/// </summary>
/// <returns>MMSYSERR.NOERROR if successful</returns>
public Wave.MMSYSERR Resume()
{
return waveOutRestart(m_hwo);
}
/// <summary>
/// Pause the playback of a sound.
/// </summary>
/// <returns>MMSYSERR.NOERROR if successful</returns>
public Wave.MMSYSERR Pause()
{
return waveOutPause(m_hwo);
}
/// <summary>
/// Get the volume of this sound.
/// </summary>
/// <param name="volLeft">Left channel volume level</param>
/// <param name="volRight">Right channel volume level</param>
/// <returns>MMSYSERR.NOERROR if successful</returns>
public Wave.MMSYSERR GetVolume(ref ushort volLeft, ref ushort volRight)
{
uint vol = 0;
Wave.MMSYSERR result = waveOutGetVolume(m_hwo, ref vol);
if (result != Wave.MMSYSERR.NOERROR)
return result;
volLeft = (ushort)(vol & 0x0000ffff);
volRight = (ushort)(vol >> 16);
return Wave.MMSYSERR.NOERROR;
}
/// <summary>
/// Sets the volume of this sound.
/// </summary>
/// <param name="volLeft">Left channel volume level</param>
/// <param name="volRight">Right channel volume level</param>
/// <returns>MMSYSERR.NOERROR if successful</returns>
public Wave.MMSYSERR SetVolume(ushort volLeft, ushort volRight)
{
uint vol = ((uint)volLeft & 0x0000ffff) | ((uint)volRight << 16);
return waveOutSetVolume(m_hwo, vol);
}
/// <summary>
/// Clean up all resources.
/// </summary>
public void Dispose()
{
Stop();
}
}
/// <summary>
/// Defines the MessageWindow used to receive messages from the audio
/// system.
/// </summary>
public class SoundMessageWindow : MessageWindow
{
public const int MM_WOM_OPEN = 0x03BB;
public const int MM_WOM_CLOSE = 0x03BC;
public const int MM_WOM_DONE = 0x03BD;
// Instance of a playback interface
protected WaveOut m_wo = null;
public SoundMessageWindow(WaveOut wo)
{
m_wo = wo;
}
protected override void WndProc(ref Message msg)
{
switch (msg.Msg)
{
// When this message is encountered, a block is
// done playing, so notify the WaveOut instance.
case MM_WOM_DONE:
m_wo.BlockDone(msg.WParam);
break;
}
base.WndProc(ref msg);
}
}
/// <summary>
/// Maintain an instance of a MessageWindow that handles audio messages.
/// </summary>
protected SoundMessageWindow m_msgWindow = null;
/// <summary>
/// An instance of WaveFile used as the source for playing audio.
/// </summary>
protected WaveFile m_file = null;
/// <summary>
/// Create an instance of WaveOut.
/// </summary>
public WaveOut()
{
m_msgWindow = new SoundMessageWindow(this);
m_file = new WaveFile();
}
/// <summary>
/// Determine the number of available playback devices.
/// </summary>
/// <returns>Number of output devices</returns>
public uint NumDevices()
{
return (uint)waveOutGetNumDevs();
}
/// <summary>
/// Get the name of the specified playback device.
/// </summary>
/// <param name="deviceId">ID of the device</param>
/// <param name="prodName">Destination string assigned the name</param>
/// <returns>MMSYSERR.NOERROR if successful</returns>
public Wave.MMSYSERR GetDeviceName(uint deviceId, ref string prodName)
{
WAVEOUTCAPS caps = new WAVEOUTCAPS();
Wave.MMSYSERR result = waveOutGetDevCaps(deviceId, caps, caps.Size);
if (result != Wave.MMSYSERR.NOERROR)
return result;
prodName = caps.szPname;
return Wave.MMSYSERR.NOERROR;
}
/// <summary>
/// Specifies if playback has finished.
/// </summary>
/// <returns>true if no playback is in progress.</returns>
public bool Done()
{
if (m_file != null)
return m_file.Done;
return true;
}
/// <summary>
/// Pause playback.
/// </summary>
/// <returns>MMSYSERR.NOERROR if successful</returns>
public Wave.MMSYSERR Pause()
{
if (m_file != null)
return m_file.Pause();
return Wave.MMSYSERR.NOERROR;
}
/// <summary>
/// Resume playback of a paused sound.
/// </summary>
/// <returns>MMSYSERR.NOERROR if successful</returns>
public Wave.MMSYSERR Resume()
{
if (m_file != null)
return m_file.Resume();
return Wave.MMSYSERR.NOERROR;
}
/// <summary>
/// Determines the length of the audio file, in milliseconds.
/// </summary>
/// <returns>Millieconds</returns>
public uint Milliseconds()
{
if (m_file != null)
return m_file.Milliseconds;
return 0;
}
/// <summary>
/// Play a file.
/// </summary>
/// <param name="fileName">Name of file to play</param>
/// <param name="bufferSize">Size of playback buffers</param>
/// <param name="volLeft">Volume of left channel</param>
/// <param name="volRight">Volume of right channel</param>
/// <returns>MMSYSERR.NOERROR if successful</returns>
public Wave.MMSYSERR Play(string fileName, int bufferSize, ushort volLeft, ushort volRight)
{
if (m_file != null)
{
return m_file.Play(0, fileName, m_msgWindow.Hwnd, bufferSize, volLeft, volRight);
}
return Wave.MMSYSERR.ERROR;
}
/// <summary>
/// Play a stream.
/// </summary>
/// <param name="strm">stream to play</param>
/// <param name="bufferSize">Size of playback buffers</param>
/// <param name="volLeft">Volume of left channel</param>
/// <param name="volRight">Volume of right channel</param>
/// <returns>MMSYSERR.NOERROR if successful</returns>
public Wave.MMSYSERR Play(Stream strm, int bufferSize, ushort volLeft, ushort volRight)
{
if (m_file != null)
{
return m_file.Play(0, strm, m_msgWindow.Hwnd, bufferSize, volLeft, volRight);
}
return Wave.MMSYSERR.ERROR;
}
public void Stop()
{
if (m_file != null)
m_file.Stop();
}
/// <summary>
/// A block has finished so notify the WaveFile. In a more complicated example,
/// this class might maintain an array of WaveFile instances. In such a case, the
/// wParam of the message could be passed from the MM_WIM_DATA message. This
/// value represents the m_hwi member of the file that caused the message.
/// The code might look something like:
/// foreach (WaveFile f in m_files)
/// {
/// if (f.m_hwi.ToInt32() == wParam.ToInt32())
/// {
/// f.BlockDone();
/// break;
/// }
/// }
/// </summary>
public void BlockDone(IntPtr hwo)
{
if (m_file != null)
m_file.BlockDone();
}
/// <summary>
/// Clean up an allocated resources.
/// </summary>
public void Dispose()
{
if (m_msgWindow != null)
m_msgWindow.Dispose();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -