聯(lián)系我們 - 廣告服務 - 聯(lián)系電話:
您的當前位置: > 關注 > > 正文

當前資訊!DirectSound能幫我們做什么?DirectSound開發(fā)指南

來源:CSDN 時間:2023-04-06 10:01:36

1DirectSound簡介(Introduction to DirectSound)

曾經(jīng)學習過Directshow的開發(fā),對于Dsound一直沒有仔細的萊學習,以前只是知道Dsound是做音頻開發(fā)的,我一直以為它和Dshow的結構體系差不多,經(jīng)過仔細學習后,發(fā)現(xiàn),其實他們完全 兩碼事。


(相關資料圖)

閑話少說,下面我們看看DirectSound到底能幫我們做些什么。

1播放WAVE格式的音頻文件或者資源。

2可以同時播放多個音頻。

3Assign high-priority sounds to hardware-controlled buffers

4播放3D立體聲音

5在聲音中添加特技效果,比如回聲,動態(tài)的改變特技的參數(shù)等

6將麥克風或者其他音頻輸入設備的聲音錄制成wave格式的文件

呵呵,DirectSound就能做這么多事情,讀到這里,我都有點懷疑DirectSound是不是就是封裝了mmio系列和wav系列的函數(shù)。因為這些底層的API也能夠完成這些事情。

2DirectSound初體驗(Getting Started with DirectSound)

在開始本節(jié)內(nèi)容前,我會首先提醒一下,如果你想用Directsound開發(fā),那么你首先要包含Dsound.h頭文件,其實我可以實話告訴你,你僅僅包含dsound.h你的工程肯定調(diào)補通,其實下面的一些頭文件也要包含,我第一次就搞了半天才搞好,

#include

#include

#include

#include

如果你還想使用Dsound的API的話,那么你就要在你的vc開發(fā)環(huán)境中添加Dsound..lib庫,

如果你的程序還提示有很多的外部鏈接找不到,那么我建議你可以將下面的庫都添加到你的工程中comctl32.lib dxerr9.lib winmm.lib dsound.lib dxguid.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib,這些是我從Dsound提供的例子中得到的,肯定夠你用的,ok,開發(fā)環(huán)境配置好了。

下面我們簡單的來學習一下如果通過Directsound的API播放聲音,既然是breif overview,那么詳細的內(nèi)容你可以參考下面的一節(jié)內(nèi)容,這里只是簡單的介紹一下播放聲音的步驟。

第一步,創(chuàng)建一個設備對象。

在你的代碼中你可以通過調(diào)用DirectSoundCreat8函數(shù)來創(chuàng)建一個支持IDirectSound8接口的對象,這個對象通常代表缺省的播放設備。當然你可以枚舉可用的設備,然后將設備的GUID傳遞給DirectSoundCreat8函數(shù)。

注意,Directsound雖然基于COM,但是你并不需要初始化com庫,這些Directsound都幫你做好了,當然,如果你使用DMOs特技,你就要自己初始化com庫了,切記。

第二步,創(chuàng)建一個輔助Buffer,也叫后備緩沖區(qū)

你可以通過IDirectSound8::CreateSoundBuffer來創(chuàng)建buffer對象,這個對象主要用來獲取處理數(shù)據(jù),這種buffer稱作輔助緩沖區(qū),以和主緩沖區(qū)區(qū)別開來,Direcsound通過把幾個后備緩沖區(qū)的聲音混合到主緩沖區(qū)中,然后輸出到聲音輸出設備上,達到混音的效果。

第三步,獲取PCM類型的數(shù)據(jù)

將WAV文件或者其他資源的數(shù)據(jù)讀取到緩沖區(qū)中。

第四步,將數(shù)據(jù)讀取到緩沖區(qū)

你可以通過IDirectSoundBuffer8::Lock.方法來準備一個輔助緩沖區(qū)來進行寫操作,通常這個方法返回一個內(nèi)存地址,見數(shù)據(jù)從你的私人buffer中復制到這個地址中,然后調(diào)用IDirectSoundBuffer8::Unlock.

第五步,播放緩沖區(qū)中的數(shù)據(jù)

