c# 通过WinAPI播放PCM声音

下面就是一篇详细讲解“c# 通过WinAPI播放PCM声音”的完整攻略。

1. 背景知识

在开始讲解之前,我们需要了解一些背景知识:PCM(Pulse Code Modulation)脉冲编码调制,是一种数字音频编码方式,将模拟声音信号转换为数字信号,并以数字的形式进行存储和传输。在WinAPI中,我们可以使用waveOut API来播放PCM声音。

2. WaveOut API

我们可以使用waveOut API来播放PCM声音,该API提供了一些函数来完成播放操作,如以下几个函数:

  • waveOutOpen:打开设备,以便播放声音。
  • waveOutClose:关闭设备。
  • waveOutPrepareHeader:准备音频数据并将其添加到播放缓冲区。
  • waveOutUnprepareHeader:回收缓冲区。
  • waveOutWrite:将准备好的音频数据写入缓冲区并播放。

3. 实现步骤

下面是通过WinAPI播放PCM声音的实现步骤:

  1. 调用waveOutOpen函数打开设备,这个函数需要传入一个WAVEFORMATEX结构体参数,这个结构体包含了声音的格式信息,如每秒采样率、每个采样点占用的位数、每个采样点的声道数等。

  2. 准备音频数据并将其添加到播放缓冲区中,需要以下几个步骤:

a. 先使用GlobalAlloc函数在进程的全局堆中分配一块内存。

b. 填充WAVEHDR结构体,并将数据保存到这个结构体中。这里需要注意的是,每个缓冲区的大小要小于等于设备的缓冲区大小,不然会导致声音卡顿或者播放不了。

c. 调用waveOutPrepareHeader函数准备音频数据,并将其添加到播放缓冲区中。

  1. 调用waveOutWrite函数将缓冲区的音频数据写入设备,并开始播放声音。

  2. 播放完声音后,调用waveOutUnprepareHeader函数回收音频缓冲区和WAVEHDR结构体的内存。

  3. 最后,调用waveOutClose函数关闭设备,释放相应资源。

4. 示例说明

下面是两个示例来说明如何使用WinAPI播放PCM声音。

示例一

这个示例演示如何从一个PCM文件中读取音频数据并播放,具体的实现步骤如下:

  1. 打开PCM文件并读取其中的音频数据。

csharp
byte[] data = File.ReadAllBytes("test.pcm");

  1. 调用waveOutOpen函数打开设备,并填写WAVEFORMATEX结构体参数。

```csharp
WAVEFORMATEX format = new WAVEFORMATEX();
format.nSamplesPerSec = 44100;
format.wBitsPerSample = 16;
format.nChannels = 2;
format.wFormatTag = WAVE_FORMAT_PCM;
format.nBlockAlign = (short)(format.nChannels * format.wBitsPerSample / 8);
format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;

IntPtr hWaveOut = IntPtr.Zero;
waveOutOpen(out hWaveOut, WAVE_MAPPER, format, IntPtr.Zero, 0, CALLBACK_NULL);
```

  1. 将音频数据准备好,并填充到WAVEHDR结构体中。

```csharp
IntPtr pData = Marshal.AllocHGlobal(data.Length);
Marshal.Copy(data, 0, pData, data.Length);

var header = new WAVEHDR();
header.dwBufferLength = data.Length;
header.lpData = pData;

waveOutPrepareHeader(hWaveOut, ref header, Marshal.SizeOf(header));
```

  1. 调用waveOutWrite函数将缓冲区的音频数据写入设备,开始播放声音。

csharp
waveOutWrite(hWaveOut, ref header, Marshal.SizeOf(header));

  1. 播放完声音后,释放相应资源。

csharp
waveOutReset(hWaveOut);
waveOutUnprepareHeader(hWaveOut, ref header, Marshal.SizeOf(header));
Marshal.FreeHGlobal(pData);
waveOutClose(hWaveOut);

示例二

这个示例演示如何使用录音设备将麦克风的声音录制下来,并使用WinAPI进行实时播放。具体的实现步骤如下:

  1. 打开录音设备,并填写WAVEFORMATEX结构体参数。

