C#实现通过winmm.dll控制声音播放的方法

下面是“C#实现通过winmm.dll控制声音播放的方法”的完整攻略:

1.简介

Winmm.dll是Windows操作系统中的一个动态链接库文件,它包含了负责音频的相关函数,通过调用这些函数我们可以实现对音频的控制。本文将介绍C#通过调用winmm.dll实现控制声音播放的方法。

2.winmm.dll 函数介绍

首先,我们需要了解winmm.dll中的一些重要函数:

  • waveOutOpen:打开音频输出设备,并且获取音频输出设备句柄。
  • waveOutSetVolume:设置音量,0表示静音,65536表示最大音量。
  • waveOutWrite:将音频数据写入音频输出设备缓冲区,并开始播放音频。
  • waveOutPause:暂停音频播放。
  • waveOutRestart:继续音频播放。
  • waveOutReset:停止音频播放,并且清空音频输出设备缓冲区。
  • waveOutClose:关闭音频输出设备。

3.实现方法

要在C#中调用winmm.dll中的函数,我们需要使用DllImport特性来声明这些函数,在使用前需要引用System.Runtime.InteropServices命名空间。

示例1:播放指定路径下的wav音频文件:

using System.Runtime.InteropServices;

namespace ConsoleApp1
{
    class Program
    {
        [DllImport("winmm.dll")]
        static extern int waveOutOpen(out IntPtr hwo, uint uDeviceID, ref WAVEFORMATEX lpFormat, IntPtr dwCallback, IntPtr dwInstance, uint fdwOpen);

        [DllImport("winmm.dll")]
        static extern int waveOutSetVolume(IntPtr hwo, uint dwVolume);

        [DllImport("winmm.dll")]
        static extern int waveOutWrite(IntPtr hwo, ref WAVEHDR pwh, uint cbwh);

        [DllImport("winmm.dll")]
        static extern int waveOutPause(IntPtr hwo);

        [DllImport("winmm.dll")]
        static extern int waveOutRestart(IntPtr hwo);

        [DllImport("winmm.dll")]
        static extern int waveOutReset(IntPtr hwo);

        [DllImport("winmm.dll")]
        static extern int waveOutClose(IntPtr hwo);

        [StructLayout(LayoutKind.Sequential)]
        public struct WAVEFORMATEX
        {
            public ushort wFormatTag;
            public ushort nChannels;
            public uint nSamplesPerSec;
            public uint nAvgBytesPerSec;
            public ushort nBlockAlign;
            public ushort wBitsPerSample;
            public ushort cbSize;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct WAVEHDR
        {
            public IntPtr lpData; 
            public uint dwBufferLength; 
            public uint dwBytesRecorded; 
            public IntPtr dwUser; 
            public uint dwFlags; 
            public uint dwLoops; 
            public IntPtr lpNext; 
            public IntPtr reserved; 
        }

        static void Main(string[] args)
        {
            string filePath = @"D:\music.wav";
            WAVEFORMATEX waveFormatEx = new WAVEFORMATEX
            {
                wFormatTag = 1,
                nChannels = 2,
                nSamplesPerSec = 44100,
                nAvgBytesPerSec = 176400,
                nBlockAlign = 4,
                wBitsPerSample = 16,
                cbSize = 0
            };
            IntPtr hWaveOut;
            waveOutOpen(out hWaveOut, 0, ref waveFormatEx, IntPtr.Zero, IntPtr.Zero, 0);
            IntPtr hFile = Win32Api.CreateFile(filePath, Win32Api.GENERIC_READ, Win32Api.FILE_SHARE_READ, IntPtr.Zero, Win32Api.OPEN_EXISTING, 0, IntPtr.Zero);
            uint cbData = Win32Api.GetFileSize(hFile, IntPtr.Zero);
            IntPtr pData = Marshal.AllocHGlobal((int)cbData);
            Win32Api.ReadFile(hFile, pData, cbData, out uint bytesRead, IntPtr.Zero);
            WAVEHDR waveHdr = new WAVEHDR
            {
                lpData = pData,
                dwBufferLength = cbData,
                dwFlags = 0
            };
            waveOutWrite(hWaveOut, ref waveHdr, (uint)Marshal.SizeOf(typeof(WAVEHDR)));
            Console.ReadKey();
            waveOutPause(hWaveOut);
            waveOutReset(hWaveOut);
            waveOutClose(hWaveOut);
            Win32Api.CloseHandle(hFile);
            Marshal.FreeHGlobal(pData);
        }
    }

    static class Win32Api
    {
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern bool ReadFile(IntPtr hFile, IntPtr lpBuffer, uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, IntPtr lpOverlapped);

        [DllImport("kernel32", SetLastError = true)]
        public extern static UInt32 GetFileSize(IntPtr hFile, IntPtr lpFileSizeHigh);

        public const uint GENERIC_READ = 0x80000000;
        public const uint FILE_SHARE_READ = 0x00000001;
        public const uint OPEN_EXISTING = 3;

