一个DirectSound的例子
                                                            生活随笔
收集整理的這篇文章主要介紹了
                                一个DirectSound的例子
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.                        
                                | 一個捕獲音頻并且播放的例子,可以用來唱歌^_^ 寫了半天才發現Direct SDK有個類似的例子,所以到了最后幾乎都是照抄了。 聲音效果不太好,修改一下加上網絡傳送功能做成語音聊天工具。不過這樣肯定不行,真正的語音聊天可能都要音頻數據處理啊等功能的。 我是想試這做個東西來唱歌,不過效果不好!程序錯誤很多,有很多地方可以改進的,不過我一貫的作風是淺嘗即止。 ?部分代碼 -------------------------------------------------------------------------- #include "sound.h" LPDIRECTSOUND8 lpDirectSound =NULL;?????? //DirectSound 設備 LPDIRECTSOUNDBUFFER8 lpDSBuffer8 = NULL; //播放緩沖區(第二緩沖區) HANDLE soundEvent[3];??? //播放通知 LPDIRECTSOUNDCAPTURE8??????? lpDSCapture = NULL;//捕獲設備對象指針 LPDIRECTSOUNDCAPTUREBUFFER8?? lpDSBCapture = NULL;//捕獲緩沖區對象指針 HANDLE captureEvent[3];??? //播放通知 //int?? FreeBufferSectionNum =0;?? //第幾段的 播放緩沖可以寫了 int?? SoundBufferLength=0;???? //播放緩沖的總長度, 一個緩沖設置分成3段,設置3個通知信號 int?? BufferSectionLength=0; //每一段的長度 BYTE?? SwapBuffer[29400] ;//應該是SwapBuffer[BufferSectionLength];?? , ?????????????????????????????????????? //不過我懶的動態申請了,所以固定了,用于把臨時保存捕獲的音頻數據, ??????????????????????????????????????? //在從這里復制到播放緩存里面去。 其實直接復制也是可以的,不過加多一個緩存在這里,便于處理啊,網絡傳送等等。 ?????????????????????????? //CWaveFile?? waveFile= NULL;?? bool SoundCreate(HWND hwnd ) { HRESULT hr = DirectSoundCreate8(NULL, & lpDirectSound, NULL); if (FAILED(hr)) ???? {???? ?????????? MessageBox(hwnd,_T("創建DirectSound接口失敗。"),_T("widebright"),MB_OK);??? // Add error-handling here. ??????? return false; ???? } hr = lpDirectSound->SetCooperativeLevel(hwnd, DSSCL_PRIORITY?? ); //DSSCL_NORMAL if (FAILED(hr)) ???? {???? ???? MessageBox(hwnd,_T("設置DirectSound協作級別失敗。"),_T("widebright"),MB_OK);??? // Add error-handling here. ?????????? lpDirectSound->Release ();??? // Add error-handling here. ??????? return false; ???? } hr =?? CreateBasicBuffer(lpDirectSound ,& lpDSBuffer8); if (FAILED(hr)) ???? {???? ???? MessageBox(hwnd,_T("創建DirectSound聲音播放緩沖區失敗。"),_T("widebright"),MB_OK);??? // Add error-handling here. ?????????? lpDirectSound->Release ();??? // Add error-handling here. ??????? return false; ???? } //g_pDSBuffer8->Lock(0,0,&lplockbuf,&len,NULL,NULL,DSBLOCK_ENTIREBUFFER); //g_pWaveFile->Read((BYTE*)lplockbuf,len,&dwWrite); //g_pDSBuffer8->Unlock(lplockbuf,len,NULL,0); //g_pDSBuffer8->SetCurrentPosition(0); //g_pDSBuffer8->Play(0,0,DSBPLAY_LOOPING); ?? return true; } //創建 播放緩沖 // //The example function creates a streaming buffer large enough to hold 3 seconds of streaming data. Nonstreaming buffers should be made just large enough to accommodate the entire sound. // //The DSBCAPS_GLOBALFOCUS flag in the example ensures that the buffer will continue playing even when the application window is not in the foreground. Without this flag, the buffer will be muted when another application or even a dialog box has the input focus. // //If the location of a buffer is not specified, DirectSound places it in hardware-controlled memory if possible. Because hardware buffers are mixed by the sound card processor, they have much less impact on application performance. // //If you wish to specify the location of a buffer rather than letting DirectSound decide where it belongs, set either the DSBCAPS_LOCHARDWARE or DSBCAPS_LOCSOFTWARE flag in the DSBUFFERDESC structure. If the DSBCAPS_LOCHARDWARE flag is set and there are insufficient hardware resources, the buffer creation request fails. // //To take advantage of the voice management features of DirectSound, specify the DSBCAPS_LOCDEFER flag when creating the buffer. This flag defers the allocation of resources for the buffer until it is played. For more information, see Dynamic Voice Management. // //You can ascertain the location of an existing buffer by using the IDirectSoundBuffer8::GetCaps method and checking the dwFlags member of the DSBCAPS structure for either the DSBCAPS_LOCHARDWARE or DSBCAPS_LOCSOFTWARE flags. One or the other is always specified. // //Buffer objects are owned by the device object that created them. When the device object is released, all buffers created by that object are also released and should not be referenced. HRESULT CreateBasicBuffer(LPDIRECTSOUND8 lpDirectSound, LPDIRECTSOUNDBUFFER8* ppDsb8) { ?? WAVEFORMATEX wfx; ?? DSBUFFERDESC dsbdesc; ?? LPDIRECTSOUNDBUFFER pDsb = NULL; ?? HRESULT hr; ?? // Set up WAV format structure. memset(&wfx, 0, sizeof(WAVEFORMATEX)); ?? wfx.wFormatTag = WAVE_FORMAT_PCM; ?? wfx.nChannels = 2; ?? wfx.nSamplesPerSec = 22050; ?? wfx.nBlockAlign = 4; ?? wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; ?? wfx.wBitsPerSample = 16; ?? // Set up DSBUFFERDESC structure. ?? memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); ?? dsbdesc.dwSize = sizeof(DSBUFFERDESC); ?? dsbdesc.dwFlags = ????? DSBCAPS_CTRLPAN????? //聲源 是否可以左右移動 //DSBCAPS_CTRL3D????? //聲源是否可以在?? 3D空移動。 //DSBCAPS_CTRLFX????? //特效處理支持 | DSBCAPS_CTRLVOLUME?????????? //音量控制 //| DSBCAPS_CTRLFREQUENCY???? //頻率控制 | DSBCAPS_CTRLPOSITIONNOTIFY //可以設置播放位置通知 ???? | DSBCAPS_GLOBALFOCUS;?? //在程序失去焦點的時候,依然播放聲音 ?? dsbdesc.dwBufferBytes =?? wfx.nAvgBytesPerSec/2;?????? //設置緩沖區長度 為多少秒,就設置這里為wfx.nAvgBytesPerSec 乘以多少,這里和捕獲的統一設置成一秒 ?? dsbdesc.lpwfxFormat = &wfx; SoundBufferLength=dsbdesc.dwBufferBytes ; //記錄緩沖的總長度************************************************** BufferSectionLength = SoundBufferLength/3?? ; //平均分成3段,每段的長度 BufferSectionLength -=?? BufferSectionLength % wfx.nBlockAlign; //內存對齊 // Create buffer. ?? hr = lpDirectSound->CreateSoundBuffer(&dsbdesc, &pDsb, NULL); ?? if (SUCCEEDED(hr)) ?? { ????? hr = pDsb->QueryInterface(IID_IDirectSoundBuffer8, (LPVOID*) ppDsb8); ????? pDsb->Release(); ?? } ?? return hr; } //設置通知對象 //The buffer must be stopped when this method is called. //dwOffset---Offset from the beginning of the buffer where the notify event is to be triggered, or DSBPN_OFFSETSTOP. 通知觸發時buffer的偏移 // hEventNotify ---Handle to the event to be signaled when the offset has been reached.?? 通知觸發的event HRESULT SetNotification(HANDLE?? *hEventNotify ,LPDIRECTSOUNDBUFFER8 lpDsbSecondary ) { #define cEvents?? 3 ?? LPDIRECTSOUNDNOTIFY8 lpDsNotify; ?? DSBPOSITIONNOTIFY PositionNotify[cEvents]; ?? HRESULT hr; ?? ?? if (FAILED( hr = lpDsbSecondary->QueryInterface(IID_IDirectSoundNotify8, ????????????? (LPVOID*)&lpDsNotify))) ?? { ???? return hr; ?? } // Create events. ?? for (int i = 0; i < cEvents; ++i) ?? { ???? hEventNotify[i] = CreateEvent(NULL, TRUE, FALSE, NULL); ???? if (NULL == hEventNotify[i]) ???? { ?????? hr = GetLastError(); ?????? return hr; ???? } PositionNotify[i].dwOffset =?? BufferSectionLength?? * (i+1)?? -1;?? ;??? //設置這里值 為DSBPN_OFFSETSTOP 時,可以創建一個停止播放通知 ????? PositionNotify[i].hEventNotify = hEventNotify[i]; ??? ?? } ?? ????? ?? //注意沒調用一次SetNotificationPositions函數就清除以前的通知對象,所以要設置多個通知對象只能使用一個PositionNotify數組,而不能調用多次SetNotificationPositions函數 ???? hr = lpDsNotify->SetNotificationPositions(3, PositionNotify);??? ???? lpDsNotify->Release(); ???? return hr; } BOOL AppWriteDataToBuffer( ???????? LPDIRECTSOUNDBUFFER8 lpDsb,?? // The buffer. ???????? DWORD dwOffset,?????????????? // Our own write cursor. ???????? LPBYTE lpbSoundData,????????? // Start of our data. ???????? DWORD dwSoundBytes)?????????? // Size of block to copy. ???? { ?????? LPVOID?? lpvPtr1; ?????? DWORD dwBytes1; ?????? LPVOID?? lpvPtr2; ?????? DWORD dwBytes2; ?????? HRESULT hr; ????? ?????? // Obtain memory address of write block. This will be in two parts ?????? // if the block wraps around. ????? ?????? hr = lpDsb->Lock(dwOffset, dwSoundBytes, &lpvPtr1, ?????????? &dwBytes1, &lpvPtr2, &dwBytes2, 0); ????? ?????? // If the buffer was lost, restore and retry lock. ????? ?????? if (DSERR_BUFFERLOST == hr) ?????? { ???????? lpDsb->Restore(); ???????? hr = lpDsb->Lock(dwOffset, dwSoundBytes, ???????????? &lpvPtr1, &dwBytes1, ???????????? &lpvPtr2, &dwBytes2, 0); ?????? } ?????? if (SUCCEEDED(hr)) ?????? { ???????? // Write to pointers. ????? ???????? CopyMemory(lpvPtr1, lpbSoundData, dwBytes1); ???????? if (NULL != lpvPtr2)?? //如果lpvPtr2不為NULL,說明要寫的超出了緩沖的長度,這時lpvPtr2指向緩沖的開始部分,可以繼續寫進去 ???????? { ?????????? CopyMemory(lpvPtr2, lpbSoundData+dwBytes1, dwBytes2); ???????? } ????? ???????? // Release the data back to DirectSound. ????? ???????? hr = lpDsb->Unlock(lpvPtr1, dwBytes1, lpvPtr2, ???????? dwBytes2); ???????? if (SUCCEEDED(hr)) ???????? { ?????????? // Success. ?????????? return TRUE; ???????? } ?????? } ????? ?????? // Lock, Unlock, or Restore failed. ????? ?????? return FALSE; ???? } /// // 啟動 播放聲音 bool?? SoundStart(HWND hwnd ) { HRESULT hr; if( ! SoundCreate(hwnd)) exit(0); ???? //不采用 播放通知了,播放通知控制起來不方便,只需要的捕獲通知里面復制 到播放緩存的相應位置好了 //???? //?? HRESULT?? hr = SetNotification(soundEvent,lpDSBuffer8); //?? if (FAILED(hr)) //??? {???? //??? MessageBox(hwnd,_T("創建播放位置通知失敗"),_T("widebright"),MB_OK);?? //??? exit(0); //} ZeroMemory( SwapBuffer,29400);?? //無聲 AppWriteDataToBuffer (lpDSBuffer8,0,SwapBuffer,29400); lpDSBuffer8->SetVolume(DSBVOLUME_MAX); lpDSBuffer8->SetCurrentPosition (0); if (SUCCEEDED( hr = lpDSBuffer8->Play (0,0,DSBPLAY_LOOPING))) //開始播放 { ???? return true; }else{ return false; } //不采用 播放通知了,播放通知控制起來不方便,只需要的捕獲通知里面復制 到播放緩存的相應位置好了 //while (1) //?? { // //?????? DWORD?? notifyIndex =?? WaitForMultipleObjects(3,soundEvent,FALSE,INFINITE) ;???? //INFINITE 表示一直等待 ,除非hEvent產生了信號。 這里 // //?????? // //notifyIndex = notifyIndex - WAIT_OBJECT_0;??? //得到觸發 通知對象序號 // //?????? ResetEvent(soundEvent[ notifyIndex]); //??????????????? //????? //FreeBufferSectionNum = notifyIndex; //??? WaitForSingleObject(soundEvent[0], INFINITE);??????? //??? ResetEvent(soundEvent[ 0]); //?????? FreeBufferSectionNum =0; //??? WaitForSingleObject(soundEvent[1], INFINITE);??????? //??? ResetEvent(soundEvent[1]); //??? FreeBufferSectionNum =1; //??? WaitForSingleObject(soundEvent[2], INFINITE);??????? //??? ResetEvent(soundEvent[ 2]); //?????? FreeBufferSectionNum =2; // //}?? } //停止播放聲音 void SoundStop() { if ( ! lpDSBuffer8)?? {lpDSBuffer8->Stop(); lpDSBuffer8->Release ();} ???? if ( ! lpDirectSound) lpDirectSound->Release (); ???? } / 下面是錄音部分/ bool CaptureCreate(HWND hwnd ) { ????????????????? ???? HRESULT hr = DirectSoundCaptureCreate8 (&DSDEVID_DefaultCapture , &lpDSCapture,NULL); if (FAILED(hr)) ???? {???? ?????????? MessageBox(hwnd,_T("創建DirectCapture接口失敗。"),_T("widebright"),MB_OK);??? // Add error-handling here. ??????? return false; ???? } hr =?? CreateCaptureBuffer(lpDSCapture , &lpDSBCapture); if (FAILED(hr)) ???? {???? ???? MessageBox(hwnd,_T("創建DirectCapture聲音播放緩沖區失敗。"),_T("widebright"),MB_OK);??? // Add error-handling here. ?????????? lpDSCapture->Release ();??? // Add error-handling here. ??????? return false; ???? } //g_pDSBuffer8->Lock(0,0,&lplockbuf,&len,NULL,NULL,DSBLOCK_ENTIREBUFFER); //g_pWaveFile->Read((BYTE*)lplockbuf,len,&dwWrite); //g_pDSBuffer8->Unlock(lplockbuf,len,NULL,0); //g_pDSBuffer8->SetCurrentPosition(0); //g_pDSBuffer8->Play(0,0,DSBPLAY_LOOPING); ?? return true; } HRESULT CreateCaptureBuffer(LPDIRECTSOUNDCAPTURE8 pDSC, ???????????????????????????? LPDIRECTSOUNDCAPTUREBUFFER8* ppDSCB8) { ?? HRESULT hr; ?? DSCBUFFERDESC??????????????? dscbd; ?? LPDIRECTSOUNDCAPTUREBUFFER?? pDSCB; ?? WAVEFORMATEX???????????????? wfx = ????? {WAVE_FORMAT_PCM, 2, 22050, 88200, 4, 16, 0}; ???? // {WAVE_FORMAT_PCM, 2, 44100, 176400, 4, 16, 0}; ???? // wFormatTag, nChannels, nSamplesPerSec, mAvgBytesPerSec, ???? // nBlockAlign, wBitsPerSample, cbSize ?? if ((NULL == pDSC) || (NULL == ppDSCB8)) return E_INVALIDARG; ?? dscbd.dwSize = sizeof(DSCBUFFERDESC); ?? dscbd.dwFlags = 0; ?? dscbd.dwBufferBytes =?? wfx.nAvgBytesPerSec/2;????? //*******保存多少秒的數據 就設置這里為多少乘以 wfx.nAvgBytesPerSec********* ?? dscbd.dwReserved = 0; ?? dscbd.lpwfxFormat = &wfx; ?? dscbd.dwFXCount = 0; ?? dscbd.lpDSCFXDesc = NULL; ?? if (SUCCEEDED(hr = pDSC->CreateCaptureBuffer(&dscbd, &pDSCB, NULL))) ?? { ???? hr = pDSCB->QueryInterface(IID_IDirectSoundCaptureBuffer8, (LPVOID*)ppDSCB8); ???? pDSCB->Release();?? ?? } ?? return hr; } HRESULT SetCaptureNotifications(HANDLE?? *rghEvent, LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB) { ?? #define cEvents?? 3 LPDIRECTSOUNDNOTIFY8 pDSNotify; ?? WAVEFORMATEX????????? wfx;?? ?? //HANDLE????? rghEvent[cEvents] = {0}; ?? DSBPOSITIONNOTIFY?? rgdsbpn[cEvents]; ?? HRESULT???? hr; if (NULL == pDSCB) return E_INVALIDARG; ?? if (FAILED(hr = pDSCB->QueryInterface(IID_IDirectSoundNotify, (LPVOID*)&pDSNotify))) ?? { ???? return hr; ?? } ?? if (FAILED(hr = pDSCB->GetFormat(&wfx, sizeof(WAVEFORMATEX), NULL))) ?? { ???? return hr; ?? } // Create events. ?? for (int i = 0; i < cEvents; ++i) ?? { ???? rghEvent[i] = CreateEvent(NULL, TRUE, FALSE, NULL); ???? if (NULL == rghEvent[i]) ???? { ?????? hr = GetLastError(); ?????? return hr; ???? } // Describe notifications. ???????? rgdsbpn[i].dwOffset =?? BufferSectionLength?? * (i+1)?? -1; ???????? rgdsbpn[i].hEventNotify = rghEvent[0];??? //rghEvent[i];?? 可以多個通知對象共用一個event的 } // Create notifications. ?? hr = pDSNotify->SetNotificationPositions(cEvents, rgdsbpn); ?? pDSNotify->Release(); ?? return hr; } /// // 啟動 播放聲音 bool?? CaptureStart(HWND hwnd ) { ???? if( ! CaptureCreate(hwnd)) exit(0); ???? ?? ?? HRESULT?? hr = SetCaptureNotifications( captureEvent,lpDSBCapture ); ????? if (FAILED(hr)) ?? {???? ???? MessageBox(hwnd,_T("創建捕獲位置通知失敗"),_T("widebright"),MB_OK);?? ??????? exit(0); ?? } ?? ???? lpDSBCapture->Start (DSCBSTART_LOOPING); //開始捕獲 int NextCaptureOffset =0;?? //捕獲緩存區 偏移 ???? DWORD playCursor=0,writeCursor=0; ?? int NextSoundOffset = 0;?? //播放緩存區 的偏移, ???? lpDSBuffer8->GetCurrentPosition(&playCursor,&writeCursor); ???? NextSoundOffset = (writeCursor + 600 )% SoundBufferLength; while (1) ??? { ???? //??? DWORD?? notifyIndex =?? WaitForMultipleObjects(3,captureEvent,FALSE,INFINITE) ;???? //INFINITE 表示一直等待 ,除非hEvent產生了信號。 這里 ???? //???? ???? //notifyIndex = notifyIndex - WAIT_OBJECT_0;??? //得到觸發 通知對象序號 ???? //??? ResetEvent(captureEvent[ notifyIndex]); ????? VOID* pDSCaptureLockedBuffer???? = NULL; ????? DWORD dwDSCaptureLockedBufferSize; WaitForSingleObject(captureEvent[0], INFINITE);??????? ???? ResetEvent(captureEvent[ 0]); ???????? if( SUCCEEDED( hr = lpDSBCapture->Lock(NextCaptureOffset, BufferSectionLength, ?????????????????????????????????????????? &pDSCaptureLockedBuffer, ?????????????????????????????????????????? &dwDSCaptureLockedBufferSize, ?????????????????????????????????????????? NULL, NULL, 0L ) ) ) ?? { ??????? CopyMemory( SwapBuffer, ???????????????? pDSCaptureLockedBuffer, ???????????????? dwDSCaptureLockedBufferSize ); ???????????? ??? lpDSBCapture->Unlock( pDSCaptureLockedBuffer, dwDSCaptureLockedBufferSize, ??????????????????????????? NULL, 0 ); ??????????? ??????????? lpDSBuffer8->GetCurrentPosition(&playCursor,&writeCursor); //???? AppWriteDataToBuffer (lpDSBuffer8,writeCursor?? ,SwapBuffer,dwDSCaptureLockedBufferSize); ?? AppWriteDataToBuffer (lpDSBuffer8, NextSoundOffset ,SwapBuffer,dwDSCaptureLockedBufferSize); ?? } ??????? NextSoundOffset +=dwDSCaptureLockedBufferSize; ??????? NextSoundOffset %= SoundBufferLength; // Circular buffer ??????? NextCaptureOffset +=?? BufferSectionLength; ??????? NextCaptureOffset %= SoundBufferLength; // Circular buffer ???? ??????? } } //停止播放聲音 void CaptureStop() { if ( ! lpDSBCapture)?? {lpDSBuffer8->Stop (); lpDSBCapture->Release ();} ???? if ( ! lpDSCapture ) lpDSCapture ->Release (); ???? } | 
總結
以上是生活随笔為你收集整理的一个DirectSound的例子的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 3DSlicer18:Layouts
- 下一篇: Python1:if / while /
