C++ 播放音频流(PCM裸流)--改善

简介: 直接上代码,如果有需要可以直接建一个win32控制台程序然后将代码拷过去改个文件名就可以用了(注意将声道和频率与你自己的文件对应)。当然我自己也用VS2008写了个例子上传了,如果有需要下载地址如下:点击打开链接。

直接上代码,如果有需要可以直接建一个win32控制台程序然后将代码拷过去改个文件名就可以用了(注意将声道和频率与你自己的文件对应)。当然我自己也用VS2008写了个例子上传了,如果有需要下载地址如下:点击打开链接

    这份代码是打开文件截取一段数据然后播放的,可以轻松的经过加一条线程的方式改成网络传输的形式,但经过本人测试,因为没有缓存机制会有“哒哒”的噪声,也就是说这份代码在网络实时音频上的表现并不太好。为了解决这个问题,可以加上缓存机制,本人因为一开始用的是事件响应方式,所以一直困在这个框架里,不能很好的利用缓存的机制解决上面提到的问题,后来尝试了用回调函数的方式来响应数据播放完成的消息,问题就轻松的解决了。那部分的代码会在稍候放上去。

 

[cpp]  view plain  copy
 
  1. #include "stdafx.h"  
  2. #include <stdio.h>  
  3. #include <Windows.h>  
  4. #pragma comment(lib, "winmm.lib")  
  5.   
  6. char buf[1024 * 1024 * 4];  
  7.   
  8. int _tmain(int argc, _TCHAR* argv[]) {  
  9.     FILE*           thbgm;//文件  
  10.     int             cnt;  
  11.     HWAVEOUT        hwo;  
  12.     WAVEHDR         wh;  
  13.     WAVEFORMATEX    wfx;  
  14.     HANDLE          wait;  
  15.   
  16.     wfx.wFormatTag = WAVE_FORMAT_PCM;//设置波形声音的格式  
  17.     wfx.nChannels = 1;//设置音频文件的通道数量  
  18.     wfx.nSamplesPerSec = 8000;//设置每个声道播放和记录时的样本频率  
  19.     wfx.nAvgBytesPerSec = 16000;//设置请求的平均数据传输率,单位byte/s。这个值对于创建缓冲大小是很有用的  
  20.     wfx.nBlockAlign = 2;//以字节为单位设置块对齐  
  21.     wfx.wBitsPerSample = 16;  
  22.     wfx.cbSize = 0;//额外信息的大小  
  23.     wait = CreateEvent(NULL, 0, 0, NULL);  
  24.     waveOutOpen(&hwo, WAVE_MAPPER, &wfx, (DWORD_PTR)wait, 0L, CALLBACK_EVENT);//打开一个给定的波形音频输出装置来进行回放  
  25.     fopen_s(&thbgm, "paomo.pcm", "rb");  
  26.     cnt = fread(buf, sizeof(char), 1024 * 1024 * 4, thbgm);//读取文件4M的数据到内存来进行播放,通过这个部分的修改,增加线程可变成网络音频数据的实时传输。当然如果希望播放完整的音频文件,也是要在这里稍微改一改  
  27.     int dolenght = 0;  
  28.     int playsize = 1024;  
  29.     while (cnt) {//这一部分需要特别注意的是在循环回来之后不能花太长的时间去做读取数据之类的工作,不然在每个循环的间隙会有“哒哒”的噪音  
  30.         wh.lpData = buf + dolenght;  
  31.         wh.dwBufferLength = playsize;  
  32.         wh.dwFlags = 0L;  
  33.         wh.dwLoops = 1L;  
  34.         waveOutPrepareHeader(hwo, &wh, sizeof(WAVEHDR));//准备一个波形数据块用于播放  
  35.         waveOutWrite(hwo, &wh, sizeof(WAVEHDR));//在音频媒体中播放第二个函数wh指定的数据  
  36.         WaitForSingleObject(wait, INFINITE);//用来检测hHandle事件的信号状态,在某一线程中调用该函数时,线程暂时挂起,如果在挂起的INFINITE毫秒内,线程所等待的对象变为有信号状态,则该函数立即返回  
  37.         dolenght = dolenght + playsize;  
  38.         cnt = cnt - playsize;  
  39.     }  
  40.     waveOutClose(hwo);  
  41.     fclose(thbgm);  
  42.     return 0;  
  43. }  

 

    离写上面部分已经过了快一年,现在回看之前写的代码感觉略为坑爹,或许是进步了吧。之前说要把双缓存的代码放出来,哪知道后来忙别的项目去了,这部分就丢到一边,去老项目中提取代码感觉好烦一直没弄。在这一年中不少人发私信问我关于这部分代码如何写的事,没想到现在做音频的人还真不少呢。Ok,既然挖了坑就要填,今天乘着周末写了一个双缓存的Demo工程,代码如下:

 