你可以通過IDirectSoundBuffer8::Play方法來播放緩沖區(qū)中的音頻數(shù)據(jù),你可以通過IDirectSoundBuffer8::Stop來暫停播放數(shù)據(jù),你可以反復的萊停止,播放,音頻數(shù)據(jù),如果你同時創(chuàng)建了幾個buffer,那么你就可以同時來播放這些數(shù)據(jù),這些聲音會自動進行混音的。

呵呵,簡單介紹到這里的,如果想深入了解,請繼續(xù)參考下一部分。

3DirectSound實用開發(fā)技巧Using DirectSound

在進行這部分之前,我們首先學習一下Directsound中常用的幾個對象,簡單學習一下哦

對象數(shù)量作用主要接口

設備每個應用程序只有一個設備對象用來管理設備,創(chuàng)建輔助緩沖區(qū)IDirectSound8

輔助緩沖區(qū)每一個聲音對應一個輔助緩沖區(qū)用來管理一個靜態(tài)的或者動態(tài)的聲音流,然后在主緩沖區(qū)中混音IDirectSoundBuffer8, IDirectSound3DBuffer8, IDirectSoundNotify8

主緩沖區(qū)一個應用程序只有一個主緩沖區(qū)將輔助緩沖區(qū)的數(shù)據(jù)進行混音,并且控制3D參數(shù).IDirectSoundBuffer, IDirectSound3DListener8

特技沒有,或者來輔助緩沖的聲音數(shù)據(jù)進行處理Interface for the particular effect, such as IDirectSoundFXChorus8

首先,要創(chuàng)建一個設備對象,然后通過設備對象創(chuàng)建buffer對象。輔助緩沖區(qū)由應用程序創(chuàng)建和管理,DirectSound會自動地創(chuàng)建和管理主緩沖區(qū),一般來說,應用程序即使沒有獲取這個對象的接口也可以播放音頻數(shù)據(jù),但是,如果應用程序要想得到IDirectSound3DListener8接口,就必須要自己創(chuàng)建一個主緩沖區(qū)。

我們可以將短小的聲音文件全部讀取到輔助緩沖區(qū)中,然后通過一個簡單的命令來播放。如果聲音文件很長,就必須采用數(shù)據(jù)流了。

3.1Dsound設備對象(DirectSound Devices)

本節(jié)主要講述下面的幾個內(nèi)容

1如何枚舉系統(tǒng)輸出聲音的設備

2創(chuàng)建設備對象

3設置聲音設備的協(xié)作度

下面首先看看如何枚舉系統(tǒng)中的聲音輸出設備

1如何枚舉系統(tǒng)輸出聲音的設備

如果你的應用程序使用用戶首選的輸出設備來輸出聲音,那么你就沒有必要來枚舉所有的輸出設備,如果你通過DirectSoundCreat8函數(shù)來創(chuàng)建一個設備對象的同時,就給這個對象指定了一個缺省的設備,當然如果遇到下面的一些情形,你就要來枚舉設備對象

例如,你的應用程序并不支持所有的輸出設備,或者你的應用程需要兩個或者多個設備,或者你希望用戶自己來選擇輸出設備。

枚舉設備,你首先要定義一個回調(diào)函數(shù),這個回調(diào)函數(shù)可以被系統(tǒng)中的每個設備來調(diào)用,你可以在各函數(shù)做任何事情,這個函數(shù)的命名也沒有任何的限制,但是函數(shù)應該以DSEnumCallback為原型,如果枚舉沒有結束,這個回調(diào)函數(shù)就返回TRUE,如果枚舉結束,例如你找到合適的設備,這個函數(shù)就要返回FALSE。

下面是回調(diào)函數(shù)的一個例子,這個函數(shù)將枚舉的每一個設備都添加到一個combox中,將設備的GUID保存到一個item 中,這個函數(shù)的前三個參數(shù)由設備的驅(qū)動程序提供,第四個參數(shù)有DirectSoundEnumerate函數(shù)提供,這個參數(shù)可以是任意的32位值,這個例子里是combox的句柄,

