상세 컨텐츠

본문 제목

Direct Sound Creating Secondary Buffers

프로그래밍 관련/사운드

by AlrepondTech 2020. 9. 13. 21:38

본문

반응형

 

 

 

 

 

=================================

=================================

=================================

 

 

 

 

 http://blog.naver.com/majesticgow/140034470699 

Creating Secondary Buffers(두번째 버퍼생성하기)

버퍼를 만들기위해 IDirectSound8::CreateSoundBuffer를 호출해야합니다
이 함수는 IDirectSoundBuffer 인터페이스의 포인터를 반환합니다 
그리고 그것으로 부터 프로그램은 IDirectSoundBuffer8 인터페이스를 얻을수 있습니다.

 

다음의 예제 함수는 두번째 버퍼를 만들고 IDirectSoundBuffer8를 반환하는 것입니다

 

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_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY
    | DSBCAPS_GLOBALFOCUS; 
  dsbdesc.dwBufferBytes = 3 * wfx.nAvgBytesPerSec; 
  dsbdesc.lpwfxFormat = &wfx; 
 
  // Create buffer. 
 
  hr = lpDirectSound->CreateSoundBuffer(&dsbdesc, &pDsb, NULL); 
  if (SUCCEEDED(hr)) 
  { 
     hr = pDsb->QueryInterface(IID_IDirectSoundBuffer8, (LPVOID*) ppDsb8);
     pDsb->Release();
  } 
  return hr;
}

 

이 예제 함수는 3초정도의 스트리밍데이타를 가질수 있을 정도의 스트리밍버퍼를 만드는것입니다.


논 스트리밍 버퍼는 반드시 전체 사운드를 수용할만큼의 충분한 크기로 만들어져야합니다.
예제에서의 DSBCAPS_GLOBALFOCUS 플래그는 프로그램의 윈도우창이 foreground에 있지않을동안에도 연주가 계속 되게 합니다. 이 플래그가 없다면 버퍼는 또 다른 프로그램이나 또는 심지어 대화상자 가 input focus일때 멈추게됩니다. 만약 버퍼의 위치가 기입되지않다면  DirectSound는 그것을 가 능한 하드웨어 통제 메모리에 위치하게 합니다.
사운드 카드 프로세서에 의해 하드웨어 버퍼들은 혼합되기때문에 그것들은 프로그램의 수행에
영향을 덜미칩니다.

 

만약 당신이 DirectSound가 그것이 어디에 속할지를 하게 하기 보다는 버퍼의위치를 기입하고싶다 면 DSBUFFERDESC 구조체에 DSBCAPS_LOCHARDWARE 또는 DSBCAPS_LOCSOFTWARE 플래그를 설정하십시오
만약 DSBCAPS_LOCHARDWARE 플래그가 설정되어있고 불충분한 하드웨어 리소스가 있다면
버퍼생성은 실패를 알릴것입니다.

 

DirectSound의 목소리 관리 특징의 이점을 가지기 위해서는 버퍼를 만들때 DSBCAPS_LOCDEFER를 기입해야합니다. 이 플래그는 버퍼가 연주될때까지 버퍼에대한 리소스의 할당을 연기할것입니다.

 

더많은 정보를 원하면 Dynamic Voice Management를 보십시오

 

당신은 IDirectSoundBuffer8::GetCaps함수를 사용하고 DSBCAPS_LOCHARDWARE 또는

DSBCAPS_LOCSOFTWARE 플래그에 대한 DSBCAPS 구조체의 dwFlags 맴버를 확인함으로써 존재하는 버퍼 의 위치를 확인할수있다. 하나또는 그이상은 언제나 기입되어있다.

버퍼 오브젝트는 그것을 만든 장치 오브젝트에의해 소유된다. 장치 오브젝트가 반환(be released) 될때 그 오브젝트에 의해 만들어진 모든 버퍼는 또한 반환(be released)해야하고 참조(be referenced)되어서는 않됀다


이 글의 원문의 링크는 다음과 같습니다 ^^
http://msdn2.microsoft.com/en-us/library/bb204872.aspx

 

 

 

=================================

=================================

=================================

 

 

 

반응형

 

728x90

 

 

 

Using COM Interfaces

