实时采集并显示录音波形WaveIn.cs

该博客详细介绍了如何使用C#实现Windows音频输入API WaveIn来实时采集和显示录音波形。通过内部类WaveInBuffer和WaveInRecorder,创建了一个线程安全的录音系统,能够处理音频缓冲区的分配、释放、记录和回调。博客内容涵盖了WaveInHelper、BufferDoneEventHandler等关键组件,以及WaveInProc回调函数的处理逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


using System;
using System.Threading;
using System.Runtime.InteropServices;

namespace WaveLib
{
    
internal class WaveInHelper
    
{
        
public static void Try(int err)
        
{
            
if (err != WaveNative.MMSYSERR_NOERROR)
                
throw new Exception(err.ToString());
        }

    }


    
public delegate void BufferDoneEventHandler(IntPtr data, int size);

    
internal class WaveInBuffer : IDisposable
    
{
        
public WaveInBuffer NextBuffer;

        
private AutoResetEvent m_RecordEvent = new AutoResetEvent(false);
        
private IntPtr m_WaveIn;

        
private WaveNative.WaveHdr m_Header;//m_Header 数据缓存
        private byte[] m_HeaderData;
        
private GCHandle m_HeaderHandle;
        
private GCHandle m_HeaderDataHandle;

        
private bool m_Recording;

        
internal static void WaveInProc(IntPtr hdrvr, int uMsg, int dwUser, ref WaveNative.WaveHdr wavhdr, int dwParam2)
        
{
            
if (uMsg == WaveNative.MM_WIM_DATA)
            
{
                
try
                
{
                    GCHandle h 
= (GCHandle)wavhdr.dwUser;
                    WaveInBuffer buf 
= (WaveInBuffer)h.Target;
                    buf.OnCompleted();
                }

                
catch
                
{
                }

            }

        }


        
public WaveInBuffer(IntPtr waveInHandle, int size)
        
{
            
//m_Header 数据缓存
            
//size 数据缓冲区的大小
            
//dwuser 用户数据
            m_WaveIn = waveInHandle;

            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(); //数据缓存.lpData = 缓存地址1
            m_Header.dwBufferLength = size;
           
            WaveInHelper.Try(
            WaveNative.waveInPrepareHeader(m_WaveIn, 
ref m_Header,32));// Marshal.SizeOf(m_Header)));
        }

        
~WaveInBuffer()
        
{
            Dispose();
        }


        
public void Dispose()
        
{
            
if (m_Header.lpData != IntPtr.Zero)
            
{
                WaveNative.waveInUnprepareHeader(m_WaveIn, 
ref m_Header, Marshal.SizeOf(m_Header));
                m_HeaderHandle.Free();
                m_Header.lpData 
= IntPtr.Zero;
            }

            m_RecordEvent.Close();
            
if (m_HeaderDataHandle.IsAllocated)
                m_HeaderDataHandle.Free();
            GC.SuppressFinalize(
this);
        }


        
public int Size
        
{
            
get return m_Header.dwBufferLength; }
        }


        
public IntPtr Data
        
{
            
get return m_Header.lpData; }
        }


        
public bool Record()
        
{
            
lock(this)
            
{
                m_RecordEvent.Reset();
                m_Recording 
= WaveNative.waveInAddBuffer(m_WaveIn, ref m_Header,32== WaveNative.MMSYSERR_NOERROR;// Marshal.SizeOf(m_Header) == WaveNative.MMSYSERR_NOERROR;
                
                
return m_Recording;
            }

        }


        
public void WaitFor()
        
{
            
if (m_Recording)
                m_Recording 
= m_RecordEvent.WaitOne();
            
else
                Thread.Sleep(
0);
        }


        
private void OnCompleted()
        
{
            m_RecordEvent.Set();
            m_Recording 
= false;
        }

    }


    
public class WaveInRecorder : IDisposable
    
