最轻便易行的视音频播放示例8,输出设备基本操作

by admin on 2019年4月19日

DirectSound是DirectX组件之一,提供了对音频设备的捕获和播音技术,同时它也是绝无仅有多少个帮忙Xp系统的节奏本事之1。
DirectSound首要有以下特点:

DirectSound是DirectX组件之壹,提供了对音频设备的抓获和广播工夫,同时它也是绝无仅有多少个帮助Xp系统的音频本领之壹。
DirectSound首要有以下特点:

DirectSound是DirectX组件之一,提供了对音频设备的破获和广播手艺,同时它也是唯1多少个帮忙Xp系统的韵律本事之一。
DirectSound首要有以下特征:

本文记录DirectSound播放音频的技能。DirectSound是Windows下最常见的韵律播放本事。方今许多的节拍播放应用都以通过DirectSound来播放的。本文记录七个应用DirectSound播放PCM的例证。
注:一个人兄长已经提示作者DirectSound已经安排被X奥迪(Audi)o2代替了。后来考证了1晃意识确有此事。因而在下次更新初级中学结束学业生升学考试虑出席X奥迪o二播放PCM的例子。本文依旧记录一下DirectSound那位“元老”。

优点:

优点:

优点:

home88一必发 1

  • 广播音频低延迟
  • 硬件财富调整
  • 同时播放多个声音。
  • 决定硬件缓冲区的运用优先级(DirectSound使用缓冲区来播放音频)。
  • 模拟3D旋律环境。
  • 动态退换音响效果(回声、和声等)。
  • 抓获音频输入设备声音位wav(多为PCM数据,未经压缩)。
  • 广播音频低延迟
  • 硬件能源调节
  • 同时播放多个声音。
  • 操纵硬件缓冲区的接纳优先级(DirectSound使用缓冲区来播放音频)。
  • 模拟3D旋律环境。
  • 动态转移音响效果(回声、和声等)。
  • 破获音频输入设备声音位wav(多为PCM数据,未经压缩)。
  • 广播音频低延迟
  • 硬件能源调整
  • 同时播放多个声音。
  • 决定硬件缓冲区的利用优先级(DirectSound使用缓冲区来播音音频)。
  • 模拟3D旋律环境。
  • 动态变动音响效果(回声、和声等)。
  • 破获音频输入设备声音位wav(多为PCM数据,未经压缩)。

 

缺点:

缺点:

缺点:

DirectSound简介

DirectSound是微软所支付DirectX的机件之壹,能够在Windows
操作系统上录音,并且记下波形音响效果(waveform sound)。如今DirectSound
是1个早熟的API
,提供点不清有效的效应,例如能够在较高的分辨率播放多声道音响。
DirectSound3D(DS3D)最早是19玖三年与 DirectX 三 一同发布的。DirectX
八以往的DirectSound和DirectSound3D的(DS3D)被合称DirectX 奥迪o。

DirectSound有以下几种对象:

对象

数量

作用

主要接口

设备

每个应用程序只有一个设备对象

用来管理设备,创建辅助缓冲区

IDirectSound8

辅助缓冲区

每一个声音对应一个辅助缓冲区

用来管理一个静态的或者动态的声音流,然后在主缓冲区中混音

IDirectSoundBuffer8,

IDirectSound3DBuffer8,

IDirectSoundNotify8

主缓冲区

一个应用程序只有一个主缓冲区

将辅助缓冲区的数据进行混音,并且控制3D参数.

IDirectSoundBuffer,

IDirectSound3DListener8

  • 只得播放wav音频文件。
  • 只可以播放wav音频文件。
  • 唯其如此播放wav音频文件。

DirectSound播放音频的流水生产线

动用DirectSound播放音频一般景观下需求如下步骤:

  1. 初始化

一) 创造叁个IDirectSound八接口的靶子
二) 设置合作级
3) 创设2个主缓冲对象
四) 创造二个副缓冲对象
伍) 创建布告对象
陆) 设置布告地方

七) 开首广播

  1. 循环播放音响

1) 数据填充至副缓冲区

2) 等待播放完毕

上面结合详细分析一下上文的流水生产线。

1. 初始化
1) 创造三个IDirectSound捌接口的对象

经过DirectSoundCreate八()方法能够创立一个设备对象。那个目的平时代表缺省的播报设备。DirectSoundCreate⑧()函数原型如下。

[cpp] view
plaincopyhome88一必发 2home88一必发 3

 

  1. HRESULT DirectSoundCreate8(  
  2.      LPCGUID lpcGuidDevice,  
  3.      LPDIRECTSOUND8 * ppDS8,  
  4.      LPUNKNOWN pUnkOuter  
  5. )  

参数的含义如下:
lpcGuidDevice:要创制的配备对象的GUID。能够内定为NULL,代表暗许的播报设备。
ppDS八:重返的IDirectSound八对象的地点。
pUnkOuter:必须设为NULL。
诸如如下代码就可以成立二个IDirectSound8接口的指标

[cpp] view
plaincopyhome88一必发 4home88一必发 5

 

  1. IDirectSound8 *m_pDS=NULL;    
  2. DirectSoundCreate8(NULL,&m_pDS,NULL);  

二) 设置合营级
Windows
是3个多职责环境,同暂时间有五个应用程序去拜访设备。通过行使合营等第,DirectSound能够有限支撑应用程序不会在其他设施使用时去做客,每一个DirectSound应用程序都有二个搭档次和等级别,那么些等级决定着访问硬件的权能。
在创设二个装置对象今后,必须经过用IDirectSound八的SetCooperativeLevel()设置合营权限,不然将听不到声音。SetCooperativeLevel()的原型如下

[cpp] view
plaincopyhome88一必发 6home88一必发 7

 

  1. HRESULT SetCooperativeLevel(  
  2.  HWND hwnd,  
  3.  DWORD dwLevel  
  4. )  

参数的含义如下:
hwnd:应用程序窗口句柄。
dwLevel:支持以下三种等第。
DSSCL_EXCLUSIVE:与DSSCL_P悍马H二IOPRADOITY具备同等的效劳。
DSSCL_NOCR-VMAL:寻常的和谐层级标识,别的程序可共享声卡设备开展广播。
DSSCL_PPAJEROIOLX570ITY:设置声卡设备为当前程序独占。
DSSCL_W汉兰达ITEP猎豹CS6IMACRUISER:可写主缓冲区,此时副缓冲区就无法展开始播放报处理,即无法将次缓冲区的数据送进混声器,再出口到主缓冲区上。那是最完全调整声音播放的法子。