        [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
        public static extern bool CloseHandle(IntPtr hObject);
    }
}

示例2:通过麦克风录制音频并播放:

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

namespace ConsoleApp1
{
    class Program
    {
        [DllImport("winmm.dll")]
        static extern int waveInOpen(out IntPtr hwi, uint uDeviceID, ref WAVEFORMATEX lpFormat, IntPtr dwCallback, IntPtr dwInstance, uint fdwOpen);

        [DllImport("winmm.dll")]
        static extern int waveInClose(IntPtr hwi);

        [DllImport("winmm.dll")]
        static extern int waveInStart(IntPtr hwi);

        [DllImport("winmm.dll")]
        static extern int waveInStop(IntPtr hwi);

        [DllImport("winmm.dll")]
        static extern int waveOutOpen(out IntPtr hwo, uint uDeviceID, ref WAVEFORMATEX lpFormat, IntPtr dwCallback, IntPtr dwInstance, uint fdwOpen);

        [DllImport("winmm.dll")]
        static extern int waveOutSetVolume(IntPtr hwo, uint dwVolume);

        [DllImport("winmm.dll")]
        static extern int waveOutWrite(IntPtr hwo, ref WAVEHDR pwh, uint cbwh);

        [DllImport("winmm.dll")]
        static extern int waveOutPause(IntPtr hwo);


        [DllImport("winmm.dll")]
        static extern int waveOutReset(IntPtr hwo);

        [DllImport("winmm.dll")]
        static extern int waveOutClose(IntPtr hwo);

        [StructLayout(LayoutKind.Sequential)]
        public struct WAVEFORMATEX
        {
            public ushort wFormatTag;
            public ushort nChannels;
            public uint nSamplesPerSec;
            public uint nAvgBytesPerSec;
            public ushort nBlockAlign;
            public ushort wBitsPerSample;
            public ushort cbSize;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct WAVEHDR
        {
            public IntPtr lpData; 
            public uint dwBufferLength; 
            public uint dwBytesRecorded; 
            public IntPtr dwUser; 
            public uint dwFlags; 
            public uint dwLoops; 
            public IntPtr lpNext; 
            public IntPtr reserved; 
        }

        static void Main(string[] args)
        {
            uint deviceID = 0;
            WAVEFORMATEX waveFormatEx = new WAVEFORMATEX
            {
                wFormatTag = 1,
                nChannels = 2,
                nSamplesPerSec = 44100,
                nAvgBytesPerSec = 176400,
                nBlockAlign = 4,
                wBitsPerSample = 16,
                cbSize = 0
            };
            IntPtr hWaveIn;
            waveInOpen(out hWaveIn, deviceID, ref waveFormatEx, IntPtr.Zero, IntPtr.Zero, 0);
            WAVEHDR[] waveHdrArray = new WAVEHDR[2];
            for (int i = 0; i < 2; i++)
            {
                waveHdrArray[i] = new WAVEHDR
                {
                    lpData = Marshal.AllocHGlobal(waveFormatEx.nAvgBytesPerSec),
                    dwBufferLength = waveFormatEx.nAvgBytesPerSec,
                    dwFlags = 0
                };
                waveInPrepareHeader(hWaveIn, ref waveHdrArray[i], (uint)Marshal.SizeOf(typeof(WAVEHDR)));
            }
            for (int i = 0; i < 2; i++)
            {
                waveInAddBuffer(hWaveIn, ref waveHdrArray[i], (uint)Marshal.SizeOf(typeof(WAVEHDR)));
            }
            waveOutOpen(out IntPtr hWaveOut, deviceID, ref waveFormatEx, IntPtr.Zero, IntPtr.Zero, 0);
            waveOutSetVolume(hWaveOut, 0xFFFF);
            waveOutWrite(hWaveOut, ref waveHdrArray[0], (uint)Marshal.SizeOf(typeof(WAVEHDR)));
            waveInStart(hWaveIn);
            Console.ReadKey();
            waveInStop(hWaveIn);
            waveOutReset(hWaveOut);
            for (int i = 0; i < 2; i++)
            {
                waveInUnprepareHeader(hWaveIn, ref waveHdrArray[i], (uint)Marshal.SizeOf(typeof(WAVEHDR)));
                Marshal.FreeHGlobal(waveHdrArray[i].lpData);
            }
            waveInClose(hWaveIn);
            waveOutClose(hWaveOut);
        }

        [DllImport("winmm.dll")]
        static extern int waveInPrepareHeader(IntPtr hwi, ref WAVEHDR pwh, uint cbwh);

        [DllImport("winmm.dll")]
        static extern int waveInUnprepareHeader(IntPtr hwi, ref WAVEHDR pwh, uint cbwh);

        [DllImport("winmm.dll")]
        static extern int waveInAddBuffer(IntPtr hwi, ref WAVEHDR pwh, uint cbwh);
    }

