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"
34 #ifndef E_PROP_ID_UNSUPPORTED
35 #define E_PROP_ID_UNSUPPORTED ((HRESULT)0x80070490)
39 static const IDirectSoundBufferVtbl DS8Primary_Vtbl
;
40 static const IDirectSound3DListenerVtbl DS8Primary3D_Vtbl
;
41 static const IKsPropertySetVtbl DS8PrimaryProp_Vtbl
;
43 static void DS8Primary_SetParams(DS8Primary
*This
, const DS3DLISTENER
*params
, LONG flags
);
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 trigger_elapsed_notifies(DS8Buffer
*buf
, DWORD lastpos
, DWORD curpos
)
64 DSBPOSITIONNOTIFY
*not = buf
->notify
;
65 DSBPOSITIONNOTIFY
*not_end
= not + buf
->nnotify
;
66 for(;not != not_end
;++not)
68 HANDLE event
= not->hEventNotify
;
69 DWORD ofs
= not->dwOffset
;
71 if(ofs
== (DWORD
)DSBPN_OFFSETSTOP
)
74 if(curpos
< lastpos
) /* Wraparound case */
76 if(ofs
< curpos
|| ofs
>= lastpos
)
78 TRACE("Triggering notification %d from buffer %p\n", not - buf
->notify
, buf
);
82 else if(ofs
>= lastpos
&& ofs
< curpos
) /* Normal case */
84 TRACE("Triggering notification %d from buffer %p\n", not - buf
->notify
, buf
);
90 static void trigger_stop_notifies(DS8Buffer
*buf
)
92 DSBPOSITIONNOTIFY
*not = buf
->notify
;
93 DSBPOSITIONNOTIFY
*not_end
= not + buf
->nnotify
;
94 for(;not != not_end
;++not)
96 if(not->dwOffset
!= (DWORD
)DSBPN_OFFSETSTOP
)
98 TRACE("Triggering notification %d from buffer %p\n", not - buf
->notify
, buf
);
99 SetEvent(not->hEventNotify
);
103 void DS8Primary_triggernots(DS8Primary
*prim
)
105 DS8Buffer
**curnot
, **endnot
;
107 curnot
= prim
->notifies
;
108 endnot
= curnot
+ prim
->nnotifies
;
109 while(curnot
!= endnot
)
111 DS8Buffer
*buf
= *curnot
;
112 DS8Data
*data
= buf
->buffer
;
113 DWORD curpos
= buf
->lastpos
;
117 alGetSourcei(buf
->source
, AL_BYTE_OFFSET
, &ofs
);
118 alGetSourcei(buf
->source
, AL_SOURCE_STATE
, &state
);
119 if(buf
->segsize
== 0)
120 curpos
= (state
== AL_STOPPED
) ? data
->buf_size
: ofs
;
123 if(state
!= AL_STOPPED
)
124 curpos
= ofs
+ buf
->queue_base
;
128 alGetSourcei(buf
->source
, AL_BUFFERS_QUEUED
, &queued
);
129 curpos
= buf
->segsize
*queued
+ buf
->queue_base
;
132 if(curpos
>= (DWORD
)data
->buf_size
)
135 curpos
%= (DWORD
)data
->buf_size
;
136 else if(buf
->isplaying
)
138 curpos
= data
->buf_size
;
139 alSourceStop(buf
->source
);
140 alSourcei(buf
->source
, AL_BUFFER
, 0);
142 buf
->isplaying
= FALSE
;
146 if(state
!= AL_PLAYING
)
147 state
= buf
->isplaying
? AL_PLAYING
: AL_PAUSED
;
151 if(buf
->lastpos
!= curpos
)
153 trigger_elapsed_notifies(buf
, buf
->lastpos
, curpos
);
154 buf
->lastpos
= curpos
;
156 if(state
!= AL_PLAYING
)
158 /* Remove this buffer from list and put another at the current
159 * position; don't increment i
161 trigger_stop_notifies(buf
);
162 *curnot
= *(--endnot
);
171 static void do_buffer_stream(DS8Buffer
*buf
, BYTE
*scratch_mem
)
173 DS8Data
*data
= buf
->buffer
;
174 ALint ofs
, done
= 0, queued
= QBUFFERS
, state
= AL_PLAYING
;
177 alGetSourcei(buf
->source
, AL_BUFFERS_QUEUED
, &queued
);
178 alGetSourcei(buf
->source
, AL_SOURCE_STATE
, &state
);
179 alGetSourcei(buf
->source
, AL_BUFFERS_PROCESSED
, &done
);
183 ALuint bids
[QBUFFERS
];
186 alSourceUnqueueBuffers(buf
->source
, done
, bids
);
187 buf
->queue_base
= (buf
->queue_base
+ buf
->segsize
*done
) % data
->buf_size
;
189 while(queued
< QBUFFERS
)
191 which
= buf
->stream_bids
[buf
->curidx
];
192 ofs
= buf
->data_offset
;
194 if(buf
->segsize
< data
->buf_size
- ofs
)
196 alBufferData(which
, data
->buf_format
, data
->data
+ ofs
, buf
->segsize
,
197 data
->format
.Format
.nSamplesPerSec
);
198 buf
->data_offset
= ofs
+ buf
->segsize
;
200 else if(buf
->islooping
)
202 ALsizei rem
= data
->buf_size
- ofs
;
203 if(rem
> 2048) rem
= 2048;
205 memcpy(scratch_mem
, data
->data
+ ofs
, rem
);
206 while(rem
< buf
->segsize
)
208 ALsizei todo
= buf
->segsize
- rem
;
209 if(todo
> data
->buf_size
)
210 todo
= data
->buf_size
;
211 memcpy(scratch_mem
+ rem
, data
->data
, todo
);
214 alBufferData(which
, data
->buf_format
, scratch_mem
, buf
->segsize
,
215 data
->format
.Format
.nSamplesPerSec
);
216 buf
->data_offset
= (ofs
+buf
->segsize
) % data
->buf_size
;
220 ALsizei rem
= data
->buf_size
- ofs
;
221 if(rem
> 2048) rem
= 2048;
224 memcpy(scratch_mem
, data
->data
+ ofs
, rem
);
225 memset(scratch_mem
+rem
, (data
->format
.Format
.wBitsPerSample
==8) ? 128 : 0,
227 alBufferData(which
, data
->buf_format
, scratch_mem
, buf
->segsize
,
228 data
->format
.Format
.nSamplesPerSec
);
229 buf
->data_offset
= data
->buf_size
;
232 alSourceQueueBuffers(buf
->source
, 1, &which
);
233 buf
->curidx
= (buf
->curidx
+1)%QBUFFERS
;
239 buf
->data_offset
= 0;
240 buf
->queue_base
= data
->buf_size
;
242 buf
->isplaying
= FALSE
;
244 else if(state
!= AL_PLAYING
)
245 alSourcePlay(buf
->source
);
248 void DS8Primary_streamfeeder(DS8Primary
*prim
, BYTE
*scratch_mem
)
250 /* OpenAL doesn't support our lovely buffer extensions so just make sure
251 * enough buffers are queued for streaming
255 DS8Buffer
*buf
= &prim
->writable_buf
;
256 if(buf
->segsize
!= 0 && buf
->isplaying
)
257 do_buffer_stream(buf
, scratch_mem
);
261 struct DSBufferGroup
*bufgroup
= prim
->BufferGroups
;
262 struct DSBufferGroup
*endgroup
= bufgroup
+ prim
->NumBufferGroups
;
263 for(;bufgroup
!= endgroup
;++bufgroup
)
265 DWORD64 usemask
= ~bufgroup
->FreeBuffers
;
268 int idx
= CTZ64(usemask
);
269 DS8Buffer
*buf
= bufgroup
->Buffers
+ idx
;
270 usemask
&= ~(U64(1) << idx
);
272 if(buf
->segsize
!= 0 && buf
->isplaying
)
273 do_buffer_stream(buf
, scratch_mem
);
281 HRESULT
DS8Primary_PreInit(DS8Primary
*This
, DS8Impl
*parent
)
289 This
->IDirectSoundBuffer_iface
.lpVtbl
= &DS8Primary_Vtbl
;
290 This
->IDirectSound3DListener_iface
.lpVtbl
= &DS8Primary3D_Vtbl
;
291 This
->IKsPropertySet_iface
.lpVtbl
= &DS8PrimaryProp_Vtbl
;
293 This
->parent
= parent
;
294 This
->share
= parent
->share
;
295 This
->ctx
= parent
->share
->ctx
;
296 This
->refresh
= parent
->share
->refresh
;
297 This
->auxslot
= parent
->share
->auxslot
;
299 wfx
= &This
->format
.Format
;
300 wfx
->wFormatTag
= WAVE_FORMAT_PCM
;
302 wfx
->wBitsPerSample
= 8;
303 wfx
->nSamplesPerSec
= 22050;
304 wfx
->nBlockAlign
= wfx
->wBitsPerSample
* wfx
->nChannels
/ 8;
305 wfx
->nAvgBytesPerSec
= wfx
->nSamplesPerSec
* wfx
->nBlockAlign
;
308 This
->stopped
= TRUE
;
310 /* Apparently primary buffer size is always 32k,
311 * tested on windows with 192k 24 bits sound @ 6 channels
312 * where it will run out in 60 ms and it isn't pointer aligned
314 This
->buf_size
= 32768;
316 setALContext(This
->ctx
);
317 This
->deferred
.eax
= EnvironmentDefaults
[EAX_ENVIRONMENT_GENERIC
];
318 This
->deferred
.eax1_volume
= 0.5f
;
319 This
->deferred
.eax1_dampening
= 0.5f
;
320 if(This
->auxslot
!= 0)
322 ALint revid
= alGetEnumValue("AL_EFFECT_REVERB");
323 if(revid
!= 0 && revid
!= -1)
325 alGenEffects(1, &This
->effect
);
326 alEffecti(This
->effect
, AL_EFFECT_TYPE
, AL_EFFECT_REVERB
);
332 num_srcs
= This
->share
->sources
.max_alloc
;
334 hr
= DSERR_OUTOFMEMORY
;
335 This
->notifies
= HeapAlloc(GetProcessHeap(), 0, num_srcs
*sizeof(*This
->notifies
));
336 if(!This
->notifies
) goto fail
;
337 This
->sizenotifies
= num_srcs
;
339 count
= (num_srcs
+63) / 64;
340 This
->BufferGroups
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
341 count
*sizeof(*This
->BufferGroups
));
342 if(!This
->BufferGroups
) goto fail
;
344 for(i
= 0;i
< count
;++i
)
346 This
->BufferGroups
[i
].Buffers
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
347 64*sizeof(This
->BufferGroups
[0].Buffers
[0]));
348 if(!This
->BufferGroups
[i
].Buffers
)
351 HeapFree(GetProcessHeap(), 0, This
->BufferGroups
[--i
].Buffers
);
352 HeapFree(GetProcessHeap(), 0, This
->BufferGroups
);
353 This
->BufferGroups
= NULL
;
356 This
->BufferGroups
[i
].FreeBuffers
= ~(DWORD64
)0;
358 This
->NumBufferGroups
= count
;
363 DS8Primary_Clear(This
);
367 void DS8Primary_Clear(DS8Primary
*This
)
369 struct DSBufferGroup
*bufgroup
;
372 TRACE("Clearing primary %p\n", This
);
377 setALContext(This
->ctx
);
379 alDeleteEffects(1, &This
->effect
);
382 bufgroup
= This
->BufferGroups
;
383 for(i
= 0;i
< This
->NumBufferGroups
;++i
)
385 DWORD64 usemask
= ~bufgroup
[i
].FreeBuffers
;
388 int idx
= CTZ64(usemask
);
389 DS8Buffer
*buf
= bufgroup
[i
].Buffers
+ idx
;
390 usemask
&= ~(U64(1) << idx
);
392 DS8Buffer_Destroy(buf
);
394 HeapFree(GetProcessHeap(), 0, This
->BufferGroups
[i
].Buffers
);
397 HeapFree(GetProcessHeap(), 0, This
->BufferGroups
);
398 HeapFree(GetProcessHeap(), 0, This
->notifies
);
399 memset(This
, 0, sizeof(*This
));
402 static HRESULT WINAPI
DS8Primary_QueryInterface(IDirectSoundBuffer
*iface
, REFIID riid
, LPVOID
*ppv
)
404 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
406 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
409 if(IsEqualIID(riid
, &IID_IUnknown
) ||
410 IsEqualIID(riid
, &IID_IDirectSoundBuffer
))
411 *ppv
= &This
->IDirectSoundBuffer_iface
;
412 else if(IsEqualIID(riid
, &IID_IDirectSound3DListener
))
414 if((This
->flags
&DSBCAPS_CTRL3D
))
415 *ppv
= &This
->IDirectSound3DListener_iface
;
417 else if(IsEqualIID(riid
, &IID_IKsPropertySet
))
418 *ppv
= &This
->IKsPropertySet_iface
;
420 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid
));
424 IUnknown_AddRef((IUnknown
*)*ppv
);
428 return E_NOINTERFACE
;
431 static ULONG WINAPI
DS8Primary_AddRef(IDirectSoundBuffer
*iface
)
433 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
436 ret
= InterlockedIncrement(&This
->ref
);
437 if(ret
== 1) This
->flags
= 0;
442 static ULONG WINAPI
DS8Primary_Release(IDirectSoundBuffer
*iface
)
444 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
447 oldval
= *(volatile LONG
*)&This
->ref
;
451 oldval
= InterlockedCompareExchange(&This
->ref
, ref
-1, ref
);
452 } while(oldval
!= ref
);
457 static HRESULT WINAPI
DS8Primary_GetCaps(IDirectSoundBuffer
*iface
, DSBCAPS
*caps
)
459 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
461 TRACE("(%p)->(%p)\n", iface
, caps
);
463 if(!caps
|| caps
->dwSize
< sizeof(*caps
))
465 WARN("Invalid DSBCAPS (%p, %lu)\n", caps
, caps
? caps
->dwSize
: 0);
466 return DSERR_INVALIDPARAM
;
469 caps
->dwFlags
= This
->flags
;
470 caps
->dwBufferBytes
= This
->buf_size
;
471 caps
->dwUnlockTransferRate
= 0;
472 caps
->dwPlayCpuOverhead
= 0;
477 static HRESULT WINAPI
DS8Primary_GetCurrentPosition(IDirectSoundBuffer
*iface
, DWORD
*playpos
, DWORD
*curpos
)
479 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
480 HRESULT hr
= DSERR_PRIOLEVELNEEDED
;
482 EnterCriticalSection(&This
->share
->crst
);
484 hr
= IDirectSoundBuffer8_GetCurrentPosition(This
->write_emu
, playpos
, curpos
);
485 LeaveCriticalSection(&This
->share
->crst
);
490 static HRESULT WINAPI
DS8Primary_GetFormat(IDirectSoundBuffer
*iface
, WAVEFORMATEX
*wfx
, DWORD allocated
, DWORD
*written
)
492 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
498 WARN("Cannot report format or format size\n");
499 return DSERR_INVALIDPARAM
;
502 EnterCriticalSection(&This
->share
->crst
);
503 size
= sizeof(This
->format
.Format
) + This
->format
.Format
.cbSize
;
509 hr
= DSERR_INVALIDPARAM
;
511 memcpy(wfx
, &This
->format
.Format
, size
);
513 LeaveCriticalSection(&This
->share
->crst
);
518 static HRESULT WINAPI
DS8Primary_GetVolume(IDirectSoundBuffer
*iface
, LONG
*volume
)
520 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
523 TRACE("(%p)->(%p)\n", iface
, volume
);
526 return DSERR_INVALIDPARAM
;
529 if(!(This
->flags
&DSBCAPS_CTRLVOLUME
))
530 return DSERR_CONTROLUNAVAIL
;
532 setALContext(This
->ctx
);
533 alGetListenerf(AL_GAIN
, &gain
);
537 *volume
= clampI(gain_to_mB(gain
), DSBVOLUME_MIN
, DSBVOLUME_MAX
);
541 static HRESULT WINAPI
DS8Primary_GetPan(IDirectSoundBuffer
*iface
, LONG
*pan
)
543 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
546 WARN("(%p)->(%p): semi-stub\n", iface
, pan
);
549 return DSERR_INVALIDPARAM
;
551 EnterCriticalSection(&This
->share
->crst
);
553 hr
= IDirectSoundBuffer8_GetPan(This
->write_emu
, pan
);
554 else if(!(This
->flags
& DSBCAPS_CTRLPAN
))
555 hr
= DSERR_CONTROLUNAVAIL
;
558 LeaveCriticalSection(&This
->share
->crst
);
563 static HRESULT WINAPI
DS8Primary_GetFrequency(IDirectSoundBuffer
*iface
, DWORD
*freq
)
565 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
568 WARN("(%p)->(%p): semi-stub\n", iface
, freq
);
571 return DSERR_INVALIDPARAM
;
573 if(!(This
->flags
&DSBCAPS_CTRLFREQUENCY
))
574 return DSERR_CONTROLUNAVAIL
;
576 EnterCriticalSection(&This
->share
->crst
);
577 *freq
= This
->format
.Format
.nSamplesPerSec
;
578 LeaveCriticalSection(&This
->share
->crst
);
583 static HRESULT WINAPI
DS8Primary_GetStatus(IDirectSoundBuffer
*iface
, DWORD
*status
)
585 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
587 TRACE("(%p)->(%p)\n", iface
, status
);
590 return DSERR_INVALIDPARAM
;
592 EnterCriticalSection(&This
->share
->crst
);
593 *status
= DSBSTATUS_PLAYING
|DSBSTATUS_LOOPING
;
594 if((This
->flags
&DSBCAPS_LOCDEFER
))
595 *status
|= DSBSTATUS_LOCHARDWARE
;
599 struct DSBufferGroup
*bufgroup
= This
->BufferGroups
;
603 for(i
= 0;i
< This
->NumBufferGroups
;++i
)
605 DWORD64 usemask
= ~bufgroup
[i
].FreeBuffers
;
608 int idx
= CTZ64(usemask
);
609 DS8Buffer
*buf
= bufgroup
[i
].Buffers
+ idx
;
610 usemask
&= ~(U64(1) << idx
);
612 hr
= DS8Buffer_GetStatus(&buf
->IDirectSoundBuffer8_iface
, &state
);
613 if(SUCCEEDED(hr
) && (state
&DSBSTATUS_PLAYING
)) break;
616 if(!(state
&DSBSTATUS_PLAYING
))
618 /* Primary stopped and no buffers playing.. */
622 LeaveCriticalSection(&This
->share
->crst
);
627 HRESULT WINAPI
DS8Primary_Initialize(IDirectSoundBuffer
*iface
, IDirectSound
*ds
, const DSBUFFERDESC
*desc
)
629 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
632 TRACE("(%p)->(%p, %p)\n", iface
, ds
, desc
);
634 if(!desc
|| desc
->lpwfxFormat
|| desc
->dwBufferBytes
)
636 WARN("Bad DSBDESC for primary buffer\n");
637 return DSERR_INVALIDPARAM
;
639 if((desc
->dwFlags
&DSBCAPS_CTRLFX
) ||
640 (desc
->dwFlags
&DSBCAPS_CTRLPOSITIONNOTIFY
) ||
641 (desc
->dwFlags
&DSBCAPS_LOCSOFTWARE
))
643 WARN("Bad dwFlags %08lx\n", desc
->dwFlags
);
644 return DSERR_INVALIDPARAM
;
647 /* Should be 0 if not initialized */
649 return DSERR_ALREADYINITIALIZED
;
652 if(This
->parent
->prio_level
== DSSCL_WRITEPRIMARY
)
654 DSBUFFERDESC emudesc
;
659 ERR("There shouldn't be a write_emu!\n");
660 IDirectSoundBuffer8_Release(This
->write_emu
);
661 This
->write_emu
= NULL
;
664 memset(&emudesc
, 0, sizeof(emudesc
));
665 emudesc
.dwSize
= sizeof(emudesc
);
666 emudesc
.dwFlags
= DSBCAPS_LOCHARDWARE
| (desc
->dwFlags
&DSBCAPS_CTRLPAN
);
667 /* Dont play last incomplete sample */
668 emudesc
.dwBufferBytes
= This
->buf_size
- (This
->buf_size
%This
->format
.Format
.nBlockAlign
);
669 emudesc
.lpwfxFormat
= &This
->format
.Format
;
671 hr
= DS8Buffer_Create(&emu
, This
, NULL
, TRUE
);
674 This
->write_emu
= &emu
->IDirectSoundBuffer8_iface
;
675 hr
= DS8Buffer_Initialize(This
->write_emu
, ds
, &emudesc
);
678 IDirectSoundBuffer8_Release(This
->write_emu
);
679 This
->write_emu
= NULL
;
686 DS3DLISTENER
*listener
= &This
->deferred
.ds3d
;
687 listener
->dwSize
= sizeof(This
->deferred
.ds3d
);
688 listener
->vPosition
.x
= 0.0f
;
689 listener
->vPosition
.y
= 0.0f
;
690 listener
->vPosition
.z
= 0.0f
;
691 listener
->vVelocity
.x
= 0.0f
;
692 listener
->vVelocity
.y
= 0.0f
;
693 listener
->vVelocity
.z
= 0.0f
;
694 listener
->vOrientFront
.x
= 0.0f
;
695 listener
->vOrientFront
.y
= 0.0f
;
696 listener
->vOrientFront
.z
= 1.0f
;
697 listener
->vOrientTop
.x
= 0.0f
;
698 listener
->vOrientTop
.y
= 1.0f
;
699 listener
->vOrientTop
.z
= 0.0f
;
700 listener
->flDistanceFactor
= DS3D_DEFAULTDISTANCEFACTOR
;
701 listener
->flRolloffFactor
= DS3D_DEFAULTROLLOFFFACTOR
;
702 listener
->flDopplerFactor
= DS3D_DEFAULTDOPPLERFACTOR
;
704 This
->flags
= desc
->dwFlags
| DSBCAPS_LOCHARDWARE
;
706 if((This
->flags
&DSBCAPS_CTRL3D
))
708 union PrimaryParamFlags dirty
= { 0l };
712 dirty
.bit
.orientation
= 1;
713 dirty
.bit
.distancefactor
= 1;
714 dirty
.bit
.rollofffactor
= 1;
715 dirty
.bit
.dopplerfactor
= 1;
716 DS8Primary_SetParams(This
, listener
, dirty
.flags
);
722 static HRESULT WINAPI
DS8Primary_Lock(IDirectSoundBuffer
*iface
, DWORD ofs
, DWORD bytes
, void **ptr1
, DWORD
*len1
, void **ptr2
, DWORD
*len2
, DWORD flags
)
724 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
725 HRESULT hr
= DSERR_PRIOLEVELNEEDED
;
727 TRACE("(%p)->(%lu, %lu, %p, %p, %p, %p, %lu)\n", iface
, ofs
, bytes
, ptr1
, len1
, ptr2
, len2
, flags
);
729 EnterCriticalSection(&This
->share
->crst
);
731 hr
= IDirectSoundBuffer8_Lock(This
->write_emu
, ofs
, bytes
, ptr1
, len1
, ptr2
, len2
, flags
);
732 LeaveCriticalSection(&This
->share
->crst
);
737 static HRESULT WINAPI
DS8Primary_Play(IDirectSoundBuffer
*iface
, DWORD res1
, DWORD res2
, DWORD flags
)
739 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
742 TRACE("(%p)->(%lu, %lu, %lu)\n", iface
, res1
, res2
, flags
);
744 if(!(flags
& DSBPLAY_LOOPING
))
746 WARN("Flags (%08lx) not set to DSBPLAY_LOOPING\n", flags
);
747 return DSERR_INVALIDPARAM
;
750 EnterCriticalSection(&This
->share
->crst
);
753 hr
= IDirectSoundBuffer8_Play(This
->write_emu
, res1
, res2
, flags
);
755 This
->stopped
= FALSE
;
756 LeaveCriticalSection(&This
->share
->crst
);
761 static HRESULT WINAPI
DS8Primary_SetCurrentPosition(IDirectSoundBuffer
*iface
, DWORD pos
)
763 WARN("(%p)->(%lu)\n", iface
, pos
);
764 return DSERR_INVALIDCALL
;
767 /* Just assume the format is crap, and clean up the damage */
768 static HRESULT
copy_waveformat(WAVEFORMATEX
*wfx
, const WAVEFORMATEX
*from
)
770 if(from
->nChannels
<= 0)
772 WARN("Invalid Channels %d\n", from
->nChannels
);
773 return DSERR_INVALIDPARAM
;
775 if(from
->nSamplesPerSec
< DSBFREQUENCY_MIN
|| from
->nSamplesPerSec
> DSBFREQUENCY_MAX
)
777 WARN("Invalid SamplesPerSec %lu\n", from
->nSamplesPerSec
);
778 return DSERR_INVALIDPARAM
;
780 if(from
->nBlockAlign
<= 0)
782 WARN("Invalid BlockAlign %d\n", from
->nBlockAlign
);
783 return DSERR_INVALIDPARAM
;
785 if(from
->wBitsPerSample
== 0 || (from
->wBitsPerSample
%8) != 0)
787 WARN("Invalid BitsPerSample %d\n", from
->wBitsPerSample
);
788 return DSERR_INVALIDPARAM
;
790 if(from
->nBlockAlign
!= from
->nChannels
*from
->wBitsPerSample
/8)
792 WARN("Invalid BlockAlign %d (expected %u = %u*%u/8)\n",
793 from
->nBlockAlign
, from
->nChannels
*from
->wBitsPerSample
/8,
794 from
->nChannels
, from
->wBitsPerSample
);
795 return DSERR_INVALIDPARAM
;
797 if(from
->nAvgBytesPerSec
!= from
->nBlockAlign
*from
->nSamplesPerSec
)
799 WARN("Invalid AvgBytesPerSec %lu (expected %lu = %lu*%u)\n",
800 from
->nAvgBytesPerSec
, from
->nSamplesPerSec
*from
->nBlockAlign
,
801 from
->nSamplesPerSec
, from
->nBlockAlign
);
802 return DSERR_INVALIDPARAM
;
805 if(from
->wFormatTag
== WAVE_FORMAT_PCM
)
807 if(from
->wBitsPerSample
> 32)
808 return DSERR_INVALIDPARAM
;
811 else if(from
->wFormatTag
== WAVE_FORMAT_IEEE_FLOAT
)
813 if(from
->wBitsPerSample
!= 32)
814 return DSERR_INVALIDPARAM
;
817 else if(from
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
819 WAVEFORMATEXTENSIBLE
*wfe
= (WAVEFORMATEXTENSIBLE
*)wfx
;
820 const WAVEFORMATEXTENSIBLE
*fromx
= (const WAVEFORMATEXTENSIBLE
*)from
;
821 const WORD size
= sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
);
823 /* Fail silently.. */
824 if(from
->cbSize
< size
) return DS_OK
;
825 if(fromx
->Samples
.wValidBitsPerSample
> fromx
->Format
.wBitsPerSample
)
826 return DSERR_INVALIDPARAM
;
828 if(IsEqualGUID(&fromx
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
))
830 if(from
->wBitsPerSample
> 32)
831 return DSERR_INVALIDPARAM
;
833 else if(IsEqualGUID(&fromx
->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
))
835 if(from
->wBitsPerSample
!= 32)
836 return DSERR_INVALIDPARAM
;
840 ERR("Unhandled extensible format: %s\n", debugstr_guid(&fromx
->SubFormat
));
841 return DSERR_INVALIDPARAM
;
844 wfe
->Format
.cbSize
= size
;
845 wfe
->Samples
.wValidBitsPerSample
= fromx
->Samples
.wValidBitsPerSample
;
846 if(!wfe
->Samples
.wValidBitsPerSample
)
847 wfe
->Samples
.wValidBitsPerSample
= fromx
->Format
.wBitsPerSample
;
848 wfe
->dwChannelMask
= fromx
->dwChannelMask
;
849 wfe
->SubFormat
= fromx
->SubFormat
;
853 ERR("Unhandled format tag %04x\n", from
->wFormatTag
);
854 return DSERR_INVALIDPARAM
;
857 wfx
->wFormatTag
= from
->wFormatTag
;
858 wfx
->nChannels
= from
->nChannels
;
859 wfx
->nSamplesPerSec
= from
->nSamplesPerSec
;
860 wfx
->nAvgBytesPerSec
= from
->nSamplesPerSec
* from
->nBlockAlign
;
861 wfx
->nBlockAlign
= from
->wBitsPerSample
* from
->nChannels
/ 8;
862 wfx
->wBitsPerSample
= from
->wBitsPerSample
;
866 static HRESULT WINAPI
DS8Primary_SetFormat(IDirectSoundBuffer
*iface
, const WAVEFORMATEX
*wfx
)
868 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
871 TRACE("(%p)->(%p)\n", iface
, wfx
);
875 WARN("Missing format\n");
876 return DSERR_INVALIDPARAM
;
879 EnterCriticalSection(&This
->share
->crst
);
881 if(This
->parent
->prio_level
< DSSCL_PRIORITY
)
883 hr
= DSERR_PRIOLEVELNEEDED
;
887 TRACE("Requested primary format:\n"
888 " FormatTag = %04x\n"
890 " SamplesPerSec = %lu\n"
891 " AvgBytesPerSec = %lu\n"
893 " BitsPerSample = %u\n",
894 wfx
->wFormatTag
, wfx
->nChannels
,
895 wfx
->nSamplesPerSec
, wfx
->nAvgBytesPerSec
,
896 wfx
->nBlockAlign
, wfx
->wBitsPerSample
);
898 hr
= copy_waveformat(&This
->format
.Format
, wfx
);
899 if(SUCCEEDED(hr
) && This
->write_emu
)
904 IDirectSoundBuffer8_Release(This
->write_emu
);
905 This
->write_emu
= NULL
;
907 memset(&desc
, 0, sizeof(desc
));
908 desc
.dwSize
= sizeof(desc
);
909 desc
.dwFlags
= DSBCAPS_LOCHARDWARE
|DSBCAPS_CTRLPAN
;
910 desc
.dwBufferBytes
= This
->buf_size
- (This
->buf_size
% This
->format
.Format
.nBlockAlign
);
911 desc
.lpwfxFormat
= &This
->format
.Format
;
913 hr
= DS8Buffer_Create(&buf
, This
, NULL
, TRUE
);
914 if(FAILED(hr
)) goto out
;
916 This
->write_emu
= &buf
->IDirectSoundBuffer8_iface
;
917 hr
= DS8Buffer_Initialize(This
->write_emu
, &This
->parent
->IDirectSound_iface
, &desc
);
920 IDirectSoundBuffer8_Release(This
->write_emu
);
921 This
->write_emu
= NULL
;
926 LeaveCriticalSection(&This
->share
->crst
);
930 static HRESULT WINAPI
DS8Primary_SetVolume(IDirectSoundBuffer
*iface
, LONG vol
)
932 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
934 TRACE("(%p)->(%ld)\n", iface
, vol
);
936 if(vol
> DSBVOLUME_MAX
|| vol
< DSBVOLUME_MIN
)
938 WARN("Invalid volume (%ld)\n", vol
);
939 return DSERR_INVALIDPARAM
;
942 if(!(This
->flags
&DSBCAPS_CTRLVOLUME
))
943 return DSERR_CONTROLUNAVAIL
;
945 setALContext(This
->ctx
);
946 alListenerf(AL_GAIN
, mB_to_gain(vol
));
952 static HRESULT WINAPI
DS8Primary_SetPan(IDirectSoundBuffer
*iface
, LONG pan
)
954 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
957 TRACE("(%p)->(%ld)\n", iface
, pan
);
959 if(pan
> DSBPAN_RIGHT
|| pan
< DSBPAN_LEFT
)
961 WARN("invalid parameter: pan = %ld\n", pan
);
962 return DSERR_INVALIDPARAM
;
965 EnterCriticalSection(&This
->share
->crst
);
966 if(!(This
->flags
&DSBCAPS_CTRLPAN
))
968 WARN("control unavailable\n");
969 hr
= DSERR_CONTROLUNAVAIL
;
971 else if(This
->write_emu
)
972 hr
= IDirectSoundBuffer8_SetPan(This
->write_emu
, pan
);
975 FIXME("Not supported\n");
978 LeaveCriticalSection(&This
->share
->crst
);
983 static HRESULT WINAPI
DS8Primary_SetFrequency(IDirectSoundBuffer
*iface
, DWORD freq
)
985 WARN("(%p)->(%lu)\n", iface
, freq
);
986 return DSERR_CONTROLUNAVAIL
;
989 static HRESULT WINAPI
DS8Primary_Stop(IDirectSoundBuffer
*iface
)
991 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
994 TRACE("(%p)->()\n", iface
);
996 EnterCriticalSection(&This
->share
->crst
);
998 hr
= IDirectSoundBuffer8_Stop(This
->write_emu
);
1000 This
->stopped
= TRUE
;
1001 LeaveCriticalSection(&This
->share
->crst
);
1006 static HRESULT WINAPI
DS8Primary_Unlock(IDirectSoundBuffer
*iface
, void *ptr1
, DWORD len1
, void *ptr2
, DWORD len2
)
1008 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
1009 HRESULT hr
= DSERR_INVALIDCALL
;
1011 TRACE("(%p)->(%p, %lu, %p, %lu)\n", iface
, ptr1
, len1
, ptr2
, len2
);
1013 EnterCriticalSection(&This
->share
->crst
);
1015 hr
= IDirectSoundBuffer8_Unlock(This
->write_emu
, ptr1
, len1
, ptr2
, len2
);
1016 LeaveCriticalSection(&This
->share
->crst
);
1021 static HRESULT WINAPI
DS8Primary_Restore(IDirectSoundBuffer
*iface
)
1023 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
1026 TRACE("(%p)->()\n", iface
);
1028 EnterCriticalSection(&This
->share
->crst
);
1030 hr
= IDirectSoundBuffer8_Restore(This
->write_emu
);
1031 LeaveCriticalSection(&This
->share
->crst
);
1036 static const IDirectSoundBufferVtbl DS8Primary_Vtbl
=
1038 DS8Primary_QueryInterface
,
1042 DS8Primary_GetCurrentPosition
,
1043 DS8Primary_GetFormat
,
1044 DS8Primary_GetVolume
,
1046 DS8Primary_GetFrequency
,
1047 DS8Primary_GetStatus
,
1048 DS8Primary_Initialize
,
1051 DS8Primary_SetCurrentPosition
,
1052 DS8Primary_SetFormat
,
1053 DS8Primary_SetVolume
,
1055 DS8Primary_SetFrequency
,
1062 static void DS8Primary_SetParams(DS8Primary
*This
, const DS3DLISTENER
*params
, LONG flags
)
1064 union PrimaryParamFlags dirty
= { flags
};
1068 alListener3f(AL_POSITION
, params
->vPosition
.x
, params
->vPosition
.y
,
1069 -params
->vPosition
.z
);
1071 alListener3f(AL_VELOCITY
, params
->vVelocity
.x
, params
->vVelocity
.y
,
1072 -params
->vVelocity
.z
);
1073 if(dirty
.bit
.orientation
)
1075 ALfloat orient
[6] = {
1076 params
->vOrientFront
.x
, params
->vOrientFront
.y
, -params
->vOrientFront
.z
,
1077 params
->vOrientTop
.x
, params
->vOrientTop
.y
, -params
->vOrientTop
.z
1079 alListenerfv(AL_ORIENTATION
, orient
);
1081 if(dirty
.bit
.distancefactor
)
1083 alSpeedOfSound(343.3f
/params
->flDistanceFactor
);
1084 if(BITFIELD_TEST(This
->share
->Exts
, EXT_EFX
))
1085 alListenerf(AL_METERS_PER_UNIT
, params
->flDistanceFactor
);
1087 if(dirty
.bit
.rollofffactor
)
1089 struct DSBufferGroup
*bufgroup
= This
->BufferGroups
;
1090 ALfloat rolloff
= params
->flRolloffFactor
;
1091 This
->rollofffactor
= rolloff
;
1093 for(i
= 0;i
< This
->NumBufferGroups
;++i
)
1095 DWORD64 usemask
= ~bufgroup
[i
].FreeBuffers
;
1098 int idx
= CTZ64(usemask
);
1099 DS8Buffer
*buf
= bufgroup
[i
].Buffers
+ idx
;
1100 usemask
&= ~(U64(1) << idx
);
1102 if(buf
->ds3dmode
!= DS3DMODE_DISABLE
)
1103 alSourcef(buf
->source
, AL_ROLLOFF_FACTOR
, rolloff
);
1107 if(dirty
.bit
.dopplerfactor
)
1108 alDopplerFactor(params
->flDopplerFactor
);
1109 if(dirty
.bit
.effect
)
1110 alAuxiliaryEffectSloti(This
->auxslot
, AL_EFFECTSLOT_EFFECT
, This
->effect
);
1113 static HRESULT WINAPI
DS8Primary3D_QueryInterface(IDirectSound3DListener
*iface
, REFIID riid
, void **ppv
)
1115 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1116 return DS8Primary_QueryInterface(&This
->IDirectSoundBuffer_iface
, riid
, ppv
);
1119 static ULONG WINAPI
DS8Primary3D_AddRef(IDirectSound3DListener
*iface
)
1121 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1124 ret
= InterlockedIncrement(&This
->ds3d_ref
);
1125 TRACE("new refcount %ld\n", ret
);
1130 static ULONG WINAPI
DS8Primary3D_Release(IDirectSound3DListener
*iface
)
1132 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1135 ret
= InterlockedDecrement(&This
->ds3d_ref
);
1136 TRACE("new refcount %ld\n", ret
);
1142 static HRESULT WINAPI
DS8Primary3D_GetDistanceFactor(IDirectSound3DListener
*iface
, D3DVALUE
*distancefactor
)
1144 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1146 TRACE("(%p)->(%p)\n", iface
, distancefactor
);
1150 WARN("Invalid parameter %p\n", distancefactor
);
1151 return DSERR_INVALIDPARAM
;
1154 setALContext(This
->ctx
);
1155 *distancefactor
= 343.3f
/alGetFloat(AL_SPEED_OF_SOUND
);
1162 static HRESULT WINAPI
DS8Primary3D_GetDopplerFactor(IDirectSound3DListener
*iface
, D3DVALUE
*dopplerfactor
)
1164 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1166 TRACE("(%p)->(%p)\n", iface
, dopplerfactor
);
1170 WARN("Invalid parameter %p\n", dopplerfactor
);
1171 return DSERR_INVALIDPARAM
;
1174 setALContext(This
->ctx
);
1175 *dopplerfactor
= alGetFloat(AL_DOPPLER_FACTOR
);
1182 static HRESULT WINAPI
DS8Primary3D_GetOrientation(IDirectSound3DListener
*iface
, D3DVECTOR
*front
, D3DVECTOR
*top
)
1184 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1187 TRACE("(%p)->(%p, %p)\n", iface
, front
, top
);
1191 WARN("Invalid parameter %p %p\n", front
, top
);
1192 return DSERR_INVALIDPARAM
;
1195 setALContext(This
->ctx
);
1196 alGetListenerfv(AL_ORIENTATION
, orient
);
1200 front
->x
= orient
[0];
1201 front
->y
= orient
[1];
1202 front
->z
= -orient
[2];
1205 top
->z
= -orient
[5];
1209 static HRESULT WINAPI
DS8Primary3D_GetPosition(IDirectSound3DListener
*iface
, D3DVECTOR
*pos
)
1211 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1214 TRACE("(%p)->(%p)\n", iface
, pos
);
1218 WARN("Invalid parameter %p\n", pos
);
1219 return DSERR_INVALIDPARAM
;
1222 setALContext(This
->ctx
);
1223 alGetListenerfv(AL_POSITION
, alpos
);
1233 static HRESULT WINAPI
DS8Primary3D_GetRolloffFactor(IDirectSound3DListener
*iface
, D3DVALUE
*rollofffactor
)
1235 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1237 TRACE("(%p)->(%p)\n", iface
, rollofffactor
);
1241 WARN("Invalid parameter %p\n", rollofffactor
);
1242 return DSERR_INVALIDPARAM
;
1245 EnterCriticalSection(&This
->share
->crst
);
1246 *rollofffactor
= This
->rollofffactor
;
1247 LeaveCriticalSection(&This
->share
->crst
);
1252 static HRESULT WINAPI
DS8Primary3D_GetVelocity(IDirectSound3DListener
*iface
, D3DVECTOR
*velocity
)
1254 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1257 TRACE("(%p)->(%p)\n", iface
, velocity
);
1261 WARN("Invalid parameter %p\n", velocity
);
1262 return DSERR_INVALIDPARAM
;
1265 setALContext(This
->ctx
);
1266 alGetListenerfv(AL_VELOCITY
, vel
);
1270 velocity
->x
= vel
[0];
1271 velocity
->y
= vel
[1];
1272 velocity
->z
= -vel
[2];
1276 static HRESULT WINAPI
DS8Primary3D_GetAllParameters(IDirectSound3DListener
*iface
, DS3DLISTENER
*listener
)
1278 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1280 TRACE("(%p)->(%p)\n", iface
, listener
);
1282 if(!listener
|| listener
->dwSize
< sizeof(*listener
))
1284 WARN("Invalid DS3DLISTENER %p %lu\n", listener
, listener
? listener
->dwSize
: 0);
1285 return DSERR_INVALIDPARAM
;
1288 EnterCriticalSection(&This
->share
->crst
);
1289 setALContext(This
->ctx
);
1290 DS8Primary3D_GetPosition(iface
, &listener
->vPosition
);
1291 DS8Primary3D_GetVelocity(iface
, &listener
->vVelocity
);
1292 DS8Primary3D_GetOrientation(iface
, &listener
->vOrientFront
, &listener
->vOrientTop
);
1293 DS8Primary3D_GetDistanceFactor(iface
, &listener
->flDistanceFactor
);
1294 DS8Primary3D_GetRolloffFactor(iface
, &listener
->flRolloffFactor
);
1295 DS8Primary3D_GetDopplerFactor(iface
, &listener
->flDopplerFactor
);
1297 LeaveCriticalSection(&This
->share
->crst
);
1303 static HRESULT WINAPI
DS8Primary3D_SetDistanceFactor(IDirectSound3DListener
*iface
, D3DVALUE factor
, DWORD apply
)
1305 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1307 TRACE("(%p)->(%f, %lu)\n", iface
, factor
, apply
);
1309 if(factor
< DS3D_MINDISTANCEFACTOR
||
1310 factor
> DS3D_MAXDISTANCEFACTOR
)
1312 WARN("Invalid parameter %f\n", factor
);
1313 return DSERR_INVALIDPARAM
;
1316 if(apply
== DS3D_DEFERRED
)
1318 EnterCriticalSection(&This
->share
->crst
);
1319 This
->deferred
.ds3d
.flDistanceFactor
= factor
;
1320 This
->dirty
.bit
.distancefactor
= 1;
1321 LeaveCriticalSection(&This
->share
->crst
);
1325 setALContext(This
->ctx
);
1326 alSpeedOfSound(343.3f
/factor
);
1327 if(BITFIELD_TEST(This
->share
->Exts
, EXT_EFX
))
1328 alListenerf(AL_METERS_PER_UNIT
, factor
);
1336 static HRESULT WINAPI
DS8Primary3D_SetDopplerFactor(IDirectSound3DListener
*iface
, D3DVALUE factor
, DWORD apply
)
1338 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1340 TRACE("(%p)->(%f, %lu)\n", iface
, factor
, apply
);
1342 if(factor
< DS3D_MINDOPPLERFACTOR
||
1343 factor
> DS3D_MAXDOPPLERFACTOR
)
1345 WARN("Invalid parameter %f\n", factor
);
1346 return DSERR_INVALIDPARAM
;
1349 if(apply
== DS3D_DEFERRED
)
1351 EnterCriticalSection(&This
->share
->crst
);
1352 This
->deferred
.ds3d
.flDopplerFactor
= factor
;
1353 This
->dirty
.bit
.dopplerfactor
= 1;
1354 LeaveCriticalSection(&This
->share
->crst
);
1358 setALContext(This
->ctx
);
1359 alDopplerFactor(factor
);
1367 static HRESULT WINAPI
DS8Primary3D_SetOrientation(IDirectSound3DListener
*iface
, D3DVALUE xFront
, D3DVALUE yFront
, D3DVALUE zFront
, D3DVALUE xTop
, D3DVALUE yTop
, D3DVALUE zTop
, DWORD apply
)
1369 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1371 TRACE("(%p)->(%f, %f, %f, %f, %f, %f, %lu)\n", iface
, xFront
, yFront
, zFront
, xTop
, yTop
, zTop
, apply
);
1373 if(apply
== DS3D_DEFERRED
)
1375 EnterCriticalSection(&This
->share
->crst
);
1376 This
->deferred
.ds3d
.vOrientFront
.x
= xFront
;
1377 This
->deferred
.ds3d
.vOrientFront
.y
= yFront
;
1378 This
->deferred
.ds3d
.vOrientFront
.z
= zFront
;
1379 This
->deferred
.ds3d
.vOrientTop
.x
= xTop
;
1380 This
->deferred
.ds3d
.vOrientTop
.y
= yTop
;
1381 This
->deferred
.ds3d
.vOrientTop
.z
= zTop
;
1382 This
->dirty
.bit
.orientation
= 1;
1383 LeaveCriticalSection(&This
->share
->crst
);
1387 ALfloat orient
[6] = {
1388 xFront
, yFront
, -zFront
,
1391 setALContext(This
->ctx
);
1392 alListenerfv(AL_ORIENTATION
, orient
);
1400 static HRESULT WINAPI
DS8Primary3D_SetPosition(IDirectSound3DListener
*iface
, D3DVALUE x
, D3DVALUE y
, D3DVALUE z
, DWORD apply
)
1402 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1404 TRACE("(%p)->(%f, %f, %f, %lu)\n", iface
, x
, y
, z
, apply
);
1406 if(apply
== DS3D_DEFERRED
)
1408 EnterCriticalSection(&This
->share
->crst
);
1409 This
->deferred
.ds3d
.vPosition
.x
= x
;
1410 This
->deferred
.ds3d
.vPosition
.y
= y
;
1411 This
->deferred
.ds3d
.vPosition
.z
= z
;
1412 This
->dirty
.bit
.pos
= 1;
1413 LeaveCriticalSection(&This
->share
->crst
);
1417 setALContext(This
->ctx
);
1418 alListener3f(AL_POSITION
, x
, y
, -z
);
1426 static HRESULT WINAPI
DS8Primary3D_SetRolloffFactor(IDirectSound3DListener
*iface
, D3DVALUE factor
, DWORD apply
)
1428 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1430 TRACE("(%p)->(%f, %lu)\n", iface
, factor
, apply
);
1432 if(factor
< DS3D_MINROLLOFFFACTOR
||
1433 factor
> DS3D_MAXROLLOFFFACTOR
)
1435 WARN("Invalid parameter %f\n", factor
);
1436 return DSERR_INVALIDPARAM
;
1439 EnterCriticalSection(&This
->share
->crst
);
1440 if(apply
== DS3D_DEFERRED
)
1442 This
->deferred
.ds3d
.flRolloffFactor
= factor
;
1443 This
->dirty
.bit
.rollofffactor
= 1;
1447 struct DSBufferGroup
*bufgroup
= This
->BufferGroups
;
1450 This
->rollofffactor
= factor
;
1452 setALContext(This
->ctx
);
1453 for(i
= 0;i
< This
->NumBufferGroups
;++i
)
1455 DWORD64 usemask
= ~bufgroup
[i
].FreeBuffers
;
1458 int idx
= CTZ64(usemask
);
1459 DS8Buffer
*buf
= bufgroup
[i
].Buffers
+ idx
;
1460 usemask
&= ~(U64(1) << idx
);
1462 if(buf
->ds3dmode
!= DS3DMODE_DISABLE
)
1463 alSourcef(buf
->source
, AL_ROLLOFF_FACTOR
, factor
);
1469 LeaveCriticalSection(&This
->share
->crst
);
1474 static HRESULT WINAPI
DS8Primary3D_SetVelocity(IDirectSound3DListener
*iface
, D3DVALUE x
, D3DVALUE y
, D3DVALUE z
, DWORD apply
)
1476 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1478 TRACE("(%p)->(%f, %f, %f, %lu)\n", iface
, x
, y
, z
, apply
);
1480 if(apply
== DS3D_DEFERRED
)
1482 EnterCriticalSection(&This
->share
->crst
);
1483 This
->deferred
.ds3d
.vVelocity
.x
= x
;
1484 This
->deferred
.ds3d
.vVelocity
.y
= y
;
1485 This
->deferred
.ds3d
.vVelocity
.z
= z
;
1486 This
->dirty
.bit
.vel
= 1;
1487 LeaveCriticalSection(&This
->share
->crst
);
1491 setALContext(This
->ctx
);
1492 alListener3f(AL_VELOCITY
, x
, y
, -z
);
1500 static HRESULT WINAPI
DS8Primary3D_SetAllParameters(IDirectSound3DListener
*iface
, const DS3DLISTENER
*listen
, DWORD apply
)
1502 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1504 TRACE("(%p)->(%p, %lu)\n", iface
, listen
, apply
);
1506 if(!listen
|| listen
->dwSize
< sizeof(*listen
))
1508 WARN("Invalid parameter %p %lu\n", listen
, listen
? listen
->dwSize
: 0);
1509 return DSERR_INVALIDPARAM
;
1512 if(listen
->flDistanceFactor
> DS3D_MAXDISTANCEFACTOR
||
1513 listen
->flDistanceFactor
< DS3D_MINDISTANCEFACTOR
)
1515 WARN("Invalid distance factor (%f)\n", listen
->flDistanceFactor
);
1516 return DSERR_INVALIDPARAM
;
1519 if(listen
->flDopplerFactor
> DS3D_MAXDOPPLERFACTOR
||
1520 listen
->flDopplerFactor
< DS3D_MINDOPPLERFACTOR
)
1522 WARN("Invalid doppler factor (%f)\n", listen
->flDopplerFactor
);
1523 return DSERR_INVALIDPARAM
;
1526 if(listen
->flRolloffFactor
< DS3D_MINROLLOFFFACTOR
||
1527 listen
->flRolloffFactor
> DS3D_MAXROLLOFFFACTOR
)
1529 WARN("Invalid rolloff factor (%f)\n", listen
->flRolloffFactor
);
1530 return DSERR_INVALIDPARAM
;
1533 if(apply
== DS3D_DEFERRED
)
1535 EnterCriticalSection(&This
->share
->crst
);
1536 This
->deferred
.ds3d
= *listen
;
1537 This
->deferred
.ds3d
.dwSize
= sizeof(This
->deferred
.ds3d
);
1538 This
->dirty
.bit
.pos
= 1;
1539 This
->dirty
.bit
.vel
= 1;
1540 This
->dirty
.bit
.orientation
= 1;
1541 This
->dirty
.bit
.distancefactor
= 1;
1542 This
->dirty
.bit
.rollofffactor
= 1;
1543 This
->dirty
.bit
.dopplerfactor
= 1;
1544 LeaveCriticalSection(&This
->share
->crst
);
1548 union PrimaryParamFlags dirty
= { 0l };
1551 dirty
.bit
.orientation
= 1;
1552 dirty
.bit
.distancefactor
= 1;
1553 dirty
.bit
.rollofffactor
= 1;
1554 dirty
.bit
.dopplerfactor
= 1;
1556 EnterCriticalSection(&This
->share
->crst
);
1557 setALContext(This
->ctx
);
1558 DS8Primary_SetParams(This
, listen
, dirty
.flags
);
1561 LeaveCriticalSection(&This
->share
->crst
);
1567 HRESULT WINAPI
DS8Primary3D_CommitDeferredSettings(IDirectSound3DListener
*iface
)
1569 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1570 struct DSBufferGroup
*bufgroup
;
1574 EnterCriticalSection(&This
->share
->crst
);
1575 setALContext(This
->ctx
);
1576 alDeferUpdatesSOFT();
1578 if((flags
=InterlockedExchange(&This
->dirty
.flags
, 0)) != 0)
1580 DS8Primary_SetParams(This
, &This
->deferred
.ds3d
, flags
);
1581 /* checkALError is here for debugging */
1584 TRACE("Dirty flags was: 0x%02lx\n", flags
);
1586 bufgroup
= This
->BufferGroups
;
1587 for(i
= 0;i
< This
->NumBufferGroups
;++i
)
1589 DWORD64 usemask
= ~bufgroup
[i
].FreeBuffers
;
1592 int idx
= CTZ64(usemask
);
1593 DS8Buffer
*buf
= bufgroup
[i
].Buffers
+ idx
;
1594 usemask
&= ~(U64(1) << idx
);
1596 if((flags
=InterlockedExchange(&buf
->dirty
.flags
, 0)) != 0)
1597 DS8Buffer_SetParams(buf
, &buf
->deferred
.ds3d
, &buf
->deferred
.eax
, flags
);
1600 alProcessUpdatesSOFT();
1604 LeaveCriticalSection(&This
->share
->crst
);
1609 static const IDirectSound3DListenerVtbl DS8Primary3D_Vtbl
=
1611 DS8Primary3D_QueryInterface
,
1612 DS8Primary3D_AddRef
,
1613 DS8Primary3D_Release
,
1614 DS8Primary3D_GetAllParameters
,
1615 DS8Primary3D_GetDistanceFactor
,
1616 DS8Primary3D_GetDopplerFactor
,
1617 DS8Primary3D_GetOrientation
,
1618 DS8Primary3D_GetPosition
,
1619 DS8Primary3D_GetRolloffFactor
,
1620 DS8Primary3D_GetVelocity
,
1621 DS8Primary3D_SetAllParameters
,
1622 DS8Primary3D_SetDistanceFactor
,
1623 DS8Primary3D_SetDopplerFactor
,
1624 DS8Primary3D_SetOrientation
,
1625 DS8Primary3D_SetPosition
,
1626 DS8Primary3D_SetRolloffFactor
,
1627 DS8Primary3D_SetVelocity
,
1628 DS8Primary3D_CommitDeferredSettings
1632 static HRESULT WINAPI
DS8PrimaryProp_QueryInterface(IKsPropertySet
*iface
, REFIID riid
, void **ppv
)
1634 DS8Primary
*This
= impl_from_IKsPropertySet(iface
);
1635 return DS8Primary_QueryInterface(&This
->IDirectSoundBuffer_iface
, riid
, ppv
);
1638 static ULONG WINAPI
DS8PrimaryProp_AddRef(IKsPropertySet
*iface
)
1640 DS8Primary
*This
= impl_from_IKsPropertySet(iface
);
1643 ret
= InterlockedIncrement(&This
->prop_ref
);
1644 TRACE("new refcount %ld\n", ret
);
1649 static ULONG WINAPI
DS8PrimaryProp_Release(IKsPropertySet
*iface
)
1651 DS8Primary
*This
= impl_from_IKsPropertySet(iface
);
1654 ret
= InterlockedDecrement(&This
->prop_ref
);
1655 TRACE("new refcount %ld\n", ret
);
1660 static HRESULT WINAPI
DS8PrimaryProp_Get(IKsPropertySet
*iface
,
1661 REFGUID guidPropSet
, ULONG dwPropID
,
1662 LPVOID pInstanceData
, ULONG cbInstanceData
,
1663 LPVOID pPropData
, ULONG cbPropData
,
1668 (void)pInstanceData
;
1669 (void)cbInstanceData
;
1674 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet
));
1676 return E_PROP_ID_UNSUPPORTED
;
1679 static HRESULT WINAPI
DS8PrimaryProp_Set(IKsPropertySet
*iface
,
1680 REFGUID guidPropSet
, ULONG dwPropID
,
1681 LPVOID pInstanceData
, ULONG cbInstanceData
,
1682 LPVOID pPropData
, ULONG cbPropData
)
1686 (void)pInstanceData
;
1687 (void)cbInstanceData
;
1691 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet
));
1693 return E_PROP_ID_UNSUPPORTED
;
1696 static HRESULT WINAPI
DS8PrimaryProp_QuerySupport(IKsPropertySet
*iface
,
1697 REFGUID guidPropSet
, ULONG dwPropID
,
1698 ULONG
*pTypeSupport
)
1704 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet
));
1706 return E_PROP_ID_UNSUPPORTED
;
1709 static const IKsPropertySetVtbl DS8PrimaryProp_Vtbl
=
1711 DS8PrimaryProp_QueryInterface
,
1712 DS8PrimaryProp_AddRef
,
1713 DS8PrimaryProp_Release
,
1716 DS8PrimaryProp_QuerySupport