3) 创设八个主缓冲对象
采纳IDirectSound八的CreateSoundBuffer()能够创设三个IDirectSoundBuffer接口的主缓冲区对象。CreateSoundBuffer()的原型如下。

[cpp] view
plaincopyhome88一必发 8home88一必发 9

 

  1. HRESULT CreateSoundBuffer(  
  2.  LPCDSBUFFERDESC pcDSBufferDesc,  
  3.  LPDIRECTSOUNDBUFFER * ppDSBuffer,  
  4.  LPUNKNOWN pUnkOuter  
  5. )  

参数的含义如下:
pcDSBufferDesc:描述声音缓冲的DSBUFFE汉兰达DESC结构体的地点
ppDSBuffer:重返的IDirectSoundBuffer接口的指标的地址。
pUnkOuter:必须设置为NULL。
在这之中涉及到二个叙述声音缓冲的组织体DSBUFFECR-VDESC,该结构体的定义如下:

[cpp] view
plaincopyhome88一必发 10home88一必发 11

 

  1. typedef struct _DSBUFFERDESC  
  2. {  
  3.     DWORD           dwSize;  
  4.     DWORD           dwFlags;  
  5.     DWORD           dwBufferBytes;  
  6.     DWORD           dwReserved;  
  7.     LPWAVEFORMATEX  lpwfxFormat;  
  8. } DSBUFFERDESC  

简言之解释一下其中的变量的意思:
dwSize:结构体的大大小小。必须初叶化该值。
dwFlags:设置声音缓存的性质。有多数摘取,能够组合使用,就不壹1列出了。详细的参数能够查看文书档案。
dwBufferBytes:缓冲的分寸。
dwReserved:保留参数,如今并未有用。
lpwfxFormat:指向3个WAVE格式文件头的指针。
设置DSBUFFE汉兰达DESC实现后,即可使用CreateSoundBuffer()创制主缓冲了。示例代码如下:

[cpp] view
plaincopyhome88一必发 12home88一必发 13

 

  1. DSBUFFERDESC dsbd;  
  2. memset(&dsbd,0,sizeof(dsbd));  
  3. dsbd.dwSize=sizeof(dsbd);  
  4. dsbd.dwFlags=DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLPOSITIONNOTIFY |DSBCAPS_GETCURRENTPOSITION2;  
  5. dsbd.dwBufferBytes=MAX_AUDIO_BUF*BUFFERNOTIFYSIZE;   
  6. //WAVE Header  
  7. dsbd.lpwfxFormat=(WAVEFORMATEX*)malloc(sizeof(WAVEFORMATEX));  
  8. dsbd.lpwfxFormat->wFormatTag=WAVE_FORMAT_PCM;     
  9. /* format type */  
  10. (dsbd.lpwfxFormat)->nChannels=channels;            
  11. /* number of channels (i.e. mono, stereo…) */  
  12. (dsbd.lpwfxFormat)->nSamplesPerSec=sample_rate;       
  13. /* sample rate */  
  14. (dsbd.lpwfxFormat)->nAvgBytesPerSec=sample_rate*(bits_per_sample/8)*channels;   
  15. /* for buffer estimation */  
  16. (dsbd.lpwfxFormat)->nBlockAlign=(bits_per_sample/8)*channels;          
  17. /* block size of data */  
  18. (dsbd.lpwfxFormat)->wBitsPerSample=bits_per_sample;       
  19. /* number of bits per sample of mono data */  
  20. (dsbd.lpwfxFormat)->cbSize=0;  
  21.   
  22.   
  23. //Creates a sound buffer object to manage audio samples.   
  24. HRESULT hr1;  
  25. if( FAILED(m_pDS->CreateSoundBuffer(&dsbd,&m_pDSBuffer,NULL))){     
  26.     return FALSE;  
  27. }  

四) 创立多个副缓冲对象
行使IDirectSoundBuffer的QueryInterface()能够收获叁个IDirectSoundBuffer八接口的靶子。IDirectSoundBuffer捌的GUID为IID_IDirectSoundBuffer捌。示例代码如下。

[cpp] view
plaincopyhome88一必发 14home88一必发 15

 

  1. IDirectSoundBuffer *m_pDSBuffer=NULL;  
  2. IDirectSoundBuffer8 *m_pDSBuffer8=NULL;  
  3. …  
  4. if( FAILED(m_pDSBuffer->QueryInterface(IID_IDirectSoundBuffer8,(LPVOID*)&m_pDSBuffer8))){  
  5.     return FALSE ;  
  6. }  

伍) 创立公告对象
行使IDirectSoundBuffer8的QueryInterface()能够收获3个IDirectSoundNotify捌接口的指标。IDirectSoundBuffer八的GUID为IID_IDirectSoundNotify。示例代码如下。

[cpp] view
plaincopyhome88一必发 16home88一必发 17

 

  1. IDirectSoundBuffer8 *m_pDSBuffer8=NULL;  
  2. IDirectSoundNotify8 *m_pDSNotify=NULL;    
  3. …  
  4. if(FAILED(m_pDSBuffer8->QueryInterface(IID_IDirectSoundNotify,(LPVOID*)&m_pDSNotify))){  
  5.     return FALSE ;  
  6. }  

一句话回顾一下公告对象的职能:当DirectSound缓冲区中的数据播放完成后,告知系统应该填充新的数额。

陆) 设置文告地方
选用IDirectSoundNotify8的SetNotificationPositions()能够设置文告的职位。SetNotificationPositions()的原型如下。

[cpp] 最轻便易行的视音频播放示例8,输出设备基本操作。view
plaincopyhome88一必发 18home88一必发 19

 

  1. HRESULT SetNotificationPositions(  
  2.          DWORD dwPositionNotifies,  
  3.          LPCDSBPOSITIONNOTIFY pcPositionNotifies  
  4. )  

参数含义如下。
dwPositionNotifies:DSBPOSITIONNOTIFY结构体的数量。既涵盖多少个关照的岗位。
pcPositionNotifies:指向DSBPOSITIONNOTIFY结构体数组的指针。
再那里提到到一个布局体DSBPOSITIONNOTIFY,它讲述了文告的职位。DSBPOSITIONNOTIFY的概念如下。

