Improve the name of a couple member variables
[dsound-openal.git] / primary.c
blob031e83cf7fe72a118d54b957c66faf2004ad538d
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"
33 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
34 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
36 #ifndef E_PROP_ID_UNSUPPORTED
37 #define E_PROP_ID_UNSUPPORTED ((HRESULT)0x80070490)
38 #endif
41 static const IDirectSoundBufferVtbl DS8Primary_Vtbl;
42 static const IDirectSound3DListenerVtbl DS8Primary3D_Vtbl;
43 static const IKsPropertySetVtbl DS8PrimaryProp_Vtbl;
45 static void DS8Primary_SetParams(DS8Primary *This, const DS3DLISTENER *params, LONG flags);
48 static inline DS8Primary *impl_from_IDirectSoundBuffer(IDirectSoundBuffer *iface)
50 return CONTAINING_RECORD(iface, DS8Primary, IDirectSoundBuffer_iface);
53 static inline DS8Primary *impl_from_IDirectSound3DListener(IDirectSound3DListener *iface)
55 return CONTAINING_RECORD(iface, DS8Primary, IDirectSound3DListener_iface);
58 static inline DS8Primary *impl_from_IKsPropertySet(IKsPropertySet *iface)
60 return CONTAINING_RECORD(iface, DS8Primary, IKsPropertySet_iface);
64 static void trigger_elapsed_notifies(DS8Buffer *buf, DWORD lastpos, DWORD curpos)
66 DSBPOSITIONNOTIFY *not = buf->notify;
67 DSBPOSITIONNOTIFY *not_end = not + buf->nnotify;
68 for(;not != not_end;++not)
70 HANDLE event = not->hEventNotify;
71 DWORD ofs = not->dwOffset;
73 if(ofs == (DWORD)DSBPN_OFFSETSTOP)
74 continue;
76 if(curpos < lastpos) /* Wraparound case */
78 if(ofs < curpos || ofs >= lastpos)
80 TRACE("Triggering notification %d from buffer %p\n", not - buf->notify, buf);
81 SetEvent(event);
84 else if(ofs >= lastpos && ofs < curpos) /* Normal case */
86 TRACE("Triggering notification %d from buffer %p\n", not - buf->notify, buf);
87 SetEvent(event);
92 static void trigger_stop_notifies(DS8Buffer *buf)
94 DSBPOSITIONNOTIFY *not = buf->notify;
95 DSBPOSITIONNOTIFY *not_end = not + buf->nnotify;
96 for(;not != not_end;++not)
98 if(not->dwOffset != (DWORD)DSBPN_OFFSETSTOP)
99 continue;
100 TRACE("Triggering notification %d from buffer %p\n", not - buf->notify, buf);
101 SetEvent(not->hEventNotify);
105 void DS8Primary_triggernots(DS8Primary *prim)
107 DS8Buffer **curnot, **endnot;
109 curnot = prim->notifies;
110 endnot = curnot + prim->nnotifies;
111 while(curnot != endnot)
113 DS8Buffer *buf = *curnot;
114 DS8Data *data = buf->buffer;
115 DWORD curpos = buf->lastpos;
116 ALint state = 0;
117 ALint ofs;
119 alGetSourcei(buf->source, AL_BYTE_OFFSET, &ofs);
120 alGetSourcei(buf->source, AL_SOURCE_STATE, &state);
121 if(buf->segsize == 0)
122 curpos = (state == AL_STOPPED) ? data->buf_size : ofs;
123 else
125 if(state != AL_STOPPED)
126 curpos = ofs + buf->queue_base;
127 else
129 ALint queued;
130 alGetSourcei(buf->source, AL_BUFFERS_QUEUED, &queued);
131 curpos = buf->segsize*queued + buf->queue_base;
134 if(curpos >= (DWORD)data->buf_size)
136 if(buf->islooping)
137 curpos %= (DWORD)data->buf_size;
138 else if(buf->isplaying)
140 curpos = data->buf_size;
141 alSourceStop(buf->source);
142 alSourcei(buf->source, AL_BUFFER, 0);
143 buf->curidx = 0;
144 buf->isplaying = FALSE;
148 if(state != AL_PLAYING)
149 state = buf->isplaying ? AL_PLAYING : AL_PAUSED;
151 checkALError();
153 if(buf->lastpos != curpos)
155 trigger_elapsed_notifies(buf, buf->lastpos, curpos);
156 buf->lastpos = curpos;
158 if(state != AL_PLAYING)
160 /* Remove this buffer from list and put another at the current
161 * position; don't increment i
163 trigger_stop_notifies(buf);
164 *curnot = *(--endnot);
165 prim->nnotifies--;
166 continue;
168 curnot++;
170 checkALError();
173 static void do_buffer_stream(DS8Buffer *buf, BYTE *scratch_mem)
175 DS8Data *data = buf->buffer;
176 ALint ofs, done = 0, queued = QBUFFERS, state = AL_PLAYING;
177 ALuint which;
179 alGetSourcei(buf->source, AL_BUFFERS_QUEUED, &queued);
180 alGetSourcei(buf->source, AL_SOURCE_STATE, &state);
181 alGetSourcei(buf->source, AL_BUFFERS_PROCESSED, &done);
183 if(done > 0)
185 ALuint bids[QBUFFERS];
186 queued -= done;
188 alSourceUnqueueBuffers(buf->source, done, bids);
189 buf->queue_base = (buf->queue_base + buf->segsize*done) % data->buf_size;
191 while(queued < QBUFFERS)
193 which = buf->stream_bids[buf->curidx];
194 ofs = buf->data_offset;
196 if(buf->segsize < data->buf_size - ofs)
198 alBufferData(which, data->buf_format, data->data + ofs, buf->segsize,
199 data->format.Format.nSamplesPerSec);
200 buf->data_offset = ofs + buf->segsize;
202 else if(buf->islooping)
204 ALsizei rem = data->buf_size - ofs;
205 if(rem > 2048) rem = 2048;
207 memcpy(scratch_mem, data->data + ofs, rem);
208 while(rem < buf->segsize)
210 ALsizei todo = buf->segsize - rem;
211 if(todo > data->buf_size)
212 todo = data->buf_size;
213 memcpy(scratch_mem + rem, data->data, todo);
214 rem += todo;
216 alBufferData(which, data->buf_format, scratch_mem, buf->segsize,
217 data->format.Format.nSamplesPerSec);
218 buf->data_offset = (ofs+buf->segsize) % data->buf_size;
220 else
222 ALsizei rem = data->buf_size - ofs;
223 if(rem > 2048) rem = 2048;
224 if(rem == 0) break;
226 memcpy(scratch_mem, data->data + ofs, rem);
227 memset(scratch_mem+rem, (data->format.Format.wBitsPerSample==8) ? 128 : 0,
228 buf->segsize - rem);
229 alBufferData(which, data->buf_format, scratch_mem, buf->segsize,
230 data->format.Format.nSamplesPerSec);
231 buf->data_offset = data->buf_size;
234 alSourceQueueBuffers(buf->source, 1, &which);
235 buf->curidx = (buf->curidx+1)%QBUFFERS;
236 queued++;
239 if(!queued)
241 buf->data_offset = 0;
242 buf->queue_base = data->buf_size;
243 buf->curidx = 0;
244 buf->isplaying = FALSE;
246 else if(state != AL_PLAYING)
247 alSourcePlay(buf->source);
250 void DS8Primary_streamfeeder(DS8Primary *prim, BYTE *scratch_mem)
252 /* OpenAL doesn't support our lovely buffer extensions so just make sure
253 * enough buffers are queued for streaming
255 if(prim->write_emu)
257 DS8Buffer *buf = &prim->writable_buf;
258 if(buf->segsize != 0 && buf->isplaying)
259 do_buffer_stream(buf, scratch_mem);
261 else
263 struct DSBufferGroup *bufgroup = prim->BufferGroups;
264 struct DSBufferGroup *endgroup = bufgroup + prim->NumBufferGroups;
265 for(;bufgroup != endgroup;++bufgroup)
267 DWORD64 usemask = ~bufgroup->FreeBuffers;
268 while(usemask)
270 int idx = CTZ64(usemask);
271 DS8Buffer *buf = bufgroup->Buffers + idx;
272 usemask &= ~(U64(1) << idx);
274 if(buf->segsize != 0 && buf->isplaying)
275 do_buffer_stream(buf, scratch_mem);
279 checkALError();
283 HRESULT DS8Primary_PreInit(DS8Primary *This, DS8Impl *parent)
285 WAVEFORMATEX *wfx;
286 DWORD num_srcs;
287 DWORD count;
288 HRESULT hr;
289 DWORD i;
291 This->IDirectSoundBuffer_iface.lpVtbl = &DS8Primary_Vtbl;
292 This->IDirectSound3DListener_iface.lpVtbl = &DS8Primary3D_Vtbl;
293 This->IKsPropertySet_iface.lpVtbl = &DS8PrimaryProp_Vtbl;
295 This->parent = parent;
296 This->crst = &parent->share->crst;
297 This->ctx = parent->share->ctx;
298 This->refresh = parent->share->refresh;
299 This->Exts = parent->share->Exts;
300 This->sources = &parent->share->sources;
301 This->auxslot = parent->share->auxslot;
303 wfx = &This->format.Format;
304 wfx->wFormatTag = WAVE_FORMAT_PCM;
305 wfx->nChannels = 2;
306 wfx->wBitsPerSample = 8;
307 wfx->nSamplesPerSec = 22050;
308 wfx->nBlockAlign = wfx->wBitsPerSample * wfx->nChannels / 8;
309 wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
310 wfx->cbSize = 0;
312 This->stopped = TRUE;
314 /* Apparently primary buffer size is always 32k,
315 * tested on windows with 192k 24 bits sound @ 6 channels
316 * where it will run out in 60 ms and it isn't pointer aligned
318 This->buf_size = 32768;
320 setALContext(This->ctx);
321 This->deferred.eax = EnvironmentDefaults[EAX_ENVIRONMENT_GENERIC];
322 This->deferred.eax1_dampening = 0.5f;
323 if(This->auxslot != 0)
325 ALint revid = alGetEnumValue("AL_EFFECT_REVERB");
326 if(revid != 0 && revid != -1)
328 alGenEffects(1, &This->effect);
329 alEffecti(This->effect, AL_EFFECT_TYPE, AL_EFFECT_REVERB);
330 checkALError();
333 popALContext();
335 num_srcs = This->sources->max_alloc;
337 hr = DSERR_OUTOFMEMORY;
338 This->notifies = HeapAlloc(GetProcessHeap(), 0, num_srcs*sizeof(*This->notifies));
339 if(!This->notifies) goto fail;
340 This->sizenotifies = num_srcs;
342 count = (num_srcs+63) / 64;
343 This->BufferGroups = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
344 count*sizeof(*This->BufferGroups));
345 if(!This->BufferGroups) goto fail;
346 This->NumBufferGroups = count;
348 /* Only flag usable buffers as free. */
349 count = 0;
350 for(i = 0;i < This->NumBufferGroups;++i)
352 DWORD count_rem = num_srcs - count;
353 if(count_rem >= 64)
355 This->BufferGroups[i].FreeBuffers = ~(DWORD64)0;
356 count += 64;
358 else
360 This->BufferGroups[i].FreeBuffers = (U64(1) << count_rem) - 1;
361 count += count_rem;
365 return S_OK;
367 fail:
368 DS8Primary_Clear(This);
369 return hr;
372 void DS8Primary_Clear(DS8Primary *This)
374 struct DSBufferGroup *bufgroup;
375 DWORD i;
377 TRACE("Clearing primary %p\n", This);
379 if(!This->parent)
380 return;
382 setALContext(This->ctx);
383 if(This->effect)
384 alDeleteEffects(1, &This->effect);
385 popALContext();
387 bufgroup = This->BufferGroups;
388 for(i = 0;i < This->NumBufferGroups;++i)
390 DWORD64 usemask = ~bufgroup[i].FreeBuffers;
391 while(usemask)
393 int idx = CTZ64(usemask);
394 DS8Buffer *buf = bufgroup[i].Buffers + idx;
395 usemask &= ~(U64(1) << idx);
397 DS8Buffer_Destroy(buf);
401 HeapFree(GetProcessHeap(), 0, This->BufferGroups);
402 HeapFree(GetProcessHeap(), 0, This->notifies);
403 memset(This, 0, sizeof(*This));
406 static HRESULT WINAPI DS8Primary_QueryInterface(IDirectSoundBuffer *iface, REFIID riid, LPVOID *ppv)
408 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
410 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
412 *ppv = NULL;
413 if(IsEqualIID(riid, &IID_IUnknown) ||
414 IsEqualIID(riid, &IID_IDirectSoundBuffer))
415 *ppv = &This->IDirectSoundBuffer_iface;
416 else if(IsEqualIID(riid, &IID_IDirectSound3DListener))
418 if((This->flags&DSBCAPS_CTRL3D))
419 *ppv = &This->IDirectSound3DListener_iface;
421 else if(IsEqualIID(riid, &IID_IKsPropertySet))
422 *ppv = &This->IKsPropertySet_iface;
423 else
424 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
426 if(*ppv)
428 IUnknown_AddRef((IUnknown*)*ppv);
429 return S_OK;
432 return E_NOINTERFACE;
435 static ULONG WINAPI DS8Primary_AddRef(IDirectSoundBuffer *iface)
437 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
438 LONG ret;
440 ret = InterlockedIncrement(&This->ref);
441 if(ret == 1) This->flags = 0;
443 return ret;
446 static ULONG WINAPI DS8Primary_Release(IDirectSoundBuffer *iface)
448 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
449 LONG ref, oldval;
451 oldval = *(volatile LONG*)&This->ref;
452 do {
453 ref = oldval;
454 if(!ref) return 0;
455 oldval = InterlockedCompareExchange(&This->ref, ref-1, ref);
456 } while(oldval != ref);
458 return ref-1;
461 static HRESULT WINAPI DS8Primary_GetCaps(IDirectSoundBuffer *iface, DSBCAPS *caps)
463 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
465 TRACE("(%p)->(%p)\n", iface, caps);
467 if(!caps || caps->dwSize < sizeof(*caps))
469 WARN("Invalid DSBCAPS (%p, %lu)\n", caps, caps ? caps->dwSize : 0);
470 return DSERR_INVALIDPARAM;
473 caps->dwFlags = This->flags;
474 caps->dwBufferBytes = This->buf_size;
475 caps->dwUnlockTransferRate = 0;
476 caps->dwPlayCpuOverhead = 0;
478 return DS_OK;
481 static HRESULT WINAPI DS8Primary_GetCurrentPosition(IDirectSoundBuffer *iface, DWORD *playpos, DWORD *curpos)
483 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
484 HRESULT hr = DSERR_PRIOLEVELNEEDED;
486 EnterCriticalSection(This->crst);
487 if(This->write_emu)
488 hr = IDirectSoundBuffer8_GetCurrentPosition(This->write_emu, playpos, curpos);
489 LeaveCriticalSection(This->crst);
491 return hr;
494 static HRESULT WINAPI DS8Primary_GetFormat(IDirectSoundBuffer *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
496 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
497 HRESULT hr = S_OK;
498 UINT size;
500 if(!wfx && !written)
502 WARN("Cannot report format or format size\n");
503 return DSERR_INVALIDPARAM;
506 EnterCriticalSection(This->crst);
507 size = sizeof(This->format.Format) + This->format.Format.cbSize;
508 if(written)
509 *written = size;
510 if(wfx)
512 if(allocated < size)
513 hr = DSERR_INVALIDPARAM;
514 else
515 memcpy(wfx, &This->format.Format, size);
517 LeaveCriticalSection(This->crst);
519 return hr;
522 static HRESULT WINAPI DS8Primary_GetVolume(IDirectSoundBuffer *iface, LONG *volume)
524 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
525 ALfloat gain;
527 TRACE("(%p)->(%p)\n", iface, volume);
529 if(!volume)
530 return DSERR_INVALIDPARAM;
531 *volume = 0;
533 if(!(This->flags&DSBCAPS_CTRLVOLUME))
534 return DSERR_CONTROLUNAVAIL;
536 setALContext(This->ctx);
537 alGetListenerf(AL_GAIN, &gain);
538 checkALError();
539 popALContext();
541 *volume = clampI(gain_to_mB(gain), DSBVOLUME_MIN, DSBVOLUME_MAX);
542 return DS_OK;
545 static HRESULT WINAPI DS8Primary_GetPan(IDirectSoundBuffer *iface, LONG *pan)
547 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
548 HRESULT hr = DS_OK;
550 WARN("(%p)->(%p): semi-stub\n", iface, pan);
552 if(!pan)
553 return DSERR_INVALIDPARAM;
555 EnterCriticalSection(This->crst);
556 if(This->write_emu)
557 hr = IDirectSoundBuffer8_GetPan(This->write_emu, pan);
558 else if(!(This->flags & DSBCAPS_CTRLPAN))
559 hr = DSERR_CONTROLUNAVAIL;
560 else
561 *pan = 0;
562 LeaveCriticalSection(This->crst);
564 return hr;
567 static HRESULT WINAPI DS8Primary_GetFrequency(IDirectSoundBuffer *iface, DWORD *freq)
569 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
570 HRESULT hr = DS_OK;
572 WARN("(%p)->(%p): semi-stub\n", iface, freq);
574 if(!freq)
575 return DSERR_INVALIDPARAM;
577 if(!(This->flags&DSBCAPS_CTRLFREQUENCY))
578 return DSERR_CONTROLUNAVAIL;
580 EnterCriticalSection(This->crst);
581 *freq = This->format.Format.nSamplesPerSec;
582 LeaveCriticalSection(This->crst);
584 return hr;
587 static HRESULT WINAPI DS8Primary_GetStatus(IDirectSoundBuffer *iface, DWORD *status)
589 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
591 TRACE("(%p)->(%p)\n", iface, status);
593 if(!status)
594 return DSERR_INVALIDPARAM;
596 EnterCriticalSection(This->crst);
597 *status = DSBSTATUS_PLAYING|DSBSTATUS_LOOPING;
598 if((This->flags&DSBCAPS_LOCDEFER))
599 *status |= DSBSTATUS_LOCHARDWARE;
601 if(This->stopped)
603 struct DSBufferGroup *bufgroup = This->BufferGroups;
604 DWORD i, state = 0;
605 HRESULT hr;
607 for(i = 0;i < This->NumBufferGroups;++i)
609 DWORD64 usemask = ~bufgroup[i].FreeBuffers;
610 while(usemask)
612 int idx = CTZ64(usemask);
613 DS8Buffer *buf = bufgroup[i].Buffers + idx;
614 usemask &= ~(U64(1) << idx);
616 hr = DS8Buffer_GetStatus(&buf->IDirectSoundBuffer8_iface, &state);
617 if(SUCCEEDED(hr) && (state&DSBSTATUS_PLAYING)) break;
620 if(!(state&DSBSTATUS_PLAYING))
622 /* Primary stopped and no buffers playing.. */
623 *status = 0;
626 LeaveCriticalSection(This->crst);
628 return DS_OK;
631 HRESULT WINAPI DS8Primary_Initialize(IDirectSoundBuffer *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
633 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
634 HRESULT hr;
636 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
638 if(!desc || desc->lpwfxFormat || desc->dwBufferBytes)
640 WARN("Bad DSBDESC for primary buffer\n");
641 return DSERR_INVALIDPARAM;
643 if((desc->dwFlags&DSBCAPS_CTRLFX) ||
644 (desc->dwFlags&DSBCAPS_CTRLPOSITIONNOTIFY) ||
645 (desc->dwFlags&DSBCAPS_LOCSOFTWARE))
647 WARN("Bad dwFlags %08lx\n", desc->dwFlags);
648 return DSERR_INVALIDPARAM;
651 /* Should be 0 if not initialized */
652 if(This->flags)
653 return DSERR_ALREADYINITIALIZED;
655 hr = DS_OK;
656 if(This->parent->prio_level == DSSCL_WRITEPRIMARY)
658 DSBUFFERDESC emudesc;
659 DS8Buffer *emu;
661 if(This->write_emu)
663 ERR("There shouldn't be a write_emu!\n");
664 IDirectSoundBuffer8_Release(This->write_emu);
665 This->write_emu = NULL;
668 memset(&emudesc, 0, sizeof(emudesc));
669 emudesc.dwSize = sizeof(emudesc);
670 emudesc.dwFlags = DSBCAPS_LOCHARDWARE | (desc->dwFlags&DSBCAPS_CTRLPAN);
671 /* Dont play last incomplete sample */
672 emudesc.dwBufferBytes = This->buf_size - (This->buf_size%This->format.Format.nBlockAlign);
673 emudesc.lpwfxFormat = &This->format.Format;
675 hr = DS8Buffer_Create(&emu, This, NULL, TRUE);
676 if(SUCCEEDED(hr))
678 This->write_emu = &emu->IDirectSoundBuffer8_iface;
679 hr = DS8Buffer_Initialize(This->write_emu, ds, &emudesc);
680 if(FAILED(hr))
682 IDirectSoundBuffer8_Release(This->write_emu);
683 This->write_emu = NULL;
688 if(SUCCEEDED(hr))
690 DS3DLISTENER *listener = &This->deferred.ds3d;
691 listener->dwSize = sizeof(This->deferred.ds3d);
692 listener->vPosition.x = 0.0f;
693 listener->vPosition.y = 0.0f;
694 listener->vPosition.z = 0.0f;
695 listener->vVelocity.x = 0.0f;
696 listener->vVelocity.y = 0.0f;
697 listener->vVelocity.z = 0.0f;
698 listener->vOrientFront.x = 0.0f;
699 listener->vOrientFront.y = 0.0f;
700 listener->vOrientFront.z = 1.0f;
701 listener->vOrientTop.x = 0.0f;
702 listener->vOrientTop.y = 1.0f;
703 listener->vOrientTop.z = 0.0f;
704 listener->flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
705 listener->flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
706 listener->flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
708 This->flags = desc->dwFlags | DSBCAPS_LOCHARDWARE;
710 if((This->flags&DSBCAPS_CTRL3D))
712 union PrimaryParamFlags dirty = { 0l };
714 dirty.bit.pos = 1;
715 dirty.bit.vel = 1;
716 dirty.bit.orientation = 1;
717 dirty.bit.distancefactor = 1;
718 dirty.bit.rollofffactor = 1;
719 dirty.bit.dopplerfactor = 1;
720 DS8Primary_SetParams(This, listener, dirty.flags);
723 return hr;
726 static HRESULT WINAPI DS8Primary_Lock(IDirectSoundBuffer *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
728 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
729 HRESULT hr = DSERR_PRIOLEVELNEEDED;
731 TRACE("(%p)->(%lu, %lu, %p, %p, %p, %p, %lu)\n", iface, ofs, bytes, ptr1, len1, ptr2, len2, flags);
733 EnterCriticalSection(This->crst);
734 if(This->write_emu)
735 hr = IDirectSoundBuffer8_Lock(This->write_emu, ofs, bytes, ptr1, len1, ptr2, len2, flags);
736 LeaveCriticalSection(This->crst);
738 return hr;
741 static HRESULT WINAPI DS8Primary_Play(IDirectSoundBuffer *iface, DWORD res1, DWORD res2, DWORD flags)
743 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
744 HRESULT hr;
746 TRACE("(%p)->(%lu, %lu, %lu)\n", iface, res1, res2, flags);
748 if(!(flags & DSBPLAY_LOOPING))
750 WARN("Flags (%08lx) not set to DSBPLAY_LOOPING\n", flags);
751 return DSERR_INVALIDPARAM;
754 EnterCriticalSection(This->crst);
755 hr = S_OK;
756 if(This->write_emu)
757 hr = IDirectSoundBuffer8_Play(This->write_emu, res1, res2, flags);
758 if(SUCCEEDED(hr))
759 This->stopped = FALSE;
760 LeaveCriticalSection(This->crst);
762 return hr;
765 static HRESULT WINAPI DS8Primary_SetCurrentPosition(IDirectSoundBuffer *iface, DWORD pos)
767 WARN("(%p)->(%lu)\n", iface, pos);
768 return DSERR_INVALIDCALL;
771 /* Just assume the format is crap, and clean up the damage */
772 static HRESULT copy_waveformat(WAVEFORMATEX *wfx, const WAVEFORMATEX *from)
774 if(from->nChannels <= 0)
776 WARN("Invalid Channels %d\n", from->nChannels);
777 return DSERR_INVALIDPARAM;
779 if(from->nSamplesPerSec < DSBFREQUENCY_MIN || from->nSamplesPerSec > DSBFREQUENCY_MAX)
781 WARN("Invalid SamplesPerSec %lu\n", from->nSamplesPerSec);
782 return DSERR_INVALIDPARAM;
784 if(from->nBlockAlign <= 0)
786 WARN("Invalid BlockAlign %d\n", from->nBlockAlign);
787 return DSERR_INVALIDPARAM;
789 if(from->wBitsPerSample == 0 || (from->wBitsPerSample%8) != 0)
791 WARN("Invalid BitsPerSample %d\n", from->wBitsPerSample);
792 return DSERR_INVALIDPARAM;
794 if(from->nBlockAlign != from->nChannels*from->wBitsPerSample/8)
796 WARN("Invalid BlockAlign %d (expected %u = %u*%u/8)\n",
797 from->nBlockAlign, from->nChannels*from->wBitsPerSample/8,
798 from->nChannels, from->wBitsPerSample);
799 return DSERR_INVALIDPARAM;
801 if(from->nAvgBytesPerSec != from->nBlockAlign*from->nSamplesPerSec)
803 WARN("Invalid AvgBytesPerSec %lu (expected %lu = %lu*%u)\n",
804 from->nAvgBytesPerSec, from->nSamplesPerSec*from->nBlockAlign,
805 from->nSamplesPerSec, from->nBlockAlign);
806 return DSERR_INVALIDPARAM;
809 if(from->wFormatTag == WAVE_FORMAT_PCM)
811 if(from->wBitsPerSample > 32)
812 return DSERR_INVALIDPARAM;
813 wfx->cbSize = 0;
815 else if(from->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
817 if(from->wBitsPerSample != 32)
818 return DSERR_INVALIDPARAM;
819 wfx->cbSize = 0;
821 else if(from->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
823 WAVEFORMATEXTENSIBLE *wfe = (WAVEFORMATEXTENSIBLE*)wfx;
824 const WAVEFORMATEXTENSIBLE *fromx = (const WAVEFORMATEXTENSIBLE*)from;
825 const WORD size = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
827 /* Fail silently.. */
828 if(from->cbSize < size) return DS_OK;
829 if(fromx->Samples.wValidBitsPerSample > fromx->Format.wBitsPerSample)
830 return DSERR_INVALIDPARAM;
832 if(IsEqualGUID(&fromx->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
834 if(from->wBitsPerSample > 32)
835 return DSERR_INVALIDPARAM;
837 else if(IsEqualGUID(&fromx->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
839 if(from->wBitsPerSample != 32)
840 return DSERR_INVALIDPARAM;
842 else
844 ERR("Unhandled extensible format: %s\n", debugstr_guid(&fromx->SubFormat));
845 return DSERR_INVALIDPARAM;
848 wfe->Format.cbSize = size;
849 wfe->Samples.wValidBitsPerSample = fromx->Samples.wValidBitsPerSample;
850 if(!wfe->Samples.wValidBitsPerSample)
851 wfe->Samples.wValidBitsPerSample = fromx->Format.wBitsPerSample;
852 wfe->dwChannelMask = fromx->dwChannelMask;
853 wfe->SubFormat = fromx->SubFormat;
855 else
857 ERR("Unhandled format tag %04x\n", from->wFormatTag);
858 return DSERR_INVALIDPARAM;
861 wfx->wFormatTag = from->wFormatTag;
862 wfx->nChannels = from->nChannels;
863 wfx->nSamplesPerSec = from->nSamplesPerSec;
864 wfx->nAvgBytesPerSec = from->nSamplesPerSec * from->nBlockAlign;
865 wfx->nBlockAlign = from->wBitsPerSample * from->nChannels / 8;
866 wfx->wBitsPerSample = from->wBitsPerSample;
867 return DS_OK;
870 static HRESULT WINAPI DS8Primary_SetFormat(IDirectSoundBuffer *iface, const WAVEFORMATEX *wfx)
872 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
873 HRESULT hr = S_OK;
875 TRACE("(%p)->(%p)\n", iface, wfx);
877 if(!wfx)
879 WARN("Missing format\n");
880 return DSERR_INVALIDPARAM;
883 EnterCriticalSection(This->crst);
885 if(This->parent->prio_level < DSSCL_PRIORITY)
887 hr = DSERR_PRIOLEVELNEEDED;
888 goto out;
891 TRACE("Requested primary format:\n"
892 " FormatTag = %04x\n"
893 " Channels = %u\n"
894 " SamplesPerSec = %lu\n"
895 " AvgBytesPerSec = %lu\n"
896 " BlockAlign = %u\n"
897 " BitsPerSample = %u\n",
898 wfx->wFormatTag, wfx->nChannels,
899 wfx->nSamplesPerSec, wfx->nAvgBytesPerSec,
900 wfx->nBlockAlign, wfx->wBitsPerSample);
902 hr = copy_waveformat(&This->format.Format, wfx);
903 if(SUCCEEDED(hr) && This->write_emu)
905 DS8Buffer *buf;
906 DSBUFFERDESC desc;
908 IDirectSoundBuffer8_Release(This->write_emu);
909 This->write_emu = NULL;
911 memset(&desc, 0, sizeof(desc));
912 desc.dwSize = sizeof(desc);
913 desc.dwFlags = DSBCAPS_LOCHARDWARE|DSBCAPS_CTRLPAN;
914 desc.dwBufferBytes = This->buf_size - (This->buf_size % This->format.Format.nBlockAlign);
915 desc.lpwfxFormat = &This->format.Format;
917 hr = DS8Buffer_Create(&buf, This, NULL, TRUE);
918 if(FAILED(hr)) goto out;
920 This->write_emu = &buf->IDirectSoundBuffer8_iface;
921 hr = DS8Buffer_Initialize(This->write_emu, &This->parent->IDirectSound_iface, &desc);
922 if(FAILED(hr))
924 IDirectSoundBuffer8_Release(This->write_emu);
925 This->write_emu = NULL;
929 out:
930 LeaveCriticalSection(This->crst);
931 return hr;
934 static HRESULT WINAPI DS8Primary_SetVolume(IDirectSoundBuffer *iface, LONG vol)
936 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
938 TRACE("(%p)->(%ld)\n", iface, vol);
940 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
942 WARN("Invalid volume (%ld)\n", vol);
943 return DSERR_INVALIDPARAM;
946 if(!(This->flags&DSBCAPS_CTRLVOLUME))
947 return DSERR_CONTROLUNAVAIL;
949 setALContext(This->ctx);
950 alListenerf(AL_GAIN, mB_to_gain(vol));
951 popALContext();
953 return DS_OK;
956 static HRESULT WINAPI DS8Primary_SetPan(IDirectSoundBuffer *iface, LONG pan)
958 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
959 HRESULT hr;
961 TRACE("(%p)->(%ld)\n", iface, pan);
963 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
965 WARN("invalid parameter: pan = %ld\n", pan);
966 return DSERR_INVALIDPARAM;
969 EnterCriticalSection(This->crst);
970 if(!(This->flags&DSBCAPS_CTRLPAN))
972 WARN("control unavailable\n");
973 hr = DSERR_CONTROLUNAVAIL;
975 else if(This->write_emu)
976 hr = IDirectSoundBuffer8_SetPan(This->write_emu, pan);
977 else
979 FIXME("Not supported\n");
980 hr = E_NOTIMPL;
982 LeaveCriticalSection(This->crst);
984 return hr;
987 static HRESULT WINAPI DS8Primary_SetFrequency(IDirectSoundBuffer *iface, DWORD freq)
989 WARN("(%p)->(%lu)\n", iface, freq);
990 return DSERR_CONTROLUNAVAIL;
993 static HRESULT WINAPI DS8Primary_Stop(IDirectSoundBuffer *iface)
995 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
996 HRESULT hr = S_OK;
998 TRACE("(%p)->()\n", iface);
1000 EnterCriticalSection(This->crst);
1001 if(This->write_emu)
1002 hr = IDirectSoundBuffer8_Stop(This->write_emu);
1003 if(SUCCEEDED(hr))
1004 This->stopped = TRUE;
1005 LeaveCriticalSection(This->crst);
1007 return hr;
1010 static HRESULT WINAPI DS8Primary_Unlock(IDirectSoundBuffer *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
1012 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
1013 HRESULT hr = DSERR_INVALIDCALL;
1015 TRACE("(%p)->(%p, %lu, %p, %lu)\n", iface, ptr1, len1, ptr2, len2);
1017 EnterCriticalSection(This->crst);
1018 if(This->write_emu)
1019 hr = IDirectSoundBuffer8_Unlock(This->write_emu, ptr1, len1, ptr2, len2);
1020 LeaveCriticalSection(This->crst);
1022 return hr;
1025 static HRESULT WINAPI DS8Primary_Restore(IDirectSoundBuffer *iface)
1027 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
1028 HRESULT hr = S_OK;
1030 TRACE("(%p)->()\n", iface);
1032 EnterCriticalSection(This->crst);
1033 if(This->write_emu)
1034 hr = IDirectSoundBuffer8_Restore(This->write_emu);
1035 LeaveCriticalSection(This->crst);
1037 return hr;
1040 static const IDirectSoundBufferVtbl DS8Primary_Vtbl =
1042 DS8Primary_QueryInterface,
1043 DS8Primary_AddRef,
1044 DS8Primary_Release,
1045 DS8Primary_GetCaps,
1046 DS8Primary_GetCurrentPosition,
1047 DS8Primary_GetFormat,
1048 DS8Primary_GetVolume,
1049 DS8Primary_GetPan,
1050 DS8Primary_GetFrequency,
1051 DS8Primary_GetStatus,
1052 DS8Primary_Initialize,
1053 DS8Primary_Lock,
1054 DS8Primary_Play,
1055 DS8Primary_SetCurrentPosition,
1056 DS8Primary_SetFormat,
1057 DS8Primary_SetVolume,
1058 DS8Primary_SetPan,
1059 DS8Primary_SetFrequency,
1060 DS8Primary_Stop,
1061 DS8Primary_Unlock,
1062 DS8Primary_Restore
1066 static void DS8Primary_SetParams(DS8Primary *This, const DS3DLISTENER *params, LONG flags)
1068 union PrimaryParamFlags dirty = { flags };
1069 DWORD i;
1071 if(dirty.bit.pos)
1072 alListener3f(AL_POSITION, params->vPosition.x, params->vPosition.y,
1073 -params->vPosition.z);
1074 if(dirty.bit.vel)
1075 alListener3f(AL_VELOCITY, params->vVelocity.x, params->vVelocity.y,
1076 -params->vVelocity.z);
1077 if(dirty.bit.orientation)
1079 ALfloat orient[6] = {
1080 params->vOrientFront.x, params->vOrientFront.y, -params->vOrientFront.z,
1081 params->vOrientTop.x, params->vOrientTop.y, -params->vOrientTop.z
1083 alListenerfv(AL_ORIENTATION, orient);
1085 if(dirty.bit.distancefactor)
1087 alSpeedOfSound(343.3f/params->flDistanceFactor);
1088 if(BITFIELD_TEST(This->Exts, EXT_EFX))
1089 alListenerf(AL_METERS_PER_UNIT, params->flDistanceFactor);
1091 if(dirty.bit.rollofffactor)
1093 struct DSBufferGroup *bufgroup = This->BufferGroups;
1094 ALfloat rolloff = params->flRolloffFactor;
1095 This->rollofffactor = rolloff;
1097 for(i = 0;i < This->NumBufferGroups;++i)
1099 DWORD64 usemask = ~bufgroup[i].FreeBuffers;
1100 while(usemask)
1102 int idx = CTZ64(usemask);
1103 DS8Buffer *buf = bufgroup[i].Buffers + idx;
1104 usemask &= ~(U64(1) << idx);
1106 if(buf->ds3dmode != DS3DMODE_DISABLE)
1107 alSourcef(buf->source, AL_ROLLOFF_FACTOR, rolloff);
1111 if(dirty.bit.dopplerfactor)
1112 alDopplerFactor(params->flDopplerFactor);
1113 if(dirty.bit.effect)
1114 alAuxiliaryEffectSloti(This->auxslot, AL_EFFECTSLOT_EFFECT, This->effect);
1117 static HRESULT WINAPI DS8Primary3D_QueryInterface(IDirectSound3DListener *iface, REFIID riid, void **ppv)
1119 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1120 return DS8Primary_QueryInterface(&This->IDirectSoundBuffer_iface, riid, ppv);
1123 static ULONG WINAPI DS8Primary3D_AddRef(IDirectSound3DListener *iface)
1125 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1126 LONG ret;
1128 ret = InterlockedIncrement(&This->ds3d_ref);
1129 TRACE("new refcount %ld\n", ret);
1131 return ret;
1134 static ULONG WINAPI DS8Primary3D_Release(IDirectSound3DListener *iface)
1136 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1137 LONG ret;
1139 ret = InterlockedDecrement(&This->ds3d_ref);
1140 TRACE("new refcount %ld\n", ret);
1142 return ret;
1146 static HRESULT WINAPI DS8Primary3D_GetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE *distancefactor)
1148 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1150 TRACE("(%p)->(%p)\n", iface, distancefactor);
1152 if(!distancefactor)
1154 WARN("Invalid parameter %p\n", distancefactor);
1155 return DSERR_INVALIDPARAM;
1158 setALContext(This->ctx);
1159 *distancefactor = 343.3f/alGetFloat(AL_SPEED_OF_SOUND);
1160 checkALError();
1161 popALContext();
1163 return S_OK;
1166 static HRESULT WINAPI DS8Primary3D_GetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE *dopplerfactor)
1168 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1170 TRACE("(%p)->(%p)\n", iface, dopplerfactor);
1172 if(!dopplerfactor)
1174 WARN("Invalid parameter %p\n", dopplerfactor);
1175 return DSERR_INVALIDPARAM;
1178 setALContext(This->ctx);
1179 *dopplerfactor = alGetFloat(AL_DOPPLER_FACTOR);
1180 checkALError();
1181 popALContext();
1183 return S_OK;
1186 static HRESULT WINAPI DS8Primary3D_GetOrientation(IDirectSound3DListener *iface, D3DVECTOR *front, D3DVECTOR *top)
1188 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1189 ALfloat orient[6];
1191 TRACE("(%p)->(%p, %p)\n", iface, front, top);
1193 if(!front || !top)
1195 WARN("Invalid parameter %p %p\n", front, top);
1196 return DSERR_INVALIDPARAM;
1199 setALContext(This->ctx);
1200 alGetListenerfv(AL_ORIENTATION, orient);
1201 checkALError();
1202 popALContext();
1204 front->x = orient[0];
1205 front->y = orient[1];
1206 front->z = -orient[2];
1207 top->x = orient[3];
1208 top->y = orient[4];
1209 top->z = -orient[5];
1210 return S_OK;
1213 static HRESULT WINAPI DS8Primary3D_GetPosition(IDirectSound3DListener *iface, D3DVECTOR *pos)
1215 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1216 ALfloat alpos[3];
1218 TRACE("(%p)->(%p)\n", iface, pos);
1220 if(!pos)
1222 WARN("Invalid parameter %p\n", pos);
1223 return DSERR_INVALIDPARAM;
1226 setALContext(This->ctx);
1227 alGetListenerfv(AL_POSITION, alpos);
1228 checkALError();
1229 popALContext();
1231 pos->x = alpos[0];
1232 pos->y = alpos[1];
1233 pos->z = -alpos[2];
1234 return S_OK;
1237 static HRESULT WINAPI DS8Primary3D_GetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE *rollofffactor)
1239 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1241 TRACE("(%p)->(%p)\n", iface, rollofffactor);
1243 if(!rollofffactor)
1245 WARN("Invalid parameter %p\n", rollofffactor);
1246 return DSERR_INVALIDPARAM;
1249 EnterCriticalSection(This->crst);
1250 *rollofffactor = This->rollofffactor;
1251 LeaveCriticalSection(This->crst);
1253 return S_OK;
1256 static HRESULT WINAPI DS8Primary3D_GetVelocity(IDirectSound3DListener *iface, D3DVECTOR *velocity)
1258 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1259 ALfloat vel[3];
1261 TRACE("(%p)->(%p)\n", iface, velocity);
1263 if(!velocity)
1265 WARN("Invalid parameter %p\n", velocity);
1266 return DSERR_INVALIDPARAM;
1269 setALContext(This->ctx);
1270 alGetListenerfv(AL_VELOCITY, vel);
1271 checkALError();
1272 popALContext();
1274 velocity->x = vel[0];
1275 velocity->y = vel[1];
1276 velocity->z = -vel[2];
1277 return S_OK;
1280 static HRESULT WINAPI DS8Primary3D_GetAllParameters(IDirectSound3DListener *iface, DS3DLISTENER *listener)
1282 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1284 TRACE("(%p)->(%p)\n", iface, listener);
1286 if(!listener || listener->dwSize < sizeof(*listener))
1288 WARN("Invalid DS3DLISTENER %p %lu\n", listener, listener ? listener->dwSize : 0);
1289 return DSERR_INVALIDPARAM;
1292 EnterCriticalSection(This->crst);
1293 setALContext(This->ctx);
1294 DS8Primary3D_GetPosition(iface, &listener->vPosition);
1295 DS8Primary3D_GetVelocity(iface, &listener->vVelocity);
1296 DS8Primary3D_GetOrientation(iface, &listener->vOrientFront, &listener->vOrientTop);
1297 DS8Primary3D_GetDistanceFactor(iface, &listener->flDistanceFactor);
1298 DS8Primary3D_GetRolloffFactor(iface, &listener->flRolloffFactor);
1299 DS8Primary3D_GetDopplerFactor(iface, &listener->flDopplerFactor);
1300 popALContext();
1301 LeaveCriticalSection(This->crst);
1303 return DS_OK;
1307 static HRESULT WINAPI DS8Primary3D_SetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1309 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1311 TRACE("(%p)->(%f, %lu)\n", iface, factor, apply);
1313 if(factor < DS3D_MINDISTANCEFACTOR ||
1314 factor > DS3D_MAXDISTANCEFACTOR)
1316 WARN("Invalid parameter %f\n", factor);
1317 return DSERR_INVALIDPARAM;
1320 if(apply == DS3D_DEFERRED)
1322 EnterCriticalSection(This->crst);
1323 This->deferred.ds3d.flDistanceFactor = factor;
1324 This->dirty.bit.distancefactor = 1;
1325 LeaveCriticalSection(This->crst);
1327 else
1329 setALContext(This->ctx);
1330 alSpeedOfSound(343.3f/factor);
1331 if(BITFIELD_TEST(This->Exts, EXT_EFX))
1332 alListenerf(AL_METERS_PER_UNIT, factor);
1333 checkALError();
1334 popALContext();
1337 return S_OK;
1340 static HRESULT WINAPI DS8Primary3D_SetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1342 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1344 TRACE("(%p)->(%f, %lu)\n", iface, factor, apply);
1346 if(factor < DS3D_MINDOPPLERFACTOR ||
1347 factor > DS3D_MAXDOPPLERFACTOR)
1349 WARN("Invalid parameter %f\n", factor);
1350 return DSERR_INVALIDPARAM;
1353 if(apply == DS3D_DEFERRED)
1355 EnterCriticalSection(This->crst);
1356 This->deferred.ds3d.flDopplerFactor = factor;
1357 This->dirty.bit.dopplerfactor = 1;
1358 LeaveCriticalSection(This->crst);
1360 else
1362 setALContext(This->ctx);
1363 alDopplerFactor(factor);
1364 checkALError();
1365 popALContext();
1368 return S_OK;
1371 static HRESULT WINAPI DS8Primary3D_SetOrientation(IDirectSound3DListener *iface, D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront, D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop, DWORD apply)
1373 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1375 TRACE("(%p)->(%f, %f, %f, %f, %f, %f, %lu)\n", iface, xFront, yFront, zFront, xTop, yTop, zTop, apply);
1377 if(apply == DS3D_DEFERRED)
1379 EnterCriticalSection(This->crst);
1380 This->deferred.ds3d.vOrientFront.x = xFront;
1381 This->deferred.ds3d.vOrientFront.y = yFront;
1382 This->deferred.ds3d.vOrientFront.z = zFront;
1383 This->deferred.ds3d.vOrientTop.x = xTop;
1384 This->deferred.ds3d.vOrientTop.y = yTop;
1385 This->deferred.ds3d.vOrientTop.z = zTop;
1386 This->dirty.bit.orientation = 1;
1387 LeaveCriticalSection(This->crst);
1389 else
1391 ALfloat orient[6] = {
1392 xFront, yFront, -zFront,
1393 xTop, yTop, -zTop
1395 setALContext(This->ctx);
1396 alListenerfv(AL_ORIENTATION, orient);
1397 checkALError();
1398 popALContext();
1401 return S_OK;
1404 static HRESULT WINAPI DS8Primary3D_SetPosition(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1406 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1408 TRACE("(%p)->(%f, %f, %f, %lu)\n", iface, x, y, z, apply);
1410 if(apply == DS3D_DEFERRED)
1412 EnterCriticalSection(This->crst);
1413 This->deferred.ds3d.vPosition.x = x;
1414 This->deferred.ds3d.vPosition.y = y;
1415 This->deferred.ds3d.vPosition.z = z;
1416 This->dirty.bit.pos = 1;
1417 LeaveCriticalSection(This->crst);
1419 else
1421 setALContext(This->ctx);
1422 alListener3f(AL_POSITION, x, y, -z);
1423 checkALError();
1424 popALContext();
1427 return S_OK;
1430 static HRESULT WINAPI DS8Primary3D_SetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1432 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1434 TRACE("(%p)->(%f, %lu)\n", iface, factor, apply);
1436 if(factor < DS3D_MINROLLOFFFACTOR ||
1437 factor > DS3D_MAXROLLOFFFACTOR)
1439 WARN("Invalid parameter %f\n", factor);
1440 return DSERR_INVALIDPARAM;
1443 EnterCriticalSection(This->crst);
1444 if(apply == DS3D_DEFERRED)
1446 This->deferred.ds3d.flRolloffFactor = factor;
1447 This->dirty.bit.rollofffactor = 1;
1449 else
1451 struct DSBufferGroup *bufgroup = This->BufferGroups;
1452 DWORD i;
1454 This->rollofffactor = factor;
1456 setALContext(This->ctx);
1457 for(i = 0;i < This->NumBufferGroups;++i)
1459 DWORD64 usemask = ~bufgroup[i].FreeBuffers;
1460 while(usemask)
1462 int idx = CTZ64(usemask);
1463 DS8Buffer *buf = bufgroup[i].Buffers + idx;
1464 usemask &= ~(U64(1) << idx);
1466 if(buf->ds3dmode != DS3DMODE_DISABLE)
1467 alSourcef(buf->source, AL_ROLLOFF_FACTOR, factor);
1470 checkALError();
1471 popALContext();
1473 LeaveCriticalSection(This->crst);
1475 return S_OK;
1478 static HRESULT WINAPI DS8Primary3D_SetVelocity(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1480 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1482 TRACE("(%p)->(%f, %f, %f, %lu)\n", iface, x, y, z, apply);
1484 if(apply == DS3D_DEFERRED)
1486 EnterCriticalSection(This->crst);
1487 This->deferred.ds3d.vVelocity.x = x;
1488 This->deferred.ds3d.vVelocity.y = y;
1489 This->deferred.ds3d.vVelocity.z = z;
1490 This->dirty.bit.vel = 1;
1491 LeaveCriticalSection(This->crst);
1493 else
1495 setALContext(This->ctx);
1496 alListener3f(AL_VELOCITY, x, y, -z);
1497 checkALError();
1498 popALContext();
1501 return S_OK;
1504 static HRESULT WINAPI DS8Primary3D_SetAllParameters(IDirectSound3DListener *iface, const DS3DLISTENER *listen, DWORD apply)
1506 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1508 TRACE("(%p)->(%p, %lu)\n", iface, listen, apply);
1510 if(!listen || listen->dwSize < sizeof(*listen))
1512 WARN("Invalid parameter %p %lu\n", listen, listen ? listen->dwSize : 0);
1513 return DSERR_INVALIDPARAM;
1516 if(listen->flDistanceFactor > DS3D_MAXDISTANCEFACTOR ||
1517 listen->flDistanceFactor < DS3D_MINDISTANCEFACTOR)
1519 WARN("Invalid distance factor (%f)\n", listen->flDistanceFactor);
1520 return DSERR_INVALIDPARAM;
1523 if(listen->flDopplerFactor > DS3D_MAXDOPPLERFACTOR ||
1524 listen->flDopplerFactor < DS3D_MINDOPPLERFACTOR)
1526 WARN("Invalid doppler factor (%f)\n", listen->flDopplerFactor);
1527 return DSERR_INVALIDPARAM;
1530 if(listen->flRolloffFactor < DS3D_MINROLLOFFFACTOR ||
1531 listen->flRolloffFactor > DS3D_MAXROLLOFFFACTOR)
1533 WARN("Invalid rolloff factor (%f)\n", listen->flRolloffFactor);
1534 return DSERR_INVALIDPARAM;
1537 if(apply == DS3D_DEFERRED)
1539 EnterCriticalSection(This->crst);
1540 This->deferred.ds3d = *listen;
1541 This->deferred.ds3d.dwSize = sizeof(This->deferred.ds3d);
1542 This->dirty.bit.pos = 1;
1543 This->dirty.bit.vel = 1;
1544 This->dirty.bit.orientation = 1;
1545 This->dirty.bit.distancefactor = 1;
1546 This->dirty.bit.rollofffactor = 1;
1547 This->dirty.bit.dopplerfactor = 1;
1548 LeaveCriticalSection(This->crst);
1550 else
1552 union PrimaryParamFlags dirty = { 0l };
1553 dirty.bit.pos = 1;
1554 dirty.bit.vel = 1;
1555 dirty.bit.orientation = 1;
1556 dirty.bit.distancefactor = 1;
1557 dirty.bit.rollofffactor = 1;
1558 dirty.bit.dopplerfactor = 1;
1560 EnterCriticalSection(This->crst);
1561 setALContext(This->ctx);
1562 DS8Primary_SetParams(This, listen, dirty.flags);
1563 checkALError();
1564 popALContext();
1565 LeaveCriticalSection(This->crst);
1568 return S_OK;
1571 HRESULT WINAPI DS8Primary3D_CommitDeferredSettings(IDirectSound3DListener *iface)
1573 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1574 struct DSBufferGroup *bufgroup;
1575 LONG flags;
1576 DWORD i;
1578 EnterCriticalSection(This->crst);
1579 setALContext(This->ctx);
1580 alDeferUpdatesSOFT();
1582 if((flags=InterlockedExchange(&This->dirty.flags, 0)) != 0)
1584 DS8Primary_SetParams(This, &This->deferred.ds3d, flags);
1585 /* checkALError is here for debugging */
1586 checkALError();
1588 TRACE("Dirty flags was: 0x%02lx\n", flags);
1590 bufgroup = This->BufferGroups;
1591 for(i = 0;i < This->NumBufferGroups;++i)
1593 DWORD64 usemask = ~bufgroup[i].FreeBuffers;
1594 while(usemask)
1596 int idx = CTZ64(usemask);
1597 DS8Buffer *buf = bufgroup[i].Buffers + idx;
1598 usemask &= ~(U64(1) << idx);
1600 if((flags=InterlockedExchange(&buf->dirty.flags, 0)) != 0)
1601 DS8Buffer_SetParams(buf, &buf->deferred.ds3d, &buf->deferred.eax, flags);
1604 alProcessUpdatesSOFT();
1605 checkALError();
1607 popALContext();
1608 LeaveCriticalSection(This->crst);
1610 return DS_OK;
1613 static const IDirectSound3DListenerVtbl DS8Primary3D_Vtbl =
1615 DS8Primary3D_QueryInterface,
1616 DS8Primary3D_AddRef,
1617 DS8Primary3D_Release,
1618 DS8Primary3D_GetAllParameters,
1619 DS8Primary3D_GetDistanceFactor,
1620 DS8Primary3D_GetDopplerFactor,
1621 DS8Primary3D_GetOrientation,
1622 DS8Primary3D_GetPosition,
1623 DS8Primary3D_GetRolloffFactor,
1624 DS8Primary3D_GetVelocity,
1625 DS8Primary3D_SetAllParameters,
1626 DS8Primary3D_SetDistanceFactor,
1627 DS8Primary3D_SetDopplerFactor,
1628 DS8Primary3D_SetOrientation,
1629 DS8Primary3D_SetPosition,
1630 DS8Primary3D_SetRolloffFactor,
1631 DS8Primary3D_SetVelocity,
1632 DS8Primary3D_CommitDeferredSettings
1636 static HRESULT WINAPI DS8PrimaryProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
1638 DS8Primary *This = impl_from_IKsPropertySet(iface);
1639 return DS8Primary_QueryInterface(&This->IDirectSoundBuffer_iface, riid, ppv);
1642 static ULONG WINAPI DS8PrimaryProp_AddRef(IKsPropertySet *iface)
1644 DS8Primary *This = impl_from_IKsPropertySet(iface);
1645 LONG ret;
1647 ret = InterlockedIncrement(&This->prop_ref);
1648 TRACE("new refcount %ld\n", ret);
1650 return ret;
1653 static ULONG WINAPI DS8PrimaryProp_Release(IKsPropertySet *iface)
1655 DS8Primary *This = impl_from_IKsPropertySet(iface);
1656 LONG ret;
1658 ret = InterlockedDecrement(&This->prop_ref);
1659 TRACE("new refcount %ld\n", ret);
1661 return ret;
1664 static HRESULT WINAPI DS8PrimaryProp_Get(IKsPropertySet *iface,
1665 REFGUID guidPropSet, ULONG dwPropID,
1666 LPVOID pInstanceData, ULONG cbInstanceData,
1667 LPVOID pPropData, ULONG cbPropData,
1668 ULONG *pcbReturned)
1670 (void)iface;
1671 (void)dwPropID;
1672 (void)pInstanceData;
1673 (void)cbInstanceData;
1674 (void)pPropData;
1675 (void)cbPropData;
1676 (void)pcbReturned;
1678 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
1680 return E_PROP_ID_UNSUPPORTED;
1683 static HRESULT WINAPI DS8PrimaryProp_Set(IKsPropertySet *iface,
1684 REFGUID guidPropSet, ULONG dwPropID,
1685 LPVOID pInstanceData, ULONG cbInstanceData,
1686 LPVOID pPropData, ULONG cbPropData)
1688 (void)iface;
1689 (void)dwPropID;
1690 (void)pInstanceData;
1691 (void)cbInstanceData;
1692 (void)pPropData;
1693 (void)cbPropData;
1695 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
1697 return E_PROP_ID_UNSUPPORTED;
1700 static HRESULT WINAPI DS8PrimaryProp_QuerySupport(IKsPropertySet *iface,
1701 REFGUID guidPropSet, ULONG dwPropID,
1702 ULONG *pTypeSupport)
1704 (void)iface;
1705 (void)dwPropID;
1706 (void)pTypeSupport;
1708 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
1710 return E_PROP_ID_UNSUPPORTED;
1713 static const IKsPropertySetVtbl DS8PrimaryProp_Vtbl =
1715 DS8PrimaryProp_QueryInterface,
1716 DS8PrimaryProp_AddRef,
1717 DS8PrimaryProp_Release,
1718 DS8PrimaryProp_Get,
1719 DS8PrimaryProp_Set,
1720 DS8PrimaryProp_QuerySupport