```csharp
WAVEFORMATEX format = new WAVEFORMATEX();
format.nSamplesPerSec = 44100;
format.wBitsPerSample = 16;
format.nChannels = 2;
format.wFormatTag = WAVE_FORMAT_PCM;
format.nBlockAlign = (short)(format.nChannels * format.wBitsPerSample / 8);
format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;

IntPtr hWaveIn = IntPtr.Zero;
waveInOpen(out hWaveIn, WAVE_MAPPER, format, IntPtr.Zero, 0, CALLBACK_NULL);
```

  1. 准备音频数据并将其添加到录音缓冲区中。

```csharp
const int BUFFER_SIZE = 16384; // 缓冲区大小

byte[] data = new byte[BUFFER_SIZE];
GCHandle hData = GCHandle.Alloc(data, GCHandleType.Pinned);

var header = new WAVEHDR();
header.lpData = hData.AddrOfPinnedObject();
header.dwBufferLength = BUFFER_SIZE;
header.dwFlags = 0;

waveInPrepareHeader(hWaveIn, ref header, Marshal.SizeOf(header));
waveInAddBuffer(hWaveIn, ref header, Marshal.SizeOf(header));
```

  1. 开始录音。

csharp
waveInStart(hWaveIn);

  1. 调用waveOutOpen函数打开播放设备,并填写WAVEFORMATEX结构体参数。
    csharp
    IntPtr hWaveOut = IntPtr.Zero;
    waveOutOpen(out hWaveOut, WAVE_MAPPER, format, IntPtr.Zero, 0, CALLBACK_NULL);

  2. 在录音过程中,不断从录音缓冲区中获取音频数据,并将数据添加到播放缓冲区中。

```csharp
while (true)
{
uint flags = 0;

   waveInUnprepareHeader(hWaveIn, ref header, Marshal.SizeOf(header));
   waveInPrepareHeader(hWaveIn, ref header, Marshal.SizeOf(header));
   waveInAddBuffer(hWaveIn, ref header, Marshal.SizeOf(header));

   waveInGetPosition(hWaveIn, out uint position, Marshal.SizeOf<uint>());

   while ((flags & WHDR_DONE) == 0)
   {
       waveOutGetPosition(hWaveOut, out uint waveOutPosition, Marshal.SizeOf<uint>());

       if (waveOutPosition - position >= BUFFER_SIZE)
           continue;

       waveOutWrite(hWaveOut, ref header, Marshal.SizeOf(header));
       waveOutGetPosition(hWaveOut, out waveOutPosition, Marshal.SizeOf<uint>());

       waveInGetErrorText(waveInGetError(hWaveIn), sb, sb.Capacity);
       Console.WriteLine(sb.ToString().Trim());
       flags = header.dwFlags;
   }

}
```

  1. 在录音完成后,释放相应资源。

```csharp
waveInStop(hWaveIn);
waveInReset(hWaveIn);
waveInUnprepareHeader(hWaveIn, ref header, Marshal.SizeOf(header));

waveOutReset(hWaveOut);
waveOutUnprepareHeader(hWaveOut, ref header, Marshal.SizeOf(header));
waveOutClose(hWaveOut);

hData.Free();
```

以上就是使用WinAPI播放PCM声音的完整攻略,示例代码仅供参考。如果你需要播放其他格式的声音,比如MP3、WAV等,可以使用相应的解码库先将其解码成PCM数据再进行播放。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:c# 通过WinAPI播放PCM声音 - Python技术站

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

