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
31 #include "dsound_private.h"
33 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM
, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
34 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
36 #ifndef E_PROP_ID_UNSUPPORTED
37 #define E_PROP_ID_UNSUPPORTED ((HRESULT)0x80070490)
41 static const IDirectSoundBufferVtbl DS8Primary_Vtbl
;
42 static const IDirectSound3DListenerVtbl DS8Primary3D_Vtbl
;
43 static const IKsPropertySetVtbl DS8PrimaryProp_Vtbl
;
46 static inline DS8Primary
*impl_from_IDirectSoundBuffer(IDirectSoundBuffer
*iface
)
48 return CONTAINING_RECORD(iface
, DS8Primary
, IDirectSoundBuffer_iface
);
51 static inline DS8Primary
*impl_from_IDirectSound3DListener(IDirectSound3DListener
*iface
)
53 return CONTAINING_RECORD(iface
, DS8Primary
, IDirectSound3DListener_iface
);
56 static inline DS8Primary
*impl_from_IKsPropertySet(IKsPropertySet
*iface
)
58 return CONTAINING_RECORD(iface
, DS8Primary
, IKsPropertySet_iface
);
62 static void AL_APIENTRY
wrap_DeferUpdates(void)
63 { alcSuspendContext(alcGetCurrentContext()); }
64 static void AL_APIENTRY
wrap_ProcessUpdates(void)
65 { alcProcessContext(alcGetCurrentContext()); }
68 static void trigger_elapsed_notifies(DS8Buffer
*buf
, DWORD lastpos
, DWORD curpos
)
70 DSBPOSITIONNOTIFY
*not = buf
->notify
;
71 DSBPOSITIONNOTIFY
*not_end
= not + buf
->nnotify
;
72 for(;not != not_end
;++not)
74 HANDLE event
= not->hEventNotify
;
75 DWORD ofs
= not->dwOffset
;
77 if(ofs
== (DWORD
)DSBPN_OFFSETSTOP
)
80 if(curpos
< lastpos
) /* Wraparound case */
82 if(ofs
< curpos
|| ofs
>= lastpos
)
84 TRACE("Triggering notification %d from buffer %p\n", not - buf
->notify
, buf
);
88 else if(ofs
>= lastpos
&& ofs
< curpos
) /* Normal case */
90 TRACE("Triggering notification %d from buffer %p\n", not - buf
->notify
, buf
);
96 static void trigger_stop_notifies(DS8Buffer
*buf
)
98 DSBPOSITIONNOTIFY
*not = buf
->notify
;
99 DSBPOSITIONNOTIFY
*not_end
= not + buf
->nnotify
;
100 for(;not != not_end
;++not)
102 if(not->dwOffset
!= (DWORD
)DSBPN_OFFSETSTOP
)
104 TRACE("Triggering notification %d from buffer %p\n", not - buf
->notify
, buf
);
105 SetEvent(not->hEventNotify
);
109 void DS8Primary_triggernots(DS8Primary
*prim
)
111 DS8Buffer
**curnot
, **endnot
;
113 curnot
= prim
->notifies
;
114 endnot
= curnot
+ prim
->nnotifies
;
115 while(curnot
!= endnot
)
117 DS8Buffer
*buf
= *curnot
;
118 DS8Data
*data
= buf
->buffer
;
119 DWORD curpos
= buf
->lastpos
;
123 alGetSourcei(buf
->source
, AL_BYTE_OFFSET
, &ofs
);
124 alGetSourcei(buf
->source
, AL_SOURCE_STATE
, &state
);
125 if(buf
->segsize
== 0)
126 curpos
= (state
== AL_STOPPED
) ? data
->buf_size
: ofs
;
129 if(state
!= AL_STOPPED
)
130 curpos
= ofs
+ buf
->queue_base
;
134 alGetSourcei(buf
->source
, AL_BUFFERS_QUEUED
, &queued
);
135 curpos
= buf
->segsize
*queued
+ buf
->queue_base
;
138 if(curpos
>= (DWORD
)data
->buf_size
)
141 curpos
%= (DWORD
)data
->buf_size
;
142 else if(buf
->isplaying
)
144 curpos
= data
->buf_size
;
145 alSourceStop(buf
->source
);
146 alSourcei(buf
->source
, AL_BUFFER
, 0);
148 buf
->isplaying
= FALSE
;
152 if(state
!= AL_PLAYING
)
153 state
= buf
->isplaying
? AL_PLAYING
: AL_PAUSED
;
157 if(buf
->lastpos
!= curpos
)
159 trigger_elapsed_notifies(buf
, buf
->lastpos
, curpos
);
160 buf
->lastpos
= curpos
;
162 if(state
!= AL_PLAYING
)
164 /* Remove this buffer from list and put another at the current
165 * position; don't increment i
167 trigger_stop_notifies(buf
);
168 *curnot
= *(--endnot
);
177 static void do_buffer_stream(DS8Buffer
*buf
, BYTE
*scratch_mem
)
179 DS8Data
*data
= buf
->buffer
;
180 ALint ofs
, done
= 0, queued
= QBUFFERS
, state
= AL_PLAYING
;
183 alGetSourcei(buf
->source
, AL_BUFFERS_QUEUED
, &queued
);
184 alGetSourcei(buf
->source
, AL_SOURCE_STATE
, &state
);
185 alGetSourcei(buf
->source
, AL_BUFFERS_PROCESSED
, &done
);
189 ALuint bids
[QBUFFERS
];
192 alSourceUnqueueBuffers(buf
->source
, done
, bids
);
193 buf
->queue_base
= (buf
->queue_base
+ buf
->segsize
*done
) % data
->buf_size
;
195 while(queued
< QBUFFERS
)
197 which
= buf
->stream_bids
[buf
->curidx
];
198 ofs
= buf
->data_offset
;
200 if(buf
->segsize
< data
->buf_size
- ofs
)
202 alBufferData(which
, data
->buf_format
, data
->data
+ ofs
, buf
->segsize
,
203 data
->format
.Format
.nSamplesPerSec
);
204 buf
->data_offset
= ofs
+ buf
->segsize
;
206 else if(buf
->islooping
)
208 ALsizei rem
= data
->buf_size
- ofs
;
209 if(rem
> 2048) rem
= 2048;
211 memcpy(scratch_mem
, data
->data
+ ofs
, rem
);
212 while(rem
< buf
->segsize
)
214 ALsizei todo
= buf
->segsize
- rem
;
215 if(todo
> data
->buf_size
)
216 todo
= data
->buf_size
;
217 memcpy(scratch_mem
+ rem
, data
->data
, todo
);
220 alBufferData(which
, data
->buf_format
, scratch_mem
, buf
->segsize
,
221 data
->format
.Format
.nSamplesPerSec
);
222 buf
->data_offset
= (ofs
+buf
->segsize
) % data
->buf_size
;
226 ALsizei rem
= data
->buf_size
- ofs
;
227 if(rem
> 2048) rem
= 2048;
230 memcpy(scratch_mem
, data
->data
+ ofs
, rem
);
231 memset(scratch_mem
+rem
, (data
->format
.Format
.wBitsPerSample
==8) ? 128 : 0,
233 alBufferData(which
, data
->buf_format
, scratch_mem
, buf
->segsize
,
234 data
->format
.Format
.nSamplesPerSec
);
235 buf
->data_offset
= data
->buf_size
;
238 alSourceQueueBuffers(buf
->source
, 1, &which
);
239 buf
->curidx
= (buf
->curidx
+1)%QBUFFERS
;
245 buf
->data_offset
= 0;
246 buf
->queue_base
= data
->buf_size
;
248 buf
->isplaying
= FALSE
;
250 else if(state
!= AL_PLAYING
)
251 alSourcePlay(buf
->source
);
254 void DS8Primary_streamfeeder(DS8Primary
*prim
, BYTE
*scratch_mem
)
256 /* OpenAL doesn't support our lovely buffer extensions so just make sure
257 * enough buffers are queued for streaming
261 DS8Buffer
*buf
= &prim
->writable_buf
;
262 if(buf
->segsize
!= 0 && buf
->isplaying
)
263 do_buffer_stream(buf
, scratch_mem
);
267 struct DSBufferGroup
*bufgroup
= prim
->BufferGroups
;
268 struct DSBufferGroup
*endgroup
= bufgroup
+ prim
->NumBufferGroups
;
269 for(;bufgroup
!= endgroup
;++bufgroup
)
271 DWORD64 usemask
= ~bufgroup
->FreeBuffers
;
274 int idx
= CTZ64(usemask
);
275 DS8Buffer
*buf
= bufgroup
->Buffers
+ idx
;
276 usemask
&= ~(U64(1) << idx
);
278 if(buf
->segsize
!= 0 && buf
->isplaying
)
279 do_buffer_stream(buf
, scratch_mem
);
287 HRESULT
DS8Primary_PreInit(DS8Primary
*This
, DS8Impl
*parent
)
289 DS3DLISTENER
*listener
;
296 This
->IDirectSoundBuffer_iface
.lpVtbl
= &DS8Primary_Vtbl
;
297 This
->IDirectSound3DListener_iface
.lpVtbl
= &DS8Primary3D_Vtbl
;
298 This
->IKsPropertySet_iface
.lpVtbl
= &DS8PrimaryProp_Vtbl
;
300 This
->parent
= parent
;
301 This
->crst
= &parent
->share
->crst
;
302 This
->ctx
= parent
->share
->ctx
;
303 This
->refresh
= parent
->share
->refresh
;
304 This
->SupportedExt
= parent
->share
->SupportedExt
;
305 This
->ExtAL
= &parent
->share
->ExtAL
;
306 This
->sources
= parent
->share
->sources
;
307 This
->auxslot
= parent
->share
->auxslot
;
309 wfx
= &This
->format
.Format
;
310 wfx
->wFormatTag
= WAVE_FORMAT_PCM
;
312 wfx
->wBitsPerSample
= 8;
313 wfx
->nSamplesPerSec
= 22050;
314 wfx
->nBlockAlign
= wfx
->wBitsPerSample
* wfx
->nChannels
/ 8;
315 wfx
->nAvgBytesPerSec
= wfx
->nSamplesPerSec
* wfx
->nBlockAlign
;
318 This
->stopped
= TRUE
;
320 /* Apparently primary buffer size is always 32k,
321 * tested on windows with 192k 24 bits sound @ 6 channels
322 * where it will run out in 60 ms and it isn't pointer aligned
324 This
->buf_size
= 32768;
326 setALContext(This
->ctx
);
327 if(This
->SupportedExt
[SOFT_DEFERRED_UPDATES
])
329 This
->DeferUpdates
= This
->ExtAL
->DeferUpdatesSOFT
;
330 This
->ProcessUpdates
= This
->ExtAL
->ProcessUpdatesSOFT
;
334 This
->DeferUpdates
= wrap_DeferUpdates
;
335 This
->ProcessUpdates
= wrap_ProcessUpdates
;
338 This
->eax_prop
= EnvironmentDefaults
[EAX_ENVIRONMENT_GENERIC
];
339 if(This
->SupportedExt
[EXT_EFX
] && This
->auxslot
!= 0)
341 ALint revid
= alGetEnumValue("AL_EFFECT_REVERB");
342 if(revid
!= 0 && revid
!= -1)
344 This
->ExtAL
->GenEffects(1, &This
->effect
);
345 This
->ExtAL
->Effecti(This
->effect
, AL_EFFECT_TYPE
, AL_EFFECT_REVERB
);
351 listener
= &This
->params
;
352 listener
->dwSize
= sizeof(This
->params
);
353 listener
->vPosition
.x
= 0.0f
;
354 listener
->vPosition
.y
= 0.0f
;
355 listener
->vPosition
.z
= 0.0f
;
356 listener
->vVelocity
.x
= 0.0f
;
357 listener
->vVelocity
.y
= 0.0f
;
358 listener
->vVelocity
.z
= 0.0f
;
359 listener
->vOrientFront
.x
= 0.0f
;
360 listener
->vOrientFront
.y
= 0.0f
;
361 listener
->vOrientFront
.z
= 1.0f
;
362 listener
->vOrientTop
.x
= 0.0f
;
363 listener
->vOrientTop
.y
= 1.0f
;
364 listener
->vOrientTop
.z
= 0.0f
;
365 listener
->flDistanceFactor
= DS3D_DEFAULTDISTANCEFACTOR
;
366 listener
->flRolloffFactor
= DS3D_DEFAULTROLLOFFFACTOR
;
367 listener
->flDopplerFactor
= DS3D_DEFAULTDOPPLERFACTOR
;
369 num_srcs
= parent
->share
->max_sources
;
371 hr
= DSERR_OUTOFMEMORY
;
372 This
->notifies
= HeapAlloc(GetProcessHeap(), 0, num_srcs
*sizeof(*This
->notifies
));
373 if(!This
->notifies
) goto fail
;
374 This
->sizenotifies
= num_srcs
;
376 count
= (num_srcs
+63) / 64;
377 This
->BufferGroups
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
378 count
*sizeof(*This
->BufferGroups
));
379 if(!This
->BufferGroups
) goto fail
;
380 This
->NumBufferGroups
= count
;
382 /* Only flag usable buffers as free. */
384 for(i
= 0;i
< This
->NumBufferGroups
;++i
)
386 DWORD count_rem
= num_srcs
- count
;
389 This
->BufferGroups
[i
].FreeBuffers
= ~(DWORD64
)0;
394 This
->BufferGroups
[i
].FreeBuffers
= (U64(1) << count_rem
) - 1;
402 DS8Primary_Clear(This
);
406 void DS8Primary_Clear(DS8Primary
*This
)
408 struct DSBufferGroup
*bufgroup
;
411 TRACE("Clearing primary %p\n", This
);
416 setALContext(This
->ctx
);
418 This
->ExtAL
->DeleteEffects(1, &This
->effect
);
421 bufgroup
= This
->BufferGroups
;
422 for(i
= 0;i
< This
->NumBufferGroups
;++i
)
424 DWORD64 usemask
= ~bufgroup
[i
].FreeBuffers
;
427 int idx
= CTZ64(usemask
);
428 DS8Buffer
*buf
= bufgroup
[i
].Buffers
+ idx
;
429 usemask
&= ~(U64(1) << idx
);
431 DS8Buffer_Destroy(buf
);
435 HeapFree(GetProcessHeap(), 0, This
->BufferGroups
);
436 HeapFree(GetProcessHeap(), 0, This
->notifies
);
437 memset(This
, 0, sizeof(*This
));
440 static HRESULT WINAPI
DS8Primary_QueryInterface(IDirectSoundBuffer
*iface
, REFIID riid
, LPVOID
*ppv
)
442 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
444 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
447 if(IsEqualIID(riid
, &IID_IUnknown
) ||
448 IsEqualIID(riid
, &IID_IDirectSoundBuffer
))
449 *ppv
= &This
->IDirectSoundBuffer_iface
;
450 else if(IsEqualIID(riid
, &IID_IDirectSound3DListener
))
452 if((This
->flags
&DSBCAPS_CTRL3D
))
453 *ppv
= &This
->IDirectSound3DListener_iface
;
455 else if(IsEqualIID(riid
, &IID_IKsPropertySet
))
456 *ppv
= &This
->IKsPropertySet_iface
;
458 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid
));
462 IUnknown_AddRef((IUnknown
*)*ppv
);
466 return E_NOINTERFACE
;
469 static ULONG WINAPI
DS8Primary_AddRef(IDirectSoundBuffer
*iface
)
471 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
474 ret
= InterlockedIncrement(&This
->ref
);
475 if(ret
== 1) This
->flags
= 0;
480 static ULONG WINAPI
DS8Primary_Release(IDirectSoundBuffer
*iface
)
482 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
485 oldval
= *(volatile LONG
*)&This
->ref
;
489 oldval
= InterlockedCompareExchange(&This
->ref
, ref
-1, ref
);
490 } while(oldval
!= ref
);
495 static HRESULT WINAPI
DS8Primary_GetCaps(IDirectSoundBuffer
*iface
, DSBCAPS
*caps
)
497 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
499 TRACE("(%p)->(%p)\n", iface
, caps
);
501 if(!caps
|| caps
->dwSize
< sizeof(*caps
))
503 WARN("Invalid DSBCAPS (%p, %lu)\n", caps
, caps
? caps
->dwSize
: 0);
504 return DSERR_INVALIDPARAM
;
507 caps
->dwFlags
= This
->flags
;
508 caps
->dwBufferBytes
= This
->buf_size
;
509 caps
->dwUnlockTransferRate
= 0;
510 caps
->dwPlayCpuOverhead
= 0;
515 static HRESULT WINAPI
DS8Primary_GetCurrentPosition(IDirectSoundBuffer
*iface
, DWORD
*playpos
, DWORD
*curpos
)
517 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
518 HRESULT hr
= DSERR_PRIOLEVELNEEDED
;
520 EnterCriticalSection(This
->crst
);
522 hr
= IDirectSoundBuffer8_GetCurrentPosition(This
->write_emu
, playpos
, curpos
);
523 LeaveCriticalSection(This
->crst
);
528 static HRESULT WINAPI
DS8Primary_GetFormat(IDirectSoundBuffer
*iface
, WAVEFORMATEX
*wfx
, DWORD allocated
, DWORD
*written
)
530 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
536 WARN("Cannot report format or format size\n");
537 return DSERR_INVALIDPARAM
;
540 EnterCriticalSection(This
->crst
);
541 size
= sizeof(This
->format
.Format
) + This
->format
.Format
.cbSize
;
547 hr
= DSERR_INVALIDPARAM
;
549 memcpy(wfx
, &This
->format
.Format
, size
);
551 LeaveCriticalSection(This
->crst
);
556 static HRESULT WINAPI
DS8Primary_GetVolume(IDirectSoundBuffer
*iface
, LONG
*volume
)
558 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
561 TRACE("(%p)->(%p)\n", iface
, volume
);
564 return DSERR_INVALIDPARAM
;
567 if(!(This
->flags
&DSBCAPS_CTRLVOLUME
))
568 return DSERR_CONTROLUNAVAIL
;
570 setALContext(This
->ctx
);
571 alGetListenerf(AL_GAIN
, &gain
);
575 *volume
= clampI(gain_to_mB(gain
), DSBVOLUME_MIN
, DSBVOLUME_MAX
);
579 static HRESULT WINAPI
DS8Primary_GetPan(IDirectSoundBuffer
*iface
, LONG
*pan
)
581 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
584 WARN("(%p)->(%p): semi-stub\n", iface
, pan
);
587 return DSERR_INVALIDPARAM
;
589 EnterCriticalSection(This
->crst
);
591 hr
= IDirectSoundBuffer8_GetPan(This
->write_emu
, pan
);
592 else if(!(This
->flags
& DSBCAPS_CTRLPAN
))
593 hr
= DSERR_CONTROLUNAVAIL
;
596 LeaveCriticalSection(This
->crst
);
601 static HRESULT WINAPI
DS8Primary_GetFrequency(IDirectSoundBuffer
*iface
, DWORD
*freq
)
603 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
606 WARN("(%p)->(%p): semi-stub\n", iface
, freq
);
609 return DSERR_INVALIDPARAM
;
611 if(!(This
->flags
&DSBCAPS_CTRLFREQUENCY
))
612 return DSERR_CONTROLUNAVAIL
;
614 EnterCriticalSection(This
->crst
);
615 *freq
= This
->format
.Format
.nSamplesPerSec
;
616 LeaveCriticalSection(This
->crst
);
621 static HRESULT WINAPI
DS8Primary_GetStatus(IDirectSoundBuffer
*iface
, DWORD
*status
)
623 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
625 TRACE("(%p)->(%p)\n", iface
, status
);
628 return DSERR_INVALIDPARAM
;
630 EnterCriticalSection(This
->crst
);
631 *status
= DSBSTATUS_PLAYING
|DSBSTATUS_LOOPING
;
632 if((This
->flags
&DSBCAPS_LOCDEFER
))
633 *status
|= DSBSTATUS_LOCHARDWARE
;
637 struct DSBufferGroup
*bufgroup
= This
->BufferGroups
;
641 for(i
= 0;i
< This
->NumBufferGroups
;++i
)
643 DWORD64 usemask
= ~bufgroup
[i
].FreeBuffers
;
646 int idx
= CTZ64(usemask
);
647 DS8Buffer
*buf
= bufgroup
[i
].Buffers
+ idx
;
648 usemask
&= ~(U64(1) << idx
);
650 hr
= DS8Buffer_GetStatus(&buf
->IDirectSoundBuffer8_iface
, &state
);
651 if(SUCCEEDED(hr
) && (state
&DSBSTATUS_PLAYING
)) break;
654 if(!(state
&DSBSTATUS_PLAYING
))
656 /* Primary stopped and no buffers playing.. */
660 LeaveCriticalSection(This
->crst
);
665 HRESULT WINAPI
DS8Primary_Initialize(IDirectSoundBuffer
*iface
, IDirectSound
*ds
, const DSBUFFERDESC
*desc
)
667 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
670 TRACE("(%p)->(%p, %p)\n", iface
, ds
, desc
);
672 if(!desc
|| desc
->lpwfxFormat
|| desc
->dwBufferBytes
)
674 WARN("Bad DSBDESC for primary buffer\n");
675 return DSERR_INVALIDPARAM
;
677 if((desc
->dwFlags
&DSBCAPS_CTRLFX
) ||
678 (desc
->dwFlags
&DSBCAPS_CTRLPOSITIONNOTIFY
) ||
679 (desc
->dwFlags
&DSBCAPS_LOCSOFTWARE
))
681 WARN("Bad dwFlags %08lx\n", desc
->dwFlags
);
682 return DSERR_INVALIDPARAM
;
685 /* Should be 0 if not initialized */
687 return DSERR_ALREADYINITIALIZED
;
690 if(This
->parent
->prio_level
== DSSCL_WRITEPRIMARY
)
692 DSBUFFERDESC emudesc
;
697 ERR("There shouldn't be a write_emu!\n");
698 IDirectSoundBuffer8_Release(This
->write_emu
);
699 This
->write_emu
= NULL
;
702 memset(&emudesc
, 0, sizeof(emudesc
));
703 emudesc
.dwSize
= sizeof(emudesc
);
704 emudesc
.dwFlags
= DSBCAPS_LOCHARDWARE
| (desc
->dwFlags
&DSBCAPS_CTRLPAN
);
705 /* Dont play last incomplete sample */
706 emudesc
.dwBufferBytes
= This
->buf_size
- (This
->buf_size
%This
->format
.Format
.nBlockAlign
);
707 emudesc
.lpwfxFormat
= &This
->format
.Format
;
709 hr
= DS8Buffer_Create(&emu
, This
, NULL
, TRUE
);
712 This
->write_emu
= &emu
->IDirectSoundBuffer8_iface
;
713 hr
= DS8Buffer_Initialize(This
->write_emu
, ds
, &emudesc
);
716 IDirectSoundBuffer8_Release(This
->write_emu
);
717 This
->write_emu
= NULL
;
723 This
->flags
= desc
->dwFlags
| DSBCAPS_LOCHARDWARE
;
727 static HRESULT WINAPI
DS8Primary_Lock(IDirectSoundBuffer
*iface
, DWORD ofs
, DWORD bytes
, void **ptr1
, DWORD
*len1
, void **ptr2
, DWORD
*len2
, DWORD flags
)
729 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
730 HRESULT hr
= DSERR_PRIOLEVELNEEDED
;
732 TRACE("(%p)->(%lu, %lu, %p, %p, %p, %p, %lu)\n", iface
, ofs
, bytes
, ptr1
, len1
, ptr2
, len2
, flags
);
734 EnterCriticalSection(This
->crst
);
736 hr
= IDirectSoundBuffer8_Lock(This
->write_emu
, ofs
, bytes
, ptr1
, len1
, ptr2
, len2
, flags
);
737 LeaveCriticalSection(This
->crst
);
742 static HRESULT WINAPI
DS8Primary_Play(IDirectSoundBuffer
*iface
, DWORD res1
, DWORD res2
, DWORD flags
)
744 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
747 TRACE("(%p)->(%lu, %lu, %lu)\n", iface
, res1
, res2
, flags
);
749 if(!(flags
& DSBPLAY_LOOPING
))
751 WARN("Flags (%08lx) not set to DSBPLAY_LOOPING\n", flags
);
752 return DSERR_INVALIDPARAM
;
755 EnterCriticalSection(This
->crst
);
758 hr
= IDirectSoundBuffer8_Play(This
->write_emu
, res1
, res2
, flags
);
760 This
->stopped
= FALSE
;
761 LeaveCriticalSection(This
->crst
);
766 static HRESULT WINAPI
DS8Primary_SetCurrentPosition(IDirectSoundBuffer
*iface
, DWORD pos
)
768 WARN("(%p)->(%lu)\n", iface
, pos
);
769 return DSERR_INVALIDCALL
;
772 /* Just assume the format is crap, and clean up the damage */
773 static HRESULT
copy_waveformat(WAVEFORMATEX
*wfx
, const WAVEFORMATEX
*from
)
775 if(from
->nBlockAlign
<= 0 || from
->nChannels
<= 0)
776 return DSERR_INVALIDPARAM
;
777 if(from
->nSamplesPerSec
< DSBFREQUENCY_MIN
|| from
->nSamplesPerSec
> DSBFREQUENCY_MAX
)
778 return DSERR_INVALIDPARAM
;
779 if(from
->wBitsPerSample
== 0 || (from
->wBitsPerSample
%8) != 0)
780 return DSERR_INVALIDPARAM
;
781 if(from
->nBlockAlign
!= from
->nChannels
*from
->wBitsPerSample
/8)
782 return DSERR_INVALIDPARAM
;
783 if(from
->nAvgBytesPerSec
!= from
->nBlockAlign
*from
->nSamplesPerSec
)
784 return DSERR_INVALIDPARAM
;
786 if(from
->wFormatTag
== WAVE_FORMAT_PCM
)
788 if(from
->wBitsPerSample
> 32)
789 return DSERR_INVALIDPARAM
;
791 wfx
->wBitsPerSample
= from
->wBitsPerSample
;
793 else if(from
->wFormatTag
== WAVE_FORMAT_IEEE_FLOAT
)
795 if(from
->wBitsPerSample
!= 32)
796 return DSERR_INVALIDPARAM
;
798 wfx
->wBitsPerSample
= from
->wBitsPerSample
;
800 else if(from
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
802 WAVEFORMATEXTENSIBLE
*wfe
= (WAVEFORMATEXTENSIBLE
*)wfx
;
803 const WAVEFORMATEXTENSIBLE
*fromx
= (const WAVEFORMATEXTENSIBLE
*)from
;
804 const WORD size
= sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
);
806 /* Fail silently.. */
807 if(from
->cbSize
< size
) return DS_OK
;
808 if(fromx
->Samples
.wValidBitsPerSample
> fromx
->Format
.wBitsPerSample
)
809 return DSERR_INVALIDPARAM
;
811 if(IsEqualGUID(&wfe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
) ||
812 IsEqualGUID(&wfe
->SubFormat
, &GUID_NULL
))
814 if(from
->wBitsPerSample
> 32)
815 return DSERR_INVALIDPARAM
;
817 else if(IsEqualGUID(&wfe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
))
819 if(from
->wBitsPerSample
!= 32)
820 return DSERR_INVALIDPARAM
;
824 ERR("Unhandled extensible format: %s\n", debugstr_guid(&wfe
->SubFormat
));
825 return DSERR_INVALIDPARAM
;
828 wfe
->Format
.wBitsPerSample
= from
->wBitsPerSample
;
829 wfe
->Samples
.wValidBitsPerSample
= fromx
->Samples
.wValidBitsPerSample
;
830 if(!wfe
->Samples
.wValidBitsPerSample
)
831 wfe
->Samples
.wValidBitsPerSample
= wfe
->Format
.wBitsPerSample
;
832 wfe
->Format
.cbSize
= size
;
833 wfe
->dwChannelMask
= fromx
->dwChannelMask
;
834 wfe
->SubFormat
= fromx
->SubFormat
;
838 ERR("Unhandled format tag %04x\n", from
->wFormatTag
);
839 return DSERR_INVALIDPARAM
;
842 wfx
->nChannels
= from
->nChannels
;
843 wfx
->wFormatTag
= from
->wFormatTag
;
844 wfx
->nSamplesPerSec
= from
->nSamplesPerSec
;
845 wfx
->nBlockAlign
= wfx
->wBitsPerSample
* wfx
->nChannels
/ 8;
846 wfx
->nAvgBytesPerSec
= wfx
->nSamplesPerSec
* wfx
->nBlockAlign
;
850 static HRESULT WINAPI
DS8Primary_SetFormat(IDirectSoundBuffer
*iface
, const WAVEFORMATEX
*wfx
)
852 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
855 TRACE("(%p)->(%p)\n", iface
, wfx
);
859 WARN("Missing format\n");
860 return DSERR_INVALIDPARAM
;
863 EnterCriticalSection(This
->crst
);
865 if(This
->parent
->prio_level
< DSSCL_PRIORITY
)
867 hr
= DSERR_PRIOLEVELNEEDED
;
871 TRACE("Requested primary format:\n"
872 " FormatTag = %04x\n"
874 " SamplesPerSec = %lu\n"
875 " AvgBytesPerSec = %lu\n"
877 " BitsPerSample = %u\n",
878 wfx
->wFormatTag
, wfx
->nChannels
,
879 wfx
->nSamplesPerSec
, wfx
->nAvgBytesPerSec
,
880 wfx
->nBlockAlign
, wfx
->wBitsPerSample
);
882 hr
= copy_waveformat(&This
->format
.Format
, wfx
);
883 if(SUCCEEDED(hr
) && This
->write_emu
)
888 memset(&desc
, 0, sizeof(desc
));
889 desc
.dwSize
= sizeof(desc
);
890 desc
.dwFlags
= DSBCAPS_LOCHARDWARE
|DSBCAPS_CTRLPAN
;
891 desc
.dwBufferBytes
= This
->buf_size
- (This
->buf_size
% This
->format
.Format
.nBlockAlign
);
892 desc
.lpwfxFormat
= &This
->format
.Format
;
894 hr
= DS8Buffer_Create(&buf
, This
, NULL
, TRUE
);
895 if(FAILED(hr
)) goto out
;
897 hr
= DS8Buffer_Initialize(&buf
->IDirectSoundBuffer8_iface
, &This
->parent
->IDirectSound_iface
, &desc
);
899 DS8Buffer_Destroy(buf
);
902 IDirectSoundBuffer8_Release(This
->write_emu
);
903 This
->write_emu
= &buf
->IDirectSoundBuffer8_iface
;
908 LeaveCriticalSection(This
->crst
);
912 static HRESULT WINAPI
DS8Primary_SetVolume(IDirectSoundBuffer
*iface
, LONG vol
)
914 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
916 TRACE("(%p)->(%ld)\n", iface
, vol
);
918 if(vol
> DSBVOLUME_MAX
|| vol
< DSBVOLUME_MIN
)
920 WARN("Invalid volume (%ld)\n", vol
);
921 return DSERR_INVALIDPARAM
;
924 if(!(This
->flags
&DSBCAPS_CTRLVOLUME
))
925 return DSERR_CONTROLUNAVAIL
;
927 setALContext(This
->ctx
);
928 alListenerf(AL_GAIN
, mB_to_gain(vol
));
934 static HRESULT WINAPI
DS8Primary_SetPan(IDirectSoundBuffer
*iface
, LONG pan
)
936 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
939 TRACE("(%p)->(%ld)\n", iface
, pan
);
941 if(pan
> DSBPAN_RIGHT
|| pan
< DSBPAN_LEFT
)
943 WARN("invalid parameter: pan = %ld\n", pan
);
944 return DSERR_INVALIDPARAM
;
947 EnterCriticalSection(This
->crst
);
948 if(!(This
->flags
&DSBCAPS_CTRLPAN
))
950 WARN("control unavailable\n");
951 hr
= DSERR_CONTROLUNAVAIL
;
953 else if(This
->write_emu
)
954 hr
= IDirectSoundBuffer8_SetPan(This
->write_emu
, pan
);
957 FIXME("Not supported\n");
960 LeaveCriticalSection(This
->crst
);
965 static HRESULT WINAPI
DS8Primary_SetFrequency(IDirectSoundBuffer
*iface
, DWORD freq
)
967 WARN("(%p)->(%lu)\n", iface
, freq
);
968 return DSERR_CONTROLUNAVAIL
;
971 static HRESULT WINAPI
DS8Primary_Stop(IDirectSoundBuffer
*iface
)
973 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
976 TRACE("(%p)->()\n", iface
);
978 EnterCriticalSection(This
->crst
);
980 hr
= IDirectSoundBuffer8_Stop(This
->write_emu
);
982 This
->stopped
= TRUE
;
983 LeaveCriticalSection(This
->crst
);
988 static HRESULT WINAPI
DS8Primary_Unlock(IDirectSoundBuffer
*iface
, void *ptr1
, DWORD len1
, void *ptr2
, DWORD len2
)
990 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
991 HRESULT hr
= DSERR_INVALIDCALL
;
993 TRACE("(%p)->(%p, %lu, %p, %lu)\n", iface
, ptr1
, len1
, ptr2
, len2
);
995 EnterCriticalSection(This
->crst
);
997 hr
= IDirectSoundBuffer8_Unlock(This
->write_emu
, ptr1
, len1
, ptr2
, len2
);
998 LeaveCriticalSection(This
->crst
);
1003 static HRESULT WINAPI
DS8Primary_Restore(IDirectSoundBuffer
*iface
)
1005 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
1008 TRACE("(%p)->()\n", iface
);
1010 EnterCriticalSection(This
->crst
);
1012 hr
= IDirectSoundBuffer8_Restore(This
->write_emu
);
1013 LeaveCriticalSection(This
->crst
);
1018 static const IDirectSoundBufferVtbl DS8Primary_Vtbl
=
1020 DS8Primary_QueryInterface
,
1024 DS8Primary_GetCurrentPosition
,
1025 DS8Primary_GetFormat
,
1026 DS8Primary_GetVolume
,
1028 DS8Primary_GetFrequency
,
1029 DS8Primary_GetStatus
,
1030 DS8Primary_Initialize
,
1033 DS8Primary_SetCurrentPosition
,
1034 DS8Primary_SetFormat
,
1035 DS8Primary_SetVolume
,
1037 DS8Primary_SetFrequency
,
1044 static void DS8Primary_SetParams(DS8Primary
*This
, const DS3DLISTENER
*params
, LONG flags
)
1046 union PrimaryParamFlags dirty
= { flags
};
1050 alListener3f(AL_POSITION
, params
->vPosition
.x
, params
->vPosition
.y
,
1051 -params
->vPosition
.z
);
1053 alListener3f(AL_VELOCITY
, params
->vVelocity
.x
, params
->vVelocity
.y
,
1054 -params
->vVelocity
.z
);
1055 if(dirty
.bit
.orientation
)
1057 ALfloat orient
[6] = {
1058 params
->vOrientFront
.x
, params
->vOrientFront
.y
, -params
->vOrientFront
.z
,
1059 params
->vOrientTop
.x
, params
->vOrientTop
.y
, -params
->vOrientTop
.z
1061 alListenerfv(AL_ORIENTATION
, orient
);
1063 if(dirty
.bit
.distancefactor
)
1065 alSpeedOfSound(343.3f
/params
->flDistanceFactor
);
1066 if(This
->SupportedExt
[EXT_EFX
])
1067 alListenerf(AL_METERS_PER_UNIT
, params
->flDistanceFactor
);
1069 if(dirty
.bit
.rollofffactor
)
1071 struct DSBufferGroup
*bufgroup
= This
->BufferGroups
;
1072 ALfloat rolloff
= params
->flRolloffFactor
;
1073 This
->rollofffactor
= rolloff
;
1075 for(i
= 0;i
< This
->NumBufferGroups
;++i
)
1077 DWORD64 usemask
= ~bufgroup
[i
].FreeBuffers
;
1080 int idx
= CTZ64(usemask
);
1081 DS8Buffer
*buf
= bufgroup
[i
].Buffers
+ idx
;
1082 usemask
&= ~(U64(1) << idx
);
1084 if(buf
->ds3dmode
!= DS3DMODE_DISABLE
)
1085 alSourcef(buf
->source
, AL_ROLLOFF_FACTOR
, rolloff
);
1089 if(dirty
.bit
.dopplerfactor
)
1090 alDopplerFactor(params
->flDopplerFactor
);
1091 if(dirty
.bit
.effect
)
1092 This
->ExtAL
->AuxiliaryEffectSloti(This
->auxslot
, AL_EFFECTSLOT_EFFECT
, This
->effect
);
1095 static HRESULT WINAPI
DS8Primary3D_QueryInterface(IDirectSound3DListener
*iface
, REFIID riid
, void **ppv
)
1097 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1098 return DS8Primary_QueryInterface(&This
->IDirectSoundBuffer_iface
, riid
, ppv
);
1101 static ULONG WINAPI
DS8Primary3D_AddRef(IDirectSound3DListener
*iface
)
1103 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1106 ret
= InterlockedIncrement(&This
->ds3d_ref
);
1107 TRACE("new refcount %ld\n", ret
);
1112 static ULONG WINAPI
DS8Primary3D_Release(IDirectSound3DListener
*iface
)
1114 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1117 ret
= InterlockedDecrement(&This
->ds3d_ref
);
1118 TRACE("new refcount %ld\n", ret
);
1124 static HRESULT WINAPI
DS8Primary3D_GetDistanceFactor(IDirectSound3DListener
*iface
, D3DVALUE
*distancefactor
)
1126 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1128 TRACE("(%p)->(%p)\n", iface
, distancefactor
);
1132 WARN("Invalid parameter %p\n", distancefactor
);
1133 return DSERR_INVALIDPARAM
;
1136 setALContext(This
->ctx
);
1137 *distancefactor
= 343.3f
/alGetFloat(AL_SPEED_OF_SOUND
);
1144 static HRESULT WINAPI
DS8Primary3D_GetDopplerFactor(IDirectSound3DListener
*iface
, D3DVALUE
*dopplerfactor
)
1146 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1148 TRACE("(%p)->(%p)\n", iface
, dopplerfactor
);
1152 WARN("Invalid parameter %p\n", dopplerfactor
);
1153 return DSERR_INVALIDPARAM
;
1156 setALContext(This
->ctx
);
1157 *dopplerfactor
= alGetFloat(AL_DOPPLER_FACTOR
);
1164 static HRESULT WINAPI
DS8Primary3D_GetOrientation(IDirectSound3DListener
*iface
, D3DVECTOR
*front
, D3DVECTOR
*top
)
1166 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1169 TRACE("(%p)->(%p, %p)\n", iface
, front
, top
);
1173 WARN("Invalid parameter %p %p\n", front
, top
);
1174 return DSERR_INVALIDPARAM
;
1177 setALContext(This
->ctx
);
1178 alGetListenerfv(AL_ORIENTATION
, orient
);
1182 front
->x
= orient
[0];
1183 front
->y
= orient
[1];
1184 front
->z
= -orient
[2];
1187 top
->z
= -orient
[5];
1191 static HRESULT WINAPI
DS8Primary3D_GetPosition(IDirectSound3DListener
*iface
, D3DVECTOR
*pos
)
1193 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1196 TRACE("(%p)->(%p)\n", iface
, pos
);
1200 WARN("Invalid parameter %p\n", pos
);
1201 return DSERR_INVALIDPARAM
;
1204 setALContext(This
->ctx
);
1205 alGetListenerfv(AL_POSITION
, alpos
);
1215 static HRESULT WINAPI
DS8Primary3D_GetRolloffFactor(IDirectSound3DListener
*iface
, D3DVALUE
*rollofffactor
)
1217 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1219 TRACE("(%p)->(%p)\n", iface
, rollofffactor
);
1223 WARN("Invalid parameter %p\n", rollofffactor
);
1224 return DSERR_INVALIDPARAM
;
1227 EnterCriticalSection(This
->crst
);
1228 *rollofffactor
= This
->rollofffactor
;
1229 LeaveCriticalSection(This
->crst
);
1234 static HRESULT WINAPI
DS8Primary3D_GetVelocity(IDirectSound3DListener
*iface
, D3DVECTOR
*velocity
)
1236 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1239 TRACE("(%p)->(%p)\n", iface
, velocity
);
1243 WARN("Invalid parameter %p\n", velocity
);
1244 return DSERR_INVALIDPARAM
;
1247 setALContext(This
->ctx
);
1248 alGetListenerfv(AL_VELOCITY
, vel
);
1252 velocity
->x
= vel
[0];
1253 velocity
->y
= vel
[1];
1254 velocity
->z
= -vel
[2];
1258 static HRESULT WINAPI
DS8Primary3D_GetAllParameters(IDirectSound3DListener
*iface
, DS3DLISTENER
*listener
)
1260 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1262 TRACE("(%p)->(%p)\n", iface
, listener
);
1264 if(!listener
|| listener
->dwSize
< sizeof(*listener
))
1266 WARN("Invalid DS3DLISTENER %p %lu\n", listener
, listener
? listener
->dwSize
: 0);
1267 return DSERR_INVALIDPARAM
;
1270 EnterCriticalSection(This
->crst
);
1271 setALContext(This
->ctx
);
1272 DS8Primary3D_GetPosition(iface
, &listener
->vPosition
);
1273 DS8Primary3D_GetVelocity(iface
, &listener
->vVelocity
);
1274 DS8Primary3D_GetOrientation(iface
, &listener
->vOrientFront
, &listener
->vOrientTop
);
1275 DS8Primary3D_GetDistanceFactor(iface
, &listener
->flDistanceFactor
);
1276 DS8Primary3D_GetRolloffFactor(iface
, &listener
->flRolloffFactor
);
1277 DS8Primary3D_GetDopplerFactor(iface
, &listener
->flDopplerFactor
);
1279 LeaveCriticalSection(This
->crst
);
1285 static HRESULT WINAPI
DS8Primary3D_SetDistanceFactor(IDirectSound3DListener
*iface
, D3DVALUE factor
, DWORD apply
)
1287 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1289 TRACE("(%p)->(%f, %lu)\n", iface
, factor
, apply
);
1291 if(factor
< DS3D_MINDISTANCEFACTOR
||
1292 factor
> DS3D_MAXDISTANCEFACTOR
)
1294 WARN("Invalid parameter %f\n", factor
);
1295 return DSERR_INVALIDPARAM
;
1298 if(apply
== DS3D_DEFERRED
)
1300 EnterCriticalSection(This
->crst
);
1301 This
->params
.flDistanceFactor
= factor
;
1302 This
->dirty
.bit
.distancefactor
= 1;
1303 LeaveCriticalSection(This
->crst
);
1307 setALContext(This
->ctx
);
1308 alSpeedOfSound(343.3f
/factor
);
1309 if(This
->SupportedExt
[EXT_EFX
])
1310 alListenerf(AL_METERS_PER_UNIT
, factor
);
1318 static HRESULT WINAPI
DS8Primary3D_SetDopplerFactor(IDirectSound3DListener
*iface
, D3DVALUE factor
, DWORD apply
)
1320 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1322 TRACE("(%p)->(%f, %lu)\n", iface
, factor
, apply
);
1324 if(factor
< DS3D_MINDOPPLERFACTOR
||
1325 factor
> DS3D_MAXDOPPLERFACTOR
)
1327 WARN("Invalid parameter %f\n", factor
);
1328 return DSERR_INVALIDPARAM
;
1331 if(apply
== DS3D_DEFERRED
)
1333 EnterCriticalSection(This
->crst
);
1334 This
->params
.flDopplerFactor
= factor
;
1335 This
->dirty
.bit
.dopplerfactor
= 1;
1336 LeaveCriticalSection(This
->crst
);
1340 setALContext(This
->ctx
);
1341 alDopplerFactor(factor
);
1349 static HRESULT WINAPI
DS8Primary3D_SetOrientation(IDirectSound3DListener
*iface
, D3DVALUE xFront
, D3DVALUE yFront
, D3DVALUE zFront
, D3DVALUE xTop
, D3DVALUE yTop
, D3DVALUE zTop
, DWORD apply
)
1351 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1353 TRACE("(%p)->(%f, %f, %f, %f, %f, %f, %lu)\n", iface
, xFront
, yFront
, zFront
, xTop
, yTop
, zTop
, apply
);
1355 if(apply
== DS3D_DEFERRED
)
1357 EnterCriticalSection(This
->crst
);
1358 This
->params
.vOrientFront
.x
= xFront
;
1359 This
->params
.vOrientFront
.y
= yFront
;
1360 This
->params
.vOrientFront
.z
= zFront
;
1361 This
->params
.vOrientTop
.x
= xTop
;
1362 This
->params
.vOrientTop
.y
= yTop
;
1363 This
->params
.vOrientTop
.z
= zTop
;
1364 This
->dirty
.bit
.orientation
= 1;
1365 LeaveCriticalSection(This
->crst
);
1369 ALfloat orient
[6] = {
1370 xFront
, yFront
, -zFront
,
1373 setALContext(This
->ctx
);
1374 alListenerfv(AL_ORIENTATION
, orient
);
1382 static HRESULT WINAPI
DS8Primary3D_SetPosition(IDirectSound3DListener
*iface
, D3DVALUE x
, D3DVALUE y
, D3DVALUE z
, DWORD apply
)
1384 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1386 TRACE("(%p)->(%f, %f, %f, %lu)\n", iface
, x
, y
, z
, apply
);
1388 if(apply
== DS3D_DEFERRED
)
1390 EnterCriticalSection(This
->crst
);
1391 This
->params
.vPosition
.x
= x
;
1392 This
->params
.vPosition
.y
= y
;
1393 This
->params
.vPosition
.z
= z
;
1394 This
->dirty
.bit
.pos
= 1;
1395 LeaveCriticalSection(This
->crst
);
1399 setALContext(This
->ctx
);
1400 alListener3f(AL_POSITION
, x
, y
, -z
);
1408 static HRESULT WINAPI
DS8Primary3D_SetRolloffFactor(IDirectSound3DListener
*iface
, D3DVALUE factor
, DWORD apply
)
1410 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1412 TRACE("(%p)->(%f, %lu)\n", iface
, factor
, apply
);
1414 if(factor
< DS3D_MINROLLOFFFACTOR
||
1415 factor
> DS3D_MAXROLLOFFFACTOR
)
1417 WARN("Invalid parameter %f\n", factor
);
1418 return DSERR_INVALIDPARAM
;
1421 EnterCriticalSection(This
->crst
);
1422 if(apply
== DS3D_DEFERRED
)
1424 This
->params
.flRolloffFactor
= factor
;
1425 This
->dirty
.bit
.rollofffactor
= 1;
1429 struct DSBufferGroup
*bufgroup
= This
->BufferGroups
;
1432 setALContext(This
->ctx
);
1433 for(i
= 0;i
< This
->NumBufferGroups
;++i
)
1435 DWORD64 usemask
= ~bufgroup
[i
].FreeBuffers
;
1438 int idx
= CTZ64(usemask
);
1439 DS8Buffer
*buf
= bufgroup
[i
].Buffers
+ idx
;
1440 usemask
&= ~(U64(1) << idx
);
1442 if(buf
->ds3dmode
!= DS3DMODE_DISABLE
)
1443 alSourcef(buf
->source
, AL_ROLLOFF_FACTOR
, factor
);
1449 This
->rollofffactor
= factor
;
1451 LeaveCriticalSection(This
->crst
);
1456 static HRESULT WINAPI
DS8Primary3D_SetVelocity(IDirectSound3DListener
*iface
, D3DVALUE x
, D3DVALUE y
, D3DVALUE z
, DWORD apply
)
1458 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1460 TRACE("(%p)->(%f, %f, %f, %lu)\n", iface
, x
, y
, z
, apply
);
1462 if(apply
== DS3D_DEFERRED
)
1464 EnterCriticalSection(This
->crst
);
1465 This
->params
.vVelocity
.x
= x
;
1466 This
->params
.vVelocity
.y
= y
;
1467 This
->params
.vVelocity
.z
= z
;
1468 This
->dirty
.bit
.vel
= 1;
1469 LeaveCriticalSection(This
->crst
);
1473 setALContext(This
->ctx
);
1474 alListener3f(AL_VELOCITY
, x
, y
, -z
);
1482 static HRESULT WINAPI
DS8Primary3D_SetAllParameters(IDirectSound3DListener
*iface
, const DS3DLISTENER
*listen
, DWORD apply
)
1484 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1486 TRACE("(%p)->(%p, %lu)\n", iface
, listen
, apply
);
1488 if(!listen
|| listen
->dwSize
< sizeof(*listen
))
1490 WARN("Invalid parameter %p %lu\n", listen
, listen
? listen
->dwSize
: 0);
1491 return DSERR_INVALIDPARAM
;
1494 if(listen
->flDistanceFactor
> DS3D_MAXDISTANCEFACTOR
||
1495 listen
->flDistanceFactor
< DS3D_MINDISTANCEFACTOR
)
1497 WARN("Invalid distance factor (%f)\n", listen
->flDistanceFactor
);
1498 return DSERR_INVALIDPARAM
;
1501 if(listen
->flDopplerFactor
> DS3D_MAXDOPPLERFACTOR
||
1502 listen
->flDopplerFactor
< DS3D_MINDOPPLERFACTOR
)
1504 WARN("Invalid doppler factor (%f)\n", listen
->flDopplerFactor
);
1505 return DSERR_INVALIDPARAM
;
1508 if(listen
->flRolloffFactor
< DS3D_MINROLLOFFFACTOR
||
1509 listen
->flRolloffFactor
> DS3D_MAXROLLOFFFACTOR
)
1511 WARN("Invalid rolloff factor (%f)\n", listen
->flRolloffFactor
);
1512 return DSERR_INVALIDPARAM
;
1515 if(apply
== DS3D_DEFERRED
)
1517 EnterCriticalSection(This
->crst
);
1518 This
->params
= *listen
;
1519 This
->params
.dwSize
= sizeof(This
->params
);
1520 This
->dirty
.bit
.pos
= 1;
1521 This
->dirty
.bit
.vel
= 1;
1522 This
->dirty
.bit
.orientation
= 1;
1523 This
->dirty
.bit
.distancefactor
= 1;
1524 This
->dirty
.bit
.rollofffactor
= 1;
1525 This
->dirty
.bit
.dopplerfactor
= 1;
1526 LeaveCriticalSection(This
->crst
);
1530 union PrimaryParamFlags dirty
= { 0l };
1533 dirty
.bit
.orientation
= 1;
1534 dirty
.bit
.distancefactor
= 1;
1535 dirty
.bit
.rollofffactor
= 1;
1536 dirty
.bit
.dopplerfactor
= 1;
1538 EnterCriticalSection(This
->crst
);
1539 setALContext(This
->ctx
);
1540 DS8Primary_SetParams(This
, listen
, dirty
.flags
);
1543 LeaveCriticalSection(This
->crst
);
1549 HRESULT WINAPI
DS8Primary3D_CommitDeferredSettings(IDirectSound3DListener
*iface
)
1551 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1552 struct DSBufferGroup
*bufgroup
;
1556 EnterCriticalSection(This
->crst
);
1557 setALContext(This
->ctx
);
1558 This
->DeferUpdates();
1560 if((flags
=InterlockedExchange(&This
->dirty
.flags
, 0)) != 0)
1562 DS8Primary_SetParams(This
, &This
->params
, flags
);
1563 /* checkALError is here for debugging */
1566 TRACE("Dirty flags was: 0x%02lx\n", flags
);
1568 bufgroup
= This
->BufferGroups
;
1569 for(i
= 0;i
< This
->NumBufferGroups
;++i
)
1571 DWORD64 usemask
= ~bufgroup
[i
].FreeBuffers
;
1574 int idx
= CTZ64(usemask
);
1575 DS8Buffer
*buf
= bufgroup
[i
].Buffers
+ idx
;
1576 usemask
&= ~(U64(1) << idx
);
1578 if((flags
=InterlockedExchange(&buf
->dirty
.flags
, 0)) != 0)
1579 DS8Buffer_SetParams(buf
, &buf
->params
, flags
);
1584 This
->ProcessUpdates();
1586 LeaveCriticalSection(This
->crst
);
1591 static const IDirectSound3DListenerVtbl DS8Primary3D_Vtbl
=
1593 DS8Primary3D_QueryInterface
,
1594 DS8Primary3D_AddRef
,
1595 DS8Primary3D_Release
,
1596 DS8Primary3D_GetAllParameters
,
1597 DS8Primary3D_GetDistanceFactor
,
1598 DS8Primary3D_GetDopplerFactor
,
1599 DS8Primary3D_GetOrientation
,
1600 DS8Primary3D_GetPosition
,
1601 DS8Primary3D_GetRolloffFactor
,
1602 DS8Primary3D_GetVelocity
,
1603 DS8Primary3D_SetAllParameters
,
1604 DS8Primary3D_SetDistanceFactor
,
1605 DS8Primary3D_SetDopplerFactor
,
1606 DS8Primary3D_SetOrientation
,
1607 DS8Primary3D_SetPosition
,
1608 DS8Primary3D_SetRolloffFactor
,
1609 DS8Primary3D_SetVelocity
,
1610 DS8Primary3D_CommitDeferredSettings
1614 static HRESULT WINAPI
DS8PrimaryProp_QueryInterface(IKsPropertySet
*iface
, REFIID riid
, void **ppv
)
1616 DS8Primary
*This
= impl_from_IKsPropertySet(iface
);
1617 return DS8Primary_QueryInterface(&This
->IDirectSoundBuffer_iface
, riid
, ppv
);
1620 static ULONG WINAPI
DS8PrimaryProp_AddRef(IKsPropertySet
*iface
)
1622 DS8Primary
*This
= impl_from_IKsPropertySet(iface
);
1625 ret
= InterlockedIncrement(&This
->prop_ref
);
1626 TRACE("new refcount %ld\n", ret
);
1631 static ULONG WINAPI
DS8PrimaryProp_Release(IKsPropertySet
*iface
)
1633 DS8Primary
*This
= impl_from_IKsPropertySet(iface
);
1636 ret
= InterlockedDecrement(&This
->prop_ref
);
1637 TRACE("new refcount %ld\n", ret
);
1642 static HRESULT WINAPI
DS8PrimaryProp_Get(IKsPropertySet
*iface
,
1643 REFGUID guidPropSet
, ULONG dwPropID
,
1644 LPVOID pInstanceData
, ULONG cbInstanceData
,
1645 LPVOID pPropData
, ULONG cbPropData
,
1650 (void)pInstanceData
;
1651 (void)cbInstanceData
;
1656 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet
));
1658 return E_PROP_ID_UNSUPPORTED
;
1661 static HRESULT WINAPI
DS8PrimaryProp_Set(IKsPropertySet
*iface
,
1662 REFGUID guidPropSet
, ULONG dwPropID
,
1663 LPVOID pInstanceData
, ULONG cbInstanceData
,
1664 LPVOID pPropData
, ULONG cbPropData
)
1668 (void)pInstanceData
;
1669 (void)cbInstanceData
;
1673 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet
));
1675 return E_PROP_ID_UNSUPPORTED
;
1678 static HRESULT WINAPI
DS8PrimaryProp_QuerySupport(IKsPropertySet
*iface
,
1679 REFGUID guidPropSet
, ULONG dwPropID
,
1680 ULONG
*pTypeSupport
)
1686 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet
));
1688 return E_PROP_ID_UNSUPPORTED
;
1691 static const IKsPropertySetVtbl DS8PrimaryProp_Vtbl
=
1693 DS8PrimaryProp_QueryInterface
,
1694 DS8PrimaryProp_AddRef
,
1695 DS8PrimaryProp_Release
,
1698 DS8PrimaryProp_QuerySupport