Don't use special storage for the primary's write_emu
[dsound-openal.git] / buffer.c
blob4e9faa1973f8ee457c27410c4fb5ac3e1de6b163
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"
30 #include "ks.h"
31 #include <devpropdef.h>
33 #include "dsound_private.h"
36 #ifndef DS_INCOMPLETE
37 #define DS_INCOMPLETE ((HRESULT)0x08780020)
38 #endif
40 #ifndef WAVE_FORMAT_IEEE_FLOAT
41 #define WAVE_FORMAT_IEEE_FLOAT 3
42 #endif
45 /* TODO: when bufferlost is set, return from all calls except initialize with
46 * DSERR_BUFFERLOST
48 static const IDirectSoundBuffer8Vtbl DS8Buffer_Vtbl;
49 static const IDirectSound3DBufferVtbl DS8Buffer3d_Vtbl;
50 static const IDirectSoundNotifyVtbl DS8BufferNot_Vtbl;
51 static const IKsPropertySetVtbl DS8BufferProp_Vtbl;
54 static inline DS8Buffer *impl_from_IDirectSoundBuffer8(IDirectSoundBuffer8 *iface)
56 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSoundBuffer8_iface);
59 static inline DS8Buffer *impl_from_IDirectSoundBuffer(IDirectSoundBuffer *iface)
61 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSoundBuffer8_iface);
64 static inline DS8Buffer *impl_from_IDirectSound3DBuffer(IDirectSound3DBuffer *iface)
66 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSound3DBuffer_iface);
69 static inline DS8Buffer *impl_from_IDirectSoundNotify(IDirectSoundNotify *iface)
71 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSoundNotify_iface);
74 static inline DS8Buffer *impl_from_IKsPropertySet(IKsPropertySet *iface)
76 return CONTAINING_RECORD(iface, DS8Buffer, IKsPropertySet_iface);
80 /* Should be called with critsect held and context set.. */
81 static void DS8Buffer_addnotify(DS8Buffer *buf)
83 DS8Primary *prim = buf->primary;
84 DS8Buffer **list;
85 DWORD i;
87 list = prim->notifies;
88 for(i = 0; i < prim->nnotifies; ++i)
90 if(buf == list[i])
92 ERR("Buffer %p already in notification list\n", buf);
93 return;
96 if(prim->nnotifies == prim->sizenotifies)
98 list = HeapReAlloc(GetProcessHeap(), 0, list, (prim->nnotifies + 1) * sizeof(*list));
99 if(!list) return;
100 prim->sizenotifies++;
102 list[prim->nnotifies++] = buf;
103 prim->notifies = list;
107 static const char *get_fmtstr_PCM(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out)
109 out->Format = *format;
110 out->Format.cbSize = 0;
112 if(out->Format.nChannels != 1 && out->Format.nChannels != 2 &&
113 !HAS_EXTENSION(prim->share, EXT_MCFORMATS))
115 WARN("Multi-channel not available\n");
116 return NULL;
119 if(format->wBitsPerSample == 8)
121 switch(format->nChannels)
123 case 1: return "AL_FORMAT_MONO8";
124 case 2: return "AL_FORMAT_STEREO8";
125 case 4: return "AL_FORMAT_QUAD8";
126 case 6: return "AL_FORMAT_51CHN8";
127 case 7: return "AL_FORMAT_61CHN8";
128 case 8: return "AL_FORMAT_71CHN8";
131 else if(format->wBitsPerSample == 16)
133 switch(format->nChannels)
135 case 1: return "AL_FORMAT_MONO16";
136 case 2: return "AL_FORMAT_STEREO16";
137 case 4: return "AL_FORMAT_QUAD16";
138 case 6: return "AL_FORMAT_51CHN16";
139 case 7: return "AL_FORMAT_61CHN16";
140 case 8: return "AL_FORMAT_71CHN16";
144 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
145 format->wBitsPerSample, format->nChannels);
146 return NULL;
149 static const char *get_fmtstr_FLOAT(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out)
151 out->Format = *format;
152 out->Format.cbSize = 0;
154 if(out->Format.nChannels != 1 && out->Format.nChannels != 2 &&
155 !HAS_EXTENSION(prim->share, EXT_MCFORMATS))
157 WARN("Multi-channel not available\n");
158 return NULL;
161 if(format->wBitsPerSample == 32 && HAS_EXTENSION(prim->share, EXT_FLOAT32))
163 switch(format->nChannels)
165 case 1: return "AL_FORMAT_MONO_FLOAT32";
166 case 2: return "AL_FORMAT_STEREO_FLOAT32";
167 case 4: return "AL_FORMAT_QUAD32";
168 case 6: return "AL_FORMAT_51CHN32";
169 case 7: return "AL_FORMAT_61CHN32";
170 case 8: return "AL_FORMAT_71CHN32";
174 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
175 format->wBitsPerSample, format->nChannels);
176 return NULL;
179 /* Speaker configs */
180 #define MONO SPEAKER_FRONT_CENTER
181 #define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)
182 #define REAR (SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
183 #define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
184 #define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
185 #define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
186 #define X7DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
188 static const char *get_fmtstr_EXT(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out)
190 *out = *CONTAINING_RECORD(format, const WAVEFORMATEXTENSIBLE, Format);
191 out->Format.cbSize = sizeof(*out) - sizeof(out->Format);
193 if(!out->Samples.wValidBitsPerSample)
194 out->Samples.wValidBitsPerSample = out->Format.wBitsPerSample;
195 else if(out->Samples.wValidBitsPerSample > out->Format.wBitsPerSample)
197 WARN("Invalid ValidBitsPerSample (%u > %u)\n", out->Samples.wValidBitsPerSample, out->Format.wBitsPerSample);
198 return NULL;
200 else if(out->Samples.wValidBitsPerSample < out->Format.wBitsPerSample)
202 FIXME("Padded samples not supported (%u of %u)\n", out->Samples.wValidBitsPerSample, out->Format.wBitsPerSample);
203 return NULL;
206 if(out->dwChannelMask != MONO && out->dwChannelMask != STEREO &&
207 !HAS_EXTENSION(prim->share, EXT_MCFORMATS))
209 WARN("Multi-channel not available\n");
210 return NULL;
213 if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
215 if(out->Samples.wValidBitsPerSample == 8)
217 switch(out->dwChannelMask)
219 case MONO: return "AL_FORMAT_MONO8";
220 case STEREO: return "AL_FORMAT_STEREO8";
221 case REAR: return "AL_FORMAT_REAR8";
222 case QUAD: return "AL_FORMAT_QUAD8";
223 case X5DOT1: return "AL_FORMAT_51CHN8";
224 case X6DOT1: return "AL_FORMAT_61CHN8";
225 case X7DOT1: return "AL_FORMAT_71CHN8";
228 else if(out->Samples.wValidBitsPerSample == 16)
230 switch(out->dwChannelMask)
232 case MONO: return "AL_FORMAT_MONO16";
233 case STEREO: return "AL_FORMAT_STEREO16";
234 case REAR: return "AL_FORMAT_REAR16";
235 case QUAD: return "AL_FORMAT_QUAD16";
236 case X5DOT1: return "AL_FORMAT_51CHN16";
237 case X6DOT1: return "AL_FORMAT_61CHN16";
238 case X7DOT1: return "AL_FORMAT_71CHN16";
242 FIXME("Could not get OpenAL PCM format (%d-bit, channelmask %#lx)\n",
243 out->Samples.wValidBitsPerSample, out->dwChannelMask);
244 return NULL;
246 else if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) &&
247 HAS_EXTENSION(prim->share, EXT_FLOAT32))
249 if(out->Samples.wValidBitsPerSample == 32)
251 switch(out->dwChannelMask)
253 case MONO: return "AL_FORMAT_MONO_FLOAT32";
254 case STEREO: return "AL_FORMAT_STEREO_FLOAT32";
255 case REAR: return "AL_FORMAT_REAR32";
256 case QUAD: return "AL_FORMAT_QUAD32";
257 case X5DOT1: return "AL_FORMAT_51CHN32";
258 case X6DOT1: return "AL_FORMAT_61CHN32";
259 case X7DOT1: return "AL_FORMAT_71CHN32";
262 else
264 WARN("Invalid float bits: %u\n", out->Samples.wValidBitsPerSample);
265 return NULL;
268 FIXME("Could not get OpenAL float format (%d-bit, channelmask %#lx)\n",
269 out->Samples.wValidBitsPerSample, out->dwChannelMask);
270 return NULL;
272 else if(!IsEqualGUID(&out->SubFormat, &GUID_NULL))
273 ERR("Unhandled extensible format: %s\n", debugstr_guid(&out->SubFormat));
274 return NULL;
277 static void DS8Data_Release(DS8Data *This);
278 static HRESULT DS8Data_Create(DS8Data **ppv, const DSBUFFERDESC *desc, DS8Primary *prim)
280 HRESULT hr = DSERR_INVALIDPARAM;
281 const WAVEFORMATEX *format;
282 const char *fmt_str = NULL;
283 DS8Data *pBuffer;
284 DWORD buf_size;
286 format = desc->lpwfxFormat;
287 TRACE("Requested buffer format:\n"
288 " FormatTag = 0x%04x\n"
289 " Channels = %d\n"
290 " SamplesPerSec = %lu\n"
291 " AvgBytesPerSec = %lu\n"
292 " BlockAlign = %d\n"
293 " BitsPerSample = %d\n",
294 format->wFormatTag, format->nChannels,
295 format->nSamplesPerSec, format->nAvgBytesPerSec,
296 format->nBlockAlign, format->wBitsPerSample);
298 if(format->nChannels <= 0)
300 WARN("Invalid Channels %d\n", format->nChannels);
301 return DSERR_INVALIDPARAM;
303 if(format->nSamplesPerSec < DSBFREQUENCY_MIN || format->nSamplesPerSec > DSBFREQUENCY_MAX)
305 WARN("Invalid SamplesPerSec %lu\n", format->nSamplesPerSec);
306 return DSERR_INVALIDPARAM;
308 if(format->nBlockAlign <= 0)
310 WARN("Invalid BlockAlign %d\n", format->nBlockAlign);
311 return DSERR_INVALIDPARAM;
313 if(format->wBitsPerSample == 0 || (format->wBitsPerSample%8) != 0)
315 WARN("Invalid BitsPerSample %d\n", format->wBitsPerSample);
316 return DSERR_INVALIDPARAM;
318 if(format->nBlockAlign != format->nChannels*format->wBitsPerSample/8)
320 WARN("Invalid BlockAlign %d (expected %u = %u*%u/8)\n",
321 format->nBlockAlign, format->nChannels*format->wBitsPerSample/8,
322 format->nChannels, format->wBitsPerSample);
323 return DSERR_INVALIDPARAM;
325 if(format->nAvgBytesPerSec != format->nBlockAlign*format->nSamplesPerSec)
327 WARN("Invalid AvgBytesPerSec %lu (expected %lu = %lu*%u)\n",
328 format->nAvgBytesPerSec, format->nSamplesPerSec*format->nBlockAlign,
329 format->nSamplesPerSec, format->nBlockAlign);
330 return DSERR_INVALIDPARAM;
333 if((desc->dwFlags&(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE)) == (DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE))
335 WARN("Hardware and software location requested\n");
336 return DSERR_INVALIDPARAM;
339 buf_size = desc->dwBufferBytes + format->nBlockAlign - 1;
340 buf_size -= buf_size%format->nBlockAlign;
341 if(buf_size < DSBSIZE_MIN) return DSERR_BUFFERTOOSMALL;
342 if(buf_size > DSBSIZE_MAX) return DSERR_INVALIDPARAM;
344 /* Generate a new buffer. Supporting the DSBCAPS_LOC* flags properly
345 * will need the EAX-RAM extension. Currently, we just tell the app it
346 * gets what it wanted. */
347 if(!HAS_EXTENSION(prim->share, SOFTX_MAP_BUFFER))
348 pBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pBuffer)+buf_size);
349 else
350 pBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pBuffer));
351 if(!pBuffer) return E_OUTOFMEMORY;
352 pBuffer->ref = 1;
353 pBuffer->primary = prim;
355 pBuffer->dsbflags = desc->dwFlags;
356 if(!(pBuffer->dsbflags&(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE|DSBCAPS_LOCDEFER)))
357 pBuffer->dsbflags |= DSBCAPS_LOCHARDWARE;
358 pBuffer->buf_size = buf_size;
360 if(format->wFormatTag == WAVE_FORMAT_PCM)
361 fmt_str = get_fmtstr_PCM(prim, format, &pBuffer->format);
362 else if(format->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
363 fmt_str = get_fmtstr_FLOAT(prim, format, &pBuffer->format);
364 else if(format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
366 const WAVEFORMATEXTENSIBLE *wfe;
368 if(format->cbSize != sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) &&
369 format->cbSize != sizeof(WAVEFORMATEXTENSIBLE))
370 goto fail;
372 wfe = CONTAINING_RECORD(format, const WAVEFORMATEXTENSIBLE, Format);
373 TRACE("Extensible values:\n"
374 " Samples = %d\n"
375 " ChannelMask = 0x%lx\n"
376 " SubFormat = %s\n",
377 wfe->Samples.wReserved, wfe->dwChannelMask,
378 debugstr_guid(&wfe->SubFormat));
380 fmt_str = get_fmtstr_EXT(prim, format, &pBuffer->format);
382 else
383 ERR("Unhandled formattag 0x%04x\n", format->wFormatTag);
384 if(!fmt_str) goto fail;
386 alGetError();
387 pBuffer->buf_format = alGetEnumValue(fmt_str);
388 if(alGetError() != AL_NO_ERROR || pBuffer->buf_format == 0 ||
389 pBuffer->buf_format == -1)
391 WARN("Could not get OpenAL format from %s\n", fmt_str);
392 goto fail;
395 hr = E_OUTOFMEMORY;
396 if(!HAS_EXTENSION(prim->share, SOFTX_MAP_BUFFER))
398 pBuffer->data = (BYTE*)(pBuffer+1);
400 alGenBuffers(1, &pBuffer->bid);
401 checkALError();
403 else
405 const ALbitfieldSOFT map_bits = AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT |
406 AL_MAP_PERSISTENT_BIT_SOFT;
407 alGenBuffers(1, &pBuffer->bid);
408 alBufferStorageSOFT(pBuffer->bid, pBuffer->buf_format, NULL, pBuffer->buf_size,
409 pBuffer->format.Format.nSamplesPerSec, map_bits);
410 pBuffer->data = alMapBufferSOFT(pBuffer->bid, 0, pBuffer->buf_size, map_bits);
411 checkALError();
413 if(!pBuffer->data) goto fail;
416 *ppv = pBuffer;
417 return S_OK;
419 fail:
420 DS8Data_Release(pBuffer);
421 return hr;
424 static void DS8Data_AddRef(DS8Data *data)
426 InterlockedIncrement(&data->ref);
429 /* This function is always called with the device lock held */
430 static void DS8Data_Release(DS8Data *This)
432 if(InterlockedDecrement(&This->ref)) return;
434 TRACE("Deleting %p\n", This);
435 if(This->bid)
437 DS8Primary *prim = This->primary;
438 if(HAS_EXTENSION(prim->share, SOFTX_MAP_BUFFER))
439 alUnmapBufferSOFT(This->bid);
440 alDeleteBuffers(1, &This->bid);
441 checkALError();
443 HeapFree(GetProcessHeap(), 0, This);
447 HRESULT DS8Buffer_Create(DS8Buffer **ppv, DS8Primary *prim, IDirectSoundBuffer *orig)
449 DS8Buffer *This = NULL;
450 EAX30BUFFERPROPERTIES *eaxbuffer;
451 DS3DBUFFER *ds3dbuffer;
452 HRESULT hr;
453 DWORD i;
455 *ppv = NULL;
456 EnterCriticalSection(&prim->share->crst);
457 for(i = 0;i < prim->NumBufferGroups;++i)
459 if(prim->BufferGroups[i].FreeBuffers)
461 int idx = CTZ64(prim->BufferGroups[i].FreeBuffers);
462 This = prim->BufferGroups[i].Buffers + idx;
463 memset(This, 0, sizeof(*This));
464 prim->BufferGroups[i].FreeBuffers &= ~(U64(1) << idx);
465 break;
468 if(!This)
470 struct DSBufferGroup *grp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
471 (prim->NumBufferGroups+1)*sizeof(prim->BufferGroups[0]));
472 if(grp)
474 for(i = 0;i < prim->NumBufferGroups;i++)
475 grp[i] = prim->BufferGroups[i];
476 grp[i].FreeBuffers = ~U64(0);
477 grp[i].Buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
478 64*sizeof(grp[0].Buffers[0]));
479 if(!grp[i].Buffers)
481 HeapFree(GetProcessHeap(), 0, grp);
482 grp = NULL;
484 else
486 HeapFree(GetProcessHeap(), 0, prim->BufferGroups);
487 prim->BufferGroups = grp;
488 prim->NumBufferGroups++;
490 This = prim->BufferGroups[i].Buffers + 0;
491 memset(This, 0, sizeof(*This));
492 prim->BufferGroups[i].FreeBuffers &= ~(U64(1) << 0);
496 LeaveCriticalSection(&prim->share->crst);
497 if(!This)
499 WARN("Out of memory allocating buffers\n");
500 return DSERR_OUTOFMEMORY;
503 This->IDirectSoundBuffer8_iface.lpVtbl = &DS8Buffer_Vtbl;
504 This->IDirectSound3DBuffer_iface.lpVtbl = &DS8Buffer3d_Vtbl;
505 This->IDirectSoundNotify_iface.lpVtbl = &DS8BufferNot_Vtbl;
506 This->IKsPropertySet_iface.lpVtbl = &DS8BufferProp_Vtbl;
508 This->share = prim->share;
509 This->primary = prim;
510 This->ctx = prim->ctx;
511 This->ref = This->all_ref = 1;
513 if(orig)
515 DS8Buffer *org = impl_from_IDirectSoundBuffer(orig);
516 hr = DSERR_BUFFERLOST;
517 if(org->bufferlost)
518 goto fail;
519 DS8Data_AddRef(org->buffer);
520 This->buffer = org->buffer;
523 This->rollofffactor = 0.0f;
525 ds3dbuffer = &This->deferred.ds3d;
526 ds3dbuffer->dwSize = sizeof(This->deferred.ds3d);
527 ds3dbuffer->vPosition.x = 0.0f;
528 ds3dbuffer->vPosition.y = 0.0f;
529 ds3dbuffer->vPosition.z = 0.0f;
530 ds3dbuffer->vVelocity.x = 0.0f;
531 ds3dbuffer->vVelocity.y = 0.0f;
532 ds3dbuffer->vVelocity.z = 0.0f;
533 ds3dbuffer->dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
534 ds3dbuffer->dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
535 ds3dbuffer->vConeOrientation.x = 0.0f;
536 ds3dbuffer->vConeOrientation.y = 0.0f;
537 ds3dbuffer->vConeOrientation.z = 1.0f;
538 ds3dbuffer->lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
539 ds3dbuffer->flMinDistance = DS3D_DEFAULTMINDISTANCE;
540 ds3dbuffer->flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
541 ds3dbuffer->dwMode = DS3DMODE_NORMAL;
542 eaxbuffer = &This->deferred.eax;
543 eaxbuffer->lDirect = 0;
544 eaxbuffer->lDirectHF = 0;
545 eaxbuffer->lRoom = 0;
546 eaxbuffer->lRoomHF = 0;
547 eaxbuffer->lObstruction = 0;
548 eaxbuffer->flObstructionLFRatio = 0.0f;
549 eaxbuffer->lOcclusion = 0;
550 eaxbuffer->flOcclusionLFRatio = 0.25f;
551 eaxbuffer->flOcclusionRoomRatio = 1.5f;
552 eaxbuffer->flOcclusionDirectRatio = 1.0f;
553 eaxbuffer->lExclusion = 0;
554 eaxbuffer->flExclusionLFRatio = 1.0f;
555 eaxbuffer->lOutsideVolumeHF = 0;
556 eaxbuffer->flDopplerFactor = 1.0f;
557 eaxbuffer->flRolloffFactor = 0.0f;
558 eaxbuffer->flRoomRolloffFactor = 0.0f;
559 eaxbuffer->flAirAbsorptionFactor = 0.0f;
560 eaxbuffer->dwFlags = EAX30BUFFERFLAGS_DIRECTHFAUTO | EAX30BUFFERFLAGS_ROOMAUTO |
561 EAX30BUFFERFLAGS_ROOMHFAUTO;
562 This->deferred.eax1_reverbmix = 1.0f;
564 /* Disable until initialized. */
565 This->ds3dmode = DS3DMODE_DISABLE;
567 *ppv = This;
568 return DS_OK;
570 fail:
571 DS8Buffer_Destroy(This);
572 return hr;
575 void DS8Buffer_Destroy(DS8Buffer *This)
577 DS8Primary *prim = This->primary;
578 DWORD i;
580 if(!prim) return;
581 TRACE("Destroying %p\n", This);
583 EnterCriticalSection(&prim->share->crst);
584 /* Remove from list, if in list */
585 for(i = 0;i < prim->nnotifies;++i)
587 if(This == prim->notifies[i])
589 prim->notifies[i] = prim->notifies[--prim->nnotifies];
590 break;
594 setALContext(This->ctx);
595 if(This->source)
597 alSourceStop(This->source);
598 alSourcei(This->source, AL_BUFFER, 0);
599 checkALError();
601 prim->share->sources.ids[prim->share->sources.avail_num++] = This->source;
602 This->source = 0;
604 if(This->stream_bids[0])
605 alDeleteBuffers(QBUFFERS, This->stream_bids);
606 if(This->filter[0])
607 alDeleteFilters(2, This->filter);
609 if(This->buffer)
610 DS8Data_Release(This->buffer);
612 popALContext();
614 HeapFree(GetProcessHeap(), 0, This->notify);
616 for(i = 0;i < prim->NumBufferGroups;++i)
618 DWORD_PTR idx = This - prim->BufferGroups[i].Buffers;
619 if(idx < 64)
621 prim->BufferGroups[i].FreeBuffers |= U64(1) << idx;
622 This = NULL;
623 break;
626 LeaveCriticalSection(&prim->share->crst);
630 static HRESULT WINAPI DS8Buffer_QueryInterface(IDirectSoundBuffer8 *iface, REFIID riid, void **ppv)
632 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
634 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
636 *ppv = NULL;
637 if(IsEqualIID(riid, &IID_IUnknown))
638 *ppv = &This->IDirectSoundBuffer8_iface;
639 else if(IsEqualIID(riid, &IID_IDirectSoundBuffer))
640 *ppv = &This->IDirectSoundBuffer8_iface;
641 else if(IsEqualIID(riid, &IID_IDirectSoundBuffer8))
643 if(This->primary->parent->is_8)
644 *ppv = &This->IDirectSoundBuffer8_iface;
646 else if(IsEqualIID(riid, &IID_IDirectSound3DBuffer))
648 if((This->buffer->dsbflags&DSBCAPS_CTRL3D))
649 *ppv = &This->IDirectSound3DBuffer_iface;
651 else if(IsEqualIID(riid, &IID_IDirectSoundNotify))
653 if((This->buffer->dsbflags&DSBCAPS_CTRLPOSITIONNOTIFY))
654 *ppv = &This->IDirectSoundNotify_iface;
656 else if(IsEqualIID(riid, &IID_IKsPropertySet))
657 *ppv = &This->IKsPropertySet_iface;
658 else
659 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
661 if(*ppv)
663 IUnknown_AddRef((IUnknown*)*ppv);
664 return S_OK;
667 return E_NOINTERFACE;
670 static ULONG WINAPI DS8Buffer_AddRef(IDirectSoundBuffer8 *iface)
672 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
673 LONG ret;
675 InterlockedIncrement(&This->all_ref);
676 ret = InterlockedIncrement(&This->ref);
677 TRACE("new refcount %ld\n", ret);
679 return ret;
682 static ULONG WINAPI DS8Buffer_Release(IDirectSoundBuffer8 *iface)
684 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
685 LONG ret;
687 ret = InterlockedDecrement(&This->ref);
688 TRACE("new refcount %ld\n", ret);
689 if(InterlockedDecrement(&This->all_ref) == 0)
690 DS8Buffer_Destroy(This);
692 return ret;
695 static HRESULT WINAPI DS8Buffer_GetCaps(IDirectSoundBuffer8 *iface, DSBCAPS *caps)
697 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
698 DS8Data *data;
700 TRACE("(%p)->(%p)\n", iface, caps);
702 if(!caps || caps->dwSize < sizeof(*caps))
704 WARN("Invalid DSBCAPS (%p, %lu)\n", caps, (caps ? caps->dwSize : 0));
705 return DSERR_INVALIDPARAM;
707 data = This->buffer;
709 caps->dwFlags = data->dsbflags;
710 if((data->dsbflags&DSBCAPS_LOCDEFER))
712 if(This->loc_status == DSBSTATUS_LOCHARDWARE)
713 caps->dwFlags |= DSBCAPS_LOCHARDWARE;
714 else if(This->loc_status == DSBSTATUS_LOCSOFTWARE)
715 caps->dwFlags |= DSBCAPS_LOCSOFTWARE;
717 caps->dwBufferBytes = data->buf_size;
718 caps->dwUnlockTransferRate = 4096;
719 caps->dwPlayCpuOverhead = 0;
721 return S_OK;
724 HRESULT WINAPI DS8Buffer_GetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD *playpos, DWORD *curpos)
726 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
727 ALsizei writecursor, pos;
728 DS8Data *data;
730 TRACE("(%p)->(%p, %p)\n", iface, playpos, curpos);
732 data = This->buffer;
733 if(This->segsize != 0)
735 ALint queued = QBUFFERS;
736 ALint status = 0;
737 ALint ofs = 0;
739 EnterCriticalSection(&This->share->crst);
741 setALContext(This->ctx);
742 alGetSourcei(This->source, AL_BUFFERS_QUEUED, &queued);
743 alGetSourcei(This->source, AL_BYTE_OFFSET, &ofs);
744 alGetSourcei(This->source, AL_SOURCE_STATE, &status);
745 checkALError();
746 popALContext();
748 if(status == AL_STOPPED)
749 pos = This->segsize*queued + This->queue_base;
750 else
751 pos = ofs + This->queue_base;
752 if(pos >= data->buf_size)
754 if(This->islooping)
755 pos %= data->buf_size;
756 else if(This->isplaying)
758 pos = data->buf_size;
759 alSourceStop(This->source);
760 alSourcei(This->source, AL_BUFFER, 0);
761 This->curidx = 0;
762 This->isplaying = FALSE;
765 if(This->isplaying)
766 writecursor = (This->segsize*QBUFFERS + pos) % data->buf_size;
767 else
768 writecursor = pos % data->buf_size;
770 LeaveCriticalSection(&This->share->crst);
772 else
774 const WAVEFORMATEX *format = &data->format.Format;
775 ALint status = 0;
776 ALint ofs = 0;
778 setALContext(This->ctx);
779 alGetSourcei(This->source, AL_BYTE_OFFSET, &ofs);
780 alGetSourcei(This->source, AL_SOURCE_STATE, &status);
781 checkALError();
782 popALContext();
784 /* AL_STOPPED means the source naturally reached its end, where
785 * DirectSound's position should be at the end (OpenAL reports a 0
786 * position). The Stop method correlates to pausing, which would put
787 * the source into an AL_PAUSED state and hold its current position.
789 pos = (status == AL_STOPPED) ? data->buf_size : ofs;
790 if(status == AL_PLAYING)
792 writecursor = format->nSamplesPerSec / This->primary->refresh;
793 writecursor *= format->nBlockAlign;
795 else
796 writecursor = 0;
797 writecursor = (writecursor + pos) % data->buf_size;
799 TRACE("%p Play pos = %u, write pos = %u\n", This, pos, writecursor);
801 if(pos > data->buf_size)
803 ERR("playpos > buf_size\n");
804 pos %= data->buf_size;
806 if(writecursor >= data->buf_size)
808 ERR("writepos >= buf_size\n");
809 writecursor %= data->buf_size;
812 if(playpos) *playpos = pos;
813 if(curpos) *curpos = writecursor;
815 return S_OK;
818 static HRESULT WINAPI DS8Buffer_GetFormat(IDirectSoundBuffer8 *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
820 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
821 HRESULT hr = S_OK;
822 UINT size;
824 TRACE("(%p)->(%p, %lu, %p)\n", iface, wfx, allocated, written);
826 if(!wfx && !written)
828 WARN("Cannot report format or format size\n");
829 return DSERR_INVALIDPARAM;
832 size = sizeof(This->buffer->format.Format) + This->buffer->format.Format.cbSize;
833 if(wfx)
835 if(allocated < size)
836 hr = DSERR_INVALIDPARAM;
837 else
838 memcpy(wfx, &This->buffer->format.Format, size);
840 if(written)
841 *written = size;
843 return hr;
846 static HRESULT WINAPI DS8Buffer_GetVolume(IDirectSoundBuffer8 *iface, LONG *vol)
848 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
849 HRESULT hr;
851 TRACE("(%p)->(%p)\n", iface, vol);
853 if(!vol)
855 WARN("Invalid pointer\n");
856 return DSERR_INVALIDPARAM;
859 hr = DSERR_CONTROLUNAVAIL;
860 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
861 WARN("Volume control not set\n");
862 else
864 ALfloat gain = 1.0f;
866 setALContext(This->ctx);
867 alGetSourcef(This->source, AL_GAIN, &gain);
868 checkALError();
869 popALContext();
871 *vol = clampI(gain_to_mB(gain), DSBVOLUME_MIN, DSBVOLUME_MAX);
872 hr = DS_OK;
875 return hr;
878 static HRESULT WINAPI DS8Buffer_GetPan(IDirectSoundBuffer8 *iface, LONG *pan)
880 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
881 HRESULT hr;
883 TRACE("(%p)->(%p)\n", iface, pan);
885 if(!pan)
887 WARN("Invalid pointer\n");
888 return DSERR_INVALIDPARAM;
891 hr = DSERR_CONTROLUNAVAIL;
892 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
893 WARN("Panning control not set\n");
894 else
896 if((This->buffer->dsbflags&DSBCAPS_CTRL3D))
897 *pan = 0;
898 else
900 ALfloat pos[3];
902 setALContext(This->ctx);
903 alGetSourcefv(This->source, AL_POSITION, pos);
904 checkALError();
905 popALContext();
907 *pan = clampI((LONG)((pos[0]+0.5f)*(DSBPAN_RIGHT-DSBPAN_LEFT) + 0.5f) + DSBPAN_LEFT,
908 DSBPAN_LEFT, DSBPAN_RIGHT);
910 hr = DS_OK;
913 return hr;
916 static HRESULT WINAPI DS8Buffer_GetFrequency(IDirectSoundBuffer8 *iface, DWORD *freq)
918 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
919 HRESULT hr;
921 TRACE("(%p)->(%p)\n", iface, freq);
923 if(!freq)
925 WARN("Invalid pointer\n");
926 return DSERR_INVALIDPARAM;
929 hr = DSERR_CONTROLUNAVAIL;
930 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
931 WARN("Frequency control not set\n");
932 else
934 ALfloat pitch = 1.0f;
936 setALContext(This->ctx);
937 alGetSourcefv(This->source, AL_PITCH, &pitch);
938 checkALError();
939 popALContext();
941 *freq = (DWORD)(This->buffer->format.Format.nSamplesPerSec * pitch);
942 hr = DS_OK;
945 return hr;
948 HRESULT WINAPI DS8Buffer_GetStatus(IDirectSoundBuffer8 *iface, DWORD *status)
950 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
951 ALint state, looping;
953 TRACE("(%p)->(%p)\n", iface, status);
955 if(!status)
957 WARN("Invalid pointer\n");
958 return DSERR_INVALIDPARAM;
960 *status = 0;
962 if(This->segsize == 0)
964 setALContext(This->ctx);
965 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
966 alGetSourcei(This->source, AL_LOOPING, &looping);
967 checkALError();
968 popALContext();
970 else
972 EnterCriticalSection(&This->share->crst);
973 state = This->isplaying ? AL_PLAYING : AL_PAUSED;
974 looping = This->islooping;
975 LeaveCriticalSection(&This->share->crst);
978 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
979 *status |= This->loc_status;
980 if(state == AL_PLAYING)
981 *status |= DSBSTATUS_PLAYING | (looping ? DSBSTATUS_LOOPING : 0);
983 TRACE("%p status = 0x%08lx\n", This, *status);
984 return S_OK;
987 HRESULT WINAPI DS8Buffer_Initialize(IDirectSoundBuffer8 *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
989 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
990 DS8Primary *prim;
991 DS8Data *data;
992 HRESULT hr;
994 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
996 EnterCriticalSection(&This->share->crst);
997 setALContext(This->ctx);
999 hr = DSERR_ALREADYINITIALIZED;
1000 if(This->init_done) goto out;
1002 prim = This->primary;
1003 if(!This->buffer)
1005 hr = DSERR_INVALIDPARAM;
1006 if(!desc)
1008 WARN("Missing DSound buffer description\n");
1009 goto out;
1011 if(!desc->lpwfxFormat)
1013 WARN("Missing buffer format (%p)\n", This);
1014 goto out;
1016 if((desc->dwFlags&DSBCAPS_CTRL3D) && desc->lpwfxFormat->nChannels != 1)
1018 if(prim->parent->is_8)
1020 /* DirectSoundBuffer8 objects aren't allowed non-mono 3D
1021 * buffers */
1022 WARN("Can't create multi-channel 3D buffers\n");
1023 goto out;
1025 else
1027 static int once = 0;
1028 if(!once++)
1029 ERR("Multi-channel 3D sounds are not spatialized\n");
1032 if((desc->dwFlags&DSBCAPS_CTRLPAN) && desc->lpwfxFormat->nChannels != 1)
1034 static int once = 0;
1035 if(!once++)
1036 ERR("Panning for multi-channel buffers is not supported\n");
1039 hr = DS8Data_Create(&This->buffer, desc, prim);
1040 if(FAILED(hr)) goto out;
1042 data = This->buffer;
1043 if(data->format.Format.wBitsPerSample == 8)
1044 memset(data->data, 0x80, data->buf_size);
1045 else
1046 memset(data->data, 0x00, data->buf_size);
1049 data = This->buffer;
1050 if((data->dsbflags&DSBCAPS_LOCHARDWARE))
1051 This->loc_status = DSBSTATUS_LOCHARDWARE;
1052 else if((data->dsbflags&DSBCAPS_LOCSOFTWARE))
1053 This->loc_status = DSBSTATUS_LOCSOFTWARE;
1055 if(!(data->dsbflags&DSBCAPS_STATIC) && !HAS_EXTENSION(This->share, SOFTX_MAP_BUFFER))
1057 This->segsize = (data->format.Format.nAvgBytesPerSec+prim->refresh-1) / prim->refresh;
1058 This->segsize = clampI(This->segsize, data->format.Format.nBlockAlign, 2048);
1059 This->segsize += data->format.Format.nBlockAlign - 1;
1060 This->segsize -= This->segsize%data->format.Format.nBlockAlign;
1062 alGenBuffers(QBUFFERS, This->stream_bids);
1063 checkALError();
1066 hr = DSERR_ALLOCATED;
1067 if(!This->share->sources.avail_num)
1069 ERR("Out of sources\n");
1070 goto out;
1073 This->source = This->share->sources.ids[--(This->share->sources.avail_num)];
1074 alSourceRewind(This->source);
1075 alSourcef(This->source, AL_GAIN, 1.0f);
1076 alSourcef(This->source, AL_PITCH, 1.0f);
1077 checkALError();
1079 if((data->dsbflags&DSBCAPS_CTRL3D))
1081 union BufferParamFlags dirty = { 0 };
1083 if(HAS_EXTENSION(This->share, EXT_EFX))
1085 alGenFilters(2, This->filter);
1086 alFilteri(This->filter[0], AL_FILTER_TYPE, AL_FILTER_LOWPASS);
1087 alFilteri(This->filter[1], AL_FILTER_TYPE, AL_FILTER_LOWPASS);
1088 if(UNLIKELY(alGetError() != AL_NO_ERROR))
1090 alDeleteFilters(2, This->filter);
1091 This->filter[0] = This->filter[1] = 0;
1095 dirty.bit.pos = 1;
1096 dirty.bit.vel = 1;
1097 dirty.bit.cone_angles = 1;
1098 dirty.bit.cone_orient = 1;
1099 dirty.bit.cone_outsidevolume = 1;
1100 dirty.bit.min_distance = 1;
1101 dirty.bit.max_distance = 1;
1102 dirty.bit.mode = 1;
1103 dirty.bit.doppler = 1;
1104 dirty.bit.rolloff = 1;
1105 if(HAS_EXTENSION(This->share, EXT_EFX))
1107 dirty.bit.dry_filter = 1;
1108 dirty.bit.wet_filter = 1;
1109 dirty.bit.room_rolloff = 1;
1110 dirty.bit.cone_outsidevolumehf = 1;
1111 dirty.bit.air_absorb = 1;
1112 dirty.bit.flags = 1;
1114 DS8Buffer_SetParams(This, &This->deferred.ds3d, &This->deferred.eax, dirty.flags);
1115 checkALError();
1117 else
1119 ALuint source = This->source;
1121 /* Non-3D sources aren't distance attenuated */
1122 This->ds3dmode = DS3DMODE_DISABLE;
1123 alSource3f(source, AL_POSITION, 0.0f, 0.0f, -1.0f);
1124 alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
1125 alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
1126 alSourcef(source, AL_CONE_OUTER_GAIN, 1.0f);
1127 alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f);
1128 alSourcef(source, AL_MAX_DISTANCE, 1000.0f);
1129 alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f);
1130 alSourcef(source, AL_DOPPLER_FACTOR, 0.0f);
1131 alSourcei(source, AL_CONE_INNER_ANGLE, 360);
1132 alSourcei(source, AL_CONE_OUTER_ANGLE, 360);
1133 alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);
1134 if(HAS_EXTENSION(This->share, EXT_EFX))
1136 alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, 0.0f);
1137 alSourcef(source, AL_CONE_OUTER_GAINHF, 1.0f);
1138 alSourcef(source, AL_AIR_ABSORPTION_FACTOR, 0.0f);
1139 alSourcei(source, AL_DIRECT_FILTER_GAINHF_AUTO, AL_TRUE);
1140 alSourcei(source, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO, AL_TRUE);
1141 alSourcei(source, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO, AL_TRUE);
1142 alSourcei(source, AL_DIRECT_FILTER, AL_FILTER_NULL);
1143 alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL);
1145 if(HAS_EXTENSION(This->share, SOFT_SOURCE_SPATIALIZE))
1147 /* Set to auto so panning works for mono, and multi-channel works
1148 * as expected.
1150 alSourcei(source, AL_SOURCE_SPATIALIZE_SOFT, AL_AUTO_SOFT);
1152 checkALError();
1154 hr = S_OK;
1156 out:
1157 This->init_done = SUCCEEDED(hr);
1159 popALContext();
1160 LeaveCriticalSection(&This->share->crst);
1162 return hr;
1165 static HRESULT WINAPI DS8Buffer_Lock(IDirectSoundBuffer8 *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
1167 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1168 DWORD remain;
1170 TRACE("(%p)->(%lu, %lu, %p, %p, %p, %p, 0x%lx)\n", This, ofs, bytes, ptr1, len1, ptr2, len2, flags);
1172 if(!ptr1 || !len1)
1174 WARN("Invalid pointer/len %p %p\n", ptr1, len1);
1175 return DSERR_INVALIDPARAM;
1178 *ptr1 = NULL;
1179 *len1 = 0;
1180 if(ptr2) *ptr2 = NULL;
1181 if(len2) *len2 = 0;
1183 if((flags&DSBLOCK_FROMWRITECURSOR))
1184 DS8Buffer_GetCurrentPosition(iface, NULL, &ofs);
1185 else if(ofs >= (DWORD)This->buffer->buf_size)
1187 WARN("Invalid ofs %lu\n", ofs);
1188 return DSERR_INVALIDPARAM;
1190 if((flags&DSBLOCK_ENTIREBUFFER))
1191 bytes = This->buffer->buf_size;
1192 else if(bytes > (DWORD)This->buffer->buf_size)
1194 WARN("Invalid size %lu\n", bytes);
1195 return DSERR_INVALIDPARAM;
1198 if(InterlockedExchange(&This->buffer->locked, TRUE) == TRUE)
1200 WARN("Already locked\n");
1201 return DSERR_INVALIDPARAM;
1204 *ptr1 = This->buffer->data + ofs;
1205 if(bytes >= (DWORD)This->buffer->buf_size-ofs)
1207 *len1 = This->buffer->buf_size - ofs;
1208 remain = bytes - *len1;
1210 else
1212 *len1 = bytes;
1213 remain = 0;
1216 if(ptr2 && len2 && remain)
1218 *ptr2 = This->buffer->data;
1219 *len2 = remain;
1222 return DS_OK;
1225 static HRESULT WINAPI DS8Buffer_Play(IDirectSoundBuffer8 *iface, DWORD res1, DWORD prio, DWORD flags)
1227 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1228 ALint state = AL_STOPPED;
1229 DS8Data *data;
1230 HRESULT hr;
1232 TRACE("(%p)->(%lu, %lu, %lu)\n", iface, res1, prio, flags);
1234 EnterCriticalSection(&This->share->crst);
1235 setALContext(This->ctx);
1237 hr = DSERR_BUFFERLOST;
1238 if(This->bufferlost)
1240 WARN("Buffer %p lost\n", This);
1241 goto out;
1244 data = This->buffer;
1245 if((data->dsbflags&DSBCAPS_LOCDEFER))
1247 if((flags&DSBPLAY_LOCSOFTWARE))
1248 This->loc_status = DSBSTATUS_LOCSOFTWARE;
1249 else
1250 This->loc_status = DSBSTATUS_LOCHARDWARE;
1252 else if(prio)
1254 ERR("Invalid priority set for non-deferred buffer %p, %lu!\n", This->buffer, prio);
1255 hr = DSERR_INVALIDPARAM;
1256 goto out;
1259 if(This->segsize != 0)
1261 This->islooping = !!(flags&DSBPLAY_LOOPING);
1262 if(This->isplaying) state = AL_PLAYING;
1264 else
1266 alSourcei(This->source, AL_LOOPING, (flags&DSBPLAY_LOOPING) ? AL_TRUE : AL_FALSE);
1267 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1269 checkALError();
1271 hr = S_OK;
1272 if(state == AL_PLAYING)
1273 goto out;
1275 if(This->segsize == 0)
1277 if(state != AL_PAUSED)
1278 alSourcei(This->source, AL_BUFFER, data->bid);
1279 alSourcePlay(This->source);
1281 else
1283 alSourceRewind(This->source);
1284 alSourcei(This->source, AL_BUFFER, 0);
1285 This->queue_base = This->data_offset % data->buf_size;
1286 This->curidx = 0;
1288 if(alGetError() != AL_NO_ERROR)
1290 ERR("Couldn't start source\n");
1291 alSourcei(This->source, AL_BUFFER, 0);
1292 checkALError();
1293 hr = DSERR_GENERIC;
1294 goto out;
1296 This->isplaying = TRUE;
1297 This->playflags = flags;
1299 if(This->nnotify)
1300 DS8Buffer_addnotify(This);
1302 out:
1303 popALContext();
1304 LeaveCriticalSection(&This->share->crst);
1305 return hr;
1308 static HRESULT WINAPI DS8Buffer_SetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD pos)
1310 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1311 DS8Data *data;
1313 TRACE("(%p)->(%lu)\n", iface, pos);
1315 data = This->buffer;
1316 if(pos >= (DWORD)data->buf_size)
1317 return DSERR_INVALIDPARAM;
1318 pos -= pos%data->format.Format.nBlockAlign;
1320 EnterCriticalSection(&This->share->crst);
1322 if(This->segsize != 0)
1324 if(This->isplaying)
1326 setALContext(This->ctx);
1327 /* Perform a flush, so the next timer update will restart at the
1328 * proper position */
1329 alSourceRewind(This->source);
1330 alSourcei(This->source, AL_BUFFER, 0);
1331 checkALError();
1332 popALContext();
1334 This->queue_base = This->data_offset = pos;
1335 This->curidx = 0;
1337 else
1339 setALContext(This->ctx);
1340 alSourcei(This->source, AL_BYTE_OFFSET, pos);
1341 checkALError();
1342 popALContext();
1344 This->lastpos = pos;
1346 LeaveCriticalSection(&This->share->crst);
1347 return DS_OK;
1350 static HRESULT WINAPI DS8Buffer_SetFormat(IDirectSoundBuffer8 *iface, const WAVEFORMATEX *wfx)
1352 /* This call only works on primary buffers */
1353 WARN("(%p)->(%p)\n", iface, wfx);
1354 return DSERR_INVALIDCALL;
1357 static HRESULT WINAPI DS8Buffer_SetVolume(IDirectSoundBuffer8 *iface, LONG vol)
1359 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1360 HRESULT hr = S_OK;
1362 TRACE("(%p)->(%ld)\n", iface, vol);
1364 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
1366 WARN("Invalid volume (%ld)\n", vol);
1367 return DSERR_INVALIDPARAM;
1370 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
1371 hr = DSERR_CONTROLUNAVAIL;
1372 if(SUCCEEDED(hr))
1374 ALfloat fvol = mB_to_gain(vol);
1375 setALContext(This->ctx);
1376 alSourcef(This->source, AL_GAIN, fvol);
1377 popALContext();
1380 return hr;
1383 static HRESULT WINAPI DS8Buffer_SetPan(IDirectSoundBuffer8 *iface, LONG pan)
1385 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1386 HRESULT hr = S_OK;
1388 TRACE("(%p)->(%ld)\n", iface, pan);
1390 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
1392 WARN("invalid parameter: pan = %ld\n", pan);
1393 return DSERR_INVALIDPARAM;
1396 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
1397 hr = DSERR_CONTROLUNAVAIL;
1398 else
1400 if(!(This->buffer->dsbflags&DSBCAPS_CTRL3D))
1402 ALfloat pos[3];
1403 pos[0] = (ALfloat)(pan-DSBPAN_LEFT)/(ALfloat)(DSBPAN_RIGHT-DSBPAN_LEFT) - 0.5f;
1404 pos[1] = 0.0f;
1405 /* NOTE: Strict movement along the X plane can cause the sound to
1406 * jump between left and right sharply. Using a curved path helps
1407 * smooth it out.
1409 pos[2] = -sqrtf(1.0f - pos[0]*pos[0]);
1411 setALContext(This->ctx);
1412 alSourcefv(This->source, AL_POSITION, pos);
1413 checkALError();
1414 popALContext();
1418 return hr;
1421 static HRESULT WINAPI DS8Buffer_SetFrequency(IDirectSoundBuffer8 *iface, DWORD freq)
1423 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1424 HRESULT hr = S_OK;
1426 TRACE("(%p)->(%lu)\n", iface, freq);
1428 if(freq < DSBFREQUENCY_MIN || freq > DSBFREQUENCY_MAX)
1430 WARN("invalid parameter: freq = %lu\n", freq);
1431 return DSERR_INVALIDPARAM;
1434 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
1435 hr = DSERR_CONTROLUNAVAIL;
1436 else
1438 ALfloat pitch = 1.0f;
1439 if(freq != DSBFREQUENCY_ORIGINAL)
1440 pitch = freq / (ALfloat)This->buffer->format.Format.nSamplesPerSec;
1442 setALContext(This->ctx);
1443 alSourcef(This->source, AL_PITCH, pitch);
1444 checkALError();
1445 popALContext();
1448 return hr;
1451 static HRESULT WINAPI DS8Buffer_Stop(IDirectSoundBuffer8 *iface)
1453 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1455 TRACE("(%p)->()\n", iface);
1457 EnterCriticalSection(&This->share->crst);
1458 setALContext(This->ctx);
1460 alSourcePause(This->source);
1461 checkALError();
1463 This->isplaying = FALSE;
1464 DS8Primary_triggernots(This->primary);
1466 popALContext();
1467 LeaveCriticalSection(&This->share->crst);
1469 return S_OK;
1472 static HRESULT WINAPI DS8Buffer_Unlock(IDirectSoundBuffer8 *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
1474 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1475 DS8Data *buf = This->buffer;
1476 DWORD bufsize = buf->buf_size;
1477 DWORD_PTR ofs1, ofs2;
1478 DWORD_PTR boundary = (DWORD_PTR)buf->data;
1479 HRESULT hr;
1481 TRACE("(%p)->(%p, %lu, %p, %lu)\n", iface, ptr1, len1, ptr2, len2);
1483 if(InterlockedExchange(&buf->locked, FALSE) == FALSE)
1485 WARN("Not locked\n");
1486 return DSERR_INVALIDPARAM;
1489 hr = DSERR_INVALIDPARAM;
1490 /* Make sure offset is between boundary and boundary + bufsize */
1491 ofs1 = (DWORD_PTR)ptr1;
1492 ofs2 = (DWORD_PTR)ptr2;
1493 if(ofs1 < boundary || (ofs2 && ofs2 != boundary))
1494 goto out;
1495 ofs1 -= boundary;
1496 ofs2 = 0;
1497 if(bufsize-ofs1 < len1 || len2 > ofs1)
1498 goto out;
1499 if(!ptr2)
1500 len2 = 0;
1502 hr = DS_OK;
1503 if(!len1 && !len2)
1504 goto out;
1506 if(HAS_EXTENSION(This->share, SOFTX_MAP_BUFFER))
1508 setALContext(This->ctx);
1509 alFlushMappedBufferSOFT(buf->bid, 0, buf->buf_size);
1510 checkALError();
1511 popALContext();
1513 else if(This->segsize == 0)
1515 setALContext(This->ctx);
1516 alBufferData(buf->bid, buf->buf_format, buf->data, buf->buf_size,
1517 buf->format.Format.nSamplesPerSec);
1518 checkALError();
1519 popALContext();
1522 out:
1523 if(hr != S_OK)
1524 WARN("Invalid parameters (0x%lx,%lu) (%p,%lu,%p,%lu)\n", boundary, bufsize, ptr1, len1, ptr2, len2);
1525 return hr;
1528 static HRESULT WINAPI DS8Buffer_Restore(IDirectSoundBuffer8 *iface)
1530 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1531 HRESULT hr;
1533 TRACE("(%p)->()\n", iface);
1535 EnterCriticalSection(&This->share->crst);
1536 if(This->primary->parent->prio_level < DSSCL_WRITEPRIMARY ||
1537 iface == This->primary->write_emu)
1539 This->bufferlost = 0;
1540 hr = S_OK;
1542 else
1543 hr = DSERR_BUFFERLOST;
1544 LeaveCriticalSection(&This->share->crst);
1546 return hr;
1549 static HRESULT WINAPI DS8Buffer_SetFX(IDirectSoundBuffer8 *iface, DWORD fxcount, DSEFFECTDESC *desc, DWORD *rescodes)
1551 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1552 ALenum state = AL_INITIAL;
1553 DS8Data *data;
1554 HRESULT hr;
1555 DWORD i;
1557 TRACE("(%p)->(%lu, %p, %p)\n", This, fxcount, desc, rescodes);
1559 data = This->buffer;
1560 if(!(data->dsbflags&DSBCAPS_CTRLFX))
1562 WARN("FX control not set\n");
1563 return DSERR_CONTROLUNAVAIL;
1566 if(data->locked)
1568 WARN("Buffer is locked\n");
1569 return DSERR_INVALIDCALL;
1572 EnterCriticalSection(&This->share->crst);
1573 setALContext(This->ctx);
1575 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1576 checkALError();
1577 if(This->segsize != 0 && state != AL_PLAYING)
1578 state = This->isplaying ? AL_PLAYING : AL_PAUSED;
1579 if(state == AL_PLAYING)
1581 WARN("Buffer is playing\n");
1582 hr = DSERR_INVALIDCALL;
1583 goto done;
1586 hr = DSERR_INVALIDPARAM;
1587 if(fxcount == 0)
1589 if(desc || rescodes)
1591 WARN("Non-NULL desc and/or result pointer specified with no effects.\n");
1592 goto done;
1595 /* No effects; we can handle that */
1596 hr = DS_OK;
1597 goto done;
1600 if(!desc || !rescodes)
1602 WARN("NULL desc and/or result pointer specified.\n");
1603 goto done;
1606 /* We don't (currently) handle DSound effects */
1607 for(i = 0;i < fxcount;++i)
1609 FIXME("Cannot handle effect: %s\n", debugstr_guid(&desc[i].guidDSFXClass));
1610 rescodes[i] = DSFXR_FAILED;
1612 hr = DS_INCOMPLETE;
1614 done:
1615 popALContext();
1616 LeaveCriticalSection(&This->share->crst);
1618 return hr;
1621 static HRESULT WINAPI DS8Buffer_AcquireResources(IDirectSoundBuffer8 *iface, DWORD flags, DWORD fxcount, DWORD *rescodes)
1623 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1625 TRACE("(%p)->(%lu, %lu, %p)\n", This, flags, fxcount, rescodes);
1627 /* effects aren't supported at the moment.. */
1628 if(fxcount != 0 || rescodes)
1630 WARN("Non-zero effect count and/or result pointer specified with no effects.\n");
1631 return DSERR_INVALIDPARAM;
1634 EnterCriticalSection(&This->share->crst);
1635 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1637 if((flags&DSBPLAY_LOCSOFTWARE))
1638 This->loc_status = DSBSTATUS_LOCSOFTWARE;
1639 else
1640 This->loc_status = DSBSTATUS_LOCHARDWARE;
1642 LeaveCriticalSection(&This->share->crst);
1644 return S_OK;
1647 static HRESULT WINAPI DS8Buffer_GetObjectInPath(IDirectSoundBuffer8 *iface, REFGUID guid, DWORD idx, REFGUID rguidiface, void **ppv)
1649 FIXME("(%p)->(%s, %lu, %s, %p) : stub!\n", iface, debugstr_guid(guid), idx, debugstr_guid(rguidiface), ppv);
1650 return E_NOTIMPL;
1653 static const IDirectSoundBuffer8Vtbl DS8Buffer_Vtbl = {
1654 DS8Buffer_QueryInterface,
1655 DS8Buffer_AddRef,
1656 DS8Buffer_Release,
1657 DS8Buffer_GetCaps,
1658 DS8Buffer_GetCurrentPosition,
1659 DS8Buffer_GetFormat,
1660 DS8Buffer_GetVolume,
1661 DS8Buffer_GetPan,
1662 DS8Buffer_GetFrequency,
1663 DS8Buffer_GetStatus,
1664 DS8Buffer_Initialize,
1665 DS8Buffer_Lock,
1666 DS8Buffer_Play,
1667 DS8Buffer_SetCurrentPosition,
1668 DS8Buffer_SetFormat,
1669 DS8Buffer_SetVolume,
1670 DS8Buffer_SetPan,
1671 DS8Buffer_SetFrequency,
1672 DS8Buffer_Stop,
1673 DS8Buffer_Unlock,
1674 DS8Buffer_Restore,
1675 DS8Buffer_SetFX,
1676 DS8Buffer_AcquireResources,
1677 DS8Buffer_GetObjectInPath
1681 void DS8Buffer_SetParams(DS8Buffer *This, const DS3DBUFFER *params, const EAX30BUFFERPROPERTIES *eax_params, LONG flags)
1683 DS8Primary *prim = This->primary;
1684 const ALuint source = This->source;
1685 union BufferParamFlags dirty = { flags };
1687 if(dirty.bit.pos)
1688 alSource3f(source, AL_POSITION, params->vPosition.x, params->vPosition.y,
1689 -params->vPosition.z);
1690 if(dirty.bit.vel)
1691 alSource3f(source, AL_VELOCITY, params->vVelocity.x, params->vVelocity.y,
1692 -params->vVelocity.z);
1693 if(dirty.bit.cone_angles)
1695 alSourcei(source, AL_CONE_INNER_ANGLE, params->dwInsideConeAngle);
1696 alSourcei(source, AL_CONE_OUTER_ANGLE, params->dwOutsideConeAngle);
1698 if(dirty.bit.cone_orient)
1699 alSource3f(source, AL_DIRECTION, params->vConeOrientation.x,
1700 params->vConeOrientation.y,
1701 -params->vConeOrientation.z);
1702 if(dirty.bit.cone_outsidevolume)
1703 alSourcef(source, AL_CONE_OUTER_GAIN, mB_to_gain(params->lConeOutsideVolume));
1704 if(dirty.bit.min_distance)
1705 alSourcef(source, AL_REFERENCE_DISTANCE, params->flMinDistance);
1706 if(dirty.bit.max_distance)
1707 alSourcef(source, AL_MAX_DISTANCE, params->flMaxDistance);
1708 if(dirty.bit.mode)
1710 This->ds3dmode = params->dwMode;
1711 if(HAS_EXTENSION(This->share, SOFT_SOURCE_SPATIALIZE))
1712 alSourcei(source, AL_SOURCE_SPATIALIZE_SOFT,
1713 (params->dwMode==DS3DMODE_DISABLE) ? AL_FALSE : AL_TRUE);
1714 alSourcei(source, AL_SOURCE_RELATIVE, (params->dwMode!=DS3DMODE_NORMAL) ?
1715 AL_TRUE : AL_FALSE);
1716 alSourcef(source, AL_ROLLOFF_FACTOR, (params->dwMode==DS3DMODE_DISABLE) ?
1717 0.0f : prim->rollofffactor);
1720 if(dirty.bit.dry_filter)
1721 alSourcei(source, AL_DIRECT_FILTER, This->filter[0]);
1722 if(dirty.bit.wet_filter)
1723 alSource3i(source, AL_AUXILIARY_SEND_FILTER, prim->auxslot, 0, This->filter[1]);
1724 if(dirty.bit.doppler)
1725 alSourcef(source, AL_DOPPLER_FACTOR, eax_params->flDopplerFactor);
1726 if(dirty.bit.rolloff)
1728 This->rollofffactor = eax_params->flRolloffFactor;
1729 alSourcef(source, AL_ROLLOFF_FACTOR, eax_params->flRolloffFactor + prim->rollofffactor);
1731 if(dirty.bit.room_rolloff)
1732 alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, eax_params->flRoomRolloffFactor);
1733 if(dirty.bit.cone_outsidevolumehf)
1734 alSourcef(source, AL_CONE_OUTER_GAINHF, mB_to_gain(eax_params->lOutsideVolumeHF));
1735 if(dirty.bit.air_absorb)
1736 alSourcef(source, AL_AIR_ABSORPTION_FACTOR, eax_params->flAirAbsorptionFactor);
1737 if(dirty.bit.flags)
1739 alSourcei(source, AL_DIRECT_FILTER_GAINHF_AUTO,
1740 (eax_params->dwFlags&EAX30BUFFERFLAGS_DIRECTHFAUTO) ? AL_TRUE : AL_FALSE);
1741 alSourcei(source, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
1742 (eax_params->dwFlags&EAX30BUFFERFLAGS_ROOMAUTO) ? AL_TRUE : AL_FALSE);
1743 alSourcei(source, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
1744 (eax_params->dwFlags&EAX30BUFFERFLAGS_ROOMHFAUTO) ? AL_TRUE : AL_FALSE);
1748 static HRESULT WINAPI DS8Buffer3D_QueryInterface(IDirectSound3DBuffer *iface, REFIID riid, void **ppv)
1750 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1751 return DS8Buffer_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
1754 static ULONG WINAPI DS8Buffer3D_AddRef(IDirectSound3DBuffer *iface)
1756 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1757 LONG ret;
1759 InterlockedIncrement(&This->all_ref);
1760 ret = InterlockedIncrement(&This->ds3d_ref);
1761 TRACE("new refcount %ld\n", ret);
1763 return ret;
1766 static ULONG WINAPI DS8Buffer3D_Release(IDirectSound3DBuffer *iface)
1768 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1769 LONG ret;
1771 ret = InterlockedDecrement(&This->ds3d_ref);
1772 TRACE("new refcount %ld\n", ret);
1773 if(InterlockedDecrement(&This->all_ref) == 0)
1774 DS8Buffer_Destroy(This);
1776 return ret;
1779 static HRESULT WINAPI DS8Buffer3D_GetConeAngles(IDirectSound3DBuffer *iface, DWORD *pdwInsideConeAngle, DWORD *pdwOutsideConeAngle)
1781 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1782 ALint inangle, outangle;
1784 TRACE("(%p)->(%p, %p)\n", This, pdwInsideConeAngle, pdwOutsideConeAngle);
1785 if(!pdwInsideConeAngle || !pdwOutsideConeAngle)
1787 WARN("Invalid pointers (%p, %p)\n", pdwInsideConeAngle, pdwOutsideConeAngle);
1788 return DSERR_INVALIDPARAM;
1791 EnterCriticalSection(&This->share->crst);
1792 setALContext(This->ctx);
1794 alGetSourcei(This->source, AL_CONE_INNER_ANGLE, &inangle);
1795 alGetSourcei(This->source, AL_CONE_OUTER_ANGLE, &outangle);
1796 checkALError();
1798 popALContext();
1799 LeaveCriticalSection(&This->share->crst);
1801 *pdwInsideConeAngle = inangle;
1802 *pdwOutsideConeAngle = outangle;
1803 return S_OK;
1806 static HRESULT WINAPI DS8Buffer3D_GetConeOrientation(IDirectSound3DBuffer *iface, D3DVECTOR *orient)
1808 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1809 ALfloat dir[3];
1811 TRACE("(%p)->(%p)\n", This, orient);
1812 if(!orient)
1814 WARN("Invalid pointer\n");
1815 return DSERR_INVALIDPARAM;
1818 setALContext(This->ctx);
1819 alGetSourcefv(This->source, AL_DIRECTION, dir);
1820 checkALError();
1821 popALContext();
1823 orient->x = dir[0];
1824 orient->y = dir[1];
1825 orient->z = -dir[2];
1826 return S_OK;
1829 static HRESULT WINAPI DS8Buffer3D_GetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG *vol)
1831 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1832 ALfloat gain;
1834 TRACE("(%p)->(%p)\n", This, vol);
1835 if(!vol)
1837 WARN("Invalid pointer\n");
1838 return DSERR_INVALIDPARAM;
1841 setALContext(This->ctx);
1842 alGetSourcef(This->source, AL_CONE_OUTER_GAIN, &gain);
1843 checkALError();
1844 popALContext();
1846 *vol = clampI(gain_to_mB(gain), DSBVOLUME_MIN, DSBVOLUME_MAX);
1847 return S_OK;
1850 static HRESULT WINAPI DS8Buffer3D_GetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE *maxdist)
1852 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1853 ALfloat dist;
1855 TRACE("(%p)->(%p)\n", This, maxdist);
1856 if(!maxdist)
1858 WARN("Invalid pointer\n");
1859 return DSERR_INVALIDPARAM;
1862 setALContext(This->ctx);
1863 alGetSourcef(This->source, AL_MAX_DISTANCE, &dist);
1864 checkALError();
1865 popALContext();
1867 *maxdist = dist;
1868 return S_OK;
1871 static HRESULT WINAPI DS8Buffer3D_GetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE *mindist)
1873 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1874 ALfloat dist;
1876 TRACE("(%p)->(%p)\n", This, mindist);
1877 if(!mindist)
1879 WARN("Invalid pointer\n");
1880 return DSERR_INVALIDPARAM;
1883 setALContext(This->ctx);
1884 alGetSourcef(This->source, AL_REFERENCE_DISTANCE, &dist);
1885 checkALError();
1886 popALContext();
1888 *mindist = dist;
1889 return S_OK;
1892 static HRESULT WINAPI DS8Buffer3D_GetMode(IDirectSound3DBuffer *iface, DWORD *mode)
1894 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1896 TRACE("(%p)->(%p)\n", This, mode);
1897 if(!mode)
1899 WARN("Invalid pointer\n");
1900 return DSERR_INVALIDPARAM;
1903 EnterCriticalSection(&This->share->crst);
1904 *mode = This->ds3dmode;
1905 LeaveCriticalSection(&This->share->crst);
1907 return S_OK;
1910 static HRESULT WINAPI DS8Buffer3D_GetPosition(IDirectSound3DBuffer *iface, D3DVECTOR *pos)
1912 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1913 ALfloat alpos[3];
1915 TRACE("(%p)->(%p)\n", This, pos);
1916 if(!pos)
1918 WARN("Invalid pointer\n");
1919 return DSERR_INVALIDPARAM;
1922 setALContext(This->ctx);
1923 alGetSourcefv(This->source, AL_POSITION, alpos);
1924 checkALError();
1925 popALContext();
1927 pos->x = alpos[0];
1928 pos->y = alpos[1];
1929 pos->z = -alpos[2];
1930 return S_OK;
1933 static HRESULT WINAPI DS8Buffer3D_GetVelocity(IDirectSound3DBuffer *iface, D3DVECTOR *vel)
1935 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1936 ALfloat alvel[3];
1938 TRACE("(%p)->(%p)\n", This, vel);
1939 if(!vel)
1941 WARN("Invalid pointer\n");
1942 return DSERR_INVALIDPARAM;
1945 setALContext(This->ctx);
1946 alGetSourcefv(This->source, AL_VELOCITY, alvel);
1947 checkALError();
1948 popALContext();
1950 vel->x = alvel[0];
1951 vel->y = alvel[1];
1952 vel->z = -alvel[2];
1953 return S_OK;
1956 static HRESULT WINAPI DS8Buffer3D_GetAllParameters(IDirectSound3DBuffer *iface, DS3DBUFFER *ds3dbuffer)
1958 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1960 TRACE("(%p)->(%p)\n", iface, ds3dbuffer);
1962 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
1964 WARN("Invalid parameters %p %lu\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
1965 return DSERR_INVALIDPARAM;
1968 EnterCriticalSection(&This->share->crst);
1969 setALContext(This->ctx);
1971 DS8Buffer3D_GetPosition(iface, &ds3dbuffer->vPosition);
1972 DS8Buffer3D_GetVelocity(iface, &ds3dbuffer->vVelocity);
1973 DS8Buffer3D_GetConeAngles(iface, &ds3dbuffer->dwInsideConeAngle, &ds3dbuffer->dwOutsideConeAngle);
1974 DS8Buffer3D_GetConeOrientation(iface, &ds3dbuffer->vConeOrientation);
1975 DS8Buffer3D_GetConeOutsideVolume(iface, &ds3dbuffer->lConeOutsideVolume);
1976 DS8Buffer3D_GetMinDistance(iface, &ds3dbuffer->flMinDistance);
1977 DS8Buffer3D_GetMaxDistance(iface, &ds3dbuffer->flMaxDistance);
1978 DS8Buffer3D_GetMode(iface, &ds3dbuffer->dwMode);
1980 popALContext();
1981 LeaveCriticalSection(&This->share->crst);
1983 return DS_OK;
1986 static HRESULT WINAPI DS8Buffer3D_SetConeAngles(IDirectSound3DBuffer *iface, DWORD dwInsideConeAngle, DWORD dwOutsideConeAngle, DWORD apply)
1988 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1990 TRACE("(%p)->(%lu, %lu, %lu)\n", This, dwInsideConeAngle, dwOutsideConeAngle, apply);
1991 if(dwInsideConeAngle > DS3D_MAXCONEANGLE ||
1992 dwOutsideConeAngle > DS3D_MAXCONEANGLE)
1994 WARN("Invalid cone angles (%lu, %lu)\n", dwInsideConeAngle, dwOutsideConeAngle);
1995 return DSERR_INVALIDPARAM;
1998 EnterCriticalSection(&This->share->crst);
1999 if(apply == DS3D_DEFERRED)
2001 This->deferred.ds3d.dwInsideConeAngle = dwInsideConeAngle;
2002 This->deferred.ds3d.dwOutsideConeAngle = dwOutsideConeAngle;
2003 This->dirty.bit.cone_angles = 1;
2005 else
2007 setALContext(This->ctx);
2008 alSourcei(This->source, AL_CONE_INNER_ANGLE, dwInsideConeAngle);
2009 alSourcei(This->source, AL_CONE_OUTER_ANGLE, dwOutsideConeAngle);
2010 checkALError();
2011 popALContext();
2013 LeaveCriticalSection(&This->share->crst);
2015 return S_OK;
2018 static HRESULT WINAPI DS8Buffer3D_SetConeOrientation(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2020 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2022 TRACE("(%p)->(%f, %f, %f, %lu)\n", This, x, y, z, apply);
2024 if(apply == DS3D_DEFERRED)
2026 EnterCriticalSection(&This->share->crst);
2027 This->deferred.ds3d.vConeOrientation.x = x;
2028 This->deferred.ds3d.vConeOrientation.y = y;
2029 This->deferred.ds3d.vConeOrientation.z = z;
2030 This->dirty.bit.cone_orient = 1;
2031 LeaveCriticalSection(&This->share->crst);
2033 else
2035 setALContext(This->ctx);
2036 alSource3f(This->source, AL_DIRECTION, x, y, -z);
2037 checkALError();
2038 popALContext();
2041 return S_OK;
2044 static HRESULT WINAPI DS8Buffer3D_SetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG vol, DWORD apply)
2046 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2048 TRACE("(%p)->(%ld, %lu)\n", This, vol, apply);
2049 if(vol < DSBVOLUME_MIN || vol > DSBVOLUME_MAX)
2051 WARN("Invalid volume (%ld)\n", vol);
2052 return DSERR_INVALIDPARAM;
2055 if(apply == DS3D_DEFERRED)
2057 EnterCriticalSection(&This->share->crst);
2058 This->deferred.ds3d.lConeOutsideVolume = vol;
2059 This->dirty.bit.cone_outsidevolume = 1;
2060 LeaveCriticalSection(&This->share->crst);
2062 else
2064 setALContext(This->ctx);
2065 alSourcef(This->source, AL_CONE_OUTER_GAIN, mB_to_gain(vol));
2066 checkALError();
2067 popALContext();
2070 return S_OK;
2073 static HRESULT WINAPI DS8Buffer3D_SetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE maxdist, DWORD apply)
2075 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2077 TRACE("(%p)->(%f, %lu)\n", This, maxdist, apply);
2078 if(maxdist < 0.0f)
2080 WARN("Invalid max distance (%f)\n", maxdist);
2081 return DSERR_INVALIDPARAM;
2084 if(apply == DS3D_DEFERRED)
2086 EnterCriticalSection(&This->share->crst);
2087 This->deferred.ds3d.flMaxDistance = maxdist;
2088 This->dirty.bit.max_distance = 1;
2089 LeaveCriticalSection(&This->share->crst);
2091 else
2093 setALContext(This->ctx);
2094 alSourcef(This->source, AL_MAX_DISTANCE, maxdist);
2095 checkALError();
2096 popALContext();
2099 return S_OK;
2102 static HRESULT WINAPI DS8Buffer3D_SetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE mindist, DWORD apply)
2104 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2106 TRACE("(%p)->(%f, %lu)\n", This, mindist, apply);
2107 if(mindist < 0.0f)
2109 WARN("Invalid min distance (%f)\n", mindist);
2110 return DSERR_INVALIDPARAM;
2113 if(apply == DS3D_DEFERRED)
2115 EnterCriticalSection(&This->share->crst);
2116 This->deferred.ds3d.flMinDistance = mindist;
2117 This->dirty.bit.min_distance = 1;
2118 LeaveCriticalSection(&This->share->crst);
2120 else
2122 setALContext(This->ctx);
2123 alSourcef(This->source, AL_REFERENCE_DISTANCE, mindist);
2124 checkALError();
2125 popALContext();
2128 return S_OK;
2131 static HRESULT WINAPI DS8Buffer3D_SetMode(IDirectSound3DBuffer *iface, DWORD mode, DWORD apply)
2133 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2135 TRACE("(%p)->(%lu, %lu)\n", This, mode, apply);
2136 if(mode != DS3DMODE_NORMAL && mode != DS3DMODE_HEADRELATIVE &&
2137 mode != DS3DMODE_DISABLE)
2139 WARN("Invalid mode (%lu)\n", mode);
2140 return DSERR_INVALIDPARAM;
2143 EnterCriticalSection(&This->share->crst);
2144 if(apply == DS3D_DEFERRED)
2146 This->deferred.ds3d.dwMode = mode;
2147 This->dirty.bit.mode = 1;
2149 else
2151 DS8Primary *prim = This->primary;
2153 setALContext(This->ctx);
2154 This->ds3dmode = mode;
2155 if(HAS_EXTENSION(This->share, SOFT_SOURCE_SPATIALIZE))
2156 alSourcei(This->source, AL_SOURCE_SPATIALIZE_SOFT,
2157 (mode==DS3DMODE_DISABLE) ? AL_FALSE : AL_TRUE);
2158 alSourcei(This->source, AL_SOURCE_RELATIVE,
2159 (mode != DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE);
2160 alSourcef(This->source, AL_ROLLOFF_FACTOR,
2161 (mode == DS3DMODE_DISABLE) ? 0.0f : prim->rollofffactor);
2162 checkALError();
2163 popALContext();
2165 LeaveCriticalSection(&This->share->crst);
2167 return S_OK;
2170 static HRESULT WINAPI DS8Buffer3D_SetPosition(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2172 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2174 TRACE("(%p)->(%f, %f, %f, %lu)\n", This, x, y, z, apply);
2176 if(apply == DS3D_DEFERRED)
2178 EnterCriticalSection(&This->share->crst);
2179 This->deferred.ds3d.vPosition.x = x;
2180 This->deferred.ds3d.vPosition.y = y;
2181 This->deferred.ds3d.vPosition.z = z;
2182 This->dirty.bit.pos = 1;
2183 LeaveCriticalSection(&This->share->crst);
2185 else
2187 setALContext(This->ctx);
2188 alSource3f(This->source, AL_POSITION, x, y, -z);
2189 checkALError();
2190 popALContext();
2193 return S_OK;
2196 static HRESULT WINAPI DS8Buffer3D_SetVelocity(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2198 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2200 TRACE("(%p)->(%f, %f, %f, %lu)\n", This, x, y, z, apply);
2202 if(apply == DS3D_DEFERRED)
2204 EnterCriticalSection(&This->share->crst);
2205 This->deferred.ds3d.vVelocity.x = x;
2206 This->deferred.ds3d.vVelocity.y = y;
2207 This->deferred.ds3d.vVelocity.z = z;
2208 This->dirty.bit.vel = 1;
2209 LeaveCriticalSection(&This->share->crst);
2211 else
2213 setALContext(This->ctx);
2214 alSource3f(This->source, AL_VELOCITY, x, y, -z);
2215 checkALError();
2216 popALContext();
2219 return S_OK;
2222 static HRESULT WINAPI DS8Buffer3D_SetAllParameters(IDirectSound3DBuffer *iface, const DS3DBUFFER *ds3dbuffer, DWORD apply)
2224 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2225 TRACE("(%p)->(%p, %lu)\n", This, ds3dbuffer, apply);
2227 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
2229 WARN("Invalid DS3DBUFFER (%p, %lu)\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
2230 return DSERR_INVALIDPARAM;
2233 if(ds3dbuffer->dwInsideConeAngle > DS3D_MAXCONEANGLE ||
2234 ds3dbuffer->dwOutsideConeAngle > DS3D_MAXCONEANGLE)
2236 WARN("Invalid cone angles (%lu, %lu)\n",
2237 ds3dbuffer->dwInsideConeAngle, ds3dbuffer->dwOutsideConeAngle);
2238 return DSERR_INVALIDPARAM;
2241 if(ds3dbuffer->lConeOutsideVolume > DSBVOLUME_MAX ||
2242 ds3dbuffer->lConeOutsideVolume < DSBVOLUME_MIN)
2244 WARN("Invalid cone outside volume (%ld)\n", ds3dbuffer->lConeOutsideVolume);
2245 return DSERR_INVALIDPARAM;
2248 if(ds3dbuffer->flMaxDistance < 0.0f)
2250 WARN("Invalid max distance (%f)\n", ds3dbuffer->flMaxDistance);
2251 return DSERR_INVALIDPARAM;
2254 if(ds3dbuffer->flMinDistance < 0.0f)
2256 WARN("Invalid min distance (%f)\n", ds3dbuffer->flMinDistance);
2257 return DSERR_INVALIDPARAM;
2260 if(ds3dbuffer->dwMode != DS3DMODE_NORMAL &&
2261 ds3dbuffer->dwMode != DS3DMODE_HEADRELATIVE &&
2262 ds3dbuffer->dwMode != DS3DMODE_DISABLE)
2264 WARN("Invalid mode (%lu)\n", ds3dbuffer->dwMode);
2265 return DSERR_INVALIDPARAM;
2268 if(apply == DS3D_DEFERRED)
2270 EnterCriticalSection(&This->share->crst);
2271 This->deferred.ds3d = *ds3dbuffer;
2272 This->deferred.ds3d.dwSize = sizeof(This->deferred.ds3d);
2273 This->dirty.bit.pos = 1;
2274 This->dirty.bit.vel = 1;
2275 This->dirty.bit.cone_angles = 1;
2276 This->dirty.bit.cone_orient = 1;
2277 This->dirty.bit.cone_outsidevolume = 1;
2278 This->dirty.bit.min_distance = 1;
2279 This->dirty.bit.max_distance = 1;
2280 This->dirty.bit.mode = 1;
2281 LeaveCriticalSection(&This->share->crst);
2283 else
2285 union BufferParamFlags dirty = { 0 };
2286 dirty.bit.pos = 1;
2287 dirty.bit.vel = 1;
2288 dirty.bit.cone_angles = 1;
2289 dirty.bit.cone_orient = 1;
2290 dirty.bit.cone_outsidevolume = 1;
2291 dirty.bit.min_distance = 1;
2292 dirty.bit.max_distance = 1;
2293 dirty.bit.mode = 1;
2295 EnterCriticalSection(&This->share->crst);
2296 setALContext(This->ctx);
2297 DS8Buffer_SetParams(This, ds3dbuffer, NULL, dirty.flags);
2298 checkALError();
2299 popALContext();
2300 LeaveCriticalSection(&This->share->crst);
2303 return S_OK;
2306 static const IDirectSound3DBufferVtbl DS8Buffer3d_Vtbl =
2308 DS8Buffer3D_QueryInterface,
2309 DS8Buffer3D_AddRef,
2310 DS8Buffer3D_Release,
2311 DS8Buffer3D_GetAllParameters,
2312 DS8Buffer3D_GetConeAngles,
2313 DS8Buffer3D_GetConeOrientation,
2314 DS8Buffer3D_GetConeOutsideVolume,
2315 DS8Buffer3D_GetMaxDistance,
2316 DS8Buffer3D_GetMinDistance,
2317 DS8Buffer3D_GetMode,
2318 DS8Buffer3D_GetPosition,
2319 DS8Buffer3D_GetVelocity,
2320 DS8Buffer3D_SetAllParameters,
2321 DS8Buffer3D_SetConeAngles,
2322 DS8Buffer3D_SetConeOrientation,
2323 DS8Buffer3D_SetConeOutsideVolume,
2324 DS8Buffer3D_SetMaxDistance,
2325 DS8Buffer3D_SetMinDistance,
2326 DS8Buffer3D_SetMode,
2327 DS8Buffer3D_SetPosition,
2328 DS8Buffer3D_SetVelocity
2332 static HRESULT WINAPI DS8BufferNot_QueryInterface(IDirectSoundNotify *iface, REFIID riid, void **ppv)
2334 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2335 return DS8Buffer_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2338 static ULONG WINAPI DS8BufferNot_AddRef(IDirectSoundNotify *iface)
2340 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2341 LONG ret;
2343 InterlockedIncrement(&This->all_ref);
2344 ret = InterlockedIncrement(&This->not_ref);
2345 TRACE("new refcount %ld\n", ret);
2347 return ret;
2350 static ULONG WINAPI DS8BufferNot_Release(IDirectSoundNotify *iface)
2352 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2353 LONG ret;
2355 ret = InterlockedDecrement(&This->not_ref);
2356 TRACE("new refcount %ld\n", ret);
2357 if(InterlockedDecrement(&This->all_ref) == 0)
2358 DS8Buffer_Destroy(This);
2360 return ret;
2363 static HRESULT WINAPI DS8BufferNot_SetNotificationPositions(IDirectSoundNotify *iface, DWORD count, const DSBPOSITIONNOTIFY *notifications)
2365 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2366 DSBPOSITIONNOTIFY *nots;
2367 DWORD state;
2368 HRESULT hr;
2370 TRACE("(%p)->(%lu, %p))\n", iface, count, notifications);
2372 EnterCriticalSection(&This->share->crst);
2373 hr = DSERR_INVALIDPARAM;
2374 if(count && !notifications)
2375 goto out;
2377 hr = DS8Buffer_GetStatus(&This->IDirectSoundBuffer8_iface, &state);
2378 if(FAILED(hr)) goto out;
2380 hr = DSERR_INVALIDCALL;
2381 if((state&DSBSTATUS_PLAYING))
2382 goto out;
2384 if(!count)
2386 HeapFree(GetProcessHeap(), 0, This->notify);
2387 This->notify = 0;
2388 This->nnotify = 0;
2389 hr = S_OK;
2391 else
2393 DWORD i;
2395 hr = DSERR_INVALIDPARAM;
2396 for(i = 0;i < count;++i)
2398 if(notifications[i].dwOffset >= (DWORD)This->buffer->buf_size &&
2399 notifications[i].dwOffset != (DWORD)DSBPN_OFFSETSTOP)
2400 goto out;
2403 hr = E_OUTOFMEMORY;
2404 nots = HeapAlloc(GetProcessHeap(), 0, count*sizeof(*nots));
2405 if(!nots) goto out;
2406 memcpy(nots, notifications, count*sizeof(*nots));
2408 HeapFree(GetProcessHeap(), 0, This->notify);
2409 This->notify = nots;
2410 This->nnotify = count;
2412 hr = S_OK;
2415 out:
2416 LeaveCriticalSection(&This->share->crst);
2417 return hr;
2420 static const IDirectSoundNotifyVtbl DS8BufferNot_Vtbl =
2422 DS8BufferNot_QueryInterface,
2423 DS8BufferNot_AddRef,
2424 DS8BufferNot_Release,
2425 DS8BufferNot_SetNotificationPositions
2429 static HRESULT WINAPI DS8BufferProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
2431 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2432 return DS8Buffer_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2435 static ULONG WINAPI DS8BufferProp_AddRef(IKsPropertySet *iface)
2437 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2438 LONG ret;
2440 InterlockedIncrement(&This->all_ref);
2441 ret = InterlockedIncrement(&This->prop_ref);
2442 TRACE("new refcount %ld\n", ret);
2444 return ret;
2447 static ULONG WINAPI DS8BufferProp_Release(IKsPropertySet *iface)
2449 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2450 LONG ret;
2452 ret = InterlockedDecrement(&This->prop_ref);
2453 TRACE("new refcount %ld\n", ret);
2454 if(InterlockedDecrement(&This->all_ref) == 0)
2455 DS8Buffer_Destroy(This);
2457 return ret;
2460 /* NOTE: Due to some apparent quirks in DSound, the listener properties are
2461 handled through secondary buffers. */
2462 static HRESULT WINAPI DS8BufferProp_Get(IKsPropertySet *iface,
2463 REFGUID guidPropSet, ULONG dwPropID,
2464 LPVOID pInstanceData, ULONG cbInstanceData,
2465 LPVOID pPropData, ULONG cbPropData,
2466 ULONG *pcbReturned)
2468 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2469 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2471 TRACE("(%p)->(%s, %lu, %p, %lu, %p, %lu, %p)\n", iface, debugstr_guid(guidPropSet),
2472 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData, pcbReturned);
2474 if(!pcbReturned)
2475 return E_POINTER;
2476 *pcbReturned = 0;
2478 if(cbPropData > 0 && !pPropData)
2480 WARN("pPropData is NULL with cbPropData > 0\n");
2481 return E_POINTER;
2484 EnterCriticalSection(&This->share->crst);
2485 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX30_BufferProperties))
2486 hr = EAX3Buffer_Get(This, dwPropID, pPropData, cbPropData, pcbReturned);
2487 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2488 hr = EAX2Buffer_Get(This, dwPropID, pPropData, cbPropData, pcbReturned);
2489 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX30_ListenerProperties))
2490 hr = EAX3_Get(This->primary, dwPropID, pPropData, cbPropData, pcbReturned);
2491 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
2492 hr = EAX2_Get(This->primary, dwPropID, pPropData, cbPropData, pcbReturned);
2493 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX10_BufferProperties))
2494 hr = EAX1Buffer_Get(This, dwPropID, pPropData, cbPropData, pcbReturned);
2495 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX10_ListenerProperties))
2496 hr = EAX1_Get(This->primary, dwPropID, pPropData, cbPropData, pcbReturned);
2497 else
2498 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2499 LeaveCriticalSection(&This->share->crst);
2501 return hr;
2504 static HRESULT WINAPI DS8BufferProp_Set(IKsPropertySet *iface,
2505 REFGUID guidPropSet, ULONG dwPropID,
2506 LPVOID pInstanceData, ULONG cbInstanceData,
2507 LPVOID pPropData, ULONG cbPropData)
2509 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2510 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2512 TRACE("(%p)->(%s, %lu, %p, %lu, %p, %lu)\n", iface, debugstr_guid(guidPropSet),
2513 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData);
2515 if(cbPropData > 0 && !pPropData)
2517 WARN("pPropData is NULL with cbPropData > 0\n");
2518 return E_POINTER;
2521 EnterCriticalSection(&This->share->crst);
2522 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX30_BufferProperties))
2524 DWORD propid = dwPropID & ~DSPROPERTY_EAX30BUFFER_DEFERRED;
2525 BOOL immediate = !(dwPropID&DSPROPERTY_EAX30BUFFER_DEFERRED);
2527 setALContext(This->ctx);
2528 hr = EAX3Buffer_Set(This, propid, pPropData, cbPropData);
2529 if(hr == DS_OK && immediate)
2531 DS8Primary *prim = This->primary;
2532 DS8Primary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
2534 popALContext();
2536 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2538 DWORD propid = dwPropID & ~DSPROPERTY_EAX20BUFFER_DEFERRED;
2539 BOOL immediate = !(dwPropID&DSPROPERTY_EAX20BUFFER_DEFERRED);
2541 setALContext(This->ctx);
2542 hr = EAX2Buffer_Set(This, propid, pPropData, cbPropData);
2543 if(hr == DS_OK && immediate)
2545 DS8Primary *prim = This->primary;
2546 DS8Primary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
2548 popALContext();
2550 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX30_ListenerProperties))
2552 DS8Primary *prim = This->primary;
2553 DWORD propid = dwPropID & ~DSPROPERTY_EAX30LISTENER_DEFERRED;
2554 BOOL immediate = !(dwPropID&DSPROPERTY_EAX30LISTENER_DEFERRED);
2556 setALContext(prim->ctx);
2557 hr = EAX3_Set(prim, propid, pPropData, cbPropData);
2558 if(hr == DS_OK && immediate)
2559 DS8Primary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
2560 popALContext();
2562 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
2564 DS8Primary *prim = This->primary;
2565 DWORD propid = dwPropID & ~DSPROPERTY_EAX20LISTENER_DEFERRED;
2566 BOOL immediate = !(dwPropID&DSPROPERTY_EAX20LISTENER_DEFERRED);
2568 setALContext(prim->ctx);
2569 hr = EAX2_Set(prim, propid, pPropData, cbPropData);
2570 if(hr == DS_OK && immediate)
2571 DS8Primary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
2572 popALContext();
2574 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX10_BufferProperties))
2576 DWORD propid = dwPropID & ~DSPROPERTY_EAX20BUFFER_DEFERRED;
2577 BOOL immediate = !(dwPropID&DSPROPERTY_EAX20BUFFER_DEFERRED);
2579 setALContext(This->ctx);
2580 hr = EAX1Buffer_Set(This, propid, pPropData, cbPropData);
2581 if(hr == DS_OK && immediate)
2583 DS8Primary *prim = This->primary;
2584 DS8Primary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
2586 popALContext();
2588 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX10_ListenerProperties))
2590 DS8Primary *prim = This->primary;
2591 DWORD propid = dwPropID & ~DSPROPERTY_EAX20LISTENER_DEFERRED;
2592 BOOL immediate = !(dwPropID&DSPROPERTY_EAX20LISTENER_DEFERRED);
2594 setALContext(prim->ctx);
2595 hr = EAX1_Set(prim, propid, pPropData, cbPropData);
2596 if(hr == DS_OK && immediate)
2597 DS8Primary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
2598 popALContext();
2600 else
2601 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2602 LeaveCriticalSection(&This->share->crst);
2604 return hr;
2607 static HRESULT WINAPI DS8BufferProp_QuerySupport(IKsPropertySet *iface,
2608 REFGUID guidPropSet, ULONG dwPropID,
2609 ULONG *pTypeSupport)
2611 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2612 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2614 TRACE("(%p)->(%s, %lu, %p)\n", iface, debugstr_guid(guidPropSet), dwPropID, pTypeSupport);
2616 if(!pTypeSupport)
2617 return E_POINTER;
2618 *pTypeSupport = 0;
2620 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX30_BufferProperties))
2622 EnterCriticalSection(&This->share->crst);
2624 if(This->filter[0] == 0)
2625 hr = E_PROP_ID_UNSUPPORTED;
2626 else switch(dwPropID)
2628 case DSPROPERTY_EAX30BUFFER_NONE:
2629 case DSPROPERTY_EAX30BUFFER_ALLPARAMETERS:
2630 case DSPROPERTY_EAX30BUFFER_OBSTRUCTIONPARAMETERS:
2631 case DSPROPERTY_EAX30BUFFER_OCCLUSIONPARAMETERS:
2632 case DSPROPERTY_EAX30BUFFER_EXCLUSIONPARAMETERS:
2633 case DSPROPERTY_EAX30BUFFER_DIRECT:
2634 case DSPROPERTY_EAX30BUFFER_DIRECTHF:
2635 case DSPROPERTY_EAX30BUFFER_ROOM:
2636 case DSPROPERTY_EAX30BUFFER_ROOMHF:
2637 case DSPROPERTY_EAX30BUFFER_OBSTRUCTION:
2638 case DSPROPERTY_EAX30BUFFER_OBSTRUCTIONLFRATIO:
2639 case DSPROPERTY_EAX30BUFFER_OCCLUSION:
2640 case DSPROPERTY_EAX30BUFFER_OCCLUSIONLFRATIO:
2641 case DSPROPERTY_EAX30BUFFER_OCCLUSIONROOMRATIO:
2642 case DSPROPERTY_EAX30BUFFER_OCCLUSIONDIRECTRATIO:
2643 case DSPROPERTY_EAX30BUFFER_EXCLUSION:
2644 case DSPROPERTY_EAX30BUFFER_EXCLUSIONLFRATIO:
2645 case DSPROPERTY_EAX30BUFFER_OUTSIDEVOLUMEHF:
2646 case DSPROPERTY_EAX30BUFFER_DOPPLERFACTOR:
2647 case DSPROPERTY_EAX30BUFFER_ROLLOFFFACTOR:
2648 case DSPROPERTY_EAX30BUFFER_ROOMROLLOFFFACTOR:
2649 case DSPROPERTY_EAX30BUFFER_AIRABSORPTIONFACTOR:
2650 case DSPROPERTY_EAX30BUFFER_FLAGS:
2651 *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET;
2652 hr = DS_OK;
2653 break;
2654 default:
2655 hr = E_PROP_ID_UNSUPPORTED;
2656 FIXME("Unhandled EAX3 buffer propid: 0x%08lx\n", dwPropID);
2657 break;
2660 LeaveCriticalSection(&This->share->crst);
2662 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2664 EnterCriticalSection(&This->share->crst);
2666 if(This->filter[0] == 0)
2667 hr = E_PROP_ID_UNSUPPORTED;
2668 else switch(dwPropID)
2670 case DSPROPERTY_EAX20BUFFER_NONE:
2671 case DSPROPERTY_EAX20BUFFER_ALLPARAMETERS:
2672 case DSPROPERTY_EAX20BUFFER_DIRECT:
2673 case DSPROPERTY_EAX20BUFFER_DIRECTHF:
2674 case DSPROPERTY_EAX20BUFFER_ROOM:
2675 case DSPROPERTY_EAX20BUFFER_ROOMHF:
2676 case DSPROPERTY_EAX20BUFFER_ROOMROLLOFFFACTOR:
2677 case DSPROPERTY_EAX20BUFFER_OBSTRUCTION:
2678 case DSPROPERTY_EAX20BUFFER_OBSTRUCTIONLFRATIO:
2679 case DSPROPERTY_EAX20BUFFER_OCCLUSION:
2680 case DSPROPERTY_EAX20BUFFER_OCCLUSIONLFRATIO:
2681 case DSPROPERTY_EAX20BUFFER_OCCLUSIONROOMRATIO:
2682 case DSPROPERTY_EAX20BUFFER_OUTSIDEVOLUMEHF:
2683 case DSPROPERTY_EAX20BUFFER_AIRABSORPTIONFACTOR:
2684 case DSPROPERTY_EAX20BUFFER_FLAGS:
2685 *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET;
2686 hr = DS_OK;
2687 break;
2688 default:
2689 hr = E_PROP_ID_UNSUPPORTED;
2690 FIXME("Unhandled EAX2 buffer propid: 0x%08lx\n", dwPropID);
2691 break;
2694 LeaveCriticalSection(&This->share->crst);
2696 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX30_ListenerProperties))
2698 DS8Primary *prim = This->primary;
2700 EnterCriticalSection(&This->share->crst);
2702 if(prim->effect == 0)
2703 hr = E_PROP_ID_UNSUPPORTED;
2704 else switch(dwPropID)
2706 case DSPROPERTY_EAX30LISTENER_NONE:
2707 case DSPROPERTY_EAX30LISTENER_ALLPARAMETERS:
2708 case DSPROPERTY_EAX30LISTENER_ENVIRONMENT:
2709 case DSPROPERTY_EAX30LISTENER_ENVIRONMENTSIZE:
2710 case DSPROPERTY_EAX30LISTENER_ENVIRONMENTDIFFUSION:
2711 case DSPROPERTY_EAX30LISTENER_ROOM:
2712 case DSPROPERTY_EAX30LISTENER_ROOMHF:
2713 case DSPROPERTY_EAX30LISTENER_ROOMLF:
2714 case DSPROPERTY_EAX30LISTENER_DECAYTIME:
2715 case DSPROPERTY_EAX30LISTENER_DECAYHFRATIO:
2716 case DSPROPERTY_EAX30LISTENER_DECAYLFRATIO:
2717 case DSPROPERTY_EAX30LISTENER_REFLECTIONS:
2718 case DSPROPERTY_EAX30LISTENER_REFLECTIONSDELAY:
2719 case DSPROPERTY_EAX30LISTENER_REFLECTIONSPAN:
2720 case DSPROPERTY_EAX30LISTENER_REVERB:
2721 case DSPROPERTY_EAX30LISTENER_REVERBDELAY:
2722 case DSPROPERTY_EAX30LISTENER_REVERBPAN:
2723 case DSPROPERTY_EAX30LISTENER_ECHOTIME:
2724 case DSPROPERTY_EAX30LISTENER_ECHODEPTH:
2725 case DSPROPERTY_EAX30LISTENER_MODULATIONTIME:
2726 case DSPROPERTY_EAX30LISTENER_MODULATIONDEPTH:
2727 case DSPROPERTY_EAX30LISTENER_AIRABSORPTIONHF:
2728 case DSPROPERTY_EAX30LISTENER_HFREFERENCE:
2729 case DSPROPERTY_EAX30LISTENER_LFREFERENCE:
2730 case DSPROPERTY_EAX30LISTENER_ROOMROLLOFFFACTOR:
2731 case DSPROPERTY_EAX30LISTENER_FLAGS:
2732 *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET;
2733 hr = DS_OK;
2734 break;
2735 default:
2736 hr = E_PROP_ID_UNSUPPORTED;
2737 FIXME("Unhandled EAX3 listener propid: 0x%08lx\n", dwPropID);
2738 break;
2741 LeaveCriticalSection(&This->share->crst);
2743 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
2745 DS8Primary *prim = This->primary;
2747 EnterCriticalSection(&This->share->crst);
2749 if(prim->effect == 0)
2750 hr = E_PROP_ID_UNSUPPORTED;
2751 else switch(dwPropID)
2753 case DSPROPERTY_EAX20LISTENER_NONE:
2754 case DSPROPERTY_EAX20LISTENER_ALLPARAMETERS:
2755 case DSPROPERTY_EAX20LISTENER_ROOM:
2756 case DSPROPERTY_EAX20LISTENER_ROOMHF:
2757 case DSPROPERTY_EAX20LISTENER_ROOMROLLOFFFACTOR:
2758 case DSPROPERTY_EAX20LISTENER_DECAYTIME:
2759 case DSPROPERTY_EAX20LISTENER_DECAYHFRATIO:
2760 case DSPROPERTY_EAX20LISTENER_REFLECTIONS:
2761 case DSPROPERTY_EAX20LISTENER_REFLECTIONSDELAY:
2762 case DSPROPERTY_EAX20LISTENER_REVERB:
2763 case DSPROPERTY_EAX20LISTENER_REVERBDELAY:
2764 case DSPROPERTY_EAX20LISTENER_ENVIRONMENT:
2765 case DSPROPERTY_EAX20LISTENER_ENVIRONMENTSIZE:
2766 case DSPROPERTY_EAX20LISTENER_ENVIRONMENTDIFFUSION:
2767 case DSPROPERTY_EAX20LISTENER_AIRABSORPTIONHF:
2768 case DSPROPERTY_EAX20LISTENER_FLAGS:
2769 *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET;
2770 hr = DS_OK;
2771 break;
2772 default:
2773 hr = E_PROP_ID_UNSUPPORTED;
2774 FIXME("Unhandled EAX2 listener propid: 0x%08lx\n", dwPropID);
2775 break;
2778 LeaveCriticalSection(&This->share->crst);
2780 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX10_ListenerProperties))
2782 DS8Primary *prim = This->primary;
2784 EnterCriticalSection(&This->share->crst);
2786 if(prim->effect == 0)
2787 hr = E_PROP_ID_UNSUPPORTED;
2788 else switch(dwPropID)
2790 case DSPROPERTY_EAX10LISTENER_ALL:
2791 case DSPROPERTY_EAX10LISTENER_ENVIRONMENT:
2792 case DSPROPERTY_EAX10LISTENER_VOLUME:
2793 case DSPROPERTY_EAX10LISTENER_DECAYTIME:
2794 case DSPROPERTY_EAX10LISTENER_DAMPING:
2795 *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET;
2796 hr = DS_OK;
2797 break;
2798 default:
2799 hr = E_PROP_ID_UNSUPPORTED;
2800 FIXME("Unhandled EAX1 listener propid: 0x%08lx\n", dwPropID);
2801 break;
2804 LeaveCriticalSection(&This->share->crst);
2806 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX10_BufferProperties))
2808 EnterCriticalSection(&This->share->crst);
2810 if(This->filter[0] == 0)
2811 hr = E_PROP_ID_UNSUPPORTED;
2812 else switch(dwPropID)
2814 case DSPROPERTY_EAX10BUFFER_ALL:
2815 case DSPROPERTY_EAX10BUFFER_REVERBMIX:
2816 *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET;
2817 hr = DS_OK;
2818 break;
2819 default:
2820 hr = E_PROP_ID_UNSUPPORTED;
2821 FIXME("Unhandled EAX1 buffer propid: 0x%08lx\n", dwPropID);
2822 break;
2825 LeaveCriticalSection(&This->share->crst);
2827 else
2828 FIXME("Unhandled propset: %s (propid: %lu)\n", debugstr_guid(guidPropSet), dwPropID);
2830 return hr;
2833 static const IKsPropertySetVtbl DS8BufferProp_Vtbl =
2835 DS8BufferProp_QueryInterface,
2836 DS8BufferProp_AddRef,
2837 DS8BufferProp_Release,
2838 DS8BufferProp_Get,
2839 DS8BufferProp_Set,
2840 DS8BufferProp_QuerySupport