Report the EAX last error as settable
[dsound-openal.git] / buffer.c
blobf30705f79719ee6e8f2c47ebe600f44de97d9dc1
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 DSBuffer_Vtbl;
49 static const IDirectSound3DBufferVtbl DSBuffer3d_Vtbl;
50 static const IDirectSoundNotifyVtbl DSBufferNot_Vtbl;
51 static const IKsPropertySetVtbl DSBufferProp_Vtbl;
54 static inline DSBuffer *impl_from_IDirectSoundBuffer8(IDirectSoundBuffer8 *iface)
56 return CONTAINING_RECORD(iface, DSBuffer, IDirectSoundBuffer8_iface);
59 static inline DSBuffer *impl_from_IDirectSoundBuffer(IDirectSoundBuffer *iface)
61 return CONTAINING_RECORD(iface, DSBuffer, IDirectSoundBuffer8_iface);
64 static inline DSBuffer *impl_from_IDirectSound3DBuffer(IDirectSound3DBuffer *iface)
66 return CONTAINING_RECORD(iface, DSBuffer, IDirectSound3DBuffer_iface);
69 static inline DSBuffer *impl_from_IDirectSoundNotify(IDirectSoundNotify *iface)
71 return CONTAINING_RECORD(iface, DSBuffer, IDirectSoundNotify_iface);
74 static inline DSBuffer *impl_from_IKsPropertySet(IKsPropertySet *iface)
76 return CONTAINING_RECORD(iface, DSBuffer, IKsPropertySet_iface);
80 /* Should be called with critsect held and context set.. */
81 static void DSBuffer_addnotify(DSBuffer *buf)
83 DSPrimary *prim = buf->primary;
84 DSBuffer **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 DSPrimary *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 DSPrimary *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 DSPrimary *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 DSData_Release(DSData *This);
278 static HRESULT DSData_Create(DSData **ppv, const DSBUFFERDESC *desc, DSPrimary *prim)
280 HRESULT hr = DSERR_INVALIDPARAM;
281 const WAVEFORMATEX *format;
282 const char *fmt_str = NULL;
283 DSData *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 pBuffer->buf_size = buf_size;
358 if(format->wFormatTag == WAVE_FORMAT_PCM)
359 fmt_str = get_fmtstr_PCM(prim, format, &pBuffer->format);
360 else if(format->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
361 fmt_str = get_fmtstr_FLOAT(prim, format, &pBuffer->format);
362 else if(format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
364 const WAVEFORMATEXTENSIBLE *wfe;
366 if(format->cbSize != sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) &&
367 format->cbSize != sizeof(WAVEFORMATEXTENSIBLE))
368 goto fail;
370 wfe = CONTAINING_RECORD(format, const WAVEFORMATEXTENSIBLE, Format);
371 TRACE("Extensible values:\n"
372 " Samples = %d\n"
373 " ChannelMask = 0x%lx\n"
374 " SubFormat = %s\n",
375 wfe->Samples.wReserved, wfe->dwChannelMask,
376 debugstr_guid(&wfe->SubFormat));
378 fmt_str = get_fmtstr_EXT(prim, format, &pBuffer->format);
380 else
381 ERR("Unhandled formattag 0x%04x\n", format->wFormatTag);
382 if(!fmt_str) goto fail;
384 alGetError();
385 pBuffer->buf_format = alGetEnumValue(fmt_str);
386 if(alGetError() != AL_NO_ERROR || pBuffer->buf_format == 0 ||
387 pBuffer->buf_format == -1)
389 WARN("Could not get OpenAL format from %s\n", fmt_str);
390 goto fail;
393 hr = E_OUTOFMEMORY;
394 if(!HAS_EXTENSION(prim->share, SOFTX_MAP_BUFFER))
396 pBuffer->data = (BYTE*)(pBuffer+1);
398 alGenBuffers(1, &pBuffer->bid);
399 checkALError();
401 else
403 const ALbitfieldSOFT map_bits = AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT |
404 AL_MAP_PERSISTENT_BIT_SOFT;
405 alGenBuffers(1, &pBuffer->bid);
406 alBufferStorageSOFT(pBuffer->bid, pBuffer->buf_format, NULL, pBuffer->buf_size,
407 pBuffer->format.Format.nSamplesPerSec, map_bits);
408 pBuffer->data = alMapBufferSOFT(pBuffer->bid, 0, pBuffer->buf_size, map_bits);
409 checkALError();
411 if(!pBuffer->data) goto fail;
414 *ppv = pBuffer;
415 return S_OK;
417 fail:
418 DSData_Release(pBuffer);
419 return hr;
422 static void DSData_AddRef(DSData *data)
424 InterlockedIncrement(&data->ref);
427 /* This function is always called with the device lock held */
428 static void DSData_Release(DSData *This)
430 if(InterlockedDecrement(&This->ref)) return;
432 TRACE("Deleting %p\n", This);
433 if(This->bid)
435 DSPrimary *prim = This->primary;
436 if(HAS_EXTENSION(prim->share, SOFTX_MAP_BUFFER))
437 alUnmapBufferSOFT(This->bid);
438 alDeleteBuffers(1, &This->bid);
439 checkALError();
441 HeapFree(GetProcessHeap(), 0, This);
445 HRESULT DSBuffer_Create(DSBuffer **ppv, DSPrimary *prim, IDirectSoundBuffer *orig)
447 DSBuffer *This = NULL;
448 DWORD i;
450 *ppv = NULL;
451 EnterCriticalSection(&prim->share->crst);
452 for(i = 0;i < prim->NumBufferGroups;++i)
454 if(prim->BufferGroups[i].FreeBuffers)
456 int idx = CTZ64(prim->BufferGroups[i].FreeBuffers);
457 This = prim->BufferGroups[i].Buffers + idx;
458 memset(This, 0, sizeof(*This));
459 prim->BufferGroups[i].FreeBuffers &= ~(U64(1) << idx);
460 break;
463 if(!This)
465 struct DSBufferGroup *grp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
466 (prim->NumBufferGroups+1)*sizeof(prim->BufferGroups[0]));
467 if(grp)
469 for(i = 0;i < prim->NumBufferGroups;i++)
470 grp[i] = prim->BufferGroups[i];
471 grp[i].FreeBuffers = ~U64(0);
472 grp[i].Buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
473 64*sizeof(grp[0].Buffers[0]));
474 if(!grp[i].Buffers)
476 HeapFree(GetProcessHeap(), 0, grp);
477 grp = NULL;
479 else
481 HeapFree(GetProcessHeap(), 0, prim->BufferGroups);
482 prim->BufferGroups = grp;
483 prim->NumBufferGroups++;
485 This = prim->BufferGroups[i].Buffers + 0;
486 memset(This, 0, sizeof(*This));
487 prim->BufferGroups[i].FreeBuffers &= ~(U64(1) << 0);
491 LeaveCriticalSection(&prim->share->crst);
492 if(!This)
494 WARN("Out of memory allocating buffers\n");
495 return DSERR_OUTOFMEMORY;
498 This->IDirectSoundBuffer8_iface.lpVtbl = &DSBuffer_Vtbl;
499 This->IDirectSound3DBuffer_iface.lpVtbl = &DSBuffer3d_Vtbl;
500 This->IDirectSoundNotify_iface.lpVtbl = &DSBufferNot_Vtbl;
501 This->IKsPropertySet_iface.lpVtbl = &DSBufferProp_Vtbl;
503 This->share = prim->share;
504 This->primary = prim;
505 This->ctx = prim->ctx;
507 This->current.vol = 0;
508 This->current.pan = 0;
509 This->current.frequency = 0;
510 This->current.ds3d.dwSize = sizeof(This->current.ds3d);
511 This->current.ds3d.vPosition.x = 0.0f;
512 This->current.ds3d.vPosition.y = 0.0f;
513 This->current.ds3d.vPosition.z = 0.0f;
514 This->current.ds3d.vVelocity.x = 0.0f;
515 This->current.ds3d.vVelocity.y = 0.0f;
516 This->current.ds3d.vVelocity.z = 0.0f;
517 This->current.ds3d.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
518 This->current.ds3d.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
519 This->current.ds3d.vConeOrientation.x = 0.0f;
520 This->current.ds3d.vConeOrientation.y = 0.0f;
521 This->current.ds3d.vConeOrientation.z = 1.0f;
522 This->current.ds3d.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
523 This->current.ds3d.flMinDistance = DS3D_DEFAULTMINDISTANCE;
524 This->current.ds3d.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
525 This->current.ds3d.dwMode = DS3DMODE_NORMAL;
526 This->current.eax.lDirect = 0;
527 This->current.eax.lDirectHF = 0;
528 This->current.eax.lRoom = 0;
529 This->current.eax.lRoomHF = 0;
530 This->current.eax.lObstruction = 0;
531 This->current.eax.flObstructionLFRatio = 0.0f;
532 This->current.eax.lOcclusion = 0;
533 This->current.eax.flOcclusionLFRatio = 0.25f;
534 This->current.eax.flOcclusionRoomRatio = 1.5f;
535 This->current.eax.flOcclusionDirectRatio = 1.0f;
536 This->current.eax.lExclusion = 0;
537 This->current.eax.flExclusionLFRatio = 1.0f;
538 This->current.eax.lOutsideVolumeHF = 0;
539 This->current.eax.flDopplerFactor = 1.0f;
540 This->current.eax.flRolloffFactor = 0.0f;
541 This->current.eax.flRoomRolloffFactor = 0.0f;
542 This->current.eax.flAirAbsorptionFactor = 0.0f;
543 This->current.eax.dwFlags = EAXSOURCEFLAGS_DIRECTHFAUTO | EAXSOURCEFLAGS_ROOMAUTO |
544 EAXSOURCEFLAGS_ROOMHFAUTO;
545 This->current.fxslot_targets[0] = FXSLOT_TARGET_PRIMARY;
546 for(i = 1;i < EAX_MAX_ACTIVE_FXSLOTS;++i)
547 This->current.fxslot_targets[i] = FXSLOT_TARGET_NULL;
548 for(i = 0;i < EAX_MAX_ACTIVE_FXSLOTS;++i)
550 This->current.send[i].lSend = 0;
551 This->current.send[i].lSendHF = 0;
552 This->current.send[i].lOcclusion = 0;
553 This->current.send[i].flOcclusionLFRatio = 0.25f;
554 This->current.send[i].flOcclusionRoomRatio = 1.5f;
555 This->current.send[i].flOcclusionDirectRatio = 1.0f;
556 This->current.send[i].lExclusion = 0;
557 This->current.send[i].flExclusionLFRatio = 1.0f;
559 This->current.eax1_reverbmix = 1.0f;
561 if(orig)
563 DSBuffer *org = impl_from_IDirectSoundBuffer(orig);
564 DSData *data = org->buffer;
566 if(org->bufferlost)
568 DSBuffer_Destroy(This);
569 return DSERR_BUFFERLOST;
571 DSData_AddRef(data);
572 This->buffer = data;
574 /* According to MSDN, volume isn't copied. */
575 if((data->dsbflags&DSBCAPS_CTRLPAN))
576 This->current.pan = org->current.pan;
577 if((data->dsbflags&DSBCAPS_CTRLFREQUENCY))
578 This->current.frequency = org->current.frequency;
579 if((data->dsbflags&DSBCAPS_CTRL3D))
580 This->current.ds3d = org->current.ds3d;
583 This->deferred.ds3d = This->current.ds3d;
584 This->deferred.eax = This->current.eax;
585 for(i = 0;i < EAX_MAX_ACTIVE_FXSLOTS;++i)
586 This->deferred.fxslot_targets[i] = This->current.fxslot_targets[i];
587 for(i = 0;i < EAX_MAX_ACTIVE_FXSLOTS;++i)
588 This->deferred.send[i] = This->current.send[i];
589 This->deferred.eax1_reverbmix = This->current.eax1_reverbmix;
591 *ppv = This;
592 return DS_OK;
595 void DSBuffer_Destroy(DSBuffer *This)
597 DSPrimary *prim = This->primary;
598 DWORD i;
600 if(!prim) return;
601 TRACE("Destroying %p\n", This);
603 EnterCriticalSection(&prim->share->crst);
604 /* Remove from list, if in list */
605 for(i = 0;i < prim->nnotifies;++i)
607 if(This == prim->notifies[i])
609 prim->notifies[i] = prim->notifies[--prim->nnotifies];
610 break;
614 setALContext(This->ctx);
615 if(This->source)
617 DeviceShare *share = This->share;
619 alSourceRewind(This->source);
620 alSourcei(This->source, AL_BUFFER, 0);
621 checkALError();
623 if(This->loc_status == DSBSTATUS_LOCHARDWARE)
624 share->sources.ids[share->sources.availhw_num++] = This->source;
625 else
627 DWORD base = share->sources.maxhw_alloc;
628 share->sources.ids[base + share->sources.availsw_num++] = This->source;
630 This->source = 0;
632 if(This->stream_bids[0])
633 alDeleteBuffers(QBUFFERS, This->stream_bids);
634 if(This->filter[0])
635 alDeleteFilters(1+EAX_MAX_ACTIVE_FXSLOTS, This->filter);
637 if(This->buffer)
638 DSData_Release(This->buffer);
640 popALContext();
642 HeapFree(GetProcessHeap(), 0, This->notify);
644 for(i = 0;i < prim->NumBufferGroups;++i)
646 DWORD_PTR idx = This - prim->BufferGroups[i].Buffers;
647 if(idx < 64)
649 prim->BufferGroups[i].FreeBuffers |= U64(1) << idx;
650 This = NULL;
651 break;
654 LeaveCriticalSection(&prim->share->crst);
657 HRESULT DSBuffer_GetInterface(DSBuffer *buf, REFIID riid, void **ppv)
659 *ppv = NULL;
660 if(IsEqualIID(riid, &IID_IDirectSoundBuffer))
661 *ppv = &buf->IDirectSoundBuffer8_iface;
662 else if(IsEqualIID(riid, &IID_IDirectSoundBuffer8))
664 if(buf->primary->parent->is_8)
665 *ppv = &buf->IDirectSoundBuffer8_iface;
667 else if(IsEqualIID(riid, &IID_IDirectSound3DBuffer))
669 if((buf->buffer->dsbflags&DSBCAPS_CTRL3D))
670 *ppv = &buf->IDirectSound3DBuffer_iface;
672 else if(IsEqualIID(riid, &IID_IDirectSoundNotify))
674 if((buf->buffer->dsbflags&DSBCAPS_CTRLPOSITIONNOTIFY))
675 *ppv = &buf->IDirectSoundNotify_iface;
677 else if(IsEqualIID(riid, &IID_IKsPropertySet))
678 *ppv = &buf->IKsPropertySet_iface;
679 else if(IsEqualIID(riid, &IID_IUnknown))
680 *ppv = &buf->IDirectSoundBuffer8_iface;
681 else
682 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
684 if(*ppv)
686 IUnknown_AddRef((IUnknown*)*ppv);
687 return S_OK;
690 return E_NOINTERFACE;
693 static HRESULT DSBuffer_SetLoc(DSBuffer *buf, DWORD loc_status)
695 DeviceShare *share = buf->share;
696 DSData *data = buf->buffer;
697 ALsizei i;
699 if((loc_status && buf->loc_status == loc_status) || (!loc_status && buf->loc_status))
700 return DS_OK;
702 /* If we have a source, we're changing location, so return the source we
703 * have to get a new one.
705 if(buf->source)
707 alSourceRewind(buf->source);
708 alSourcei(buf->source, AL_BUFFER, 0);
709 checkALError();
711 if(buf->loc_status == DSBSTATUS_LOCHARDWARE)
712 share->sources.ids[share->sources.availhw_num++] = buf->source;
713 else
715 DWORD base = share->sources.maxhw_alloc;
716 share->sources.ids[base + share->sources.availsw_num++] = buf->source;
718 buf->source = 0;
720 buf->loc_status = 0;
722 if(!loc_status)
724 if(share->sources.availhw_num)
725 loc_status = DSBSTATUS_LOCHARDWARE;
726 else if(share->sources.availsw_num)
727 loc_status = DSBSTATUS_LOCSOFTWARE;
730 if((loc_status == DSBSTATUS_LOCHARDWARE && !share->sources.availhw_num) ||
731 (loc_status == DSBSTATUS_LOCSOFTWARE && !share->sources.availsw_num) ||
732 !loc_status)
734 ERR("Out of %s sources\n",
735 (loc_status == DSBSTATUS_LOCHARDWARE) ? "hardware" :
736 (loc_status == DSBSTATUS_LOCSOFTWARE) ? "software" : "any"
738 return DSERR_ALLOCATED;
741 if(loc_status == DSBSTATUS_LOCHARDWARE)
742 buf->source = share->sources.ids[--(share->sources.availhw_num)];
743 else
745 DWORD base = share->sources.maxhw_alloc;
746 buf->source = share->sources.ids[base + --(share->sources.availsw_num)];
748 alSourcef(buf->source, AL_GAIN, mB_to_gain(buf->current.vol));
749 alSourcef(buf->source, AL_PITCH,
750 buf->current.frequency ? (float)buf->current.frequency/data->format.Format.nSamplesPerSec
751 : 1.0f);
752 checkALError();
754 /* TODO: Don't set EAX parameters or connect to effect slots for software
755 * buffers. Need to check if EAX buffer properties are still tracked, or if
756 * they're lost/reset when leaving hardware.
758 * Alternatively, we can just allow it and say software processing supports
759 * EAX too. Depends if apps may get upset over that.
762 if((data->dsbflags&DSBCAPS_CTRL3D))
764 const DSPrimary *prim = buf->primary;
765 const ALuint source = buf->source;
766 const DS3DBUFFER *params = &buf->current.ds3d;
767 const EAXSOURCEPROPERTIES *eax_params = &buf->current.eax;
769 alSource3f(source, AL_POSITION, params->vPosition.x, params->vPosition.y,
770 -params->vPosition.z);
771 alSource3f(source, AL_VELOCITY, params->vVelocity.x, params->vVelocity.y,
772 -params->vVelocity.z);
773 alSourcei(source, AL_CONE_INNER_ANGLE, params->dwInsideConeAngle);
774 alSourcei(source, AL_CONE_OUTER_ANGLE, params->dwOutsideConeAngle);
775 alSource3f(source, AL_DIRECTION, params->vConeOrientation.x,
776 params->vConeOrientation.y,
777 -params->vConeOrientation.z);
778 alSourcef(source, AL_CONE_OUTER_GAIN, mB_to_gain(params->lConeOutsideVolume));
779 alSourcef(source, AL_REFERENCE_DISTANCE, params->flMinDistance);
780 alSourcef(source, AL_MAX_DISTANCE, params->flMaxDistance);
781 if(HAS_EXTENSION(share, SOFT_SOURCE_SPATIALIZE))
782 alSourcei(source, AL_SOURCE_SPATIALIZE_SOFT,
783 (params->dwMode==DS3DMODE_DISABLE) ? AL_FALSE : AL_TRUE
785 alSourcei(source, AL_SOURCE_RELATIVE,
786 (params->dwMode!=DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE
789 alSourcef(source, AL_ROLLOFF_FACTOR,
790 prim->current.ds3d.flRolloffFactor + eax_params->flRolloffFactor);
791 alSourcef(source, AL_DOPPLER_FACTOR, eax_params->flDopplerFactor);
792 if(HAS_EXTENSION(share, EXT_EFX))
794 alSourcei(source, AL_DIRECT_FILTER, buf->filter[0]);
795 for(i = 0;i < share->num_sends;++i)
797 DWORD target = buf->current.fxslot_targets[i];
798 ALuint slot;
799 if(target >= FXSLOT_TARGET_NULL) slot = 0;
800 else if(target == FXSLOT_TARGET_PRIMARY) slot = prim->primary_slot;
801 else slot = prim->auxslot[buf->current.fxslot_targets[i]];
802 alSource3i(source, AL_AUXILIARY_SEND_FILTER, slot, i, buf->filter[1+i]);
804 alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, eax_params->flRoomRolloffFactor);
805 alSourcef(source, AL_CONE_OUTER_GAINHF, mB_to_gain(eax_params->lOutsideVolumeHF));
806 alSourcef(source, AL_AIR_ABSORPTION_FACTOR,
807 clampF(prim->current.ctx.flAirAbsorptionHF / -5.0f *
808 eax_params->flAirAbsorptionFactor, 0.0f, 10.0f)
810 alSourcei(source, AL_DIRECT_FILTER_GAINHF_AUTO,
811 (eax_params->dwFlags&EAXSOURCEFLAGS_DIRECTHFAUTO) ? AL_TRUE : AL_FALSE);
812 alSourcei(source, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
813 (eax_params->dwFlags&EAXSOURCEFLAGS_ROOMAUTO) ? AL_TRUE : AL_FALSE);
814 alSourcei(source, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
815 (eax_params->dwFlags&EAXSOURCEFLAGS_ROOMHFAUTO) ? AL_TRUE : AL_FALSE);
817 checkALError();
819 else
821 const ALuint source = buf->source;
822 const ALfloat x = (ALfloat)(buf->current.pan-DSBPAN_LEFT)/(DSBPAN_RIGHT-DSBPAN_LEFT) -
823 0.5f;
825 alSource3f(source, AL_POSITION, x, 0.0f, -sqrtf(1.0f - x*x));
826 alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
827 alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
828 alSourcef(source, AL_CONE_OUTER_GAIN, 1.0f);
829 alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f);
830 alSourcef(source, AL_MAX_DISTANCE, 1000.0f);
831 alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f);
832 alSourcef(source, AL_DOPPLER_FACTOR, 0.0f);
833 alSourcei(source, AL_CONE_INNER_ANGLE, 360);
834 alSourcei(source, AL_CONE_OUTER_ANGLE, 360);
835 alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);
836 if(HAS_EXTENSION(share, EXT_EFX))
838 alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, 0.0f);
839 alSourcef(source, AL_CONE_OUTER_GAINHF, 1.0f);
840 alSourcef(source, AL_AIR_ABSORPTION_FACTOR, 0.0f);
841 alSourcei(source, AL_DIRECT_FILTER_GAINHF_AUTO, AL_TRUE);
842 alSourcei(source, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO, AL_TRUE);
843 alSourcei(source, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO, AL_TRUE);
844 alSourcei(source, AL_DIRECT_FILTER, AL_FILTER_NULL);
845 for(i = 0;i < share->num_sends;++i)
846 alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, i, AL_FILTER_NULL);
848 if(HAS_EXTENSION(share, SOFT_SOURCE_SPATIALIZE))
850 /* Set to auto so panning works for mono, and multi-channel works
851 * as expected.
853 alSourcei(source, AL_SOURCE_SPATIALIZE_SOFT, AL_AUTO_SOFT);
855 checkALError();
858 buf->loc_status = loc_status;
859 return DS_OK;
863 static HRESULT WINAPI DSBuffer_QueryInterface(IDirectSoundBuffer8 *iface, REFIID riid, void **ppv)
865 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
866 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
867 return DSBuffer_GetInterface(This, riid, ppv);
870 static ULONG WINAPI DSBuffer_AddRef(IDirectSoundBuffer8 *iface)
872 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
873 LONG ret;
875 InterlockedIncrement(&This->all_ref);
876 ret = InterlockedIncrement(&This->ref);
877 TRACE("(%p) ref %lu\n", iface, ret);
879 return ret;
882 static ULONG WINAPI DSBuffer_Release(IDirectSoundBuffer8 *iface)
884 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
885 LONG ret;
887 ret = InterlockedDecrement(&This->ref);
888 TRACE("(%p) ref %lu\n", iface, ret);
889 if(InterlockedDecrement(&This->all_ref) == 0)
890 DSBuffer_Destroy(This);
892 return ret;
895 static HRESULT WINAPI DSBuffer_GetCaps(IDirectSoundBuffer8 *iface, DSBCAPS *caps)
897 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
898 DSData *data;
900 TRACE("(%p)->(%p)\n", iface, caps);
902 if(!caps || caps->dwSize < sizeof(*caps))
904 WARN("Invalid DSBCAPS (%p, %lu)\n", caps, (caps ? caps->dwSize : 0));
905 return DSERR_INVALIDPARAM;
907 data = This->buffer;
909 caps->dwFlags = data->dsbflags;
910 if(!(data->dsbflags&DSBCAPS_LOCDEFER))
912 if(This->loc_status == DSBSTATUS_LOCHARDWARE)
913 caps->dwFlags |= DSBCAPS_LOCHARDWARE;
914 else if(This->loc_status == DSBSTATUS_LOCSOFTWARE)
915 caps->dwFlags |= DSBCAPS_LOCSOFTWARE;
917 caps->dwBufferBytes = data->buf_size;
918 caps->dwUnlockTransferRate = 4096;
919 caps->dwPlayCpuOverhead = 0;
921 return S_OK;
924 HRESULT WINAPI DSBuffer_GetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD *playpos, DWORD *curpos)
926 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
927 ALsizei writecursor, pos;
928 DSData *data;
930 TRACE("(%p)->(%p, %p)\n", iface, playpos, curpos);
932 data = This->buffer;
933 if(This->segsize != 0)
935 ALint queued = QBUFFERS;
936 ALint status = AL_INITIAL;
937 ALint ofs = 0;
939 EnterCriticalSection(&This->share->crst);
941 if(LIKELY(This->source))
943 setALContext(This->ctx);
944 alGetSourcei(This->source, AL_BUFFERS_QUEUED, &queued);
945 alGetSourcei(This->source, AL_BYTE_OFFSET, &ofs);
946 alGetSourcei(This->source, AL_SOURCE_STATE, &status);
947 checkALError();
948 popALContext();
951 if(status == AL_STOPPED)
952 pos = This->segsize*queued + This->queue_base;
953 else
954 pos = ofs + This->queue_base;
955 if(pos >= data->buf_size)
957 if(This->islooping)
958 pos %= data->buf_size;
959 else if(This->isplaying)
961 pos = data->buf_size;
962 alSourceStop(This->source);
963 alSourcei(This->source, AL_BUFFER, 0);
964 This->curidx = 0;
965 This->isplaying = FALSE;
968 if(This->isplaying)
969 writecursor = (This->segsize*QBUFFERS + pos) % data->buf_size;
970 else
971 writecursor = pos % data->buf_size;
973 LeaveCriticalSection(&This->share->crst);
975 else
977 const WAVEFORMATEX *format = &data->format.Format;
978 ALint status = AL_INITIAL;
979 ALint ofs = 0;
981 if(LIKELY(This->source))
983 setALContext(This->ctx);
984 alGetSourcei(This->source, AL_BYTE_OFFSET, &ofs);
985 alGetSourcei(This->source, AL_SOURCE_STATE, &status);
986 checkALError();
987 popALContext();
990 if(status == AL_PLAYING)
992 pos = ofs;
993 writecursor = format->nSamplesPerSec / This->primary->refresh;
994 writecursor *= format->nBlockAlign;
996 else
998 /* AL_STOPPED means the source naturally reached its end, where
999 * DirectSound's position should be at the end (OpenAL reports 0
1000 * for stopped sources). The Stop method correlates to pausing,
1001 * which would put the source into an AL_PAUSED state and correctly
1002 * hold its current position. AL_INITIAL means the buffer hasn't
1003 * been played since last changing location.
1005 switch(status)
1007 case AL_STOPPED: pos = data->buf_size; break;
1008 case AL_PAUSED: pos = ofs; break;
1009 case AL_INITIAL: pos = This->lastpos; break;
1010 default: pos = 0;
1012 writecursor = 0;
1014 writecursor = (writecursor + pos) % data->buf_size;
1016 TRACE("%p Play pos = %u, write pos = %u\n", This, pos, writecursor);
1018 if(pos > data->buf_size)
1020 ERR("playpos > buf_size\n");
1021 pos %= data->buf_size;
1023 if(writecursor >= data->buf_size)
1025 ERR("writepos >= buf_size\n");
1026 writecursor %= data->buf_size;
1029 if(playpos) *playpos = pos;
1030 if(curpos) *curpos = writecursor;
1032 return S_OK;
1035 static HRESULT WINAPI DSBuffer_GetFormat(IDirectSoundBuffer8 *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
1037 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1038 HRESULT hr = S_OK;
1039 UINT size;
1041 TRACE("(%p)->(%p, %lu, %p)\n", iface, wfx, allocated, written);
1043 if(!wfx && !written)
1045 WARN("Cannot report format or format size\n");
1046 return DSERR_INVALIDPARAM;
1049 size = sizeof(This->buffer->format.Format) + This->buffer->format.Format.cbSize;
1050 if(wfx)
1052 if(allocated < size)
1053 hr = DSERR_INVALIDPARAM;
1054 else
1055 memcpy(wfx, &This->buffer->format.Format, size);
1057 if(written)
1058 *written = size;
1060 return hr;
1063 static HRESULT WINAPI DSBuffer_GetVolume(IDirectSoundBuffer8 *iface, LONG *vol)
1065 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1066 HRESULT hr;
1068 TRACE("(%p)->(%p)\n", iface, vol);
1070 if(!vol)
1072 WARN("Invalid pointer\n");
1073 return DSERR_INVALIDPARAM;
1076 hr = DSERR_CONTROLUNAVAIL;
1077 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
1078 WARN("Volume control not set\n");
1079 else
1081 *vol = This->current.vol;
1082 hr = DS_OK;
1085 return hr;
1088 static HRESULT WINAPI DSBuffer_GetPan(IDirectSoundBuffer8 *iface, LONG *pan)
1090 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1091 HRESULT hr;
1093 TRACE("(%p)->(%p)\n", iface, pan);
1095 if(!pan)
1097 WARN("Invalid pointer\n");
1098 return DSERR_INVALIDPARAM;
1101 hr = DSERR_CONTROLUNAVAIL;
1102 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
1103 WARN("Panning control not set\n");
1104 else
1106 *pan = This->current.pan;
1107 hr = DS_OK;
1110 return hr;
1113 static HRESULT WINAPI DSBuffer_GetFrequency(IDirectSoundBuffer8 *iface, DWORD *freq)
1115 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1116 HRESULT hr;
1118 TRACE("(%p)->(%p)\n", iface, freq);
1120 if(!freq)
1122 WARN("Invalid pointer\n");
1123 return DSERR_INVALIDPARAM;
1126 hr = DSERR_CONTROLUNAVAIL;
1127 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
1128 WARN("Frequency control not set\n");
1129 else
1131 *freq = This->current.frequency;
1132 hr = DS_OK;
1135 return hr;
1138 HRESULT WINAPI DSBuffer_GetStatus(IDirectSoundBuffer8 *iface, DWORD *status)
1140 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1141 ALint state, looping;
1143 TRACE("(%p)->(%p)\n", iface, status);
1145 if(!status)
1147 WARN("Invalid pointer\n");
1148 return DSERR_INVALIDPARAM;
1150 *status = 0;
1152 if(This->segsize == 0)
1154 state = AL_INITIAL;
1155 looping = AL_FALSE;
1156 if(LIKELY(This->source))
1158 setALContext(This->ctx);
1159 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1160 alGetSourcei(This->source, AL_LOOPING, &looping);
1161 checkALError();
1162 popALContext();
1165 else
1167 EnterCriticalSection(&This->share->crst);
1168 state = This->isplaying ? AL_PLAYING : AL_PAUSED;
1169 looping = This->islooping;
1170 LeaveCriticalSection(&This->share->crst);
1173 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1174 *status |= This->loc_status;
1175 if(state == AL_PLAYING)
1176 *status |= DSBSTATUS_PLAYING | (looping ? DSBSTATUS_LOOPING : 0);
1178 TRACE("%p status = 0x%08lx\n", This, *status);
1179 return S_OK;
1182 HRESULT WINAPI DSBuffer_Initialize(IDirectSoundBuffer8 *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
1184 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1185 DSPrimary *prim;
1186 DSData *data;
1187 HRESULT hr;
1189 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
1191 EnterCriticalSection(&This->share->crst);
1192 setALContext(This->ctx);
1194 hr = DSERR_ALREADYINITIALIZED;
1195 if(This->init_done) goto out;
1197 prim = This->primary;
1198 if(!This->buffer)
1200 hr = DSERR_INVALIDPARAM;
1201 if(!desc)
1203 WARN("Missing DSound buffer description\n");
1204 goto out;
1206 if(!desc->lpwfxFormat)
1208 WARN("Missing buffer format (%p)\n", This);
1209 goto out;
1211 if((desc->dwFlags&DSBCAPS_CTRL3D) && desc->lpwfxFormat->nChannels != 1)
1213 if(prim->parent->is_8)
1215 /* DirectSoundBuffer8 objects aren't allowed non-mono 3D
1216 * buffers */
1217 WARN("Can't create multi-channel 3D buffers\n");
1218 goto out;
1220 else
1222 static int once = 0;
1223 if(!once++)
1224 ERR("Multi-channel 3D sounds are not spatialized\n");
1227 if((desc->dwFlags&DSBCAPS_CTRLPAN) && desc->lpwfxFormat->nChannels != 1)
1229 static int once = 0;
1230 if(!once++)
1231 ERR("Panning for multi-channel buffers is not supported\n");
1234 hr = DSData_Create(&This->buffer, desc, prim);
1235 if(FAILED(hr)) goto out;
1237 data = This->buffer;
1238 if(data->format.Format.wBitsPerSample == 8)
1239 memset(data->data, 0x80, data->buf_size);
1240 else
1241 memset(data->data, 0x00, data->buf_size);
1244 data = This->buffer;
1245 if(!(data->dsbflags&DSBCAPS_STATIC) && !HAS_EXTENSION(This->share, SOFTX_MAP_BUFFER))
1247 This->segsize = (data->format.Format.nAvgBytesPerSec+prim->refresh-1) / prim->refresh;
1248 This->segsize = clampI(This->segsize, data->format.Format.nBlockAlign, 2048);
1249 This->segsize += data->format.Format.nBlockAlign - 1;
1250 This->segsize -= This->segsize%data->format.Format.nBlockAlign;
1252 alGenBuffers(QBUFFERS, This->stream_bids);
1253 checkALError();
1255 if(!(data->dsbflags&DSBCAPS_CTRL3D))
1257 /* Non-3D sources aren't distance attenuated. */
1258 This->current.ds3d.dwMode = DS3DMODE_DISABLE;
1260 else
1262 if(HAS_EXTENSION(This->share, EXT_EFX))
1264 ALsizei i;
1266 alGenFilters(1+EAX_MAX_ACTIVE_FXSLOTS, This->filter);
1267 alFilteri(This->filter[0], AL_FILTER_TYPE, AL_FILTER_LOWPASS);
1268 for(i = 0;i < EAX_MAX_ACTIVE_FXSLOTS;++i)
1269 alFilteri(This->filter[1+i], AL_FILTER_TYPE, AL_FILTER_LOWPASS);
1270 if(UNLIKELY(alGetError() != AL_NO_ERROR))
1272 alDeleteFilters(1+EAX_MAX_ACTIVE_FXSLOTS, This->filter);
1273 This->filter[0] = This->filter[1] = This->filter[2]= 0;
1277 if(!This->current.frequency)
1278 This->current.frequency = data->format.Format.nSamplesPerSec;
1279 This->filter_mBLimit = prim->filter_mBLimit;
1281 hr = DS_OK;
1282 if(!(data->dsbflags&DSBCAPS_LOCDEFER))
1284 DWORD loc = 0;
1285 if((data->dsbflags&DSBCAPS_LOCHARDWARE)) loc = DSBSTATUS_LOCHARDWARE;
1286 else if((data->dsbflags&DSBCAPS_LOCSOFTWARE)) loc = DSBSTATUS_LOCSOFTWARE;
1287 hr = DSBuffer_SetLoc(This, loc);
1289 out:
1290 This->init_done = SUCCEEDED(hr);
1292 popALContext();
1293 LeaveCriticalSection(&This->share->crst);
1295 return hr;
1298 static HRESULT WINAPI DSBuffer_Lock(IDirectSoundBuffer8 *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
1300 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1301 DWORD remain;
1303 TRACE("(%p)->(%lu, %lu, %p, %p, %p, %p, 0x%lx)\n", This, ofs, bytes, ptr1, len1, ptr2, len2, flags);
1305 if(!ptr1 || !len1)
1307 WARN("Invalid pointer/len %p %p\n", ptr1, len1);
1308 return DSERR_INVALIDPARAM;
1311 *ptr1 = NULL;
1312 *len1 = 0;
1313 if(ptr2) *ptr2 = NULL;
1314 if(len2) *len2 = 0;
1316 if((flags&DSBLOCK_FROMWRITECURSOR))
1317 DSBuffer_GetCurrentPosition(iface, NULL, &ofs);
1318 else if(ofs >= (DWORD)This->buffer->buf_size)
1320 WARN("Invalid ofs %lu\n", ofs);
1321 return DSERR_INVALIDPARAM;
1323 if((flags&DSBLOCK_ENTIREBUFFER))
1324 bytes = This->buffer->buf_size;
1325 else if(bytes > (DWORD)This->buffer->buf_size)
1327 WARN("Invalid size %lu\n", bytes);
1328 return DSERR_INVALIDPARAM;
1331 if(InterlockedExchange(&This->buffer->locked, TRUE) == TRUE)
1333 WARN("Already locked\n");
1334 return DSERR_INVALIDPARAM;
1337 *ptr1 = This->buffer->data + ofs;
1338 if(bytes >= (DWORD)This->buffer->buf_size-ofs)
1340 *len1 = This->buffer->buf_size - ofs;
1341 remain = bytes - *len1;
1343 else
1345 *len1 = bytes;
1346 remain = 0;
1349 if(ptr2 && len2 && remain)
1351 *ptr2 = This->buffer->data;
1352 *len2 = remain;
1355 return DS_OK;
1358 static HRESULT WINAPI DSBuffer_Play(IDirectSoundBuffer8 *iface, DWORD res1, DWORD prio, DWORD flags)
1360 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1361 ALint state = AL_STOPPED;
1362 DSData *data;
1363 HRESULT hr;
1365 TRACE("(%p)->(%lu, %lu, %lu)\n", iface, res1, prio, flags);
1367 EnterCriticalSection(&This->share->crst);
1368 setALContext(This->ctx);
1370 hr = DSERR_BUFFERLOST;
1371 if(This->bufferlost)
1373 WARN("Buffer %p lost\n", This);
1374 goto out;
1377 data = This->buffer;
1378 if((data->dsbflags&DSBCAPS_LOCDEFER))
1380 DWORD loc = 0;
1382 hr = DSERR_INVALIDPARAM;
1383 if((flags&(DSBPLAY_LOCSOFTWARE|DSBPLAY_LOCHARDWARE)) == (DSBPLAY_LOCSOFTWARE|DSBPLAY_LOCHARDWARE))
1385 WARN("Both hardware and software specified\n");
1386 goto out;
1389 if((flags&DSBPLAY_LOCHARDWARE)) loc = DSBSTATUS_LOCHARDWARE;
1390 else if((flags&DSBPLAY_LOCSOFTWARE)) loc = DSBSTATUS_LOCSOFTWARE;
1392 if(loc && This->loc_status && loc != This->loc_status)
1394 if(This->segsize != 0)
1396 if(This->isplaying)
1397 state = AL_PLAYING;
1399 else
1401 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1402 checkALError();
1405 if(state == AL_PLAYING)
1407 ERR("Attemping to change location on playing buffer\n");
1408 goto out;
1412 hr = DSBuffer_SetLoc(This, loc);
1413 if(FAILED(hr)) goto out;
1415 else if(prio)
1417 ERR("Invalid priority set for non-deferred buffer %p, %lu!\n", This->buffer, prio);
1418 hr = DSERR_INVALIDPARAM;
1419 goto out;
1422 if(This->segsize != 0)
1424 This->islooping = !!(flags&DSBPLAY_LOOPING);
1425 if(This->isplaying) state = AL_PLAYING;
1427 else
1429 alSourcei(This->source, AL_LOOPING, (flags&DSBPLAY_LOOPING) ? AL_TRUE : AL_FALSE);
1430 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1431 checkALError();
1434 hr = S_OK;
1435 if(state == AL_PLAYING)
1436 goto out;
1438 if(This->segsize == 0)
1440 if(state == AL_INITIAL)
1442 alSourcei(This->source, AL_BUFFER, data->bid);
1443 alSourcei(This->source, AL_BYTE_OFFSET, This->lastpos % data->buf_size);
1445 alSourcePlay(This->source);
1447 else
1449 alSourceRewind(This->source);
1450 alSourcei(This->source, AL_BUFFER, 0);
1451 This->queue_base = This->data_offset % data->buf_size;
1452 This->curidx = 0;
1454 if(alGetError() != AL_NO_ERROR)
1456 ERR("Couldn't start source\n");
1457 hr = DSERR_GENERIC;
1458 goto out;
1460 This->isplaying = TRUE;
1462 if(This->nnotify)
1463 DSBuffer_addnotify(This);
1465 out:
1466 popALContext();
1467 LeaveCriticalSection(&This->share->crst);
1468 return hr;
1471 static HRESULT WINAPI DSBuffer_SetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD pos)
1473 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1474 DSData *data;
1476 TRACE("(%p)->(%lu)\n", iface, pos);
1478 data = This->buffer;
1479 if(pos >= (DWORD)data->buf_size)
1480 return DSERR_INVALIDPARAM;
1481 pos -= pos%data->format.Format.nBlockAlign;
1483 EnterCriticalSection(&This->share->crst);
1485 if(This->segsize != 0)
1487 if(This->isplaying)
1489 setALContext(This->ctx);
1490 /* Perform a flush, so the next timer update will restart at the
1491 * proper position */
1492 alSourceRewind(This->source);
1493 alSourcei(This->source, AL_BUFFER, 0);
1494 checkALError();
1495 popALContext();
1497 This->queue_base = This->data_offset = pos;
1498 This->curidx = 0;
1500 else
1502 if(LIKELY(This->source))
1504 setALContext(This->ctx);
1505 alSourcei(This->source, AL_BYTE_OFFSET, pos);
1506 checkALError();
1507 popALContext();
1510 This->lastpos = pos;
1512 LeaveCriticalSection(&This->share->crst);
1513 return DS_OK;
1516 static HRESULT WINAPI DSBuffer_SetFormat(IDirectSoundBuffer8 *iface, const WAVEFORMATEX *wfx)
1518 /* This call only works on primary buffers */
1519 WARN("(%p)->(%p)\n", iface, wfx);
1520 return DSERR_INVALIDCALL;
1523 static HRESULT WINAPI DSBuffer_SetVolume(IDirectSoundBuffer8 *iface, LONG vol)
1525 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1526 HRESULT hr = S_OK;
1528 TRACE("(%p)->(%ld)\n", iface, vol);
1530 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
1532 WARN("Invalid volume (%ld)\n", vol);
1533 return DSERR_INVALIDPARAM;
1536 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
1537 hr = DSERR_CONTROLUNAVAIL;
1538 else
1540 This->current.vol = vol;
1541 if(LIKELY(This->source))
1543 setALContext(This->ctx);
1544 alSourcef(This->source, AL_GAIN, mB_to_gain(vol));
1545 popALContext();
1549 return hr;
1552 static HRESULT WINAPI DSBuffer_SetPan(IDirectSoundBuffer8 *iface, LONG pan)
1554 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1555 HRESULT hr = S_OK;
1557 TRACE("(%p)->(%ld)\n", iface, pan);
1559 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
1561 WARN("invalid parameter: pan = %ld\n", pan);
1562 return DSERR_INVALIDPARAM;
1565 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
1566 hr = DSERR_CONTROLUNAVAIL;
1567 else
1569 This->current.pan = pan;
1570 if(LIKELY(This->source && !(This->buffer->dsbflags&DSBCAPS_CTRL3D)))
1572 ALfloat pos[3];
1573 pos[0] = (ALfloat)(pan-DSBPAN_LEFT)/(ALfloat)(DSBPAN_RIGHT-DSBPAN_LEFT) - 0.5f;
1574 pos[1] = 0.0f;
1575 /* NOTE: Strict movement along the X plane can cause the sound to
1576 * jump between left and right sharply. Using a curved path helps
1577 * smooth it out.
1579 pos[2] = -sqrtf(1.0f - pos[0]*pos[0]);
1581 setALContext(This->ctx);
1582 alSourcefv(This->source, AL_POSITION, pos);
1583 checkALError();
1584 popALContext();
1588 return hr;
1591 static HRESULT WINAPI DSBuffer_SetFrequency(IDirectSoundBuffer8 *iface, DWORD freq)
1593 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1594 DSData *data;
1595 HRESULT hr = S_OK;
1597 TRACE("(%p)->(%lu)\n", iface, freq);
1599 if(freq != 0 && (freq < DSBFREQUENCY_MIN || freq > DSBFREQUENCY_MAX))
1601 WARN("invalid parameter: freq = %lu\n", freq);
1602 return DSERR_INVALIDPARAM;
1605 data = This->buffer;
1606 if(!(data->dsbflags&DSBCAPS_CTRLFREQUENCY))
1607 hr = DSERR_CONTROLUNAVAIL;
1608 else
1610 This->current.frequency = freq ? freq : data->format.Format.nSamplesPerSec;
1611 if(LIKELY(This->source))
1613 setALContext(This->ctx);
1614 alSourcef(This->source, AL_PITCH,
1615 This->current.frequency / (ALfloat)data->format.Format.nSamplesPerSec
1617 checkALError();
1618 popALContext();
1622 return hr;
1625 static HRESULT WINAPI DSBuffer_Stop(IDirectSoundBuffer8 *iface)
1627 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1629 TRACE("(%p)->()\n", iface);
1631 EnterCriticalSection(&This->share->crst);
1632 if(LIKELY(This->source))
1634 const ALuint source = This->source;
1635 ALint state, ofs;
1637 setALContext(This->ctx);
1638 alSourcePause(source);
1639 alGetSourcei(source, AL_BYTE_OFFSET, &ofs);
1640 alGetSourcei(source, AL_SOURCE_STATE, &state);
1641 checkALError();
1643 This->isplaying = FALSE;
1644 if(This->nnotify)
1645 DSPrimary_triggernots(This->primary);
1646 /* Ensure the notification's last tracked position is updated, as well
1647 * as the queue offsets for streaming sources.
1649 if(This->segsize == 0)
1650 This->lastpos = (state == AL_STOPPED) ? This->buffer->buf_size : ofs;
1651 else
1653 DSData *data = This->buffer;
1654 ALint done = 0;
1656 alGetSourcei(This->source, AL_BUFFERS_PROCESSED, &done);
1657 This->queue_base += This->segsize*done + ofs;
1658 if(This->queue_base >= data->buf_size)
1660 if(This->islooping)
1661 This->queue_base %= data->buf_size;
1662 else
1663 This->queue_base = data->buf_size;
1665 This->lastpos = This->queue_base;
1667 alSourceRewind(This->source);
1668 alSourcei(This->source, AL_BUFFER, 0);
1669 checkALError();
1671 This->curidx = 0;
1672 This->data_offset = This->lastpos % data->buf_size;
1674 This->islooping = FALSE;
1675 popALContext();
1677 LeaveCriticalSection(&This->share->crst);
1679 return S_OK;
1682 static HRESULT WINAPI DSBuffer_Unlock(IDirectSoundBuffer8 *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
1684 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1685 DSData *buf = This->buffer;
1686 DWORD bufsize = buf->buf_size;
1687 DWORD_PTR ofs1, ofs2;
1688 DWORD_PTR boundary = (DWORD_PTR)buf->data;
1689 HRESULT hr;
1691 TRACE("(%p)->(%p, %lu, %p, %lu)\n", iface, ptr1, len1, ptr2, len2);
1693 if(InterlockedExchange(&buf->locked, FALSE) == FALSE)
1695 WARN("Not locked\n");
1696 return DSERR_INVALIDPARAM;
1699 hr = DSERR_INVALIDPARAM;
1700 /* Make sure offset is between boundary and boundary + bufsize */
1701 ofs1 = (DWORD_PTR)ptr1;
1702 ofs2 = (DWORD_PTR)ptr2;
1703 if(ofs1 < boundary || (ofs2 && ofs2 != boundary))
1704 goto out;
1705 ofs1 -= boundary;
1706 ofs2 = 0;
1707 if(bufsize-ofs1 < len1 || len2 > ofs1)
1708 goto out;
1709 if(!ptr2)
1710 len2 = 0;
1712 hr = DS_OK;
1713 if(!len1 && !len2)
1714 goto out;
1716 if(HAS_EXTENSION(This->share, SOFTX_MAP_BUFFER))
1718 setALContext(This->ctx);
1719 alFlushMappedBufferSOFT(buf->bid, 0, buf->buf_size);
1720 checkALError();
1721 popALContext();
1723 else if(This->segsize == 0)
1725 setALContext(This->ctx);
1726 alBufferData(buf->bid, buf->buf_format, buf->data, buf->buf_size,
1727 buf->format.Format.nSamplesPerSec);
1728 checkALError();
1729 popALContext();
1732 out:
1733 if(hr != S_OK)
1734 WARN("Invalid parameters (0x%lx,%lu) (%p,%lu,%p,%lu)\n", boundary, bufsize, ptr1, len1, ptr2, len2);
1735 return hr;
1738 static HRESULT WINAPI DSBuffer_Restore(IDirectSoundBuffer8 *iface)
1740 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1741 HRESULT hr;
1743 TRACE("(%p)->()\n", iface);
1745 EnterCriticalSection(&This->share->crst);
1746 if(This->primary->parent->prio_level < DSSCL_WRITEPRIMARY ||
1747 (IDirectSoundBuffer*)&This->IDirectSoundBuffer8_iface == This->primary->write_emu)
1749 This->bufferlost = 0;
1750 hr = S_OK;
1752 else
1753 hr = DSERR_BUFFERLOST;
1754 LeaveCriticalSection(&This->share->crst);
1756 return hr;
1759 static HRESULT WINAPI DSBuffer_SetFX(IDirectSoundBuffer8 *iface, DWORD fxcount, DSEFFECTDESC *desc, DWORD *rescodes)
1761 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1762 ALenum state = AL_INITIAL;
1763 DSData *data;
1764 HRESULT hr;
1765 DWORD i;
1767 TRACE("(%p)->(%lu, %p, %p)\n", This, fxcount, desc, rescodes);
1769 data = This->buffer;
1770 if(!(data->dsbflags&DSBCAPS_CTRLFX))
1772 WARN("FX control not set\n");
1773 return DSERR_CONTROLUNAVAIL;
1776 if(data->locked)
1778 WARN("Buffer is locked\n");
1779 return DSERR_INVALIDCALL;
1782 EnterCriticalSection(&This->share->crst);
1784 setALContext(This->ctx);
1785 if(LIKELY(This->source))
1787 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1788 checkALError();
1790 popALContext();
1791 if(This->segsize != 0 && state != AL_PLAYING)
1792 state = This->isplaying ? AL_PLAYING : AL_PAUSED;
1793 if(state == AL_PLAYING)
1795 WARN("Buffer is playing\n");
1796 hr = DSERR_INVALIDCALL;
1797 goto done;
1800 hr = DSERR_INVALIDPARAM;
1801 if(fxcount == 0)
1803 if(desc || rescodes)
1805 WARN("Non-NULL desc and/or result pointer specified with no effects.\n");
1806 goto done;
1809 /* No effects; we can handle that */
1810 hr = DS_OK;
1811 goto done;
1814 if(!desc || !rescodes)
1816 WARN("NULL desc and/or result pointer specified.\n");
1817 goto done;
1820 /* We don't (currently) handle DSound effects */
1821 for(i = 0;i < fxcount;++i)
1823 FIXME("Cannot handle effect: %s\n", debugstr_guid(&desc[i].guidDSFXClass));
1824 rescodes[i] = DSFXR_FAILED;
1826 hr = DS_INCOMPLETE;
1828 done:
1829 LeaveCriticalSection(&This->share->crst);
1831 return hr;
1834 static HRESULT WINAPI DSBuffer_AcquireResources(IDirectSoundBuffer8 *iface, DWORD flags, DWORD fxcount, DWORD *rescodes)
1836 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1837 HRESULT hr;
1839 TRACE("(%p)->(%lu, %lu, %p)\n", This, flags, fxcount, rescodes);
1841 /* effects aren't supported at the moment.. */
1842 if(fxcount != 0 || rescodes)
1844 WARN("Non-zero effect count and/or result pointer specified with no effects.\n");
1845 return DSERR_INVALIDPARAM;
1848 EnterCriticalSection(&This->share->crst);
1849 setALContext(This->ctx);
1851 hr = DS_OK;
1852 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1854 DWORD loc = 0;
1856 hr = DSERR_INVALIDPARAM;
1857 if((flags&(DSBPLAY_LOCSOFTWARE|DSBPLAY_LOCHARDWARE)) == (DSBPLAY_LOCSOFTWARE|DSBPLAY_LOCHARDWARE))
1859 WARN("Both hardware and software specified\n");
1860 goto out;
1863 if((flags&DSBPLAY_LOCHARDWARE)) loc = DSBSTATUS_LOCHARDWARE;
1864 else if((flags&DSBPLAY_LOCSOFTWARE)) loc = DSBSTATUS_LOCSOFTWARE;
1866 if(loc && This->loc_status && loc != This->loc_status)
1868 ALint state = AL_INITIAL;
1870 if(This->segsize != 0)
1872 if(This->isplaying)
1873 state = AL_PLAYING;
1875 else
1877 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1878 checkALError();
1881 if(state == AL_PLAYING)
1883 ERR("Attemping to change location on playing buffer\n");
1884 goto out;
1888 hr = DSBuffer_SetLoc(This, loc);
1891 out:
1892 popALContext();
1893 LeaveCriticalSection(&This->share->crst);
1894 return hr;
1897 static HRESULT WINAPI DSBuffer_GetObjectInPath(IDirectSoundBuffer8 *iface, REFGUID guid, DWORD idx, REFGUID rguidiface, void **ppv)
1899 FIXME("(%p)->(%s, %lu, %s, %p) : stub!\n", iface, debugstr_guid(guid), idx, debugstr_guid(rguidiface), ppv);
1900 return E_NOTIMPL;
1903 static const IDirectSoundBuffer8Vtbl DSBuffer_Vtbl = {
1904 DSBuffer_QueryInterface,
1905 DSBuffer_AddRef,
1906 DSBuffer_Release,
1907 DSBuffer_GetCaps,
1908 DSBuffer_GetCurrentPosition,
1909 DSBuffer_GetFormat,
1910 DSBuffer_GetVolume,
1911 DSBuffer_GetPan,
1912 DSBuffer_GetFrequency,
1913 DSBuffer_GetStatus,
1914 DSBuffer_Initialize,
1915 DSBuffer_Lock,
1916 DSBuffer_Play,
1917 DSBuffer_SetCurrentPosition,
1918 DSBuffer_SetFormat,
1919 DSBuffer_SetVolume,
1920 DSBuffer_SetPan,
1921 DSBuffer_SetFrequency,
1922 DSBuffer_Stop,
1923 DSBuffer_Unlock,
1924 DSBuffer_Restore,
1925 DSBuffer_SetFX,
1926 DSBuffer_AcquireResources,
1927 DSBuffer_GetObjectInPath
1931 void DSBuffer_SetParams(DSBuffer *This, const DS3DBUFFER *params, LONG flags)
1933 DSPrimary *prim = This->primary;
1934 const ALuint source = This->source;
1935 union BufferParamFlags dirty = { flags };
1936 ALsizei i;
1938 /* Copy deferred parameters first. */
1939 if(dirty.bit.pos)
1940 This->current.ds3d.vPosition = params->vPosition;
1941 if(dirty.bit.vel)
1942 This->current.ds3d.vVelocity = params->vVelocity;
1943 if(dirty.bit.cone_angles)
1945 This->current.ds3d.dwInsideConeAngle = params->dwInsideConeAngle;
1946 This->current.ds3d.dwOutsideConeAngle = params->dwOutsideConeAngle;
1948 if(dirty.bit.cone_orient)
1949 This->current.ds3d.vConeOrientation = params->vConeOrientation;
1950 if(dirty.bit.cone_outsidevolume)
1951 This->current.ds3d.lConeOutsideVolume = params->lConeOutsideVolume;
1952 if(dirty.bit.min_distance)
1953 This->current.ds3d.flMinDistance = params->flMinDistance;
1954 if(dirty.bit.max_distance)
1955 This->current.ds3d.flMaxDistance = params->flMaxDistance;
1956 if(dirty.bit.mode)
1957 This->current.ds3d.dwMode = params->dwMode;
1958 /* Always copy EAX params (they're always set deferred first, then applied
1959 * when committing all params).
1961 This->current.eax = This->deferred.eax;
1962 for(i = 0;i < EAX_MAX_ACTIVE_FXSLOTS;++i)
1963 This->current.fxslot_targets[i] = This->deferred.fxslot_targets[i];
1964 for(i = 0;i < EAX_MAX_ACTIVE_FXSLOTS;++i)
1965 This->current.send[i] = This->deferred.send[i];
1966 This->current.eax1_reverbmix = This->deferred.eax1_reverbmix;
1968 /* Now apply what's changed to OpenAL. */
1969 if(UNLIKELY(!source)) return;
1971 if(dirty.bit.pos)
1972 alSource3f(source, AL_POSITION, params->vPosition.x, params->vPosition.y,
1973 -params->vPosition.z);
1974 if(dirty.bit.vel)
1975 alSource3f(source, AL_VELOCITY, params->vVelocity.x, params->vVelocity.y,
1976 -params->vVelocity.z);
1977 if(dirty.bit.cone_angles)
1979 alSourcei(source, AL_CONE_INNER_ANGLE, params->dwInsideConeAngle);
1980 alSourcei(source, AL_CONE_OUTER_ANGLE, params->dwOutsideConeAngle);
1982 if(dirty.bit.cone_orient)
1983 alSource3f(source, AL_DIRECTION, params->vConeOrientation.x,
1984 params->vConeOrientation.y,
1985 -params->vConeOrientation.z);
1986 if(dirty.bit.cone_outsidevolume)
1987 alSourcef(source, AL_CONE_OUTER_GAIN, mB_to_gain(params->lConeOutsideVolume));
1988 if(dirty.bit.min_distance)
1989 alSourcef(source, AL_REFERENCE_DISTANCE, params->flMinDistance);
1990 if(dirty.bit.max_distance)
1991 alSourcef(source, AL_MAX_DISTANCE, params->flMaxDistance);
1992 if(dirty.bit.mode)
1994 if(HAS_EXTENSION(This->share, SOFT_SOURCE_SPATIALIZE))
1995 alSourcei(source, AL_SOURCE_SPATIALIZE_SOFT,
1996 (params->dwMode==DS3DMODE_DISABLE) ? AL_FALSE : AL_TRUE
1998 alSourcei(source, AL_SOURCE_RELATIVE,
1999 (params->dwMode!=DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE
2003 if(dirty.bit.dry_filter)
2004 alSourcei(source, AL_DIRECT_FILTER, This->filter[0]);
2005 for(i = 0;i < EAX_MAX_ACTIVE_FXSLOTS;++i)
2007 if((dirty.bit.send_filter&(1<<i)))
2009 DWORD target = This->current.fxslot_targets[i];
2010 ALuint slot;
2011 if(target >= FXSLOT_TARGET_NULL) slot = 0;
2012 else if(target == FXSLOT_TARGET_PRIMARY) slot = prim->primary_slot;
2013 else slot = prim->auxslot[This->current.fxslot_targets[i]];
2014 alSource3i(source, AL_AUXILIARY_SEND_FILTER, slot, i, This->filter[1+i]);
2017 if(dirty.bit.doppler)
2018 alSourcef(source, AL_DOPPLER_FACTOR, This->current.eax.flDopplerFactor);
2019 if(dirty.bit.rolloff)
2020 alSourcef(source, AL_ROLLOFF_FACTOR, This->current.eax.flRolloffFactor +
2021 prim->current.ds3d.flRolloffFactor);
2022 if(dirty.bit.room_rolloff)
2023 alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, This->current.eax.flRoomRolloffFactor);
2024 if(dirty.bit.cone_outsidevolumehf)
2025 alSourcef(source, AL_CONE_OUTER_GAINHF, mB_to_gain(This->current.eax.lOutsideVolumeHF));
2026 if(dirty.bit.air_absorb)
2027 alSourcef(source, AL_AIR_ABSORPTION_FACTOR, This->current.eax.flAirAbsorptionFactor *
2028 prim->current.ctx.flAirAbsorptionHF / -5.0f);
2029 if(dirty.bit.flags)
2031 alSourcei(source, AL_DIRECT_FILTER_GAINHF_AUTO,
2032 (This->current.eax.dwFlags&EAXSOURCEFLAGS_DIRECTHFAUTO) ? AL_TRUE : AL_FALSE);
2033 alSourcei(source, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
2034 (This->current.eax.dwFlags&EAXSOURCEFLAGS_ROOMAUTO) ? AL_TRUE : AL_FALSE);
2035 alSourcei(source, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
2036 (This->current.eax.dwFlags&EAXSOURCEFLAGS_ROOMHFAUTO) ? AL_TRUE : AL_FALSE);
2040 static HRESULT WINAPI DSBuffer3D_QueryInterface(IDirectSound3DBuffer *iface, REFIID riid, void **ppv)
2042 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2043 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2044 return DSBuffer_GetInterface(This, riid, ppv);
2047 static ULONG WINAPI DSBuffer3D_AddRef(IDirectSound3DBuffer *iface)
2049 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2050 LONG ret;
2052 InterlockedIncrement(&This->all_ref);
2053 ret = InterlockedIncrement(&This->ds3d_ref);
2054 TRACE("(%p) ref %lu\n", iface, ret);
2056 return ret;
2059 static ULONG WINAPI DSBuffer3D_Release(IDirectSound3DBuffer *iface)
2061 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2062 LONG ret;
2064 ret = InterlockedDecrement(&This->ds3d_ref);
2065 TRACE("(%p) ref %lu\n", iface, ret);
2066 if(InterlockedDecrement(&This->all_ref) == 0)
2067 DSBuffer_Destroy(This);
2069 return ret;
2072 static HRESULT WINAPI DSBuffer3D_GetConeAngles(IDirectSound3DBuffer *iface, DWORD *pdwInsideConeAngle, DWORD *pdwOutsideConeAngle)
2074 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2076 TRACE("(%p)->(%p, %p)\n", This, pdwInsideConeAngle, pdwOutsideConeAngle);
2077 if(!pdwInsideConeAngle || !pdwOutsideConeAngle)
2079 WARN("Invalid pointers (%p, %p)\n", pdwInsideConeAngle, pdwOutsideConeAngle);
2080 return DSERR_INVALIDPARAM;
2083 EnterCriticalSection(&This->share->crst);
2084 *pdwInsideConeAngle = This->current.ds3d.dwInsideConeAngle;
2085 *pdwOutsideConeAngle = This->current.ds3d.dwOutsideConeAngle;
2086 LeaveCriticalSection(&This->share->crst);
2088 return S_OK;
2091 static HRESULT WINAPI DSBuffer3D_GetConeOrientation(IDirectSound3DBuffer *iface, D3DVECTOR *orient)
2093 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2095 TRACE("(%p)->(%p)\n", This, orient);
2096 if(!orient)
2098 WARN("Invalid pointer\n");
2099 return DSERR_INVALIDPARAM;
2102 EnterCriticalSection(&This->share->crst);
2103 *orient = This->current.ds3d.vConeOrientation;
2104 LeaveCriticalSection(&This->share->crst);
2106 return S_OK;
2109 static HRESULT WINAPI DSBuffer3D_GetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG *vol)
2111 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2113 TRACE("(%p)->(%p)\n", This, vol);
2114 if(!vol)
2116 WARN("Invalid pointer\n");
2117 return DSERR_INVALIDPARAM;
2120 *vol = This->current.ds3d.lConeOutsideVolume;
2121 return S_OK;
2124 static HRESULT WINAPI DSBuffer3D_GetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE *maxdist)
2126 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2128 TRACE("(%p)->(%p)\n", This, maxdist);
2129 if(!maxdist)
2131 WARN("Invalid pointer\n");
2132 return DSERR_INVALIDPARAM;
2135 *maxdist = This->current.ds3d.flMaxDistance;
2136 return S_OK;
2139 static HRESULT WINAPI DSBuffer3D_GetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE *mindist)
2141 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2143 TRACE("(%p)->(%p)\n", This, mindist);
2144 if(!mindist)
2146 WARN("Invalid pointer\n");
2147 return DSERR_INVALIDPARAM;
2150 *mindist = This->current.ds3d.flMinDistance;
2151 return S_OK;
2154 static HRESULT WINAPI DSBuffer3D_GetMode(IDirectSound3DBuffer *iface, DWORD *mode)
2156 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2158 TRACE("(%p)->(%p)\n", This, mode);
2159 if(!mode)
2161 WARN("Invalid pointer\n");
2162 return DSERR_INVALIDPARAM;
2165 *mode = This->current.ds3d.dwMode;
2166 return S_OK;
2169 static HRESULT WINAPI DSBuffer3D_GetPosition(IDirectSound3DBuffer *iface, D3DVECTOR *pos)
2171 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2173 TRACE("(%p)->(%p)\n", This, pos);
2174 if(!pos)
2176 WARN("Invalid pointer\n");
2177 return DSERR_INVALIDPARAM;
2180 EnterCriticalSection(&This->share->crst);
2181 *pos = This->current.ds3d.vPosition;
2182 LeaveCriticalSection(&This->share->crst);
2184 return S_OK;
2187 static HRESULT WINAPI DSBuffer3D_GetVelocity(IDirectSound3DBuffer *iface, D3DVECTOR *vel)
2189 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2191 TRACE("(%p)->(%p)\n", This, vel);
2192 if(!vel)
2194 WARN("Invalid pointer\n");
2195 return DSERR_INVALIDPARAM;
2198 EnterCriticalSection(&This->share->crst);
2199 *vel = This->current.ds3d.vVelocity;
2200 LeaveCriticalSection(&This->share->crst);
2202 return S_OK;
2205 static HRESULT WINAPI DSBuffer3D_GetAllParameters(IDirectSound3DBuffer *iface, DS3DBUFFER *ds3dbuffer)
2207 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2209 TRACE("(%p)->(%p)\n", iface, ds3dbuffer);
2211 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
2213 WARN("Invalid parameters %p %lu\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
2214 return DSERR_INVALIDPARAM;
2217 EnterCriticalSection(&This->share->crst);
2218 ds3dbuffer->vPosition = This->current.ds3d.vPosition;
2219 ds3dbuffer->vVelocity = This->current.ds3d.vVelocity;
2220 ds3dbuffer->dwInsideConeAngle = This->current.ds3d.dwInsideConeAngle;
2221 ds3dbuffer->dwOutsideConeAngle = This->current.ds3d.dwOutsideConeAngle;
2222 ds3dbuffer->vConeOrientation = This->current.ds3d.vConeOrientation;
2223 ds3dbuffer->lConeOutsideVolume = This->current.ds3d.lConeOutsideVolume;
2224 ds3dbuffer->flMinDistance = This->current.ds3d.flMinDistance;
2225 ds3dbuffer->flMaxDistance = This->current.ds3d.flMaxDistance;
2226 ds3dbuffer->dwMode = This->current.ds3d.dwMode;
2227 LeaveCriticalSection(&This->share->crst);
2229 return DS_OK;
2232 static HRESULT WINAPI DSBuffer3D_SetConeAngles(IDirectSound3DBuffer *iface, DWORD dwInsideConeAngle, DWORD dwOutsideConeAngle, DWORD apply)
2234 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2236 TRACE("(%p)->(%lu, %lu, %lu)\n", This, dwInsideConeAngle, dwOutsideConeAngle, apply);
2237 if(dwInsideConeAngle > DS3D_MAXCONEANGLE || dwOutsideConeAngle > DS3D_MAXCONEANGLE)
2239 WARN("Invalid cone angles (%lu, %lu)\n", dwInsideConeAngle, dwOutsideConeAngle);
2240 return DSERR_INVALIDPARAM;
2243 EnterCriticalSection(&This->share->crst);
2244 if(apply == DS3D_DEFERRED)
2246 This->deferred.ds3d.dwInsideConeAngle = dwInsideConeAngle;
2247 This->deferred.ds3d.dwOutsideConeAngle = dwOutsideConeAngle;
2248 This->dirty.bit.cone_angles = 1;
2250 else
2252 setALContext(This->ctx);
2253 This->current.ds3d.dwInsideConeAngle = dwInsideConeAngle;
2254 This->current.ds3d.dwOutsideConeAngle = dwOutsideConeAngle;
2255 if(LIKELY(This->source))
2257 alSourcei(This->source, AL_CONE_INNER_ANGLE, dwInsideConeAngle);
2258 alSourcei(This->source, AL_CONE_OUTER_ANGLE, dwOutsideConeAngle);
2259 checkALError();
2261 popALContext();
2263 LeaveCriticalSection(&This->share->crst);
2265 return S_OK;
2268 static HRESULT WINAPI DSBuffer3D_SetConeOrientation(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2270 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2272 TRACE("(%p)->(%f, %f, %f, %lu)\n", This, x, y, z, apply);
2274 EnterCriticalSection(&This->share->crst);
2275 if(apply == DS3D_DEFERRED)
2277 This->deferred.ds3d.vConeOrientation.x = x;
2278 This->deferred.ds3d.vConeOrientation.y = y;
2279 This->deferred.ds3d.vConeOrientation.z = z;
2280 This->dirty.bit.cone_orient = 1;
2282 else
2284 setALContext(This->ctx);
2285 This->current.ds3d.vConeOrientation.x = x;
2286 This->current.ds3d.vConeOrientation.y = y;
2287 This->current.ds3d.vConeOrientation.z = z;
2288 if(LIKELY(This->source))
2290 alSource3f(This->source, AL_DIRECTION, x, y, -z);
2291 checkALError();
2293 popALContext();
2295 LeaveCriticalSection(&This->share->crst);
2297 return S_OK;
2300 static HRESULT WINAPI DSBuffer3D_SetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG vol, DWORD apply)
2302 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2304 TRACE("(%p)->(%ld, %lu)\n", This, vol, apply);
2305 if(vol < DSBVOLUME_MIN || vol > DSBVOLUME_MAX)
2307 WARN("Invalid volume (%ld)\n", vol);
2308 return DSERR_INVALIDPARAM;
2311 EnterCriticalSection(&This->share->crst);
2312 if(apply == DS3D_DEFERRED)
2314 This->deferred.ds3d.lConeOutsideVolume = vol;
2315 This->dirty.bit.cone_outsidevolume = 1;
2317 else
2319 setALContext(This->ctx);
2320 This->current.ds3d.lConeOutsideVolume = vol;
2321 if(LIKELY(This->source))
2323 alSourcef(This->source, AL_CONE_OUTER_GAIN, mB_to_gain(vol));
2324 checkALError();
2326 popALContext();
2328 LeaveCriticalSection(&This->share->crst);
2330 return S_OK;
2333 static HRESULT WINAPI DSBuffer3D_SetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE maxdist, DWORD apply)
2335 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2337 TRACE("(%p)->(%f, %lu)\n", This, maxdist, apply);
2338 if(maxdist < 0.0f)
2340 WARN("Invalid max distance (%f)\n", maxdist);
2341 return DSERR_INVALIDPARAM;
2344 EnterCriticalSection(&This->share->crst);
2345 if(apply == DS3D_DEFERRED)
2347 This->deferred.ds3d.flMaxDistance = maxdist;
2348 This->dirty.bit.max_distance = 1;
2350 else
2352 setALContext(This->ctx);
2353 This->current.ds3d.flMaxDistance = maxdist;
2354 if(LIKELY(This->source))
2356 alSourcef(This->source, AL_MAX_DISTANCE, maxdist);
2357 checkALError();
2359 popALContext();
2361 LeaveCriticalSection(&This->share->crst);
2363 return S_OK;
2366 static HRESULT WINAPI DSBuffer3D_SetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE mindist, DWORD apply)
2368 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2370 TRACE("(%p)->(%f, %lu)\n", This, mindist, apply);
2371 if(mindist < 0.0f)
2373 WARN("Invalid min distance (%f)\n", mindist);
2374 return DSERR_INVALIDPARAM;
2377 EnterCriticalSection(&This->share->crst);
2378 if(apply == DS3D_DEFERRED)
2380 This->deferred.ds3d.flMinDistance = mindist;
2381 This->dirty.bit.min_distance = 1;
2383 else
2385 setALContext(This->ctx);
2386 This->current.ds3d.flMinDistance = mindist;
2387 if(LIKELY(This->source))
2389 alSourcef(This->source, AL_REFERENCE_DISTANCE, mindist);
2390 checkALError();
2392 popALContext();
2394 LeaveCriticalSection(&This->share->crst);
2396 return S_OK;
2399 static HRESULT WINAPI DSBuffer3D_SetMode(IDirectSound3DBuffer *iface, DWORD mode, DWORD apply)
2401 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2403 TRACE("(%p)->(%lu, %lu)\n", This, mode, apply);
2404 if(mode != DS3DMODE_NORMAL && mode != DS3DMODE_HEADRELATIVE &&
2405 mode != DS3DMODE_DISABLE)
2407 WARN("Invalid mode (%lu)\n", mode);
2408 return DSERR_INVALIDPARAM;
2411 EnterCriticalSection(&This->share->crst);
2412 if(apply == DS3D_DEFERRED)
2414 This->deferred.ds3d.dwMode = mode;
2415 This->dirty.bit.mode = 1;
2417 else
2419 setALContext(This->ctx);
2420 This->current.ds3d.dwMode = mode;
2421 if(LIKELY(This->source))
2423 if(HAS_EXTENSION(This->share, SOFT_SOURCE_SPATIALIZE))
2424 alSourcei(This->source, AL_SOURCE_SPATIALIZE_SOFT,
2425 (mode==DS3DMODE_DISABLE) ? AL_FALSE : AL_TRUE);
2426 alSourcei(This->source, AL_SOURCE_RELATIVE,
2427 (mode != DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE);
2428 checkALError();
2430 popALContext();
2432 LeaveCriticalSection(&This->share->crst);
2434 return S_OK;
2437 static HRESULT WINAPI DSBuffer3D_SetPosition(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2439 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2441 TRACE("(%p)->(%f, %f, %f, %lu)\n", This, x, y, z, apply);
2443 EnterCriticalSection(&This->share->crst);
2444 if(apply == DS3D_DEFERRED)
2446 This->deferred.ds3d.vPosition.x = x;
2447 This->deferred.ds3d.vPosition.y = y;
2448 This->deferred.ds3d.vPosition.z = z;
2449 This->dirty.bit.pos = 1;
2451 else
2453 setALContext(This->ctx);
2454 This->current.ds3d.vPosition.x = x;
2455 This->current.ds3d.vPosition.y = y;
2456 This->current.ds3d.vPosition.z = z;
2457 if(LIKELY(This->source))
2459 alSource3f(This->source, AL_POSITION, x, y, -z);
2460 checkALError();
2462 popALContext();
2464 LeaveCriticalSection(&This->share->crst);
2466 return S_OK;
2469 static HRESULT WINAPI DSBuffer3D_SetVelocity(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2471 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2473 TRACE("(%p)->(%f, %f, %f, %lu)\n", This, x, y, z, apply);
2475 EnterCriticalSection(&This->share->crst);
2476 if(apply == DS3D_DEFERRED)
2478 This->deferred.ds3d.vVelocity.x = x;
2479 This->deferred.ds3d.vVelocity.y = y;
2480 This->deferred.ds3d.vVelocity.z = z;
2481 This->dirty.bit.vel = 1;
2483 else
2485 setALContext(This->ctx);
2486 This->current.ds3d.vVelocity.x = x;
2487 This->current.ds3d.vVelocity.y = y;
2488 This->current.ds3d.vVelocity.z = z;
2489 if(LIKELY(This->source))
2491 alSource3f(This->source, AL_VELOCITY, x, y, -z);
2492 checkALError();
2494 popALContext();
2496 LeaveCriticalSection(&This->share->crst);
2498 return S_OK;
2501 static HRESULT WINAPI DSBuffer3D_SetAllParameters(IDirectSound3DBuffer *iface, const DS3DBUFFER *ds3dbuffer, DWORD apply)
2503 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2504 TRACE("(%p)->(%p, %lu)\n", This, ds3dbuffer, apply);
2506 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
2508 WARN("Invalid DS3DBUFFER (%p, %lu)\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
2509 return DSERR_INVALIDPARAM;
2512 if(ds3dbuffer->dwInsideConeAngle > DS3D_MAXCONEANGLE ||
2513 ds3dbuffer->dwOutsideConeAngle > DS3D_MAXCONEANGLE)
2515 WARN("Invalid cone angles (%lu, %lu)\n",
2516 ds3dbuffer->dwInsideConeAngle, ds3dbuffer->dwOutsideConeAngle);
2517 return DSERR_INVALIDPARAM;
2520 if(ds3dbuffer->lConeOutsideVolume > DSBVOLUME_MAX ||
2521 ds3dbuffer->lConeOutsideVolume < DSBVOLUME_MIN)
2523 WARN("Invalid cone outside volume (%ld)\n", ds3dbuffer->lConeOutsideVolume);
2524 return DSERR_INVALIDPARAM;
2527 if(ds3dbuffer->flMaxDistance < 0.0f)
2529 WARN("Invalid max distance (%f)\n", ds3dbuffer->flMaxDistance);
2530 return DSERR_INVALIDPARAM;
2533 if(ds3dbuffer->flMinDistance < 0.0f)
2535 WARN("Invalid min distance (%f)\n", ds3dbuffer->flMinDistance);
2536 return DSERR_INVALIDPARAM;
2539 if(ds3dbuffer->dwMode != DS3DMODE_NORMAL &&
2540 ds3dbuffer->dwMode != DS3DMODE_HEADRELATIVE &&
2541 ds3dbuffer->dwMode != DS3DMODE_DISABLE)
2543 WARN("Invalid mode (%lu)\n", ds3dbuffer->dwMode);
2544 return DSERR_INVALIDPARAM;
2547 if(apply == DS3D_DEFERRED)
2549 EnterCriticalSection(&This->share->crst);
2550 This->deferred.ds3d = *ds3dbuffer;
2551 This->deferred.ds3d.dwSize = sizeof(This->deferred.ds3d);
2552 This->dirty.bit.pos = 1;
2553 This->dirty.bit.vel = 1;
2554 This->dirty.bit.cone_angles = 1;
2555 This->dirty.bit.cone_orient = 1;
2556 This->dirty.bit.cone_outsidevolume = 1;
2557 This->dirty.bit.min_distance = 1;
2558 This->dirty.bit.max_distance = 1;
2559 This->dirty.bit.mode = 1;
2560 LeaveCriticalSection(&This->share->crst);
2562 else
2564 union BufferParamFlags dirty = { 0 };
2565 dirty.bit.pos = 1;
2566 dirty.bit.vel = 1;
2567 dirty.bit.cone_angles = 1;
2568 dirty.bit.cone_orient = 1;
2569 dirty.bit.cone_outsidevolume = 1;
2570 dirty.bit.min_distance = 1;
2571 dirty.bit.max_distance = 1;
2572 dirty.bit.mode = 1;
2574 EnterCriticalSection(&This->share->crst);
2575 setALContext(This->ctx);
2576 DSBuffer_SetParams(This, ds3dbuffer, dirty.flags);
2577 checkALError();
2578 popALContext();
2579 LeaveCriticalSection(&This->share->crst);
2582 return S_OK;
2585 static const IDirectSound3DBufferVtbl DSBuffer3d_Vtbl =
2587 DSBuffer3D_QueryInterface,
2588 DSBuffer3D_AddRef,
2589 DSBuffer3D_Release,
2590 DSBuffer3D_GetAllParameters,
2591 DSBuffer3D_GetConeAngles,
2592 DSBuffer3D_GetConeOrientation,
2593 DSBuffer3D_GetConeOutsideVolume,
2594 DSBuffer3D_GetMaxDistance,
2595 DSBuffer3D_GetMinDistance,
2596 DSBuffer3D_GetMode,
2597 DSBuffer3D_GetPosition,
2598 DSBuffer3D_GetVelocity,
2599 DSBuffer3D_SetAllParameters,
2600 DSBuffer3D_SetConeAngles,
2601 DSBuffer3D_SetConeOrientation,
2602 DSBuffer3D_SetConeOutsideVolume,
2603 DSBuffer3D_SetMaxDistance,
2604 DSBuffer3D_SetMinDistance,
2605 DSBuffer3D_SetMode,
2606 DSBuffer3D_SetPosition,
2607 DSBuffer3D_SetVelocity
2611 static HRESULT WINAPI DSBufferNot_QueryInterface(IDirectSoundNotify *iface, REFIID riid, void **ppv)
2613 DSBuffer *This = impl_from_IDirectSoundNotify(iface);
2614 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2615 return DSBuffer_GetInterface(This, riid, ppv);
2618 static ULONG WINAPI DSBufferNot_AddRef(IDirectSoundNotify *iface)
2620 DSBuffer *This = impl_from_IDirectSoundNotify(iface);
2621 LONG ret;
2623 InterlockedIncrement(&This->all_ref);
2624 ret = InterlockedIncrement(&This->not_ref);
2625 TRACE("(%p) ref %lu\n", iface, ret);
2627 return ret;
2630 static ULONG WINAPI DSBufferNot_Release(IDirectSoundNotify *iface)
2632 DSBuffer *This = impl_from_IDirectSoundNotify(iface);
2633 LONG ret;
2635 ret = InterlockedDecrement(&This->not_ref);
2636 TRACE("(%p) ref %lu\n", iface, ret);
2637 if(InterlockedDecrement(&This->all_ref) == 0)
2638 DSBuffer_Destroy(This);
2640 return ret;
2643 static HRESULT WINAPI DSBufferNot_SetNotificationPositions(IDirectSoundNotify *iface, DWORD count, const DSBPOSITIONNOTIFY *notifications)
2645 DSBuffer *This = impl_from_IDirectSoundNotify(iface);
2646 DSBPOSITIONNOTIFY *nots;
2647 DWORD state;
2648 HRESULT hr;
2650 TRACE("(%p)->(%lu, %p))\n", iface, count, notifications);
2652 EnterCriticalSection(&This->share->crst);
2653 hr = DSERR_INVALIDPARAM;
2654 if(count && !notifications)
2655 goto out;
2657 hr = DSBuffer_GetStatus(&This->IDirectSoundBuffer8_iface, &state);
2658 if(FAILED(hr)) goto out;
2660 hr = DSERR_INVALIDCALL;
2661 if((state&DSBSTATUS_PLAYING))
2662 goto out;
2664 if(!count)
2666 HeapFree(GetProcessHeap(), 0, This->notify);
2667 This->notify = 0;
2668 This->nnotify = 0;
2669 hr = S_OK;
2671 else
2673 DWORD i;
2675 hr = DSERR_INVALIDPARAM;
2676 for(i = 0;i < count;++i)
2678 if(notifications[i].dwOffset >= (DWORD)This->buffer->buf_size &&
2679 notifications[i].dwOffset != (DWORD)DSBPN_OFFSETSTOP)
2680 goto out;
2683 hr = E_OUTOFMEMORY;
2684 nots = HeapAlloc(GetProcessHeap(), 0, count*sizeof(*nots));
2685 if(!nots) goto out;
2686 memcpy(nots, notifications, count*sizeof(*nots));
2688 HeapFree(GetProcessHeap(), 0, This->notify);
2689 This->notify = nots;
2690 This->nnotify = count;
2692 hr = S_OK;
2695 out:
2696 LeaveCriticalSection(&This->share->crst);
2697 return hr;
2700 static const IDirectSoundNotifyVtbl DSBufferNot_Vtbl =
2702 DSBufferNot_QueryInterface,
2703 DSBufferNot_AddRef,
2704 DSBufferNot_Release,
2705 DSBufferNot_SetNotificationPositions
2709 static const char *debug_bufferprop(const GUID *guid)
2711 #define HANDLE_ID(id) if(IsEqualGUID(guid, &(id))) return #id
2712 HANDLE_ID(EAXPROPERTYID_EAX40_Source);
2713 HANDLE_ID(DSPROPSETID_EAX30_BufferProperties);
2714 HANDLE_ID(DSPROPSETID_EAX20_BufferProperties);
2715 HANDLE_ID(EAXPROPERTYID_EAX40_FXSlot0);
2716 HANDLE_ID(EAXPROPERTYID_EAX40_FXSlot1);
2717 HANDLE_ID(EAXPROPERTYID_EAX40_FXSlot2);
2718 HANDLE_ID(EAXPROPERTYID_EAX40_FXSlot3);
2719 HANDLE_ID(DSPROPSETID_EAX30_ListenerProperties);
2720 HANDLE_ID(DSPROPSETID_EAX20_ListenerProperties);
2721 HANDLE_ID(EAXPROPERTYID_EAX40_Context);
2722 HANDLE_ID(DSPROPSETID_EAX10_BufferProperties);
2723 HANDLE_ID(DSPROPSETID_EAX10_ListenerProperties);
2724 HANDLE_ID(DSPROPSETID_VoiceManager);
2725 HANDLE_ID(DSPROPSETID_ZOOMFX_BufferProperties);
2726 HANDLE_ID(DSPROPSETID_I3DL2_ListenerProperties);
2727 HANDLE_ID(DSPROPSETID_I3DL2_BufferProperties);
2728 #undef HANDLE_ID
2729 return debugstr_guid(guid);
2732 static HRESULT WINAPI DSBufferProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
2734 DSBuffer *This = impl_from_IKsPropertySet(iface);
2735 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2736 return DSBuffer_GetInterface(This, riid, ppv);
2739 static ULONG WINAPI DSBufferProp_AddRef(IKsPropertySet *iface)
2741 DSBuffer *This = impl_from_IKsPropertySet(iface);
2742 LONG ret;
2744 InterlockedIncrement(&This->all_ref);
2745 ret = InterlockedIncrement(&This->prop_ref);
2746 TRACE("(%p) ref %lu\n", iface, ret);
2748 return ret;
2751 static ULONG WINAPI DSBufferProp_Release(IKsPropertySet *iface)
2753 DSBuffer *This = impl_from_IKsPropertySet(iface);
2754 LONG ret;
2756 ret = InterlockedDecrement(&This->prop_ref);
2757 TRACE("(%p) ref %lu\n", iface, ret);
2758 if(InterlockedDecrement(&This->all_ref) == 0)
2759 DSBuffer_Destroy(This);
2761 return ret;
2764 /* NOTE: Due to some apparent quirks in DSound, the listener properties are
2765 handled through secondary buffers. */
2766 static HRESULT WINAPI DSBufferProp_Get(IKsPropertySet *iface,
2767 REFGUID guidPropSet, ULONG dwPropID,
2768 LPVOID pInstanceData, ULONG cbInstanceData,
2769 LPVOID pPropData, ULONG cbPropData,
2770 ULONG *pcbReturned)
2772 DSBuffer *This = impl_from_IKsPropertySet(iface);
2773 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2775 TRACE("(%p)->(%s, 0x%lx, %p, %lu, %p, %lu, %p)\n", iface, debug_bufferprop(guidPropSet),
2776 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData, pcbReturned);
2778 if(!pcbReturned)
2779 return E_POINTER;
2780 *pcbReturned = 0;
2782 if(cbPropData > 0 && !pPropData)
2784 WARN("pPropData is NULL with cbPropData > 0\n");
2785 return E_POINTER;
2788 EnterCriticalSection(&This->share->crst);
2789 if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_Source))
2790 hr = EAX4Source_Get(This, dwPropID, pPropData, cbPropData, pcbReturned);
2791 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX30_BufferProperties))
2792 hr = EAX3Buffer_Get(This, dwPropID, pPropData, cbPropData, pcbReturned);
2793 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2794 hr = EAX2Buffer_Get(This, dwPropID, pPropData, cbPropData, pcbReturned);
2795 else if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot0))
2796 hr = EAX4Slot_Get(This->primary, 0, dwPropID, pPropData, cbPropData, pcbReturned);
2797 else if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot1))
2798 hr = EAX4Slot_Get(This->primary, 1, dwPropID, pPropData, cbPropData, pcbReturned);
2799 else if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot2))
2800 hr = EAX4Slot_Get(This->primary, 2, dwPropID, pPropData, cbPropData, pcbReturned);
2801 else if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot3))
2802 hr = EAX4Slot_Get(This->primary, 3, dwPropID, pPropData, cbPropData, pcbReturned);
2803 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX30_ListenerProperties))
2804 hr = EAX3_Get(This->primary, dwPropID, pPropData, cbPropData, pcbReturned);
2805 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
2806 hr = EAX2_Get(This->primary, dwPropID, pPropData, cbPropData, pcbReturned);
2807 else if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_Context))
2808 hr = EAX4Context_Get(This->primary, dwPropID, pPropData, cbPropData, pcbReturned);
2809 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX10_BufferProperties))
2810 hr = EAX1Buffer_Get(This, dwPropID, pPropData, cbPropData, pcbReturned);
2811 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX10_ListenerProperties))
2812 hr = EAX1_Get(This->primary, dwPropID, pPropData, cbPropData, pcbReturned);
2813 else
2814 FIXME("Unhandled propset: %s\n", debug_bufferprop(guidPropSet));
2815 LeaveCriticalSection(&This->share->crst);
2817 return hr;
2820 static HRESULT WINAPI DSBufferProp_Set(IKsPropertySet *iface,
2821 REFGUID guidPropSet, ULONG dwPropID,
2822 LPVOID pInstanceData, ULONG cbInstanceData,
2823 LPVOID pPropData, ULONG cbPropData)
2825 DSBuffer *This = impl_from_IKsPropertySet(iface);
2826 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2827 LONG idx;
2829 TRACE("(%p)->(%s, 0x%lx, %p, %lu, %p, %lu)\n", iface, debug_bufferprop(guidPropSet),
2830 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData);
2832 if(cbPropData > 0 && !pPropData)
2834 WARN("pPropData is NULL with cbPropData > 0\n");
2835 return E_POINTER;
2838 EnterCriticalSection(&This->share->crst);
2839 if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_Source))
2841 DWORD propid = dwPropID & ~EAXSOURCE_PARAMETER_DEFERRED;
2842 BOOL immediate = !(dwPropID&EAXSOURCE_PARAMETER_DEFERRED);
2844 setALContext(This->ctx);
2845 hr = EAX4Source_Set(This, propid, pPropData, cbPropData);
2846 if(hr == DS_OK && immediate)
2848 DSPrimary *prim = This->primary;
2849 DSPrimary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
2851 popALContext();
2853 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX30_BufferProperties))
2855 DWORD propid = dwPropID & ~DSPROPERTY_EAX30BUFFER_DEFERRED;
2856 BOOL immediate = !(dwPropID&DSPROPERTY_EAX30BUFFER_DEFERRED);
2858 setALContext(This->ctx);
2859 hr = EAX3Buffer_Set(This, propid, pPropData, cbPropData);
2860 if(hr == DS_OK && immediate)
2862 DSPrimary *prim = This->primary;
2863 DSPrimary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
2865 popALContext();
2867 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2869 DWORD propid = dwPropID & ~DSPROPERTY_EAX20BUFFER_DEFERRED;
2870 BOOL immediate = !(dwPropID&DSPROPERTY_EAX20BUFFER_DEFERRED);
2872 setALContext(This->ctx);
2873 hr = EAX2Buffer_Set(This, propid, pPropData, cbPropData);
2874 if(hr == DS_OK && immediate)
2876 DSPrimary *prim = This->primary;
2877 DSPrimary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
2879 popALContext();
2881 else if(((idx=0),IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot0)) ||
2882 ((idx=1),IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot1)) ||
2883 ((idx=2),IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot2)) ||
2884 ((idx=3),IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot3)))
2886 DSPrimary *prim = This->primary;
2887 DWORD propid = dwPropID & ~EAXFXSLOT_PARAMETER_DEFERRED;
2888 BOOL immediate = !(dwPropID&EAXFXSLOT_PARAMETER_DEFERRED);
2890 setALContext(prim->ctx);
2891 hr = EAX4Slot_Set(prim, idx, propid, pPropData, cbPropData);
2892 if(hr == DS_OK && immediate)
2893 DSPrimary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
2894 popALContext();
2896 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX30_ListenerProperties))
2898 DSPrimary *prim = This->primary;
2899 DWORD propid = dwPropID & ~DSPROPERTY_EAX30LISTENER_DEFERRED;
2900 BOOL immediate = !(dwPropID&DSPROPERTY_EAX30LISTENER_DEFERRED);
2902 setALContext(prim->ctx);
2903 hr = EAX3_Set(prim, propid, pPropData, cbPropData);
2904 if(hr == DS_OK && immediate)
2905 DSPrimary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
2906 popALContext();
2908 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
2910 DSPrimary *prim = This->primary;
2911 DWORD propid = dwPropID & ~DSPROPERTY_EAX20LISTENER_DEFERRED;
2912 BOOL immediate = !(dwPropID&DSPROPERTY_EAX20LISTENER_DEFERRED);
2914 setALContext(prim->ctx);
2915 hr = EAX2_Set(prim, propid, pPropData, cbPropData);
2916 if(hr == DS_OK && immediate)
2917 DSPrimary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
2918 popALContext();
2920 else if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_Context))
2922 DSPrimary *prim = This->primary;
2923 DWORD propid = dwPropID & ~EAXCONTEXT_PARAMETER_DEFERRED;
2924 BOOL immediate = !(dwPropID&EAXCONTEXT_PARAMETER_DEFERRED);
2926 setALContext(prim->ctx);
2927 hr = EAX4Context_Set(prim, propid, pPropData, cbPropData);
2928 if(hr == DS_OK && immediate)
2929 DSPrimary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
2930 popALContext();
2932 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX10_BufferProperties))
2934 DWORD propid = dwPropID & ~DSPROPERTY_EAX20BUFFER_DEFERRED;
2935 BOOL immediate = !(dwPropID&DSPROPERTY_EAX20BUFFER_DEFERRED);
2937 setALContext(This->ctx);
2938 hr = EAX1Buffer_Set(This, propid, pPropData, cbPropData);
2939 if(hr == DS_OK && immediate)
2941 DSPrimary *prim = This->primary;
2942 DSPrimary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
2944 popALContext();
2946 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX10_ListenerProperties))
2948 DSPrimary *prim = This->primary;
2949 DWORD propid = dwPropID & ~DSPROPERTY_EAX20LISTENER_DEFERRED;
2950 BOOL immediate = !(dwPropID&DSPROPERTY_EAX20LISTENER_DEFERRED);
2952 setALContext(prim->ctx);
2953 hr = EAX1_Set(prim, propid, pPropData, cbPropData);
2954 if(hr == DS_OK && immediate)
2955 DSPrimary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
2956 popALContext();
2958 else
2959 FIXME("Unhandled propset: %s\n", debug_bufferprop(guidPropSet));
2960 LeaveCriticalSection(&This->share->crst);
2962 return hr;
2965 static HRESULT WINAPI DSBufferProp_QuerySupport(IKsPropertySet *iface,
2966 REFGUID guidPropSet, ULONG dwPropID,
2967 ULONG *pTypeSupport)
2969 DSBuffer *This = impl_from_IKsPropertySet(iface);
2970 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2972 TRACE("(%p)->(%s, 0x%lx, %p)\n", iface, debug_bufferprop(guidPropSet), dwPropID,
2973 pTypeSupport);
2975 if(!pTypeSupport)
2976 return E_POINTER;
2977 *pTypeSupport = 0;
2979 EnterCriticalSection(&This->share->crst);
2980 if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_Source))
2981 hr = EAX4Source_Query(This, dwPropID, pTypeSupport);
2982 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX30_BufferProperties))
2983 hr = EAX3Buffer_Query(This, dwPropID, pTypeSupport);
2984 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2985 hr = EAX2Buffer_Query(This, dwPropID, pTypeSupport);
2986 else if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot0))
2987 hr = EAX4Slot_Query(This->primary, 0, dwPropID, pTypeSupport);
2988 else if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot1))
2989 hr = EAX4Slot_Query(This->primary, 1, dwPropID, pTypeSupport);
2990 else if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot2))
2991 hr = EAX4Slot_Query(This->primary, 2, dwPropID, pTypeSupport);
2992 else if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot3))
2993 hr = EAX4Slot_Query(This->primary, 3, dwPropID, pTypeSupport);
2994 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX30_ListenerProperties))
2995 hr = EAX3_Query(This->primary, dwPropID, pTypeSupport);
2996 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
2997 hr = EAX2_Query(This->primary, dwPropID, pTypeSupport);
2998 else if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_Context))
2999 hr = EAX4Context_Query(This->primary, dwPropID, pTypeSupport);
3000 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX10_ListenerProperties))
3001 hr = EAX1_Query(This->primary, dwPropID, pTypeSupport);
3002 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX10_BufferProperties))
3003 hr = EAX1Buffer_Query(This, dwPropID, pTypeSupport);
3004 else
3005 FIXME("Unhandled propset: %s (propid: %lu)\n", debug_bufferprop(guidPropSet), dwPropID);
3006 LeaveCriticalSection(&This->share->crst);
3008 return hr;
3011 static const IKsPropertySetVtbl DSBufferProp_Vtbl =
3013 DSBufferProp_QueryInterface,
3014 DSBufferProp_AddRef,
3015 DSBufferProp_Release,
3016 DSBufferProp_Get,
3017 DSBufferProp_Set,
3018 DSBufferProp_QuerySupport