1 /* DirectSound COM interface
3 * Copyright 2009 Maarten Lankhorst
5 * Some code taken from the original dsound-openal implementation
6 * Copyright 2007-2009 Chris Robinson
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #define NONAMELESSSTRUCT
29 #define NONAMELESSUNION
39 #include "wine/debug.h"
42 #include "dsound_private.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(dsound
);
56 #include "dsound_private.h"
58 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM
, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
59 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
61 #ifndef E_PROP_ID_UNSUPPORTED
62 #define E_PROP_ID_UNSUPPORTED ((HRESULT)0x80070490)
67 static const IDirectSoundBufferVtbl DS8Primary_Vtbl
;
68 static const IDirectSound3DListenerVtbl DS8Primary3D_Vtbl
;
69 static const IKsPropertySetVtbl DS8PrimaryProp_Vtbl
;
72 static inline DS8Primary
*impl_from_IDirectSoundBuffer(IDirectSoundBuffer
*iface
)
74 return CONTAINING_RECORD(iface
, DS8Primary
, IDirectSoundBuffer_iface
);
77 static inline DS8Primary
*impl_from_IDirectSound3DListener(IDirectSound3DListener
*iface
)
79 return CONTAINING_RECORD(iface
, DS8Primary
, IDirectSound3DListener_iface
);
82 static inline DS8Primary
*impl_from_IKsPropertySet(IKsPropertySet
*iface
)
84 return CONTAINING_RECORD(iface
, DS8Primary
, IKsPropertySet_iface
);
88 static void AL_APIENTRY
wrap_DeferUpdates(void)
89 { alcSuspendContext(alcGetCurrentContext()); }
90 static void AL_APIENTRY
wrap_ProcessUpdates(void)
91 { alcProcessContext(alcGetCurrentContext()); }
94 static void trigger_elapsed_notifies(DS8Buffer
*buf
, DWORD lastpos
, DWORD curpos
)
97 for(i
= 0; i
< buf
->nnotify
; ++i
)
99 DSBPOSITIONNOTIFY
*not = &buf
->notify
[i
];
100 HANDLE event
= not->hEventNotify
;
101 DWORD ofs
= not->dwOffset
;
103 if(ofs
== (DWORD
)DSBPN_OFFSETSTOP
)
106 /* Wraparound case */
109 if(ofs
< curpos
|| ofs
>= lastpos
)
111 TRACE("Triggering notification %"LONGFMT
"u (%"LONGFMT
"u) from buffer %p\n", i
, ofs
, buf
);
118 if(ofs
>= lastpos
&& ofs
< curpos
)
120 TRACE("Triggering notification %"LONGFMT
"u (%"LONGFMT
"u) from buffer %p\n", i
, ofs
, buf
);
126 static void trigger_stop_notifies(DS8Buffer
*buf
)
129 for(i
= 0; i
< buf
->nnotify
; ++i
)
131 DSBPOSITIONNOTIFY
*not = &buf
->notify
[i
];
132 if(not->dwOffset
== (DWORD
)DSBPN_OFFSETSTOP
)
134 TRACE("Triggering notification %"LONGFMT
"u from buffer %p\n", i
, buf
);
135 SetEvent(not->hEventNotify
);
140 static DWORD CALLBACK
DS8Primary_thread(void *dwUser
)
142 DS8Primary
*prim
= (DS8Primary
*)dwUser
;
143 DWORD i
, active_notifies
;
146 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL
);
148 TRACE("Primary buffer (%p) message loop start\n", prim
);
149 while(GetMessageA(&msg
, NULL
, 0, 0))
151 if(msg
.message
!= WM_USER
)
154 EnterCriticalSection(prim
->crst
);
155 setALContext(prim
->ctx
);
157 for(i
= 0;i
< prim
->nnotifies
;)
159 DS8Buffer
*buf
= prim
->notifies
[i
];
160 IDirectSoundBuffer8
*dsb
= &buf
->IDirectSoundBuffer8_iface
;
161 DWORD status
=0, curpos
=buf
->lastpos
;
163 IDirectSoundBuffer8_GetStatus(dsb
, &status
);
164 IDirectSoundBuffer8_GetCurrentPosition(dsb
, &curpos
, NULL
);
165 if(buf
->lastpos
!= curpos
)
167 trigger_elapsed_notifies(buf
, buf
->lastpos
, curpos
);
168 buf
->lastpos
= curpos
;
170 if(!(status
&DSBSTATUS_PLAYING
))
172 /* Remove this buffer from list and put another at the
173 * current position; don't increment i
175 trigger_stop_notifies(buf
);
176 prim
->notifies
[i
] = prim
->notifies
[--prim
->nnotifies
];
183 /* OpenAL doesn't support our lovely buffer extensions
184 * so just make sure enough buffers are queued
186 if(!prim
->SupportedExt
[SOFT_BUFFER_SAMPLES
] &&
187 !prim
->SupportedExt
[SOFT_BUFFER_SUB_DATA
] &&
188 !prim
->SupportedExt
[EXT_STATIC_BUFFER
])
190 for(i
= 0;i
< prim
->nbuffers
;++i
)
192 DS8Buffer
*buf
= prim
->buffers
[i
];
193 ALint done
= 0, queued
= QBUFFERS
, state
= AL_PLAYING
;
196 if(buf
->buffer
->numsegs
== 1 || !buf
->isplaying
)
199 alGetSourcei(buf
->source
, AL_SOURCE_STATE
, &state
);
200 alGetSourcei(buf
->source
, AL_BUFFERS_QUEUED
, &queued
);
201 alGetSourcei(buf
->source
, AL_BUFFERS_PROCESSED
, &done
);
205 alSourceUnqueueBuffers(buf
->source
, 1, &which
);
206 while(queued
< QBUFFERS
)
208 which
= buf
->buffer
->buffers
[buf
->curidx
];
209 ofs
= buf
->curidx
*buf
->buffer
->segsize
;
210 if(buf
->curidx
< buf
->buffer
->numsegs
-1)
211 alBufferData(which
, buf
->buffer
->buf_format
,
212 buf
->buffer
->data
+ ofs
, buf
->buffer
->segsize
,
213 buf
->buffer
->format
.Format
.nSamplesPerSec
);
215 alBufferData(which
, buf
->buffer
->buf_format
,
216 buf
->buffer
->data
+ ofs
, buf
->buffer
->lastsegsize
,
217 buf
->buffer
->format
.Format
.nSamplesPerSec
);
219 alSourceQueueBuffers(buf
->source
, 1, &which
);
220 buf
->curidx
= (buf
->curidx
+1)%buf
->buffer
->numsegs
;
223 if(!buf
->curidx
&& !buf
->islooping
)
225 buf
->isplaying
= FALSE
;
229 if(state
!= AL_PLAYING
)
233 IDirectSoundBuffer8_Stop(&buf
->IDirectSoundBuffer8_iface
);
236 alSourcePlay(buf
->source
);
241 else if(active_notifies
== 0 && prim
->timer_id
)
243 TRACE("No more notifies, killing timer\n");
244 timeKillEvent(prim
->timer_id
);
246 timeEndPeriod(prim
->timer_res
);
250 LeaveCriticalSection(prim
->crst
);
252 TRACE("Primary buffer (%p) message loop quit\n", prim
);
256 timeKillEvent(prim
->timer_id
);
258 timeEndPeriod(prim
->timer_res
);
259 TRACE("Killed timer\n");
265 static void CALLBACK
DS8Primary_timer(UINT timerID
, UINT msg
, DWORD_PTR dwUser
,
266 DWORD_PTR dw1
, DWORD_PTR dw2
)
272 PostThreadMessageA(dwUser
, WM_USER
, 0, 0);
275 void DS8Primary_starttimer(DS8Primary
*prim
)
277 DWORD triggertime
, res
= DS_TIME_RES
;
278 ALint refresh
= FAKE_REFRESH_COUNT
;
284 timeGetDevCaps(&time
, sizeof(TIMECAPS
));
286 alcGetIntegerv(prim
->parent
->device
, ALC_REFRESH
, 1, &refresh
);
287 checkALCError(prim
->parent
->device
);
289 triggertime
= 1000 / refresh
/ 2;
290 if(triggertime
< time
.wPeriodMin
)
291 triggertime
= time
.wPeriodMin
;
292 TRACE("Calling timer every %"LONGFMT
"u ms for %i refreshes per second\n", triggertime
, refresh
);
294 if (res
< time
.wPeriodMin
)
295 res
= time
.wPeriodMin
;
296 if (timeBeginPeriod(res
) == TIMERR_NOCANDO
)
297 WARN("Could not set minimum resolution, don't expect sound\n");
299 prim
->timer_res
= res
;
300 prim
->timer_id
= timeSetEvent(triggertime
, res
, DS8Primary_timer
, prim
->thread_id
, TIME_PERIODIC
|TIME_KILL_SYNCHRONOUS
);
305 HRESULT
DS8Primary_PreInit(DS8Primary
*This
, DS8Impl
*parent
)
307 DS3DLISTENER
*listener
;
311 This
->IDirectSoundBuffer_iface
.lpVtbl
= (IDirectSoundBufferVtbl
*)&DS8Primary_Vtbl
;
312 This
->IDirectSound3DListener_iface
.lpVtbl
= (IDirectSound3DListenerVtbl
*)&DS8Primary3D_Vtbl
;
313 This
->IKsPropertySet_iface
.lpVtbl
= (IKsPropertySetVtbl
*)&DS8PrimaryProp_Vtbl
;
315 This
->parent
= parent
;
316 This
->crst
= &parent
->share
->crst
;
317 This
->ctx
= parent
->share
->ctx
;
318 This
->SupportedExt
= parent
->share
->SupportedExt
;
319 This
->ExtAL
= &parent
->share
->ExtAL
;
320 This
->sources
= parent
->share
->sources
;
321 This
->auxslot
= parent
->share
->auxslot
;
323 /* Allocate enough for a WAVEFORMATEXTENSIBLE */
324 wfx
= &This
->format
.Format
;
326 wfx
->wFormatTag
= WAVE_FORMAT_PCM
;
328 wfx
->wBitsPerSample
= 8;
329 wfx
->nSamplesPerSec
= 22050;
330 wfx
->nBlockAlign
= wfx
->wBitsPerSample
* wfx
->nChannels
/ 8;
331 wfx
->nAvgBytesPerSec
= wfx
->nSamplesPerSec
* wfx
->nBlockAlign
;
334 This
->stopped
= TRUE
;
336 /* Apparently primary buffer size is always 32k,
337 * tested on windows with 192k 24 bits sound @ 6 channels
338 * where it will run out in 60 ms and it isn't pointer aligned
340 This
->buf_size
= 32768;
342 if(This
->SupportedExt
[SOFT_DEFERRED_UPDATES
])
344 This
->DeferUpdates
= This
->ExtAL
->DeferUpdatesSOFT
;
345 This
->ProcessUpdates
= This
->ExtAL
->ProcessUpdatesSOFT
;
349 This
->DeferUpdates
= wrap_DeferUpdates
;
350 This
->ProcessUpdates
= wrap_ProcessUpdates
;
353 This
->eax_prop
= EnvironmentDefaults
[EAX_ENVIRONMENT_GENERIC
];
354 if(This
->SupportedExt
[EXT_EFX
] && This
->auxslot
!= 0)
356 ALint revid
= alGetEnumValue("AL_EFFECT_REVERB");
357 if(revid
!= 0 && revid
!= -1)
359 This
->ExtAL
->GenEffects(1, &This
->effect
);
360 This
->ExtAL
->Effecti(This
->effect
, AL_EFFECT_TYPE
, AL_EFFECT_REVERB
);
365 /* Make sure DS3DListener defaults are applied to OpenAL */
366 listener
= &This
->params
;
367 listener
->dwSize
= sizeof(This
->params
);
368 listener
->vPosition
.x
= 0.0;
369 listener
->vPosition
.y
= 0.0;
370 listener
->vPosition
.z
= 0.0;
371 listener
->vVelocity
.x
= 0.0;
372 listener
->vVelocity
.y
= 0.0;
373 listener
->vVelocity
.z
= 0.0;
374 listener
->vOrientFront
.x
= 0.0;
375 listener
->vOrientFront
.y
= 0.0;
376 listener
->vOrientFront
.z
= 1.0;
377 listener
->vOrientTop
.x
= 0.0;
378 listener
->vOrientTop
.y
= 1.0;
379 listener
->vOrientTop
.z
= 0.0;
380 listener
->flDistanceFactor
= DS3D_DEFAULTDISTANCEFACTOR
;
381 listener
->flRolloffFactor
= DS3D_DEFAULTROLLOFFFACTOR
;
382 listener
->flDopplerFactor
= DS3D_DEFAULTDOPPLERFACTOR
;
383 hr
= IDirectSound3DListener_SetAllParameters(&This
->IDirectSound3DListener_iface
, listener
, DS3D_IMMEDIATE
);
385 ERR("Could not set 3d parameters: %08"LONGFMT
"x\n", hr
);
387 This
->sizenotifies
= This
->sizebuffers
= parent
->share
->max_sources
;
389 hr
= DSERR_OUTOFMEMORY
;
390 This
->buffers
= HeapAlloc(GetProcessHeap(), 0, This
->sizebuffers
*sizeof(*This
->buffers
));
391 This
->notifies
= HeapAlloc(GetProcessHeap(), 0, This
->sizenotifies
*sizeof(*This
->notifies
));
392 if(!This
->buffers
|| !This
->notifies
)
395 This
->thread_hdl
= CreateThread(NULL
, 0, DS8Primary_thread
, This
, 0, &This
->thread_id
);
396 if(This
->thread_hdl
== NULL
)
402 DS8Primary_Clear(This
);
406 void DS8Primary_Clear(DS8Primary
*This
)
408 TRACE("Clearing primary %p\n", This
);
415 PostThreadMessageA(This
->thread_id
, WM_QUIT
, 0, 0);
416 if(WaitForSingleObject(This
->thread_hdl
, 1000) != WAIT_OBJECT_0
)
418 /* HACK: Apparently, if the device is initialized (thus the primary
419 * buffer has PreInit called) then immediately deleted (the primary
420 * buffer has Clear called), the WM_QUIT message gets sent before
421 * the thread has a chance to run which apparently prevents it from
422 * receiving the message.
423 * If the wait attempt fails, try sending the message again. */
424 PostThreadMessageA(This
->thread_id
, WM_QUIT
, 0, 0);
425 if(WaitForSingleObject(This
->thread_hdl
, 1000) != WAIT_OBJECT_0
)
426 ERR("Thread wait timed out\n");
428 CloseHandle(This
->thread_hdl
);
431 setALContext(This
->ctx
);
433 This
->ExtAL
->DeleteEffects(1, &This
->effect
);
435 while(This
->nbuffers
--)
436 DS8Buffer_Destroy(This
->buffers
[This
->nbuffers
]);
438 HeapFree(GetProcessHeap(), 0, This
->notifies
);
439 HeapFree(GetProcessHeap(), 0, This
->buffers
);
440 memset(This
, 0, sizeof(*This
));
443 static HRESULT WINAPI
DS8Primary_QueryInterface(IDirectSoundBuffer
*iface
, REFIID riid
, LPVOID
*ppv
)
445 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
447 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
450 if(IsEqualIID(riid
, &IID_IUnknown
) ||
451 IsEqualIID(riid
, &IID_IDirectSoundBuffer
))
452 *ppv
= &This
->IDirectSoundBuffer_iface
;
453 else if(IsEqualIID(riid
, &IID_IDirectSound3DListener
))
455 if((This
->flags
&DSBCAPS_CTRL3D
))
456 *ppv
= &This
->IDirectSound3DListener_iface
;
459 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid
));
463 IUnknown_AddRef((IUnknown
*)*ppv
);
467 return E_NOINTERFACE
;
470 static ULONG WINAPI
DS8Primary_AddRef(IDirectSoundBuffer
*iface
)
472 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
475 ret
= InterlockedIncrement(&This
->ref
);
476 if(ret
== 1) This
->flags
= 0;
481 static ULONG WINAPI
DS8Primary_Release(IDirectSoundBuffer
*iface
)
483 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
486 ret
= InterlockedDecrement(&This
->ref
);
491 static HRESULT WINAPI
DS8Primary_GetCaps(IDirectSoundBuffer
*iface
, DSBCAPS
*caps
)
493 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
495 TRACE("(%p)->(%p)\n", iface
, caps
);
497 if(!caps
|| caps
->dwSize
< sizeof(*caps
))
499 WARN("Invalid DSBCAPS (%p, %"LONGFMT
"u)\n", caps
, caps
? caps
->dwSize
: 0);
500 return DSERR_INVALIDPARAM
;
503 caps
->dwFlags
= This
->flags
;
504 caps
->dwBufferBytes
= This
->buf_size
;
505 caps
->dwUnlockTransferRate
= 0;
506 caps
->dwPlayCpuOverhead
= 0;
511 static HRESULT WINAPI
DS8Primary_GetCurrentPosition(IDirectSoundBuffer
*iface
, DWORD
*playpos
, DWORD
*curpos
)
513 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
514 HRESULT hr
= DSERR_PRIOLEVELNEEDED
;
516 EnterCriticalSection(This
->crst
);
518 hr
= IDirectSoundBuffer8_GetCurrentPosition(This
->write_emu
, playpos
, curpos
);
519 LeaveCriticalSection(This
->crst
);
524 static HRESULT WINAPI
DS8Primary_GetFormat(IDirectSoundBuffer
*iface
, WAVEFORMATEX
*wfx
, DWORD allocated
, DWORD
*written
)
526 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
532 WARN("Cannot report format or format size\n");
533 return DSERR_INVALIDPARAM
;
536 EnterCriticalSection(This
->crst
);
537 size
= sizeof(This
->format
.Format
) + This
->format
.Format
.cbSize
;
543 hr
= DSERR_INVALIDPARAM
;
545 memcpy(wfx
, &This
->format
.Format
, size
);
547 LeaveCriticalSection(This
->crst
);
552 static HRESULT WINAPI
DS8Primary_GetVolume(IDirectSoundBuffer
*iface
, LONG
*volume
)
554 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
557 TRACE("(%p)->(%p)\n", iface
, volume
);
560 return DSERR_INVALIDPARAM
;
563 if(!(This
->flags
&DSBCAPS_CTRLVOLUME
))
564 return DSERR_CONTROLUNAVAIL
;
566 setALContext(This
->ctx
);
567 alGetListenerf(AL_GAIN
, &gain
);
571 *volume
= clampI(gain_to_mB(gain
), DSBVOLUME_MIN
, DSBVOLUME_MAX
);
575 static HRESULT WINAPI
DS8Primary_GetPan(IDirectSoundBuffer
*iface
, LONG
*pan
)
577 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
580 WARN("(%p)->(%p): semi-stub\n", iface
, pan
);
583 return DSERR_INVALIDPARAM
;
585 EnterCriticalSection(This
->crst
);
587 hr
= IDirectSoundBuffer8_GetPan(This
->write_emu
, pan
);
588 else if(!(This
->flags
& DSBCAPS_CTRLPAN
))
589 hr
= DSERR_CONTROLUNAVAIL
;
592 LeaveCriticalSection(This
->crst
);
597 static HRESULT WINAPI
DS8Primary_GetFrequency(IDirectSoundBuffer
*iface
, DWORD
*freq
)
599 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
602 WARN("(%p)->(%p): semi-stub\n", iface
, freq
);
605 return DSERR_INVALIDPARAM
;
607 if(!(This
->flags
&DSBCAPS_CTRLFREQUENCY
))
608 return DSERR_CONTROLUNAVAIL
;
610 EnterCriticalSection(This
->crst
);
611 *freq
= This
->format
.Format
.nSamplesPerSec
;
612 LeaveCriticalSection(This
->crst
);
617 static HRESULT WINAPI
DS8Primary_GetStatus(IDirectSoundBuffer
*iface
, DWORD
*status
)
619 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
621 TRACE("(%p)->(%p)\n", iface
, status
);
624 return DSERR_INVALIDPARAM
;
626 EnterCriticalSection(This
->crst
);
627 *status
= DSBSTATUS_PLAYING
|DSBSTATUS_LOOPING
;
628 if((This
->flags
&DSBCAPS_LOCDEFER
))
629 *status
|= DSBSTATUS_LOCHARDWARE
;
636 for(i
= 0;i
< This
->nbuffers
;++i
)
638 hr
= IDirectSoundBuffer8_GetStatus(&This
->buffers
[i
]->IDirectSoundBuffer8_iface
, &state
);
639 if(SUCCEEDED(hr
) && (state
&DSBSTATUS_PLAYING
))
642 if(i
== This
->nbuffers
)
644 /* Primary stopped and no buffers playing.. */
648 LeaveCriticalSection(This
->crst
);
653 static HRESULT WINAPI
DS8Primary_Initialize(IDirectSoundBuffer
*iface
, IDirectSound
*ds
, const DSBUFFERDESC
*desc
)
655 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
658 TRACE("(%p)->(%p, %p)\n", iface
, ds
, desc
);
660 if(!desc
|| desc
->lpwfxFormat
|| desc
->dwBufferBytes
)
662 WARN("Bad DSBDESC for primary buffer\n");
663 return DSERR_INVALIDPARAM
;
665 if((desc
->dwFlags
&DSBCAPS_CTRLFX
) ||
666 (desc
->dwFlags
&DSBCAPS_CTRLPOSITIONNOTIFY
) ||
667 (desc
->dwFlags
&DSBCAPS_LOCSOFTWARE
))
669 WARN("Bad dwFlags %08"LONGFMT
"x\n", desc
->dwFlags
);
670 return DSERR_INVALIDPARAM
;
673 /* Should be 0 if not initialized */
675 return DSERR_ALREADYINITIALIZED
;
678 if(This
->parent
->prio_level
== DSSCL_WRITEPRIMARY
)
680 DSBUFFERDESC emudesc
;
685 ERR("There shouldn't be a write_emu!\n");
686 IDirectSoundBuffer8_Release(This
->write_emu
);
687 This
->write_emu
= NULL
;
690 memset(&emudesc
, 0, sizeof(emudesc
));
691 emudesc
.dwSize
= sizeof(emudesc
);
692 emudesc
.dwFlags
= DSBCAPS_LOCHARDWARE
| (desc
->dwFlags
&DSBCAPS_CTRLPAN
);
693 /* Dont play last incomplete sample */
694 emudesc
.dwBufferBytes
= This
->buf_size
- (This
->buf_size
%This
->format
.Format
.nBlockAlign
);
695 emudesc
.lpwfxFormat
= &This
->format
.Format
;
697 hr
= DS8Buffer_Create(&emu
, This
, NULL
);
700 This
->write_emu
= &emu
->IDirectSoundBuffer8_iface
;
701 hr
= IDirectSoundBuffer8_Initialize(This
->write_emu
, ds
, &emudesc
);
704 IDirectSoundBuffer8_Release(This
->write_emu
);
705 This
->write_emu
= NULL
;
711 This
->flags
= desc
->dwFlags
| DSBCAPS_LOCHARDWARE
;
715 static HRESULT WINAPI
DS8Primary_Lock(IDirectSoundBuffer
*iface
, DWORD ofs
, DWORD bytes
, void **ptr1
, DWORD
*len1
, void **ptr2
, DWORD
*len2
, DWORD flags
)
717 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
718 HRESULT hr
= DSERR_PRIOLEVELNEEDED
;
720 TRACE("(%p)->(%"LONGFMT
"u, %"LONGFMT
"u, %p, %p, %p, %p, %"LONGFMT
"u)\n", iface
, ofs
, bytes
, ptr1
, len1
, ptr2
, len2
, flags
);
722 EnterCriticalSection(This
->crst
);
724 hr
= IDirectSoundBuffer8_Lock(This
->write_emu
, ofs
, bytes
, ptr1
, len1
, ptr2
, len2
, flags
);
725 LeaveCriticalSection(This
->crst
);
730 static HRESULT WINAPI
DS8Primary_Play(IDirectSoundBuffer
*iface
, DWORD res1
, DWORD res2
, DWORD flags
)
732 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
735 TRACE("(%p)->(%"LONGFMT
"u, %"LONGFMT
"u, %"LONGFMT
"u)\n", iface
, res1
, res2
, flags
);
737 if(!(flags
& DSBPLAY_LOOPING
))
739 WARN("Flags (%08"LONGFMT
"x) not set to DSBPLAY_LOOPING\n", flags
);
740 return DSERR_INVALIDPARAM
;
743 EnterCriticalSection(This
->crst
);
746 hr
= IDirectSoundBuffer8_Play(This
->write_emu
, res1
, res2
, flags
);
748 This
->stopped
= FALSE
;
749 LeaveCriticalSection(This
->crst
);
754 static HRESULT WINAPI
DS8Primary_SetCurrentPosition(IDirectSoundBuffer
*iface
, DWORD pos
)
756 WARN("(%p)->(%"LONGFMT
"u)\n", iface
, pos
);
757 return DSERR_INVALIDCALL
;
760 /* Just assume the format is crap, and clean up the damage */
761 static void copy_waveformat(WAVEFORMATEX
*wfx
, const WAVEFORMATEX
*from
)
763 if(from
->wFormatTag
== WAVE_FORMAT_PCM
)
766 if(from
->wBitsPerSample
== 8 ||
767 from
->wBitsPerSample
== 16 ||
768 from
->wBitsPerSample
== 24 ||
769 from
->wBitsPerSample
== 32)
770 wfx
->wBitsPerSample
= from
->wBitsPerSample
;
772 else if(from
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
774 WAVEFORMATEXTENSIBLE
*wfe
= (WAVEFORMATEXTENSIBLE
*)wfx
;
775 const WAVEFORMATEXTENSIBLE
*fromx
= (const WAVEFORMATEXTENSIBLE
*)from
;
776 DWORD size
= sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
);
778 /* Fail silently.. */
779 if(from
->cbSize
< size
)
781 if(!fromx
->Samples
.wValidBitsPerSample
&&
782 !fromx
->Format
.wBitsPerSample
)
785 if(!IsEqualGUID(&wfe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
) &&
786 !IsEqualGUID(&wfe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
))
788 ERR("Unhandled extensible format: %s\n", debugstr_guid(&wfe
->SubFormat
));
792 wfe
->Format
.wBitsPerSample
= from
->wBitsPerSample
;
793 wfe
->Samples
.wValidBitsPerSample
= fromx
->Samples
.wValidBitsPerSample
;
794 if(!wfe
->Samples
.wValidBitsPerSample
)
795 wfe
->Samples
.wValidBitsPerSample
= wfe
->Format
.wBitsPerSample
;
796 wfe
->Format
.cbSize
= size
;
797 wfe
->dwChannelMask
= fromx
->dwChannelMask
;
798 wfe
->SubFormat
= fromx
->SubFormat
;
802 ERR("Unhandled format tag %04x\n", from
->wFormatTag
);
807 wfx
->nChannels
= from
->nChannels
;
808 wfx
->wFormatTag
= from
->wFormatTag
;
809 if(from
->nSamplesPerSec
>= DSBFREQUENCY_MIN
&&
810 from
->nSamplesPerSec
<= DSBFREQUENCY_MAX
)
811 wfx
->nSamplesPerSec
= from
->nSamplesPerSec
;
812 wfx
->nBlockAlign
= wfx
->wBitsPerSample
* wfx
->nChannels
/ 8;
813 wfx
->nAvgBytesPerSec
= wfx
->nSamplesPerSec
* wfx
->nBlockAlign
;
816 static HRESULT WINAPI
DS8Primary_SetFormat(IDirectSoundBuffer
*iface
, const WAVEFORMATEX
*wfx
)
818 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
822 TRACE("(%p)->(%p)\n", iface
, wfx
);
826 WARN("Missing format\n");
827 return DSERR_INVALIDPARAM
;
830 EnterCriticalSection(This
->crst
);
832 if(This
->parent
->prio_level
< DSSCL_PRIORITY
)
834 hr
= DSERR_PRIOLEVELNEEDED
;
838 TRACE("Requested primary format:\n"
839 " FormatTag = %04x\n"
841 " SamplesPerSec = %"LONGFMT
"u\n"
842 " AvgBytesPerSec = %"LONGFMT
"u\n"
844 " BitsPerSample = %u\n",
845 wfx
->wFormatTag
, wfx
->nChannels
,
846 wfx
->nSamplesPerSec
, wfx
->nAvgBytesPerSec
,
847 wfx
->nBlockAlign
, wfx
->wBitsPerSample
);
849 copy_waveformat(&This
->format
.Format
, wfx
);
851 freq
= This
->format
.Format
.nSamplesPerSec
;
852 alcGetIntegerv(This
->parent
->device
, ALC_FREQUENCY
, 1, &freq
);
853 checkALCError(This
->parent
->device
);
855 This
->format
.Format
.nSamplesPerSec
= freq
;
856 This
->format
.Format
.nAvgBytesPerSec
= This
->format
.Format
.nBlockAlign
*
857 This
->format
.Format
.nSamplesPerSec
;
864 memset(&desc
, 0, sizeof(desc
));
865 desc
.dwSize
= sizeof(desc
);
866 desc
.dwFlags
= DSBCAPS_LOCHARDWARE
|DSBCAPS_CTRLPAN
;
867 desc
.dwBufferBytes
= This
->buf_size
- (This
->buf_size
% This
->format
.Format
.nBlockAlign
);
868 desc
.lpwfxFormat
= &This
->format
.Format
;
870 hr
= DS8Buffer_Create(&buf
, This
, NULL
);
874 hr
= IDirectSoundBuffer8_Initialize(&buf
->IDirectSoundBuffer8_iface
, &This
->parent
->IDirectSound_iface
, &desc
);
876 DS8Buffer_Destroy(buf
);
879 IDirectSoundBuffer8_Release(This
->write_emu
);
880 This
->write_emu
= &buf
->IDirectSoundBuffer8_iface
;
885 LeaveCriticalSection(This
->crst
);
889 static HRESULT WINAPI
DS8Primary_SetVolume(IDirectSoundBuffer
*iface
, LONG vol
)
891 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
893 TRACE("(%p)->(%"LONGFMT
"d)\n", iface
, vol
);
895 if(vol
> DSBVOLUME_MAX
|| vol
< DSBVOLUME_MIN
)
897 WARN("Invalid volume (%"LONGFMT
"d)\n", vol
);
898 return DSERR_INVALIDPARAM
;
901 if(!(This
->flags
&DSBCAPS_CTRLVOLUME
))
902 return DSERR_CONTROLUNAVAIL
;
904 setALContext(This
->ctx
);
905 alListenerf(AL_GAIN
, mB_to_gain(vol
));
911 static HRESULT WINAPI
DS8Primary_SetPan(IDirectSoundBuffer
*iface
, LONG pan
)
913 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
916 TRACE("(%p)->(%"LONGFMT
"d)\n", iface
, pan
);
918 if(pan
> DSBPAN_RIGHT
|| pan
< DSBPAN_LEFT
)
920 WARN("invalid parameter: pan = %"LONGFMT
"d\n", pan
);
921 return DSERR_INVALIDPARAM
;
924 EnterCriticalSection(This
->crst
);
925 if(!(This
->flags
&DSBCAPS_CTRLPAN
))
927 WARN("control unavailable\n");
928 hr
= DSERR_CONTROLUNAVAIL
;
930 else if(This
->write_emu
)
931 hr
= IDirectSoundBuffer8_SetPan(This
->write_emu
, pan
);
934 FIXME("Not supported\n");
937 LeaveCriticalSection(This
->crst
);
942 static HRESULT WINAPI
DS8Primary_SetFrequency(IDirectSoundBuffer
*iface
, DWORD freq
)
944 WARN("(%p)->(%"LONGFMT
"u)\n", iface
, freq
);
945 return DSERR_CONTROLUNAVAIL
;
948 static HRESULT WINAPI
DS8Primary_Stop(IDirectSoundBuffer
*iface
)
950 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
953 TRACE("(%p)->()\n", iface
);
955 EnterCriticalSection(This
->crst
);
957 hr
= IDirectSoundBuffer8_Stop(This
->write_emu
);
959 This
->stopped
= TRUE
;
960 LeaveCriticalSection(This
->crst
);
965 static HRESULT WINAPI
DS8Primary_Unlock(IDirectSoundBuffer
*iface
, void *ptr1
, DWORD len1
, void *ptr2
, DWORD len2
)
967 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
968 HRESULT hr
= DSERR_INVALIDCALL
;
970 TRACE("(%p)->(%p, %"LONGFMT
"u, %p, %"LONGFMT
"u)\n", iface
, ptr1
, len1
, ptr2
, len2
);
972 EnterCriticalSection(This
->crst
);
974 hr
= IDirectSoundBuffer8_Unlock(This
->write_emu
, ptr1
, len1
, ptr2
, len2
);
975 LeaveCriticalSection(This
->crst
);
980 static HRESULT WINAPI
DS8Primary_Restore(IDirectSoundBuffer
*iface
)
982 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
985 TRACE("(%p)->()\n", iface
);
987 EnterCriticalSection(This
->crst
);
989 hr
= IDirectSoundBuffer8_Restore(This
->write_emu
);
990 LeaveCriticalSection(This
->crst
);
995 static const IDirectSoundBufferVtbl DS8Primary_Vtbl
=
997 DS8Primary_QueryInterface
,
1001 DS8Primary_GetCurrentPosition
,
1002 DS8Primary_GetFormat
,
1003 DS8Primary_GetVolume
,
1005 DS8Primary_GetFrequency
,
1006 DS8Primary_GetStatus
,
1007 DS8Primary_Initialize
,
1010 DS8Primary_SetCurrentPosition
,
1011 DS8Primary_SetFormat
,
1012 DS8Primary_SetVolume
,
1014 DS8Primary_SetFrequency
,
1021 static void DS8Primary_SetParams(DS8Primary
*This
, const DS3DLISTENER
*params
, LONG flags
)
1023 union PrimaryParamFlags dirty
= { flags
};
1027 alListener3f(AL_POSITION
, params
->vPosition
.x
, params
->vPosition
.y
,
1028 -params
->vPosition
.z
);
1030 alListener3f(AL_VELOCITY
, params
->vVelocity
.x
, params
->vVelocity
.y
,
1031 -params
->vVelocity
.z
);
1032 if(dirty
.bit
.orientation
)
1034 ALfloat orient
[6] = {
1035 params
->vOrientFront
.x
, params
->vOrientFront
.y
, -params
->vOrientFront
.z
,
1036 params
->vOrientTop
.x
, params
->vOrientTop
.y
, -params
->vOrientTop
.z
1038 alListenerfv(AL_ORIENTATION
, orient
);
1040 if(dirty
.bit
.distancefactor
)
1042 alSpeedOfSound(343.3f
/params
->flDistanceFactor
);
1043 if(This
->SupportedExt
[EXT_EFX
])
1044 alListenerf(AL_METERS_PER_UNIT
, params
->flDistanceFactor
);
1046 if(dirty
.bit
.rollofffactor
)
1048 ALfloat rolloff
= params
->flRolloffFactor
;
1049 This
->rollofffactor
= rolloff
;
1050 for(i
= 0;i
< This
->nbuffers
;++i
)
1052 const DS8Buffer
*buf
= This
->buffers
[i
];
1053 if(buf
->ds3dmode
!= DS3DMODE_DISABLE
)
1054 alSourcef(buf
->source
, AL_ROLLOFF_FACTOR
, rolloff
);
1057 if(dirty
.bit
.dopplerfactor
)
1058 alDopplerFactor(params
->flDopplerFactor
);
1059 if(dirty
.bit
.effect
)
1060 This
->ExtAL
->AuxiliaryEffectSloti(This
->auxslot
, AL_EFFECTSLOT_EFFECT
, This
->effect
);
1063 static HRESULT WINAPI
DS8Primary3D_QueryInterface(IDirectSound3DListener
*iface
, REFIID riid
, void **ppv
)
1065 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1066 return DS8Primary_QueryInterface(&This
->IDirectSoundBuffer_iface
, riid
, ppv
);
1069 static ULONG WINAPI
DS8Primary3D_AddRef(IDirectSound3DListener
*iface
)
1071 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1074 ret
= InterlockedIncrement(&This
->ds3d_ref
);
1075 TRACE("new refcount %"LONGFMT
"d\n", ret
);
1080 static ULONG WINAPI
DS8Primary3D_Release(IDirectSound3DListener
*iface
)
1082 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1085 ret
= InterlockedDecrement(&This
->ds3d_ref
);
1086 TRACE("new refcount %"LONGFMT
"d\n", ret
);
1092 static HRESULT WINAPI
DS8Primary3D_GetAllParameters(IDirectSound3DListener
*iface
, DS3DLISTENER
*listener
)
1094 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1096 TRACE("(%p)->(%p)\n", iface
, listener
);
1098 if(!listener
|| listener
->dwSize
< sizeof(*listener
))
1100 WARN("Invalid DS3DLISTENER %p %"LONGFMT
"u\n", listener
, listener
? listener
->dwSize
: 0);
1101 return DSERR_INVALIDPARAM
;
1104 EnterCriticalSection(This
->crst
);
1105 setALContext(This
->ctx
);
1106 IDirectSound3DListener_GetPosition(iface
, &listener
->vPosition
);
1107 IDirectSound3DListener_GetVelocity(iface
, &listener
->vVelocity
);
1108 IDirectSound3DListener_GetOrientation(iface
, &listener
->vOrientFront
, &listener
->vOrientTop
);
1109 IDirectSound3DListener_GetDistanceFactor(iface
, &listener
->flDistanceFactor
);
1110 IDirectSound3DListener_GetRolloffFactor(iface
, &listener
->flRolloffFactor
);
1111 IDirectSound3DListener_GetDopplerFactor(iface
, &listener
->flDopplerFactor
);
1113 LeaveCriticalSection(This
->crst
);
1118 static HRESULT WINAPI
DS8Primary3D_GetDistanceFactor(IDirectSound3DListener
*iface
, D3DVALUE
*distancefactor
)
1120 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1122 TRACE("(%p)->(%p)\n", iface
, distancefactor
);
1126 WARN("Invalid parameter %p\n", distancefactor
);
1127 return DSERR_INVALIDPARAM
;
1130 setALContext(This
->ctx
);
1131 *distancefactor
= 343.3f
/alGetFloat(AL_SPEED_OF_SOUND
);
1138 static HRESULT WINAPI
DS8Primary3D_GetDopplerFactor(IDirectSound3DListener
*iface
, D3DVALUE
*dopplerfactor
)
1140 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1142 TRACE("(%p)->(%p)\n", iface
, dopplerfactor
);
1146 WARN("Invalid parameter %p\n", dopplerfactor
);
1147 return DSERR_INVALIDPARAM
;
1150 setALContext(This
->ctx
);
1151 *dopplerfactor
= alGetFloat(AL_DOPPLER_FACTOR
);
1158 static HRESULT WINAPI
DS8Primary3D_GetOrientation(IDirectSound3DListener
*iface
, D3DVECTOR
*front
, D3DVECTOR
*top
)
1160 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1163 TRACE("(%p)->(%p, %p)\n", iface
, front
, top
);
1167 WARN("Invalid parameter %p %p\n", front
, top
);
1168 return DSERR_INVALIDPARAM
;
1171 setALContext(This
->ctx
);
1172 alGetListenerfv(AL_ORIENTATION
, orient
);
1176 front
->x
= orient
[0];
1177 front
->y
= orient
[1];
1178 front
->z
= -orient
[2];
1181 top
->z
= -orient
[5];
1185 static HRESULT WINAPI
DS8Primary3D_GetPosition(IDirectSound3DListener
*iface
, D3DVECTOR
*pos
)
1187 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1190 TRACE("(%p)->(%p)\n", iface
, pos
);
1194 WARN("Invalid parameter %p\n", pos
);
1195 return DSERR_INVALIDPARAM
;
1198 setALContext(This
->ctx
);
1199 alGetListenerfv(AL_POSITION
, alpos
);
1209 static HRESULT WINAPI
DS8Primary3D_GetRolloffFactor(IDirectSound3DListener
*iface
, D3DVALUE
*rollofffactor
)
1211 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1213 TRACE("(%p)->(%p)\n", iface
, rollofffactor
);
1217 WARN("Invalid parameter %p\n", rollofffactor
);
1218 return DSERR_INVALIDPARAM
;
1221 EnterCriticalSection(This
->crst
);
1222 *rollofffactor
= This
->rollofffactor
;
1223 LeaveCriticalSection(This
->crst
);
1228 static HRESULT WINAPI
DS8Primary3D_GetVelocity(IDirectSound3DListener
*iface
, D3DVECTOR
*velocity
)
1230 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1233 TRACE("(%p)->(%p)\n", iface
, velocity
);
1237 WARN("Invalid parameter %p\n", velocity
);
1238 return DSERR_INVALIDPARAM
;
1241 setALContext(This
->ctx
);
1242 alGetListenerfv(AL_VELOCITY
, vel
);
1246 velocity
->x
= vel
[0];
1247 velocity
->y
= vel
[1];
1248 velocity
->z
= -vel
[2];
1252 static HRESULT WINAPI
DS8Primary3D_SetAllParameters(IDirectSound3DListener
*iface
, const DS3DLISTENER
*listen
, DWORD apply
)
1254 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1256 TRACE("(%p)->(%p, %"LONGFMT
"u)\n", iface
, listen
, apply
);
1258 if(!listen
|| listen
->dwSize
< sizeof(*listen
))
1260 WARN("Invalid parameter %p %"LONGFMT
"u\n", listen
, listen
? listen
->dwSize
: 0);
1261 return DSERR_INVALIDPARAM
;
1264 if(listen
->flDistanceFactor
> DS3D_MAXDISTANCEFACTOR
||
1265 listen
->flDistanceFactor
< DS3D_MINDISTANCEFACTOR
)
1267 WARN("Invalid distance factor (%f)\n", listen
->flDistanceFactor
);
1268 return DSERR_INVALIDPARAM
;
1271 if(listen
->flDopplerFactor
> DS3D_MAXDOPPLERFACTOR
||
1272 listen
->flDopplerFactor
< DS3D_MINDOPPLERFACTOR
)
1274 WARN("Invalid doppler factor (%f)\n", listen
->flDopplerFactor
);
1275 return DSERR_INVALIDPARAM
;
1278 if(listen
->flRolloffFactor
< DS3D_MINROLLOFFFACTOR
||
1279 listen
->flRolloffFactor
> DS3D_MAXROLLOFFFACTOR
)
1281 WARN("Invalid rolloff factor (%f)\n", listen
->flRolloffFactor
);
1282 return DSERR_INVALIDPARAM
;
1285 if(apply
== DS3D_DEFERRED
)
1287 EnterCriticalSection(This
->crst
);
1288 This
->params
= *listen
;
1289 This
->params
.dwSize
= sizeof(This
->params
);
1290 This
->dirty
.bit
.pos
= 1;
1291 This
->dirty
.bit
.vel
= 1;
1292 This
->dirty
.bit
.orientation
= 1;
1293 This
->dirty
.bit
.distancefactor
= 1;
1294 This
->dirty
.bit
.rollofffactor
= 1;
1295 This
->dirty
.bit
.dopplerfactor
= 1;
1296 LeaveCriticalSection(This
->crst
);
1300 union PrimaryParamFlags dirty
= { 0l };
1303 dirty
.bit
.orientation
= 1;
1304 dirty
.bit
.distancefactor
= 1;
1305 dirty
.bit
.rollofffactor
= 1;
1306 dirty
.bit
.dopplerfactor
= 1;
1308 EnterCriticalSection(This
->crst
);
1309 setALContext(This
->ctx
);
1310 DS8Primary_SetParams(This
, listen
, dirty
.flags
);
1313 LeaveCriticalSection(This
->crst
);
1319 static HRESULT WINAPI
DS8Primary3D_SetDistanceFactor(IDirectSound3DListener
*iface
, D3DVALUE factor
, DWORD apply
)
1321 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1323 TRACE("(%p)->(%f, %"LONGFMT
"u)\n", iface
, factor
, apply
);
1325 if(factor
< DS3D_MINDISTANCEFACTOR
||
1326 factor
> DS3D_MAXDISTANCEFACTOR
)
1328 WARN("Invalid parameter %f\n", factor
);
1329 return DSERR_INVALIDPARAM
;
1332 if(apply
== DS3D_DEFERRED
)
1334 EnterCriticalSection(This
->crst
);
1335 This
->params
.flDistanceFactor
= factor
;
1336 This
->dirty
.bit
.distancefactor
= 1;
1337 LeaveCriticalSection(This
->crst
);
1341 setALContext(This
->ctx
);
1342 alSpeedOfSound(343.3f
/factor
);
1343 if(This
->SupportedExt
[EXT_EFX
])
1344 alListenerf(AL_METERS_PER_UNIT
, factor
);
1352 static HRESULT WINAPI
DS8Primary3D_SetDopplerFactor(IDirectSound3DListener
*iface
, D3DVALUE factor
, DWORD apply
)
1354 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1356 TRACE("(%p)->(%f, %"LONGFMT
"u)\n", iface
, factor
, apply
);
1358 if(factor
< DS3D_MINDOPPLERFACTOR
||
1359 factor
> DS3D_MAXDOPPLERFACTOR
)
1361 WARN("Invalid parameter %f\n", factor
);
1362 return DSERR_INVALIDPARAM
;
1365 if(apply
== DS3D_DEFERRED
)
1367 EnterCriticalSection(This
->crst
);
1368 This
->params
.flDopplerFactor
= factor
;
1369 This
->dirty
.bit
.dopplerfactor
= 1;
1370 LeaveCriticalSection(This
->crst
);
1374 setALContext(This
->ctx
);
1375 alDopplerFactor(factor
);
1383 static HRESULT WINAPI
DS8Primary3D_SetOrientation(IDirectSound3DListener
*iface
, D3DVALUE xFront
, D3DVALUE yFront
, D3DVALUE zFront
, D3DVALUE xTop
, D3DVALUE yTop
, D3DVALUE zTop
, DWORD apply
)
1385 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1387 TRACE("(%p)->(%f, %f, %f, %f, %f, %f, %"LONGFMT
"u)\n", iface
, xFront
, yFront
, zFront
, xTop
, yTop
, zTop
, apply
);
1389 if(apply
== DS3D_DEFERRED
)
1391 EnterCriticalSection(This
->crst
);
1392 This
->params
.vOrientFront
.x
= xFront
;
1393 This
->params
.vOrientFront
.y
= yFront
;
1394 This
->params
.vOrientFront
.z
= zFront
;
1395 This
->params
.vOrientTop
.x
= xTop
;
1396 This
->params
.vOrientTop
.y
= yTop
;
1397 This
->params
.vOrientTop
.z
= zTop
;
1398 This
->dirty
.bit
.orientation
= 1;
1399 LeaveCriticalSection(This
->crst
);
1403 ALfloat orient
[6] = {
1404 xFront
, yFront
, -zFront
,
1407 setALContext(This
->ctx
);
1408 alListenerfv(AL_ORIENTATION
, orient
);
1416 static HRESULT WINAPI
DS8Primary3D_SetPosition(IDirectSound3DListener
*iface
, D3DVALUE x
, D3DVALUE y
, D3DVALUE z
, DWORD apply
)
1418 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1420 TRACE("(%p)->(%f, %f, %f, %"LONGFMT
"u)\n", iface
, x
, y
, z
, apply
);
1422 if(apply
== DS3D_DEFERRED
)
1424 EnterCriticalSection(This
->crst
);
1425 This
->params
.vPosition
.x
= x
;
1426 This
->params
.vPosition
.y
= y
;
1427 This
->params
.vPosition
.z
= z
;
1428 This
->dirty
.bit
.pos
= 1;
1429 LeaveCriticalSection(This
->crst
);
1433 setALContext(This
->ctx
);
1434 alListener3f(AL_POSITION
, x
, y
, -z
);
1442 static HRESULT WINAPI
DS8Primary3D_SetRolloffFactor(IDirectSound3DListener
*iface
, D3DVALUE factor
, DWORD apply
)
1444 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1446 TRACE("(%p)->(%f, %"LONGFMT
"u)\n", iface
, factor
, apply
);
1448 if(factor
< DS3D_MINROLLOFFFACTOR
||
1449 factor
> DS3D_MAXROLLOFFFACTOR
)
1451 WARN("Invalid parameter %f\n", factor
);
1452 return DSERR_INVALIDPARAM
;
1455 EnterCriticalSection(This
->crst
);
1456 if(apply
== DS3D_DEFERRED
)
1458 This
->params
.flRolloffFactor
= factor
;
1459 This
->dirty
.bit
.rollofffactor
= 1;
1465 setALContext(This
->ctx
);
1466 for(i
= 0;i
< This
->nbuffers
;++i
)
1468 if(This
->buffers
[i
]->ds3dmode
!= DS3DMODE_DISABLE
)
1469 alSourcef(This
->buffers
[i
]->source
, AL_ROLLOFF_FACTOR
, factor
);
1474 This
->rollofffactor
= factor
;
1476 LeaveCriticalSection(This
->crst
);
1481 static HRESULT WINAPI
DS8Primary3D_SetVelocity(IDirectSound3DListener
*iface
, D3DVALUE x
, D3DVALUE y
, D3DVALUE z
, DWORD apply
)
1483 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1485 TRACE("(%p)->(%f, %f, %f, %"LONGFMT
"u)\n", iface
, x
, y
, z
, apply
);
1487 if(apply
== DS3D_DEFERRED
)
1489 EnterCriticalSection(This
->crst
);
1490 This
->params
.vVelocity
.x
= x
;
1491 This
->params
.vVelocity
.y
= y
;
1492 This
->params
.vVelocity
.z
= z
;
1493 This
->dirty
.bit
.vel
= 1;
1494 LeaveCriticalSection(This
->crst
);
1498 setALContext(This
->ctx
);
1499 alListener3f(AL_VELOCITY
, x
, y
, -z
);
1507 static HRESULT WINAPI
DS8Primary3D_CommitDeferredSettings(IDirectSound3DListener
*iface
)
1509 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1513 EnterCriticalSection(This
->crst
);
1514 setALContext(This
->ctx
);
1515 This
->DeferUpdates();
1517 if((flags
=InterlockedExchange(&This
->dirty
.flags
, 0)) != 0)
1519 DS8Primary_SetParams(This
, &This
->params
, flags
);
1520 /* checkALError is here for debugging */
1523 TRACE("Dirty flags was: 0x%02x\n", flags
);
1525 for(i
= 0;i
< This
->nbuffers
;++i
)
1527 DS8Buffer
*buf
= This
->buffers
[i
];
1529 if((flags
=InterlockedExchange(&buf
->dirty
.flags
, 0)) != 0)
1530 DS8Buffer_SetParams(buf
, &buf
->params
, flags
);
1534 This
->ProcessUpdates();
1536 LeaveCriticalSection(This
->crst
);
1541 static const IDirectSound3DListenerVtbl DS8Primary3D_Vtbl
=
1543 DS8Primary3D_QueryInterface
,
1544 DS8Primary3D_AddRef
,
1545 DS8Primary3D_Release
,
1546 DS8Primary3D_GetAllParameters
,
1547 DS8Primary3D_GetDistanceFactor
,
1548 DS8Primary3D_GetDopplerFactor
,
1549 DS8Primary3D_GetOrientation
,
1550 DS8Primary3D_GetPosition
,
1551 DS8Primary3D_GetRolloffFactor
,
1552 DS8Primary3D_GetVelocity
,
1553 DS8Primary3D_SetAllParameters
,
1554 DS8Primary3D_SetDistanceFactor
,
1555 DS8Primary3D_SetDopplerFactor
,
1556 DS8Primary3D_SetOrientation
,
1557 DS8Primary3D_SetPosition
,
1558 DS8Primary3D_SetRolloffFactor
,
1559 DS8Primary3D_SetVelocity
,
1560 DS8Primary3D_CommitDeferredSettings
1563 /* NOTE: Although the app handles listener properties through secondary buffers,
1564 * we pass the requests to the primary buffer though a propertyset interface.
1565 * These methods are not exposed to the app. */
1566 static HRESULT WINAPI
DS8PrimaryProp_QueryInterface(IKsPropertySet
*iface
, REFIID riid
, void **ppv
)
1568 DS8Primary
*This
= impl_from_IKsPropertySet(iface
);
1569 return DS8Primary_QueryInterface(&This
->IDirectSoundBuffer_iface
, riid
, ppv
);
1572 static ULONG WINAPI
DS8PrimaryProp_AddRef(IKsPropertySet
*iface
)
1574 DS8Primary
*This
= impl_from_IKsPropertySet(iface
);
1577 ret
= InterlockedIncrement(&This
->prop_ref
);
1578 TRACE("new refcount %"LONGFMT
"d\n", ret
);
1583 static ULONG WINAPI
DS8PrimaryProp_Release(IKsPropertySet
*iface
)
1585 DS8Primary
*This
= impl_from_IKsPropertySet(iface
);
1588 ret
= InterlockedDecrement(&This
->prop_ref
);
1589 TRACE("new refcount %"LONGFMT
"d\n", ret
);
1594 static HRESULT WINAPI
DS8PrimaryProp_Get(IKsPropertySet
*iface
,
1595 REFGUID guidPropSet
, ULONG dwPropID
,
1596 LPVOID pInstanceData
, ULONG cbInstanceData
,
1597 LPVOID pPropData
, ULONG cbPropData
,
1600 DS8Primary
*This
= impl_from_IKsPropertySet(iface
);
1601 HRESULT res
= E_PROP_ID_UNSUPPORTED
;
1602 (void)pInstanceData
;
1603 (void)cbInstanceData
;
1605 if(IsEqualIID(guidPropSet
, &DSPROPSETID_EAX20_ListenerProperties
))
1607 EnterCriticalSection(This
->crst
);
1609 if(This
->effect
== 0)
1610 res
= E_PROP_ID_UNSUPPORTED
;
1611 else switch(dwPropID
)
1613 case DSPROPERTY_EAXLISTENER_ALLPARAMETERS
:
1614 res
= DSERR_INVALIDPARAM
;
1615 if(cbPropData
>= sizeof(EAXLISTENERPROPERTIES
))
1619 EAXLISTENERPROPERTIES
*props
;
1620 } data
= { pPropData
};
1622 *data
.props
= This
->eax_prop
;
1623 *pcbReturned
= sizeof(EAXLISTENERPROPERTIES
);
1628 case DSPROPERTY_EAXLISTENER_ROOM
:
1629 res
= DSERR_INVALIDPARAM
;
1630 if(cbPropData
>= sizeof(LONG
))
1635 } data
= { pPropData
};
1637 *data
.l
= This
->eax_prop
.lRoom
;
1638 *pcbReturned
= sizeof(LONG
);
1642 case DSPROPERTY_EAXLISTENER_ROOMHF
:
1643 res
= DSERR_INVALIDPARAM
;
1644 if(cbPropData
>= sizeof(LONG
))
1649 } data
= { pPropData
};
1651 *data
.l
= This
->eax_prop
.lRoomHF
;
1652 *pcbReturned
= sizeof(LONG
);
1657 case DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR
:
1658 res
= DSERR_INVALIDPARAM
;
1659 if(cbPropData
>= sizeof(FLOAT
))
1664 } data
= { pPropData
};
1666 *data
.fl
= This
->eax_prop
.flRoomRolloffFactor
;
1667 *pcbReturned
= sizeof(FLOAT
);
1672 case DSPROPERTY_EAXLISTENER_ENVIRONMENT
:
1673 res
= DSERR_INVALIDPARAM
;
1674 if(cbPropData
>= sizeof(DWORD
))
1679 } data
= { pPropData
};
1681 *data
.dw
= This
->eax_prop
.dwEnvironment
;
1682 *pcbReturned
= sizeof(DWORD
);
1687 case DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE
:
1688 res
= DSERR_INVALIDPARAM
;
1689 if(cbPropData
>= sizeof(FLOAT
))
1694 } data
= { pPropData
};
1696 *data
.fl
= This
->eax_prop
.flEnvironmentSize
;
1697 *pcbReturned
= sizeof(FLOAT
);
1701 case DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION
:
1702 res
= DSERR_INVALIDPARAM
;
1703 if(cbPropData
>= sizeof(FLOAT
))
1708 } data
= { pPropData
};
1710 *data
.fl
= This
->eax_prop
.flEnvironmentDiffusion
;
1711 *pcbReturned
= sizeof(FLOAT
);
1716 case DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF
:
1717 res
= DSERR_INVALIDPARAM
;
1718 if(cbPropData
>= sizeof(FLOAT
))
1723 } data
= { pPropData
};
1725 *data
.fl
= This
->eax_prop
.flAirAbsorptionHF
;
1726 *pcbReturned
= sizeof(FLOAT
);
1731 case DSPROPERTY_EAXLISTENER_FLAGS
:
1732 res
= DSERR_INVALIDPARAM
;
1733 if(cbPropData
>= sizeof(DWORD
))
1738 } data
= { pPropData
};
1740 *data
.dw
= This
->eax_prop
.dwFlags
;
1741 *pcbReturned
= sizeof(DWORD
);
1747 FIXME("Unhandled propid: 0x%08"LONGFMT
"x\n", dwPropID
);
1751 LeaveCriticalSection(This
->crst
);
1754 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet
));
1759 static HRESULT WINAPI
DS8PrimaryProp_Set(IKsPropertySet
*iface
,
1760 REFGUID guidPropSet
, ULONG dwPropID
,
1761 LPVOID pInstanceData
, ULONG cbInstanceData
,
1762 LPVOID pPropData
, ULONG cbPropData
)
1764 DS8Primary
*This
= impl_from_IKsPropertySet(iface
);
1765 HRESULT res
= E_PROP_ID_UNSUPPORTED
;
1766 (void)pInstanceData
;
1767 (void)cbInstanceData
;
1769 if(IsEqualIID(guidPropSet
, &DSPROPSETID_EAX20_ListenerProperties
))
1771 DWORD propid
= dwPropID
& ~DSPROPERTY_EAXLISTENER_DEFERRED
;
1772 BOOL immediate
= !(dwPropID
&DSPROPERTY_EAXLISTENER_DEFERRED
);
1774 EnterCriticalSection(This
->crst
);
1775 setALContext(This
->ctx
);
1777 if(This
->effect
== 0)
1778 res
= E_PROP_ID_UNSUPPORTED
;
1781 case DSPROPERTY_EAXLISTENER_NONE
: /* not setting any property, just applying */
1785 case DSPROPERTY_EAXLISTENER_ALLPARAMETERS
:
1787 res
= DSERR_INVALIDPARAM
;
1788 if(cbPropData
>= sizeof(EAXLISTENERPROPERTIES
))
1792 const EAXLISTENERPROPERTIES
*props
;
1793 } data
= { pPropData
};
1795 /* FIXME: Need to validate property values... Ignore? Clamp? Error? */
1796 This
->eax_prop
= *data
.props
;
1797 This
->ExtAL
->Effectf(This
->effect
, AL_REVERB_DENSITY
,
1798 (data
.props
->flEnvironmentSize
< 2.0f
) ?
1799 (data
.props
->flEnvironmentSize
- 1.0f
) : 1.0f
);
1800 This
->ExtAL
->Effectf(This
->effect
, AL_REVERB_DIFFUSION
,
1801 data
.props
->flEnvironmentDiffusion
);
1803 This
->ExtAL
->Effectf(This
->effect
, AL_REVERB_GAIN
,
1804 mB_to_gain(data
.props
->lRoom
));
1805 This
->ExtAL
->Effectf(This
->effect
, AL_REVERB_GAINHF
,
1806 mB_to_gain(data
.props
->lRoomHF
));
1808 This
->ExtAL
->Effectf(This
->effect
, AL_REVERB_ROOM_ROLLOFF_FACTOR
,
1809 data
.props
->flRoomRolloffFactor
);
1811 This
->ExtAL
->Effectf(This
->effect
, AL_REVERB_DECAY_TIME
,
1812 data
.props
->flDecayTime
);
1813 This
->ExtAL
->Effectf(This
->effect
, AL_REVERB_DECAY_HFRATIO
,
1814 data
.props
->flDecayHFRatio
);
1816 This
->ExtAL
->Effectf(This
->effect
, AL_REVERB_REFLECTIONS_GAIN
,
1817 mB_to_gain(data
.props
->lReflections
));
1818 This
->ExtAL
->Effectf(This
->effect
, AL_REVERB_REFLECTIONS_DELAY
,
1819 data
.props
->flReflectionsDelay
);
1821 This
->ExtAL
->Effectf(This
->effect
, AL_REVERB_LATE_REVERB_GAIN
,
1822 mB_to_gain(data
.props
->lReverb
));
1823 This
->ExtAL
->Effectf(This
->effect
, AL_REVERB_LATE_REVERB_DELAY
,
1824 data
.props
->flReverbDelay
);
1826 This
->ExtAL
->Effectf(This
->effect
, AL_REVERB_AIR_ABSORPTION_GAINHF
,
1827 mB_to_gain(data
.props
->flAirAbsorptionHF
));
1829 This
->ExtAL
->Effecti(This
->effect
, AL_REVERB_DECAY_HFLIMIT
,
1830 (data
.props
->dwFlags
&EAXLISTENERFLAGS_DECAYHFLIMIT
) ?
1831 AL_TRUE
: AL_FALSE
);
1835 This
->dirty
.bit
.effect
= 1;
1840 case DSPROPERTY_EAXLISTENER_ROOM
:
1841 res
= DSERR_INVALIDPARAM
;
1842 if(cbPropData
>= sizeof(LONG
))
1847 } data
= { pPropData
};
1849 This
->eax_prop
.lRoom
= *data
.l
;
1850 This
->ExtAL
->Effectf(This
->effect
, AL_REVERB_GAIN
,
1851 mB_to_gain(This
->eax_prop
.lRoom
));
1854 This
->dirty
.bit
.effect
= 1;
1858 case DSPROPERTY_EAXLISTENER_ROOMHF
:
1859 res
= DSERR_INVALIDPARAM
;
1860 if(cbPropData
>= sizeof(LONG
))
1865 } data
= { pPropData
};
1867 This
->eax_prop
.lRoomHF
= *data
.l
;
1868 This
->ExtAL
->Effectf(This
->effect
, AL_REVERB_GAINHF
,
1869 mB_to_gain(This
->eax_prop
.lRoomHF
));
1872 This
->dirty
.bit
.effect
= 1;
1877 case DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR
:
1878 res
= DSERR_INVALIDPARAM
;
1879 if(cbPropData
>= sizeof(FLOAT
))
1884 } data
= { pPropData
};
1886 This
->eax_prop
.flRoomRolloffFactor
= *data
.fl
;
1887 This
->ExtAL
->Effectf(This
->effect
, AL_REVERB_ROOM_ROLLOFF_FACTOR
,
1888 This
->eax_prop
.flRoomRolloffFactor
);
1891 This
->dirty
.bit
.effect
= 1;
1896 case DSPROPERTY_EAXLISTENER_ENVIRONMENT
:
1897 res
= DSERR_INVALIDPARAM
;
1898 if(cbPropData
>= sizeof(DWORD
))
1903 } data
= { pPropData
};
1905 if(*data
.dw
< EAX_ENVIRONMENT_COUNT
)
1907 /* Get the environment index's default and pass it down to
1909 propid
= DSPROPERTY_EAXLISTENER_ALLPARAMETERS
;
1910 pPropData
= (void*)&EnvironmentDefaults
[*data
.dw
];
1911 cbPropData
= sizeof(EnvironmentDefaults
[*data
.dw
]);
1917 case DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE
:
1918 res
= DSERR_INVALIDPARAM
;
1919 if(cbPropData
>= sizeof(FLOAT
))
1924 } data
= { pPropData
};
1926 if(*data
.fl
>= 1.0f
&& *data
.fl
<= 100.0f
)
1928 double scale
= (*data
.fl
)/This
->eax_prop
.flEnvironmentSize
;
1930 This
->eax_prop
.flEnvironmentSize
= *data
.fl
;
1932 if((This
->eax_prop
.dwFlags
&EAXLISTENERFLAGS_DECAYTIMESCALE
))
1934 This
->eax_prop
.flDecayTime
*= scale
;
1935 This
->eax_prop
.flDecayTime
= clampF(This
->eax_prop
.flDecayTime
, 0.1f
, 20.0f
);
1937 if((This
->eax_prop
.dwFlags
&EAXLISTENERFLAGS_REFLECTIONSSCALE
))
1939 This
->eax_prop
.lReflections
+= gain_to_mB(1.0/scale
);
1940 This
->eax_prop
.lReflections
= clampI(This
->eax_prop
.lReflections
, -10000, 1000);
1942 if((This
->eax_prop
.dwFlags
&EAXLISTENERFLAGS_REFLECTIONSDELAYSCALE
))
1944 This
->eax_prop
.flReflectionsDelay
*= scale
;
1945 This
->eax_prop
.flReflectionsDelay
= clampF(This
->eax_prop
.flReflectionsDelay
, 0.0f
, 0.3f
);
1947 if((This
->eax_prop
.dwFlags
&EAXLISTENERFLAGS_REVERBSCALE
))
1949 This
->eax_prop
.lReverb
+= gain_to_mB(1.0/scale
);
1950 This
->eax_prop
.lReverb
= clampI(This
->eax_prop
.lReverb
, -10000, 2000);
1952 if((This
->eax_prop
.dwFlags
&EAXLISTENERFLAGS_REVERBDELAYSCALE
))
1954 This
->eax_prop
.flReverbDelay
*= scale
;
1955 This
->eax_prop
.flReverbDelay
= clampF(This
->eax_prop
.flReverbDelay
, 0.0f
, 0.1f
);
1958 /* Pass the updated environment properties down to ALLPARAMETERS */
1959 propid
= DSPROPERTY_EAXLISTENER_ALLPARAMETERS
;
1960 pPropData
= (void*)&This
->eax_prop
;
1961 cbPropData
= sizeof(This
->eax_prop
);
1966 case DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION
:
1967 res
= DSERR_INVALIDPARAM
;
1968 if(cbPropData
>= sizeof(FLOAT
))
1973 } data
= { pPropData
};
1975 This
->eax_prop
.flEnvironmentDiffusion
= *data
.fl
;
1976 This
->ExtAL
->Effectf(This
->effect
, AL_REVERB_DIFFUSION
,
1977 This
->eax_prop
.flEnvironmentDiffusion
);
1980 This
->dirty
.bit
.effect
= 1;
1985 case DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF
:
1986 res
= DSERR_INVALIDPARAM
;
1987 if(cbPropData
>= sizeof(FLOAT
))
1992 } data
= { pPropData
};
1994 This
->eax_prop
.flAirAbsorptionHF
= *data
.fl
;
1995 This
->ExtAL
->Effectf(This
->effect
, AL_REVERB_AIR_ABSORPTION_GAINHF
,
1996 mB_to_gain(This
->eax_prop
.flAirAbsorptionHF
));
1999 This
->dirty
.bit
.effect
= 1;
2004 case DSPROPERTY_EAXLISTENER_FLAGS
:
2005 res
= DSERR_INVALIDPARAM
;
2006 if(cbPropData
>= sizeof(DWORD
))
2011 } data
= { pPropData
};
2013 This
->eax_prop
.dwFlags
= *data
.dw
;
2014 This
->ExtAL
->Effecti(This
->effect
, AL_REVERB_DECAY_HFLIMIT
,
2015 (This
->eax_prop
.dwFlags
&EAXLISTENERFLAGS_DECAYHFLIMIT
) ?
2016 AL_TRUE
: AL_FALSE
);
2019 This
->dirty
.bit
.effect
= 1;
2025 FIXME("Unhandled propid: 0x%08"LONGFMT
"x\n", propid
);
2029 if(res
== DS_OK
&& immediate
)
2030 IDirectSound3DListener_CommitDeferredSettings(&This
->IDirectSound3DListener_iface
);
2033 LeaveCriticalSection(This
->crst
);
2036 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet
));
2041 static HRESULT WINAPI
DS8PrimaryProp_QuerySupport(IKsPropertySet
*iface
,
2042 REFGUID guidPropSet
, ULONG dwPropID
,
2043 PULONG pTypeSupport
)
2045 DS8Primary
*This
= impl_from_IKsPropertySet(iface
);
2046 HRESULT res
= E_PROP_ID_UNSUPPORTED
;
2048 if(IsEqualIID(guidPropSet
, &DSPROPSETID_EAX20_ListenerProperties
))
2050 EnterCriticalSection(This
->crst
);
2052 if(This
->effect
== 0)
2053 res
= E_PROP_ID_UNSUPPORTED
;
2054 else if(dwPropID
== DSPROPERTY_EAXLISTENER_ALLPARAMETERS
||
2055 dwPropID
== DSPROPERTY_EAXLISTENER_ROOM
||
2056 dwPropID
== DSPROPERTY_EAXLISTENER_ROOMHF
||
2057 dwPropID
== DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR
||
2058 dwPropID
== DSPROPERTY_EAXLISTENER_ENVIRONMENT
||
2059 dwPropID
== DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE
||
2060 dwPropID
== DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION
||
2061 dwPropID
== DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF
||
2062 dwPropID
== DSPROPERTY_EAXLISTENER_FLAGS
)
2064 *pTypeSupport
= KSPROPERTY_SUPPORT_GET
|KSPROPERTY_SUPPORT_SET
;
2068 FIXME("Unhandled propid: 0x%08"LONGFMT
"x\n", dwPropID
);
2070 LeaveCriticalSection(This
->crst
);
2073 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet
));
2078 static const IKsPropertySetVtbl DS8PrimaryProp_Vtbl
=
2080 DS8PrimaryProp_QueryInterface
,
2081 DS8PrimaryProp_AddRef
,
2082 DS8PrimaryProp_Release
,
2085 DS8PrimaryProp_QuerySupport