[cpp]  view plain  copy
 
  1. #include <stdio.h>  
  2. #include <Windows.h>  
  3.   
  4. #pragma comment(lib, "winmm.lib")  
  5.   
  6. #define DATASIZE 1024*512 //分次截取数据大小  
  7. FILE*           pcmfile;  //音频文件  
  8. HWAVEOUT        hwo;  
  9.   
  10. void CALLBACK WaveCallback(HWAVEOUT hWave, UINT uMsg, DWORD dwInstance, DWORD dw1, DWORD dw2)//回调函数  
  11. {  
  12.     switch (uMsg)  
  13.     {  
  14.         case WOM_DONE://上次缓存播放完成,触发该事件  
  15.         {  
  16.             LPWAVEHDR pWaveHeader = (LPWAVEHDR)dw1;  
  17.             pWaveHeader->dwBufferLength = fread(pWaveHeader->lpData, 1, DATASIZE, pcmfile);;  
  18.             waveOutPrepareHeader(hwo, pWaveHeader, sizeof(WAVEHDR));  
  19.             waveOutWrite(hwo, pWaveHeader, sizeof(WAVEHDR));  
  20.             break;  
  21.         }  
  22.     }  
  23. }  
  24.   
  25. void main()   
  26. {  
  27.     int             cnt;  
  28.     WAVEHDR         wh1;  
  29.     WAVEHDR         wh2;  
  30.     WAVEFORMATEX    wfx;  
  31.   
  32.     fopen_s(&pcmfile, "paomo.pcm", "rb");//打开文件  
  33.   
  34.     wfx.wFormatTag = WAVE_FORMAT_PCM;//设置波形声音的格式  
  35.     wfx.nChannels = 1;//设置音频文件的通道数量  
  36.     wfx.nSamplesPerSec = 8000;//设置每个声道播放和记录时的样本频率  
  37.     wfx.nAvgBytesPerSec = 16000;//设置请求的平均数据传输率,单位byte/s。这个值对于创建缓冲大小是很有用的  
  38.     wfx.nBlockAlign = 2;//以字节为单位设置块对齐  
  39.     wfx.wBitsPerSample = 16;  
  40.     wfx.cbSize = 0;//额外信息的大小  
  41.   
  42.     waveOutOpen(&hwo, WAVE_MAPPER, &wfx, (DWORD)WaveCallback, 0L, CALLBACK_FUNCTION);//打开一个给定的波形音频输出装置来进行声音播放,方式为回调函数方式。如果是对话框程序,可以将第五个参数改为(DWORD)this,操作跟本Demo程序相似  
  43.   
  44.     wh1.dwLoops = 0L;//播放区一  
  45.     wh1.lpData = new char[DATASIZE];  
  46.     wh1.dwBufferLength = DATASIZE;   
  47.     fread(wh1.lpData, 1, DATASIZE, pcmfile);  
  48.     wh1.dwFlags = 0L;  
  49.     waveOutPrepareHeader(hwo, &wh1, sizeof(WAVEHDR));//准备一个波形数据块用于播放  
  50.     waveOutWrite(hwo, &wh1, sizeof(WAVEHDR));//在音频媒体中播放第二个参数指定的数据,也相当于开启一个播放区的意思  
  51.   
  52.     wh2.dwLoops = 0L;//播放区二,基本同上  
  53.     wh2.lpData = new char[DATASIZE];  
  54.     wh2.dwBufferLength = DATASIZE;  
  55.     fread(wh2.lpData, 1, DATASIZE, pcmfile);  
  56.     wh2.dwFlags = 0L;  
  57.     waveOutPrepareHeader(hwo, &wh2, sizeof(WAVEHDR));  
  58.     waveOutWrite(hwo, &wh2, sizeof(WAVEHDR));  
  59.   
  60.     while (wh1.dwBufferLength != 0 || wh2.dwBufferLength != 0)//如果文件还在没播放完则等待500ms  
  61.     {  
  62.         Sleep(500);  
  63.     }  
  64.     waveOutUnprepareHeader(hwo, &wh1, sizeof(WAVEHDR));//清理数据  
  65.     waveOutUnprepareHeader(hwo, &wh2, sizeof(WAVEHDR));  
  66.   
  67.     delete []wh1.lpData;  
  68.     delete []wh2.lpData;  
  69.     fclose(pcmfile);//关闭文件  
  70.     return;  
  71. }  


    同上面一样,如果想要这个工程的可以到这个链接去下载。不过提醒下,本人已然抛弃了VS2008,直接用VS2013,如果还在用老平台的话要用还是要折腾一会的。

 