[cpp] view
plaincopyhome88一必发 20home88一必发 21

 

  1. typedef struct DSBPOSITIONNOTIFY {  
  2.     DWORD dwOffset;  
  3.     HANDLE hEventNotify;  
  4. } DSBPOSITIONNOTIFY;  

它的成员的意义如下。
最轻便易行的视音频播放示例8,输出设备基本操作。dwOffset:通告事件触发的岗位(距离缓冲开头地点的偏移量)。
h伊芙ntNotify:触发的事件的句柄。

柒) 起始播报
动用IDirectSoundBuffer八的SetCurrentPosition
()可以安装播放的任务。SetCurrentPosition ()原型如下

[cpp] view
plaincopyhome88一必发 22home88一必发 23

 

  1. HRESULT SetCurrentPosition(  
  2.          DWORD dwNewPosition  
  3. )  

里头dwNewPosition是播放点与缓冲区第1个字节之间的偏移量。
运用IDirectSoundBuffer8的Play ()能够起先广播音频数据。Play ()原型如下。

[cpp] view
plaincopyhome88一必发 24home88一必发 25

 

  1. HRESULT Play(  
  2.          DWORD dwReserved1,  
  3.          DWORD dwPriority,  
  4.          DWORD dwFlags  
  5. )  

参数含义:
dwReserved1:保留参数,必须取0。
dwPriority:优先级,一般情状下取0就能够。
dwFlags:标记位。近年来周围的是DSBPLAY_LOOPING。当播放至缓冲区最后的时候,重新从缓冲区启幕处发轫播报。

二. 循环往复播放音响
1) 数据填充至副缓冲区

数据填充至副缓冲区以前,要求先选择Lock()锁定缓冲区。然后就能够运用fread(),memcpy()等艺术将PCM音频采集样品数据填充至缓冲区。数据填充达成后,使用Unlock()撤除对缓冲区的锁定。
Lock()函数的原型如下。

[cpp] view
plaincopyhome88一必发 26home88一必发 27

 

  1. HRESULT Lock(  
  2.          DWORD dwOffset,  
  3.          DWORD dwBytes,  
  4.          LPVOID * ppvAudioPtr1,  
  5.          LPDWORD  pdwAudioBytes1,  
  6.          LPVOID * ppvAudioPtr2,  
  7.          LPDWORD pdwAudioBytes2,  
  8.          DWORD dwFlags  
  9. )  

参数的意义如下。
dwOffset:锁定的内存与缓冲区首地址之间的偏移量。
dwBytes:锁定的缓存的分寸。
ppv奥迪(Audi)oPtr一:获取到的针对性缓存数据的指针。
pdw奥迪(Audi)oBytes壹:获取到的缓存数据的大小。
ppv奥迪(Audi)oPtr二:未有使用,设置为NULL。
pdw奥迪oBytes贰:没有利用,设置为0。
dwFlags:一时并未有色金属切磋所究。

UnLock()函数的原型如下。

[cpp] view
plaincopyhome88一必发 28home88一必发 29

 

  1. HRESULT Unlock(  
  2.          LPVOID pvAudioPtr1,  
  3.          DWORD dwAudioBytes1,  
  4.          LPVOID pvAudioPtr2,  
  5.          DWORD dwAudioBytes2  
  6. )  

参数含义如下。
pv奥迪(Audi)oPtr一:通过Lock()获取到的指向缓存数据的指针。
dw奥迪oBytes一:写入的数据量。
pv奥迪(Audi)oPtr二:没有用到。

dw奥迪oBytes二:未有用到。

贰) 等待播放完结

基于从前安装的打招呼机制,使用WaitForMultipleObjects()等待缓冲区中的数据播放完成,然后进入下三个循环往复。

此间大家说说设备操作这一齐。

那边大家说说设备操作那三只。

此处大家说说设备操作这一起。

广播音频流程总计

DirectSound播放PCM音频数据的流程如下图所示。

 home88一必发 30

内部涉嫌到的多少个结构体之间的涉及如下图所示。
 

home88一必发 31

一. 输出设备操作

在DirectSound中,1个装备对象就代表二个音频设备,播放设备对象对应播放设备,输入设备对象对应输入设备。因为DirectSound使用COM协议,因而每一个设备对象都用接口来代表。那里IDirectSound8那么些接口就表示了二个输出设备对象,应用程序能够对同一个音频设备开创多个装备对象来进行音频输出操作。旧版本的DirectSound使用的是IDirectSound接口,比较前者少了一部分功用。

一. 输出设备操作

在DirectSound中,多个设施对象就意味着二个音频设备,播放设备对象对应播放设备,输入设备对象对应输入设备。因为DirectSound使用COM协议,因而各类设备对象都用接口来代表。那里IDirectSound8其一接口就代表了1个输出设备对象,应用程序能够对同一个音频设备开创多少个设施对象来进展音频输出操作。旧版本的DirectSound使用的是IDirectSound接口,相比较前者少了部分作用。

1. 输出设备操作

在DirectSound中,贰个设备对象就表示2个音频设备,播放设备对象对应播放设备,输入设备对象对应输入设备。因为DirectSound使用COM协议,由此每一种设备对象都用接口来表示。那里IDirectSound8本条接口就意味着了四个输出设备对象,应用程序能够对同一个音频设备开创几个设备对象来打开音频输出操作。旧版本的DirectSound使用的是IDirectSound接口,相比较前者少了有个别意义。

代码

贴上源代码。

