Don'e set redundant EAX properties on initialization
[dsound-openal.git] / primary.c
blob6b40457421c70d4950486910694e4d71de517e26
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
23 #define CONST_VTABLE
24 #include <stdarg.h>
25 #include <string.h>
27 #include <windows.h>
28 #include <dsound.h>
29 #include <mmsystem.h>
31 #include "dsound_private.h"
32 #include "eax-presets.h"
35 #ifndef E_PROP_ID_UNSUPPORTED
36 #define E_PROP_ID_UNSUPPORTED ((HRESULT)0x80070490)
37 #endif
40 static IDirectSoundBufferVtbl DSPrimary_Vtbl;
41 static IDirectSound3DListenerVtbl DSPrimary3D_Vtbl;
42 static 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)
73 continue;
75 if(curpos < lastpos) /* Wraparound case */
77 if(ofs < curpos || ofs >= lastpos)
79 TRACE("Triggering notification %d from buffer %p\n", (int)(not-buf->notify), buf);
80 SetEvent(event);
83 else if(ofs >= lastpos && ofs < curpos) /* Normal case */
85 TRACE("Triggering notification %d from buffer %p\n", (int)(not-buf->notify), buf);
86 SetEvent(event);
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)
98 continue;
99 TRACE("Triggering notification %d from buffer %p\n", (int)(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;
115 ALint state = 0;
116 ALint ofs;
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;
122 else
124 if(state != AL_STOPPED)
125 curpos = ofs + buf->queue_base;
126 else
128 ALint queued;
129 alGetSourcei(buf->source, AL_BUFFERS_QUEUED, &queued);
130 curpos = buf->segsize*queued + buf->queue_base;
133 if(curpos >= (DWORD)data->buf_size)
135 if(buf->islooping)
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);
142 buf->curidx = 0;
143 buf->isplaying = FALSE;
147 if(state != AL_PLAYING)
148 state = buf->isplaying ? AL_PLAYING : AL_PAUSED;
150 checkALError();
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);
164 prim->nnotifies--;
165 continue;
167 curnot++;
169 checkALError();
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;
176 ALuint which;
178 alGetSourcei(buf->source, AL_BUFFERS_QUEUED, &queued);
179 alGetSourcei(buf->source, AL_SOURCE_STATE, &state);
180 alGetSourcei(buf->source, AL_BUFFERS_PROCESSED, &done);
182 if(done > 0)
184 ALuint bids[QBUFFERS];
185 queued -= done;
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);
213 rem += 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;
219 else
221 ALsizei rem = data->buf_size - ofs;
222 if(rem > 2048) rem = 2048;
223 if(rem == 0) break;
225 memcpy(scratch_mem, data->data + ofs, rem);
226 memset(scratch_mem+rem, (data->format.Format.wBitsPerSample==8) ? 128 : 0,
227 buf->segsize - rem);
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;
235 queued++;
238 if(!queued)
240 buf->data_offset = 0;
241 buf->queue_base = data->buf_size;
242 buf->curidx = 0;
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
254 if(prim->write_emu)
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);
260 else
262 struct DSBufferGroup *bufgroup = prim->BufferGroups;
263 struct DSBufferGroup *endgroup = bufgroup + prim->NumBufferGroups;
264 for(;bufgroup != endgroup;++bufgroup)
266 DWORD64 usemask = ~bufgroup->FreeBuffers;
267 while(usemask)
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);
278 checkALError();
282 HRESULT DSPrimary_PreInit(DSPrimary *This, DSDevice *parent)
284 WAVEFORMATEX *wfx;
285 DWORD num_srcs;
286 DWORD count;
287 HRESULT hr;
288 DWORD i;
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;
299 wfx = &This->format.Format;
300 wfx->wFormatTag = WAVE_FORMAT_PCM;
301 wfx->nChannels = 2;
302 wfx->wBitsPerSample = 8;
303 wfx->nSamplesPerSec = 22050;
304 wfx->nBlockAlign = wfx->wBitsPerSample * wfx->nChannels / 8;
305 wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
306 wfx->cbSize = 0;
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 num_srcs = This->share->sources.maxhw_alloc + This->share->sources.maxsw_alloc;
318 hr = DSERR_OUTOFMEMORY;
319 This->notifies = HeapAlloc(GetProcessHeap(), 0, num_srcs*sizeof(*This->notifies));
320 if(!This->notifies) goto fail;
321 This->sizenotifies = num_srcs;
323 count = (MAX_HWBUFFERS+63) / 64;
324 This->BufferGroups = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
325 count*sizeof(*This->BufferGroups));
326 if(!This->BufferGroups) goto fail;
328 for(i = 0;i < count;++i)
330 This->BufferGroups[i].Buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
331 64*sizeof(This->BufferGroups[0].Buffers[0]));
332 if(!This->BufferGroups[i].Buffers)
334 while(i > 0)
335 HeapFree(GetProcessHeap(), 0, This->BufferGroups[--i].Buffers);
336 HeapFree(GetProcessHeap(), 0, This->BufferGroups);
337 This->BufferGroups = NULL;
338 goto fail;
340 This->BufferGroups[i].FreeBuffers = ~(DWORD64)0;
342 This->NumBufferGroups = count;
344 return S_OK;
346 fail:
347 DSPrimary_Clear(This);
348 return hr;
351 void DSPrimary_Clear(DSPrimary *This)
353 struct DSBufferGroup *bufgroup;
354 DWORD i;
356 if(!This->parent)
357 return;
359 bufgroup = This->BufferGroups;
360 for(i = 0;i < This->NumBufferGroups;++i)
362 DWORD64 usemask = ~bufgroup[i].FreeBuffers;
363 while(usemask)
365 int idx = CTZ64(usemask);
366 DSBuffer *buf = bufgroup[i].Buffers + idx;
367 usemask &= ~(U64(1) << idx);
369 DSBuffer_Destroy(buf);
371 HeapFree(GetProcessHeap(), 0, This->BufferGroups[i].Buffers);
374 HeapFree(GetProcessHeap(), 0, This->BufferGroups);
375 HeapFree(GetProcessHeap(), 0, This->notifies);
376 memset(This, 0, sizeof(*This));
379 static HRESULT WINAPI DSPrimary_QueryInterface(IDirectSoundBuffer *iface, REFIID riid, LPVOID *ppv)
381 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
383 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
385 *ppv = NULL;
386 if(IsEqualIID(riid, &IID_IUnknown) ||
387 IsEqualIID(riid, &IID_IDirectSoundBuffer))
388 *ppv = &This->IDirectSoundBuffer_iface;
389 else if(IsEqualIID(riid, &IID_IDirectSound3DListener))
391 if((This->flags&DSBCAPS_CTRL3D))
392 *ppv = &This->IDirectSound3DListener_iface;
394 else if(IsEqualIID(riid, &IID_IKsPropertySet))
395 *ppv = &This->IKsPropertySet_iface;
396 else
397 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
399 if(*ppv)
401 IUnknown_AddRef((IUnknown*)*ppv);
402 return S_OK;
405 return E_NOINTERFACE;
408 static ULONG WINAPI DSPrimary_AddRef(IDirectSoundBuffer *iface)
410 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
411 LONG ret;
413 ret = InterlockedIncrement(&This->ref);
414 if(ret == 1) This->flags = 0;
415 TRACE("(%p) ref %lu\n", iface, ret);
417 return ret;
420 static ULONG WINAPI DSPrimary_Release(IDirectSoundBuffer *iface)
422 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
423 LONG ref, oldval;
425 oldval = *(volatile LONG*)&This->ref;
426 do {
427 ref = oldval;
428 if(ref)
430 --ref;
431 oldval = InterlockedCompareExchange(&This->ref, ref, ref+1)-1;
433 } while(oldval != ref);
434 TRACE("(%p) ref %lu\n", iface, ref);
436 return ref;
439 static HRESULT WINAPI DSPrimary_GetCaps(IDirectSoundBuffer *iface, DSBCAPS *caps)
441 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
443 TRACE("(%p)->(%p)\n", iface, caps);
445 if(!caps || caps->dwSize < sizeof(*caps))
447 WARN("Invalid DSBCAPS (%p, %lu)\n", caps, caps ? caps->dwSize : 0);
448 return DSERR_INVALIDPARAM;
451 caps->dwFlags = This->flags;
452 caps->dwBufferBytes = This->buf_size;
453 caps->dwUnlockTransferRate = 0;
454 caps->dwPlayCpuOverhead = 0;
456 return DS_OK;
459 static HRESULT WINAPI DSPrimary_GetCurrentPosition(IDirectSoundBuffer *iface, DWORD *playpos, DWORD *curpos)
461 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
462 HRESULT hr = DSERR_PRIOLEVELNEEDED;
464 EnterCriticalSection(&This->share->crst);
465 if(This->write_emu)
466 hr = IDirectSoundBuffer_GetCurrentPosition(This->write_emu, playpos, curpos);
467 LeaveCriticalSection(&This->share->crst);
469 return hr;
472 static HRESULT WINAPI DSPrimary_GetFormat(IDirectSoundBuffer *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
474 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
475 HRESULT hr = S_OK;
476 UINT size;
478 if(!wfx && !written)
480 WARN("Cannot report format or format size\n");
481 return DSERR_INVALIDPARAM;
484 EnterCriticalSection(&This->share->crst);
485 size = sizeof(This->format.Format) + This->format.Format.cbSize;
486 if(written)
487 *written = size;
488 if(wfx)
490 if(allocated < size)
491 hr = DSERR_INVALIDPARAM;
492 else
493 memcpy(wfx, &This->format.Format, size);
495 LeaveCriticalSection(&This->share->crst);
497 return hr;
500 static HRESULT WINAPI DSPrimary_GetVolume(IDirectSoundBuffer *iface, LONG *volume)
502 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
503 ALfloat gain;
505 TRACE("(%p)->(%p)\n", iface, volume);
507 if(!volume)
508 return DSERR_INVALIDPARAM;
509 *volume = 0;
511 if(!(This->flags&DSBCAPS_CTRLVOLUME))
512 return DSERR_CONTROLUNAVAIL;
514 setALContext(This->ctx);
515 alGetListenerf(AL_GAIN, &gain);
516 checkALError();
517 popALContext();
519 *volume = clampI(gain_to_mB(gain), DSBVOLUME_MIN, DSBVOLUME_MAX);
520 return DS_OK;
523 static HRESULT WINAPI DSPrimary_GetPan(IDirectSoundBuffer *iface, LONG *pan)
525 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
526 HRESULT hr = DS_OK;
528 WARN("(%p)->(%p): semi-stub\n", iface, pan);
530 if(!pan)
531 return DSERR_INVALIDPARAM;
533 EnterCriticalSection(&This->share->crst);
534 if(This->write_emu)
535 hr = IDirectSoundBuffer_GetPan(This->write_emu, pan);
536 else if(!(This->flags & DSBCAPS_CTRLPAN))
537 hr = DSERR_CONTROLUNAVAIL;
538 else
539 *pan = 0;
540 LeaveCriticalSection(&This->share->crst);
542 return hr;
545 static HRESULT WINAPI DSPrimary_GetFrequency(IDirectSoundBuffer *iface, DWORD *freq)
547 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
548 HRESULT hr = DS_OK;
550 WARN("(%p)->(%p): semi-stub\n", iface, freq);
552 if(!freq)
553 return DSERR_INVALIDPARAM;
555 if(!(This->flags&DSBCAPS_CTRLFREQUENCY))
556 return DSERR_CONTROLUNAVAIL;
558 EnterCriticalSection(&This->share->crst);
559 *freq = This->format.Format.nSamplesPerSec;
560 LeaveCriticalSection(&This->share->crst);
562 return hr;
565 static HRESULT WINAPI DSPrimary_GetStatus(IDirectSoundBuffer *iface, DWORD *status)
567 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
569 TRACE("(%p)->(%p)\n", iface, status);
571 if(!status)
572 return DSERR_INVALIDPARAM;
574 EnterCriticalSection(&This->share->crst);
575 *status = DSBSTATUS_PLAYING|DSBSTATUS_LOOPING;
576 if((This->flags&DSBCAPS_LOCDEFER))
577 *status |= DSBSTATUS_LOCHARDWARE;
579 if(This->stopped)
581 struct DSBufferGroup *bufgroup = This->BufferGroups;
582 DWORD i, state = 0;
583 HRESULT hr;
585 for(i = 0;i < This->NumBufferGroups;++i)
587 DWORD64 usemask = ~bufgroup[i].FreeBuffers;
588 while(usemask)
590 int idx = CTZ64(usemask);
591 DSBuffer *buf = bufgroup[i].Buffers + idx;
592 usemask &= ~(U64(1) << idx);
594 hr = DSBuffer_GetStatus(&buf->IDirectSoundBuffer8_iface, &state);
595 if(SUCCEEDED(hr) && (state&DSBSTATUS_PLAYING)) break;
598 if(!(state&DSBSTATUS_PLAYING))
600 /* Primary stopped and no buffers playing.. */
601 *status = 0;
604 LeaveCriticalSection(&This->share->crst);
606 return DS_OK;
609 HRESULT WINAPI DSPrimary_Initialize(IDirectSoundBuffer *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
611 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
612 HRESULT hr;
614 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
616 if(!desc || desc->lpwfxFormat || desc->dwBufferBytes)
618 WARN("Bad DSBDESC for primary buffer\n");
619 return DSERR_INVALIDPARAM;
621 if((desc->dwFlags&DSBCAPS_CTRLFX) ||
622 (desc->dwFlags&DSBCAPS_CTRLPOSITIONNOTIFY) ||
623 (desc->dwFlags&DSBCAPS_LOCSOFTWARE))
625 WARN("Bad dwFlags %08lx\n", desc->dwFlags);
626 return DSERR_INVALIDPARAM;
629 /* Should be 0 if not initialized */
630 if(This->flags)
631 return DSERR_ALREADYINITIALIZED;
633 hr = DS_OK;
634 if(This->parent->prio_level == DSSCL_WRITEPRIMARY)
636 DSBUFFERDESC emudesc;
637 DSBuffer *emu;
639 if(This->write_emu)
641 ERR("There shouldn't be a write_emu!\n");
642 IDirectSoundBuffer_Release(This->write_emu);
643 This->write_emu = NULL;
646 memset(&emudesc, 0, sizeof(emudesc));
647 emudesc.dwSize = sizeof(emudesc);
648 emudesc.dwFlags = DSBCAPS_LOCHARDWARE | (desc->dwFlags&DSBCAPS_CTRLPAN);
649 /* Dont play last incomplete sample */
650 emudesc.dwBufferBytes = This->buf_size - (This->buf_size%This->format.Format.nBlockAlign);
651 emudesc.lpwfxFormat = &This->format.Format;
653 hr = DSBuffer_Create(&emu, This, NULL);
654 if(SUCCEEDED(hr))
656 hr = DSBuffer_Initialize(&emu->IDirectSoundBuffer8_iface, ds, &emudesc);
657 if(SUCCEEDED(hr))
658 hr = DSBuffer_GetInterface(emu, &IID_IDirectSoundBuffer, (void**)&This->write_emu);
659 if(FAILED(hr))
660 DSBuffer_Destroy(emu);
664 if(SUCCEEDED(hr))
666 This->current.ds3d.dwSize = sizeof(This->current.ds3d);
667 This->current.ds3d.vPosition.x = 0.0f;
668 This->current.ds3d.vPosition.y = 0.0f;
669 This->current.ds3d.vPosition.z = 0.0f;
670 This->current.ds3d.vVelocity.x = 0.0f;
671 This->current.ds3d.vVelocity.y = 0.0f;
672 This->current.ds3d.vVelocity.z = 0.0f;
673 This->current.ds3d.vOrientFront.x = 0.0f;
674 This->current.ds3d.vOrientFront.y = 0.0f;
675 This->current.ds3d.vOrientFront.z = 1.0f;
676 This->current.ds3d.vOrientTop.x = 0.0f;
677 This->current.ds3d.vOrientTop.y = 1.0f;
678 This->current.ds3d.vOrientTop.z = 0.0f;
679 This->current.ds3d.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
680 This->current.ds3d.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
681 This->current.ds3d.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
682 This->deferred.ds3d = This->current.ds3d;
684 This->flags = desc->dwFlags | DSBCAPS_LOCHARDWARE;
686 if((This->flags&DSBCAPS_CTRL3D))
688 union PrimaryParamFlags dirty = { 0l };
690 dirty.bit.pos = 1;
691 dirty.bit.vel = 1;
692 dirty.bit.orientation = 1;
693 dirty.bit.distancefactor = 1;
694 dirty.bit.rollofffactor = 1;
695 dirty.bit.dopplerfactor = 1;
696 DSPrimary_SetParams(This, &This->deferred.ds3d, dirty.flags);
699 return hr;
702 static HRESULT WINAPI DSPrimary_Lock(IDirectSoundBuffer *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
704 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
705 HRESULT hr = DSERR_PRIOLEVELNEEDED;
707 TRACE("(%p)->(%lu, %lu, %p, %p, %p, %p, %lu)\n", iface, ofs, bytes, ptr1, len1, ptr2, len2, flags);
709 EnterCriticalSection(&This->share->crst);
710 if(This->write_emu)
711 hr = IDirectSoundBuffer_Lock(This->write_emu, ofs, bytes, ptr1, len1, ptr2, len2, flags);
712 LeaveCriticalSection(&This->share->crst);
714 return hr;
717 static HRESULT WINAPI DSPrimary_Play(IDirectSoundBuffer *iface, DWORD res1, DWORD res2, DWORD flags)
719 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
720 HRESULT hr;
722 TRACE("(%p)->(%lu, %lu, %lu)\n", iface, res1, res2, flags);
724 if(!(flags & DSBPLAY_LOOPING))
726 WARN("Flags (%08lx) not set to DSBPLAY_LOOPING\n", flags);
727 return DSERR_INVALIDPARAM;
730 EnterCriticalSection(&This->share->crst);
731 hr = S_OK;
732 if(This->write_emu)
733 hr = IDirectSoundBuffer_Play(This->write_emu, res1, res2, flags);
734 if(SUCCEEDED(hr))
735 This->stopped = FALSE;
736 LeaveCriticalSection(&This->share->crst);
738 return hr;
741 static HRESULT WINAPI DSPrimary_SetCurrentPosition(IDirectSoundBuffer *iface, DWORD pos)
743 WARN("(%p)->(%lu)\n", iface, pos);
744 return DSERR_INVALIDCALL;
747 /* Just assume the format is crap, and clean up the damage */
748 static HRESULT copy_waveformat(WAVEFORMATEX *wfx, const WAVEFORMATEX *from)
750 if(from->nChannels <= 0)
752 WARN("Invalid Channels %d\n", from->nChannels);
753 return DSERR_INVALIDPARAM;
755 if(from->nSamplesPerSec < DSBFREQUENCY_MIN || from->nSamplesPerSec > DSBFREQUENCY_MAX)
757 WARN("Invalid SamplesPerSec %lu\n", from->nSamplesPerSec);
758 return DSERR_INVALIDPARAM;
760 if(from->nBlockAlign <= 0)
762 WARN("Invalid BlockAlign %d\n", from->nBlockAlign);
763 return DSERR_INVALIDPARAM;
765 if(from->wBitsPerSample == 0 || (from->wBitsPerSample%8) != 0)
767 WARN("Invalid BitsPerSample %d\n", from->wBitsPerSample);
768 return DSERR_INVALIDPARAM;
770 if(from->nBlockAlign != from->nChannels*from->wBitsPerSample/8)
772 WARN("Invalid BlockAlign %d (expected %u = %u*%u/8)\n",
773 from->nBlockAlign, from->nChannels*from->wBitsPerSample/8,
774 from->nChannels, from->wBitsPerSample);
775 return DSERR_INVALIDPARAM;
777 if(from->nAvgBytesPerSec != from->nBlockAlign*from->nSamplesPerSec)
779 WARN("Invalid AvgBytesPerSec %lu (expected %lu = %lu*%u)\n",
780 from->nAvgBytesPerSec, from->nSamplesPerSec*from->nBlockAlign,
781 from->nSamplesPerSec, from->nBlockAlign);
782 return DSERR_INVALIDPARAM;
785 if(from->wFormatTag == WAVE_FORMAT_PCM)
787 if(from->wBitsPerSample > 32)
788 return DSERR_INVALIDPARAM;
789 wfx->cbSize = 0;
791 else if(from->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
793 if(from->wBitsPerSample != 32)
794 return DSERR_INVALIDPARAM;
795 wfx->cbSize = 0;
797 else if(from->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
799 WAVEFORMATEXTENSIBLE *wfe = (WAVEFORMATEXTENSIBLE*)wfx;
800 const WAVEFORMATEXTENSIBLE *fromx = (const WAVEFORMATEXTENSIBLE*)from;
801 const WORD size = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
803 /* Fail silently.. */
804 if(from->cbSize < size) return DS_OK;
805 if(fromx->Samples.wValidBitsPerSample > fromx->Format.wBitsPerSample)
806 return DSERR_INVALIDPARAM;
808 if(IsEqualGUID(&fromx->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
810 if(from->wBitsPerSample > 32)
811 return DSERR_INVALIDPARAM;
813 else if(IsEqualGUID(&fromx->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
815 if(from->wBitsPerSample != 32)
816 return DSERR_INVALIDPARAM;
818 else
820 ERR("Unhandled extensible format: %s\n", debugstr_guid(&fromx->SubFormat));
821 return DSERR_INVALIDPARAM;
824 wfe->Format.cbSize = size;
825 wfe->Samples.wValidBitsPerSample = fromx->Samples.wValidBitsPerSample;
826 if(!wfe->Samples.wValidBitsPerSample)
827 wfe->Samples.wValidBitsPerSample = fromx->Format.wBitsPerSample;
828 wfe->dwChannelMask = fromx->dwChannelMask;
829 wfe->SubFormat = fromx->SubFormat;
831 else
833 ERR("Unhandled format tag %04x\n", from->wFormatTag);
834 return DSERR_INVALIDPARAM;
837 wfx->wFormatTag = from->wFormatTag;
838 wfx->nChannels = from->nChannels;
839 wfx->nSamplesPerSec = from->nSamplesPerSec;
840 wfx->nAvgBytesPerSec = from->nSamplesPerSec * from->nBlockAlign;
841 wfx->nBlockAlign = from->wBitsPerSample * from->nChannels / 8;
842 wfx->wBitsPerSample = from->wBitsPerSample;
843 return DS_OK;
846 static HRESULT WINAPI DSPrimary_SetFormat(IDirectSoundBuffer *iface, const WAVEFORMATEX *wfx)
848 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
849 HRESULT hr = S_OK;
851 TRACE("(%p)->(%p)\n", iface, wfx);
853 if(!wfx)
855 WARN("Missing format\n");
856 return DSERR_INVALIDPARAM;
859 EnterCriticalSection(&This->share->crst);
861 if(This->parent->prio_level < DSSCL_PRIORITY)
863 hr = DSERR_PRIOLEVELNEEDED;
864 goto out;
867 TRACE("Requested primary format:\n"
868 " FormatTag = %04x\n"
869 " Channels = %u\n"
870 " SamplesPerSec = %lu\n"
871 " AvgBytesPerSec = %lu\n"
872 " BlockAlign = %u\n"
873 " BitsPerSample = %u\n",
874 wfx->wFormatTag, wfx->nChannels,
875 wfx->nSamplesPerSec, wfx->nAvgBytesPerSec,
876 wfx->nBlockAlign, wfx->wBitsPerSample);
878 hr = copy_waveformat(&This->format.Format, wfx);
879 if(SUCCEEDED(hr) && This->write_emu)
881 DSBuffer *buf;
882 DSBUFFERDESC desc;
884 IDirectSoundBuffer_Release(This->write_emu);
885 This->write_emu = NULL;
887 memset(&desc, 0, sizeof(desc));
888 desc.dwSize = sizeof(desc);
889 desc.dwFlags = DSBCAPS_LOCHARDWARE | DSBCAPS_CTRLPAN;
890 desc.dwBufferBytes = This->buf_size - (This->buf_size % This->format.Format.nBlockAlign);
891 desc.lpwfxFormat = &This->format.Format;
893 hr = DSBuffer_Create(&buf, This, NULL);
894 if(SUCCEEDED(hr))
896 hr = DSBuffer_Initialize(&buf->IDirectSoundBuffer8_iface,
897 &This->parent->IDirectSound_iface, &desc);
898 if(SUCCEEDED(hr))
899 hr = DSBuffer_GetInterface(buf, &IID_IDirectSoundBuffer, (void**)&This->write_emu);
900 if(FAILED(hr))
901 DSBuffer_Destroy(buf);
905 out:
906 LeaveCriticalSection(&This->share->crst);
907 return hr;
910 static HRESULT WINAPI DSPrimary_SetVolume(IDirectSoundBuffer *iface, LONG vol)
912 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
914 TRACE("(%p)->(%ld)\n", iface, vol);
916 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
918 WARN("Invalid volume (%ld)\n", vol);
919 return DSERR_INVALIDPARAM;
922 if(!(This->flags&DSBCAPS_CTRLVOLUME))
923 return DSERR_CONTROLUNAVAIL;
925 setALContext(This->ctx);
926 alListenerf(AL_GAIN, mB_to_gain((float)vol));
927 popALContext();
929 return DS_OK;
932 static HRESULT WINAPI DSPrimary_SetPan(IDirectSoundBuffer *iface, LONG pan)
934 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
935 HRESULT hr;
937 TRACE("(%p)->(%ld)\n", iface, pan);
939 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
941 WARN("invalid parameter: pan = %ld\n", pan);
942 return DSERR_INVALIDPARAM;
945 EnterCriticalSection(&This->share->crst);
946 if(!(This->flags&DSBCAPS_CTRLPAN))
948 WARN("control unavailable\n");
949 hr = DSERR_CONTROLUNAVAIL;
951 else if(This->write_emu)
952 hr = IDirectSoundBuffer_SetPan(This->write_emu, pan);
953 else
955 FIXME("Not supported\n");
956 hr = E_NOTIMPL;
958 LeaveCriticalSection(&This->share->crst);
960 return hr;
963 static HRESULT WINAPI DSPrimary_SetFrequency(IDirectSoundBuffer *iface, DWORD freq)
965 WARN("(%p)->(%lu)\n", iface, freq);
966 return DSERR_CONTROLUNAVAIL;
969 static HRESULT WINAPI DSPrimary_Stop(IDirectSoundBuffer *iface)
971 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
972 HRESULT hr = S_OK;
974 TRACE("(%p)->()\n", iface);
976 EnterCriticalSection(&This->share->crst);
977 if(This->write_emu)
978 hr = IDirectSoundBuffer_Stop(This->write_emu);
979 if(SUCCEEDED(hr))
980 This->stopped = TRUE;
981 LeaveCriticalSection(&This->share->crst);
983 return hr;
986 static HRESULT WINAPI DSPrimary_Unlock(IDirectSoundBuffer *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
988 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
989 HRESULT hr = DSERR_INVALIDCALL;
991 TRACE("(%p)->(%p, %lu, %p, %lu)\n", iface, ptr1, len1, ptr2, len2);
993 EnterCriticalSection(&This->share->crst);
994 if(This->write_emu)
995 hr = IDirectSoundBuffer_Unlock(This->write_emu, ptr1, len1, ptr2, len2);
996 LeaveCriticalSection(&This->share->crst);
998 return hr;
1001 static HRESULT WINAPI DSPrimary_Restore(IDirectSoundBuffer *iface)
1003 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
1004 HRESULT hr = S_OK;
1006 TRACE("(%p)->()\n", iface);
1008 EnterCriticalSection(&This->share->crst);
1009 if(This->write_emu)
1010 hr = IDirectSoundBuffer_Restore(This->write_emu);
1011 LeaveCriticalSection(&This->share->crst);
1013 return hr;
1016 static IDirectSoundBufferVtbl DSPrimary_Vtbl =
1018 DSPrimary_QueryInterface,
1019 DSPrimary_AddRef,
1020 DSPrimary_Release,
1021 DSPrimary_GetCaps,
1022 DSPrimary_GetCurrentPosition,
1023 DSPrimary_GetFormat,
1024 DSPrimary_GetVolume,
1025 DSPrimary_GetPan,
1026 DSPrimary_GetFrequency,
1027 DSPrimary_GetStatus,
1028 DSPrimary_Initialize,
1029 DSPrimary_Lock,
1030 DSPrimary_Play,
1031 DSPrimary_SetCurrentPosition,
1032 DSPrimary_SetFormat,
1033 DSPrimary_SetVolume,
1034 DSPrimary_SetPan,
1035 DSPrimary_SetFrequency,
1036 DSPrimary_Stop,
1037 DSPrimary_Unlock,
1038 DSPrimary_Restore
1042 static void DSPrimary_SetParams(DSPrimary *This, const DS3DLISTENER *params, LONG flags)
1044 union PrimaryParamFlags dirty = { flags };
1045 DWORD i;
1047 if(dirty.bit.pos)
1048 This->current.ds3d.vPosition = params->vPosition;
1049 if(dirty.bit.vel)
1050 This->current.ds3d.vVelocity = params->vVelocity;
1051 if(dirty.bit.orientation)
1053 This->current.ds3d.vOrientFront = params->vOrientFront;
1054 This->current.ds3d.vOrientTop = params->vOrientTop;
1056 if(dirty.bit.distancefactor)
1057 This->current.ds3d.flDistanceFactor = params->flDistanceFactor;
1058 if(dirty.bit.rollofffactor)
1059 This->current.ds3d.flRolloffFactor = params->flRolloffFactor;
1060 if(dirty.bit.dopplerfactor)
1061 This->current.ds3d.flDopplerFactor = params->flDopplerFactor;
1063 if(dirty.bit.pos)
1064 alListener3f(AL_POSITION, params->vPosition.x, params->vPosition.y,
1065 -params->vPosition.z);
1066 if(dirty.bit.vel)
1067 alListener3f(AL_VELOCITY, params->vVelocity.x, params->vVelocity.y,
1068 -params->vVelocity.z);
1069 if(dirty.bit.orientation)
1071 ALfloat orient[6] = {
1072 params->vOrientFront.x, params->vOrientFront.y, -params->vOrientFront.z,
1073 params->vOrientTop.x, params->vOrientTop.y, -params->vOrientTop.z
1075 alListenerfv(AL_ORIENTATION, orient);
1077 if(dirty.bit.distancefactor)
1078 alSpeedOfSound(343.3f/params->flDistanceFactor);
1079 if(dirty.bit.rollofffactor)
1081 struct DSBufferGroup *bufgroup = This->BufferGroups;
1082 ALfloat rolloff = params->flRolloffFactor;
1084 for(i = 0;i < This->NumBufferGroups;++i)
1086 DWORD64 usemask = ~bufgroup[i].FreeBuffers;
1087 while(usemask)
1089 int idx = CTZ64(usemask);
1090 DSBuffer *buf = bufgroup[i].Buffers + idx;
1091 usemask &= ~(U64(1) << idx);
1093 if(buf->source)
1094 alSourcef(buf->source, AL_ROLLOFF_FACTOR, rolloff);
1098 if(dirty.bit.dopplerfactor)
1099 alDopplerFactor(params->flDopplerFactor);
1100 if(dirty.bit.eax)
1101 EAXSet(&EAXPROPERTYID_EAX40_Context, 0, 0, NULL, 0);
1104 static HRESULT WINAPI DSPrimary3D_QueryInterface(IDirectSound3DListener *iface, REFIID riid, void **ppv)
1106 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1107 return DSPrimary_QueryInterface(&This->IDirectSoundBuffer_iface, riid, ppv);
1110 static ULONG WINAPI DSPrimary3D_AddRef(IDirectSound3DListener *iface)
1112 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1113 LONG ret;
1115 ret = InterlockedIncrement(&This->ds3d_ref);
1116 TRACE("(%p) ref %lu\n", iface, ret);
1118 return ret;
1121 static ULONG WINAPI DSPrimary3D_Release(IDirectSound3DListener *iface)
1123 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1124 LONG ret;
1126 ret = InterlockedDecrement(&This->ds3d_ref);
1127 TRACE("(%p) ref %lu\n", iface, ret);
1129 return ret;
1133 static HRESULT WINAPI DSPrimary3D_GetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE *distancefactor)
1135 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1137 TRACE("(%p)->(%p)\n", iface, distancefactor);
1139 if(!distancefactor)
1141 WARN("Invalid parameter %p\n", distancefactor);
1142 return DSERR_INVALIDPARAM;
1145 *distancefactor = This->current.ds3d.flDistanceFactor;
1146 return S_OK;
1149 static HRESULT WINAPI DSPrimary3D_GetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE *dopplerfactor)
1151 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1153 TRACE("(%p)->(%p)\n", iface, dopplerfactor);
1155 if(!dopplerfactor)
1157 WARN("Invalid parameter %p\n", dopplerfactor);
1158 return DSERR_INVALIDPARAM;
1161 *dopplerfactor = This->current.ds3d.flDopplerFactor;
1162 return S_OK;
1165 static HRESULT WINAPI DSPrimary3D_GetOrientation(IDirectSound3DListener *iface, D3DVECTOR *front, D3DVECTOR *top)
1167 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1169 TRACE("(%p)->(%p, %p)\n", iface, front, top);
1171 if(!front || !top)
1173 WARN("Invalid parameter %p %p\n", front, top);
1174 return DSERR_INVALIDPARAM;
1177 EnterCriticalSection(&This->share->crst);
1178 *front = This->current.ds3d.vOrientFront;
1179 *top = This->current.ds3d.vOrientTop;
1180 LeaveCriticalSection(&This->share->crst);
1181 return S_OK;
1184 static HRESULT WINAPI DSPrimary3D_GetPosition(IDirectSound3DListener *iface, D3DVECTOR *pos)
1186 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1188 TRACE("(%p)->(%p)\n", iface, pos);
1190 if(!pos)
1192 WARN("Invalid parameter %p\n", pos);
1193 return DSERR_INVALIDPARAM;
1196 EnterCriticalSection(&This->share->crst);
1197 *pos = This->current.ds3d.vPosition;
1198 LeaveCriticalSection(&This->share->crst);
1199 return S_OK;
1202 static HRESULT WINAPI DSPrimary3D_GetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE *rollofffactor)
1204 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1206 TRACE("(%p)->(%p)\n", iface, rollofffactor);
1208 if(!rollofffactor)
1210 WARN("Invalid parameter %p\n", rollofffactor);
1211 return DSERR_INVALIDPARAM;
1214 *rollofffactor = This->current.ds3d.flRolloffFactor;
1215 return S_OK;
1218 static HRESULT WINAPI DSPrimary3D_GetVelocity(IDirectSound3DListener *iface, D3DVECTOR *velocity)
1220 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1222 TRACE("(%p)->(%p)\n", iface, velocity);
1224 if(!velocity)
1226 WARN("Invalid parameter %p\n", velocity);
1227 return DSERR_INVALIDPARAM;
1230 EnterCriticalSection(&This->share->crst);
1231 *velocity = This->current.ds3d.vVelocity;
1232 LeaveCriticalSection(&This->share->crst);
1233 return S_OK;
1236 static HRESULT WINAPI DSPrimary3D_GetAllParameters(IDirectSound3DListener *iface, DS3DLISTENER *listener)
1238 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1240 TRACE("(%p)->(%p)\n", iface, listener);
1242 if(!listener || listener->dwSize < sizeof(*listener))
1244 WARN("Invalid DS3DLISTENER %p %lu\n", listener, listener ? listener->dwSize : 0);
1245 return DSERR_INVALIDPARAM;
1248 EnterCriticalSection(&This->share->crst);
1249 listener->vPosition = This->current.ds3d.vPosition;
1250 listener->vVelocity = This->current.ds3d.vVelocity;
1251 listener->vOrientFront = This->current.ds3d.vOrientFront;
1252 listener->vOrientTop = This->current.ds3d.vOrientTop;
1253 listener->flDistanceFactor = This->current.ds3d.flDistanceFactor;
1254 listener->flRolloffFactor = This->current.ds3d.flRolloffFactor;
1255 listener->flDopplerFactor = This->current.ds3d.flDopplerFactor;
1256 LeaveCriticalSection(&This->share->crst);
1258 return DS_OK;
1262 static HRESULT WINAPI DSPrimary3D_SetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1264 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1266 TRACE("(%p)->(%f, %lu)\n", iface, factor, apply);
1268 if(factor < DS3D_MINDISTANCEFACTOR ||
1269 factor > DS3D_MAXDISTANCEFACTOR)
1271 WARN("Invalid parameter %f\n", factor);
1272 return DSERR_INVALIDPARAM;
1275 EnterCriticalSection(&This->share->crst);
1276 if(apply == DS3D_DEFERRED)
1278 This->deferred.ds3d.flDistanceFactor = factor;
1279 This->dirty.bit.distancefactor = 1;
1281 else
1283 setALContext(This->ctx);
1284 This->current.ds3d.flDistanceFactor = factor;
1285 alSpeedOfSound(343.3f/factor);
1286 checkALError();
1287 popALContext();
1289 LeaveCriticalSection(&This->share->crst);
1291 return S_OK;
1294 static HRESULT WINAPI DSPrimary3D_SetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1296 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1298 TRACE("(%p)->(%f, %lu)\n", iface, factor, apply);
1300 if(factor < DS3D_MINDOPPLERFACTOR ||
1301 factor > DS3D_MAXDOPPLERFACTOR)
1303 WARN("Invalid parameter %f\n", factor);
1304 return DSERR_INVALIDPARAM;
1307 EnterCriticalSection(&This->share->crst);
1308 if(apply == DS3D_DEFERRED)
1310 This->deferred.ds3d.flDopplerFactor = factor;
1311 This->dirty.bit.dopplerfactor = 1;
1313 else
1315 setALContext(This->ctx);
1316 This->current.ds3d.flDopplerFactor = factor;
1317 alDopplerFactor(factor);
1318 checkALError();
1319 popALContext();
1321 LeaveCriticalSection(&This->share->crst);
1323 return S_OK;
1326 static HRESULT WINAPI DSPrimary3D_SetOrientation(IDirectSound3DListener *iface, D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront, D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop, DWORD apply)
1328 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1330 TRACE("(%p)->(%f, %f, %f, %f, %f, %f, %lu)\n", iface, xFront, yFront, zFront, xTop, yTop, zTop, apply);
1332 EnterCriticalSection(&This->share->crst);
1333 if(apply == DS3D_DEFERRED)
1335 This->deferred.ds3d.vOrientFront.x = xFront;
1336 This->deferred.ds3d.vOrientFront.y = yFront;
1337 This->deferred.ds3d.vOrientFront.z = zFront;
1338 This->deferred.ds3d.vOrientTop.x = xTop;
1339 This->deferred.ds3d.vOrientTop.y = yTop;
1340 This->deferred.ds3d.vOrientTop.z = zTop;
1341 This->dirty.bit.orientation = 1;
1343 else
1345 ALfloat orient[6] = {
1346 xFront, yFront, -zFront,
1347 xTop, yTop, -zTop
1349 This->current.ds3d.vOrientFront.x = xFront;
1350 This->current.ds3d.vOrientFront.y = yFront;
1351 This->current.ds3d.vOrientFront.z = zFront;
1352 This->current.ds3d.vOrientTop.x = xTop;
1353 This->current.ds3d.vOrientTop.y = yTop;
1354 This->current.ds3d.vOrientTop.z = zTop;
1356 setALContext(This->ctx);
1357 alListenerfv(AL_ORIENTATION, orient);
1358 checkALError();
1359 popALContext();
1361 LeaveCriticalSection(&This->share->crst);
1363 return S_OK;
1366 static HRESULT WINAPI DSPrimary3D_SetPosition(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1368 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1370 TRACE("(%p)->(%f, %f, %f, %lu)\n", iface, x, y, z, apply);
1372 EnterCriticalSection(&This->share->crst);
1373 if(apply == DS3D_DEFERRED)
1375 This->deferred.ds3d.vPosition.x = x;
1376 This->deferred.ds3d.vPosition.y = y;
1377 This->deferred.ds3d.vPosition.z = z;
1378 This->dirty.bit.pos = 1;
1380 else
1382 setALContext(This->ctx);
1383 This->current.ds3d.vPosition.x = x;
1384 This->current.ds3d.vPosition.y = y;
1385 This->current.ds3d.vPosition.z = z;
1386 alListener3f(AL_POSITION, x, y, -z);
1387 checkALError();
1388 popALContext();
1390 LeaveCriticalSection(&This->share->crst);
1392 return S_OK;
1395 static HRESULT WINAPI DSPrimary3D_SetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1397 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1399 TRACE("(%p)->(%f, %lu)\n", iface, factor, apply);
1401 if(factor < DS3D_MINROLLOFFFACTOR ||
1402 factor > DS3D_MAXROLLOFFFACTOR)
1404 WARN("Invalid parameter %f\n", factor);
1405 return DSERR_INVALIDPARAM;
1408 EnterCriticalSection(&This->share->crst);
1409 if(apply == DS3D_DEFERRED)
1411 This->deferred.ds3d.flRolloffFactor = factor;
1412 This->dirty.bit.rollofffactor = 1;
1414 else
1416 struct DSBufferGroup *bufgroup = This->BufferGroups;
1417 DWORD i;
1419 This->current.ds3d.flRolloffFactor = factor;
1421 setALContext(This->ctx);
1422 for(i = 0;i < This->NumBufferGroups;++i)
1424 DWORD64 usemask = ~bufgroup[i].FreeBuffers;
1425 while(usemask)
1427 int idx = CTZ64(usemask);
1428 DSBuffer *buf = bufgroup[i].Buffers + idx;
1429 usemask &= ~(U64(1) << idx);
1431 if(buf->source)
1432 alSourcef(buf->source, AL_ROLLOFF_FACTOR, factor);
1435 checkALError();
1436 popALContext();
1438 LeaveCriticalSection(&This->share->crst);
1440 return S_OK;
1443 static HRESULT WINAPI DSPrimary3D_SetVelocity(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1445 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1447 TRACE("(%p)->(%f, %f, %f, %lu)\n", iface, x, y, z, apply);
1449 EnterCriticalSection(&This->share->crst);
1450 if(apply == DS3D_DEFERRED)
1452 This->deferred.ds3d.vVelocity.x = x;
1453 This->deferred.ds3d.vVelocity.y = y;
1454 This->deferred.ds3d.vVelocity.z = z;
1455 This->dirty.bit.vel = 1;
1457 else
1459 setALContext(This->ctx);
1460 This->current.ds3d.vVelocity.x = x;
1461 This->current.ds3d.vVelocity.y = y;
1462 This->current.ds3d.vVelocity.z = z;
1463 alListener3f(AL_VELOCITY, x, y, -z);
1464 checkALError();
1465 popALContext();
1467 LeaveCriticalSection(&This->share->crst);
1469 return S_OK;
1472 static HRESULT WINAPI DSPrimary3D_SetAllParameters(IDirectSound3DListener *iface, const DS3DLISTENER *listen, DWORD apply)
1474 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1476 TRACE("(%p)->(%p, %lu)\n", iface, listen, apply);
1478 if(!listen || listen->dwSize < sizeof(*listen))
1480 WARN("Invalid parameter %p %lu\n", listen, listen ? listen->dwSize : 0);
1481 return DSERR_INVALIDPARAM;
1484 if(listen->flDistanceFactor > DS3D_MAXDISTANCEFACTOR ||
1485 listen->flDistanceFactor < DS3D_MINDISTANCEFACTOR)
1487 WARN("Invalid distance factor (%f)\n", listen->flDistanceFactor);
1488 return DSERR_INVALIDPARAM;
1491 if(listen->flDopplerFactor > DS3D_MAXDOPPLERFACTOR ||
1492 listen->flDopplerFactor < DS3D_MINDOPPLERFACTOR)
1494 WARN("Invalid doppler factor (%f)\n", listen->flDopplerFactor);
1495 return DSERR_INVALIDPARAM;
1498 if(listen->flRolloffFactor < DS3D_MINROLLOFFFACTOR ||
1499 listen->flRolloffFactor > DS3D_MAXROLLOFFFACTOR)
1501 WARN("Invalid rolloff factor (%f)\n", listen->flRolloffFactor);
1502 return DSERR_INVALIDPARAM;
1505 if(apply == DS3D_DEFERRED)
1507 EnterCriticalSection(&This->share->crst);
1508 This->deferred.ds3d = *listen;
1509 This->deferred.ds3d.dwSize = sizeof(This->deferred.ds3d);
1510 This->dirty.bit.pos = 1;
1511 This->dirty.bit.vel = 1;
1512 This->dirty.bit.orientation = 1;
1513 This->dirty.bit.distancefactor = 1;
1514 This->dirty.bit.rollofffactor = 1;
1515 This->dirty.bit.dopplerfactor = 1;
1516 LeaveCriticalSection(&This->share->crst);
1518 else
1520 union PrimaryParamFlags dirty = { 0l };
1521 dirty.bit.pos = 1;
1522 dirty.bit.vel = 1;
1523 dirty.bit.orientation = 1;
1524 dirty.bit.distancefactor = 1;
1525 dirty.bit.rollofffactor = 1;
1526 dirty.bit.dopplerfactor = 1;
1528 EnterCriticalSection(&This->share->crst);
1529 setALContext(This->ctx);
1530 DSPrimary_SetParams(This, listen, dirty.flags);
1531 checkALError();
1532 popALContext();
1533 LeaveCriticalSection(&This->share->crst);
1536 return S_OK;
1539 HRESULT WINAPI DSPrimary3D_CommitDeferredSettings(IDirectSound3DListener *iface)
1541 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1542 struct DSBufferGroup *bufgroup;
1543 LONG flags;
1544 DWORD i;
1546 EnterCriticalSection(&This->share->crst);
1547 setALContext(This->ctx);
1548 alDeferUpdatesSOFT();
1550 if((flags=InterlockedExchange(&This->dirty.flags, 0)) != 0)
1552 DSPrimary_SetParams(This, &This->deferred.ds3d, flags);
1553 /* checkALError is here for debugging */
1554 checkALError();
1556 TRACE("Dirty flags was: 0x%02lx\n", flags);
1558 bufgroup = This->BufferGroups;
1559 for(i = 0;i < This->NumBufferGroups;++i)
1561 DWORD64 usemask = ~bufgroup[i].FreeBuffers;
1562 while(usemask)
1564 int idx = CTZ64(usemask);
1565 DSBuffer *buf = bufgroup[i].Buffers + idx;
1566 usemask &= ~(U64(1) << idx);
1568 if((flags=InterlockedExchange(&buf->dirty.flags, 0)) != 0)
1569 DSBuffer_SetParams(buf, &buf->deferred.ds3d, flags);
1572 alProcessUpdatesSOFT();
1573 checkALError();
1575 popALContext();
1576 LeaveCriticalSection(&This->share->crst);
1578 return DS_OK;
1581 static IDirectSound3DListenerVtbl DSPrimary3D_Vtbl =
1583 DSPrimary3D_QueryInterface,
1584 DSPrimary3D_AddRef,
1585 DSPrimary3D_Release,
1586 DSPrimary3D_GetAllParameters,
1587 DSPrimary3D_GetDistanceFactor,
1588 DSPrimary3D_GetDopplerFactor,
1589 DSPrimary3D_GetOrientation,
1590 DSPrimary3D_GetPosition,
1591 DSPrimary3D_GetRolloffFactor,
1592 DSPrimary3D_GetVelocity,
1593 DSPrimary3D_SetAllParameters,
1594 DSPrimary3D_SetDistanceFactor,
1595 DSPrimary3D_SetDopplerFactor,
1596 DSPrimary3D_SetOrientation,
1597 DSPrimary3D_SetPosition,
1598 DSPrimary3D_SetRolloffFactor,
1599 DSPrimary3D_SetVelocity,
1600 DSPrimary3D_CommitDeferredSettings
1604 static HRESULT WINAPI DSPrimaryProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
1606 DSPrimary *This = impl_from_IKsPropertySet(iface);
1607 return DSPrimary_QueryInterface(&This->IDirectSoundBuffer_iface, riid, ppv);
1610 static ULONG WINAPI DSPrimaryProp_AddRef(IKsPropertySet *iface)
1612 DSPrimary *This = impl_from_IKsPropertySet(iface);
1613 LONG ret;
1615 ret = InterlockedIncrement(&This->prop_ref);
1616 TRACE("(%p) ref %lu\n", iface, ret);
1618 return ret;
1621 static ULONG WINAPI DSPrimaryProp_Release(IKsPropertySet *iface)
1623 DSPrimary *This = impl_from_IKsPropertySet(iface);
1624 LONG ret;
1626 ret = InterlockedDecrement(&This->prop_ref);
1627 TRACE("(%p) ref %lu\n", iface, ret);
1629 return ret;
1632 static HRESULT WINAPI DSPrimaryProp_Get(IKsPropertySet *iface,
1633 REFGUID guidPropSet, ULONG dwPropID,
1634 LPVOID pInstanceData, ULONG cbInstanceData,
1635 LPVOID pPropData, ULONG cbPropData,
1636 ULONG *pcbReturned)
1638 (void)iface;
1639 (void)dwPropID;
1640 (void)pInstanceData;
1641 (void)cbInstanceData;
1642 (void)pPropData;
1643 (void)cbPropData;
1644 (void)pcbReturned;
1646 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
1648 return E_PROP_ID_UNSUPPORTED;
1651 static HRESULT WINAPI DSPrimaryProp_Set(IKsPropertySet *iface,
1652 REFGUID guidPropSet, ULONG dwPropID,
1653 LPVOID pInstanceData, ULONG cbInstanceData,
1654 LPVOID pPropData, ULONG cbPropData)
1656 (void)iface;
1657 (void)dwPropID;
1658 (void)pInstanceData;
1659 (void)cbInstanceData;
1660 (void)pPropData;
1661 (void)cbPropData;
1663 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
1665 return E_PROP_ID_UNSUPPORTED;
1668 static HRESULT WINAPI DSPrimaryProp_QuerySupport(IKsPropertySet *iface,
1669 REFGUID guidPropSet, ULONG dwPropID,
1670 ULONG *pTypeSupport)
1672 (void)iface;
1673 (void)pTypeSupport;
1675 FIXME("Unhandled propset: %s (propid: %lu)\n", debugstr_guid(guidPropSet), dwPropID);
1677 return E_PROP_ID_UNSUPPORTED;
1680 static IKsPropertySetVtbl DSPrimaryProp_Vtbl =
1682 DSPrimaryProp_QueryInterface,
1683 DSPrimaryProp_AddRef,
1684 DSPrimaryProp_Release,
1685 DSPrimaryProp_Get,
1686 DSPrimaryProp_Set,
1687 DSPrimaryProp_QuerySupport