{
        
private IntPtr m_WaveIn;
        
private WaveInBuffer m_Buffers; // linked list
        private WaveInBuffer m_CurrentBuffer;
        
private Thread m_Thread;
        
private BufferDoneEventHandler m_DoneProc;
        
private bool m_Finished;

        
private WaveNative.WaveDelegate m_BufferProc = new WaveNative.WaveDelegate(WaveInBuffer.WaveInProc);

        
public static int DeviceCount
        
{
            
get return WaveNative.waveInGetNumDevs(); }
        }


        
public WaveInRecorder(int device, WaveFormat format, int bufferSize, int bufferCount, BufferDoneEventHandler doneProc)
        
{
            m_DoneProc 
= doneProc;
            WaveInHelper.Try(WaveNative.waveInOpen(
out m_WaveIn, device, format, m_BufferProc, 0, WaveNative.CALLBACK_FUNCTION));
            AllocateBuffers(bufferSize, bufferCount);
            
for (int i = 0; i < bufferCount; i++)
            
{
                SelectNextBuffer();
                m_CurrentBuffer.Record();
            }

            WaveInHelper.Try(WaveNative.waveInStart(m_WaveIn));
            m_Thread 
= new Thread(new ThreadStart(ThreadProc));
            m_Thread.Start();
        }

        
~WaveInRecorder()
        
{
            Dispose();
        }

        
public void Dispose()
        
{
            
if (m_Thread != null)
                
try
                
{
                    m_Finished 
= true;
                    
if (m_WaveIn != IntPtr.Zero)
                        WaveNative.waveInReset(m_WaveIn);
                    WaitForAllBuffers();
                    m_Thread.Join();
                    m_DoneProc 
= null;
                    FreeBuffers();
                    
if (m_WaveIn != IntPtr.Zero)
                        WaveNative.waveInClose(m_WaveIn);
                }

                
finally
                
{
                    m_Thread 
= null;
                    m_WaveIn 
= IntPtr.Zero;
                }

            GC.SuppressFinalize(
this);
        }

        
private void ThreadProc()
        
{
            
while (!m_Finished)
            
{
                Advance();
                
if (m_DoneProc != null && !m_Finished)
                    m_DoneProc(m_CurrentBuffer.Data, m_CurrentBuffer.Size);
                m_CurrentBuffer.Record();
            }

        }

        
private void AllocateBuffers(int bufferSize, int bufferCount)
        
{
            FreeBuffers();
            
if (bufferCount > 0)
            
{
                m_Buffers 
= new WaveInBuffer(m_WaveIn, bufferSize);
                WaveInBuffer Prev 
= m_Buffers;
                
try
                
{
                    
for (int i = 1; i < bufferCount; i++)
                    
{
                        WaveInBuffer Buf 
= new WaveInBuffer(m_WaveIn, bufferSize);
                        Prev.NextBuffer 
= Buf;
                        Prev 
= Buf;
                    }

                }

                
finally
                
{
                    Prev.NextBuffer 
= m_Buffers;
                }

            }

        }

        
private void FreeBuffers()
        
{
            m_CurrentBuffer 
= null;
            
if (m_Buffers != null)
            
{
                WaveInBuffer First 
= m_Buffers;
                m_Buffers 
= null;

                WaveInBuffer Current 
= First;
                
do
                
{
                    WaveInBuffer Next 
= Current.NextBuffer;
                    Current.Dispose();
                    Current 
= Next;
                }
 while(Current != First);
            }

        }

        
private void Advance()
        
{
            SelectNextBuffer();
            m_CurrentBuffer.WaitFor();
        }

        
private void SelectNextBuffer()
        
{
            m_CurrentBuffer 
= m_CurrentBuffer == null ? m_Buffers : m_CurrentBuffer.NextBuffer;
        }

        
private void WaitForAllBuffers()
        
{
            WaveInBuffer Buf 
= m_Buffers;
            
while (Buf.NextBuffer != m_Buffers)
            
{
                Buf.WaitFor();
                Buf 
= Buf.NextBuffer;
            }

        }

    }

}

 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值