相关文章

  • C#与C++ dll之间传递字符串string wchar_t* char* IntPtr问题

    在C#和C++之间传递字符串时,需要注意字符串的编码方式和内存分配方式。本文将详细讲解C#和C++之间传递字符串的问题,并提供两个示例说明。 传递字符串的编码方式 在C#中,字符串使用Unicode编码,即每个字符占用两个字节。而在C++中,字符串可以使用多种编码方式,如ASCII、UTF-8、UTF-16等。因此,在C#和C++之间传递字符串时,需要注意字…

    云计算 2023年5月16日
    00
  • python分析inkscape路径数据方案简单介绍

    Python分析Inkscape路径数据方案简单介绍 什么是Inkscape路径数据? 在Inkscape中,路径是由节点和线段组成的,其中节点用于确定路径方向和曲率,线段用于连接节点并绘制路径。路径数据是描述路径的元素、属性和值的集合。 路径数据通常使用SVG(Scalable Vector Graphics)语法进行描述,SVG是一种可缩放的矢量图形语言…

    云计算 2023年5月18日
    00
  • 云开发中的战斗机 Laf,让你像写博客一样写代码

    各位云原生搬砖师 and PPT 架构师,你们有没有想过像写文章一样方便地写代码呢? 怎样才能像写文章一样写代码? 理想的需求应该是可以在线编写、调试函数,不用重启服务,随时随地在 Web 上查看函数的运行日志,无需连接服务器,无需折腾数据库、对象存储、Nginx 等,可以随时随地上线应用,招之即来,挥之即去,随手发布! 这时候懂王上线了,好家伙,这不就是 …

    2023年4月9日
    00
  • ASP.NET Core中的策略授权和ABP授权

    下面是关于“ASP.NET Core中的策略授权和ABP授权”的完整攻略,包含两个示例说明。 简介 在ASP.NET Core中,我们可以使用策略授权和ABP授权来实现身份验证和授权。在本攻略中,我们将介绍如何使用策略授权和ABP授权来提高Web应用程序的安全性。 步骤 在ASP.NET Core中使用策略授权和ABP授权时,我们可以通过以下步骤来实现: 理…

    云计算 2023年5月16日
    00
  • 2020版Python学习路线图(附学习资料)

    2020版Python学习路线图(附学习资料)攻略 一、学习前准备 在开始学习之前,需要确保你已经具备以下知识和技能: 基本的计算机操作能力,如文件操作、命令行基础等; 编程语言基础,如常用的控制语句、函数、数据类型等; 熟悉基本的算法思想,如递归、分治等; 熟悉基本的数据结构,如数组、链表、栈、队列等。 如果你还没有掌握上述基础知识,建议先学习相关的课程或…

    云计算 2023年5月18日
    00
  • Python ORM框架SQLAlchemy学习笔记之数据查询实例

    下面我将详细讲解“Python ORM框架SQLAlchemy学习笔记之数据查询实例”的完整攻略。 概述 ORM框架是Object Relational Mapping的缩写,翻译成中文叫做对象关系映射。它的作用是在不需要手写查询语句的情况下,让开发者可以用对象的方式操作数据库。SQLAlchemy就是一个Python的ORM框架。 本文将详细讲解在Pyth…

    云计算 2023年5月18日
    00
  • [AWS vs Azure] 云计算里AWS和Azure的探究(5) ——EC2和Azure VM磁盘性能分析

    云计算里AWS和Azure的探究(5) ——EC2和Azure VM磁盘性能分析   在虚拟机创建完成之后,CPU和内存的配置等等基本上是一目了然的。如果不考虑显卡性能,一台机器最重要的性能瓶颈就是硬盘。由于无论是EC2还是Azure VM都使用了虚拟机,而存储盘也是以某种形式存放在磁盘阵列或者NAS设备中,所以磁盘的读写性能成为使用云计算虚拟服务器里最重要…

    云计算 2023年4月10日
    00
  • 边缘计算+云计算,实现物联网的关键

      边缘计算+云计算,实现物联网的关键   云计算和边缘计算正在塑造物联网(IoT)的未来。这种组合为物联网网络中连接的设备带来了稳定性,并通过处理更接近源的数据来解决延迟问题。   云计算明显改变了数据处理的形式,特别是对于大数据。利用云的计算能力,物联网实现了跨越式发展,我们获得,存储和处理数据,而不必配置计算资源和管理。   物联网每年安装数十亿台智能…

    2023年4月10日
    00
合作推广
合作推广
分享本页
返回顶部