Report the "NONE" EAX properties as gettable
[dsound-openal.git] / primary.c
blob3c7a37abd2676e8595ecdc5c9ab6d1741a9e04ca
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"
34 #ifndef E_PROP_ID_UNSUPPORTED
35 #define E_PROP_ID_UNSUPPORTED ((HRESULT)0x80070490)
36 #endif
39 static const IDirectSoundBufferVtbl DS8Primary_Vtbl;
40 static const IDirectSound3DListenerVtbl DS8Primary3D_Vtbl;
41 static const IKsPropertySetVtbl DS8PrimaryProp_Vtbl;
43 static void DS8Primary_SetParams(DS8Primary *This, const DS3DLISTENER *params, LONG flags);
46 static inline DS8Primary *impl_from_IDirectSoundBuffer(IDirectSoundBuffer *iface)
48 return CONTAINING_RECORD(iface, DS8Primary, IDirectSoundBuffer_iface);
51 static inline DS8Primary *impl_from_IDirectSound3DListener(IDirectSound3DListener *iface)
53 return CONTAINING_RECORD(iface, DS8Primary, IDirectSound3DListener_iface);
56 static inline DS8Primary *impl_from_IKsPropertySet(IKsPropertySet *iface)
58 return CONTAINING_RECORD(iface, DS8Primary, IKsPropertySet_iface);
62 static void trigger_elapsed_notifies(DS8Buffer *buf, DWORD lastpos, DWORD curpos)
64 DSBPOSITIONNOTIFY *not = buf->notify;
65 DSBPOSITIONNOTIFY *not_end = not + buf->nnotify;
66 for(;not != not_end;++not)
68 HANDLE event = not->hEventNotify;
69 DWORD ofs = not->dwOffset;
71 if(ofs == (DWORD)DSBPN_OFFSETSTOP)
72 continue;
74 if(curpos < lastpos) /* Wraparound case */
76 if(ofs < curpos || ofs >= lastpos)
78 TRACE("Triggering notification %d from buffer %p\n", not - buf->notify, buf);
79 SetEvent(event);
82 else if(ofs >= lastpos && ofs < curpos) /* Normal case */
84 TRACE("Triggering notification %d from buffer %p\n", not - buf->notify, buf);
85 SetEvent(event);
90 static void trigger_stop_notifies(DS8Buffer *buf)
92 DSBPOSITIONNOTIFY *not = buf->notify;
93 DSBPOSITIONNOTIFY *not_end = not + buf->nnotify;
94 for(;not != not_end;++not)
96 if(not->dwOffset != (DWORD)DSBPN_OFFSETSTOP)
97 continue;
98 TRACE("Triggering notification %d from buffer %p\n", not - buf->notify, buf);
99 SetEvent(not->hEventNotify);
103 void DS8Primary_triggernots(DS8Primary *prim)
105 DS8Buffer **curnot, **endnot;
107 curnot = prim->notifies;
108 endnot = curnot + prim->nnotifies;
109 while(curnot != endnot)
111 DS8Buffer *buf = *curnot;
112 DS8Data *data = buf->buffer;
113 DWORD curpos = buf->lastpos;
114 ALint state = 0;
115 ALint ofs;
117 alGetSourcei(buf->source, AL_BYTE_OFFSET, &ofs);
118 alGetSourcei(buf->source, AL_SOURCE_STATE, &state);
119 if(buf->segsize == 0)
120 curpos = (state == AL_STOPPED) ? data->buf_size : ofs;
121 else
123 if(state != AL_STOPPED)
124 curpos = ofs + buf->queue_base;
125 else
127 ALint queued;
128 alGetSourcei(buf->source, AL_BUFFERS_QUEUED, &queued);
129 curpos = buf->segsize*queued + buf->queue_base;
132 if(curpos >= (DWORD)data->buf_size)
134 if(buf->islooping)
135 curpos %= (DWORD)data->buf_size;
136 else if(buf->isplaying)
138 curpos = data->buf_size;
139 alSourceStop(buf->source);
140 alSourcei(buf->source, AL_BUFFER, 0);
141 buf->curidx = 0;
142 buf->isplaying = FALSE;
146 if(state != AL_PLAYING)
147 state = buf->isplaying ? AL_PLAYING : AL_PAUSED;
149 checkALError();
151 if(buf->lastpos != curpos)
153 trigger_elapsed_notifies(buf, buf->lastpos, curpos);
154 buf->lastpos = curpos;
156 if(state != AL_PLAYING)
158 /* Remove this buffer from list and put another at the current
159 * position; don't increment i
161 trigger_stop_notifies(buf);
162 *curnot = *(--endnot);
163 prim->nnotifies--;
164 continue;
166 curnot++;
168 checkALError();
171 static void do_buffer_stream(DS8Buffer *buf, BYTE *scratch_mem)
173 DS8Data *data = buf->buffer;
174 ALint ofs, done = 0, queued = QBUFFERS, state = AL_PLAYING;
175 ALuint which;
177 alGetSourcei(buf->source, AL_BUFFERS_QUEUED, &queued);
178 alGetSourcei(buf->source, AL_SOURCE_STATE, &state);
179 alGetSourcei(buf->source, AL_BUFFERS_PROCESSED, &done);
181 if(done > 0)
183 ALuint bids[QBUFFERS];
184 queued -= done;
186 alSourceUnqueueBuffers(buf->source, done, bids);
187 buf->queue_base = (buf->queue_base + buf->segsize*done) % data->buf_size;
189 while(queued < QBUFFERS)
191 which = buf->stream_bids[buf->curidx];
192 ofs = buf->data_offset;
194 if(buf->segsize < data->buf_size - ofs)
196 alBufferData(which, data->buf_format, data->data + ofs, buf->segsize,
197 data->format.Format.nSamplesPerSec);
198 buf->data_offset = ofs + buf->segsize;
200 else if(buf->islooping)
202 ALsizei rem = data->buf_size - ofs;
203 if(rem > 2048) rem = 2048;
205 memcpy(scratch_mem, data->data + ofs, rem);
206 while(rem < buf->segsize)
208 ALsizei todo = buf->segsize - rem;
209 if(todo > data->buf_size)
210 todo = data->buf_size;
211 memcpy(scratch_mem + rem, data->data, todo);
212 rem += todo;
214 alBufferData(which, data->buf_format, scratch_mem, buf->segsize,
215 data->format.Format.nSamplesPerSec);
216 buf->data_offset = (ofs+buf->segsize) % data->buf_size;
218 else
220 ALsizei rem = data->buf_size - ofs;
221 if(rem > 2048) rem = 2048;
222 if(rem == 0) break;
224 memcpy(scratch_mem, data->data + ofs, rem);
225 memset(scratch_mem+rem, (data->format.Format.wBitsPerSample==8) ? 128 : 0,
226 buf->segsize - rem);
227 alBufferData(which, data->buf_format, scratch_mem, buf->segsize,
228 data->format.Format.nSamplesPerSec);
229 buf->data_offset = data->buf_size;
232 alSourceQueueBuffers(buf->source, 1, &which);
233 buf->curidx = (buf->curidx+1)%QBUFFERS;
234 queued++;
237 if(!queued)
239 buf->data_offset = 0;
240 buf->queue_base = data->buf_size;
241 buf->curidx = 0;
242 buf->isplaying = FALSE;
244 else if(state != AL_PLAYING)
245 alSourcePlay(buf->source);
248 void DS8Primary_streamfeeder(DS8Primary *prim, BYTE *scratch_mem)
250 /* OpenAL doesn't support our lovely buffer extensions so just make sure
251 * enough buffers are queued for streaming
253 if(prim->write_emu)
255 DS8Buffer *buf = &prim->writable_buf;
256 if(buf->segsize != 0 && buf->isplaying)
257 do_buffer_stream(buf, scratch_mem);
259 else
261 struct DSBufferGroup *bufgroup = prim->BufferGroups;
262 struct DSBufferGroup *endgroup = bufgroup + prim->NumBufferGroups;
263 for(;bufgroup != endgroup;++bufgroup)
265 DWORD64 usemask = ~bufgroup->FreeBuffers;
266 while(usemask)
268 int idx = CTZ64(usemask);
269 DS8Buffer *buf = bufgroup->Buffers + idx;
270 usemask &= ~(U64(1) << idx);
272 if(buf->segsize != 0 && buf->isplaying)
273 do_buffer_stream(buf, scratch_mem);
277 checkALError();
281 HRESULT DS8Primary_PreInit(DS8Primary *This, DS8Impl *parent)
283 WAVEFORMATEX *wfx;
284 DWORD num_srcs;
285 DWORD count;
286 HRESULT hr;
287 DWORD i;
289 This->IDirectSoundBuffer_iface.lpVtbl = &DS8Primary_Vtbl;
290 This->IDirectSound3DListener_iface.lpVtbl = &DS8Primary3D_Vtbl;
291 This->IKsPropertySet_iface.lpVtbl = &DS8PrimaryProp_Vtbl;
293 This->parent = parent;
294 This->share = parent->share;
295 This->ctx = parent->share->ctx;
296 This->refresh = parent->share->refresh;
297 This->auxslot = parent->share->auxslot;
299 wfx = &This->format.Format;
300 wfx->wFormatTag = WAVE_FORMAT_PCM;
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 setALContext(This->ctx);
317 This->deferred.eax = EnvironmentDefaults[EAX_ENVIRONMENT_GENERIC];
318 This->deferred.eax1_dampening = 0.5f;
319 if(This->auxslot != 0)
321 ALint revid = alGetEnumValue("AL_EFFECT_REVERB");
322 if(revid != 0 && revid != -1)
324 alGenEffects(1, &This->effect);
325 alEffecti(This->effect, AL_EFFECT_TYPE, AL_EFFECT_REVERB);
326 checkALError();
329 popALContext();
331 num_srcs = This->share->sources.max_alloc;
333 hr = DSERR_OUTOFMEMORY;
334 This->notifies = HeapAlloc(GetProcessHeap(), 0, num_srcs*sizeof(*This->notifies));
335 if(!This->notifies) goto fail;
336 This->sizenotifies = num_srcs;
338 count = (num_srcs+63) / 64;
339 This->BufferGroups = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
340 count*sizeof(*This->BufferGroups));
341 if(!This->BufferGroups) goto fail;
343 for(i = 0;i < count;++i)
345 This->BufferGroups[i].Buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
346 64*sizeof(This->BufferGroups[0].Buffers[0]));
347 if(!This->BufferGroups[i].Buffers)
349 while(i > 0)
350 HeapFree(GetProcessHeap(), 0, This->BufferGroups[--i].Buffers);
351 HeapFree(GetProcessHeap(), 0, This->BufferGroups);
352 This->BufferGroups = NULL;
353 goto fail;
355 This->BufferGroups[i].FreeBuffers = ~(DWORD64)0;
357 This->NumBufferGroups = count;
359 return S_OK;
361 fail:
362 DS8Primary_Clear(This);
363 return hr;
366 void DS8Primary_Clear(DS8Primary *This)
368 struct DSBufferGroup *bufgroup;
369 DWORD i;
371 TRACE("Clearing primary %p\n", This);
373 if(!This->parent)
374 return;
376 setALContext(This->ctx);
377 if(This->effect)
378 alDeleteEffects(1, &This->effect);
379 popALContext();
381 bufgroup = This->BufferGroups;
382 for(i = 0;i < This->NumBufferGroups;++i)
384 DWORD64 usemask = ~bufgroup[i].FreeBuffers;
385 while(usemask)
387 int idx = CTZ64(usemask);
388 DS8Buffer *buf = bufgroup[i].Buffers + idx;
389 usemask &= ~(U64(1) << idx);
391 DS8Buffer_Destroy(buf);
393 HeapFree(GetProcessHeap(), 0, This->BufferGroups[i].Buffers);
396 HeapFree(GetProcessHeap(), 0, This->BufferGroups);
397 HeapFree(GetProcessHeap(), 0, This->notifies);
398 memset(This, 0, sizeof(*This));
401 static HRESULT WINAPI DS8Primary_QueryInterface(IDirectSoundBuffer *iface, REFIID riid, LPVOID *ppv)
403 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
405 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
407 *ppv = NULL;
408 if(IsEqualIID(riid, &IID_IUnknown) ||
409 IsEqualIID(riid, &IID_IDirectSoundBuffer))
410 *ppv = &This->IDirectSoundBuffer_iface;
411 else if(IsEqualIID(riid, &IID_IDirectSound3DListener))
413 if((This->flags&DSBCAPS_CTRL3D))
414 *ppv = &This->IDirectSound3DListener_iface;
416 else if(IsEqualIID(riid, &IID_IKsPropertySet))
417 *ppv = &This->IKsPropertySet_iface;
418 else
419 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
421 if(*ppv)
423 IUnknown_AddRef((IUnknown*)*ppv);
424 return S_OK;
427 return E_NOINTERFACE;
430 static ULONG WINAPI DS8Primary_AddRef(IDirectSoundBuffer *iface)
432 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
433 LONG ret;
435 ret = InterlockedIncrement(&This->ref);
436 if(ret == 1) This->flags = 0;
438 return ret;
441 static ULONG WINAPI DS8Primary_Release(IDirectSoundBuffer *iface)
443 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
444 LONG ref, oldval;
446 oldval = *(volatile LONG*)&This->ref;
447 do {
448 ref = oldval;
449 if(!ref) return 0;
450 oldval = InterlockedCompareExchange(&This->ref, ref-1, ref);
451 } while(oldval != ref);
453 return ref-1;
456 static HRESULT WINAPI DS8Primary_GetCaps(IDirectSoundBuffer *iface, DSBCAPS *caps)
458 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
460 TRACE("(%p)->(%p)\n", iface, caps);
462 if(!caps || caps->dwSize < sizeof(*caps))
464 WARN("Invalid DSBCAPS (%p, %lu)\n", caps, caps ? caps->dwSize : 0);
465 return DSERR_INVALIDPARAM;
468 caps->dwFlags = This->flags;
469 caps->dwBufferBytes = This->buf_size;
470 caps->dwUnlockTransferRate = 0;
471 caps->dwPlayCpuOverhead = 0;
473 return DS_OK;
476 static HRESULT WINAPI DS8Primary_GetCurrentPosition(IDirectSoundBuffer *iface, DWORD *playpos, DWORD *curpos)
478 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
479 HRESULT hr = DSERR_PRIOLEVELNEEDED;
481 EnterCriticalSection(&This->share->crst);
482 if(This->write_emu)
483 hr = IDirectSoundBuffer8_GetCurrentPosition(This->write_emu, playpos, curpos);
484 LeaveCriticalSection(&This->share->crst);
486 return hr;
489 static HRESULT WINAPI DS8Primary_GetFormat(IDirectSoundBuffer *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
491 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
492 HRESULT hr = S_OK;
493 UINT size;
495 if(!wfx && !written)
497 WARN("Cannot report format or format size\n");
498 return DSERR_INVALIDPARAM;
501 EnterCriticalSection(&This->share->crst);
502 size = sizeof(This->format.Format) + This->format.Format.cbSize;
503 if(written)
504 *written = size;
505 if(wfx)
507 if(allocated < size)
508 hr = DSERR_INVALIDPARAM;
509 else
510 memcpy(wfx, &This->format.Format, size);
512 LeaveCriticalSection(&This->share->crst);
514 return hr;
517 static HRESULT WINAPI DS8Primary_GetVolume(IDirectSoundBuffer *iface, LONG *volume)
519 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
520 ALfloat gain;
522 TRACE("(%p)->(%p)\n", iface, volume);
524 if(!volume)
525 return DSERR_INVALIDPARAM;
526 *volume = 0;
528 if(!(This->flags&DSBCAPS_CTRLVOLUME))
529 return DSERR_CONTROLUNAVAIL;
531 setALContext(This->ctx);
532 alGetListenerf(AL_GAIN, &gain);
533 checkALError();
534 popALContext();
536 *volume = clampI(gain_to_mB(gain), DSBVOLUME_MIN, DSBVOLUME_MAX);
537 return DS_OK;
540 static HRESULT WINAPI DS8Primary_GetPan(IDirectSoundBuffer *iface, LONG *pan)
542 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
543 HRESULT hr = DS_OK;
545 WARN("(%p)->(%p): semi-stub\n", iface, pan);
547 if(!pan)
548 return DSERR_INVALIDPARAM;
550 EnterCriticalSection(&This->share->crst);
551 if(This->write_emu)
552 hr = IDirectSoundBuffer8_GetPan(This->write_emu, pan);
553 else if(!(This->flags & DSBCAPS_CTRLPAN))
554 hr = DSERR_CONTROLUNAVAIL;
555 else
556 *pan = 0;
557 LeaveCriticalSection(&This->share->crst);
559 return hr;
562 static HRESULT WINAPI DS8Primary_GetFrequency(IDirectSoundBuffer *iface, DWORD *freq)
564 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
565 HRESULT hr = DS_OK;
567 WARN("(%p)->(%p): semi-stub\n", iface, freq);
569 if(!freq)
570 return DSERR_INVALIDPARAM;
572 if(!(This->flags&DSBCAPS_CTRLFREQUENCY))
573 return DSERR_CONTROLUNAVAIL;
575 EnterCriticalSection(&This->share->crst);
576 *freq = This->format.Format.nSamplesPerSec;
577 LeaveCriticalSection(&This->share->crst);
579 return hr;
582 static HRESULT WINAPI DS8Primary_GetStatus(IDirectSoundBuffer *iface, DWORD *status)
584 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
586 TRACE("(%p)->(%p)\n", iface, status);
588 if(!status)
589 return DSERR_INVALIDPARAM;
591 EnterCriticalSection(&This->share->crst);
592 *status = DSBSTATUS_PLAYING|DSBSTATUS_LOOPING;
593 if((This->flags&DSBCAPS_LOCDEFER))
594 *status |= DSBSTATUS_LOCHARDWARE;
596 if(This->stopped)
598 struct DSBufferGroup *bufgroup = This->BufferGroups;
599 DWORD i, state = 0;
600 HRESULT hr;
602 for(i = 0;i < This->NumBufferGroups;++i)
604 DWORD64 usemask = ~bufgroup[i].FreeBuffers;
605 while(usemask)
607 int idx = CTZ64(usemask);
608 DS8Buffer *buf = bufgroup[i].Buffers + idx;
609 usemask &= ~(U64(1) << idx);
611 hr = DS8Buffer_GetStatus(&buf->IDirectSoundBuffer8_iface, &state);
612 if(SUCCEEDED(hr) && (state&DSBSTATUS_PLAYING)) break;
615 if(!(state&DSBSTATUS_PLAYING))
617 /* Primary stopped and no buffers playing.. */
618 *status = 0;
621 LeaveCriticalSection(&This->share->crst);
623 return DS_OK;
626 HRESULT WINAPI DS8Primary_Initialize(IDirectSoundBuffer *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
628 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
629 HRESULT hr;
631 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
633 if(!desc || desc->lpwfxFormat || desc->dwBufferBytes)
635 WARN("Bad DSBDESC for primary buffer\n");
636 return DSERR_INVALIDPARAM;
638 if((desc->dwFlags&DSBCAPS_CTRLFX) ||
639 (desc->dwFlags&DSBCAPS_CTRLPOSITIONNOTIFY) ||
640 (desc->dwFlags&DSBCAPS_LOCSOFTWARE))
642 WARN("Bad dwFlags %08lx\n", desc->dwFlags);
643 return DSERR_INVALIDPARAM;
646 /* Should be 0 if not initialized */
647 if(This->flags)
648 return DSERR_ALREADYINITIALIZED;
650 hr = DS_OK;
651 if(This->parent->prio_level == DSSCL_WRITEPRIMARY)
653 DSBUFFERDESC emudesc;
654 DS8Buffer *emu;
656 if(This->write_emu)
658 ERR("There shouldn't be a write_emu!\n");
659 IDirectSoundBuffer8_Release(This->write_emu);
660 This->write_emu = NULL;
663 memset(&emudesc, 0, sizeof(emudesc));
664 emudesc.dwSize = sizeof(emudesc);
665 emudesc.dwFlags = DSBCAPS_LOCHARDWARE | (desc->dwFlags&DSBCAPS_CTRLPAN);
666 /* Dont play last incomplete sample */
667 emudesc.dwBufferBytes = This->buf_size - (This->buf_size%This->format.Format.nBlockAlign);
668 emudesc.lpwfxFormat = &This->format.Format;
670 hr = DS8Buffer_Create(&emu, This, NULL, TRUE);
671 if(SUCCEEDED(hr))
673 This->write_emu = &emu->IDirectSoundBuffer8_iface;
674 hr = DS8Buffer_Initialize(This->write_emu, ds, &emudesc);
675 if(FAILED(hr))
677 IDirectSoundBuffer8_Release(This->write_emu);
678 This->write_emu = NULL;
683 if(SUCCEEDED(hr))
685 DS3DLISTENER *listener = &This->deferred.ds3d;
686 listener->dwSize = sizeof(This->deferred.ds3d);
687 listener->vPosition.x = 0.0f;
688 listener->vPosition.y = 0.0f;
689 listener->vPosition.z = 0.0f;
690 listener->vVelocity.x = 0.0f;
691 listener->vVelocity.y = 0.0f;
692 listener->vVelocity.z = 0.0f;
693 listener->vOrientFront.x = 0.0f;
694 listener->vOrientFront.y = 0.0f;
695 listener->vOrientFront.z = 1.0f;
696 listener->vOrientTop.x = 0.0f;
697 listener->vOrientTop.y = 1.0f;
698 listener->vOrientTop.z = 0.0f;
699 listener->flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
700 listener->flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
701 listener->flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
703 This->flags = desc->dwFlags | DSBCAPS_LOCHARDWARE;
705 if((This->flags&DSBCAPS_CTRL3D))
707 union PrimaryParamFlags dirty = { 0l };
709 dirty.bit.pos = 1;
710 dirty.bit.vel = 1;
711 dirty.bit.orientation = 1;
712 dirty.bit.distancefactor = 1;
713 dirty.bit.rollofffactor = 1;
714 dirty.bit.dopplerfactor = 1;
715 DS8Primary_SetParams(This, listener, dirty.flags);
718 return hr;
721 static HRESULT WINAPI DS8Primary_Lock(IDirectSoundBuffer *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
723 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
724 HRESULT hr = DSERR_PRIOLEVELNEEDED;
726 TRACE("(%p)->(%lu, %lu, %p, %p, %p, %p, %lu)\n", iface, ofs, bytes, ptr1, len1, ptr2, len2, flags);
728 EnterCriticalSection(&This->share->crst);
729 if(This->write_emu)
730 hr = IDirectSoundBuffer8_Lock(This->write_emu, ofs, bytes, ptr1, len1, ptr2, len2, flags);
731 LeaveCriticalSection(&This->share->crst);
733 return hr;
736 static HRESULT WINAPI DS8Primary_Play(IDirectSoundBuffer *iface, DWORD res1, DWORD res2, DWORD flags)
738 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
739 HRESULT hr;
741 TRACE("(%p)->(%lu, %lu, %lu)\n", iface, res1, res2, flags);
743 if(!(flags & DSBPLAY_LOOPING))
745 WARN("Flags (%08lx) not set to DSBPLAY_LOOPING\n", flags);
746 return DSERR_INVALIDPARAM;
749 EnterCriticalSection(&This->share->crst);
750 hr = S_OK;
751 if(This->write_emu)
752 hr = IDirectSoundBuffer8_Play(This->write_emu, res1, res2, flags);
753 if(SUCCEEDED(hr))
754 This->stopped = FALSE;
755 LeaveCriticalSection(&This->share->crst);
757 return hr;
760 static HRESULT WINAPI DS8Primary_SetCurrentPosition(IDirectSoundBuffer *iface, DWORD pos)
762 WARN("(%p)->(%lu)\n", iface, pos);
763 return DSERR_INVALIDCALL;
766 /* Just assume the format is crap, and clean up the damage */
767 static HRESULT copy_waveformat(WAVEFORMATEX *wfx, const WAVEFORMATEX *from)
769 if(from->nChannels <= 0)
771 WARN("Invalid Channels %d\n", from->nChannels);
772 return DSERR_INVALIDPARAM;
774 if(from->nSamplesPerSec < DSBFREQUENCY_MIN || from->nSamplesPerSec > DSBFREQUENCY_MAX)
776 WARN("Invalid SamplesPerSec %lu\n", from->nSamplesPerSec);
777 return DSERR_INVALIDPARAM;
779 if(from->nBlockAlign <= 0)
781 WARN("Invalid BlockAlign %d\n", from->nBlockAlign);
782 return DSERR_INVALIDPARAM;
784 if(from->wBitsPerSample == 0 || (from->wBitsPerSample%8) != 0)
786 WARN("Invalid BitsPerSample %d\n", from->wBitsPerSample);
787 return DSERR_INVALIDPARAM;
789 if(from->nBlockAlign != from->nChannels*from->wBitsPerSample/8)
791 WARN("Invalid BlockAlign %d (expected %u = %u*%u/8)\n",
792 from->nBlockAlign, from->nChannels*from->wBitsPerSample/8,
793 from->nChannels, from->wBitsPerSample);
794 return DSERR_INVALIDPARAM;
796 if(from->nAvgBytesPerSec != from->nBlockAlign*from->nSamplesPerSec)
798 WARN("Invalid AvgBytesPerSec %lu (expected %lu = %lu*%u)\n",
799 from->nAvgBytesPerSec, from->nSamplesPerSec*from->nBlockAlign,
800 from->nSamplesPerSec, from->nBlockAlign);
801 return DSERR_INVALIDPARAM;
804 if(from->wFormatTag == WAVE_FORMAT_PCM)
806 if(from->wBitsPerSample > 32)
807 return DSERR_INVALIDPARAM;
808 wfx->cbSize = 0;
810 else if(from->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
812 if(from->wBitsPerSample != 32)
813 return DSERR_INVALIDPARAM;
814 wfx->cbSize = 0;
816 else if(from->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
818 WAVEFORMATEXTENSIBLE *wfe = (WAVEFORMATEXTENSIBLE*)wfx;
819 const WAVEFORMATEXTENSIBLE *fromx = (const WAVEFORMATEXTENSIBLE*)from;
820 const WORD size = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
822 /* Fail silently.. */
823 if(from->cbSize < size) return DS_OK;
824 if(fromx->Samples.wValidBitsPerSample > fromx->Format.wBitsPerSample)
825 return DSERR_INVALIDPARAM;
827 if(IsEqualGUID(&fromx->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
829 if(from->wBitsPerSample > 32)
830 return DSERR_INVALIDPARAM;
832 else if(IsEqualGUID(&fromx->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
834 if(from->wBitsPerSample != 32)
835 return DSERR_INVALIDPARAM;
837 else
839 ERR("Unhandled extensible format: %s\n", debugstr_guid(&fromx->SubFormat));
840 return DSERR_INVALIDPARAM;
843 wfe->Format.cbSize = size;
844 wfe->Samples.wValidBitsPerSample = fromx->Samples.wValidBitsPerSample;
845 if(!wfe->Samples.wValidBitsPerSample)
846 wfe->Samples.wValidBitsPerSample = fromx->Format.wBitsPerSample;
847 wfe->dwChannelMask = fromx->dwChannelMask;
848 wfe->SubFormat = fromx->SubFormat;
850 else
852 ERR("Unhandled format tag %04x\n", from->wFormatTag);
853 return DSERR_INVALIDPARAM;
856 wfx->wFormatTag = from->wFormatTag;
857 wfx->nChannels = from->nChannels;
858 wfx->nSamplesPerSec = from->nSamplesPerSec;
859 wfx->nAvgBytesPerSec = from->nSamplesPerSec * from->nBlockAlign;
860 wfx->nBlockAlign = from->wBitsPerSample * from->nChannels / 8;
861 wfx->wBitsPerSample = from->wBitsPerSample;
862 return DS_OK;
865 static HRESULT WINAPI DS8Primary_SetFormat(IDirectSoundBuffer *iface, const WAVEFORMATEX *wfx)
867 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
868 HRESULT hr = S_OK;
870 TRACE("(%p)->(%p)\n", iface, wfx);
872 if(!wfx)
874 WARN("Missing format\n");
875 return DSERR_INVALIDPARAM;
878 EnterCriticalSection(&This->share->crst);
880 if(This->parent->prio_level < DSSCL_PRIORITY)
882 hr = DSERR_PRIOLEVELNEEDED;
883 goto out;
886 TRACE("Requested primary format:\n"
887 " FormatTag = %04x\n"
888 " Channels = %u\n"
889 " SamplesPerSec = %lu\n"
890 " AvgBytesPerSec = %lu\n"
891 " BlockAlign = %u\n"
892 " BitsPerSample = %u\n",
893 wfx->wFormatTag, wfx->nChannels,
894 wfx->nSamplesPerSec, wfx->nAvgBytesPerSec,
895 wfx->nBlockAlign, wfx->wBitsPerSample);
897 hr = copy_waveformat(&This->format.Format, wfx);
898 if(SUCCEEDED(hr) && This->write_emu)
900 DS8Buffer *buf;
901 DSBUFFERDESC desc;
903 IDirectSoundBuffer8_Release(This->write_emu);
904 This->write_emu = NULL;
906 memset(&desc, 0, sizeof(desc));
907 desc.dwSize = sizeof(desc);
908 desc.dwFlags = DSBCAPS_LOCHARDWARE|DSBCAPS_CTRLPAN;
909 desc.dwBufferBytes = This->buf_size - (This->buf_size % This->format.Format.nBlockAlign);
910 desc.lpwfxFormat = &This->format.Format;
912 hr = DS8Buffer_Create(&buf, This, NULL, TRUE);
913 if(FAILED(hr)) goto out;
915 This->write_emu = &buf->IDirectSoundBuffer8_iface;
916 hr = DS8Buffer_Initialize(This->write_emu, &This->parent->IDirectSound_iface, &desc);
917 if(FAILED(hr))
919 IDirectSoundBuffer8_Release(This->write_emu);
920 This->write_emu = NULL;
924 out:
925 LeaveCriticalSection(&This->share->crst);
926 return hr;
929 static HRESULT WINAPI DS8Primary_SetVolume(IDirectSoundBuffer *iface, LONG vol)
931 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
933 TRACE("(%p)->(%ld)\n", iface, vol);
935 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
937 WARN("Invalid volume (%ld)\n", vol);
938 return DSERR_INVALIDPARAM;
941 if(!(This->flags&DSBCAPS_CTRLVOLUME))
942 return DSERR_CONTROLUNAVAIL;
944 setALContext(This->ctx);
945 alListenerf(AL_GAIN, mB_to_gain(vol));
946 popALContext();
948 return DS_OK;
951 static HRESULT WINAPI DS8Primary_SetPan(IDirectSoundBuffer *iface, LONG pan)
953 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
954 HRESULT hr;
956 TRACE("(%p)->(%ld)\n", iface, pan);
958 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
960 WARN("invalid parameter: pan = %ld\n", pan);
961 return DSERR_INVALIDPARAM;
964 EnterCriticalSection(&This->share->crst);
965 if(!(This->flags&DSBCAPS_CTRLPAN))
967 WARN("control unavailable\n");
968 hr = DSERR_CONTROLUNAVAIL;
970 else if(This->write_emu)
971 hr = IDirectSoundBuffer8_SetPan(This->write_emu, pan);
972 else
974 FIXME("Not supported\n");
975 hr = E_NOTIMPL;
977 LeaveCriticalSection(&This->share->crst);
979 return hr;
982 static HRESULT WINAPI DS8Primary_SetFrequency(IDirectSoundBuffer *iface, DWORD freq)
984 WARN("(%p)->(%lu)\n", iface, freq);
985 return DSERR_CONTROLUNAVAIL;
988 static HRESULT WINAPI DS8Primary_Stop(IDirectSoundBuffer *iface)
990 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
991 HRESULT hr = S_OK;
993 TRACE("(%p)->()\n", iface);
995 EnterCriticalSection(&This->share->crst);
996 if(This->write_emu)
997 hr = IDirectSoundBuffer8_Stop(This->write_emu);
998 if(SUCCEEDED(hr))
999 This->stopped = TRUE;
1000 LeaveCriticalSection(&This->share->crst);
1002 return hr;
1005 static HRESULT WINAPI DS8Primary_Unlock(IDirectSoundBuffer *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
1007 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
1008 HRESULT hr = DSERR_INVALIDCALL;
1010 TRACE("(%p)->(%p, %lu, %p, %lu)\n", iface, ptr1, len1, ptr2, len2);
1012 EnterCriticalSection(&This->share->crst);
1013 if(This->write_emu)
1014 hr = IDirectSoundBuffer8_Unlock(This->write_emu, ptr1, len1, ptr2, len2);
1015 LeaveCriticalSection(&This->share->crst);
1017 return hr;
1020 static HRESULT WINAPI DS8Primary_Restore(IDirectSoundBuffer *iface)
1022 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
1023 HRESULT hr = S_OK;
1025 TRACE("(%p)->()\n", iface);
1027 EnterCriticalSection(&This->share->crst);
1028 if(This->write_emu)
1029 hr = IDirectSoundBuffer8_Restore(This->write_emu);
1030 LeaveCriticalSection(&This->share->crst);
1032 return hr;
1035 static const IDirectSoundBufferVtbl DS8Primary_Vtbl =
1037 DS8Primary_QueryInterface,
1038 DS8Primary_AddRef,
1039 DS8Primary_Release,
1040 DS8Primary_GetCaps,
1041 DS8Primary_GetCurrentPosition,
1042 DS8Primary_GetFormat,
1043 DS8Primary_GetVolume,
1044 DS8Primary_GetPan,
1045 DS8Primary_GetFrequency,
1046 DS8Primary_GetStatus,
1047 DS8Primary_Initialize,
1048 DS8Primary_Lock,
1049 DS8Primary_Play,
1050 DS8Primary_SetCurrentPosition,
1051 DS8Primary_SetFormat,
1052 DS8Primary_SetVolume,
1053 DS8Primary_SetPan,
1054 DS8Primary_SetFrequency,
1055 DS8Primary_Stop,
1056 DS8Primary_Unlock,
1057 DS8Primary_Restore
1061 static void DS8Primary_SetParams(DS8Primary *This, const DS3DLISTENER *params, LONG flags)
1063 union PrimaryParamFlags dirty = { flags };
1064 DWORD i;
1066 if(dirty.bit.pos)
1067 alListener3f(AL_POSITION, params->vPosition.x, params->vPosition.y,
1068 -params->vPosition.z);
1069 if(dirty.bit.vel)
1070 alListener3f(AL_VELOCITY, params->vVelocity.x, params->vVelocity.y,
1071 -params->vVelocity.z);
1072 if(dirty.bit.orientation)
1074 ALfloat orient[6] = {
1075 params->vOrientFront.x, params->vOrientFront.y, -params->vOrientFront.z,
1076 params->vOrientTop.x, params->vOrientTop.y, -params->vOrientTop.z
1078 alListenerfv(AL_ORIENTATION, orient);
1080 if(dirty.bit.distancefactor)
1082 alSpeedOfSound(343.3f/params->flDistanceFactor);
1083 if(BITFIELD_TEST(This->share->Exts, EXT_EFX))
1084 alListenerf(AL_METERS_PER_UNIT, params->flDistanceFactor);
1086 if(dirty.bit.rollofffactor)
1088 struct DSBufferGroup *bufgroup = This->BufferGroups;
1089 ALfloat rolloff = params->flRolloffFactor;
1090 This->rollofffactor = rolloff;
1092 for(i = 0;i < This->NumBufferGroups;++i)
1094 DWORD64 usemask = ~bufgroup[i].FreeBuffers;
1095 while(usemask)
1097 int idx = CTZ64(usemask);
1098 DS8Buffer *buf = bufgroup[i].Buffers + idx;
1099 usemask &= ~(U64(1) << idx);
1101 if(buf->ds3dmode != DS3DMODE_DISABLE)
1102 alSourcef(buf->source, AL_ROLLOFF_FACTOR, rolloff);
1106 if(dirty.bit.dopplerfactor)
1107 alDopplerFactor(params->flDopplerFactor);
1108 if(dirty.bit.effect)
1109 alAuxiliaryEffectSloti(This->auxslot, AL_EFFECTSLOT_EFFECT, This->effect);
1112 static HRESULT WINAPI DS8Primary3D_QueryInterface(IDirectSound3DListener *iface, REFIID riid, void **ppv)
1114 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1115 return DS8Primary_QueryInterface(&This->IDirectSoundBuffer_iface, riid, ppv);
1118 static ULONG WINAPI DS8Primary3D_AddRef(IDirectSound3DListener *iface)
1120 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1121 LONG ret;
1123 ret = InterlockedIncrement(&This->ds3d_ref);
1124 TRACE("new refcount %ld\n", ret);
1126 return ret;
1129 static ULONG WINAPI DS8Primary3D_Release(IDirectSound3DListener *iface)
1131 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1132 LONG ret;
1134 ret = InterlockedDecrement(&This->ds3d_ref);
1135 TRACE("new refcount %ld\n", ret);
1137 return ret;
1141 static HRESULT WINAPI DS8Primary3D_GetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE *distancefactor)
1143 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1145 TRACE("(%p)->(%p)\n", iface, distancefactor);
1147 if(!distancefactor)
1149 WARN("Invalid parameter %p\n", distancefactor);
1150 return DSERR_INVALIDPARAM;
1153 setALContext(This->ctx);
1154 *distancefactor = 343.3f/alGetFloat(AL_SPEED_OF_SOUND);
1155 checkALError();
1156 popALContext();
1158 return S_OK;
1161 static HRESULT WINAPI DS8Primary3D_GetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE *dopplerfactor)
1163 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1165 TRACE("(%p)->(%p)\n", iface, dopplerfactor);
1167 if(!dopplerfactor)
1169 WARN("Invalid parameter %p\n", dopplerfactor);
1170 return DSERR_INVALIDPARAM;
1173 setALContext(This->ctx);
1174 *dopplerfactor = alGetFloat(AL_DOPPLER_FACTOR);
1175 checkALError();
1176 popALContext();
1178 return S_OK;
1181 static HRESULT WINAPI DS8Primary3D_GetOrientation(IDirectSound3DListener *iface, D3DVECTOR *front, D3DVECTOR *top)
1183 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1184 ALfloat orient[6];
1186 TRACE("(%p)->(%p, %p)\n", iface, front, top);
1188 if(!front || !top)
1190 WARN("Invalid parameter %p %p\n", front, top);
1191 return DSERR_INVALIDPARAM;
1194 setALContext(This->ctx);
1195 alGetListenerfv(AL_ORIENTATION, orient);
1196 checkALError();
1197 popALContext();
1199 front->x = orient[0];
1200 front->y = orient[1];
1201 front->z = -orient[2];
1202 top->x = orient[3];
1203 top->y = orient[4];
1204 top->z = -orient[5];
1205 return S_OK;
1208 static HRESULT WINAPI DS8Primary3D_GetPosition(IDirectSound3DListener *iface, D3DVECTOR *pos)
1210 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1211 ALfloat alpos[3];
1213 TRACE("(%p)->(%p)\n", iface, pos);
1215 if(!pos)
1217 WARN("Invalid parameter %p\n", pos);
1218 return DSERR_INVALIDPARAM;
1221 setALContext(This->ctx);
1222 alGetListenerfv(AL_POSITION, alpos);
1223 checkALError();
1224 popALContext();
1226 pos->x = alpos[0];
1227 pos->y = alpos[1];
1228 pos->z = -alpos[2];
1229 return S_OK;
1232 static HRESULT WINAPI DS8Primary3D_GetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE *rollofffactor)
1234 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1236 TRACE("(%p)->(%p)\n", iface, rollofffactor);
1238 if(!rollofffactor)
1240 WARN("Invalid parameter %p\n", rollofffactor);
1241 return DSERR_INVALIDPARAM;
1244 EnterCriticalSection(&This->share->crst);
1245 *rollofffactor = This->rollofffactor;
1246 LeaveCriticalSection(&This->share->crst);
1248 return S_OK;
1251 static HRESULT WINAPI DS8Primary3D_GetVelocity(IDirectSound3DListener *iface, D3DVECTOR *velocity)
1253 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1254 ALfloat vel[3];
1256 TRACE("(%p)->(%p)\n", iface, velocity);
1258 if(!velocity)
1260 WARN("Invalid parameter %p\n", velocity);
1261 return DSERR_INVALIDPARAM;
1264 setALContext(This->ctx);
1265 alGetListenerfv(AL_VELOCITY, vel);
1266 checkALError();
1267 popALContext();
1269 velocity->x = vel[0];
1270 velocity->y = vel[1];
1271 velocity->z = -vel[2];
1272 return S_OK;
1275 static HRESULT WINAPI DS8Primary3D_GetAllParameters(IDirectSound3DListener *iface, DS3DLISTENER *listener)
1277 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1279 TRACE("(%p)->(%p)\n", iface, listener);
1281 if(!listener || listener->dwSize < sizeof(*listener))
1283 WARN("Invalid DS3DLISTENER %p %lu\n", listener, listener ? listener->dwSize : 0);
1284 return DSERR_INVALIDPARAM;
1287 EnterCriticalSection(&This->share->crst);
1288 setALContext(This->ctx);
1289 DS8Primary3D_GetPosition(iface, &listener->vPosition);
1290 DS8Primary3D_GetVelocity(iface, &listener->vVelocity);
1291 DS8Primary3D_GetOrientation(iface, &listener->vOrientFront, &listener->vOrientTop);
1292 DS8Primary3D_GetDistanceFactor(iface, &listener->flDistanceFactor);
1293 DS8Primary3D_GetRolloffFactor(iface, &listener->flRolloffFactor);
1294 DS8Primary3D_GetDopplerFactor(iface, &listener->flDopplerFactor);
1295 popALContext();
1296 LeaveCriticalSection(&This->share->crst);
1298 return DS_OK;
1302 static HRESULT WINAPI DS8Primary3D_SetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1304 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1306 TRACE("(%p)->(%f, %lu)\n", iface, factor, apply);
1308 if(factor < DS3D_MINDISTANCEFACTOR ||
1309 factor > DS3D_MAXDISTANCEFACTOR)
1311 WARN("Invalid parameter %f\n", factor);
1312 return DSERR_INVALIDPARAM;
1315 if(apply == DS3D_DEFERRED)
1317 EnterCriticalSection(&This->share->crst);
1318 This->deferred.ds3d.flDistanceFactor = factor;
1319 This->dirty.bit.distancefactor = 1;
1320 LeaveCriticalSection(&This->share->crst);
1322 else
1324 setALContext(This->ctx);
1325 alSpeedOfSound(343.3f/factor);
1326 if(BITFIELD_TEST(This->share->Exts, EXT_EFX))
1327 alListenerf(AL_METERS_PER_UNIT, factor);
1328 checkALError();
1329 popALContext();
1332 return S_OK;
1335 static HRESULT WINAPI DS8Primary3D_SetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1337 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1339 TRACE("(%p)->(%f, %lu)\n", iface, factor, apply);
1341 if(factor < DS3D_MINDOPPLERFACTOR ||
1342 factor > DS3D_MAXDOPPLERFACTOR)
1344 WARN("Invalid parameter %f\n", factor);
1345 return DSERR_INVALIDPARAM;
1348 if(apply == DS3D_DEFERRED)
1350 EnterCriticalSection(&This->share->crst);
1351 This->deferred.ds3d.flDopplerFactor = factor;
1352 This->dirty.bit.dopplerfactor = 1;
1353 LeaveCriticalSection(&This->share->crst);
1355 else
1357 setALContext(This->ctx);
1358 alDopplerFactor(factor);
1359 checkALError();
1360 popALContext();
1363 return S_OK;
1366 static HRESULT WINAPI DS8Primary3D_SetOrientation(IDirectSound3DListener *iface, D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront, D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop, DWORD apply)
1368 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1370 TRACE("(%p)->(%f, %f, %f, %f, %f, %f, %lu)\n", iface, xFront, yFront, zFront, xTop, yTop, zTop, apply);
1372 if(apply == DS3D_DEFERRED)
1374 EnterCriticalSection(&This->share->crst);
1375 This->deferred.ds3d.vOrientFront.x = xFront;
1376 This->deferred.ds3d.vOrientFront.y = yFront;
1377 This->deferred.ds3d.vOrientFront.z = zFront;
1378 This->deferred.ds3d.vOrientTop.x = xTop;
1379 This->deferred.ds3d.vOrientTop.y = yTop;
1380 This->deferred.ds3d.vOrientTop.z = zTop;
1381 This->dirty.bit.orientation = 1;
1382 LeaveCriticalSection(&This->share->crst);
1384 else
1386 ALfloat orient[6] = {
1387 xFront, yFront, -zFront,
1388 xTop, yTop, -zTop
1390 setALContext(This->ctx);
1391 alListenerfv(AL_ORIENTATION, orient);
1392 checkALError();
1393 popALContext();
1396 return S_OK;
1399 static HRESULT WINAPI DS8Primary3D_SetPosition(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1401 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1403 TRACE("(%p)->(%f, %f, %f, %lu)\n", iface, x, y, z, apply);
1405 if(apply == DS3D_DEFERRED)
1407 EnterCriticalSection(&This->share->crst);
1408 This->deferred.ds3d.vPosition.x = x;
1409 This->deferred.ds3d.vPosition.y = y;
1410 This->deferred.ds3d.vPosition.z = z;
1411 This->dirty.bit.pos = 1;
1412 LeaveCriticalSection(&This->share->crst);
1414 else
1416 setALContext(This->ctx);
1417 alListener3f(AL_POSITION, x, y, -z);
1418 checkALError();
1419 popALContext();
1422 return S_OK;
1425 static HRESULT WINAPI DS8Primary3D_SetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1427 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1429 TRACE("(%p)->(%f, %lu)\n", iface, factor, apply);
1431 if(factor < DS3D_MINROLLOFFFACTOR ||
1432 factor > DS3D_MAXROLLOFFFACTOR)
1434 WARN("Invalid parameter %f\n", factor);
1435 return DSERR_INVALIDPARAM;
1438 EnterCriticalSection(&This->share->crst);
1439 if(apply == DS3D_DEFERRED)
1441 This->deferred.ds3d.flRolloffFactor = factor;
1442 This->dirty.bit.rollofffactor = 1;
1444 else
1446 struct DSBufferGroup *bufgroup = This->BufferGroups;
1447 DWORD i;
1449 This->rollofffactor = factor;
1451 setALContext(This->ctx);
1452 for(i = 0;i < This->NumBufferGroups;++i)
1454 DWORD64 usemask = ~bufgroup[i].FreeBuffers;
1455 while(usemask)
1457 int idx = CTZ64(usemask);
1458 DS8Buffer *buf = bufgroup[i].Buffers + idx;
1459 usemask &= ~(U64(1) << idx);
1461 if(buf->ds3dmode != DS3DMODE_DISABLE)
1462 alSourcef(buf->source, AL_ROLLOFF_FACTOR, factor);
1465 checkALError();
1466 popALContext();
1468 LeaveCriticalSection(&This->share->crst);
1470 return S_OK;
1473 static HRESULT WINAPI DS8Primary3D_SetVelocity(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1475 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1477 TRACE("(%p)->(%f, %f, %f, %lu)\n", iface, x, y, z, apply);
1479 if(apply == DS3D_DEFERRED)
1481 EnterCriticalSection(&This->share->crst);
1482 This->deferred.ds3d.vVelocity.x = x;
1483 This->deferred.ds3d.vVelocity.y = y;
1484 This->deferred.ds3d.vVelocity.z = z;
1485 This->dirty.bit.vel = 1;
1486 LeaveCriticalSection(&This->share->crst);
1488 else
1490 setALContext(This->ctx);
1491 alListener3f(AL_VELOCITY, x, y, -z);
1492 checkALError();
1493 popALContext();
1496 return S_OK;
1499 static HRESULT WINAPI DS8Primary3D_SetAllParameters(IDirectSound3DListener *iface, const DS3DLISTENER *listen, DWORD apply)
1501 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1503 TRACE("(%p)->(%p, %lu)\n", iface, listen, apply);
1505 if(!listen || listen->dwSize < sizeof(*listen))
1507 WARN("Invalid parameter %p %lu\n", listen, listen ? listen->dwSize : 0);
1508 return DSERR_INVALIDPARAM;
1511 if(listen->flDistanceFactor > DS3D_MAXDISTANCEFACTOR ||
1512 listen->flDistanceFactor < DS3D_MINDISTANCEFACTOR)
1514 WARN("Invalid distance factor (%f)\n", listen->flDistanceFactor);
1515 return DSERR_INVALIDPARAM;
1518 if(listen->flDopplerFactor > DS3D_MAXDOPPLERFACTOR ||
1519 listen->flDopplerFactor < DS3D_MINDOPPLERFACTOR)
1521 WARN("Invalid doppler factor (%f)\n", listen->flDopplerFactor);
1522 return DSERR_INVALIDPARAM;
1525 if(listen->flRolloffFactor < DS3D_MINROLLOFFFACTOR ||
1526 listen->flRolloffFactor > DS3D_MAXROLLOFFFACTOR)
1528 WARN("Invalid rolloff factor (%f)\n", listen->flRolloffFactor);
1529 return DSERR_INVALIDPARAM;
1532 if(apply == DS3D_DEFERRED)
1534 EnterCriticalSection(&This->share->crst);
1535 This->deferred.ds3d = *listen;
1536 This->deferred.ds3d.dwSize = sizeof(This->deferred.ds3d);
1537 This->dirty.bit.pos = 1;
1538 This->dirty.bit.vel = 1;
1539 This->dirty.bit.orientation = 1;
1540 This->dirty.bit.distancefactor = 1;
1541 This->dirty.bit.rollofffactor = 1;
1542 This->dirty.bit.dopplerfactor = 1;
1543 LeaveCriticalSection(&This->share->crst);
1545 else
1547 union PrimaryParamFlags dirty = { 0l };
1548 dirty.bit.pos = 1;
1549 dirty.bit.vel = 1;
1550 dirty.bit.orientation = 1;
1551 dirty.bit.distancefactor = 1;
1552 dirty.bit.rollofffactor = 1;
1553 dirty.bit.dopplerfactor = 1;
1555 EnterCriticalSection(&This->share->crst);
1556 setALContext(This->ctx);
1557 DS8Primary_SetParams(This, listen, dirty.flags);
1558 checkALError();
1559 popALContext();
1560 LeaveCriticalSection(&This->share->crst);
1563 return S_OK;
1566 HRESULT WINAPI DS8Primary3D_CommitDeferredSettings(IDirectSound3DListener *iface)
1568 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1569 struct DSBufferGroup *bufgroup;
1570 LONG flags;
1571 DWORD i;
1573 EnterCriticalSection(&This->share->crst);
1574 setALContext(This->ctx);
1575 alDeferUpdatesSOFT();
1577 if((flags=InterlockedExchange(&This->dirty.flags, 0)) != 0)
1579 DS8Primary_SetParams(This, &This->deferred.ds3d, flags);
1580 /* checkALError is here for debugging */
1581 checkALError();
1583 TRACE("Dirty flags was: 0x%02lx\n", flags);
1585 bufgroup = This->BufferGroups;
1586 for(i = 0;i < This->NumBufferGroups;++i)
1588 DWORD64 usemask = ~bufgroup[i].FreeBuffers;
1589 while(usemask)
1591 int idx = CTZ64(usemask);
1592 DS8Buffer *buf = bufgroup[i].Buffers + idx;
1593 usemask &= ~(U64(1) << idx);
1595 if((flags=InterlockedExchange(&buf->dirty.flags, 0)) != 0)
1596 DS8Buffer_SetParams(buf, &buf->deferred.ds3d, &buf->deferred.eax, flags);
1599 alProcessUpdatesSOFT();
1600 checkALError();
1602 popALContext();
1603 LeaveCriticalSection(&This->share->crst);
1605 return DS_OK;
1608 static const IDirectSound3DListenerVtbl DS8Primary3D_Vtbl =
1610 DS8Primary3D_QueryInterface,
1611 DS8Primary3D_AddRef,
1612 DS8Primary3D_Release,
1613 DS8Primary3D_GetAllParameters,
1614 DS8Primary3D_GetDistanceFactor,
1615 DS8Primary3D_GetDopplerFactor,
1616 DS8Primary3D_GetOrientation,
1617 DS8Primary3D_GetPosition,
1618 DS8Primary3D_GetRolloffFactor,
1619 DS8Primary3D_GetVelocity,
1620 DS8Primary3D_SetAllParameters,
1621 DS8Primary3D_SetDistanceFactor,
1622 DS8Primary3D_SetDopplerFactor,
1623 DS8Primary3D_SetOrientation,
1624 DS8Primary3D_SetPosition,
1625 DS8Primary3D_SetRolloffFactor,
1626 DS8Primary3D_SetVelocity,
1627 DS8Primary3D_CommitDeferredSettings
1631 static HRESULT WINAPI DS8PrimaryProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
1633 DS8Primary *This = impl_from_IKsPropertySet(iface);
1634 return DS8Primary_QueryInterface(&This->IDirectSoundBuffer_iface, riid, ppv);
1637 static ULONG WINAPI DS8PrimaryProp_AddRef(IKsPropertySet *iface)
1639 DS8Primary *This = impl_from_IKsPropertySet(iface);
1640 LONG ret;
1642 ret = InterlockedIncrement(&This->prop_ref);
1643 TRACE("new refcount %ld\n", ret);
1645 return ret;
1648 static ULONG WINAPI DS8PrimaryProp_Release(IKsPropertySet *iface)
1650 DS8Primary *This = impl_from_IKsPropertySet(iface);
1651 LONG ret;
1653 ret = InterlockedDecrement(&This->prop_ref);
1654 TRACE("new refcount %ld\n", ret);
1656 return ret;
1659 static HRESULT WINAPI DS8PrimaryProp_Get(IKsPropertySet *iface,
1660 REFGUID guidPropSet, ULONG dwPropID,
1661 LPVOID pInstanceData, ULONG cbInstanceData,
1662 LPVOID pPropData, ULONG cbPropData,
1663 ULONG *pcbReturned)
1665 (void)iface;
1666 (void)dwPropID;
1667 (void)pInstanceData;
1668 (void)cbInstanceData;
1669 (void)pPropData;
1670 (void)cbPropData;
1671 (void)pcbReturned;
1673 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
1675 return E_PROP_ID_UNSUPPORTED;
1678 static HRESULT WINAPI DS8PrimaryProp_Set(IKsPropertySet *iface,
1679 REFGUID guidPropSet, ULONG dwPropID,
1680 LPVOID pInstanceData, ULONG cbInstanceData,
1681 LPVOID pPropData, ULONG cbPropData)
1683 (void)iface;
1684 (void)dwPropID;
1685 (void)pInstanceData;
1686 (void)cbInstanceData;
1687 (void)pPropData;
1688 (void)cbPropData;
1690 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
1692 return E_PROP_ID_UNSUPPORTED;
1695 static HRESULT WINAPI DS8PrimaryProp_QuerySupport(IKsPropertySet *iface,
1696 REFGUID guidPropSet, ULONG dwPropID,
1697 ULONG *pTypeSupport)
1699 (void)iface;
1700 (void)dwPropID;
1701 (void)pTypeSupport;
1703 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
1705 return E_PROP_ID_UNSUPPORTED;
1708 static const IKsPropertySetVtbl DS8PrimaryProp_Vtbl =
1710 DS8PrimaryProp_QueryInterface,
1711 DS8PrimaryProp_AddRef,
1712 DS8PrimaryProp_Release,
1713 DS8PrimaryProp_Get,
1714 DS8PrimaryProp_Set,
1715 DS8PrimaryProp_QuerySupport