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"
32 #include "eax-presets.h"
35 #ifndef E_PROP_ID_UNSUPPORTED
36 #define E_PROP_ID_UNSUPPORTED ((HRESULT)0x80070490)
40 static const IDirectSoundBufferVtbl DSPrimary_Vtbl
;
41 static const IDirectSound3DListenerVtbl DSPrimary3D_Vtbl
;
42 static const IKsPropertySetVtbl DSPrimaryProp_Vtbl
;
44 static void DSPrimary_SetParams(DSPrimary
*This
, const DS3DLISTENER
*params
, LONG flags
);
47 static inline DSPrimary
*impl_from_IDirectSoundBuffer(IDirectSoundBuffer
*iface
)
49 return CONTAINING_RECORD(iface
, DSPrimary
, IDirectSoundBuffer_iface
);
52 static inline DSPrimary
*impl_from_IDirectSound3DListener(IDirectSound3DListener
*iface
)
54 return CONTAINING_RECORD(iface
, DSPrimary
, IDirectSound3DListener_iface
);
57 static inline DSPrimary
*impl_from_IKsPropertySet(IKsPropertySet
*iface
)
59 return CONTAINING_RECORD(iface
, DSPrimary
, IKsPropertySet_iface
);
63 static void trigger_elapsed_notifies(DSBuffer
*buf
, DWORD lastpos
, DWORD curpos
)
65 DSBPOSITIONNOTIFY
*not = buf
->notify
;
66 DSBPOSITIONNOTIFY
*not_end
= not + buf
->nnotify
;
67 for(;not != not_end
;++not)
69 HANDLE event
= not->hEventNotify
;
70 DWORD ofs
= not->dwOffset
;
72 if(ofs
== (DWORD
)DSBPN_OFFSETSTOP
)
75 if(curpos
< lastpos
) /* Wraparound case */
77 if(ofs
< curpos
|| ofs
>= lastpos
)
79 TRACE("Triggering notification %d from buffer %p\n", not - buf
->notify
, buf
);
83 else if(ofs
>= lastpos
&& ofs
< curpos
) /* Normal case */
85 TRACE("Triggering notification %d from buffer %p\n", not - buf
->notify
, buf
);
91 static void trigger_stop_notifies(DSBuffer
*buf
)
93 DSBPOSITIONNOTIFY
*not = buf
->notify
;
94 DSBPOSITIONNOTIFY
*not_end
= not + buf
->nnotify
;
95 for(;not != not_end
;++not)
97 if(not->dwOffset
!= (DWORD
)DSBPN_OFFSETSTOP
)
99 TRACE("Triggering notification %d from buffer %p\n", not - buf
->notify
, buf
);
100 SetEvent(not->hEventNotify
);
104 void DSPrimary_triggernots(DSPrimary
*prim
)
106 DSBuffer
**curnot
, **endnot
;
108 curnot
= prim
->notifies
;
109 endnot
= curnot
+ prim
->nnotifies
;
110 while(curnot
!= endnot
)
112 DSBuffer
*buf
= *curnot
;
113 DSData
*data
= buf
->buffer
;
114 DWORD curpos
= buf
->lastpos
;
118 alGetSourcei(buf
->source
, AL_BYTE_OFFSET
, &ofs
);
119 alGetSourcei(buf
->source
, AL_SOURCE_STATE
, &state
);
120 if(buf
->segsize
== 0)
121 curpos
= (state
== AL_STOPPED
) ? data
->buf_size
: ofs
;
124 if(state
!= AL_STOPPED
)
125 curpos
= ofs
+ buf
->queue_base
;
129 alGetSourcei(buf
->source
, AL_BUFFERS_QUEUED
, &queued
);
130 curpos
= buf
->segsize
*queued
+ buf
->queue_base
;
133 if(curpos
>= (DWORD
)data
->buf_size
)
136 curpos
%= (DWORD
)data
->buf_size
;
137 else if(buf
->isplaying
)
139 curpos
= data
->buf_size
;
140 alSourceStop(buf
->source
);
141 alSourcei(buf
->source
, AL_BUFFER
, 0);
143 buf
->isplaying
= FALSE
;
147 if(state
!= AL_PLAYING
)
148 state
= buf
->isplaying
? AL_PLAYING
: AL_PAUSED
;
152 if(buf
->lastpos
!= curpos
)
154 trigger_elapsed_notifies(buf
, buf
->lastpos
, curpos
);
155 buf
->lastpos
= curpos
;
157 if(state
!= AL_PLAYING
)
159 /* Remove this buffer from list and put another at the current
160 * position; don't increment i
162 trigger_stop_notifies(buf
);
163 *curnot
= *(--endnot
);
172 static void do_buffer_stream(DSBuffer
*buf
, BYTE
*scratch_mem
)
174 DSData
*data
= buf
->buffer
;
175 ALint ofs
, done
= 0, queued
= QBUFFERS
, state
= AL_PLAYING
;
178 alGetSourcei(buf
->source
, AL_BUFFERS_QUEUED
, &queued
);
179 alGetSourcei(buf
->source
, AL_SOURCE_STATE
, &state
);
180 alGetSourcei(buf
->source
, AL_BUFFERS_PROCESSED
, &done
);
184 ALuint bids
[QBUFFERS
];
187 alSourceUnqueueBuffers(buf
->source
, done
, bids
);
188 buf
->queue_base
= (buf
->queue_base
+ buf
->segsize
*done
) % data
->buf_size
;
190 while(queued
< QBUFFERS
)
192 which
= buf
->stream_bids
[buf
->curidx
];
193 ofs
= buf
->data_offset
;
195 if(buf
->segsize
< data
->buf_size
- ofs
)
197 alBufferData(which
, data
->buf_format
, data
->data
+ ofs
, buf
->segsize
,
198 data
->format
.Format
.nSamplesPerSec
);
199 buf
->data_offset
= ofs
+ buf
->segsize
;
201 else if(buf
->islooping
)
203 ALsizei rem
= data
->buf_size
- ofs
;
204 if(rem
> 2048) rem
= 2048;
206 memcpy(scratch_mem
, data
->data
+ ofs
, rem
);
207 while(rem
< buf
->segsize
)
209 ALsizei todo
= buf
->segsize
- rem
;
210 if(todo
> data
->buf_size
)
211 todo
= data
->buf_size
;
212 memcpy(scratch_mem
+ rem
, data
->data
, todo
);
215 alBufferData(which
, data
->buf_format
, scratch_mem
, buf
->segsize
,
216 data
->format
.Format
.nSamplesPerSec
);
217 buf
->data_offset
= (ofs
+buf
->segsize
) % data
->buf_size
;
221 ALsizei rem
= data
->buf_size
- ofs
;
222 if(rem
> 2048) rem
= 2048;
225 memcpy(scratch_mem
, data
->data
+ ofs
, rem
);
226 memset(scratch_mem
+rem
, (data
->format
.Format
.wBitsPerSample
==8) ? 128 : 0,
228 alBufferData(which
, data
->buf_format
, scratch_mem
, buf
->segsize
,
229 data
->format
.Format
.nSamplesPerSec
);
230 buf
->data_offset
= data
->buf_size
;
233 alSourceQueueBuffers(buf
->source
, 1, &which
);
234 buf
->curidx
= (buf
->curidx
+1)%QBUFFERS
;
240 buf
->data_offset
= 0;
241 buf
->queue_base
= data
->buf_size
;
243 buf
->isplaying
= FALSE
;
245 else if(state
!= AL_PLAYING
)
246 alSourcePlay(buf
->source
);
249 void DSPrimary_streamfeeder(DSPrimary
*prim
, BYTE
*scratch_mem
)
251 /* OpenAL doesn't support our lovely buffer extensions so just make sure
252 * enough buffers are queued for streaming
256 DSBuffer
*buf
= CONTAINING_RECORD(prim
->write_emu
, DSBuffer
, IDirectSoundBuffer8_iface
);
257 if(buf
->segsize
!= 0 && buf
->isplaying
)
258 do_buffer_stream(buf
, scratch_mem
);
262 struct DSBufferGroup
*bufgroup
= prim
->BufferGroups
;
263 struct DSBufferGroup
*endgroup
= bufgroup
+ prim
->NumBufferGroups
;
264 for(;bufgroup
!= endgroup
;++bufgroup
)
266 DWORD64 usemask
= ~bufgroup
->FreeBuffers
;
269 int idx
= CTZ64(usemask
);
270 DSBuffer
*buf
= bufgroup
->Buffers
+ idx
;
271 usemask
&= ~(U64(1) << idx
);
273 if(buf
->segsize
!= 0 && buf
->isplaying
)
274 do_buffer_stream(buf
, scratch_mem
);
282 HRESULT
DSPrimary_PreInit(DSPrimary
*This
, DSDevice
*parent
)
290 This
->IDirectSoundBuffer_iface
.lpVtbl
= &DSPrimary_Vtbl
;
291 This
->IDirectSound3DListener_iface
.lpVtbl
= &DSPrimary3D_Vtbl
;
292 This
->IKsPropertySet_iface
.lpVtbl
= &DSPrimaryProp_Vtbl
;
294 This
->parent
= parent
;
295 This
->share
= parent
->share
;
296 This
->ctx
= parent
->share
->ctx
;
297 This
->refresh
= parent
->share
->refresh
;
298 for(i
= 0;i
< EAX_MAX_FXSLOTS
;++i
)
299 This
->auxslot
[i
] = parent
->share
->auxslot
[i
];
301 wfx
= &This
->format
.Format
;
302 wfx
->wFormatTag
= WAVE_FORMAT_PCM
;
304 wfx
->wBitsPerSample
= 8;
305 wfx
->nSamplesPerSec
= 22050;
306 wfx
->nBlockAlign
= wfx
->wBitsPerSample
* wfx
->nChannels
/ 8;
307 wfx
->nAvgBytesPerSec
= wfx
->nSamplesPerSec
* wfx
->nBlockAlign
;
310 This
->stopped
= TRUE
;
312 /* EAX allows the buffer's direct and room volumes to be up to +1000mB
313 * (~3.162 linear gain), but standard EFX's source filters only allow a
314 * maximum gain of 1 (+0mB). The not-currently-final AL_SOFT_filter_gain_ex
315 * extension increases the maximum filter gain to 4 (about +1200mB), which
316 * is enough to handle the original +1000mB range.
318 This
->filter_mBLimit
= HAS_EXTENSION(This
->share
, SOFTX_FILTER_GAIN_EX
) ? 1000.0f
: 0.0f
;
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 This
->eax_error
= EAX_OK
;
327 This
->current
.ctx
.guidPrimaryFXSlotID
= EAXPROPERTYID_EAX40_FXSlot0
;
328 This
->current
.ctx
.flDistanceFactor
= 1.0f
;
329 This
->current
.ctx
.flAirAbsorptionHF
= -5.0f
;
330 This
->current
.ctx
.flHFReference
= 5000.0f
;
331 This
->current
.fxslot
[0].effect_type
= FXSLOT_EFFECT_REVERB
;
332 This
->current
.fxslot
[0].fx
.reverb
= EnvironmentDefaults
[EAX_ENVIRONMENT_GENERIC
];
333 This
->current
.fxslot
[0].props
.guidLoadEffect
= EAX_REVERB_EFFECT
;
334 This
->current
.fxslot
[0].props
.lVolume
= 0;
335 This
->current
.fxslot
[0].props
.lLock
= EAXFXSLOT_UNLOCKED
;
336 This
->current
.fxslot
[0].props
.dwFlags
= EAXFXSLOTFLAGS_ENVIRONMENT
;
337 /* FIXME: Should fxslot[1] be chorus? Or left as a NULL effect? */
338 for(i
= 1;i
< EAX_MAX_FXSLOTS
;++i
)
340 This
->current
.fxslot
[i
].effect_type
= FXSLOT_EFFECT_NULL
;
341 This
->current
.fxslot
[i
].props
.guidLoadEffect
= EAX_NULL_GUID
;
342 This
->current
.fxslot
[i
].props
.lVolume
= 0;
343 This
->current
.fxslot
[i
].props
.lLock
= EAXFXSLOT_UNLOCKED
;
344 This
->current
.fxslot
[i
].props
.dwFlags
= EAXFXSLOTFLAGS_ENVIRONMENT
;
346 This
->current
.eax1_volume
= 0.5f
;
347 This
->current
.eax1_dampening
= 0.5f
;
349 This
->deferred
.ctx
= This
->current
.ctx
;
350 for(i
= 0;i
< EAX_MAX_FXSLOTS
;++i
)
351 This
->deferred
.fxslot
[i
] = This
->current
.fxslot
[i
];
352 This
->deferred
.eax1_volume
= This
->current
.eax1_volume
;
353 This
->deferred
.eax1_dampening
= This
->current
.eax1_dampening
;
355 setALContext(This
->ctx
);
356 if(This
->auxslot
[0] != 0)
360 This
->primary_slot
= This
->auxslot
[0];
363 alGenEffects(EAX_MAX_FXSLOTS
, This
->effect
);
364 if((err
=alGetError()) == AL_NO_ERROR
)
366 alEffecti(This
->effect
[0], AL_EFFECT_TYPE
, AL_EFFECT_EAXREVERB
);
367 if((err
=alGetError()) != AL_NO_ERROR
)
369 alDeleteEffects(EAX_MAX_FXSLOTS
, This
->effect
);
373 if(err
!= AL_NO_ERROR
)
375 ERR("Failed to setup effects: %s (0x%04x)\n", alGetString(err
), err
);
376 This
->effect
[0] = This
->effect
[1] =
377 This
->effect
[2] = This
->effect
[3] = 0;
382 num_srcs
= This
->share
->sources
.maxhw_alloc
+ This
->share
->sources
.maxsw_alloc
;
384 hr
= DSERR_OUTOFMEMORY
;
385 This
->notifies
= HeapAlloc(GetProcessHeap(), 0, num_srcs
*sizeof(*This
->notifies
));
386 if(!This
->notifies
) goto fail
;
387 This
->sizenotifies
= num_srcs
;
389 count
= (MAX_HWBUFFERS
+63) / 64;
390 This
->BufferGroups
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
391 count
*sizeof(*This
->BufferGroups
));
392 if(!This
->BufferGroups
) goto fail
;
394 for(i
= 0;i
< count
;++i
)
396 This
->BufferGroups
[i
].Buffers
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
397 64*sizeof(This
->BufferGroups
[0].Buffers
[0]));
398 if(!This
->BufferGroups
[i
].Buffers
)
401 HeapFree(GetProcessHeap(), 0, This
->BufferGroups
[--i
].Buffers
);
402 HeapFree(GetProcessHeap(), 0, This
->BufferGroups
);
403 This
->BufferGroups
= NULL
;
406 This
->BufferGroups
[i
].FreeBuffers
= ~(DWORD64
)0;
408 This
->NumBufferGroups
= count
;
413 DSPrimary_Clear(This
);
417 void DSPrimary_Clear(DSPrimary
*This
)
419 struct DSBufferGroup
*bufgroup
;
425 setALContext(This
->ctx
);
427 alDeleteEffects(EAX_MAX_FXSLOTS
, This
->effect
);
431 bufgroup
= This
->BufferGroups
;
432 for(i
= 0;i
< This
->NumBufferGroups
;++i
)
434 DWORD64 usemask
= ~bufgroup
[i
].FreeBuffers
;
437 int idx
= CTZ64(usemask
);
438 DSBuffer
*buf
= bufgroup
[i
].Buffers
+ idx
;
439 usemask
&= ~(U64(1) << idx
);
441 DSBuffer_Destroy(buf
);
443 HeapFree(GetProcessHeap(), 0, This
->BufferGroups
[i
].Buffers
);
446 HeapFree(GetProcessHeap(), 0, This
->BufferGroups
);
447 HeapFree(GetProcessHeap(), 0, This
->notifies
);
448 memset(This
, 0, sizeof(*This
));
451 static HRESULT WINAPI
DSPrimary_QueryInterface(IDirectSoundBuffer
*iface
, REFIID riid
, LPVOID
*ppv
)
453 DSPrimary
*This
= impl_from_IDirectSoundBuffer(iface
);
455 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
458 if(IsEqualIID(riid
, &IID_IUnknown
) ||
459 IsEqualIID(riid
, &IID_IDirectSoundBuffer
))
460 *ppv
= &This
->IDirectSoundBuffer_iface
;
461 else if(IsEqualIID(riid
, &IID_IDirectSound3DListener
))
463 if((This
->flags
&DSBCAPS_CTRL3D
))
464 *ppv
= &This
->IDirectSound3DListener_iface
;
466 else if(IsEqualIID(riid
, &IID_IKsPropertySet
))
467 *ppv
= &This
->IKsPropertySet_iface
;
469 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid
));
473 IUnknown_AddRef((IUnknown
*)*ppv
);
477 return E_NOINTERFACE
;
480 static ULONG WINAPI
DSPrimary_AddRef(IDirectSoundBuffer
*iface
)
482 DSPrimary
*This
= impl_from_IDirectSoundBuffer(iface
);
485 ret
= InterlockedIncrement(&This
->ref
);
486 if(ret
== 1) This
->flags
= 0;
487 TRACE("(%p) ref %lu\n", iface
, ret
);
492 static ULONG WINAPI
DSPrimary_Release(IDirectSoundBuffer
*iface
)
494 DSPrimary
*This
= impl_from_IDirectSoundBuffer(iface
);
497 oldval
= *(volatile LONG
*)&This
->ref
;
503 oldval
= InterlockedCompareExchange(&This
->ref
, ref
, ref
+1)-1;
505 } while(oldval
!= ref
);
506 TRACE("(%p) ref %lu\n", iface
, ref
);
511 static HRESULT WINAPI
DSPrimary_GetCaps(IDirectSoundBuffer
*iface
, DSBCAPS
*caps
)
513 DSPrimary
*This
= impl_from_IDirectSoundBuffer(iface
);
515 TRACE("(%p)->(%p)\n", iface
, caps
);
517 if(!caps
|| caps
->dwSize
< sizeof(*caps
))
519 WARN("Invalid DSBCAPS (%p, %lu)\n", caps
, caps
? caps
->dwSize
: 0);
520 return DSERR_INVALIDPARAM
;
523 caps
->dwFlags
= This
->flags
;
524 caps
->dwBufferBytes
= This
->buf_size
;
525 caps
->dwUnlockTransferRate
= 0;
526 caps
->dwPlayCpuOverhead
= 0;
531 static HRESULT WINAPI
DSPrimary_GetCurrentPosition(IDirectSoundBuffer
*iface
, DWORD
*playpos
, DWORD
*curpos
)
533 DSPrimary
*This
= impl_from_IDirectSoundBuffer(iface
);
534 HRESULT hr
= DSERR_PRIOLEVELNEEDED
;
536 EnterCriticalSection(&This
->share
->crst
);
538 hr
= IDirectSoundBuffer_GetCurrentPosition(This
->write_emu
, playpos
, curpos
);
539 LeaveCriticalSection(&This
->share
->crst
);
544 static HRESULT WINAPI
DSPrimary_GetFormat(IDirectSoundBuffer
*iface
, WAVEFORMATEX
*wfx
, DWORD allocated
, DWORD
*written
)
546 DSPrimary
*This
= impl_from_IDirectSoundBuffer(iface
);
552 WARN("Cannot report format or format size\n");
553 return DSERR_INVALIDPARAM
;
556 EnterCriticalSection(&This
->share
->crst
);
557 size
= sizeof(This
->format
.Format
) + This
->format
.Format
.cbSize
;
563 hr
= DSERR_INVALIDPARAM
;
565 memcpy(wfx
, &This
->format
.Format
, size
);
567 LeaveCriticalSection(&This
->share
->crst
);
572 static HRESULT WINAPI
DSPrimary_GetVolume(IDirectSoundBuffer
*iface
, LONG
*volume
)
574 DSPrimary
*This
= impl_from_IDirectSoundBuffer(iface
);
577 TRACE("(%p)->(%p)\n", iface
, volume
);
580 return DSERR_INVALIDPARAM
;
583 if(!(This
->flags
&DSBCAPS_CTRLVOLUME
))
584 return DSERR_CONTROLUNAVAIL
;
586 setALContext(This
->ctx
);
587 alGetListenerf(AL_GAIN
, &gain
);
591 *volume
= clampI(gain_to_mB(gain
), DSBVOLUME_MIN
, DSBVOLUME_MAX
);
595 static HRESULT WINAPI
DSPrimary_GetPan(IDirectSoundBuffer
*iface
, LONG
*pan
)
597 DSPrimary
*This
= impl_from_IDirectSoundBuffer(iface
);
600 WARN("(%p)->(%p): semi-stub\n", iface
, pan
);
603 return DSERR_INVALIDPARAM
;
605 EnterCriticalSection(&This
->share
->crst
);
607 hr
= IDirectSoundBuffer_GetPan(This
->write_emu
, pan
);
608 else if(!(This
->flags
& DSBCAPS_CTRLPAN
))
609 hr
= DSERR_CONTROLUNAVAIL
;
612 LeaveCriticalSection(&This
->share
->crst
);
617 static HRESULT WINAPI
DSPrimary_GetFrequency(IDirectSoundBuffer
*iface
, DWORD
*freq
)
619 DSPrimary
*This
= impl_from_IDirectSoundBuffer(iface
);
622 WARN("(%p)->(%p): semi-stub\n", iface
, freq
);
625 return DSERR_INVALIDPARAM
;
627 if(!(This
->flags
&DSBCAPS_CTRLFREQUENCY
))
628 return DSERR_CONTROLUNAVAIL
;
630 EnterCriticalSection(&This
->share
->crst
);
631 *freq
= This
->format
.Format
.nSamplesPerSec
;
632 LeaveCriticalSection(&This
->share
->crst
);
637 static HRESULT WINAPI
DSPrimary_GetStatus(IDirectSoundBuffer
*iface
, DWORD
*status
)
639 DSPrimary
*This
= impl_from_IDirectSoundBuffer(iface
);
641 TRACE("(%p)->(%p)\n", iface
, status
);
644 return DSERR_INVALIDPARAM
;
646 EnterCriticalSection(&This
->share
->crst
);
647 *status
= DSBSTATUS_PLAYING
|DSBSTATUS_LOOPING
;
648 if((This
->flags
&DSBCAPS_LOCDEFER
))
649 *status
|= DSBSTATUS_LOCHARDWARE
;
653 struct DSBufferGroup
*bufgroup
= This
->BufferGroups
;
657 for(i
= 0;i
< This
->NumBufferGroups
;++i
)
659 DWORD64 usemask
= ~bufgroup
[i
].FreeBuffers
;
662 int idx
= CTZ64(usemask
);
663 DSBuffer
*buf
= bufgroup
[i
].Buffers
+ idx
;
664 usemask
&= ~(U64(1) << idx
);
666 hr
= DSBuffer_GetStatus(&buf
->IDirectSoundBuffer8_iface
, &state
);
667 if(SUCCEEDED(hr
) && (state
&DSBSTATUS_PLAYING
)) break;
670 if(!(state
&DSBSTATUS_PLAYING
))
672 /* Primary stopped and no buffers playing.. */
676 LeaveCriticalSection(&This
->share
->crst
);
681 HRESULT WINAPI
DSPrimary_Initialize(IDirectSoundBuffer
*iface
, IDirectSound
*ds
, const DSBUFFERDESC
*desc
)
683 DSPrimary
*This
= impl_from_IDirectSoundBuffer(iface
);
686 TRACE("(%p)->(%p, %p)\n", iface
, ds
, desc
);
688 if(!desc
|| desc
->lpwfxFormat
|| desc
->dwBufferBytes
)
690 WARN("Bad DSBDESC for primary buffer\n");
691 return DSERR_INVALIDPARAM
;
693 if((desc
->dwFlags
&DSBCAPS_CTRLFX
) ||
694 (desc
->dwFlags
&DSBCAPS_CTRLPOSITIONNOTIFY
) ||
695 (desc
->dwFlags
&DSBCAPS_LOCSOFTWARE
))
697 WARN("Bad dwFlags %08lx\n", desc
->dwFlags
);
698 return DSERR_INVALIDPARAM
;
701 /* Should be 0 if not initialized */
703 return DSERR_ALREADYINITIALIZED
;
706 if(This
->parent
->prio_level
== DSSCL_WRITEPRIMARY
)
708 DSBUFFERDESC emudesc
;
713 ERR("There shouldn't be a write_emu!\n");
714 IDirectSoundBuffer_Release(This
->write_emu
);
715 This
->write_emu
= NULL
;
718 memset(&emudesc
, 0, sizeof(emudesc
));
719 emudesc
.dwSize
= sizeof(emudesc
);
720 emudesc
.dwFlags
= DSBCAPS_LOCHARDWARE
| (desc
->dwFlags
&DSBCAPS_CTRLPAN
);
721 /* Dont play last incomplete sample */
722 emudesc
.dwBufferBytes
= This
->buf_size
- (This
->buf_size
%This
->format
.Format
.nBlockAlign
);
723 emudesc
.lpwfxFormat
= &This
->format
.Format
;
725 hr
= DSBuffer_Create(&emu
, This
, NULL
);
728 hr
= DSBuffer_Initialize(&emu
->IDirectSoundBuffer8_iface
, ds
, &emudesc
);
730 hr
= DSBuffer_GetInterface(emu
, &IID_IDirectSoundBuffer
, (void**)&This
->write_emu
);
732 DSBuffer_Destroy(emu
);
738 This
->current
.ds3d
.dwSize
= sizeof(This
->current
.ds3d
);
739 This
->current
.ds3d
.vPosition
.x
= 0.0f
;
740 This
->current
.ds3d
.vPosition
.y
= 0.0f
;
741 This
->current
.ds3d
.vPosition
.z
= 0.0f
;
742 This
->current
.ds3d
.vVelocity
.x
= 0.0f
;
743 This
->current
.ds3d
.vVelocity
.y
= 0.0f
;
744 This
->current
.ds3d
.vVelocity
.z
= 0.0f
;
745 This
->current
.ds3d
.vOrientFront
.x
= 0.0f
;
746 This
->current
.ds3d
.vOrientFront
.y
= 0.0f
;
747 This
->current
.ds3d
.vOrientFront
.z
= 1.0f
;
748 This
->current
.ds3d
.vOrientTop
.x
= 0.0f
;
749 This
->current
.ds3d
.vOrientTop
.y
= 1.0f
;
750 This
->current
.ds3d
.vOrientTop
.z
= 0.0f
;
751 This
->current
.ds3d
.flDistanceFactor
= DS3D_DEFAULTDISTANCEFACTOR
;
752 This
->current
.ds3d
.flRolloffFactor
= DS3D_DEFAULTROLLOFFFACTOR
;
753 This
->current
.ds3d
.flDopplerFactor
= DS3D_DEFAULTDOPPLERFACTOR
;
754 This
->deferred
.ds3d
= This
->current
.ds3d
;
756 This
->flags
= desc
->dwFlags
| DSBCAPS_LOCHARDWARE
;
758 if((This
->flags
&DSBCAPS_CTRL3D
))
760 union PrimaryParamFlags dirty
= { 0l };
764 dirty
.bit
.orientation
= 1;
765 dirty
.bit
.distancefactor
= 1;
766 dirty
.bit
.rollofffactor
= 1;
767 dirty
.bit
.dopplerfactor
= 1;
768 DSPrimary_SetParams(This
, &This
->deferred
.ds3d
, dirty
.flags
);
774 static HRESULT WINAPI
DSPrimary_Lock(IDirectSoundBuffer
*iface
, DWORD ofs
, DWORD bytes
, void **ptr1
, DWORD
*len1
, void **ptr2
, DWORD
*len2
, DWORD flags
)
776 DSPrimary
*This
= impl_from_IDirectSoundBuffer(iface
);
777 HRESULT hr
= DSERR_PRIOLEVELNEEDED
;
779 TRACE("(%p)->(%lu, %lu, %p, %p, %p, %p, %lu)\n", iface
, ofs
, bytes
, ptr1
, len1
, ptr2
, len2
, flags
);
781 EnterCriticalSection(&This
->share
->crst
);
783 hr
= IDirectSoundBuffer_Lock(This
->write_emu
, ofs
, bytes
, ptr1
, len1
, ptr2
, len2
, flags
);
784 LeaveCriticalSection(&This
->share
->crst
);
789 static HRESULT WINAPI
DSPrimary_Play(IDirectSoundBuffer
*iface
, DWORD res1
, DWORD res2
, DWORD flags
)
791 DSPrimary
*This
= impl_from_IDirectSoundBuffer(iface
);
794 TRACE("(%p)->(%lu, %lu, %lu)\n", iface
, res1
, res2
, flags
);
796 if(!(flags
& DSBPLAY_LOOPING
))
798 WARN("Flags (%08lx) not set to DSBPLAY_LOOPING\n", flags
);
799 return DSERR_INVALIDPARAM
;
802 EnterCriticalSection(&This
->share
->crst
);
805 hr
= IDirectSoundBuffer_Play(This
->write_emu
, res1
, res2
, flags
);
807 This
->stopped
= FALSE
;
808 LeaveCriticalSection(&This
->share
->crst
);
813 static HRESULT WINAPI
DSPrimary_SetCurrentPosition(IDirectSoundBuffer
*iface
, DWORD pos
)
815 WARN("(%p)->(%lu)\n", iface
, pos
);
816 return DSERR_INVALIDCALL
;
819 /* Just assume the format is crap, and clean up the damage */
820 static HRESULT
copy_waveformat(WAVEFORMATEX
*wfx
, const WAVEFORMATEX
*from
)
822 if(from
->nChannels
<= 0)
824 WARN("Invalid Channels %d\n", from
->nChannels
);
825 return DSERR_INVALIDPARAM
;
827 if(from
->nSamplesPerSec
< DSBFREQUENCY_MIN
|| from
->nSamplesPerSec
> DSBFREQUENCY_MAX
)
829 WARN("Invalid SamplesPerSec %lu\n", from
->nSamplesPerSec
);
830 return DSERR_INVALIDPARAM
;
832 if(from
->nBlockAlign
<= 0)
834 WARN("Invalid BlockAlign %d\n", from
->nBlockAlign
);
835 return DSERR_INVALIDPARAM
;
837 if(from
->wBitsPerSample
== 0 || (from
->wBitsPerSample
%8) != 0)
839 WARN("Invalid BitsPerSample %d\n", from
->wBitsPerSample
);
840 return DSERR_INVALIDPARAM
;
842 if(from
->nBlockAlign
!= from
->nChannels
*from
->wBitsPerSample
/8)
844 WARN("Invalid BlockAlign %d (expected %u = %u*%u/8)\n",
845 from
->nBlockAlign
, from
->nChannels
*from
->wBitsPerSample
/8,
846 from
->nChannels
, from
->wBitsPerSample
);
847 return DSERR_INVALIDPARAM
;
849 if(from
->nAvgBytesPerSec
!= from
->nBlockAlign
*from
->nSamplesPerSec
)
851 WARN("Invalid AvgBytesPerSec %lu (expected %lu = %lu*%u)\n",
852 from
->nAvgBytesPerSec
, from
->nSamplesPerSec
*from
->nBlockAlign
,
853 from
->nSamplesPerSec
, from
->nBlockAlign
);
854 return DSERR_INVALIDPARAM
;
857 if(from
->wFormatTag
== WAVE_FORMAT_PCM
)
859 if(from
->wBitsPerSample
> 32)
860 return DSERR_INVALIDPARAM
;
863 else if(from
->wFormatTag
== WAVE_FORMAT_IEEE_FLOAT
)
865 if(from
->wBitsPerSample
!= 32)
866 return DSERR_INVALIDPARAM
;
869 else if(from
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
871 WAVEFORMATEXTENSIBLE
*wfe
= (WAVEFORMATEXTENSIBLE
*)wfx
;
872 const WAVEFORMATEXTENSIBLE
*fromx
= (const WAVEFORMATEXTENSIBLE
*)from
;
873 const WORD size
= sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
);
875 /* Fail silently.. */
876 if(from
->cbSize
< size
) return DS_OK
;
877 if(fromx
->Samples
.wValidBitsPerSample
> fromx
->Format
.wBitsPerSample
)
878 return DSERR_INVALIDPARAM
;
880 if(IsEqualGUID(&fromx
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
))
882 if(from
->wBitsPerSample
> 32)
883 return DSERR_INVALIDPARAM
;
885 else if(IsEqualGUID(&fromx
->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
))
887 if(from
->wBitsPerSample
!= 32)
888 return DSERR_INVALIDPARAM
;
892 ERR("Unhandled extensible format: %s\n", debugstr_guid(&fromx
->SubFormat
));
893 return DSERR_INVALIDPARAM
;
896 wfe
->Format
.cbSize
= size
;
897 wfe
->Samples
.wValidBitsPerSample
= fromx
->Samples
.wValidBitsPerSample
;
898 if(!wfe
->Samples
.wValidBitsPerSample
)
899 wfe
->Samples
.wValidBitsPerSample
= fromx
->Format
.wBitsPerSample
;
900 wfe
->dwChannelMask
= fromx
->dwChannelMask
;
901 wfe
->SubFormat
= fromx
->SubFormat
;
905 ERR("Unhandled format tag %04x\n", from
->wFormatTag
);
906 return DSERR_INVALIDPARAM
;
909 wfx
->wFormatTag
= from
->wFormatTag
;
910 wfx
->nChannels
= from
->nChannels
;
911 wfx
->nSamplesPerSec
= from
->nSamplesPerSec
;
912 wfx
->nAvgBytesPerSec
= from
->nSamplesPerSec
* from
->nBlockAlign
;
913 wfx
->nBlockAlign
= from
->wBitsPerSample
* from
->nChannels
/ 8;
914 wfx
->wBitsPerSample
= from
->wBitsPerSample
;
918 static HRESULT WINAPI
DSPrimary_SetFormat(IDirectSoundBuffer
*iface
, const WAVEFORMATEX
*wfx
)
920 DSPrimary
*This
= impl_from_IDirectSoundBuffer(iface
);
923 TRACE("(%p)->(%p)\n", iface
, wfx
);
927 WARN("Missing format\n");
928 return DSERR_INVALIDPARAM
;
931 EnterCriticalSection(&This
->share
->crst
);
933 if(This
->parent
->prio_level
< DSSCL_PRIORITY
)
935 hr
= DSERR_PRIOLEVELNEEDED
;
939 TRACE("Requested primary format:\n"
940 " FormatTag = %04x\n"
942 " SamplesPerSec = %lu\n"
943 " AvgBytesPerSec = %lu\n"
945 " BitsPerSample = %u\n",
946 wfx
->wFormatTag
, wfx
->nChannels
,
947 wfx
->nSamplesPerSec
, wfx
->nAvgBytesPerSec
,
948 wfx
->nBlockAlign
, wfx
->wBitsPerSample
);
950 hr
= copy_waveformat(&This
->format
.Format
, wfx
);
951 if(SUCCEEDED(hr
) && This
->write_emu
)
956 IDirectSoundBuffer_Release(This
->write_emu
);
957 This
->write_emu
= NULL
;
959 memset(&desc
, 0, sizeof(desc
));
960 desc
.dwSize
= sizeof(desc
);
961 desc
.dwFlags
= DSBCAPS_LOCHARDWARE
| DSBCAPS_CTRLPAN
;
962 desc
.dwBufferBytes
= This
->buf_size
- (This
->buf_size
% This
->format
.Format
.nBlockAlign
);
963 desc
.lpwfxFormat
= &This
->format
.Format
;
965 hr
= DSBuffer_Create(&buf
, This
, NULL
);
968 hr
= DSBuffer_Initialize(&buf
->IDirectSoundBuffer8_iface
,
969 &This
->parent
->IDirectSound_iface
, &desc
);
971 hr
= DSBuffer_GetInterface(buf
, &IID_IDirectSoundBuffer
, (void**)&This
->write_emu
);
973 DSBuffer_Destroy(buf
);
978 LeaveCriticalSection(&This
->share
->crst
);
982 static HRESULT WINAPI
DSPrimary_SetVolume(IDirectSoundBuffer
*iface
, LONG vol
)
984 DSPrimary
*This
= impl_from_IDirectSoundBuffer(iface
);
986 TRACE("(%p)->(%ld)\n", iface
, vol
);
988 if(vol
> DSBVOLUME_MAX
|| vol
< DSBVOLUME_MIN
)
990 WARN("Invalid volume (%ld)\n", vol
);
991 return DSERR_INVALIDPARAM
;
994 if(!(This
->flags
&DSBCAPS_CTRLVOLUME
))
995 return DSERR_CONTROLUNAVAIL
;
997 setALContext(This
->ctx
);
998 alListenerf(AL_GAIN
, mB_to_gain(vol
));
1004 static HRESULT WINAPI
DSPrimary_SetPan(IDirectSoundBuffer
*iface
, LONG pan
)
1006 DSPrimary
*This
= impl_from_IDirectSoundBuffer(iface
);
1009 TRACE("(%p)->(%ld)\n", iface
, pan
);
1011 if(pan
> DSBPAN_RIGHT
|| pan
< DSBPAN_LEFT
)
1013 WARN("invalid parameter: pan = %ld\n", pan
);
1014 return DSERR_INVALIDPARAM
;
1017 EnterCriticalSection(&This
->share
->crst
);
1018 if(!(This
->flags
&DSBCAPS_CTRLPAN
))
1020 WARN("control unavailable\n");
1021 hr
= DSERR_CONTROLUNAVAIL
;
1023 else if(This
->write_emu
)
1024 hr
= IDirectSoundBuffer_SetPan(This
->write_emu
, pan
);
1027 FIXME("Not supported\n");
1030 LeaveCriticalSection(&This
->share
->crst
);
1035 static HRESULT WINAPI
DSPrimary_SetFrequency(IDirectSoundBuffer
*iface
, DWORD freq
)
1037 WARN("(%p)->(%lu)\n", iface
, freq
);
1038 return DSERR_CONTROLUNAVAIL
;
1041 static HRESULT WINAPI
DSPrimary_Stop(IDirectSoundBuffer
*iface
)
1043 DSPrimary
*This
= impl_from_IDirectSoundBuffer(iface
);
1046 TRACE("(%p)->()\n", iface
);
1048 EnterCriticalSection(&This
->share
->crst
);
1050 hr
= IDirectSoundBuffer_Stop(This
->write_emu
);
1052 This
->stopped
= TRUE
;
1053 LeaveCriticalSection(&This
->share
->crst
);
1058 static HRESULT WINAPI
DSPrimary_Unlock(IDirectSoundBuffer
*iface
, void *ptr1
, DWORD len1
, void *ptr2
, DWORD len2
)
1060 DSPrimary
*This
= impl_from_IDirectSoundBuffer(iface
);
1061 HRESULT hr
= DSERR_INVALIDCALL
;
1063 TRACE("(%p)->(%p, %lu, %p, %lu)\n", iface
, ptr1
, len1
, ptr2
, len2
);
1065 EnterCriticalSection(&This
->share
->crst
);
1067 hr
= IDirectSoundBuffer_Unlock(This
->write_emu
, ptr1
, len1
, ptr2
, len2
);
1068 LeaveCriticalSection(&This
->share
->crst
);
1073 static HRESULT WINAPI
DSPrimary_Restore(IDirectSoundBuffer
*iface
)
1075 DSPrimary
*This
= impl_from_IDirectSoundBuffer(iface
);
1078 TRACE("(%p)->()\n", iface
);
1080 EnterCriticalSection(&This
->share
->crst
);
1082 hr
= IDirectSoundBuffer_Restore(This
->write_emu
);
1083 LeaveCriticalSection(&This
->share
->crst
);
1088 static const IDirectSoundBufferVtbl DSPrimary_Vtbl
=
1090 DSPrimary_QueryInterface
,
1094 DSPrimary_GetCurrentPosition
,
1095 DSPrimary_GetFormat
,
1096 DSPrimary_GetVolume
,
1098 DSPrimary_GetFrequency
,
1099 DSPrimary_GetStatus
,
1100 DSPrimary_Initialize
,
1103 DSPrimary_SetCurrentPosition
,
1104 DSPrimary_SetFormat
,
1105 DSPrimary_SetVolume
,
1107 DSPrimary_SetFrequency
,
1114 static void DSPrimary_SetParams(DSPrimary
*This
, const DS3DLISTENER
*params
, LONG flags
)
1116 union PrimaryParamFlags dirty
= { flags
};
1120 This
->current
.ds3d
.vPosition
= params
->vPosition
;
1122 This
->current
.ds3d
.vVelocity
= params
->vVelocity
;
1123 if(dirty
.bit
.orientation
)
1125 This
->current
.ds3d
.vOrientFront
= params
->vOrientFront
;
1126 This
->current
.ds3d
.vOrientTop
= params
->vOrientTop
;
1128 if(dirty
.bit
.distancefactor
)
1129 This
->current
.ds3d
.flDistanceFactor
= params
->flDistanceFactor
;
1130 if(dirty
.bit
.rollofffactor
)
1131 This
->current
.ds3d
.flRolloffFactor
= params
->flRolloffFactor
;
1132 if(dirty
.bit
.dopplerfactor
)
1133 This
->current
.ds3d
.flDopplerFactor
= params
->flDopplerFactor
;
1134 /* Always copy EAX params (they're always set deferred first, then applied
1135 * when committing all params).
1137 This
->current
.ctx
= This
->deferred
.ctx
;
1138 for(i
= 0;i
< EAX_MAX_FXSLOTS
;++i
)
1139 This
->current
.fxslot
[i
] = This
->deferred
.fxslot
[i
];
1140 This
->current
.eax1_volume
= This
->deferred
.eax1_volume
;
1141 This
->current
.eax1_dampening
= This
->deferred
.eax1_dampening
;
1144 alListener3f(AL_POSITION
, params
->vPosition
.x
, params
->vPosition
.y
,
1145 -params
->vPosition
.z
);
1147 alListener3f(AL_VELOCITY
, params
->vVelocity
.x
, params
->vVelocity
.y
,
1148 -params
->vVelocity
.z
);
1149 if(dirty
.bit
.orientation
)
1151 ALfloat orient
[6] = {
1152 params
->vOrientFront
.x
, params
->vOrientFront
.y
, -params
->vOrientFront
.z
,
1153 params
->vOrientTop
.x
, params
->vOrientTop
.y
, -params
->vOrientTop
.z
1155 alListenerfv(AL_ORIENTATION
, orient
);
1157 if(dirty
.bit
.distancefactor
)
1159 alSpeedOfSound(343.3f
/params
->flDistanceFactor
);
1160 if(HAS_EXTENSION(This
->share
, EXT_EFX
))
1161 alListenerf(AL_METERS_PER_UNIT
, params
->flDistanceFactor
);
1163 if(dirty
.bit
.rollofffactor
)
1165 struct DSBufferGroup
*bufgroup
= This
->BufferGroups
;
1166 ALfloat rolloff
= params
->flRolloffFactor
;
1168 for(i
= 0;i
< This
->NumBufferGroups
;++i
)
1170 DWORD64 usemask
= ~bufgroup
[i
].FreeBuffers
;
1173 int idx
= CTZ64(usemask
);
1174 DSBuffer
*buf
= bufgroup
[i
].Buffers
+ idx
;
1175 usemask
&= ~(U64(1) << idx
);
1178 alSourcef(buf
->source
, AL_ROLLOFF_FACTOR
,
1179 buf
->current
.eax
.flRolloffFactor
+ rolloff
);
1183 if(dirty
.bit
.dopplerfactor
)
1184 alDopplerFactor(params
->flDopplerFactor
);
1186 if(dirty
.bit
.prim_slotid
)
1188 struct DSBufferGroup
*bufgroup
= This
->BufferGroups
;
1191 if(IsEqualGUID(&This
->current
.ctx
.guidPrimaryFXSlotID
, &EAXPROPERTYID_EAX40_FXSlot0
))
1192 This
->primary_slot
= This
->auxslot
[0];
1193 else if(IsEqualGUID(&This
->current
.ctx
.guidPrimaryFXSlotID
, &EAXPROPERTYID_EAX40_FXSlot1
))
1194 This
->primary_slot
= This
->auxslot
[1];
1195 else if(IsEqualGUID(&This
->current
.ctx
.guidPrimaryFXSlotID
, &EAXPROPERTYID_EAX40_FXSlot2
))
1196 This
->primary_slot
= This
->auxslot
[2];
1197 else if(IsEqualGUID(&This
->current
.ctx
.guidPrimaryFXSlotID
, &EAXPROPERTYID_EAX40_FXSlot3
))
1198 This
->primary_slot
= This
->auxslot
[3];
1199 else /*if(IsEqualGUID(&This->current.ctx.guidPrimaryFXSlotID, &EAX_NULL_GUID))*/
1200 This
->primary_slot
= 0;
1201 slot
= This
->primary_slot
;
1203 for(i
= 0;i
< This
->NumBufferGroups
;++i
)
1205 DWORD64 usemask
= ~bufgroup
[i
].FreeBuffers
;
1208 int idx
= CTZ64(usemask
);
1209 DSBuffer
*buf
= bufgroup
[i
].Buffers
+ idx
;
1210 DSData
*data
= buf
->buffer
;
1211 usemask
&= ~(U64(1) << idx
);
1213 if(buf
->source
&& (data
->dsbflags
&DSBCAPS_CTRL3D
))
1215 if(buf
->current
.fxslot_targets
[0] == FXSLOT_TARGET_PRIMARY
)
1216 alSource3i(buf
->source
, AL_AUXILIARY_SEND_FILTER
, slot
, 0, buf
->filter
[1]);
1217 if(buf
->current
.fxslot_targets
[1] == FXSLOT_TARGET_PRIMARY
)
1218 alSource3i(buf
->source
, AL_AUXILIARY_SEND_FILTER
, slot
, 1, buf
->filter
[2]);
1223 if(dirty
.bit
.distancefactor2
) {
1224 /* TODO: Find out what this affects. */
1226 if(dirty
.bit
.air_absorbhf
)
1228 struct DSBufferGroup
*bufgroup
= This
->BufferGroups
;
1229 ALfloat mult
= This
->current
.ctx
.flAirAbsorptionHF
/ -5.0f
;
1231 for(i
= 0;i
< This
->NumBufferGroups
;++i
)
1233 DWORD64 usemask
= ~bufgroup
[i
].FreeBuffers
;
1236 int idx
= CTZ64(usemask
);
1237 DSBuffer
*buf
= bufgroup
[i
].Buffers
+ idx
;
1238 DSData
*data
= buf
->buffer
;
1239 usemask
&= ~(U64(1) << idx
);
1241 if(buf
->source
&& (data
->dsbflags
&DSBCAPS_CTRL3D
))
1242 alSourcef(buf
->source
, AL_AIR_ABSORPTION_FACTOR
,
1243 clampF(buf
->current
.eax
.flAirAbsorptionFactor
*mult
, 0.0f
, 10.0f
)
1248 if(dirty
.bit
.hfreference
) {
1249 /* NOTE: Not currently handlable in OpenAL. */
1252 if(dirty
.bit
.fxslots
)
1254 for(i
= 0;i
< EAX_MAX_FXSLOTS
;++i
)
1256 ALuint slot
= This
->auxslot
[i
];
1257 if(FXSLOT_IS_DIRTY(dirty
.bit
, i
, FXSLOT_EFFECT_BIT
))
1258 alAuxiliaryEffectSloti(slot
, AL_EFFECTSLOT_EFFECT
, This
->effect
[i
]);
1259 if(FXSLOT_IS_DIRTY(dirty
.bit
, i
, FXSLOT_VOL_BIT
))
1260 alAuxiliaryEffectSlotf(slot
, AL_EFFECTSLOT_GAIN
,
1261 mB_to_gain(This
->current
.fxslot
[i
].props
.lVolume
)
1263 if(FXSLOT_IS_DIRTY(dirty
.bit
, i
, FXSLOT_FLAGS_BIT
))
1264 alAuxiliaryEffectSloti(slot
, AL_EFFECTSLOT_AUXILIARY_SEND_AUTO
,
1265 (This
->current
.fxslot
[i
].props
.dwFlags
&EAXFXSLOTFLAGS_ENVIRONMENT
) ?
1272 static HRESULT WINAPI
DSPrimary3D_QueryInterface(IDirectSound3DListener
*iface
, REFIID riid
, void **ppv
)
1274 DSPrimary
*This
= impl_from_IDirectSound3DListener(iface
);
1275 return DSPrimary_QueryInterface(&This
->IDirectSoundBuffer_iface
, riid
, ppv
);
1278 static ULONG WINAPI
DSPrimary3D_AddRef(IDirectSound3DListener
*iface
)
1280 DSPrimary
*This
= impl_from_IDirectSound3DListener(iface
);
1283 ret
= InterlockedIncrement(&This
->ds3d_ref
);
1284 TRACE("(%p) ref %lu\n", iface
, ret
);
1289 static ULONG WINAPI
DSPrimary3D_Release(IDirectSound3DListener
*iface
)
1291 DSPrimary
*This
= impl_from_IDirectSound3DListener(iface
);
1294 ret
= InterlockedDecrement(&This
->ds3d_ref
);
1295 TRACE("(%p) ref %lu\n", iface
, ret
);
1301 static HRESULT WINAPI
DSPrimary3D_GetDistanceFactor(IDirectSound3DListener
*iface
, D3DVALUE
*distancefactor
)
1303 DSPrimary
*This
= impl_from_IDirectSound3DListener(iface
);
1305 TRACE("(%p)->(%p)\n", iface
, distancefactor
);
1309 WARN("Invalid parameter %p\n", distancefactor
);
1310 return DSERR_INVALIDPARAM
;
1313 *distancefactor
= This
->current
.ds3d
.flDistanceFactor
;
1317 static HRESULT WINAPI
DSPrimary3D_GetDopplerFactor(IDirectSound3DListener
*iface
, D3DVALUE
*dopplerfactor
)
1319 DSPrimary
*This
= impl_from_IDirectSound3DListener(iface
);
1321 TRACE("(%p)->(%p)\n", iface
, dopplerfactor
);
1325 WARN("Invalid parameter %p\n", dopplerfactor
);
1326 return DSERR_INVALIDPARAM
;
1329 *dopplerfactor
= This
->current
.ds3d
.flDopplerFactor
;
1333 static HRESULT WINAPI
DSPrimary3D_GetOrientation(IDirectSound3DListener
*iface
, D3DVECTOR
*front
, D3DVECTOR
*top
)
1335 DSPrimary
*This
= impl_from_IDirectSound3DListener(iface
);
1337 TRACE("(%p)->(%p, %p)\n", iface
, front
, top
);
1341 WARN("Invalid parameter %p %p\n", front
, top
);
1342 return DSERR_INVALIDPARAM
;
1345 EnterCriticalSection(&This
->share
->crst
);
1346 *front
= This
->current
.ds3d
.vOrientFront
;
1347 *top
= This
->current
.ds3d
.vOrientTop
;
1348 LeaveCriticalSection(&This
->share
->crst
);
1352 static HRESULT WINAPI
DSPrimary3D_GetPosition(IDirectSound3DListener
*iface
, D3DVECTOR
*pos
)
1354 DSPrimary
*This
= impl_from_IDirectSound3DListener(iface
);
1356 TRACE("(%p)->(%p)\n", iface
, pos
);
1360 WARN("Invalid parameter %p\n", pos
);
1361 return DSERR_INVALIDPARAM
;
1364 EnterCriticalSection(&This
->share
->crst
);
1365 *pos
= This
->current
.ds3d
.vPosition
;
1366 LeaveCriticalSection(&This
->share
->crst
);
1370 static HRESULT WINAPI
DSPrimary3D_GetRolloffFactor(IDirectSound3DListener
*iface
, D3DVALUE
*rollofffactor
)
1372 DSPrimary
*This
= impl_from_IDirectSound3DListener(iface
);
1374 TRACE("(%p)->(%p)\n", iface
, rollofffactor
);
1378 WARN("Invalid parameter %p\n", rollofffactor
);
1379 return DSERR_INVALIDPARAM
;
1382 *rollofffactor
= This
->current
.ds3d
.flRolloffFactor
;
1386 static HRESULT WINAPI
DSPrimary3D_GetVelocity(IDirectSound3DListener
*iface
, D3DVECTOR
*velocity
)
1388 DSPrimary
*This
= impl_from_IDirectSound3DListener(iface
);
1390 TRACE("(%p)->(%p)\n", iface
, velocity
);
1394 WARN("Invalid parameter %p\n", velocity
);
1395 return DSERR_INVALIDPARAM
;
1398 EnterCriticalSection(&This
->share
->crst
);
1399 *velocity
= This
->current
.ds3d
.vVelocity
;
1400 LeaveCriticalSection(&This
->share
->crst
);
1404 static HRESULT WINAPI
DSPrimary3D_GetAllParameters(IDirectSound3DListener
*iface
, DS3DLISTENER
*listener
)
1406 DSPrimary
*This
= impl_from_IDirectSound3DListener(iface
);
1408 TRACE("(%p)->(%p)\n", iface
, listener
);
1410 if(!listener
|| listener
->dwSize
< sizeof(*listener
))
1412 WARN("Invalid DS3DLISTENER %p %lu\n", listener
, listener
? listener
->dwSize
: 0);
1413 return DSERR_INVALIDPARAM
;
1416 EnterCriticalSection(&This
->share
->crst
);
1417 listener
->vPosition
= This
->current
.ds3d
.vPosition
;
1418 listener
->vVelocity
= This
->current
.ds3d
.vVelocity
;
1419 listener
->vOrientFront
= This
->current
.ds3d
.vOrientFront
;
1420 listener
->vOrientTop
= This
->current
.ds3d
.vOrientTop
;
1421 listener
->flDistanceFactor
= This
->current
.ds3d
.flDistanceFactor
;
1422 listener
->flRolloffFactor
= This
->current
.ds3d
.flRolloffFactor
;
1423 listener
->flDopplerFactor
= This
->current
.ds3d
.flDopplerFactor
;
1424 LeaveCriticalSection(&This
->share
->crst
);
1430 static HRESULT WINAPI
DSPrimary3D_SetDistanceFactor(IDirectSound3DListener
*iface
, D3DVALUE factor
, DWORD apply
)
1432 DSPrimary
*This
= impl_from_IDirectSound3DListener(iface
);
1434 TRACE("(%p)->(%f, %lu)\n", iface
, factor
, apply
);
1436 if(factor
< DS3D_MINDISTANCEFACTOR
||
1437 factor
> DS3D_MAXDISTANCEFACTOR
)
1439 WARN("Invalid parameter %f\n", factor
);
1440 return DSERR_INVALIDPARAM
;
1443 EnterCriticalSection(&This
->share
->crst
);
1444 if(apply
== DS3D_DEFERRED
)
1446 This
->deferred
.ds3d
.flDistanceFactor
= factor
;
1447 This
->dirty
.bit
.distancefactor
= 1;
1451 setALContext(This
->ctx
);
1452 This
->current
.ds3d
.flDistanceFactor
= factor
;
1453 alSpeedOfSound(343.3f
/factor
);
1454 if(HAS_EXTENSION(This
->share
, EXT_EFX
))
1455 alListenerf(AL_METERS_PER_UNIT
, factor
);
1459 LeaveCriticalSection(&This
->share
->crst
);
1464 static HRESULT WINAPI
DSPrimary3D_SetDopplerFactor(IDirectSound3DListener
*iface
, D3DVALUE factor
, DWORD apply
)
1466 DSPrimary
*This
= impl_from_IDirectSound3DListener(iface
);
1468 TRACE("(%p)->(%f, %lu)\n", iface
, factor
, apply
);
1470 if(factor
< DS3D_MINDOPPLERFACTOR
||
1471 factor
> DS3D_MAXDOPPLERFACTOR
)
1473 WARN("Invalid parameter %f\n", factor
);
1474 return DSERR_INVALIDPARAM
;
1477 EnterCriticalSection(&This
->share
->crst
);
1478 if(apply
== DS3D_DEFERRED
)
1480 This
->deferred
.ds3d
.flDopplerFactor
= factor
;
1481 This
->dirty
.bit
.dopplerfactor
= 1;
1485 setALContext(This
->ctx
);
1486 This
->current
.ds3d
.flDopplerFactor
= factor
;
1487 alDopplerFactor(factor
);
1491 LeaveCriticalSection(&This
->share
->crst
);
1496 static HRESULT WINAPI
DSPrimary3D_SetOrientation(IDirectSound3DListener
*iface
, D3DVALUE xFront
, D3DVALUE yFront
, D3DVALUE zFront
, D3DVALUE xTop
, D3DVALUE yTop
, D3DVALUE zTop
, DWORD apply
)
1498 DSPrimary
*This
= impl_from_IDirectSound3DListener(iface
);
1500 TRACE("(%p)->(%f, %f, %f, %f, %f, %f, %lu)\n", iface
, xFront
, yFront
, zFront
, xTop
, yTop
, zTop
, apply
);
1502 EnterCriticalSection(&This
->share
->crst
);
1503 if(apply
== DS3D_DEFERRED
)
1505 This
->deferred
.ds3d
.vOrientFront
.x
= xFront
;
1506 This
->deferred
.ds3d
.vOrientFront
.y
= yFront
;
1507 This
->deferred
.ds3d
.vOrientFront
.z
= zFront
;
1508 This
->deferred
.ds3d
.vOrientTop
.x
= xTop
;
1509 This
->deferred
.ds3d
.vOrientTop
.y
= yTop
;
1510 This
->deferred
.ds3d
.vOrientTop
.z
= zTop
;
1511 This
->dirty
.bit
.orientation
= 1;
1515 ALfloat orient
[6] = {
1516 xFront
, yFront
, -zFront
,
1519 This
->current
.ds3d
.vOrientFront
.x
= xFront
;
1520 This
->current
.ds3d
.vOrientFront
.y
= yFront
;
1521 This
->current
.ds3d
.vOrientFront
.z
= zFront
;
1522 This
->current
.ds3d
.vOrientTop
.x
= xTop
;
1523 This
->current
.ds3d
.vOrientTop
.y
= yTop
;
1524 This
->current
.ds3d
.vOrientTop
.z
= zTop
;
1526 setALContext(This
->ctx
);
1527 alListenerfv(AL_ORIENTATION
, orient
);
1531 LeaveCriticalSection(&This
->share
->crst
);
1536 static HRESULT WINAPI
DSPrimary3D_SetPosition(IDirectSound3DListener
*iface
, D3DVALUE x
, D3DVALUE y
, D3DVALUE z
, DWORD apply
)
1538 DSPrimary
*This
= impl_from_IDirectSound3DListener(iface
);
1540 TRACE("(%p)->(%f, %f, %f, %lu)\n", iface
, x
, y
, z
, apply
);
1542 EnterCriticalSection(&This
->share
->crst
);
1543 if(apply
== DS3D_DEFERRED
)
1545 This
->deferred
.ds3d
.vPosition
.x
= x
;
1546 This
->deferred
.ds3d
.vPosition
.y
= y
;
1547 This
->deferred
.ds3d
.vPosition
.z
= z
;
1548 This
->dirty
.bit
.pos
= 1;
1552 setALContext(This
->ctx
);
1553 This
->current
.ds3d
.vPosition
.x
= x
;
1554 This
->current
.ds3d
.vPosition
.y
= y
;
1555 This
->current
.ds3d
.vPosition
.z
= z
;
1556 alListener3f(AL_POSITION
, x
, y
, -z
);
1560 LeaveCriticalSection(&This
->share
->crst
);
1565 static HRESULT WINAPI
DSPrimary3D_SetRolloffFactor(IDirectSound3DListener
*iface
, D3DVALUE factor
, DWORD apply
)
1567 DSPrimary
*This
= impl_from_IDirectSound3DListener(iface
);
1569 TRACE("(%p)->(%f, %lu)\n", iface
, factor
, apply
);
1571 if(factor
< DS3D_MINROLLOFFFACTOR
||
1572 factor
> DS3D_MAXROLLOFFFACTOR
)
1574 WARN("Invalid parameter %f\n", factor
);
1575 return DSERR_INVALIDPARAM
;
1578 EnterCriticalSection(&This
->share
->crst
);
1579 if(apply
== DS3D_DEFERRED
)
1581 This
->deferred
.ds3d
.flRolloffFactor
= factor
;
1582 This
->dirty
.bit
.rollofffactor
= 1;
1586 struct DSBufferGroup
*bufgroup
= This
->BufferGroups
;
1589 This
->current
.ds3d
.flRolloffFactor
= factor
;
1591 setALContext(This
->ctx
);
1592 for(i
= 0;i
< This
->NumBufferGroups
;++i
)
1594 DWORD64 usemask
= ~bufgroup
[i
].FreeBuffers
;
1597 int idx
= CTZ64(usemask
);
1598 DSBuffer
*buf
= bufgroup
[i
].Buffers
+ idx
;
1599 usemask
&= ~(U64(1) << idx
);
1602 alSourcef(buf
->source
, AL_ROLLOFF_FACTOR
,
1603 buf
->current
.eax
.flRolloffFactor
+ factor
);
1609 LeaveCriticalSection(&This
->share
->crst
);
1614 static HRESULT WINAPI
DSPrimary3D_SetVelocity(IDirectSound3DListener
*iface
, D3DVALUE x
, D3DVALUE y
, D3DVALUE z
, DWORD apply
)
1616 DSPrimary
*This
= impl_from_IDirectSound3DListener(iface
);
1618 TRACE("(%p)->(%f, %f, %f, %lu)\n", iface
, x
, y
, z
, apply
);
1620 EnterCriticalSection(&This
->share
->crst
);
1621 if(apply
== DS3D_DEFERRED
)
1623 This
->deferred
.ds3d
.vVelocity
.x
= x
;
1624 This
->deferred
.ds3d
.vVelocity
.y
= y
;
1625 This
->deferred
.ds3d
.vVelocity
.z
= z
;
1626 This
->dirty
.bit
.vel
= 1;
1630 setALContext(This
->ctx
);
1631 This
->current
.ds3d
.vVelocity
.x
= x
;
1632 This
->current
.ds3d
.vVelocity
.y
= y
;
1633 This
->current
.ds3d
.vVelocity
.z
= z
;
1634 alListener3f(AL_VELOCITY
, x
, y
, -z
);
1638 LeaveCriticalSection(&This
->share
->crst
);
1643 static HRESULT WINAPI
DSPrimary3D_SetAllParameters(IDirectSound3DListener
*iface
, const DS3DLISTENER
*listen
, DWORD apply
)
1645 DSPrimary
*This
= impl_from_IDirectSound3DListener(iface
);
1647 TRACE("(%p)->(%p, %lu)\n", iface
, listen
, apply
);
1649 if(!listen
|| listen
->dwSize
< sizeof(*listen
))
1651 WARN("Invalid parameter %p %lu\n", listen
, listen
? listen
->dwSize
: 0);
1652 return DSERR_INVALIDPARAM
;
1655 if(listen
->flDistanceFactor
> DS3D_MAXDISTANCEFACTOR
||
1656 listen
->flDistanceFactor
< DS3D_MINDISTANCEFACTOR
)
1658 WARN("Invalid distance factor (%f)\n", listen
->flDistanceFactor
);
1659 return DSERR_INVALIDPARAM
;
1662 if(listen
->flDopplerFactor
> DS3D_MAXDOPPLERFACTOR
||
1663 listen
->flDopplerFactor
< DS3D_MINDOPPLERFACTOR
)
1665 WARN("Invalid doppler factor (%f)\n", listen
->flDopplerFactor
);
1666 return DSERR_INVALIDPARAM
;
1669 if(listen
->flRolloffFactor
< DS3D_MINROLLOFFFACTOR
||
1670 listen
->flRolloffFactor
> DS3D_MAXROLLOFFFACTOR
)
1672 WARN("Invalid rolloff factor (%f)\n", listen
->flRolloffFactor
);
1673 return DSERR_INVALIDPARAM
;
1676 if(apply
== DS3D_DEFERRED
)
1678 EnterCriticalSection(&This
->share
->crst
);
1679 This
->deferred
.ds3d
= *listen
;
1680 This
->deferred
.ds3d
.dwSize
= sizeof(This
->deferred
.ds3d
);
1681 This
->dirty
.bit
.pos
= 1;
1682 This
->dirty
.bit
.vel
= 1;
1683 This
->dirty
.bit
.orientation
= 1;
1684 This
->dirty
.bit
.distancefactor
= 1;
1685 This
->dirty
.bit
.rollofffactor
= 1;
1686 This
->dirty
.bit
.dopplerfactor
= 1;
1687 LeaveCriticalSection(&This
->share
->crst
);
1691 union PrimaryParamFlags dirty
= { 0l };
1694 dirty
.bit
.orientation
= 1;
1695 dirty
.bit
.distancefactor
= 1;
1696 dirty
.bit
.rollofffactor
= 1;
1697 dirty
.bit
.dopplerfactor
= 1;
1699 EnterCriticalSection(&This
->share
->crst
);
1700 setALContext(This
->ctx
);
1701 DSPrimary_SetParams(This
, listen
, dirty
.flags
);
1704 LeaveCriticalSection(&This
->share
->crst
);
1710 HRESULT WINAPI
DSPrimary3D_CommitDeferredSettings(IDirectSound3DListener
*iface
)
1712 DSPrimary
*This
= impl_from_IDirectSound3DListener(iface
);
1713 struct DSBufferGroup
*bufgroup
;
1717 EnterCriticalSection(&This
->share
->crst
);
1718 setALContext(This
->ctx
);
1719 alDeferUpdatesSOFT();
1721 if((flags
=InterlockedExchange(&This
->dirty
.flags
, 0)) != 0)
1723 DSPrimary_SetParams(This
, &This
->deferred
.ds3d
, flags
);
1724 /* checkALError is here for debugging */
1727 TRACE("Dirty flags was: 0x%02lx\n", flags
);
1729 bufgroup
= This
->BufferGroups
;
1730 for(i
= 0;i
< This
->NumBufferGroups
;++i
)
1732 DWORD64 usemask
= ~bufgroup
[i
].FreeBuffers
;
1735 int idx
= CTZ64(usemask
);
1736 DSBuffer
*buf
= bufgroup
[i
].Buffers
+ idx
;
1737 usemask
&= ~(U64(1) << idx
);
1739 if((flags
=InterlockedExchange(&buf
->dirty
.flags
, 0)) != 0)
1740 DSBuffer_SetParams(buf
, &buf
->deferred
.ds3d
, flags
);
1743 alProcessUpdatesSOFT();
1747 LeaveCriticalSection(&This
->share
->crst
);
1752 static const IDirectSound3DListenerVtbl DSPrimary3D_Vtbl
=
1754 DSPrimary3D_QueryInterface
,
1756 DSPrimary3D_Release
,
1757 DSPrimary3D_GetAllParameters
,
1758 DSPrimary3D_GetDistanceFactor
,
1759 DSPrimary3D_GetDopplerFactor
,
1760 DSPrimary3D_GetOrientation
,
1761 DSPrimary3D_GetPosition
,
1762 DSPrimary3D_GetRolloffFactor
,
1763 DSPrimary3D_GetVelocity
,
1764 DSPrimary3D_SetAllParameters
,
1765 DSPrimary3D_SetDistanceFactor
,
1766 DSPrimary3D_SetDopplerFactor
,
1767 DSPrimary3D_SetOrientation
,
1768 DSPrimary3D_SetPosition
,
1769 DSPrimary3D_SetRolloffFactor
,
1770 DSPrimary3D_SetVelocity
,
1771 DSPrimary3D_CommitDeferredSettings
1775 static HRESULT WINAPI
DSPrimaryProp_QueryInterface(IKsPropertySet
*iface
, REFIID riid
, void **ppv
)
1777 DSPrimary
*This
= impl_from_IKsPropertySet(iface
);
1778 return DSPrimary_QueryInterface(&This
->IDirectSoundBuffer_iface
, riid
, ppv
);
1781 static ULONG WINAPI
DSPrimaryProp_AddRef(IKsPropertySet
*iface
)
1783 DSPrimary
*This
= impl_from_IKsPropertySet(iface
);
1786 ret
= InterlockedIncrement(&This
->prop_ref
);
1787 TRACE("(%p) ref %lu\n", iface
, ret
);
1792 static ULONG WINAPI
DSPrimaryProp_Release(IKsPropertySet
*iface
)
1794 DSPrimary
*This
= impl_from_IKsPropertySet(iface
);
1797 ret
= InterlockedDecrement(&This
->prop_ref
);
1798 TRACE("(%p) ref %lu\n", iface
, ret
);
1803 static HRESULT WINAPI
DSPrimaryProp_Get(IKsPropertySet
*iface
,
1804 REFGUID guidPropSet
, ULONG dwPropID
,
1805 LPVOID pInstanceData
, ULONG cbInstanceData
,
1806 LPVOID pPropData
, ULONG cbPropData
,
1811 (void)pInstanceData
;
1812 (void)cbInstanceData
;
1817 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet
));
1819 return E_PROP_ID_UNSUPPORTED
;
1822 static HRESULT WINAPI
DSPrimaryProp_Set(IKsPropertySet
*iface
,
1823 REFGUID guidPropSet
, ULONG dwPropID
,
1824 LPVOID pInstanceData
, ULONG cbInstanceData
,
1825 LPVOID pPropData
, ULONG cbPropData
)
1829 (void)pInstanceData
;
1830 (void)cbInstanceData
;
1834 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet
));
1836 return E_PROP_ID_UNSUPPORTED
;
1839 static HRESULT WINAPI
DSPrimaryProp_QuerySupport(IKsPropertySet
*iface
,
1840 REFGUID guidPropSet
, ULONG dwPropID
,
1841 ULONG
*pTypeSupport
)
1846 FIXME("Unhandled propset: %s (propid: %lu)\n", debugstr_guid(guidPropSet
), dwPropID
);
1848 return E_PROP_ID_UNSUPPORTED
;
1851 static const IKsPropertySetVtbl DSPrimaryProp_Vtbl
=
1853 DSPrimaryProp_QueryInterface
,
1854 DSPrimaryProp_AddRef
,
1855 DSPrimaryProp_Release
,
1858 DSPrimaryProp_QuerySupport