[cpp] view
plaincopyhome88一必发 32home88一必发 33

 

  1. /** 
  2.  * 最简易的DirectSound播放音频的例子(DirectSound播放PCM) 
  3.  * Simplest Audio Play DirectSound (DirectSound play PCM)  
  4.  * 
  5.  * 雷霄骅 Lei Xiaohua 
  6.  * leixiaohua1020@126.com 
  7.  * 中华夏族民共和国审计大学/数字电视本事 
  8.  * Communication University of China / Digital TV Technology 
  9.  *  
  10.  * 
  11.  * 本程序选用DirectSound播放PCM音频采集样品数据。 
  12.  * 是最简易的DirectSound播放音频的学科。 
  13.  * 
  14.  * 函数调用步骤如下:  
  15.  * 
  16.  * [初始化] 
  17.  * DirectSoundCreate八(): 创造二个DirectSound对象。 
  18.  * SetCooperativeLevel(): 设置合营权限,不然未有声音。 
  19.  * IDirectSound捌->CreateSoundBuffer(): 创造1个主缓冲区对象。 
  20.  * IDirectSoundBuffer->QueryInterface(IID_IDirectSoundBuffer8..):  
  21.  *          创设一个副缓冲区对象,用来囤积要播放的响动数据文件。 
  22.  * IDirectSoundBuffer8->QueryInterface(IID_IDirectSoundNotify..):  
  23.  *          成立通告对象,文告应用程序钦命播放地点已经到达。 
  24.  * IDirectSoundNotify八->SetNotificationPositions(): 设置文告地方。 
  25.  * IDirectSoundBuffer8->SetCurrentPosition(): 设置播放的起先点。 
  26.  * IDirectSoundBuffer8->Play(): 开端播报。 
  27.  * 
  28.  * [巡回播放数据] 
  29.  * IDirectSoundBuffer捌->Lock(): 锁定副缓冲区,准备写入数据。 
  30.  * fread(): 读取多少。 
  31.  * IDirectSoundBuffer八->Unlock(): 解锁副缓冲区。 
  32.  * WaitForMultipleObjects(): 等待“播放地方已经高达”的关照。 
  33.  * 
  34.  * This software plays PCM raw audio data using DirectSound. 
  35.  * It’s the simplest tutorial about DirectSound. 
  36.  * 
  37.  * The process is shown as follows: 
  38.  * 
  39.  * [Init] 
  40.  * DirectSoundCreate8(): Init DirectSound object. 
  41.  * SetCooperativeLevel(): Must set, or we won’t hear sound. 
  42.  * IDirectSound8->CreateSoundBuffer(): Create primary sound buffer. 
  43.  * IDirectSoundBuffer->QueryInterface(IID_IDirectSoundBuffer8..):  
  44.  *          Create secondary sound buffer. 
  45.  * IDirectSoundBuffer8->QueryInterface(IID_IDirectSoundNotify..):  
  46.  *          Create Notification object. 
  47.  * IDirectSoundNotify8->SetNotificationPositions(): 
  48.  *          Set Notification Positions. 
  49.  * IDirectSoundBuffer8->SetCurrentPosition(): Set position to start. 
  50.  * IDirectSoundBuffer8->Play(): Begin to play. 
  51.  * 
  52.  * [Loop to play data] 
  53.  * IDirectSoundBuffer8->Lock(): Lock secondary buffer. 
  54.  * fread(): get PCM data. 
  55.  * IDirectSoundBuffer8->Unlock(): UnLock secondary buffer. 
  56.  * WaitForMultipleObjects(): Wait for Notifications. 
  57.  */  
  58. #include <stdio.h>  
  59. #include <stdlib.h>  
  60. #include <windows.h>  
  61. #include <dsound.h>  
  62.   
  63.   
  64. #define MAX_AUDIO_BUF 4   
  65. #define BUFFERNOTIFYSIZE 192000   
  66.   
  67.   
  68. int sample_rate=44100;  //PCM sample rate  
  69. int channels=2;         //PCM channel number  
  70. int bits_per_sample=16; //bits per sample  
  71.   
  72. BOOL main(int argc,char * argv[])  
  73. {  
  74.     int i;  
  75.     FILE * fp;  
  76.     if((fp=fopen(“../NocturneNo2inEflat_44.1k_s16le.pcm”,”rb”))==NULL){  
  77.         printf(“cannot open this file\n”);  
  78.         return -1;  
  79.     }  
  80.   
  81.     IDirectSound8 *m_pDS=NULL;                    
  82.     IDirectSoundBuffer8 *m_pDSBuffer8=NULL; //used to manage sound buffers.  
  83.     IDirectSoundBuffer *m_pDSBuffer=NULL;     
  84.     IDirectSoundNotify8 *m_pDSNotify=NULL;        
  85.     DSBPOSITIONNOTIFY m_pDSPosNotify[MAX_AUDIO_BUF];  
  86.     HANDLE m_event[MAX_AUDIO_BUF];  
  87.   
  88.     SetConsoleTitle(TEXT(“Simplest Audio Play DirectSound”));//Console Title  
  89.     //Init DirectSound  
  90.     if(FAILED(DirectSoundCreate8(NULL,&m_pDS,NULL)))  
  91.         return FALSE;  
  92.     if(FAILED(m_pDS->SetCooperativeLevel(FindWindow(NULL,TEXT(“Simplest Audio Play DirectSound”)),DSSCL_NORMAL)))  
  93.         return FALSE;  
  94.   
  95.   
  96.     DSBUFFERDESC dsbd;  
  97.     memset(&dsbd,0,sizeof(dsbd));  
  98.     dsbd.dwSize=sizeof(dsbd);  
  99.     dsbd.dwFlags=DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLPOSITIONNOTIFY |DSBCAPS_GETCURRENTPOSITION2;  
  100.     dsbd.dwBufferBytes=MAX_AUDIO_BUF*BUFFERNOTIFYSIZE;   
  101.     //WAVE Header  
  102.     dsbd.lpwfxFormat=(WAVEFORMATEX*)malloc(sizeof(WAVEFORMATEX));  
  103.     dsbd.lpwfxFormat->wFormatTag=WAVE_FORMAT_PCM;     
  104.     /* format type */  
  105.     (dsbd.lpwfxFormat)->nChannels=channels;            
  106.     /* number of channels (i.e. mono, stereo…) */  
  107.     (dsbd.lpwfxFormat)->nSamplesPerSec=sample_rate;       
  108.     /* sample rate */  
  109.     (dsbd.lpwfxFormat)->nAvgBytesPerSec=sample_rate*(bits_per_sample/8)*channels;   
  110.     /* for buffer estimation */  
  111.     (dsbd.lpwfxFormat)->nBlockAlign=(bits_per_sample/8)*channels;          
  112.     /* block size of data */  
  113.     (dsbd.lpwfxFormat)->wBitsPerSample=bits_per_sample;       
  114.     /* number of bits per sample of mono data */  
  115.     (dsbd.lpwfxFormat)->cbSize=0;  
  116.   
  117.     //Creates a sound buffer object to manage audio samples.   
  118.     HRESULT hr1;  
  119.     if( FAILED(m_pDS->CreateSoundBuffer(&dsbd,&m_pDSBuffer,NULL))){     
  120.         return FALSE;  
  121.     }  
  122.     if( FAILED(m_pDSBuffer->QueryInterface(IID_IDirectSoundBuffer8,(LPVOID*)&m_pDSBuffer8))){  
  123.         return FALSE ;  
  124.     }  
  125.     //Get IDirectSoundNotify8  
  126.     if(FAILED(m_pDSBuffer8->QueryInterface(IID_IDirectSoundNotify,(LPVOID*)&m_pDSNotify))){  
  127.         return FALSE ;  
  128.     }  
  129.     for(i =0;i<MAX_AUDIO_BUF;i++){  
  130.         m_pDSPosNotify[i].dwOffset =i*BUFFERNOTIFYSIZE;  
  131.         m_event[i]=::CreateEvent(NULL,false,false,NULL);   
  132.         m_pDSPosNotify[i].hEventNotify=m_event[i];  
  133.     }  
  134.     m_pDSNotify->SetNotificationPositions(MAX_AUDIO_BUF,m_pDSPosNotify);  
  135.     m_pDSNotify->Release();  
  136.   
  137.     //Start Playing  
  138.     BOOL isPlaying =TRUE;  
  139.     LPVOID buf=NULL;  
  140.     DWORD  buf_len=0;  
  141.     DWORD res=WAIT_OBJECT_0;  
  142.     DWORD offset=BUFFERNOTIFYSIZE;  
  143.   
  144.     m_pDSBuffer8->SetCurrentPosition(0);  
  145.     m_pDSBuffer8->Play(0,0,DSBPLAY_LOOPING);  
  146.     //Loop  
  147.     while(isPlaying){  
  148.         if((res >=WAIT_OBJECT_0)&&(res <=WAIT_OBJECT_0+3)){  
  149.             m_pDSBuffer8->Lock(offset,BUFFERNOTIFYSIZE,&buf,&buf_len,NULL,NULL,0);  
  150.             if(fread(buf,1,buf_len,fp)!=buf_len){  
  151.                 //File End  
  152.                 //Loop:  
  153.                 fseek(fp, 0, SEEK_SET);  
  154.                 fread(buf,1,buf_len,fp);  
  155.                 //Close:  
  156.                 //isPlaying=0;  
  157.             }  
  158.             m_pDSBuffer8->Unlock(buf,buf_len,NULL,0);  
  159.             offset+=buf_len;  
  160.             offset %= (BUFFERNOTIFYSIZE * MAX_AUDIO_BUF);  
  161.             printf(“this is %7d of buffer\n”,offset);  
  162.         }  
  163.         res = WaitForMultipleObjects (MAX_AUDIO_BUF, m_event, FALSE, INFINITE);  
  164.     }  
  165.   
  166.     return 0;  
  167. }  