    static class Win32Api
    {
        public const uint GENERIC_READ = 0x80000000;
        public const uint FILE_SHARE_READ = 0x00000001;
        public const uint OPEN_EXISTING = 3;

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern bool ReadFile(IntPtr hFile, IntPtr lpBuffer, uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, IntPtr lpOverlapped);

        [DllImport("kernel32", SetLastError = true)]
        public extern static UInt32 GetFileSize(IntPtr hFile, IntPtr lpFileSizeHigh);

        [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
        public static extern bool CloseHandle(IntPtr hObject);
    }
}

在以上两个示例中,我们先使用waveOutOpen或waveInOpen打开音频输出或输入设备获取句柄,然后设置音量大小、调用waveOutWrite或waveInAddBuffer写入音频数据、调用waveOutPause、waveOutReset、waveOutClose或waveInStop、waveInUnprepareHeader或waveOutUnprepareHeader和Marshal.FreeHGlobal等函数来实现音频的播放或录制并且清理资源。

4.总结

本文介绍了通过调用winmm.dll实现控制声音播放的方法,介绍了winmm.dll中的一些重要函数,同时提供了两个示例来演示播放wav音频、录制并播放麦克风音频的完整过程。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C#实现通过winmm.dll控制声音播放的方法 - Python技术站

(0)
上一篇 2023年5月15日
下一篇 2023年5月15日

相关文章

  • C#实现文本转语音功能

    下面我分享一下如何用C#实现文本转语音功能的攻略。 1. 确定音频库 要实现文本转语音功能,我们需要选择一个音频库。目前常用的音频库有Microsoft自带的Speech API (SAPI)和Nuance的RealSpeak等。这里我们以SAPI为例。 2. 安装SAPI 首先,我们需要从Microsoft网站上获取SAPI并安装。安装过程中需要注意选择所…

    C# 2023年5月15日
    00
  • C#中DateTime日期类型格式化显示方法汇总

    C#中DateTime日期类型格式化显示方法汇总 在C#中,DateTime是表示日期和时间的结构体。我们经常需要输出符合我们要求的日期和时间的格式来方便输出和理解。下面是一些DateTime的格式化输出方法: 标准格式字符串 格式字符串 描述 d 短日期格式,例如 2022/3/17 D 长日期格式,例如 2022年3月17日 t 短时间格式,例如 下午 …

    C# 2023年5月31日
    00
  • Unity实战之制作动画编辑器

    Unity实战之制作动画编辑器 在Unity中,可以使用动画编辑器创建和编辑动画。本文将介绍如何制作一个自定义的动画编辑器,以便更好地管理和编辑动画。 步骤1:创建自定义窗口 首先,我们需要创建一个自定义窗口。可以使用Unity的EditorGUILayout和EditorWindow类创建自定义窗口。以下是一个简单的示例: using UnityEdito…

    C# 2023年5月15日
    00
  • Blazor UI库 Bootstrap Blazor 快速上手 (v7.5.7)

    最近组件库更新比较频繁,有些同学感觉有点迷茫,就着今天刚上了张老板一节课立马撸个新的上手教程回馈社区, ;-> 1.新建工程b18QuickStartv757,将项目添加到解决方案中 dotnet new blazorserver -o b18QuickStartv757 dotnet sln add b18QuickStartv757/b18Quic…

    C# 2023年4月27日
    00
  • wpf RelativeSource绑定

    RelativeSource有四种类型 Self FindAncestor TemplatedParent PreviousData   a.Self Self用于绑定源和绑定目标相同的场景中。对象的一个属性与同一对象的另一个属性绑定。 例如,让我们取一个高度和宽度相同的椭圆。在XAML文件中添加下面给出的代码。宽度属性与高度属性相对绑定。 <Grid…

    C# 2023年4月18日
    00
  • c#实现获取字符串阵列中元素最长或最短的长度

    当需要获取字符串数组中元素的最长或最短长度时,可以通过C#中的LINQ表达式来实现。 具体步骤如下: 定义字符串数组 string[] strArray = {"Hello", "World", "C#", "Programming", "Language"}…

    C# 2023年6月8日
    00
  • C#实现判断图形文件格式的方法

    下面是详细讲解“C#实现判断图形文件格式的方法”的攻略。 1. 导入命名空间 首先,在要使用该功能的C#项目中,需要使用以下命名空间: using System.IO; 2. 使用文件头检验法判断文件格式 在C#中,判断文件格式的一种方式是使用文件头检验法,即检测文件开头的几个字节来判断文件格式。在C#中,使用以下代码可以实现文件头检验法: byte[] b…

    C# 2023年6月1日
    00
  • C# yield在WCF中的错误使用(二)

    C#yield在WCF中的错误使用(二) 在WCF中使用C#的yield关键字时,需要注意一些问题。在本文中,我们将讨论C#yield在WCF中的错误使用,并提供两个示例。 1. 错误使用C#yield的示例 以下是一个错误使用C#yield的示例: [ServiceContract] public interface IMyService { [Opera…

    C# 2023年5月15日
    00
合作推广
合作推广
分享本页
返回顶部