带C#播放口吃的低级音频播放器-修复?
我正在做一个小项目(只是为了好玩),它允许我显示当前音频缓冲区中播放的频率 该计划是: 执行带C#播放口吃的低级音频播放器-修复?,c#,multithreading,audio,buffer,waitone,C#,Multithreading,Audio,Buffer,Waitone,我正在做一个小项目(只是为了好玩),它允许我显示当前音频缓冲区中播放的频率 该计划是: 执行WaveOutPlayer.ThreadProc()方法的线程将继续播放并重新填充两个音频缓冲区。当第一个缓冲区播放时,第二个缓冲区被重新填充,反之亦然。为了确保一个缓冲区在另一个缓冲区停止播放之前不会开始播放,我使用WaitOne()方法。WaveOut设备回放缓冲区的音频数据后,将调用缓冲区的OnCompleted()方法。此方法取消等待 播放本身就开始了,但是非常不稳定 谁能告诉我为什么会这样 Vi
WaveOutPlayer.ThreadProc()方法的线程将继续播放并重新填充两个音频缓冲区。当第一个缓冲区播放时,第二个缓冲区被重新填充,反之亦然。为了确保一个缓冲区在另一个缓冲区停止播放之前不会开始播放,我使用WaitOne()
方法。WaveOut
设备回放缓冲区的音频数据后,将调用缓冲区的OnCompleted()
方法。此方法取消等待
播放本身就开始了,但是非常不稳定
谁能告诉我为什么会这样
Visual Studio的项目位于
(目前,仅支持16位立体声44,1kHz未压缩wav。)
下面是我的一些代码,它们似乎是相关的:
using System;
using System.Threading;
using System.Runtime.InteropServices;
using System.Collections;
using System.Linq;
namespace LowLevelAudio
{
internal class WaveOutHelper
{
public static void Try(int err)
{
if (err != WaveNative.MMSYSERR_NOERROR)
throw new Exception(err.ToString());
}
}
public delegate void BufferFillEventHandler(IntPtr data, int size);
public class WaveOutBuffer : IDisposable
{
private AutoResetEvent m_PlayEvent = new AutoResetEvent(false);
private IntPtr m_WaveOut;
private int m_buffersize;
private static byte[] m_samples;
private static double[] m_fftsamples;
private WaveNative.WaveHdr m_Header;
private byte[] m_HeaderData;
private GCHandle m_HeaderHandle;
private GCHandle m_HeaderDataHandle;
private WaveFormat m_waveformat;
private double[] m_fftOccurances;
private double[] m_fftHertzlist;
private bool m_Playing;
public int ID
{
get; set;
}
internal static void WaveOutProc(IntPtr hdrvr, int uMsg, int dwUser, ref WaveNative.WaveHdr wavhdr, int dwParam2)
{
if (uMsg == WaveNative.MM_WOM_DONE)
{
try
{
GCHandle h = (GCHandle)wavhdr.dwUser;
WaveOutBuffer buf = (WaveOutBuffer)h.Target;
buf.OnPlayCompleted();
}
catch(Exception ex)
{
Console.WriteLine("Exception: " + ex.Message);
}
}
}
public WaveOutBuffer(IntPtr waveOutHandle, int size, WaveFormat format)
{
m_WaveOut = waveOutHandle;
m_waveformat = format;
m_HeaderHandle = GCHandle.Alloc(m_Header, GCHandleType.Pinned);
m_Header.dwUser = (IntPtr)GCHandle.Alloc(this);
m_HeaderData = new byte[size];
m_HeaderDataHandle = GCHandle.Alloc(m_HeaderData, GCHandleType.Pinned);
m_Header.lpData = m_HeaderDataHandle.AddrOfPinnedObject();
m_Header.dwBufferLength = size;
m_buffersize = size;
m_samples = new byte[m_buffersize];
WaveOutHelper.Try(WaveNative.waveOutPrepareHeader(m_WaveOut, ref m_Header, Marshal.SizeOf(m_Header)));
}
~WaveOutBuffer()
{
Dispose();
}
public int Size
{
get { return m_Header.dwBufferLength; }
}
public IntPtr Data
{
get { return m_Header.lpData; }
}
public void Dispose()
{
if (m_Header.lpData != IntPtr.Zero)
{
WaveNative.waveOutUnprepareHeader(m_WaveOut, ref m_Header, Marshal.SizeOf(m_Header));
m_HeaderHandle.Free();
m_Header.lpData = IntPtr.Zero;
}
m_PlayEvent.Close();
if (m_HeaderDataHandle.IsAllocated)
m_HeaderDataHandle.Free();
}
public bool Play()
{
lock(this) // works, but has to be fine tuned... (to do)
{
m_PlayEvent.Reset();
m_Playing = WaveNative.waveOutWrite(m_WaveOut, ref m_Header, Marshal.SizeOf(m_Header)) == WaveNative.MMSYSERR_NOERROR;
if (!m_Playing)
throw new Exception("test exception");
return m_Playing;
}
}
public void WaitForMe()
{
Console.WriteLine(this.ID + " WaitFor()");
if (m_Playing)
{
m_Playing = m_PlayEvent.WaitOne();
}
else
{
m_Playing = false;
}
}
public void OnPlayCompleted()
{
Console.WriteLine(this.ID + " OnCompleted()");
m_PlayEvent.Set();
m_Playing = false;
}
}
public class WaveOutPlayer : IDisposable
{
private IntPtr m_WaveOut;
private WaveOutBuffer[] m_bufferlist;
private Thread m_Thread;
private BufferFillEventHandler m_FillProc;
private bool m_Finished;
private byte m_zero;
private int m_buffercount = 0;
private int m_buffersize = 0;
private WaveFormat m_waveformat;
private WaveNative.WaveDelegate m_BufferProc = new WaveNative.WaveDelegate(WaveOutBuffer.WaveOutProc);
public static int DeviceCount
{
get { return WaveNative.waveOutGetNumDevs(); }
}
public WaveOutPlayer(int device, WaveFormat format, int bufferSize, BufferFillEventHandler fillProc)
{
m_zero = format.wBitsPerSample == 8 ? (byte)128 : (byte)0;
m_FillProc = fillProc;
m_buffercount = 2;
m_buffersize = bufferSize;
m_waveformat = format;
WaveOutHelper.Try(WaveNative.waveOutOpen(out m_WaveOut, device, format, m_BufferProc, 0, WaveNative.CALLBACK_FUNCTION));
AllocateBuffers(bufferSize, m_buffercount, format);
m_Thread = new Thread(new ThreadStart(ThreadProc));
m_Thread.Start();
}
~WaveOutPlayer()
{
Dispose();
}
public void Dispose()
{
if (m_Thread != null)
{
try
{
m_Finished = true;
if (m_WaveOut != IntPtr.Zero)
WaveNative.waveOutReset(m_WaveOut);
m_Thread.Join();
m_FillProc = null;
FreeBuffers();
if (m_WaveOut != IntPtr.Zero)
WaveNative.waveOutClose(m_WaveOut);
}
finally
{
m_Thread = null;
m_WaveOut = IntPtr.Zero;
}
}
}
private void ThreadProc()
{
WaveOutBuffer b0 = m_bufferlist[0];
WaveOutBuffer b1 = m_bufferlist[1];
MainForm form = Program.getUI();
bool s = true;
m_FillProc(b0.Data, b0.Size);
while (!m_Finished)
{
if (s)
{
Console.WriteLine("-------------------------");
Console.WriteLine("Playing b0, filling b1");
b0.Play();
m_FillProc(b1.Data, b1.Size);
form.paintEqualizer(b0);
Console.WriteLine("callng waitFor on b0");
b0.WaitForMe();
}
else
{
Console.WriteLine("-------------------------");
Console.WriteLine("Playing b1, filling b0");
b1.Play();
m_FillProc(b0.Data, b0.Size);
form.paintEqualizer(b1);
Console.WriteLine("callng waitFor on b1");
b1.WaitForMe();
}
s = !s;
}
}
private void AllocateBuffers(int bufferSize, int bufferCount, WaveFormat format)
{
FreeBuffers();
m_bufferlist = new WaveOutBuffer[m_buffercount];
if (bufferCount > 0)
{
for (int i = 0; i < m_buffercount; i++)
{
m_bufferlist[i] = new WaveOutBuffer(m_WaveOut, bufferSize, format);
m_bufferlist[i].ID = i;
}
}
}
private void FreeBuffers()
{
if (m_bufferlist != null)
{
foreach (WaveOutBuffer currentBuffer in m_bufferlist)
{
if (currentBuffer != null)
{
currentBuffer.Dispose();
}
}
}
}
}
}
使用系统;
使用系统线程;
使用System.Runtime.InteropServices;
使用系统集合;
使用System.Linq;
命名空间低级别音频
{
内部类WaveOutHelper
{
公共静态void Try(int err)
{
if(err!=WaveNative.MMSYSERR\u NOERROR)
抛出新异常(err.ToString());
}
}
公共委托void BufferFillEventHandler(IntPtr数据,int大小);
公共类WaveBuffer:IDisposable
{
私有自动恢复事件m_PlayEvent=新自动恢复事件(假);
私有IntPtr m_WaveOut;
私有int m_缓冲区大小;
私有静态字节[]m_样本;
专用静态双[]m_fft示例;
专用WaveNative.WaveHdr m_头;
专用字节[]m_HeaderData;
私人GCHandle Mu HeaderHandle;
专用GCHandle m_HeaderDataHandle;
专用波格式Mu波格式;
私人双[]m_fftOccurances;
私人双[]m_fftHertzlist;
二等兵布尔穆拉;
公共整数ID
{
获得;设置;
}
内部静态无效WaveOutProc(IntPtr hdrvr、intumsg、intdwuser、ref WaveNative.WaveHdr wavhdr、intdwparam2)
{
如果(uMsg==WaveNative.MM\u WOM\u DONE)
{
尝试
{
GCHandle h=(GCHandle)wavhdr.dwUser;
WaveBuf=(WaveBuffer)h.目标;
buf.onplay已完成();
}
捕获(例外情况除外)
{
Console.WriteLine(“异常:+ex.Message”);
}
}
}
公共WaveOutOffer(IntPtr waveOutHandle、int大小、波形格式)
{
m_WaveOut=waveOutHandle;
m_波形=格式;
m_HeaderHandle=GCHandle.Alloc(m_Header,GCHandleType.pinted);
m_Header.dwUser=(IntPtr)GCHandle.Alloc(this);
m_HeaderData=新字节[大小];
m_HeaderDataHandle=GCHandle.Alloc(m_HeaderData,GCHandleType.pinted);
m_Header.lpData=m_HeaderDataHandle.AddRofPindedObject();
m_Header.dwBufferLength=大小;
m_buffersize=大小;
m_samples=新字节[m_buffersize];
Try(WaveNative.waveOutPrepareHeader(m_WaveOut,ref m_Header,Marshal.SizeOf(m_Header));
}
~WaveBuffer()
{
处置();
}
公共整数大小
{
获取{return m_Header.dwBufferLength;}
}
公共IntPtr数据
{
获取{return m_Header.lpData;}
}
公共空间处置()
{
if(m_Header.lpData!=IntPtr.Zero)
{
WaveNative.WaveOutUnpareHeader(m_WaveOut,ref m_Header,Marshal.SizeOf(m_Header));
m_HeaderHandle.Free();
m_Header.lpData=IntPtr.Zero;
}
m_PlayEvent.Close();
if(m_HeaderDataHandle.IsAllocated)
m_HeaderDataHandle.Free();
}
公共广播剧
{
lock(this)//可以工作,但必须进行微调…(要做)
{
m_PlayEvent.Reset();
m_Playing=WaveNative.waveOutWrite(m_WaveOut,ref m_头,Marshal.SizeOf(m_头))==WaveNative.MMSYSERR\u NOERROR;
如果(!m_正在播放)
抛出新异常(“测试异常”);
返回m_播放;
}
}
公共无效WaitForMe()
{
Console.WriteLine(this.ID+“WaitFor()”);
如果(你在玩)
{
m_Playing=m_PlayEvent.WaitOne();
}
其他的
{
m_Playing=假;
}
}
已完成的公共void OnPlayCompleted()
{
Console.WriteLine(this.ID+“OnCompleted()”);
m_PlayEvent.Set();
m_Playing=假;
}
}
公共类WaveOutPlayer:IDisposable
{
私有IntPtr m_WaveOut;
专用WaveBuffer[]m_缓冲列表;
私有线程m_线程;
私有缓冲区FillEventHandler m_FillProc;
私人住宅已完工;
专用字节m_零;
私有int m_buffercount=0;
私有int m_buffersize=0;
专用波格式Mu波格式;
私有WaveNative.WaveDelegate m_BufferProc=新的WaveNative.WaveDelegate(WaveBuffer.WaveOutProc);
公共静态int设备计数
{
获取{返回WaveNative.waveOutGetNumDevs();}
}
公共WaveOutPlayer(int设备、WaveFormat格式、int bufferSize、BufferFillEventHandler fillProc)
{
m_zero=format.wBitsPerSample==8?(字节)128:(字节)0;
m_FillProc=FillProc;
m_buffercount=2;
m_buffersize=buffersize