1.1 枚举

HRESULT WINAPI DirectSoundEnumerateW(In LPDSENUMCALLBACKW
pDSEnumCallback, In_opt LPVOID pContext);
typedef BOOL (CALLBACK *LPDSENUMCALLBACKW)(LPGUID, LPCWSTR, LPCWSTR,
LPVOID);

笔者们透过DirectSoundEnumerateW这些函数来枚举,该函数需求传入三个回调函数(原型见上),当枚举到2个装置时该回调会被调用。只要大家想三番五次枚举,需求在那么些回调用中回到TRUE来告诉系统,不然重临FALSE。另多个参数pContext同意用户传入额外的参数,传入回调函数的终极一个实参就是以此pContext。枚举时,DirectSound会将默许也认作三个单独的装置来对待,由此暗中认可设备会被重新枚举3回。当设备被看做私下认可设备枚举时,它的GUID和设备描述字符串都为空,须求小心处理,那里本身直接跳过了该次枚举:

if (DirectSoundEnumerateW(enumerateCallback, nullptr) != DS_OK) {
    ...
}

BOOL CALLBACK DirectSoundBasic::enumerateCallback(LPGUID guid,
                                              LPCWSTR deviceDescription,
                                              LPCWSTR deviceDriverModule,
                                              LPVOID context)
{
    Q_UNUSED(context);

    //  if primary device, skip it
    if (guid == nullptr)        return TRUE;

    ...
}

1.1 枚举

HRESULT WINAPI DirectSoundEnumerateW(In LPDSENUMCALLBACKW
pDSEnumCallback, In_opt LPVOID pContext);
typedef BOOL (CALLBACK *LPDSENUMCALLBACKW)(LPGUID, LPCWSTR, LPCWSTR,
LPVOID);

我们透过DirectSoundEnumerateW那些函数来枚举,该函数供给传入一个回调函数(原型见上),当枚举到贰个设施时该回调会被调用。假若大家想三番7回枚举,必要在这么些回调用中回到TRUE来告诉系统,不然重返FALSE。另2个参数pContext同意用户传入额外的参数,传入回调函数的结尾二个实参便是以此pContext。枚举时,DirectSound会将暗中认可也认作二个单身的装备来比较,由此暗中同意设备会被另行枚举一次。当设备被当做暗中认可设备枚举时,它的GUID和设备描述字符串都为空,供给小心处理,那里作者一直跳过了该次枚举:

if (DirectSoundEnumerateW(enumerateCallback, nullptr) != DS_OK) {
    ...
}

BOOL CALLBACK DirectSoundBasic::enumerateCallback(LPGUID guid,
                                              LPCWSTR deviceDescription,
                                              LPCWSTR deviceDriverModule,
                                              LPVOID context)
{
    Q_UNUSED(context);

    //  if primary device, skip it
    if (guid == nullptr)        return TRUE;

    ...
}

1.1 枚举

HRESULT WINAPI DirectSoundEnumerateW(In LPDSENUMCALLBACKW
pDSEnumCallback, In_opt LPVOID pContext);
typedef BOOL (CALLBACK *LPDSENUMCALLBACKW)(LPGUID, LPCWSTR, LPCWSTR,
LPVOID);