object를 생성하면 생성 method로부터 interface pointer가 return된다. 이 pointer를 사용하면 그 interface의 어떤 method도 access 할 수 있다.
pointer에 사용하는 구문은 C++ method의 경우와 같다. 다음의 code는 앞의 section에서 나온 예를 확장한것이다.
DirectPlay8 object의 생성 후 CoCreateInstance 로부터 return된 IDirectPlay8Peer interface pointer를 사용해서
IDirectPlay8Peer::Initialize method를 호출해 object를 초기화하고 있다. 알기 쉽게 error 정정 code는 생략되어 있다.


IDirectPlay8Peer* g_pDP = NULL;
...
CoInitialize( NULL );
...
hr = CoCreateInstance( CLSID_DirectPlay8, NULL, CLSCTX_INPROC_SERVER,
IID_IDirectPlay8Peer, (LPVOID*) &g_pDP );
hr = g_pDP->Initialize( NULL, DirectPlayMessageHandler, 0 );

Built on 2000년 11월 18일



Requesting Additional Interfaces

대부분 생성 method로부터 받는 interface pointer 하나만으로도 충분하다. 실제로 object가 공개(export)하는 interface가 IUnknown 이외에는 하나 뿐인 일도 적지 않다.
그러나 많은 object는 복수의 interface를 공개(export)한기 때문에 여러개의 interface의 pointer가 필요할수도 있다. 생성 method에 의해 return된 interface 외의
interface가 필요한 경우, 새로운 object를 생성 할 필요는 없다. 대신 object의 IUnknown::QueryInterface method를 사용해 다른 interface pointer를 요구할 수 있다.


CoCreateInstance 로 object를 생성 했을 경우 IUnknown interface pointer를 요구한 후, IUnknown::QueryInterface를 호출해서
필요한 모든 interface를 요구할 수 있다. 다만, 이 방법은 필요한 interface가 한개일 경우에는 오히려 불편하다. 또, object 생성 method를 사용할 경우,
return될 interface pointer를 지정할 수 없기 때문에 전혀 동작하지 않는다. 실제로 모든 COM interface는 IUnknown interface를 계승(inherit) 또는 확장(extend)
하고 있으므로 명시적인 IUnknown pointer를 취득할 필요는 없다.


interface의 확장(extend)은, C++ class의 계승(inherit)과 비슷하다. 자식(child) interface는 부모(parent) interface의 모든 method와 자식 interface의 독자적인 method를 공개(expose)한다.
실제 「확장」대신에 「계승」이라고 하는 표현을 사용하는 일도 많다. 다만, 계승은 object 내부에서 행해지는 것이다. application이 object의 interface를 계승 또는 확장할 수 없다.
그러나 자식 interface를 사용해서 자식과 부모, 양쪽 모두의 interface의 모든 method를 호출할 수가 있다.


모든 interface는 IUnknown의 자식이기 때문에 object에서 취득한 어떤 interface를 사용해도 QueryInterface를 호출할 수가 있다.
그렇게 할때 요구하는 interface의 IID 와 interface pointer의 주소를 지정할 필요가 있다. 예를 들어, 다음의 code는 IDirectSound8::CreateSoundBuffer 을 호출해
primary sound buffer object를 생성한다. 이 object는 여러개의 interface를 공개(expose)한다. CreateSoundBuffer method는 IDirectSoundBuffer8 interface를 돌려준다.
이어지는 코드에서는 IDirectSoundBuffer8 interface를 사용해 QueryInterface 를 호출해서 IDirectSound3DListener8 interface를 요구하고 있다.


IDirectSoundBuffer8* pDSBPrimary = NULL;
IDirectSound3DListener8* pDSListener;
...
if(FAILED(hr = g_pDS->CreateSoundBuffer( &dsbd, &pDSBPrimary, NULL )))
return hr;

if(FAILED(hr = pDSBPrimary->QueryInterface(IID_IDirectSound3DListener8,
(LPVOID *) &pDSListener)))
return hr;

Built on 2000년 11월 18일


 

=================================

=================================

=================================

 

 

Managing a COM Object's Lifetime

object가 생성될때 system이 필요한 memory resources를 할당(allocate)한다. 더이상 필요가 없는 object는 파기해야 한다.
object를 파기하면 system은 그 만큼의 memory를 다른 목적으로 이용할 수 있다. C++ object에서는 new 및 delete 의 각 연산자를 사용해
object의 수명을 직접 제어할 수 있다. COM에서는 object를 직접 생성 하거나 파기할 수 없다. 이것은 같은 object를 여러개의 application이
사용하고 있을 가능성이 있기 때문이다. 여러개의 application이 사용하고 있는 object를 파기하면 다른 application에서는 error가 발생할것이다.
COM 에서는 대신「참조 카운트(reference counting)」라고 하는 system을 사용해 object의 수명을 제어하고 있다.