BOOL CALLBACK DSEnumProc(LPGUID lpGUID,

LPCTSTR lpszDesc,

LPCTSTR lpszDrvName,

LPVOID lpContext )

{

HWND hCombo = (HWND)lpContext;

LPGUID lpTemp = NULL;

if (lpGUID != NULL)  //  NULL only for "Primary Sound Driver".

{

if ((lpTemp = (LPGUID)malloc(sizeof(GUID))) == NULL)

{

return(TRUE);

}

memcpy(lpTemp, lpGUID, sizeof(GUID));

}

ComboBox_AddString(hCombo, lpszDesc);

ComboBox_SetItemData(hCombo,

ComboBox_FindString(hCombo, 0, lpszDesc),

lpTemp );

free(lpTemp);

return(TRUE);

}

枚舉設備通常都是在對話框初始化的時候才進行的,我們假設hCombo就是combox句柄,hDlg就對話框的句柄,看看我們怎么來枚舉設備的吧

if (FAILED(DirectSoundEnumerate((LPDSENUMCALLBACK)DSEnumProc,

(VOID*)&hCombo)))

{

EndDialog(hDlg, TRUE);

return(TRUE);

}

在這個例子中,combox的句柄作為參數(shù)傳遞到DirectSoundEnumerate函數(shù)中,然后又被傳遞到回調(diào)函數(shù)中,這個參數(shù)你可以是你想傳遞的任意的32位值。

注:第一個被枚舉的設備通常稱為Primary sound driver,并且回調(diào)函數(shù)的lpGUID為NULL,這個設備就是用戶通過控制面板設置的缺省的輸出聲音設備,

2創(chuàng)建設備對象

創(chuàng)建設備對象最簡單的方法就是通過DirectSoundCreate8函數(shù),這個函數(shù)的第一個參數(shù)指定了和這個對象邦定的設備的GUID,你可以通過枚舉設備來獲取這個設備的GUID,你可以傳遞一個下面的參數(shù)來指定一個缺省的設備

DSDEVID_DefaultPlayback 缺省的系統(tǒng)的聲音輸出設備,這個參數(shù)也可以為NULL

SDEVID_DefaultVoicePlayback,缺省的聲音輸出設備,通常指第二缺省設備,例如USB耳機麥克風

如果沒有聲音輸出設備,這個函數(shù)就返回error,或者,在VXD驅(qū)動程序下,如果聲音輸出設備正被某個應用程序通過waveform格式的api函數(shù)所控制,該函數(shù)也返回error,

下面是創(chuàng)建對象的代碼,及其簡單

LPDIRECTSOUND8 lpds;

HRESULT hr = DirectSoundCreate8(NULL, &lpds, NULL));

如果你想通過表準的COM調(diào)用來創(chuàng)建設備對象,下面我就給出代碼,你可以比較一下

HRESULT hr = CoInitializeEx(NULL, 0);

if (FAILED(hr))

{

ErrorHandler(hr);  // Add error-handling here.

}

LPDIRECTSOUND8 lpds;

hr = CoCreateInstance(&CLSID_DirectSound8,

NULL,

CLSCTX_INPROC_SERVER,

IID_IDirectSound8,

(LPVOID*) &lpds);

if (FAILED(hr))

{

ErrorHandler(hr);  // Add error-handling here.

}

hr = lpds->Initialize(NULL);

if (FAILED(hr))

{

ErrorHandler(hr);  // Add error-handling here.

}

CoUninitialize();

3設置聲音設備的協(xié)作度

因為Windows是一個多任務操作環(huán)境,在同一個時刻有可能多個應用程序共用同一個設備,通過協(xié)作水平,DirectX就可以保證這些應用程序在訪問設備的時候不會沖突,每個Directsound應用程序都有一個協(xié)作度,用來確定來接近設備的程度,

當你創(chuàng)建完設備對象后,一定要調(diào)用IDirectSound8::SetCooperativeLevel來設置協(xié)作度,否則,你不會聽到聲音的,

HRESULT hr = lpDirectSound->SetCooperativeLevel(hwnd, DSSCL_PRIORITY);

if (FAILED(hr))