咱们经过DirectSoundEnumerateW那一个函数来枚举,该函数需求传入一个回调函数(原型见上),当枚举到3个装置时该回调会被调用。假诺大家想两次三番枚举,须要在这些回调用中回到TRUE来告诉系统,不然再次回到FALSE。另贰个参数pContext允许用户传入额外的参数,传入回调函数的最终二个实参就是以此pContext。枚举时,DirectSound会将暗中同意也认作2个独自的设备来对待,因而暗许设备会被再一次枚举二遍。当设备被看成暗中认可设备枚举时,它的GUID和设备描述字符串都为空,要求小心处理,那里本身直接跳过了该次枚举:

if (DirectSoundEnumerateW(enumerateCallback, nullptr) != DS_OK) {
    ...
}

BOOL CALLBACK DirectSoundBasic::enumerateCallback(LPGUID guid,
                                              LPCWSTR deviceDescription,
                                              LPCWSTR deviceDriverModule,
                                              LPVOID context)
{
    Q_UNUSED(context);

    //  if primary device, skip it
    if (guid == nullptr)        return TRUE;

    ...
}

运维结果

代码运转之后,会弹出1个“调节台”对话框如下图所示。同时音频设备里面能够听到广播的鸣响。

home88一必发 34

 

1.二 创造设备对象

HRESULT WINAPI DirectSoundCreate8(In_opt LPCGUID pcGuidDevice,
Outptr LPDIRECTSOUND8 *ppDS8, Pre_null LPUNKNOWN pUnkOuter);

调用DirectSoundCreate八函数,大家能够成立2个设施对象,通过传播1个枚举设备时获得的GUID,函数会返给大家二个IDirectSound8接口代表设备对象:

IDirectSound8* directSound8;
if (DirectSoundCreate8(guid, &directSound8, NULL) != DS_OK) {
    std::wcout << L"[error] DirectSoundCreate8 call error!";
    return TRUE;    //  if error, skip this device
}

1.2 创立设备对象

HRESULT WINAPI DirectSoundCreate8(In_opt LPCGUID pcGuidDevice,
Outptr LPDIRECTSOUND8 *ppDS8, Pre_null LPUNKNOWN pUnkOuter);

调用DirectSoundCreate捌函数,大家能够成立二个设施对象,通过传播贰个枚举设备时收获的GUID,函数会返给我们2个IDirectSound8接口代表设备对象:

IDirectSound8* directSound8;
if (DirectSoundCreate8(guid, &directSound8, NULL) != DS_OK) {
    std::wcout << L"[error] DirectSoundCreate8 call error!";
    return TRUE;    //  if error, skip this device
}

一.二 创制设备对象

HRESULT WINAPI DirectSoundCreate8(In_opt LPCGUID pcGuidDevice,
Outptr LPDIRECTSOUND8 *ppDS8, Pre_null LPUNKNOWN pUnkOuter);

调用DirectSoundCreate八函数,大家能够创造二个设施对象,通过传播一个枚举设备时得到的GUID,函数会返给大家1个IDirectSound8接口代表设备对象:

IDirectSound8* directSound8;
if (DirectSoundCreate8(guid, &directSound8, NULL) != DS_OK) {
    std::wcout << L"[error] DirectSoundCreate8 call error!";
    return TRUE;    //  if error, skip this device
}

下载

代码位于“Simplest Media Play”中

 

SourceForge项目地址:

CSDN下载地址:

 

上述工程分包了应用各个API(Direct3D,OpenGL,GDI,DirectSound,SDL二)播放多媒体例子。其中音频输入为PCM采集样品数据。输出至系统的声卡播放出来。录像输入为YUV/汉兰达GB像素数据。输出至显示屏上的3个窗口播放出来。
经过本工程的代码初学者能够相当慢学习运用这多少个API播放录制和节奏的技巧。
共计包罗了如下多少个子工程:
simplest_audio_play_directsound: 
使用DirectSound播放PCM音频采集样品数据。
simplest_audio_play_sdl2:  使用SDL2播放PCM音频采集样品数据。
simplest_video_play_direct三d: 
使用Direct3D的Surface播放福特ExplorerGB/YUV录制像素数据。
simplest_video_play_direct3d_texture:使用Direct3D的Texture播放凯雷德GB录制像素数据。
simplest_video_play_gdi:  使用GDI播放奇骏GB/YUV录像像素数据。
simplest_video_play_opengl:  使用OpenGL播放HummerH贰GB/YUV录制像素数据。
simplest_video_play_opengl_texture:
使用OpenGL的Texture播放YUV视频像素数据。
simplest_video_play_sdl二:  使用SDL2播放奥迪Q5GB/YUV录像像素数据。

 

from:

1.三 设置设备对象优先级

HRESULT IDirectSound8::SetCooperativeLevel(HWND hwnd, DWORD dwLevel)

在利用设备对象创设缓冲区(用来捕获、播放音频)以前,大家必要安装设备对象的合营品级。那些合作等级也正是用户对设施开始展览操作的优先级,分为:

  • DSSCL_EXCLUSIVE:
    互斥等级。对于DirectX捌.0在先版本,仅播放当下应用的节拍数据,别的应用的音响不会被广播;对于DirectX捌.0级之后版本,同DSSCL_PRIORITY版本。

  • DSSCL_NORMAL
    普通品级,那种等第下的应用程序具备最坦荡的多职分和财富共享表现,可是那种利用不能够改造主缓冲区音频数据格式,输出音频格式被限制为8位数据。在DirectSound中,次缓冲区用来填充应用程序必要播放的响声,主缓冲区会对几个次缓冲区(大概是本金和利息用的,也说不定是其余使用的)进行混音,然后用声卡输出播放。

  • DSSCL_PRIORITY: 优先等级,可以变动主缓冲区数据格式。
  • DSSCL_WRITEPRIMARY:写主缓冲区等第,应用能够一贯写入主缓冲区,此时有着次缓冲区不会被广播(要是设备的驱动是DirectSound模拟出来的,则无法设置该品级)。

留意该函数供给传入八个窗口句柄,因为大家今日只介绍DirectSound的基本操作,笔者一直传入桌面窗口的句柄并设固定DSSCL_NORMAL优先级:

if (directSound8->SetCooperativeLevel(GetDesktopWindow(), DSSCL_NORMAL) != DS_OK) {
    std::wcout << L"[error] SetCooperativeLevel call error!";
    return TRUE;
}