from:http://blog.csdn.net/weixinhum/article/details/29943973?utm_source=tuicool&utm_medium=referral

目录
相关文章
|
6月前
|
C++ 内存技术
[转]Visual C++内嵌swf文件并播放
[转]Visual C++内嵌swf文件并播放
|
10月前
|
机器学习/深度学习 人工智能 算法
【动态规划】【组合数学】【C++算法】920播放列表的数量
【动态规划】【组合数学】【C++算法】920播放列表的数量
|
开发工具 C++
C++音乐播放按钮的封装过程详解
1、准备工作:音乐、开发工具VS stdio及图形库工具 2、设计思路:先加载音乐,再通过点击不同的按钮执行不同的操作(播放音乐,暂停音乐、继续播放、结束播放) 绘制按钮我们通过一个按钮button类来操作,这样数据会存在一些必要的访问数据权限,并可以将多个函数声明写在同一个类中,调用只需使用 " 类名.函数名 “即可调用里面的函数
|
缓存 C++ 内存技术
C++ 采集音频流(PCM裸流)实现录音功能
与上一篇的“C++ 播放音频流(PCM裸流)” 点击打开链接 相对应,本篇是关于用C++实现录音功能的。同样是直接建一个win32控制台程序然后将代码拷过去改个文件名就可以用,也可以下载本人上传的相关工程,这个工程是用VS2013写的,如果是较低的版本就呵呵了。
2594 0
|
C++ 内存技术
C++ 调节PCM音频音量大小
在用解码器解码音频数据得到PCM音频数据块之后,可以在将数据送给声卡播放之前调节其音量大小,具体的实现函数如下:   [cpp] view plain copy   void RaiseVolume(char* buf, UINT32 size, UINT32 uRepe...
3168 0
|
C++ 内存技术
C++ 播放音频流(PCM裸流)
直接上代码,如果有需要可以直接建一个win32控制台程序然后将代码拷过去改个文件名就可以用了(注意将声道和频率与你自己的文件对应哦)。当然我自己也用VS2008(VS2013好用太多,强烈推荐还是用VS2013,只是它的工程太大,上传起来相当费劲,所以还是用VS2008重写了。
1858 0
|
12天前
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
15天前
|
编译器 C语言 C++
类和对象的简述(c++篇)
类和对象的简述(c++篇)
|
12天前
|
安全 编译器 C语言
【C++篇】深度解析类与对象(中)
在上一篇博客中,我们学习了C++类与对象的基础内容。这一次,我们将深入探讨C++类的关键特性,包括构造函数、析构函数、拷贝构造函数、赋值运算符重载、以及取地址运算符的重载。这些内容是理解面向对象编程的关键,也帮助我们更好地掌握C++内存管理的细节和编码的高级技巧。
|
12天前
|
存储 程序员 C语言
【C++篇】深度解析类与对象(上)
在C++中,类和对象是面向对象编程的基础组成部分。通过类,程序员可以对现实世界的实体进行模拟和抽象。类的基本概念包括成员变量、成员函数、访问控制等。本篇博客将介绍C++类与对象的基础知识,为后续学习打下良好的基础。