{

ErrorHandler(hr);  // Add error-handling here.

}

Hwnd參數(shù)代表了應用程序的窗口。

DirectSound定義了三種水平,DSSCL_NORMAL, DSSCL_PRIORITY, and DSSCL_WRITEPRIMARY

在NORMAL水平的協(xié)作度下,應用程序不能設置主緩沖區(qū)的格式,也不能對主緩沖區(qū)進行寫操作,所有在這個層次的應用程序使用的媒體格式都是22kHZ,立體聲,采樣精度8位,所以,設備可以在各個應用程序中任意的切換。

在Priority層次的協(xié)作度下,應用程序可以有優(yōu)先權使用硬件資源,比如使用硬件進行混音,當然也可以設置主緩沖區(qū)的媒體格式,游戲程序應該采用這個層次的協(xié)作度,這個層次的協(xié)作度在允許應用程序控制采用頻率和位深度的同時,也給應用程序很大的權力,這個層次的協(xié)作度允許其他應用程序的聲音和游戲的音頻同時被聽到,不影響。

最高層次的協(xié)作度就是Write_primary,當采用這個層次的協(xié)作度來使用一個dsound設備時,在非WDM模式驅(qū)動下,你的應用程序可以直接操作主緩沖區(qū),在這個模式下,應有程序必須直接的操作主緩沖區(qū)。如果你想直接把音頻數(shù)據(jù)直接寫入到主緩沖區(qū),你就要將你的協(xié)作度模式設置為writeprimary,如果你的應用程序沒有設置到這個層次,那么所有的對主緩沖區(qū)的IDirectSoundBuffer::Lock都會失敗。

當你的應用程序的協(xié)作度設置為wirte_primary水平時,并且你的應用程序gains the foreground,那么其他應用程序的輔助緩沖區(qū)就會停止,并且標示為lost,當你的應用程序轉(zhuǎn)到background,那么它的主緩沖區(qū)就會標示為lost,當它再次回到foreground的時候會恢復到原來的狀態(tài),如果你的設備沒有出現(xiàn)在你的系統(tǒng)中,那么你就沒法設置wirte primary協(xié)作度了,所以,在設置協(xié)作度之前,可以通過IDirectSound8::GetCaps方法來查詢一下設備是否可用。

4設置聲音設備(揚聲器)

在windowos98或者2000系統(tǒng)中,用戶可以通過控制面板來設置揚聲器的屬性,應用程序可以通過IDirectSound8::GetSpeakerConfig.函數(shù)來獲取這些屬性,我們不建議應用程序通過IDirectSound8::SetSpeakerConfig函授來設置揚聲器的屬性,因為這些設置的改動會影響到其他用戶或者應用程序。

5查詢輸出設備的性能

你的應用程序可以通過Directsound來檢查聲音設備的性能,然而許多應用程序并不需要這么做,因為Directsound會自動地利用硬件提供的較好的性能,并不需要你手動地來選擇。

但是,However, high-performance applications can use the information to scale their sound requirements to the available hardware. For example, an application might choose to play more sounds if hardware mixing is available than if it is not.

當你調(diào)用DirectSoundCreate8創(chuàng)建一個設備對象后,你的應用程序就可以通過IDirectSound8::GetCaps函數(shù)來獲取設備的性能屬性,下面的代碼演示了這個過程

DSCAPS dscaps;

dscaps.dwSize = sizeof(DSCAPS);

HRESULT hr = lpDirectSound->GetCaps(&dscaps);

if (FAILED(hr))

{

ErrorHandler(hr);  // Add error-handling here.

}

通過DSCAPS結構,該函數(shù)就給我返回硬件設備的一些性能,但是在調(diào)用這個函數(shù)之前一定要初始化這個結構的dwSize成員。

如果你的應用程序能夠操作硬件設備,比如你的協(xié)作度是Write_primory級別的,那么你在硬件設備上分配內(nèi)存的時候,就要調(diào)用IDirectSoudn8::GetCaps來查看一下硬件的資源是否滿足你的要求。

責任編輯:

標簽: 應用程序

精彩放送:

新聞聚焦
Top