一.3 设置设备对象优先级

HRESULT IDirectSound8::SetCooperativeLevel(HWND hwnd, DWORD dwLevel)

在应用设备对象创设缓冲区(用来捕获、播放音频)在此以前,大家供给设置设备对象的协作品级。那一个同盟品级也正是用户对设备实行操作的优先级,分为:

  • DSSCL_EXCLUSIVE:
    互斥品级。对于DirectX捌.0在先版本,仅播放当下使用的旋律数据,其余应用的响动不会被广播;对于DirectX八.0级之后版本,同DSSCL_PRIORITY版本。

  • DSSCL_NORMAL
    普通品级,这种品级下的应用程序具备最坦荡的多任务和能源共享表现,不过那种使用不可能改造主缓冲区音频数据格式,输出音频格式被限制为8位数据。在DirectSound中,次缓冲区用来填充应用程序要求播放的响动,主缓冲区会对多个次缓冲区(恐怕是本金和利息用的,也大概是别的应用的)进行混音,然后用声卡输出播放。

  • DSSCL_PRIORITY: 优先等级,可以转移主缓冲区数据格式。
  • DSSCL_WRITEPRIMARY:写主缓冲区等级,应用能够一向写入主缓冲区,此时颇具次缓冲区不会被广播(如若设备的驱动是DirectSound模拟出来的,则不可能安装该等第)。

留意该函数必要传入一个窗口句柄,因为大家明天只介绍DirectSound的基本操作,小编一向传入桌面窗口的句柄并设定点DSSCL_NORMAL优先级:

if (directSound8->SetCooperativeLevel(GetDesktopWindow(), DSSCL_NORMAL) != DS_OK) {
    std::wcout << L"[error] SetCooperativeLevel call error!";
    return TRUE;
}

一.三 设置设备对象优先级

HRESULT IDirectSound8::SetCooperativeLevel(HWND hwnd, DWORD dwLevel)

在使用设备对象成立缓冲区(用来捕获、播放音频)以前,大家须要安装设备对象的经济同盟品级。那么些协作品级相当于用户对设施开始展览操作的优先级,分为:

  • DSSCL_EXCLUSIVE:
    互斥等第。对于DirectX8.0在此以前版本,仅播放当下使用的音频数据,别的使用的响动不会被广播;对于DirectX8.0级之后版本,同DSSCL_PRIORITY版本。

  • DSSCL_NORMAL
    普通品级,那种级别下的应用程序具备最坦荡的多职分和财富共享表现,但是那种应用不可能改换主缓冲区音频数据格式,输出音频格式被限制为8位数据。在DirectSound中,次缓冲区用来填充应用程序须要播放的响动,主缓冲区会对三个次缓冲区(恐怕是本金和利息用的,也可能是此外使用的)举行混音,然后用声卡输出播放。

  • DSSCL_PRIORITY: 优先品级,可以转移主缓冲区数据格式。
  • DSSCL_WRITEPRIMARY:写主缓冲区品级,应用能够直接写入主缓冲区,此时有着次缓冲区不会被广播(借使设备的驱动是DirectSound模拟出来的,则不能够安装该等第)。

只顾该函数供给传入1个窗口句柄,因为我们今日只介绍DirectSound的基本操作,笔者一向传入桌面窗口的句柄并设固定DSSCL_NORMAL优先级:

if (directSound8->SetCooperativeLevel(GetDesktopWindow(), DSSCL_NORMAL) != DS_OK) {
    std::wcout << L"[error] SetCooperativeLevel call error!";
    return TRUE;
}

一.四 设备手艺

HRESULT IDirectSound8::GetCaps(LPDSCAPS pDSCaps)

不等的音频播放设备具备分歧的力量,DirectSound允许大家查询设备的本领:

  • 是否由此Microsoft认证。
  • 知不知道帮忙最小最大采集样品率之间的富有采集样品率。
  • 当没有DirectSound驱动时模拟驱动。
  • 次第缓冲区格式(16人、七个人)。
  • 次第缓冲区声道帮忙(单声道、立体声即多声道)。
  • 不精准的数额(某个声卡不协理):
    • 缓冲区(静态缓冲区、流缓冲区、3D缓冲区)最大数、空闲数。
    • 声卡上的总内部存款和储蓄器数量、空闲内部存款和储蓄器数量、最大空闲块大小,

我们传给GetCaps三个DSCAPS结构体地址,然后系统就帮我们填充相应的数量,调用GetCaps前须求将DSCAPS结构体的dwSize设置为DSCAPS的轻重:

DSCAPS deviceCapability = { sizeof(deviceCapability) };
if (directSound8->GetCaps(&deviceCapability) != DS_OK) {
    std::wcout << L"[error] GetCaps call error!";
    return TRUE;
}

一.四 设备技能

HRESULT IDirectSound8::GetCaps(LPDSCAPS pDSCaps)

今非昔比的节奏播放设备具有区别的力量,DirectSound允许大家询问设备的技巧:

  • 是还是不是通过Microsoft认证。
  • 知不知道援救最小最大采集样品率之间的全体采集样品率。
  • 当未有DirectSound驱动时模拟驱动。
  • 程序缓冲区格式(拾三位、八人)。
  • 程序缓冲区声道支持(单声道、立体声即多声道)。
  • 不精准的数额(有个别声卡不帮衬):
    • 缓冲区(静态缓冲区、流缓冲区、3D缓冲区)最大数、空闲数。
    • 声卡上的总内部存款和储蓄器数量、空闲内部存款和储蓄器数量、最大空闲块大小,

大家传给GetCaps2个DSCAPS结构体地址,然后系统就帮我们填充相应的数量,调用GetCaps前要求将DSCAPS结构体的dwSize设置为DSCAPS的轻重缓急:

DSCAPS deviceCapability = { sizeof(deviceCapability) };
if (directSound8->GetCaps(&deviceCapability) != DS_OK) {
    std::wcout << L"[error] GetCaps call error!";
    return TRUE;
}

一.4 设备技术

HRESULT IDirectSound8::GetCaps(LPDSCAPS pDSCaps)

