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日

相关文章

  • 在.NET中读取嵌入和使用资源文件的方法

    在.NET开发中,嵌入和使用资源文件是一个非常有用的技巧。利用资源文件,可以将特定的文件嵌入到程序集(.dll或.exe文件)中,使得程序的部署和维护更加方便。本文将详细讲解在.NET中读取嵌入和使用资源文件的方法。 嵌入资源文件 1.创建资源文件 需要将待嵌入的文件添加到资源文件中。创建资源文件的方法有两种: 手动创建:在Visual Studio中右键项…

    C# 2023年6月1日
    00
  • C#各种异常处理方式总结

    C#各种异常处理方式总结 什么是异常? 异常是指在程序运行过程中遇到的错误或情况,可以是处理到了程序正常运行范围之外的数据输入或其他问题。 异常处理的意义 在编写程序时,我们需要预先考虑到可能出现的异常情况,以规避程序崩溃或数据丢失等问题。异常处理可以帮助我们及时捕获异常并进行处理,避免程序崩溃或数据不完整。 异常处理方式 C#提供了多种异常处理方式,包括使…

    C# 2023年5月15日
    00
  • 详解.Net中字符串不变性与相等判断的特殊场景

    针对.Net中字符串不变性与相等判断的特殊场景,我们需要从以下几个方面进行讲解: 字符串不变性的概念与原理 字符串相等判断的常规方法 特殊场景下的字符串相等判断问题及解决方法 1. 字符串不变性的概念与原理 在 .Net 中,为了追求运行效率和确保字符串的安全性,字符串被设计为不可变对象,即字符串一旦被创建之后,不能被修改。基于这种不可变的特性,字符串在被使…

    C# 2023年5月31日
    00
  • ASP.Net Core中的内存和GC机制

    ASP.NET Core中的内存和GC机制 在本攻略中,我们将深入了解ASP.NET Core中的内存和GC机制。我们将介绍.NET Core内存管理的基本原理、GC机制的工作原理和使用方法,并提供两个示例说明。 .NET Core内存管理的基本原理 .NET Core内存管理的基本原理是将内存分为两个部分:托管堆和非托管堆。托管堆是由.NET运行时管理的内…

    C# 2023年5月16日
    00
  • 在C#中使用Channels的完整教程

    在C#中使用Channels的完整教程 什么是Channel? Channel是在C# 7.0版本中引入的一种全新的内置类型,用于在多个awaitable操作之间更方便地进行同步和异步消息传递。 Channel可以看做是一个类似线程安全队列的数据结构,支持读/取操作(receive)和写/存操作(send),并且本身天生具有异步支持(async/await)…

    C# 2023年6月3日
    00
  • C# Linq的Union()方法 – 返回两个序列的并集

    C# Linq的Union()操作符 Union() 是 C# Linq 提供的操作符之一,它可以将两个集合合并为一个集合,并且去除重复的元素。它的语法如下: IEnumerable<TSource> Union<TSource>( this IEnumerable<TSource> first, IEnumerable&…

    C# 2023年4月19日
    00
  • .NET 6 即将到来的新特性 隐式命名空间引用

    .NET 6 即将到来的新特性:隐式命名空间引用 在 .NET 6 中,引入了一项新特性:隐式命名空间引用。这项特性可以让我们在项目中使用命名空间时更加方便,无需显式地引用命名空间。本攻略将详细介绍隐式命名空间引用的使用方法,并提供两个示例说明。 隐式命名空间引用 在 .NET 6 中,我们可以使用隐式命名空间引用来简化项目中的命名空间引用。隐式命名空间引用…

    C# 2023年5月17日
    00
  • C# 网络编程之UDP

    C# 网络编程之UDP 什么是UDP UDP是一个无连接的传输协议,它不保证可靠传输和数据的顺序,但是其传输速度很快,适合于传输实时性要求高的数据。 UDP的使用场景 由于UDP不需要建立连接,所以适合于一对多或多对多的广播传输。比如实现网络游戏的消息传输,实时视频传输等。 UDP编程实现 发送端实现 UDP发送方需要绑定发送端口,然后指定目标地址和目标端口…

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