Add a missing newline to an ERR message
[dsound-openal.git] / primary.c
blobcd996a462c341523e99a4e879ea8a19a34cfdf67
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 #include <stdarg.h>
25 #ifdef __WINESRC__
27 #define COBJMACROS
28 #define NONAMELESSSTRUCT
29 #define NONAMELESSUNION
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winuser.h"
33 #include "winnls.h"
34 #include "winreg.h"
35 #include "vfwmsgs.h"
36 #include "mmsystem.h"
37 #include "winternl.h"
38 #include "mmddk.h"
39 #include "wine/debug.h"
40 #include "dsound.h"
42 #include "dsound_private.h"
44 #include "mmreg.h"
45 #include "ks.h"
46 #include "ksmedia.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
50 #else
52 #define WINVER 0x0600
53 #include <windows.h>
54 #include <dsound.h>
56 #include "dsound_private.h"
58 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
59 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
61 #ifndef E_PROP_ID_UNSUPPORTED
62 #define E_PROP_ID_UNSUPPORTED ((HRESULT)0x80070490)
63 #endif
65 #endif
67 static const IDirectSoundBufferVtbl DS8Primary_Vtbl;
68 static const IDirectSound3DListenerVtbl DS8Primary3D_Vtbl;
69 static const IKsPropertySetVtbl DS8PrimaryProp_Vtbl;
72 static inline DS8Primary *impl_from_IDirectSoundBuffer(IDirectSoundBuffer *iface)
74 return CONTAINING_RECORD(iface, DS8Primary, IDirectSoundBuffer_iface);
77 static inline DS8Primary *impl_from_IDirectSound3DListener(IDirectSound3DListener *iface)
79 return CONTAINING_RECORD(iface, DS8Primary, IDirectSound3DListener_iface);
82 static inline DS8Primary *impl_from_IKsPropertySet(IKsPropertySet *iface)
84 return CONTAINING_RECORD(iface, DS8Primary, IKsPropertySet_iface);
88 static void AL_APIENTRY wrap_DeferUpdates(void)
89 { alcSuspendContext(alcGetCurrentContext()); }
90 static void AL_APIENTRY wrap_ProcessUpdates(void)
91 { alcProcessContext(alcGetCurrentContext()); }
94 static void trigger_elapsed_notifies(DS8Buffer *buf, DWORD lastpos, DWORD curpos)
96 DWORD i;
97 for(i = 0; i < buf->nnotify; ++i)
99 DSBPOSITIONNOTIFY *not = &buf->notify[i];
100 HANDLE event = not->hEventNotify;
101 DWORD ofs = not->dwOffset;
103 if(ofs == (DWORD)DSBPN_OFFSETSTOP)
104 continue;
106 /* Wraparound case */
107 if(curpos < lastpos)
109 if(ofs < curpos || ofs >= lastpos)
110 SetEvent(event);
111 continue;
114 /* Normal case */
115 if(ofs >= lastpos && ofs < curpos)
116 SetEvent(event);
120 static void trigger_stop_notifies(DS8Buffer *buf)
122 DWORD i;
123 for(i = 0; i < buf->nnotify; ++i)
125 DSBPOSITIONNOTIFY *not = &buf->notify[i];
126 if(not->dwOffset == (DWORD)DSBPN_OFFSETSTOP)
127 SetEvent(not->hEventNotify);
131 static DWORD CALLBACK ThreadProc(void *dwUser)
133 DS8Primary *prim = (DS8Primary*)dwUser;
134 DWORD i, active_notifies;
135 MSG msg;
137 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
139 TRACE("Primary buffer (%p) message loop start\n", prim);
140 while(GetMessageA(&msg, NULL, 0, 0))
142 if(msg.message != WM_USER)
143 continue;
145 EnterCriticalSection(prim->crst);
146 setALContext(prim->ctx);
148 for(i = 0;i < prim->nnotifies;)
150 DS8Buffer *buf = prim->notifies[i];
151 IDirectSoundBuffer8 *dsb = &buf->IDirectSoundBuffer8_iface;
152 DWORD status=0, curpos=buf->lastpos;
154 IDirectSoundBuffer8_GetStatus(dsb, &status);
155 IDirectSoundBuffer8_GetCurrentPosition(dsb, &curpos, NULL);
156 if(buf->lastpos != curpos)
158 trigger_elapsed_notifies(buf, buf->lastpos, curpos);
159 buf->lastpos = curpos;
161 if(!(status&DSBSTATUS_PLAYING))
163 /* Remove this buffer from list and put another at the
164 * current position; don't increment i
166 trigger_stop_notifies(buf);
167 prim->notifies[i] = prim->notifies[--prim->nnotifies];
168 continue;
170 i++;
172 active_notifies = i;
174 /* OpenAL doesn't support our lovely buffer extensions
175 * so just make sure enough buffers are queued
177 if(!prim->SupportedExt[SOFT_BUFFER_SAMPLES] &&
178 !prim->SupportedExt[SOFT_BUFFER_SUB_DATA] &&
179 !prim->SupportedExt[EXT_STATIC_BUFFER])
181 for(i = 0;i < prim->nbuffers;++i)
183 DS8Buffer *buf = prim->buffers[i];
184 ALint done = 0, queued = QBUFFERS, state = AL_PLAYING;
185 ALuint which, ofs;
187 if(buf->buffer->numsegs == 1 || !buf->isplaying)
188 continue;
190 alGetSourcei(buf->source, AL_SOURCE_STATE, &state);
191 alGetSourcei(buf->source, AL_BUFFERS_QUEUED, &queued);
192 alGetSourcei(buf->source, AL_BUFFERS_PROCESSED, &done);
194 queued -= done;
195 while(done--)
196 alSourceUnqueueBuffers(buf->source, 1, &which);
197 while(queued < QBUFFERS)
199 which = buf->buffer->buffers[buf->curidx];
200 ofs = buf->curidx*buf->buffer->segsize;
201 if(buf->curidx < buf->buffer->numsegs-1)
202 alBufferData(which, buf->buffer->buf_format,
203 buf->buffer->data + ofs, buf->buffer->segsize,
204 buf->buffer->format.Format.nSamplesPerSec);
205 else
206 alBufferData(which, buf->buffer->buf_format,
207 buf->buffer->data + ofs, buf->buffer->lastsegsize,
208 buf->buffer->format.Format.nSamplesPerSec);
210 alSourceQueueBuffers(buf->source, 1, &which);
211 buf->curidx = (buf->curidx+1)%buf->buffer->numsegs;
212 queued++;
214 if(!buf->curidx && !buf->islooping)
216 buf->isplaying = FALSE;
217 break;
220 if(state != AL_PLAYING)
222 if(!queued)
224 IDirectSoundBuffer8_Stop(&buf->IDirectSoundBuffer8_iface);
225 continue;
227 alSourcePlay(buf->source);
230 checkALError();
232 else if(active_notifies == 0 && prim->timer_id)
234 TRACE("No more notifies, killing timer\n");
235 timeKillEvent(prim->timer_id);
236 prim->timer_id = 0;
237 timeEndPeriod(prim->timer_res);
240 popALContext();
241 LeaveCriticalSection(prim->crst);
243 TRACE("Primary buffer (%p) message loop quit\n", prim);
245 if(prim->timer_id)
247 timeKillEvent(prim->timer_id);
248 prim->timer_id = 0;
249 timeEndPeriod(prim->timer_res);
250 TRACE("Killed timer\n");
253 return 0;
256 static void CALLBACK DS8Primary_timer(UINT timerID, UINT msg, DWORD_PTR dwUser,
257 DWORD_PTR dw1, DWORD_PTR dw2)
259 (void)timerID;
260 (void)msg;
261 (void)dw1;
262 (void)dw2;
263 PostThreadMessageA(dwUser, WM_USER, 0, 0);
266 void DS8Primary_starttimer(DS8Primary *prim)
268 DWORD triggertime, res = DS_TIME_RES;
269 ALint refresh = FAKE_REFRESH_COUNT;
270 TIMECAPS time;
272 if(prim->timer_id)
273 return;
275 timeGetDevCaps(&time, sizeof(TIMECAPS));
277 alcGetIntegerv(prim->parent->device, ALC_REFRESH, 1, &refresh);
278 checkALCError(prim->parent->device);
280 triggertime = 1000 / refresh / 2;
281 if(triggertime < time.wPeriodMin)
282 triggertime = time.wPeriodMin;
283 TRACE("Calling timer every %"LONGFMT"u ms for %i refreshes per second\n", triggertime, refresh);
285 if (res < time.wPeriodMin)
286 res = time.wPeriodMin;
287 if (timeBeginPeriod(res) == TIMERR_NOCANDO)
288 WARN("Could not set minimum resolution, don't expect sound\n");
290 prim->timer_res = res;
291 prim->timer_id = timeSetEvent(triggertime, res, DS8Primary_timer, prim->thread_id, TIME_PERIODIC|TIME_KILL_SYNCHRONOUS);
296 HRESULT DS8Primary_PreInit(DS8Primary *This, DS8Impl *parent)
298 DS3DLISTENER *listener;
299 WAVEFORMATEX *wfx;
300 HRESULT hr;
302 This->IDirectSoundBuffer_iface.lpVtbl = (IDirectSoundBufferVtbl*)&DS8Primary_Vtbl;
303 This->IDirectSound3DListener_iface.lpVtbl = (IDirectSound3DListenerVtbl*)&DS8Primary3D_Vtbl;
304 This->IKsPropertySet_iface.lpVtbl = (IKsPropertySetVtbl*)&DS8PrimaryProp_Vtbl;
306 This->parent = parent;
307 This->crst = &parent->share->crst;
308 This->ctx = parent->share->ctx;
309 This->SupportedExt = parent->share->SupportedExt;
310 This->ExtAL = &parent->share->ExtAL;
311 This->sources = parent->share->sources;
312 This->auxslot = parent->share->auxslot;
314 /* Allocate enough for a WAVEFORMATEXTENSIBLE */
315 wfx = &This->format.Format;
317 wfx->wFormatTag = WAVE_FORMAT_PCM;
318 wfx->nChannels = 2;
319 wfx->wBitsPerSample = 8;
320 wfx->nSamplesPerSec = 22050;
321 wfx->nBlockAlign = wfx->wBitsPerSample * wfx->nChannels / 8;
322 wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
323 wfx->cbSize = 0;
325 This->stopped = TRUE;
327 /* Apparently primary buffer size is always 32k,
328 * tested on windows with 192k 24 bits sound @ 6 channels
329 * where it will run out in 60 ms and it isn't pointer aligned
331 This->buf_size = 32768;
333 if(This->SupportedExt[SOFT_DEFERRED_UPDATES])
335 This->DeferUpdates = This->ExtAL->DeferUpdatesSOFT;
336 This->ProcessUpdates = This->ExtAL->ProcessUpdatesSOFT;
338 else
340 This->DeferUpdates = wrap_DeferUpdates;
341 This->ProcessUpdates = wrap_ProcessUpdates;
344 This->eax_prop = EnvironmentDefaults[EAX_ENVIRONMENT_GENERIC];
345 if(This->SupportedExt[EXT_EFX] && This->auxslot != 0)
347 ALint revid = alGetEnumValue("AL_EFFECT_REVERB");
348 if(revid != 0 && revid != -1)
350 This->ExtAL->GenEffects(1, &This->effect);
351 This->ExtAL->Effecti(This->effect, AL_EFFECT_TYPE, AL_EFFECT_REVERB);
352 checkALError();
356 /* Make sure DS3DListener defaults are applied to OpenAL */
357 listener = &This->listen;
358 listener->dwSize = sizeof(*listener);
359 listener->vPosition.x = 0.0;
360 listener->vPosition.y = 0.0;
361 listener->vPosition.z = 0.0;
362 listener->vVelocity.x = 0.0;
363 listener->vVelocity.y = 0.0;
364 listener->vVelocity.z = 0.0;
365 listener->vOrientFront.x = 0.0;
366 listener->vOrientFront.y = 0.0;
367 listener->vOrientFront.z = 1.0;
368 listener->vOrientTop.x = 0.0;
369 listener->vOrientTop.y = 1.0;
370 listener->vOrientTop.z = 0.0;
371 listener->flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
372 listener->flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
373 listener->flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
374 hr = IDirectSound3DListener_SetAllParameters(&This->IDirectSound3DListener_iface, listener, DS3D_IMMEDIATE);
375 if(FAILED(hr))
376 ERR("Could not set 3d parameters: %08"LONGFMT"x\n", hr);
378 This->sizenotifies = This->sizebuffers = parent->share->max_sources;
380 hr = DSERR_OUTOFMEMORY;
381 This->buffers = HeapAlloc(GetProcessHeap(), 0, This->sizebuffers*sizeof(*This->buffers));
382 This->notifies = HeapAlloc(GetProcessHeap(), 0, This->sizenotifies*sizeof(*This->notifies));
383 if(!This->buffers || !This->notifies)
384 goto fail;
386 This->thread_hdl = CreateThread(NULL, 0, ThreadProc, This, 0, &This->thread_id);
387 if(This->thread_hdl == NULL)
388 goto fail;
390 return S_OK;
392 fail:
393 DS8Primary_Clear(This);
394 return hr;
397 void DS8Primary_Clear(DS8Primary *This)
399 TRACE("Clearing primary %p\n", This);
401 if(!This->parent)
402 return;
404 if(This->thread_hdl)
406 PostThreadMessageA(This->thread_id, WM_QUIT, 0, 0);
407 if(WaitForSingleObject(This->thread_hdl, 1000) != WAIT_OBJECT_0)
408 ERR("Thread wait timed out\n");
409 CloseHandle(This->thread_hdl);
412 setALContext(This->ctx);
413 if(This->effect)
414 This->ExtAL->DeleteEffects(1, &This->effect);
415 popALContext();
416 while(This->nbuffers--)
417 DS8Buffer_Destroy(This->buffers[This->nbuffers]);
419 HeapFree(GetProcessHeap(), 0, This->notifies);
420 HeapFree(GetProcessHeap(), 0, This->buffers);
421 memset(This, 0, sizeof(*This));
424 static HRESULT WINAPI DS8Primary_QueryInterface(IDirectSoundBuffer *iface, REFIID riid, LPVOID *ppv)
426 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
428 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
430 *ppv = NULL;
431 if(IsEqualIID(riid, &IID_IUnknown) ||
432 IsEqualIID(riid, &IID_IDirectSoundBuffer))
433 *ppv = &This->IDirectSoundBuffer_iface;
434 else if(IsEqualIID(riid, &IID_IDirectSound3DListener))
436 if((This->flags&DSBCAPS_CTRL3D))
437 *ppv = &This->IDirectSound3DListener_iface;
439 else
440 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
442 if(*ppv)
444 IUnknown_AddRef((IUnknown*)*ppv);
445 return S_OK;
448 return E_NOINTERFACE;
451 static ULONG WINAPI DS8Primary_AddRef(IDirectSoundBuffer *iface)
453 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
454 LONG ret;
456 ret = InterlockedIncrement(&This->ref);
457 if(ret == 1) This->flags = 0;
459 return ret;
462 static ULONG WINAPI DS8Primary_Release(IDirectSoundBuffer *iface)
464 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
465 LONG ret;
467 ret = InterlockedDecrement(&This->ref);
469 return ret;
472 static HRESULT WINAPI DS8Primary_GetCaps(IDirectSoundBuffer *iface, DSBCAPS *caps)
474 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
476 TRACE("(%p)->(%p)\n", iface, caps);
478 if(!caps || caps->dwSize < sizeof(*caps))
480 WARN("Invalid DSBCAPS (%p, %"LONGFMT"u)\n", caps, caps ? caps->dwSize : 0);
481 return DSERR_INVALIDPARAM;
484 EnterCriticalSection(This->crst);
485 caps->dwFlags = This->flags;
486 caps->dwBufferBytes = This->buf_size;
487 caps->dwUnlockTransferRate = 0;
488 caps->dwPlayCpuOverhead = 0;
489 LeaveCriticalSection(This->crst);
491 return DS_OK;
494 static HRESULT WINAPI DS8Primary_GetCurrentPosition(IDirectSoundBuffer *iface, DWORD *playpos, DWORD *curpos)
496 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
497 HRESULT hr = DSERR_PRIOLEVELNEEDED;
499 EnterCriticalSection(This->crst);
500 if(This->write_emu)
501 hr = IDirectSoundBuffer8_GetCurrentPosition(This->write_emu, playpos, curpos);
502 LeaveCriticalSection(This->crst);
504 return hr;
507 static HRESULT WINAPI DS8Primary_GetFormat(IDirectSoundBuffer *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
509 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
510 HRESULT hr = S_OK;
511 UINT size;
513 if(!wfx && !written)
515 WARN("Cannot report format or format size\n");
516 return DSERR_INVALIDPARAM;
519 EnterCriticalSection(This->crst);
520 size = sizeof(This->format.Format) + This->format.Format.cbSize;
521 if(written)
522 *written = size;
523 if(wfx)
525 if(allocated < size)
526 hr = DSERR_INVALIDPARAM;
527 else
528 memcpy(wfx, &This->format.Format, size);
530 LeaveCriticalSection(This->crst);
532 return hr;
535 static HRESULT WINAPI DS8Primary_GetVolume(IDirectSoundBuffer *iface, LONG *volume)
537 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
538 HRESULT hr = S_OK;
540 TRACE("(%p)->(%p)\n", iface, volume);
542 if(!volume)
543 return DSERR_INVALIDPARAM;
545 EnterCriticalSection(This->crst);
546 if(!(This->flags & DSBCAPS_CTRLVOLUME))
547 hr = DSERR_CONTROLUNAVAIL;
548 else
550 ALfloat gain;
552 setALContext(This->ctx);
553 alGetListenerf(AL_GAIN, &gain);
554 checkALError();
555 popALContext();
557 *volume = clampI(gain_to_mB(gain), DSBVOLUME_MIN, DSBVOLUME_MAX);
559 LeaveCriticalSection(This->crst);
561 return hr;
564 static HRESULT WINAPI DS8Primary_GetPan(IDirectSoundBuffer *iface, LONG *pan)
566 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
567 HRESULT hr = S_OK;
569 WARN("(%p)->(%p): semi-stub\n", iface, pan);
571 if(!pan)
572 return DSERR_INVALIDPARAM;
574 EnterCriticalSection(This->crst);
575 if(This->write_emu)
576 hr = IDirectSoundBuffer8_GetPan(This->write_emu, pan);
577 else if(!(This->flags & DSBCAPS_CTRLPAN))
578 hr = DSERR_CONTROLUNAVAIL;
579 else
580 *pan = 0;
581 LeaveCriticalSection(This->crst);
583 return hr;
586 static HRESULT WINAPI DS8Primary_GetFrequency(IDirectSoundBuffer *iface, DWORD *freq)
588 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
589 HRESULT hr = S_OK;
591 WARN("(%p)->(%p): semi-stub\n", iface, freq);
593 if(!freq)
594 return DSERR_INVALIDPARAM;
596 EnterCriticalSection(This->crst);
597 if(!(This->flags & DSBCAPS_CTRLFREQUENCY))
598 hr = DSERR_CONTROLUNAVAIL;
599 else
600 *freq = This->format.Format.nSamplesPerSec;
601 LeaveCriticalSection(This->crst);
603 return hr;
606 static HRESULT WINAPI DS8Primary_GetStatus(IDirectSoundBuffer *iface, DWORD *status)
608 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
610 TRACE("(%p)->(%p)\n", iface, status);
612 if(!status)
613 return DSERR_INVALIDPARAM;
615 EnterCriticalSection(This->crst);
617 *status = DSBSTATUS_PLAYING|DSBSTATUS_LOOPING;
618 if((This->flags&DSBCAPS_LOCDEFER))
619 *status |= DSBSTATUS_LOCHARDWARE;
621 if(This->stopped)
623 DWORD i, state;
624 HRESULT hr;
626 for(i = 0;i < This->nbuffers;++i)
628 hr = IDirectSoundBuffer8_GetStatus(&This->buffers[i]->IDirectSoundBuffer8_iface, &state);
629 if(SUCCEEDED(hr) && (state&DSBSTATUS_PLAYING))
630 break;
632 if(i == This->nbuffers)
634 /* Primary stopped and no buffers playing.. */
635 *status = 0;
639 LeaveCriticalSection(This->crst);
641 return S_OK;
644 static HRESULT WINAPI DS8Primary_Initialize(IDirectSoundBuffer *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
646 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
647 HRESULT hr = S_OK;
649 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
651 if(!desc || desc->lpwfxFormat || desc->dwBufferBytes)
653 WARN("Bad DSBDESC for primary buffer\n");
654 return DSERR_INVALIDPARAM;
656 if((desc->dwFlags&DSBCAPS_CTRLFX) ||
657 (desc->dwFlags&DSBCAPS_CTRLPOSITIONNOTIFY) ||
658 (desc->dwFlags&DSBCAPS_LOCSOFTWARE))
660 WARN("Bad dwFlags %08"LONGFMT"x\n", desc->dwFlags);
661 return DSERR_INVALIDPARAM;
664 EnterCriticalSection(This->crst);
665 /* Should be 0 if not initialized */
666 if(This->flags)
668 hr = DSERR_ALREADYINITIALIZED;
669 goto out;
672 if(This->parent->prio_level == DSSCL_WRITEPRIMARY)
674 DSBUFFERDESC emudesc;
675 DS8Buffer *emu;
677 if(This->write_emu)
679 ERR("There shouldn't be a write_emu!\n");
680 IDirectSoundBuffer8_Release(This->write_emu);
681 This->write_emu = NULL;
684 memset(&emudesc, 0, sizeof(emudesc));
685 emudesc.dwSize = sizeof(emudesc);
686 emudesc.dwFlags = DSBCAPS_LOCHARDWARE | (desc->dwFlags&DSBCAPS_CTRLPAN);
687 /* Dont play last incomplete sample */
688 emudesc.dwBufferBytes = This->buf_size - (This->buf_size%This->format.Format.nBlockAlign);
689 emudesc.lpwfxFormat = &This->format.Format;
691 hr = DS8Buffer_Create(&emu, This, NULL);
692 if(SUCCEEDED(hr))
694 This->write_emu = &emu->IDirectSoundBuffer8_iface;
695 hr = IDirectSoundBuffer8_Initialize(This->write_emu, ds, &emudesc);
696 if(FAILED(hr))
698 IDirectSoundBuffer8_Release(This->write_emu);
699 This->write_emu = NULL;
704 if(SUCCEEDED(hr))
705 This->flags = desc->dwFlags | DSBCAPS_LOCHARDWARE;
706 out:
707 LeaveCriticalSection(This->crst);
708 return hr;
711 static HRESULT WINAPI DS8Primary_Lock(IDirectSoundBuffer *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
713 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
714 HRESULT hr = DSERR_PRIOLEVELNEEDED;
716 TRACE("(%p)->(%"LONGFMT"u, %"LONGFMT"u, %p, %p, %p, %p, %"LONGFMT"u)\n", iface, ofs, bytes, ptr1, len1, ptr2, len2, flags);
718 EnterCriticalSection(This->crst);
719 if(This->write_emu)
720 hr = IDirectSoundBuffer8_Lock(This->write_emu, ofs, bytes, ptr1, len1, ptr2, len2, flags);
721 LeaveCriticalSection(This->crst);
723 return hr;
726 static HRESULT WINAPI DS8Primary_Play(IDirectSoundBuffer *iface, DWORD res1, DWORD res2, DWORD flags)
728 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
729 HRESULT hr;
731 TRACE("(%p)->(%"LONGFMT"u, %"LONGFMT"u, %"LONGFMT"u)\n", iface, res1, res2, flags);
733 if(!(flags & DSBPLAY_LOOPING))
735 WARN("Flags (%08"LONGFMT"x) not set to DSBPLAY_LOOPING\n", flags);
736 return DSERR_INVALIDPARAM;
739 EnterCriticalSection(This->crst);
740 hr = S_OK;
741 if(This->write_emu)
742 hr = IDirectSoundBuffer8_Play(This->write_emu, res1, res2, flags);
743 if(SUCCEEDED(hr))
744 This->stopped = FALSE;
745 LeaveCriticalSection(This->crst);
747 return hr;
750 static HRESULT WINAPI DS8Primary_SetCurrentPosition(IDirectSoundBuffer *iface, DWORD pos)
752 WARN("(%p)->(%"LONGFMT"u)\n", iface, pos);
753 return DSERR_INVALIDCALL;
756 /* Just assume the format is crap, and clean up the damage */
757 static void copy_waveformat(WAVEFORMATEX *wfx, const WAVEFORMATEX *from)
759 if(from->wFormatTag == WAVE_FORMAT_PCM)
761 wfx->cbSize = 0;
762 if(from->wBitsPerSample == 8 ||
763 from->wBitsPerSample == 16 ||
764 from->wBitsPerSample == 24 ||
765 from->wBitsPerSample == 32)
766 wfx->wBitsPerSample = from->wBitsPerSample;
768 else if(from->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
770 WAVEFORMATEXTENSIBLE *wfe = (WAVEFORMATEXTENSIBLE*)wfx;
771 const WAVEFORMATEXTENSIBLE *fromx = (const WAVEFORMATEXTENSIBLE*)from;
772 DWORD size = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
774 /* Fail silently.. */
775 if(from->cbSize < size)
776 return;
777 if(!fromx->Samples.wValidBitsPerSample &&
778 !fromx->Format.wBitsPerSample)
779 return;
781 if(!IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) &&
782 !IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
784 ERR("Unhandled extensible format: %s\n", debugstr_guid(&wfe->SubFormat));
785 return;
788 wfe->Format.wBitsPerSample = from->wBitsPerSample;
789 wfe->Samples.wValidBitsPerSample = fromx->Samples.wValidBitsPerSample;
790 if(!wfe->Samples.wValidBitsPerSample)
791 wfe->Samples.wValidBitsPerSample = wfe->Format.wBitsPerSample;
792 wfe->Format.cbSize = size;
793 wfe->dwChannelMask = fromx->dwChannelMask;
794 wfe->SubFormat = fromx->SubFormat;
796 else
798 ERR("Unhandled format tag %04x\n", from->wFormatTag);
799 return;
802 if(from->nChannels)
803 wfx->nChannels = from->nChannels;
804 wfx->wFormatTag = from->wFormatTag;
805 if(from->nSamplesPerSec >= DSBFREQUENCY_MIN &&
806 from->nSamplesPerSec <= DSBFREQUENCY_MAX)
807 wfx->nSamplesPerSec = from->nSamplesPerSec;
808 wfx->nBlockAlign = wfx->wBitsPerSample * wfx->nChannels / 8;
809 wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
812 static HRESULT WINAPI DS8Primary_SetFormat(IDirectSoundBuffer *iface, const WAVEFORMATEX *wfx)
814 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
815 HRESULT hr = S_OK;
816 ALCint freq;
818 TRACE("(%p)->(%p)\n", iface, wfx);
820 if(!wfx)
822 WARN("Missing format\n");
823 return DSERR_INVALIDPARAM;
826 EnterCriticalSection(This->crst);
828 if(This->parent->prio_level < DSSCL_PRIORITY)
830 hr = DSERR_PRIOLEVELNEEDED;
831 goto out;
834 TRACE("Requested primary format:\n"
835 " FormatTag = %04x\n"
836 " Channels = %u\n"
837 " SamplesPerSec = %"LONGFMT"u\n"
838 " AvgBytesPerSec = %"LONGFMT"u\n"
839 " BlockAlign = %u\n"
840 " BitsPerSample = %u\n",
841 wfx->wFormatTag, wfx->nChannels,
842 wfx->nSamplesPerSec, wfx->nAvgBytesPerSec,
843 wfx->nBlockAlign, wfx->wBitsPerSample);
845 copy_waveformat(&This->format.Format, wfx);
847 freq = This->format.Format.nSamplesPerSec;
848 alcGetIntegerv(This->parent->device, ALC_FREQUENCY, 1, &freq);
849 checkALCError(This->parent->device);
851 This->format.Format.nSamplesPerSec = freq;
852 This->format.Format.nAvgBytesPerSec = This->format.Format.nBlockAlign *
853 This->format.Format.nSamplesPerSec;
855 if(This->write_emu)
857 DS8Buffer *buf;
858 DSBUFFERDESC desc;
860 memset(&desc, 0, sizeof(desc));
861 desc.dwSize = sizeof(desc);
862 desc.dwFlags = DSBCAPS_LOCHARDWARE|DSBCAPS_CTRLPAN;
863 desc.dwBufferBytes = This->buf_size - (This->buf_size % This->format.Format.nBlockAlign);
864 desc.lpwfxFormat = &This->format.Format;
866 hr = DS8Buffer_Create(&buf, This, NULL);
867 if(FAILED(hr))
868 goto out;
870 hr = IDirectSoundBuffer8_Initialize(&buf->IDirectSoundBuffer8_iface, &This->parent->IDirectSound_iface, &desc);
871 if(FAILED(hr))
872 DS8Buffer_Destroy(buf);
873 else
875 IDirectSoundBuffer8_Release(This->write_emu);
876 This->write_emu = &buf->IDirectSoundBuffer8_iface;
880 out:
881 LeaveCriticalSection(This->crst);
882 return hr;
885 static HRESULT WINAPI DS8Primary_SetVolume(IDirectSoundBuffer *iface, LONG vol)
887 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
888 HRESULT hr = S_OK;
890 TRACE("(%p)->(%"LONGFMT"d)\n", iface, vol);
892 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
894 WARN("Invalid volume (%"LONGFMT"d)\n", vol);
895 return DSERR_INVALIDPARAM;
898 EnterCriticalSection(This->crst);
899 if(!(This->flags&DSBCAPS_CTRLVOLUME))
900 hr = DSERR_CONTROLUNAVAIL;
901 if(SUCCEEDED(hr))
903 setALContext(This->ctx);
904 alListenerf(AL_GAIN, mB_to_gain(vol));
905 popALContext();
907 LeaveCriticalSection(This->crst);
909 return hr;
912 static HRESULT WINAPI DS8Primary_SetPan(IDirectSoundBuffer *iface, LONG pan)
914 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
915 HRESULT hr;
917 TRACE("(%p)->(%"LONGFMT"d)\n", iface, pan);
919 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
921 WARN("invalid parameter: pan = %"LONGFMT"d\n", pan);
922 return DSERR_INVALIDPARAM;
925 EnterCriticalSection(This->crst);
926 if(!(This->flags&DSBCAPS_CTRLPAN))
928 WARN("control unavailable\n");
929 hr = DSERR_CONTROLUNAVAIL;
931 else if(This->write_emu)
932 hr = IDirectSoundBuffer8_SetPan(This->write_emu, pan);
933 else
935 FIXME("Not supported\n");
936 hr = E_NOTIMPL;
938 LeaveCriticalSection(This->crst);
940 return hr;
943 static HRESULT WINAPI DS8Primary_SetFrequency(IDirectSoundBuffer *iface, DWORD freq)
945 WARN("(%p)->(%"LONGFMT"u)\n", iface, freq);
946 return DSERR_CONTROLUNAVAIL;
949 static HRESULT WINAPI DS8Primary_Stop(IDirectSoundBuffer *iface)
951 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
952 HRESULT hr = S_OK;
954 TRACE("(%p)->()\n", iface);
956 EnterCriticalSection(This->crst);
957 if(This->write_emu)
958 hr = IDirectSoundBuffer8_Stop(This->write_emu);
959 if(SUCCEEDED(hr))
960 This->stopped = TRUE;
961 LeaveCriticalSection(This->crst);
963 return hr;
966 static HRESULT WINAPI DS8Primary_Unlock(IDirectSoundBuffer *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
968 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
969 HRESULT hr = DSERR_INVALIDCALL;
971 TRACE("(%p)->(%p, %"LONGFMT"u, %p, %"LONGFMT"u)\n", iface, ptr1, len1, ptr2, len2);
973 EnterCriticalSection(This->crst);
974 if(This->write_emu)
975 hr = IDirectSoundBuffer8_Unlock(This->write_emu, ptr1, len1, ptr2, len2);
976 LeaveCriticalSection(This->crst);
978 return hr;
981 static HRESULT WINAPI DS8Primary_Restore(IDirectSoundBuffer *iface)
983 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
984 HRESULT hr = S_OK;
986 TRACE("(%p)->()\n", iface);
988 EnterCriticalSection(This->crst);
989 if(This->write_emu)
990 hr = IDirectSoundBuffer8_Restore(This->write_emu);
991 LeaveCriticalSection(This->crst);
993 return hr;
996 static const IDirectSoundBufferVtbl DS8Primary_Vtbl =
998 DS8Primary_QueryInterface,
999 DS8Primary_AddRef,
1000 DS8Primary_Release,
1001 DS8Primary_GetCaps,
1002 DS8Primary_GetCurrentPosition,
1003 DS8Primary_GetFormat,
1004 DS8Primary_GetVolume,
1005 DS8Primary_GetPan,
1006 DS8Primary_GetFrequency,
1007 DS8Primary_GetStatus,
1008 DS8Primary_Initialize,
1009 DS8Primary_Lock,
1010 DS8Primary_Play,
1011 DS8Primary_SetCurrentPosition,
1012 DS8Primary_SetFormat,
1013 DS8Primary_SetVolume,
1014 DS8Primary_SetPan,
1015 DS8Primary_SetFrequency,
1016 DS8Primary_Stop,
1017 DS8Primary_Unlock,
1018 DS8Primary_Restore
1022 static HRESULT WINAPI DS8Primary3D_QueryInterface(IDirectSound3DListener *iface, REFIID riid, void **ppv)
1024 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1025 return DS8Primary_QueryInterface(&This->IDirectSoundBuffer_iface, riid, ppv);
1028 static ULONG WINAPI DS8Primary3D_AddRef(IDirectSound3DListener *iface)
1030 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1031 LONG ret;
1033 ret = InterlockedIncrement(&This->ds3d_ref);
1034 TRACE("new refcount %"LONGFMT"d\n", ret);
1036 return ret;
1039 static ULONG WINAPI DS8Primary3D_Release(IDirectSound3DListener *iface)
1041 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1042 LONG ret;
1044 ret = InterlockedDecrement(&This->ds3d_ref);
1045 TRACE("new refcount %"LONGFMT"d\n", ret);
1047 return ret;
1051 static HRESULT WINAPI DS8Primary3D_GetAllParameters(IDirectSound3DListener *iface, DS3DLISTENER *listener)
1053 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1055 TRACE("(%p)->(%p)\n", iface, listener);
1057 if(!listener || listener->dwSize < sizeof(*listener))
1059 WARN("Invalid DS3DLISTENER %p %"LONGFMT"u\n", listener, listener ? listener->dwSize : 0);
1060 return DSERR_INVALIDPARAM;
1063 EnterCriticalSection(This->crst);
1064 setALContext(This->ctx);
1065 IDirectSound3DListener_GetPosition(iface, &listener->vPosition);
1066 IDirectSound3DListener_GetVelocity(iface, &listener->vVelocity);
1067 IDirectSound3DListener_GetOrientation(iface, &listener->vOrientFront, &listener->vOrientTop);
1068 IDirectSound3DListener_GetDistanceFactor(iface, &listener->flDistanceFactor);
1069 IDirectSound3DListener_GetRolloffFactor(iface, &listener->flRolloffFactor);
1070 IDirectSound3DListener_GetDopplerFactor(iface, &listener->flDopplerFactor);
1071 popALContext();
1072 LeaveCriticalSection(This->crst);
1074 return DS_OK;
1077 static HRESULT WINAPI DS8Primary3D_GetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE *distancefactor)
1079 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1081 TRACE("(%p)->(%p)\n", iface, distancefactor);
1083 if(!distancefactor)
1085 WARN("Invalid parameter %p\n", distancefactor);
1086 return DSERR_INVALIDPARAM;
1089 setALContext(This->ctx);
1090 *distancefactor = 343.3f/alGetFloat(AL_SPEED_OF_SOUND);
1091 checkALError();
1092 popALContext();
1094 return S_OK;
1097 static HRESULT WINAPI DS8Primary3D_GetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE *dopplerfactor)
1099 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1101 TRACE("(%p)->(%p)\n", iface, dopplerfactor);
1103 if(!dopplerfactor)
1105 WARN("Invalid parameter %p\n", dopplerfactor);
1106 return DSERR_INVALIDPARAM;
1109 setALContext(This->ctx);
1110 *dopplerfactor = alGetFloat(AL_DOPPLER_FACTOR);
1111 checkALError();
1112 popALContext();
1114 return S_OK;
1117 static HRESULT WINAPI DS8Primary3D_GetOrientation(IDirectSound3DListener *iface, D3DVECTOR *front, D3DVECTOR *top)
1119 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1120 ALfloat orient[6];
1122 TRACE("(%p)->(%p, %p)\n", iface, front, top);
1124 if(!front || !top)
1126 WARN("Invalid parameter %p %p\n", front, top);
1127 return DSERR_INVALIDPARAM;
1130 setALContext(This->ctx);
1131 alGetListenerfv(AL_ORIENTATION, orient);
1132 checkALError();
1133 popALContext();
1135 front->x = orient[0];
1136 front->y = orient[1];
1137 front->z = -orient[2];
1138 top->x = orient[3];
1139 top->y = orient[4];
1140 top->z = -orient[5];
1141 return S_OK;
1144 static HRESULT WINAPI DS8Primary3D_GetPosition(IDirectSound3DListener *iface, D3DVECTOR *pos)
1146 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1147 ALfloat alpos[3];
1149 TRACE("(%p)->(%p)\n", iface, pos);
1151 if(!pos)
1153 WARN("Invalid parameter %p\n", pos);
1154 return DSERR_INVALIDPARAM;
1157 setALContext(This->ctx);
1158 alGetListenerfv(AL_POSITION, alpos);
1159 checkALError();
1160 popALContext();
1162 pos->x = alpos[0];
1163 pos->y = alpos[1];
1164 pos->z = -alpos[2];
1165 return S_OK;
1168 static HRESULT WINAPI DS8Primary3D_GetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE *rollofffactor)
1170 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1172 TRACE("(%p)->(%p)\n", iface, rollofffactor);
1174 if(!rollofffactor)
1176 WARN("Invalid parameter %p\n", rollofffactor);
1177 return DSERR_INVALIDPARAM;
1180 EnterCriticalSection(This->crst);
1181 *rollofffactor = This->rollofffactor;
1182 LeaveCriticalSection(This->crst);
1184 return S_OK;
1187 static HRESULT WINAPI DS8Primary3D_GetVelocity(IDirectSound3DListener *iface, D3DVECTOR *velocity)
1189 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1190 ALfloat vel[3];
1192 TRACE("(%p)->(%p)\n", iface, velocity);
1194 if(!velocity)
1196 WARN("Invalid parameter %p\n", velocity);
1197 return DSERR_INVALIDPARAM;
1200 setALContext(This->ctx);
1201 alGetListenerfv(AL_VELOCITY, vel);
1202 checkALError();
1203 popALContext();
1205 velocity->x = vel[0];
1206 velocity->y = vel[1];
1207 velocity->z = -vel[2];
1208 return S_OK;
1211 static HRESULT WINAPI DS8Primary3D_SetAllParameters(IDirectSound3DListener *iface, const DS3DLISTENER *listen, DWORD apply)
1213 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1215 TRACE("(%p)->(%p, %"LONGFMT"u)\n", iface, listen, apply);
1217 if(!listen || listen->dwSize < sizeof(*listen))
1219 WARN("Invalid parameter %p %"LONGFMT"u\n", listen, listen ? listen->dwSize : 0);
1220 return DSERR_INVALIDPARAM;
1223 if(listen->flDistanceFactor > DS3D_MAXDISTANCEFACTOR ||
1224 listen->flDistanceFactor < DS3D_MINDISTANCEFACTOR)
1226 WARN("Invalid distance factor (%f)\n", listen->flDistanceFactor);
1227 return DSERR_INVALIDPARAM;
1230 if(listen->flDopplerFactor > DS3D_MAXDOPPLERFACTOR ||
1231 listen->flDopplerFactor < DS3D_MINDOPPLERFACTOR)
1233 WARN("Invalid doppler factor (%f)\n", listen->flDopplerFactor);
1234 return DSERR_INVALIDPARAM;
1237 if(listen->flRolloffFactor < DS3D_MINROLLOFFFACTOR ||
1238 listen->flRolloffFactor > DS3D_MAXROLLOFFFACTOR)
1240 WARN("Invalid rolloff factor (%f)\n", listen->flRolloffFactor);
1241 return DSERR_INVALIDPARAM;
1244 EnterCriticalSection(This->crst);
1245 setALContext(This->ctx);
1246 IDirectSound3DListener_SetPosition(iface, listen->vPosition.x, listen->vPosition.y, listen->vPosition.z, apply);
1247 IDirectSound3DListener_SetVelocity(iface, listen->vVelocity.x, listen->vVelocity.y, listen->vVelocity.z, apply);
1248 IDirectSound3DListener_SetOrientation(iface, listen->vOrientFront.x, listen->vOrientFront.y, listen->vOrientFront.z,
1249 listen->vOrientTop.x, listen->vOrientTop.y, listen->vOrientTop.z, apply);
1250 IDirectSound3DListener_SetDistanceFactor(iface, listen->flDistanceFactor, apply);
1251 IDirectSound3DListener_SetRolloffFactor(iface, listen->flRolloffFactor, apply);
1252 IDirectSound3DListener_SetDopplerFactor(iface, listen->flDopplerFactor, apply);
1253 popALContext();
1254 LeaveCriticalSection(This->crst);
1256 return S_OK;
1259 static HRESULT WINAPI DS8Primary3D_SetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1261 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1263 TRACE("(%p)->(%f, %"LONGFMT"u)\n", iface, factor, apply);
1265 if(factor < DS3D_MINDISTANCEFACTOR ||
1266 factor > DS3D_MAXDISTANCEFACTOR)
1268 WARN("Invalid parameter %f\n", factor);
1269 return DSERR_INVALIDPARAM;
1272 if(apply == DS3D_DEFERRED)
1274 EnterCriticalSection(This->crst);
1275 This->listen.flDistanceFactor = factor;
1276 This->dirty.bit.distancefactor = 1;
1277 LeaveCriticalSection(This->crst);
1279 else
1281 setALContext(This->ctx);
1282 alSpeedOfSound(343.3f/factor);
1283 if(This->SupportedExt[EXT_EFX])
1284 alListenerf(AL_METERS_PER_UNIT, factor);
1285 checkALError();
1286 popALContext();
1289 return S_OK;
1292 static HRESULT WINAPI DS8Primary3D_SetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1294 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1296 TRACE("(%p)->(%f, %"LONGFMT"u)\n", iface, factor, apply);
1298 if(factor < DS3D_MINDOPPLERFACTOR ||
1299 factor > DS3D_MAXDOPPLERFACTOR)
1301 WARN("Invalid parameter %f\n", factor);
1302 return DSERR_INVALIDPARAM;
1305 if(apply == DS3D_DEFERRED)
1307 EnterCriticalSection(This->crst);
1308 This->listen.flDopplerFactor = factor;
1309 This->dirty.bit.dopplerfactor = 1;
1310 LeaveCriticalSection(This->crst);
1312 else
1314 setALContext(This->ctx);
1315 alDopplerFactor(factor);
1316 checkALError();
1317 popALContext();
1320 return S_OK;
1323 static HRESULT WINAPI DS8Primary3D_SetOrientation(IDirectSound3DListener *iface, D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront, D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop, DWORD apply)
1325 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1327 TRACE("(%p)->(%f, %f, %f, %f, %f, %f, %"LONGFMT"u)\n", iface, xFront, yFront, zFront, xTop, yTop, zTop, apply);
1329 if(apply == DS3D_DEFERRED)
1331 EnterCriticalSection(This->crst);
1332 This->listen.vOrientFront.x = xFront;
1333 This->listen.vOrientFront.y = yFront;
1334 This->listen.vOrientFront.z = zFront;
1335 This->listen.vOrientTop.x = xTop;
1336 This->listen.vOrientTop.y = yTop;
1337 This->listen.vOrientTop.z = zTop;
1338 This->dirty.bit.orientation = 1;
1339 LeaveCriticalSection(This->crst);
1341 else
1343 ALfloat orient[6] = {
1344 xFront, yFront, -zFront,
1345 xTop, yTop, -zTop
1347 setALContext(This->ctx);
1348 alListenerfv(AL_ORIENTATION, orient);
1349 checkALError();
1350 popALContext();
1353 return S_OK;
1356 static HRESULT WINAPI DS8Primary3D_SetPosition(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1358 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1360 TRACE("(%p)->(%f, %f, %f, %"LONGFMT"u)\n", iface, x, y, z, apply);
1362 if(apply == DS3D_DEFERRED)
1364 EnterCriticalSection(This->crst);
1365 This->listen.vPosition.x = x;
1366 This->listen.vPosition.y = y;
1367 This->listen.vPosition.z = z;
1368 This->dirty.bit.pos = 1;
1369 LeaveCriticalSection(This->crst);
1371 else
1373 setALContext(This->ctx);
1374 alListener3f(AL_POSITION, x, y, -z);
1375 checkALError();
1376 popALContext();
1379 return S_OK;
1382 static HRESULT WINAPI DS8Primary3D_SetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1384 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1386 TRACE("(%p)->(%f, %"LONGFMT"u)\n", iface, factor, apply);
1388 if(factor < DS3D_MINROLLOFFFACTOR ||
1389 factor > DS3D_MAXROLLOFFFACTOR)
1391 WARN("Invalid parameter %f\n", factor);
1392 return DSERR_INVALIDPARAM;
1395 EnterCriticalSection(This->crst);
1396 if(apply == DS3D_DEFERRED)
1398 This->listen.flRolloffFactor = factor;
1399 This->dirty.bit.rollofffactor = 1;
1401 else
1403 DWORD i;
1405 setALContext(This->ctx);
1406 for(i = 0;i < This->nbuffers;++i)
1408 if(This->buffers[i]->ds3dmode != DS3DMODE_DISABLE)
1409 alSourcef(This->buffers[i]->source, AL_ROLLOFF_FACTOR, factor);
1411 checkALError();
1412 popALContext();
1414 This->rollofffactor = factor;
1416 LeaveCriticalSection(This->crst);
1418 return S_OK;
1421 static HRESULT WINAPI DS8Primary3D_SetVelocity(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1423 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1425 TRACE("(%p)->(%f, %f, %f, %"LONGFMT"u)\n", iface, x, y, z, apply);
1427 if(apply == DS3D_DEFERRED)
1429 EnterCriticalSection(This->crst);
1430 This->listen.vVelocity.x = x;
1431 This->listen.vVelocity.y = y;
1432 This->listen.vVelocity.z = z;
1433 This->dirty.bit.vel = 1;
1434 LeaveCriticalSection(This->crst);
1436 else
1438 setALContext(This->ctx);
1439 alListener3f(AL_VELOCITY, x, y, -z);
1440 checkALError();
1441 popALContext();
1444 return S_OK;
1447 static HRESULT WINAPI DS8Primary3D_CommitDeferredSettings(IDirectSound3DListener *iface)
1449 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1450 const DS3DLISTENER *listen = &This->listen;
1451 DWORD i;
1453 EnterCriticalSection(This->crst);
1454 setALContext(This->ctx);
1455 This->DeferUpdates();
1457 if(This->dirty.bit.pos)
1458 alListener3f(AL_POSITION, listen->vPosition.x, listen->vPosition.y, -listen->vPosition.z);
1459 if(This->dirty.bit.vel)
1460 alListener3f(AL_VELOCITY, listen->vVelocity.x, listen->vVelocity.y, -listen->vVelocity.z);
1461 if(This->dirty.bit.orientation)
1463 ALfloat orient[6] = {
1464 listen->vOrientFront.x, listen->vOrientFront.y, -listen->vOrientFront.z,
1465 listen->vOrientTop.x, listen->vOrientTop.y, -listen->vOrientTop.z
1467 alListenerfv(AL_ORIENTATION, orient);
1469 if(This->dirty.bit.distancefactor)
1471 alSpeedOfSound(343.3f/listen->flDistanceFactor);
1472 if(This->SupportedExt[EXT_EFX])
1473 alListenerf(AL_METERS_PER_UNIT, listen->flDistanceFactor);
1476 if(This->dirty.bit.rollofffactor)
1478 ALfloat rolloff = This->rollofffactor;
1479 for(i = 0;i < This->nbuffers;++i)
1481 DS8Buffer *buf = This->buffers[i];
1482 if(buf->ds3dmode != DS3DMODE_DISABLE)
1483 alSourcef(buf->source, AL_ROLLOFF_FACTOR, rolloff);
1487 if(This->dirty.bit.dopplerfactor)
1488 alDopplerFactor(listen->flDopplerFactor);
1490 if(This->dirty.bit.effect)
1491 This->ExtAL->AuxiliaryEffectSloti(This->auxslot, AL_EFFECTSLOT_EFFECT, This->effect);
1493 /* checkALError is here for debugging */
1494 checkALError();
1496 TRACE("Dirty flags was: 0x%02x\n", This->dirty.flags);
1497 This->dirty.flags = 0;
1499 for(i = 0;i < This->nbuffers;++i)
1501 DS8Buffer *buf = This->buffers[i];
1503 if(!buf->dirty.flags)
1504 continue;
1506 if(buf->dirty.bit.pos)
1507 alSource3f(buf->source, AL_POSITION,
1508 buf->ds3dbuffer.vPosition.x,
1509 buf->ds3dbuffer.vPosition.y,
1510 -buf->ds3dbuffer.vPosition.z);
1511 if(buf->dirty.bit.vel)
1512 alSource3f(buf->source, AL_VELOCITY,
1513 buf->ds3dbuffer.vVelocity.x,
1514 buf->ds3dbuffer.vVelocity.y,
1515 -buf->ds3dbuffer.vVelocity.z);
1516 if(buf->dirty.bit.cone_angles)
1518 alSourcei(buf->source, AL_CONE_INNER_ANGLE,
1519 buf->ds3dbuffer.dwInsideConeAngle);
1520 alSourcei(buf->source, AL_CONE_OUTER_ANGLE,
1521 buf->ds3dbuffer.dwOutsideConeAngle);
1523 if(buf->dirty.bit.cone_orient)
1524 alSource3f(buf->source, AL_DIRECTION,
1525 buf->ds3dbuffer.vConeOrientation.x,
1526 buf->ds3dbuffer.vConeOrientation.y,
1527 -buf->ds3dbuffer.vConeOrientation.z);
1528 if(buf->dirty.bit.cone_outsidevolume)
1529 alSourcef(buf->source, AL_CONE_OUTER_GAIN,
1530 mB_to_gain(buf->ds3dbuffer.lConeOutsideVolume));
1531 if(buf->dirty.bit.min_distance)
1532 alSourcef(buf->source, AL_REFERENCE_DISTANCE, buf->ds3dbuffer.flMinDistance);
1533 if(buf->dirty.bit.max_distance)
1534 alSourcef(buf->source, AL_MAX_DISTANCE, buf->ds3dbuffer.flMaxDistance);
1535 if(buf->dirty.bit.mode)
1537 buf->ds3dmode = buf->ds3dbuffer.dwMode;
1538 alSourcei(buf->source, AL_SOURCE_RELATIVE,
1539 (buf->ds3dmode!=DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE);
1540 alSourcef(buf->source, AL_ROLLOFF_FACTOR,
1541 (buf->ds3dmode==DS3DMODE_DISABLE) ? 0.0f : This->rollofffactor);
1543 buf->dirty.flags = 0;
1545 checkALError();
1547 This->ProcessUpdates();
1548 popALContext();
1549 LeaveCriticalSection(This->crst);
1551 return S_OK;
1554 static const IDirectSound3DListenerVtbl DS8Primary3D_Vtbl =
1556 DS8Primary3D_QueryInterface,
1557 DS8Primary3D_AddRef,
1558 DS8Primary3D_Release,
1559 DS8Primary3D_GetAllParameters,
1560 DS8Primary3D_GetDistanceFactor,
1561 DS8Primary3D_GetDopplerFactor,
1562 DS8Primary3D_GetOrientation,
1563 DS8Primary3D_GetPosition,
1564 DS8Primary3D_GetRolloffFactor,
1565 DS8Primary3D_GetVelocity,
1566 DS8Primary3D_SetAllParameters,
1567 DS8Primary3D_SetDistanceFactor,
1568 DS8Primary3D_SetDopplerFactor,
1569 DS8Primary3D_SetOrientation,
1570 DS8Primary3D_SetPosition,
1571 DS8Primary3D_SetRolloffFactor,
1572 DS8Primary3D_SetVelocity,
1573 DS8Primary3D_CommitDeferredSettings
1576 /* NOTE: Although the app handles listener properties through secondary buffers,
1577 * we pass the requests to the primary buffer though a propertyset interface.
1578 * These methods are not exposed to the app. */
1579 static HRESULT WINAPI DS8PrimaryProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
1581 DS8Primary *This = impl_from_IKsPropertySet(iface);
1582 return DS8Primary_QueryInterface(&This->IDirectSoundBuffer_iface, riid, ppv);
1585 static ULONG WINAPI DS8PrimaryProp_AddRef(IKsPropertySet *iface)
1587 DS8Primary *This = impl_from_IKsPropertySet(iface);
1588 LONG ret;
1590 ret = InterlockedIncrement(&This->prop_ref);
1591 TRACE("new refcount %"LONGFMT"d\n", ret);
1593 return ret;
1596 static ULONG WINAPI DS8PrimaryProp_Release(IKsPropertySet *iface)
1598 DS8Primary *This = impl_from_IKsPropertySet(iface);
1599 LONG ret;
1601 ret = InterlockedDecrement(&This->prop_ref);
1602 TRACE("new refcount %"LONGFMT"d\n", ret);
1604 return ret;
1607 static HRESULT WINAPI DS8PrimaryProp_Get(IKsPropertySet *iface,
1608 REFGUID guidPropSet, ULONG dwPropID,
1609 LPVOID pInstanceData, ULONG cbInstanceData,
1610 LPVOID pPropData, ULONG cbPropData,
1611 PULONG pcbReturned)
1613 DS8Primary *This = impl_from_IKsPropertySet(iface);
1614 HRESULT res = E_PROP_ID_UNSUPPORTED;
1615 (void)pInstanceData;
1616 (void)cbInstanceData;
1618 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
1620 EnterCriticalSection(This->crst);
1622 if(This->effect == 0)
1623 res = E_PROP_ID_UNSUPPORTED;
1624 else switch(dwPropID)
1626 case DSPROPERTY_EAXLISTENER_ALLPARAMETERS:
1627 res = DSERR_INVALIDPARAM;
1628 if(cbPropData >= sizeof(EAXLISTENERPROPERTIES))
1630 union {
1631 void *v;
1632 EAXLISTENERPROPERTIES *props;
1633 } data = { pPropData };
1635 *data.props = This->eax_prop;
1636 *pcbReturned = sizeof(EAXLISTENERPROPERTIES);
1637 res = DS_OK;
1639 break;
1641 case DSPROPERTY_EAXLISTENER_ROOM:
1642 res = DSERR_INVALIDPARAM;
1643 if(cbPropData >= sizeof(LONG))
1645 union {
1646 void *v;
1647 LONG *l;
1648 } data = { pPropData };
1650 *data.l = This->eax_prop.lRoom;
1651 *pcbReturned = sizeof(LONG);
1652 res = DS_OK;
1654 break;
1655 case DSPROPERTY_EAXLISTENER_ROOMHF:
1656 res = DSERR_INVALIDPARAM;
1657 if(cbPropData >= sizeof(LONG))
1659 union {
1660 void *v;
1661 LONG *l;
1662 } data = { pPropData };
1664 *data.l = This->eax_prop.lRoomHF;
1665 *pcbReturned = sizeof(LONG);
1666 res = DS_OK;
1668 break;
1670 case DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR:
1671 res = DSERR_INVALIDPARAM;
1672 if(cbPropData >= sizeof(FLOAT))
1674 union {
1675 void *v;
1676 FLOAT *fl;
1677 } data = { pPropData };
1679 *data.fl = This->eax_prop.flRoomRolloffFactor;
1680 *pcbReturned = sizeof(FLOAT);
1681 res = DS_OK;
1683 break;
1685 case DSPROPERTY_EAXLISTENER_ENVIRONMENT:
1686 res = DSERR_INVALIDPARAM;
1687 if(cbPropData >= sizeof(DWORD))
1689 union {
1690 void *v;
1691 DWORD *dw;
1692 } data = { pPropData };
1694 *data.dw = This->eax_prop.dwEnvironment;
1695 *pcbReturned = sizeof(DWORD);
1696 res = DS_OK;
1698 break;
1700 case DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE:
1701 res = DSERR_INVALIDPARAM;
1702 if(cbPropData >= sizeof(FLOAT))
1704 union {
1705 void *v;
1706 FLOAT *fl;
1707 } data = { pPropData };
1709 *data.fl = This->eax_prop.flEnvironmentSize;
1710 *pcbReturned = sizeof(FLOAT);
1711 res = DS_OK;
1713 break;
1714 case DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION:
1715 res = DSERR_INVALIDPARAM;
1716 if(cbPropData >= sizeof(FLOAT))
1718 union {
1719 void *v;
1720 FLOAT *fl;
1721 } data = { pPropData };
1723 *data.fl = This->eax_prop.flEnvironmentDiffusion;
1724 *pcbReturned = sizeof(FLOAT);
1725 res = DS_OK;
1727 break;
1729 case DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF:
1730 res = DSERR_INVALIDPARAM;
1731 if(cbPropData >= sizeof(FLOAT))
1733 union {
1734 void *v;
1735 FLOAT *fl;
1736 } data = { pPropData };
1738 *data.fl = This->eax_prop.flAirAbsorptionHF;
1739 *pcbReturned = sizeof(FLOAT);
1740 res = DS_OK;
1742 break;
1744 case DSPROPERTY_EAXLISTENER_FLAGS:
1745 res = DSERR_INVALIDPARAM;
1746 if(cbPropData >= sizeof(DWORD))
1748 union {
1749 void *v;
1750 DWORD *dw;
1751 } data = { pPropData };
1753 *data.dw = This->eax_prop.dwFlags;
1754 *pcbReturned = sizeof(DWORD);
1755 res = DS_OK;
1757 break;
1759 default:
1760 FIXME("Unhandled propid: 0x%08"LONGFMT"x\n", dwPropID);
1761 break;
1764 LeaveCriticalSection(This->crst);
1766 else
1767 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
1769 return res;
1772 static HRESULT WINAPI DS8PrimaryProp_Set(IKsPropertySet *iface,
1773 REFGUID guidPropSet, ULONG dwPropID,
1774 LPVOID pInstanceData, ULONG cbInstanceData,
1775 LPVOID pPropData, ULONG cbPropData)
1777 DS8Primary *This = impl_from_IKsPropertySet(iface);
1778 HRESULT res = E_PROP_ID_UNSUPPORTED;
1779 (void)pInstanceData;
1780 (void)cbInstanceData;
1782 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
1784 DWORD propid = dwPropID & ~DSPROPERTY_EAXLISTENER_DEFERRED;
1785 BOOL immediate = !(dwPropID&DSPROPERTY_EAXLISTENER_DEFERRED);
1787 EnterCriticalSection(This->crst);
1788 setALContext(This->ctx);
1790 if(This->effect == 0)
1791 res = E_PROP_ID_UNSUPPORTED;
1792 else switch(propid)
1794 case 0: /* 0 = not setting any property, just apply */
1795 res = DS_OK;
1796 break;
1798 case DSPROPERTY_EAXLISTENER_ALLPARAMETERS:
1799 do_allparams:
1800 res = DSERR_INVALIDPARAM;
1801 if(cbPropData >= sizeof(EAXLISTENERPROPERTIES))
1803 union {
1804 const void *v;
1805 const EAXLISTENERPROPERTIES *props;
1806 } data = { pPropData };
1808 /* FIXME: Need to validate property values... Ignore? Clamp? Error? */
1809 This->eax_prop = *data.props;
1810 This->ExtAL->Effectf(This->effect, AL_REVERB_DENSITY,
1811 (data.props->flEnvironmentSize < 2.0f) ?
1812 (data.props->flEnvironmentSize - 1.0f) : 1.0f);
1813 This->ExtAL->Effectf(This->effect, AL_REVERB_DIFFUSION,
1814 data.props->flEnvironmentDiffusion);
1816 This->ExtAL->Effectf(This->effect, AL_REVERB_GAIN,
1817 mB_to_gain(data.props->lRoom));
1818 This->ExtAL->Effectf(This->effect, AL_REVERB_GAINHF,
1819 mB_to_gain(data.props->lRoomHF));
1821 This->ExtAL->Effectf(This->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
1822 data.props->flRoomRolloffFactor);
1824 This->ExtAL->Effectf(This->effect, AL_REVERB_DECAY_TIME,
1825 data.props->flDecayTime);
1826 This->ExtAL->Effectf(This->effect, AL_REVERB_DECAY_HFRATIO,
1827 data.props->flDecayHFRatio);
1829 This->ExtAL->Effectf(This->effect, AL_REVERB_REFLECTIONS_GAIN,
1830 mB_to_gain(data.props->lReflections));
1831 This->ExtAL->Effectf(This->effect, AL_REVERB_REFLECTIONS_DELAY,
1832 data.props->flReflectionsDelay);
1834 This->ExtAL->Effectf(This->effect, AL_REVERB_LATE_REVERB_GAIN,
1835 mB_to_gain(data.props->lReverb));
1836 This->ExtAL->Effectf(This->effect, AL_REVERB_LATE_REVERB_DELAY,
1837 data.props->flReverbDelay);
1839 This->ExtAL->Effectf(This->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
1840 mB_to_gain(data.props->flAirAbsorptionHF));
1842 This->ExtAL->Effecti(This->effect, AL_REVERB_DECAY_HFLIMIT,
1843 (data.props->dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
1844 AL_TRUE : AL_FALSE);
1846 checkALError();
1848 This->dirty.bit.effect = 1;
1849 res = DS_OK;
1851 break;
1853 case DSPROPERTY_EAXLISTENER_ROOM:
1854 res = DSERR_INVALIDPARAM;
1855 if(cbPropData >= sizeof(LONG))
1857 union {
1858 const void *v;
1859 const LONG *l;
1860 } data = { pPropData };
1862 This->eax_prop.lRoom = *data.l;
1863 This->ExtAL->Effectf(This->effect, AL_REVERB_GAIN,
1864 mB_to_gain(This->eax_prop.lRoom));
1865 checkALError();
1867 This->dirty.bit.effect = 1;
1868 res = DS_OK;
1870 break;
1871 case DSPROPERTY_EAXLISTENER_ROOMHF:
1872 res = DSERR_INVALIDPARAM;
1873 if(cbPropData >= sizeof(LONG))
1875 union {
1876 const void *v;
1877 const LONG *l;
1878 } data = { pPropData };
1880 This->eax_prop.lRoomHF = *data.l;
1881 This->ExtAL->Effectf(This->effect, AL_REVERB_GAINHF,
1882 mB_to_gain(This->eax_prop.lRoomHF));
1883 checkALError();
1885 This->dirty.bit.effect = 1;
1886 res = DS_OK;
1888 break;
1890 case DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR:
1891 res = DSERR_INVALIDPARAM;
1892 if(cbPropData >= sizeof(FLOAT))
1894 union {
1895 const void *v;
1896 const FLOAT *fl;
1897 } data = { pPropData };
1899 This->eax_prop.flRoomRolloffFactor = *data.fl;
1900 This->ExtAL->Effectf(This->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
1901 This->eax_prop.flRoomRolloffFactor);
1902 checkALError();
1904 This->dirty.bit.effect = 1;
1905 res = DS_OK;
1907 break;
1909 case DSPROPERTY_EAXLISTENER_ENVIRONMENT:
1910 res = DSERR_INVALIDPARAM;
1911 if(cbPropData >= sizeof(DWORD))
1913 union {
1914 const void *v;
1915 const DWORD *dw;
1916 } data = { pPropData };
1918 if(*data.dw < EAX_ENVIRONMENT_COUNT)
1920 /* Get the environment index's default and pass it down to
1921 * ALLPARAMETERS */
1922 propid = DSPROPERTY_EAXLISTENER_ALLPARAMETERS;
1923 pPropData = (void*)&EnvironmentDefaults[*data.dw];
1924 cbPropData = sizeof(EnvironmentDefaults[*data.dw]);
1925 goto do_allparams;
1928 break;
1930 case DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE:
1931 res = DSERR_INVALIDPARAM;
1932 if(cbPropData >= sizeof(FLOAT))
1934 union {
1935 const void *v;
1936 const FLOAT *fl;
1937 } data = { pPropData };
1939 if(*data.fl >= 1.0f && *data.fl <= 100.0f)
1941 double scale = (*data.fl)/This->eax_prop.flEnvironmentSize;
1943 This->eax_prop.flEnvironmentSize = *data.fl;
1945 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYTIMESCALE))
1947 This->eax_prop.flDecayTime *= scale;
1948 This->eax_prop.flDecayTime = clampF(This->eax_prop.flDecayTime, 0.1f, 20.0f);
1950 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSSCALE))
1952 This->eax_prop.lReflections += gain_to_mB(1.0/scale);
1953 This->eax_prop.lReflections = clampI(This->eax_prop.lReflections, -10000, 1000);
1955 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSDELAYSCALE))
1957 This->eax_prop.flReflectionsDelay *= scale;
1958 This->eax_prop.flReflectionsDelay = clampF(This->eax_prop.flReflectionsDelay, 0.0f, 0.3f);
1960 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBSCALE))
1962 This->eax_prop.lReverb += gain_to_mB(1.0/scale);
1963 This->eax_prop.lReverb = clampI(This->eax_prop.lReverb, -10000, 2000);
1965 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBDELAYSCALE))
1967 This->eax_prop.flReverbDelay *= scale;
1968 This->eax_prop.flReverbDelay = clampF(This->eax_prop.flReverbDelay, 0.0f, 0.1f);
1971 /* Pass the updated environment properties down to ALLPARAMETERS */
1972 propid = DSPROPERTY_EAXLISTENER_ALLPARAMETERS;
1973 pPropData = (void*)&This->eax_prop;
1974 cbPropData = sizeof(This->eax_prop);
1975 goto do_allparams;
1978 break;
1979 case DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION:
1980 res = DSERR_INVALIDPARAM;
1981 if(cbPropData >= sizeof(FLOAT))
1983 union {
1984 const void *v;
1985 const FLOAT *fl;
1986 } data = { pPropData };
1988 This->eax_prop.flEnvironmentDiffusion = *data.fl;
1989 This->ExtAL->Effectf(This->effect, AL_REVERB_DIFFUSION,
1990 This->eax_prop.flEnvironmentDiffusion);
1991 checkALError();
1993 This->dirty.bit.effect = 1;
1994 res = DS_OK;
1996 break;
1998 case DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF:
1999 res = DSERR_INVALIDPARAM;
2000 if(cbPropData >= sizeof(FLOAT))
2002 union {
2003 const void *v;
2004 const FLOAT *fl;
2005 } data = { pPropData };
2007 This->eax_prop.flAirAbsorptionHF = *data.fl;
2008 This->ExtAL->Effectf(This->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
2009 mB_to_gain(This->eax_prop.flAirAbsorptionHF));
2010 checkALError();
2012 This->dirty.bit.effect = 1;
2013 res = DS_OK;
2015 break;
2017 case DSPROPERTY_EAXLISTENER_FLAGS:
2018 res = DSERR_INVALIDPARAM;
2019 if(cbPropData >= sizeof(DWORD))
2021 union {
2022 const void *v;
2023 const DWORD *dw;
2024 } data = { pPropData };
2026 This->eax_prop.dwFlags = *data.dw;
2027 This->ExtAL->Effecti(This->effect, AL_REVERB_DECAY_HFLIMIT,
2028 (This->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
2029 AL_TRUE : AL_FALSE);
2030 checkALError();
2032 This->dirty.bit.effect = 1;
2033 res = DS_OK;
2035 break;
2037 default:
2038 FIXME("Unhandled propid: 0x%08"LONGFMT"x\n", propid);
2039 break;
2042 if(res == DS_OK && immediate)
2043 IDirectSound3DListener_CommitDeferredSettings(&This->IDirectSound3DListener_iface);
2045 popALContext();
2046 LeaveCriticalSection(This->crst);
2048 else
2049 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2051 return res;
2054 static HRESULT WINAPI DS8PrimaryProp_QuerySupport(IKsPropertySet *iface,
2055 REFGUID guidPropSet, ULONG dwPropID,
2056 PULONG pTypeSupport)
2058 DS8Primary *This = impl_from_IKsPropertySet(iface);
2059 HRESULT res = E_PROP_ID_UNSUPPORTED;
2061 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
2063 EnterCriticalSection(This->crst);
2065 if(This->effect == 0)
2066 res = E_PROP_ID_UNSUPPORTED;
2067 else if(dwPropID == DSPROPERTY_EAXLISTENER_ALLPARAMETERS ||
2068 dwPropID == DSPROPERTY_EAXLISTENER_ROOM ||
2069 dwPropID == DSPROPERTY_EAXLISTENER_ROOMHF ||
2070 dwPropID == DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR ||
2071 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENT ||
2072 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE ||
2073 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION ||
2074 dwPropID == DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF ||
2075 dwPropID == DSPROPERTY_EAXLISTENER_FLAGS)
2077 *pTypeSupport = KSPROPERTY_SUPPORT_GET|KSPROPERTY_SUPPORT_SET;
2078 res = DS_OK;
2080 else
2081 FIXME("Unhandled propid: 0x%08"LONGFMT"x\n", dwPropID);
2083 LeaveCriticalSection(This->crst);
2085 else
2086 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2088 return res;
2091 static const IKsPropertySetVtbl DS8PrimaryProp_Vtbl =
2093 DS8PrimaryProp_QueryInterface,
2094 DS8PrimaryProp_AddRef,
2095 DS8PrimaryProp_Release,
2096 DS8PrimaryProp_Get,
2097 DS8PrimaryProp_Set,
2098 DS8PrimaryProp_QuerySupport