不等的点子播放设备具有分裂的手艺,DirectSound允许大家查询设备的力量:

  • 是或不是由此Microsoft认证。
  • 知道还是不知道支持最小最大采集样品率之间的全数采集样品率。
  • 当未有DirectSound驱动时模拟驱动。
  • 次第缓冲区格式(1八个人、七个人)。
  • 次第缓冲区声道支持(单声道、立体声即多声道)。
  • 不精准的数码(某个声卡不援助):
    • 缓冲区(静态缓冲区、流缓冲区、3D缓冲区)最大数、空闲数。
    • 声卡上的总内部存款和储蓄器数量、空闲内部存款和储蓄器数量、最大空闲块大小,

笔者们传给GetCaps2个DSCAPS结构体地址,然后系统就帮大家填充相应的数据,调用GetCaps前供给将DSCAPS结构体的dwSize设置为DSCAPS的分寸:

DSCAPS deviceCapability = { sizeof(deviceCapability) };
if (directSound8->GetCaps(&deviceCapability) != DS_OK) {
    std::wcout << L"[error] GetCaps call error!";
    return TRUE;
}

一.5 播放器配置

HRESULT IDirectSound8::GetSpeakerConfig(LPDWORD pdwSpeakerConfig)
HRESULT IDirectSound8::SetSpeakerConfig(LPDWORD pdwSpeakerConfig)

播放器配置只可以是以下之1:

  • DSSPEAKER_5POINT1_SURROUNDDSSPEAKER_5POINT1_BACK:
    家庭影院配置,八个围绕扬声器,1个低音炮。
  • DSSPEAKER_DIRECTOUT:直接播放。
  • DSSPEAKER_HEADPHONE:头戴式动圈耳机。
  • DSSPEAKER_MONO:单声道扬声器。
  • DSSPEAKER_QUAD:四声道播放器。
  • DSSPEAKER_STEREO:立体声播放器。
  • DSSPEAKER_SURROUND:环绕播放器。
  • DSSPEAKER_7POINT1_WIDEDSSPEAKER_7POINT1_SURROUND:家庭影院配置,七个围绕扬声器,一个低音炮。

就算MSDN文书档案未有写清楚,不过透过查以上宏定义大家发现它们是按大小顺序定义的,因而不容许由此O逍客|来含有各个也许,例子中只要调用出错直接回到TRUE表示大家一连枚举设备并继续查询那几个设备才干:

DWORD deviceSpeakerConfiguration;
if (directSound8->GetSpeakerConfig(&deviceSpeakerConfiguration) != DS_OK) {
    std::wcout << L"[error] GetSpeakerConfig call error!";
    return TRUE;
}

1.五 播放器配置

HRESULT IDirectSound8::GetSpeakerConfig(LPDWORD pdwSpeakerConfig)
HRESULT IDirectSound8::SetSpeakerConfig(LPDWORD pdwSpeakerConfig)

播放器配置只可以是以下之壹:

  • DSSPEAKER_5POINT1_SURROUNDDSSPEAKER_5POINT1_BACK:
    家庭影院配置,四个围绕扬声器,贰个低音炮。
  • DSSPEAKER_DIRECTOUT:直接播放。
  • DSSPEAKER_HEADPHONE:头戴式动铁耳机。
  • DSSPEAKER_MONO:单声道扬声器。
  • DSSPEAKER_QUAD:4声道播放器。
  • DSSPEAKER_STEREO:立体声播放器。
  • DSSPEAKER_SURROUND:环绕播放器。
  • DSSPEAKER_7POINT1_WIDEDSSPEAKER_7POINT1_SURROUND:家庭影院配置,多少个围绕扬声器,一个低音炮。

固然如此MSDN文书档案未有写清楚,然而经过查以上宏定义大家发现它们是按大小顺序定义的,由此不容许通过OPRADO|来含有多样或然,例子中一经调用出错直接再次来到TRUE表示大家后续枚举设备并持续查询这些设备本事:

DWORD deviceSpeakerConfiguration;
if (directSound8->GetSpeakerConfig(&deviceSpeakerConfiguration) != DS_OK) {
    std::wcout << L"[error] GetSpeakerConfig call error!";
    return TRUE;
}

一.5 播放器配置

HRESULT IDirectSound8::GetSpeakerConfig(LPDWORD pdwSpeakerConfig)
HRESULT IDirectSound8::SetSpeakerConfig(LPDWORD pdwSpeakerConfig)

播放器配置只可以是以下之一:

  • DSSPEAKER_5POINT1_SURROUNDDSSPEAKER_5POINT1_BACK:
    家庭影院配置,伍个围绕扬声器,1个低音炮。
  • DSSPEAKER_DIRECTOUT:直接播放。
  • DSSPEAKER_HEADPHONE:头戴式耳机。
  • DSSPEAKER_MONO:单声道扬声器。
  • DSSPEAKER_QUAD:四声道播放器。
  • DSSPEAKER_STEREO:立体声播放器。
  • DSSPEAKER_SURROUND:环绕播放器。
  • DSSPEAKER_7POINT1_home88一必发,WIDEDSSPEAKER_7POINT1_SURROUND:家庭影院配置,多少个围绕扬声器,二个低音炮。

虽说MSDN文书档案没有写清楚,可是经过查以上宏定义大家发现它们是按大小顺序定义的,因而不恐怕由此O途乐|来含有多样只怕,例子中1旦调用出错直接重返TRUE表示我们继续枚举设备并承接查询那3个设备才能:

DWORD deviceSpeakerConfiguration;
if (directSound8->GetSpeakerConfig(&deviceSpeakerConfiguration) != DS_OK) {
    std::wcout << L"[error] GetSpeakerConfig call error!";
    return TRUE;
}

二. 周转结果

此次大家用GUI分界面来展示实例运维的结果(出于方便惦记,今后笔者会用调节台来显示示例),为防备用户误操作改变展现的数量本人将大多控件都disable了:

home88一必发 35

完整代码见链接。

二. 运作结果

这一次大家用GUI分界面来体现实例运营的结果(出于方便思索,以往笔者会用调控台来显示示例),为制止用户误操作改换展现的数额自个儿将超越5二%控件都disable了:

home88一必发 36

完全代码见链接。

二. 运维结果

此番大家用GUI分界面来体现实例运营的结果(出于方便记挂,以往作者会用调整台来彰显示例),为严防用户误操作改动展现的数量小编将多数控件都disable了:

home88一必发 37

全体代码见链接。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图