object의 참조 카운트는 그 object의 interface가 요구된 회수를 나타낸다. interface가 요구될 때마다 참조 카운트는 증가(increment) 된다.
application이 필요 없어진 interface를 release하면 참조 카운트는 감소된다. 참조 카운트가 0 이 되지 않는 이상 object는 memory상에 남는다(remain).
참조 카운트가 0 이 되면 object는 스스로 파기된다. object의 참조 카운트에 대해 알 필요는 없다.
object의 interface의 취득 및 release를 올바르게 하면 object의 수명은 적절히 제어된다.


Note COM programming에서는 참조 카운트를 올바르게 처리하는 것이 매우 중요하다. 이 처리에 실패하면 memory 누수(leak)가 생기기 쉬워진다.
COM programmer가 가장 많이 하는 실수중 하나가 interface의 release 하는 것을 잊는것이다.
interface가 release 되지 않으면 참조 카운트가 언제까지나 0 이 되지 않고, object는 반영구적으로(indefinitely) memory에 남아 있게 된다.


Incrementing and Decrementing the Reference Count

새로운 interface pointer를 얻을때마다 반드시 IUnknown::AddRef 를 호출해 참조 카운트를 증가해야한다.
그러나 application이 method를 호출할 필요는 없다. object 생성 method 또는 IUnknown::QueryInterface 를 호출해
interface pointer를 취득했을 경우, object에 의해 자동으로 참조 카운트가 증가된다. 그러나 기존의 pointer를 copy하는 등 그 외의 방법으로
interface pointer를 얻었을 경우에는 IUnknown::AddRef를 명시적으로 호출해야한다. 그렇지 않으면 원래의 interface pointer를
release 했을 때 그 pointer의 copy를 계속해서 사용할 필요가 있어도 object가 파기되는 경우가 있다.


참조 카운트를 증가시킨것이 application이든 object든 상관없이 모든 interface pointer는 application에 의해 release 해야 한다.
interface pointer가 불필요하게 되었을 경우에는 IUnknown::Release 를 호출해 참조 카운트를 감소시킨다.
모든 interface pointer에 대해 초기화할때 NULL로 설정하고 release할때 다시 NULL로 설정하는 것이 일반적이다.
이렇게 하면 cleanup code에서 모든 interface pointer를 test할 수 있다.
NULL이 아닌 pointer는 아직 active 상태이므로 application을 종료하기 전에 release해야한다.


다음 code는「Requesting Additional Interfaces」에서 설명한 sample을 참조 카운트의 처리 방법을 나타내기 위해서 확장한 것이다.

IDirectSoundBuffer8* pDSBPrimary = NULL;
IDirectSound3DListener8* pDSListener = NULL;
IDirectSound3DListener8* pDSListener2 = NULL;
...// object를 생성 해 interface를 더 얻는다.
// object에 의해 참조 카운트가 증가된다.
if(FAILED(hr = g_pDS->CreateSoundBuffer(&dsbd, &pDSBPrimary, NULL))) return hr;
if(FAILED(hr=pDSBPrimary->QueryInterface(IID_IDirectSound3DListener8, (LPVOID *) &pDSListener))) return hr;
// IDirectSound3DListener8 interface pointer의 copy를 생성 한다.
// AddRef 를 호출해 참조 카운트를 증가한다 이것에 의해
// 사용중인 object가 파기되는 것을 막을 수가 있다.
pDSListener2 = pDSListener;
pDSListener2->AddRef();
...// cleanup code. pointer가 아직 active상태인지 아닌지를 확인한다.
// active 상태이면 Release 를 호출해 interface를 release 한다.
if(pDSBPrimary ! = NULL) {
    pDSBPrimary->Release();
    pDSBPrimary = NULL;
}
if(pDSListener ! = NULL) {
    pDSListener->Release();
    pDSListener = NULL;
}
if(pDSListener2 ! = NULL) {
    pDSListener2->Release();
    pDSListener2 = NULL;
}


Built on 2000년 11월 18일

 

=================================

=================================

=================================

 

 

 

 

반응형


관련글 더보기

댓글 영역