Rename some types and methods for a bit of consistency
[dsound-openal.git] / primary.c
blobac4d891409bd86b3867d6f68344cc1fc0f5f2830
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 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)
73 continue;
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);
80 SetEvent(event);
83 else if(ofs >= lastpos && ofs < curpos) /* Normal case */
85 TRACE("Triggering notification %d from buffer %p\n", 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", 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;
298 This->auxslot = parent->share->auxslot;
300 wfx = &This->format.Format;
301 wfx->wFormatTag = WAVE_FORMAT_PCM;
302 wfx->nChannels = 2;
303 wfx->wBitsPerSample = 8;
304 wfx->nSamplesPerSec = 22050;
305 wfx->nBlockAlign = wfx->wBitsPerSample * wfx->nChannels / 8;
306 wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
307 wfx->cbSize = 0;
309 This->stopped = TRUE;
311 /* Apparently primary buffer size is always 32k,
312 * tested on windows with 192k 24 bits sound @ 6 channels
313 * where it will run out in 60 ms and it isn't pointer aligned
315 This->buf_size = 32768;
317 setALContext(This->ctx);
318 This->deferred.eax = EnvironmentDefaults[EAX_ENVIRONMENT_GENERIC];
319 This->deferred.eax1_volume = 0.5f;
320 This->deferred.eax1_dampening = 0.5f;
321 if(This->auxslot != 0)
323 ALint revid = alGetEnumValue("AL_EFFECT_EAXREVERB");
324 if(revid != 0 && revid != -1)
326 alGenEffects(1, &This->effect);
327 alEffecti(This->effect, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB);
328 checkALError();
331 popALContext();
333 num_srcs = This->share->sources.maxhw_alloc + This->share->sources.maxsw_alloc;
335 hr = DSERR_OUTOFMEMORY;
336 This->notifies = HeapAlloc(GetProcessHeap(), 0, num_srcs*sizeof(*This->notifies));
337 if(!This->notifies) goto fail;
338 This->sizenotifies = num_srcs;
340 count = (MAX_HWBUFFERS+63) / 64;
341 This->BufferGroups = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
342 count*sizeof(*This->BufferGroups));
343 if(!This->BufferGroups) goto fail;
345 for(i = 0;i < count;++i)
347 This->BufferGroups[i].Buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
348 64*sizeof(This->BufferGroups[0].Buffers[0]));
349 if(!This->BufferGroups[i].Buffers)
351 while(i > 0)
352 HeapFree(GetProcessHeap(), 0, This->BufferGroups[--i].Buffers);
353 HeapFree(GetProcessHeap(), 0, This->BufferGroups);
354 This->BufferGroups = NULL;
355 goto fail;
357 This->BufferGroups[i].FreeBuffers = ~(DWORD64)0;
359 This->NumBufferGroups = count;
361 return S_OK;
363 fail:
364 DSPrimary_Clear(This);
365 return hr;
368 void DSPrimary_Clear(DSPrimary *This)
370 struct DSBufferGroup *bufgroup;
371 DWORD i;
373 TRACE("Clearing primary %p\n", This);
375 if(!This->parent)
376 return;
378 setALContext(This->ctx);
379 if(This->effect)
380 alDeleteEffects(1, &This->effect);
381 popALContext();
383 bufgroup = This->BufferGroups;
384 for(i = 0;i < This->NumBufferGroups;++i)
386 DWORD64 usemask = ~bufgroup[i].FreeBuffers;
387 while(usemask)
389 int idx = CTZ64(usemask);
390 DSBuffer *buf = bufgroup[i].Buffers + idx;
391 usemask &= ~(U64(1) << idx);
393 DSBuffer_Destroy(buf);
395 HeapFree(GetProcessHeap(), 0, This->BufferGroups[i].Buffers);
398 HeapFree(GetProcessHeap(), 0, This->BufferGroups);
399 HeapFree(GetProcessHeap(), 0, This->notifies);
400 memset(This, 0, sizeof(*This));
403 static HRESULT WINAPI DSPrimary_QueryInterface(IDirectSoundBuffer *iface, REFIID riid, LPVOID *ppv)
405 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
407 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
409 *ppv = NULL;
410 if(IsEqualIID(riid, &IID_IUnknown) ||
411 IsEqualIID(riid, &IID_IDirectSoundBuffer))
412 *ppv = &This->IDirectSoundBuffer_iface;
413 else if(IsEqualIID(riid, &IID_IDirectSound3DListener))
415 if((This->flags&DSBCAPS_CTRL3D))
416 *ppv = &This->IDirectSound3DListener_iface;
418 else if(IsEqualIID(riid, &IID_IKsPropertySet))
419 *ppv = &This->IKsPropertySet_iface;
420 else
421 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
423 if(*ppv)
425 IUnknown_AddRef((IUnknown*)*ppv);
426 return S_OK;
429 return E_NOINTERFACE;
432 static ULONG WINAPI DSPrimary_AddRef(IDirectSoundBuffer *iface)
434 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
435 LONG ret;
437 ret = InterlockedIncrement(&This->ref);
438 if(ret == 1) This->flags = 0;
439 TRACE("(%p) ref %lu\n", iface, ret);
441 return ret;
444 static ULONG WINAPI DSPrimary_Release(IDirectSoundBuffer *iface)
446 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
447 LONG ref, oldval;
449 oldval = *(volatile LONG*)&This->ref;
450 do {
451 ref = oldval;
452 if(ref)
454 --ref;
455 oldval = InterlockedCompareExchange(&This->ref, ref, ref+1)-1;
457 } while(oldval != ref);
458 TRACE("(%p) ref %lu\n", iface, ref);
460 return ref;
463 static HRESULT WINAPI DSPrimary_GetCaps(IDirectSoundBuffer *iface, DSBCAPS *caps)
465 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
467 TRACE("(%p)->(%p)\n", iface, caps);
469 if(!caps || caps->dwSize < sizeof(*caps))
471 WARN("Invalid DSBCAPS (%p, %lu)\n", caps, caps ? caps->dwSize : 0);
472 return DSERR_INVALIDPARAM;
475 caps->dwFlags = This->flags;
476 caps->dwBufferBytes = This->buf_size;
477 caps->dwUnlockTransferRate = 0;
478 caps->dwPlayCpuOverhead = 0;
480 return DS_OK;
483 static HRESULT WINAPI DSPrimary_GetCurrentPosition(IDirectSoundBuffer *iface, DWORD *playpos, DWORD *curpos)
485 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
486 HRESULT hr = DSERR_PRIOLEVELNEEDED;
488 EnterCriticalSection(&This->share->crst);
489 if(This->write_emu)
490 hr = IDirectSoundBuffer8_GetCurrentPosition(This->write_emu, playpos, curpos);
491 LeaveCriticalSection(&This->share->crst);
493 return hr;
496 static HRESULT WINAPI DSPrimary_GetFormat(IDirectSoundBuffer *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
498 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
499 HRESULT hr = S_OK;
500 UINT size;
502 if(!wfx && !written)
504 WARN("Cannot report format or format size\n");
505 return DSERR_INVALIDPARAM;
508 EnterCriticalSection(&This->share->crst);
509 size = sizeof(This->format.Format) + This->format.Format.cbSize;
510 if(written)
511 *written = size;
512 if(wfx)
514 if(allocated < size)
515 hr = DSERR_INVALIDPARAM;
516 else
517 memcpy(wfx, &This->format.Format, size);
519 LeaveCriticalSection(&This->share->crst);
521 return hr;
524 static HRESULT WINAPI DSPrimary_GetVolume(IDirectSoundBuffer *iface, LONG *volume)
526 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
527 ALfloat gain;
529 TRACE("(%p)->(%p)\n", iface, volume);
531 if(!volume)
532 return DSERR_INVALIDPARAM;
533 *volume = 0;
535 if(!(This->flags&DSBCAPS_CTRLVOLUME))
536 return DSERR_CONTROLUNAVAIL;
538 setALContext(This->ctx);
539 alGetListenerf(AL_GAIN, &gain);
540 checkALError();
541 popALContext();
543 *volume = clampI(gain_to_mB(gain), DSBVOLUME_MIN, DSBVOLUME_MAX);
544 return DS_OK;
547 static HRESULT WINAPI DSPrimary_GetPan(IDirectSoundBuffer *iface, LONG *pan)
549 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
550 HRESULT hr = DS_OK;
552 WARN("(%p)->(%p): semi-stub\n", iface, pan);
554 if(!pan)
555 return DSERR_INVALIDPARAM;
557 EnterCriticalSection(&This->share->crst);
558 if(This->write_emu)
559 hr = IDirectSoundBuffer8_GetPan(This->write_emu, pan);
560 else if(!(This->flags & DSBCAPS_CTRLPAN))
561 hr = DSERR_CONTROLUNAVAIL;
562 else
563 *pan = 0;
564 LeaveCriticalSection(&This->share->crst);
566 return hr;
569 static HRESULT WINAPI DSPrimary_GetFrequency(IDirectSoundBuffer *iface, DWORD *freq)
571 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
572 HRESULT hr = DS_OK;
574 WARN("(%p)->(%p): semi-stub\n", iface, freq);
576 if(!freq)
577 return DSERR_INVALIDPARAM;
579 if(!(This->flags&DSBCAPS_CTRLFREQUENCY))
580 return DSERR_CONTROLUNAVAIL;
582 EnterCriticalSection(&This->share->crst);
583 *freq = This->format.Format.nSamplesPerSec;
584 LeaveCriticalSection(&This->share->crst);
586 return hr;
589 static HRESULT WINAPI DSPrimary_GetStatus(IDirectSoundBuffer *iface, DWORD *status)
591 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
593 TRACE("(%p)->(%p)\n", iface, status);
595 if(!status)
596 return DSERR_INVALIDPARAM;
598 EnterCriticalSection(&This->share->crst);
599 *status = DSBSTATUS_PLAYING|DSBSTATUS_LOOPING;
600 if((This->flags&DSBCAPS_LOCDEFER))
601 *status |= DSBSTATUS_LOCHARDWARE;
603 if(This->stopped)
605 struct DSBufferGroup *bufgroup = This->BufferGroups;
606 DWORD i, state = 0;
607 HRESULT hr;
609 for(i = 0;i < This->NumBufferGroups;++i)
611 DWORD64 usemask = ~bufgroup[i].FreeBuffers;
612 while(usemask)
614 int idx = CTZ64(usemask);
615 DSBuffer *buf = bufgroup[i].Buffers + idx;
616 usemask &= ~(U64(1) << idx);
618 hr = DSBuffer_GetStatus(&buf->IDirectSoundBuffer8_iface, &state);
619 if(SUCCEEDED(hr) && (state&DSBSTATUS_PLAYING)) break;
622 if(!(state&DSBSTATUS_PLAYING))
624 /* Primary stopped and no buffers playing.. */
625 *status = 0;
628 LeaveCriticalSection(&This->share->crst);
630 return DS_OK;
633 HRESULT WINAPI DSPrimary_Initialize(IDirectSoundBuffer *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
635 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
636 HRESULT hr;
638 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
640 if(!desc || desc->lpwfxFormat || desc->dwBufferBytes)
642 WARN("Bad DSBDESC for primary buffer\n");
643 return DSERR_INVALIDPARAM;
645 if((desc->dwFlags&DSBCAPS_CTRLFX) ||
646 (desc->dwFlags&DSBCAPS_CTRLPOSITIONNOTIFY) ||
647 (desc->dwFlags&DSBCAPS_LOCSOFTWARE))
649 WARN("Bad dwFlags %08lx\n", desc->dwFlags);
650 return DSERR_INVALIDPARAM;
653 /* Should be 0 if not initialized */
654 if(This->flags)
655 return DSERR_ALREADYINITIALIZED;
657 hr = DS_OK;
658 if(This->parent->prio_level == DSSCL_WRITEPRIMARY)
660 DSBUFFERDESC emudesc;
661 DSBuffer *emu;
663 if(This->write_emu)
665 ERR("There shouldn't be a write_emu!\n");
666 IDirectSoundBuffer8_Release(This->write_emu);
667 This->write_emu = NULL;
670 memset(&emudesc, 0, sizeof(emudesc));
671 emudesc.dwSize = sizeof(emudesc);
672 emudesc.dwFlags = DSBCAPS_LOCHARDWARE | (desc->dwFlags&DSBCAPS_CTRLPAN);
673 /* Dont play last incomplete sample */
674 emudesc.dwBufferBytes = This->buf_size - (This->buf_size%This->format.Format.nBlockAlign);
675 emudesc.lpwfxFormat = &This->format.Format;
677 hr = DSBuffer_Create(&emu, This, NULL);
678 if(SUCCEEDED(hr))
680 This->write_emu = &emu->IDirectSoundBuffer8_iface;
681 hr = DSBuffer_Initialize(This->write_emu, ds, &emudesc);
682 if(FAILED(hr))
684 IDirectSoundBuffer8_Release(This->write_emu);
685 This->write_emu = NULL;
690 if(SUCCEEDED(hr))
692 DS3DLISTENER *listener = &This->deferred.ds3d;
693 listener->dwSize = sizeof(This->deferred.ds3d);
694 listener->vPosition.x = 0.0f;
695 listener->vPosition.y = 0.0f;
696 listener->vPosition.z = 0.0f;
697 listener->vVelocity.x = 0.0f;
698 listener->vVelocity.y = 0.0f;
699 listener->vVelocity.z = 0.0f;
700 listener->vOrientFront.x = 0.0f;
701 listener->vOrientFront.y = 0.0f;
702 listener->vOrientFront.z = 1.0f;
703 listener->vOrientTop.x = 0.0f;
704 listener->vOrientTop.y = 1.0f;
705 listener->vOrientTop.z = 0.0f;
706 listener->flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
707 listener->flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
708 listener->flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
710 This->flags = desc->dwFlags | DSBCAPS_LOCHARDWARE;
712 if((This->flags&DSBCAPS_CTRL3D))
714 union PrimaryParamFlags dirty = { 0l };
716 dirty.bit.pos = 1;
717 dirty.bit.vel = 1;
718 dirty.bit.orientation = 1;
719 dirty.bit.distancefactor = 1;
720 dirty.bit.rollofffactor = 1;
721 dirty.bit.dopplerfactor = 1;
722 DSPrimary_SetParams(This, listener, dirty.flags);
725 return hr;
728 static HRESULT WINAPI DSPrimary_Lock(IDirectSoundBuffer *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
730 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
731 HRESULT hr = DSERR_PRIOLEVELNEEDED;
733 TRACE("(%p)->(%lu, %lu, %p, %p, %p, %p, %lu)\n", iface, ofs, bytes, ptr1, len1, ptr2, len2, flags);
735 EnterCriticalSection(&This->share->crst);
736 if(This->write_emu)
737 hr = IDirectSoundBuffer8_Lock(This->write_emu, ofs, bytes, ptr1, len1, ptr2, len2, flags);
738 LeaveCriticalSection(&This->share->crst);
740 return hr;
743 static HRESULT WINAPI DSPrimary_Play(IDirectSoundBuffer *iface, DWORD res1, DWORD res2, DWORD flags)
745 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
746 HRESULT hr;
748 TRACE("(%p)->(%lu, %lu, %lu)\n", iface, res1, res2, flags);
750 if(!(flags & DSBPLAY_LOOPING))
752 WARN("Flags (%08lx) not set to DSBPLAY_LOOPING\n", flags);
753 return DSERR_INVALIDPARAM;
756 EnterCriticalSection(&This->share->crst);
757 hr = S_OK;
758 if(This->write_emu)
759 hr = IDirectSoundBuffer8_Play(This->write_emu, res1, res2, flags);
760 if(SUCCEEDED(hr))
761 This->stopped = FALSE;
762 LeaveCriticalSection(&This->share->crst);
764 return hr;
767 static HRESULT WINAPI DSPrimary_SetCurrentPosition(IDirectSoundBuffer *iface, DWORD pos)
769 WARN("(%p)->(%lu)\n", iface, pos);
770 return DSERR_INVALIDCALL;
773 /* Just assume the format is crap, and clean up the damage */
774 static HRESULT copy_waveformat(WAVEFORMATEX *wfx, const WAVEFORMATEX *from)
776 if(from->nChannels <= 0)
778 WARN("Invalid Channels %d\n", from->nChannels);
779 return DSERR_INVALIDPARAM;
781 if(from->nSamplesPerSec < DSBFREQUENCY_MIN || from->nSamplesPerSec > DSBFREQUENCY_MAX)
783 WARN("Invalid SamplesPerSec %lu\n", from->nSamplesPerSec);
784 return DSERR_INVALIDPARAM;
786 if(from->nBlockAlign <= 0)
788 WARN("Invalid BlockAlign %d\n", from->nBlockAlign);
789 return DSERR_INVALIDPARAM;
791 if(from->wBitsPerSample == 0 || (from->wBitsPerSample%8) != 0)
793 WARN("Invalid BitsPerSample %d\n", from->wBitsPerSample);
794 return DSERR_INVALIDPARAM;
796 if(from->nBlockAlign != from->nChannels*from->wBitsPerSample/8)
798 WARN("Invalid BlockAlign %d (expected %u = %u*%u/8)\n",
799 from->nBlockAlign, from->nChannels*from->wBitsPerSample/8,
800 from->nChannels, from->wBitsPerSample);
801 return DSERR_INVALIDPARAM;
803 if(from->nAvgBytesPerSec != from->nBlockAlign*from->nSamplesPerSec)
805 WARN("Invalid AvgBytesPerSec %lu (expected %lu = %lu*%u)\n",
806 from->nAvgBytesPerSec, from->nSamplesPerSec*from->nBlockAlign,
807 from->nSamplesPerSec, from->nBlockAlign);
808 return DSERR_INVALIDPARAM;
811 if(from->wFormatTag == WAVE_FORMAT_PCM)
813 if(from->wBitsPerSample > 32)
814 return DSERR_INVALIDPARAM;
815 wfx->cbSize = 0;
817 else if(from->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
819 if(from->wBitsPerSample != 32)
820 return DSERR_INVALIDPARAM;
821 wfx->cbSize = 0;
823 else if(from->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
825 WAVEFORMATEXTENSIBLE *wfe = (WAVEFORMATEXTENSIBLE*)wfx;
826 const WAVEFORMATEXTENSIBLE *fromx = (const WAVEFORMATEXTENSIBLE*)from;
827 const WORD size = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
829 /* Fail silently.. */
830 if(from->cbSize < size) return DS_OK;
831 if(fromx->Samples.wValidBitsPerSample > fromx->Format.wBitsPerSample)
832 return DSERR_INVALIDPARAM;
834 if(IsEqualGUID(&fromx->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
836 if(from->wBitsPerSample > 32)
837 return DSERR_INVALIDPARAM;
839 else if(IsEqualGUID(&fromx->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
841 if(from->wBitsPerSample != 32)
842 return DSERR_INVALIDPARAM;
844 else
846 ERR("Unhandled extensible format: %s\n", debugstr_guid(&fromx->SubFormat));
847 return DSERR_INVALIDPARAM;
850 wfe->Format.cbSize = size;
851 wfe->Samples.wValidBitsPerSample = fromx->Samples.wValidBitsPerSample;
852 if(!wfe->Samples.wValidBitsPerSample)
853 wfe->Samples.wValidBitsPerSample = fromx->Format.wBitsPerSample;
854 wfe->dwChannelMask = fromx->dwChannelMask;
855 wfe->SubFormat = fromx->SubFormat;
857 else
859 ERR("Unhandled format tag %04x\n", from->wFormatTag);
860 return DSERR_INVALIDPARAM;
863 wfx->wFormatTag = from->wFormatTag;
864 wfx->nChannels = from->nChannels;
865 wfx->nSamplesPerSec = from->nSamplesPerSec;
866 wfx->nAvgBytesPerSec = from->nSamplesPerSec * from->nBlockAlign;
867 wfx->nBlockAlign = from->wBitsPerSample * from->nChannels / 8;
868 wfx->wBitsPerSample = from->wBitsPerSample;
869 return DS_OK;
872 static HRESULT WINAPI DSPrimary_SetFormat(IDirectSoundBuffer *iface, const WAVEFORMATEX *wfx)
874 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
875 HRESULT hr = S_OK;
877 TRACE("(%p)->(%p)\n", iface, wfx);
879 if(!wfx)
881 WARN("Missing format\n");
882 return DSERR_INVALIDPARAM;
885 EnterCriticalSection(&This->share->crst);
887 if(This->parent->prio_level < DSSCL_PRIORITY)
889 hr = DSERR_PRIOLEVELNEEDED;
890 goto out;
893 TRACE("Requested primary format:\n"
894 " FormatTag = %04x\n"
895 " Channels = %u\n"
896 " SamplesPerSec = %lu\n"
897 " AvgBytesPerSec = %lu\n"
898 " BlockAlign = %u\n"
899 " BitsPerSample = %u\n",
900 wfx->wFormatTag, wfx->nChannels,
901 wfx->nSamplesPerSec, wfx->nAvgBytesPerSec,
902 wfx->nBlockAlign, wfx->wBitsPerSample);
904 hr = copy_waveformat(&This->format.Format, wfx);
905 if(SUCCEEDED(hr) && This->write_emu)
907 DSBuffer *buf;
908 DSBUFFERDESC desc;
910 IDirectSoundBuffer8_Release(This->write_emu);
911 This->write_emu = NULL;
913 memset(&desc, 0, sizeof(desc));
914 desc.dwSize = sizeof(desc);
915 desc.dwFlags = DSBCAPS_LOCHARDWARE|DSBCAPS_CTRLPAN;
916 desc.dwBufferBytes = This->buf_size - (This->buf_size % This->format.Format.nBlockAlign);
917 desc.lpwfxFormat = &This->format.Format;
919 hr = DSBuffer_Create(&buf, This, NULL);
920 if(FAILED(hr)) goto out;
922 This->write_emu = &buf->IDirectSoundBuffer8_iface;
923 hr = DSBuffer_Initialize(This->write_emu, &This->parent->IDirectSound_iface, &desc);
924 if(FAILED(hr))
926 IDirectSoundBuffer8_Release(This->write_emu);
927 This->write_emu = NULL;
931 out:
932 LeaveCriticalSection(&This->share->crst);
933 return hr;
936 static HRESULT WINAPI DSPrimary_SetVolume(IDirectSoundBuffer *iface, LONG vol)
938 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
940 TRACE("(%p)->(%ld)\n", iface, vol);
942 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
944 WARN("Invalid volume (%ld)\n", vol);
945 return DSERR_INVALIDPARAM;
948 if(!(This->flags&DSBCAPS_CTRLVOLUME))
949 return DSERR_CONTROLUNAVAIL;
951 setALContext(This->ctx);
952 alListenerf(AL_GAIN, mB_to_gain(vol));
953 popALContext();
955 return DS_OK;
958 static HRESULT WINAPI DSPrimary_SetPan(IDirectSoundBuffer *iface, LONG pan)
960 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
961 HRESULT hr;
963 TRACE("(%p)->(%ld)\n", iface, pan);
965 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
967 WARN("invalid parameter: pan = %ld\n", pan);
968 return DSERR_INVALIDPARAM;
971 EnterCriticalSection(&This->share->crst);
972 if(!(This->flags&DSBCAPS_CTRLPAN))
974 WARN("control unavailable\n");
975 hr = DSERR_CONTROLUNAVAIL;
977 else if(This->write_emu)
978 hr = IDirectSoundBuffer8_SetPan(This->write_emu, pan);
979 else
981 FIXME("Not supported\n");
982 hr = E_NOTIMPL;
984 LeaveCriticalSection(&This->share->crst);
986 return hr;
989 static HRESULT WINAPI DSPrimary_SetFrequency(IDirectSoundBuffer *iface, DWORD freq)
991 WARN("(%p)->(%lu)\n", iface, freq);
992 return DSERR_CONTROLUNAVAIL;
995 static HRESULT WINAPI DSPrimary_Stop(IDirectSoundBuffer *iface)
997 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
998 HRESULT hr = S_OK;
1000 TRACE("(%p)->()\n", iface);
1002 EnterCriticalSection(&This->share->crst);
1003 if(This->write_emu)
1004 hr = IDirectSoundBuffer8_Stop(This->write_emu);
1005 if(SUCCEEDED(hr))
1006 This->stopped = TRUE;
1007 LeaveCriticalSection(&This->share->crst);
1009 return hr;
1012 static HRESULT WINAPI DSPrimary_Unlock(IDirectSoundBuffer *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
1014 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
1015 HRESULT hr = DSERR_INVALIDCALL;
1017 TRACE("(%p)->(%p, %lu, %p, %lu)\n", iface, ptr1, len1, ptr2, len2);
1019 EnterCriticalSection(&This->share->crst);
1020 if(This->write_emu)
1021 hr = IDirectSoundBuffer8_Unlock(This->write_emu, ptr1, len1, ptr2, len2);
1022 LeaveCriticalSection(&This->share->crst);
1024 return hr;
1027 static HRESULT WINAPI DSPrimary_Restore(IDirectSoundBuffer *iface)
1029 DSPrimary *This = impl_from_IDirectSoundBuffer(iface);
1030 HRESULT hr = S_OK;
1032 TRACE("(%p)->()\n", iface);
1034 EnterCriticalSection(&This->share->crst);
1035 if(This->write_emu)
1036 hr = IDirectSoundBuffer8_Restore(This->write_emu);
1037 LeaveCriticalSection(&This->share->crst);
1039 return hr;
1042 static const IDirectSoundBufferVtbl DSPrimary_Vtbl =
1044 DSPrimary_QueryInterface,
1045 DSPrimary_AddRef,
1046 DSPrimary_Release,
1047 DSPrimary_GetCaps,
1048 DSPrimary_GetCurrentPosition,
1049 DSPrimary_GetFormat,
1050 DSPrimary_GetVolume,
1051 DSPrimary_GetPan,
1052 DSPrimary_GetFrequency,
1053 DSPrimary_GetStatus,
1054 DSPrimary_Initialize,
1055 DSPrimary_Lock,
1056 DSPrimary_Play,
1057 DSPrimary_SetCurrentPosition,
1058 DSPrimary_SetFormat,
1059 DSPrimary_SetVolume,
1060 DSPrimary_SetPan,
1061 DSPrimary_SetFrequency,
1062 DSPrimary_Stop,
1063 DSPrimary_Unlock,
1064 DSPrimary_Restore
1068 static void DSPrimary_SetParams(DSPrimary *This, const DS3DLISTENER *params, LONG flags)
1070 union PrimaryParamFlags dirty = { flags };
1071 DWORD i;
1073 if(dirty.bit.pos)
1074 alListener3f(AL_POSITION, params->vPosition.x, params->vPosition.y,
1075 -params->vPosition.z);
1076 if(dirty.bit.vel)
1077 alListener3f(AL_VELOCITY, params->vVelocity.x, params->vVelocity.y,
1078 -params->vVelocity.z);
1079 if(dirty.bit.orientation)
1081 ALfloat orient[6] = {
1082 params->vOrientFront.x, params->vOrientFront.y, -params->vOrientFront.z,
1083 params->vOrientTop.x, params->vOrientTop.y, -params->vOrientTop.z
1085 alListenerfv(AL_ORIENTATION, orient);
1087 if(dirty.bit.distancefactor)
1089 alSpeedOfSound(343.3f/params->flDistanceFactor);
1090 if(HAS_EXTENSION(This->share, EXT_EFX))
1091 alListenerf(AL_METERS_PER_UNIT, params->flDistanceFactor);
1093 if(dirty.bit.rollofffactor)
1095 struct DSBufferGroup *bufgroup = This->BufferGroups;
1096 ALfloat rolloff = params->flRolloffFactor;
1097 This->rollofffactor = rolloff;
1099 for(i = 0;i < This->NumBufferGroups;++i)
1101 DWORD64 usemask = ~bufgroup[i].FreeBuffers;
1102 while(usemask)
1104 int idx = CTZ64(usemask);
1105 DSBuffer *buf = bufgroup[i].Buffers + idx;
1106 usemask &= ~(U64(1) << idx);
1108 if(buf->source)
1109 alSourcef(buf->source, AL_ROLLOFF_FACTOR,
1110 buf->current.eax.flRolloffFactor + rolloff);
1114 if(dirty.bit.dopplerfactor)
1115 alDopplerFactor(params->flDopplerFactor);
1116 if(dirty.bit.effect)
1117 alAuxiliaryEffectSloti(This->auxslot, AL_EFFECTSLOT_EFFECT, This->effect);
1120 static HRESULT WINAPI DSPrimary3D_QueryInterface(IDirectSound3DListener *iface, REFIID riid, void **ppv)
1122 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1123 return DSPrimary_QueryInterface(&This->IDirectSoundBuffer_iface, riid, ppv);
1126 static ULONG WINAPI DSPrimary3D_AddRef(IDirectSound3DListener *iface)
1128 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1129 LONG ret;
1131 ret = InterlockedIncrement(&This->ds3d_ref);
1132 TRACE("(%p) ref %lu\n", iface, ret);
1134 return ret;
1137 static ULONG WINAPI DSPrimary3D_Release(IDirectSound3DListener *iface)
1139 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1140 LONG ret;
1142 ret = InterlockedDecrement(&This->ds3d_ref);
1143 TRACE("(%p) ref %lu\n", iface, ret);
1145 return ret;
1149 static HRESULT WINAPI DSPrimary3D_GetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE *distancefactor)
1151 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1153 TRACE("(%p)->(%p)\n", iface, distancefactor);
1155 if(!distancefactor)
1157 WARN("Invalid parameter %p\n", distancefactor);
1158 return DSERR_INVALIDPARAM;
1161 setALContext(This->ctx);
1162 *distancefactor = 343.3f/alGetFloat(AL_SPEED_OF_SOUND);
1163 checkALError();
1164 popALContext();
1166 return S_OK;
1169 static HRESULT WINAPI DSPrimary3D_GetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE *dopplerfactor)
1171 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1173 TRACE("(%p)->(%p)\n", iface, dopplerfactor);
1175 if(!dopplerfactor)
1177 WARN("Invalid parameter %p\n", dopplerfactor);
1178 return DSERR_INVALIDPARAM;
1181 setALContext(This->ctx);
1182 *dopplerfactor = alGetFloat(AL_DOPPLER_FACTOR);
1183 checkALError();
1184 popALContext();
1186 return S_OK;
1189 static HRESULT WINAPI DSPrimary3D_GetOrientation(IDirectSound3DListener *iface, D3DVECTOR *front, D3DVECTOR *top)
1191 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1192 ALfloat orient[6];
1194 TRACE("(%p)->(%p, %p)\n", iface, front, top);
1196 if(!front || !top)
1198 WARN("Invalid parameter %p %p\n", front, top);
1199 return DSERR_INVALIDPARAM;
1202 setALContext(This->ctx);
1203 alGetListenerfv(AL_ORIENTATION, orient);
1204 checkALError();
1205 popALContext();
1207 front->x = orient[0];
1208 front->y = orient[1];
1209 front->z = -orient[2];
1210 top->x = orient[3];
1211 top->y = orient[4];
1212 top->z = -orient[5];
1213 return S_OK;
1216 static HRESULT WINAPI DSPrimary3D_GetPosition(IDirectSound3DListener *iface, D3DVECTOR *pos)
1218 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1219 ALfloat alpos[3];
1221 TRACE("(%p)->(%p)\n", iface, pos);
1223 if(!pos)
1225 WARN("Invalid parameter %p\n", pos);
1226 return DSERR_INVALIDPARAM;
1229 setALContext(This->ctx);
1230 alGetListenerfv(AL_POSITION, alpos);
1231 checkALError();
1232 popALContext();
1234 pos->x = alpos[0];
1235 pos->y = alpos[1];
1236 pos->z = -alpos[2];
1237 return S_OK;
1240 static HRESULT WINAPI DSPrimary3D_GetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE *rollofffactor)
1242 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1244 TRACE("(%p)->(%p)\n", iface, rollofffactor);
1246 if(!rollofffactor)
1248 WARN("Invalid parameter %p\n", rollofffactor);
1249 return DSERR_INVALIDPARAM;
1252 EnterCriticalSection(&This->share->crst);
1253 *rollofffactor = This->rollofffactor;
1254 LeaveCriticalSection(&This->share->crst);
1256 return S_OK;
1259 static HRESULT WINAPI DSPrimary3D_GetVelocity(IDirectSound3DListener *iface, D3DVECTOR *velocity)
1261 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1262 ALfloat vel[3];
1264 TRACE("(%p)->(%p)\n", iface, velocity);
1266 if(!velocity)
1268 WARN("Invalid parameter %p\n", velocity);
1269 return DSERR_INVALIDPARAM;
1272 setALContext(This->ctx);
1273 alGetListenerfv(AL_VELOCITY, vel);
1274 checkALError();
1275 popALContext();
1277 velocity->x = vel[0];
1278 velocity->y = vel[1];
1279 velocity->z = -vel[2];
1280 return S_OK;
1283 static HRESULT WINAPI DSPrimary3D_GetAllParameters(IDirectSound3DListener *iface, DS3DLISTENER *listener)
1285 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1287 TRACE("(%p)->(%p)\n", iface, listener);
1289 if(!listener || listener->dwSize < sizeof(*listener))
1291 WARN("Invalid DS3DLISTENER %p %lu\n", listener, listener ? listener->dwSize : 0);
1292 return DSERR_INVALIDPARAM;
1295 EnterCriticalSection(&This->share->crst);
1296 setALContext(This->ctx);
1297 DSPrimary3D_GetPosition(iface, &listener->vPosition);
1298 DSPrimary3D_GetVelocity(iface, &listener->vVelocity);
1299 DSPrimary3D_GetOrientation(iface, &listener->vOrientFront, &listener->vOrientTop);
1300 DSPrimary3D_GetDistanceFactor(iface, &listener->flDistanceFactor);
1301 DSPrimary3D_GetRolloffFactor(iface, &listener->flRolloffFactor);
1302 DSPrimary3D_GetDopplerFactor(iface, &listener->flDopplerFactor);
1303 popALContext();
1304 LeaveCriticalSection(&This->share->crst);
1306 return DS_OK;
1310 static HRESULT WINAPI DSPrimary3D_SetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1312 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1314 TRACE("(%p)->(%f, %lu)\n", iface, factor, apply);
1316 if(factor < DS3D_MINDISTANCEFACTOR ||
1317 factor > DS3D_MAXDISTANCEFACTOR)
1319 WARN("Invalid parameter %f\n", factor);
1320 return DSERR_INVALIDPARAM;
1323 if(apply == DS3D_DEFERRED)
1325 EnterCriticalSection(&This->share->crst);
1326 This->deferred.ds3d.flDistanceFactor = factor;
1327 This->dirty.bit.distancefactor = 1;
1328 LeaveCriticalSection(&This->share->crst);
1330 else
1332 setALContext(This->ctx);
1333 alSpeedOfSound(343.3f/factor);
1334 if(HAS_EXTENSION(This->share, EXT_EFX))
1335 alListenerf(AL_METERS_PER_UNIT, factor);
1336 checkALError();
1337 popALContext();
1340 return S_OK;
1343 static HRESULT WINAPI DSPrimary3D_SetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1345 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1347 TRACE("(%p)->(%f, %lu)\n", iface, factor, apply);
1349 if(factor < DS3D_MINDOPPLERFACTOR ||
1350 factor > DS3D_MAXDOPPLERFACTOR)
1352 WARN("Invalid parameter %f\n", factor);
1353 return DSERR_INVALIDPARAM;
1356 if(apply == DS3D_DEFERRED)
1358 EnterCriticalSection(&This->share->crst);
1359 This->deferred.ds3d.flDopplerFactor = factor;
1360 This->dirty.bit.dopplerfactor = 1;
1361 LeaveCriticalSection(&This->share->crst);
1363 else
1365 setALContext(This->ctx);
1366 alDopplerFactor(factor);
1367 checkALError();
1368 popALContext();
1371 return S_OK;
1374 static HRESULT WINAPI DSPrimary3D_SetOrientation(IDirectSound3DListener *iface, D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront, D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop, DWORD apply)
1376 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1378 TRACE("(%p)->(%f, %f, %f, %f, %f, %f, %lu)\n", iface, xFront, yFront, zFront, xTop, yTop, zTop, apply);
1380 if(apply == DS3D_DEFERRED)
1382 EnterCriticalSection(&This->share->crst);
1383 This->deferred.ds3d.vOrientFront.x = xFront;
1384 This->deferred.ds3d.vOrientFront.y = yFront;
1385 This->deferred.ds3d.vOrientFront.z = zFront;
1386 This->deferred.ds3d.vOrientTop.x = xTop;
1387 This->deferred.ds3d.vOrientTop.y = yTop;
1388 This->deferred.ds3d.vOrientTop.z = zTop;
1389 This->dirty.bit.orientation = 1;
1390 LeaveCriticalSection(&This->share->crst);
1392 else
1394 ALfloat orient[6] = {
1395 xFront, yFront, -zFront,
1396 xTop, yTop, -zTop
1398 setALContext(This->ctx);
1399 alListenerfv(AL_ORIENTATION, orient);
1400 checkALError();
1401 popALContext();
1404 return S_OK;
1407 static HRESULT WINAPI DSPrimary3D_SetPosition(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1409 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1411 TRACE("(%p)->(%f, %f, %f, %lu)\n", iface, x, y, z, apply);
1413 if(apply == DS3D_DEFERRED)
1415 EnterCriticalSection(&This->share->crst);
1416 This->deferred.ds3d.vPosition.x = x;
1417 This->deferred.ds3d.vPosition.y = y;
1418 This->deferred.ds3d.vPosition.z = z;
1419 This->dirty.bit.pos = 1;
1420 LeaveCriticalSection(&This->share->crst);
1422 else
1424 setALContext(This->ctx);
1425 alListener3f(AL_POSITION, x, y, -z);
1426 checkALError();
1427 popALContext();
1430 return S_OK;
1433 static HRESULT WINAPI DSPrimary3D_SetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1435 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1437 TRACE("(%p)->(%f, %lu)\n", iface, factor, apply);
1439 if(factor < DS3D_MINROLLOFFFACTOR ||
1440 factor > DS3D_MAXROLLOFFFACTOR)
1442 WARN("Invalid parameter %f\n", factor);
1443 return DSERR_INVALIDPARAM;
1446 EnterCriticalSection(&This->share->crst);
1447 if(apply == DS3D_DEFERRED)
1449 This->deferred.ds3d.flRolloffFactor = factor;
1450 This->dirty.bit.rollofffactor = 1;
1452 else
1454 struct DSBufferGroup *bufgroup = This->BufferGroups;
1455 DWORD i;
1457 This->rollofffactor = factor;
1459 setALContext(This->ctx);
1460 for(i = 0;i < This->NumBufferGroups;++i)
1462 DWORD64 usemask = ~bufgroup[i].FreeBuffers;
1463 while(usemask)
1465 int idx = CTZ64(usemask);
1466 DSBuffer *buf = bufgroup[i].Buffers + idx;
1467 usemask &= ~(U64(1) << idx);
1469 if(buf->source)
1470 alSourcef(buf->source, AL_ROLLOFF_FACTOR,
1471 buf->current.eax.flRolloffFactor + factor);
1474 checkALError();
1475 popALContext();
1477 LeaveCriticalSection(&This->share->crst);
1479 return S_OK;
1482 static HRESULT WINAPI DSPrimary3D_SetVelocity(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1484 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1486 TRACE("(%p)->(%f, %f, %f, %lu)\n", iface, x, y, z, apply);
1488 if(apply == DS3D_DEFERRED)
1490 EnterCriticalSection(&This->share->crst);
1491 This->deferred.ds3d.vVelocity.x = x;
1492 This->deferred.ds3d.vVelocity.y = y;
1493 This->deferred.ds3d.vVelocity.z = z;
1494 This->dirty.bit.vel = 1;
1495 LeaveCriticalSection(&This->share->crst);
1497 else
1499 setALContext(This->ctx);
1500 alListener3f(AL_VELOCITY, x, y, -z);
1501 checkALError();
1502 popALContext();
1505 return S_OK;
1508 static HRESULT WINAPI DSPrimary3D_SetAllParameters(IDirectSound3DListener *iface, const DS3DLISTENER *listen, DWORD apply)
1510 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1512 TRACE("(%p)->(%p, %lu)\n", iface, listen, apply);
1514 if(!listen || listen->dwSize < sizeof(*listen))
1516 WARN("Invalid parameter %p %lu\n", listen, listen ? listen->dwSize : 0);
1517 return DSERR_INVALIDPARAM;
1520 if(listen->flDistanceFactor > DS3D_MAXDISTANCEFACTOR ||
1521 listen->flDistanceFactor < DS3D_MINDISTANCEFACTOR)
1523 WARN("Invalid distance factor (%f)\n", listen->flDistanceFactor);
1524 return DSERR_INVALIDPARAM;
1527 if(listen->flDopplerFactor > DS3D_MAXDOPPLERFACTOR ||
1528 listen->flDopplerFactor < DS3D_MINDOPPLERFACTOR)
1530 WARN("Invalid doppler factor (%f)\n", listen->flDopplerFactor);
1531 return DSERR_INVALIDPARAM;
1534 if(listen->flRolloffFactor < DS3D_MINROLLOFFFACTOR ||
1535 listen->flRolloffFactor > DS3D_MAXROLLOFFFACTOR)
1537 WARN("Invalid rolloff factor (%f)\n", listen->flRolloffFactor);
1538 return DSERR_INVALIDPARAM;
1541 if(apply == DS3D_DEFERRED)
1543 EnterCriticalSection(&This->share->crst);
1544 This->deferred.ds3d = *listen;
1545 This->deferred.ds3d.dwSize = sizeof(This->deferred.ds3d);
1546 This->dirty.bit.pos = 1;
1547 This->dirty.bit.vel = 1;
1548 This->dirty.bit.orientation = 1;
1549 This->dirty.bit.distancefactor = 1;
1550 This->dirty.bit.rollofffactor = 1;
1551 This->dirty.bit.dopplerfactor = 1;
1552 LeaveCriticalSection(&This->share->crst);
1554 else
1556 union PrimaryParamFlags dirty = { 0l };
1557 dirty.bit.pos = 1;
1558 dirty.bit.vel = 1;
1559 dirty.bit.orientation = 1;
1560 dirty.bit.distancefactor = 1;
1561 dirty.bit.rollofffactor = 1;
1562 dirty.bit.dopplerfactor = 1;
1564 EnterCriticalSection(&This->share->crst);
1565 setALContext(This->ctx);
1566 DSPrimary_SetParams(This, listen, dirty.flags);
1567 checkALError();
1568 popALContext();
1569 LeaveCriticalSection(&This->share->crst);
1572 return S_OK;
1575 HRESULT WINAPI DSPrimary3D_CommitDeferredSettings(IDirectSound3DListener *iface)
1577 DSPrimary *This = impl_from_IDirectSound3DListener(iface);
1578 struct DSBufferGroup *bufgroup;
1579 LONG flags;
1580 DWORD i;
1582 EnterCriticalSection(&This->share->crst);
1583 setALContext(This->ctx);
1584 alDeferUpdatesSOFT();
1586 if((flags=InterlockedExchange(&This->dirty.flags, 0)) != 0)
1588 DSPrimary_SetParams(This, &This->deferred.ds3d, flags);
1589 /* checkALError is here for debugging */
1590 checkALError();
1592 TRACE("Dirty flags was: 0x%02lx\n", flags);
1594 bufgroup = This->BufferGroups;
1595 for(i = 0;i < This->NumBufferGroups;++i)
1597 DWORD64 usemask = ~bufgroup[i].FreeBuffers;
1598 while(usemask)
1600 int idx = CTZ64(usemask);
1601 DSBuffer *buf = bufgroup[i].Buffers + idx;
1602 usemask &= ~(U64(1) << idx);
1604 if((flags=InterlockedExchange(&buf->dirty.flags, 0)) != 0)
1605 DSBuffer_SetParams(buf, &buf->deferred.ds3d, &buf->deferred.eax, flags);
1608 alProcessUpdatesSOFT();
1609 checkALError();
1611 popALContext();
1612 LeaveCriticalSection(&This->share->crst);
1614 return DS_OK;
1617 static const IDirectSound3DListenerVtbl DSPrimary3D_Vtbl =
1619 DSPrimary3D_QueryInterface,
1620 DSPrimary3D_AddRef,
1621 DSPrimary3D_Release,
1622 DSPrimary3D_GetAllParameters,
1623 DSPrimary3D_GetDistanceFactor,
1624 DSPrimary3D_GetDopplerFactor,
1625 DSPrimary3D_GetOrientation,
1626 DSPrimary3D_GetPosition,
1627 DSPrimary3D_GetRolloffFactor,
1628 DSPrimary3D_GetVelocity,
1629 DSPrimary3D_SetAllParameters,
1630 DSPrimary3D_SetDistanceFactor,
1631 DSPrimary3D_SetDopplerFactor,
1632 DSPrimary3D_SetOrientation,
1633 DSPrimary3D_SetPosition,
1634 DSPrimary3D_SetRolloffFactor,
1635 DSPrimary3D_SetVelocity,
1636 DSPrimary3D_CommitDeferredSettings
1640 static HRESULT WINAPI DSPrimaryProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
1642 DSPrimary *This = impl_from_IKsPropertySet(iface);
1643 return DSPrimary_QueryInterface(&This->IDirectSoundBuffer_iface, riid, ppv);
1646 static ULONG WINAPI DSPrimaryProp_AddRef(IKsPropertySet *iface)
1648 DSPrimary *This = impl_from_IKsPropertySet(iface);
1649 LONG ret;
1651 ret = InterlockedIncrement(&This->prop_ref);
1652 TRACE("(%p) ref %lu\n", iface, ret);
1654 return ret;
1657 static ULONG WINAPI DSPrimaryProp_Release(IKsPropertySet *iface)
1659 DSPrimary *This = impl_from_IKsPropertySet(iface);
1660 LONG ret;
1662 ret = InterlockedDecrement(&This->prop_ref);
1663 TRACE("(%p) ref %lu\n", iface, ret);
1665 return ret;
1668 static HRESULT WINAPI DSPrimaryProp_Get(IKsPropertySet *iface,
1669 REFGUID guidPropSet, ULONG dwPropID,
1670 LPVOID pInstanceData, ULONG cbInstanceData,
1671 LPVOID pPropData, ULONG cbPropData,
1672 ULONG *pcbReturned)
1674 (void)iface;
1675 (void)dwPropID;
1676 (void)pInstanceData;
1677 (void)cbInstanceData;
1678 (void)pPropData;
1679 (void)cbPropData;
1680 (void)pcbReturned;
1682 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
1684 return E_PROP_ID_UNSUPPORTED;
1687 static HRESULT WINAPI DSPrimaryProp_Set(IKsPropertySet *iface,
1688 REFGUID guidPropSet, ULONG dwPropID,
1689 LPVOID pInstanceData, ULONG cbInstanceData,
1690 LPVOID pPropData, ULONG cbPropData)
1692 (void)iface;
1693 (void)dwPropID;
1694 (void)pInstanceData;
1695 (void)cbInstanceData;
1696 (void)pPropData;
1697 (void)cbPropData;
1699 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
1701 return E_PROP_ID_UNSUPPORTED;
1704 static HRESULT WINAPI DSPrimaryProp_QuerySupport(IKsPropertySet *iface,
1705 REFGUID guidPropSet, ULONG dwPropID,
1706 ULONG *pTypeSupport)
1708 (void)iface;
1709 (void)pTypeSupport;
1711 FIXME("Unhandled propset: %s (propid: %lu)\n", debugstr_guid(guidPropSet), dwPropID);
1713 return E_PROP_ID_UNSUPPORTED;
1716 static const IKsPropertySetVtbl DSPrimaryProp_Vtbl =
1718 DSPrimaryProp_QueryInterface,
1719 DSPrimaryProp_AddRef,
1720 DSPrimaryProp_Release,
1721 DSPrimaryProp_Get,
1722 DSPrimaryProp_Set,
1723 DSPrimaryProp_QuerySupport