使用winmm.dll本机代码录制C#音频

时间:2011-08-18 10:15:37

标签: c# audio pinvoke recording native-code

请告诉我如何使用c#代码将音频文件录制并保存到硬盘中。 我已从其中一个技术网页下载了代码。 这可能是我不太了解它也可以支持录音和保存功能。 请让我告诉你一些我下载的代码,以便你能给我任何建议。我应该怎么做。

[WaveIn.CS]

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

namespace SoundViewer
{
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;
    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_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();
        m_Header.dwBufferLength = size;
        WaveInHelper.Try(WaveNative.waveInPrepareHeader(m_WaveIn, ref m_Header, 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, Marshal.SizeOf(m_Header)) == WaveNative.MMSYSERR_NOERROR;
            System.Diagnostics.Debug.Write(string.Format("\n m_WaveIn: {0}, m_Header.dwBytesRecorded: {1}", m_WaveIn, m_Header.dwBytesRecorded));                
            //m_WaveIn.ToPointer();
            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();
    }

    public void Recording()
    {
        //int rawsize = Marshal.SizeOf(m_WaveIn);
        //byte[] rawdata = new byte[256 * 1024];
        ////Marshal.Copy(m_WaveIn, rawdata, 0, rawsize);
        ////System.IO.File.WriteAllBytes(string.Format("C:\\TempImage\\audio_{0}.wav", Guid.NewGuid()), rawdata );

        //Marshal.Copy(rawdata, 0, m_WaveIn, rawdata.Length);
        ////System.IO.File.WriteAllBytes(string.Format("C:\\TempImage\\audio_{0}.wav", Guid.NewGuid()), rawdata);

        ////Marshal.FreeHGlobal(m_WaveIn);

        //System.IO.MemoryStream ms = new System.IO.MemoryStream(

        //int elementSize = Marshal.SizeOf(typeof(IntPtr));
        //System.Diagnostics.Debug.Print("Reading unmanaged memory:");
        //// Print the 10 elements of the C-style unmanagedArray
        //for (int i = 0; i < 10; i++)
        //{
        //    System.Diagnostics.Debug.Print(Marshal.ReadIntPtr(m_WaveIn, i * elementSize));
        //}
    }

    ~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;
        }
    }
}

}

[WaveNative.cs]

internal class WaveNative
{
    // consts
    public const int MMSYSERR_NOERROR = 0; // no error

    public const int MM_WOM_OPEN = 0x3BB;
    public const int MM_WOM_CLOSE = 0x3BC;
    public const int MM_WOM_DONE = 0x3BD;

    public const int MM_WIM_OPEN = 0x3BE;
    public const int MM_WIM_CLOSE = 0x3BF;
    public const int MM_WIM_DATA = 0x3C0;

    public const int CALLBACK_FUNCTION = 0x00030000;    // dwCallback is a FARPROC 

    public const int TIME_MS = 0x0001;  // time in milliseconds 
    public const int TIME_SAMPLES = 0x0002;  // number of wave samples 
    public const int TIME_BYTES = 0x0004;  // current byte offset 

    // callbacks
    public delegate void WaveDelegate(IntPtr hdrvr, int uMsg, int dwUser, ref WaveHdr wavhdr, int dwParam2);

    // structs 

    [StructLayout(LayoutKind.Sequential)] public struct WaveHdr
    {
        public IntPtr lpData; // pointer to locked data buffer
        public int dwBufferLength; // length of data buffer
        public int dwBytesRecorded; // used for input only
        public IntPtr dwUser; // for client's use
        public int dwFlags; // assorted flags (see defines)
        public int dwLoops; // loop control counter
        public IntPtr lpNext; // PWaveHdr, reserved for driver
        public int reserved; // reserved for driver
    }

    private const string mmdll = "winmm.dll";

    // WaveOut calls
    [DllImport(mmdll)]
    public static extern int waveOutGetNumDevs();
    [DllImport(mmdll)]
    public static extern int waveOutPrepareHeader(IntPtr hWaveOut, ref WaveHdr lpWaveOutHdr, int uSize);
    [DllImport(mmdll)]
    public static extern int waveOutUnprepareHeader(IntPtr hWaveOut, ref WaveHdr lpWaveOutHdr, int uSize);
    [DllImport(mmdll)]
    public static extern int waveOutWrite(IntPtr hWaveOut, ref WaveHdr lpWaveOutHdr, int uSize);
    [DllImport(mmdll)]
    public static extern int waveOutOpen(out IntPtr hWaveOut, int uDeviceID, WaveFormat lpFormat, WaveDelegate dwCallback, int dwInstance, int dwFlags);
    [DllImport(mmdll)]
    public static extern int waveOutReset(IntPtr hWaveOut);
    [DllImport(mmdll)]
    public static extern int waveOutClose(IntPtr hWaveOut);
    [DllImport(mmdll)]
    public static extern int waveOutPause(IntPtr hWaveOut);
    [DllImport(mmdll)]
    public static extern int waveOutRestart(IntPtr hWaveOut);
    [DllImport(mmdll)]
    public static extern int waveOutGetPosition(IntPtr hWaveOut, out int lpInfo, int uSize);
    [DllImport(mmdll)]
    public static extern int waveOutSetVolume(IntPtr hWaveOut, int dwVolume);
    [DllImport(mmdll)]
    public static extern int waveOutGetVolume(IntPtr hWaveOut, out int dwVolume);

    // WaveIn calls
    [DllImport(mmdll)]
    public static extern int waveInGetNumDevs();
    [DllImport(mmdll)]
    public static extern int waveInAddBuffer(IntPtr hwi, ref WaveHdr pwh, int cbwh);
    [DllImport(mmdll)]
    public static extern int waveInClose(IntPtr hwi);
    [DllImport(mmdll)]
    public static extern int waveInOpen(out IntPtr phwi, int uDeviceID, WaveFormat lpFormat, WaveDelegate dwCallback, int dwInstance, int dwFlags);
    [DllImport(mmdll)]
    public static extern int waveInPrepareHeader(IntPtr hWaveIn, ref WaveHdr lpWaveInHdr, int uSize);
    [DllImport(mmdll)]
    public static extern int waveInUnprepareHeader(IntPtr hWaveIn, ref WaveHdr lpWaveInHdr, int uSize);
    [DllImport(mmdll)]
    public static extern int waveInReset(IntPtr hwi);
    [DllImport(mmdll)]
    public static extern int waveInStart(IntPtr hwi);
    [DllImport(mmdll)]
    public static extern int waveInStop(IntPtr hwi);        
}

0 个答案:

没有答案