Fix some formatter types
[dsound-openal.git] / buffer.c
blobf63fdfa5494326a8cfac93ebd0c31f0c67eded73
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 IDirectSoundBuffer8Vtbl DSBuffer_Vtbl;
49 static IDirectSound3DBufferVtbl DSBuffer3d_Vtbl;
50 static IDirectSoundNotifyVtbl DSBufferNot_Vtbl;
51 static 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_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_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_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((float)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((float)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 filter=0, slot=0;
799 if(target < FXSLOT_TARGET_NULL)
801 ALint idx = (target == FXSLOT_TARGET_PRIMARY) ?
802 prim->primary_idx : (ALint)target;
803 if(idx >= 0)
805 slot = prim->auxslot[idx];
806 filter = buf->filter[1+idx];
809 alSource3i(source, AL_AUXILIARY_SEND_FILTER, slot, i, filter);
811 alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, eax_params->flRoomRolloffFactor);
812 alSourcef(source, AL_CONE_OUTER_GAINHF, mB_to_gain((float)eax_params->lOutsideVolumeHF));
813 alSourcef(source, AL_AIR_ABSORPTION_FACTOR,
814 clampF(prim->current.ctx.flAirAbsorptionHF / -5.0f *
815 eax_params->flAirAbsorptionFactor, 0.0f, 10.0f)
817 alSourcei(source, AL_DIRECT_FILTER_GAINHF_AUTO,
818 (eax_params->dwFlags&EAXSOURCEFLAGS_DIRECTHFAUTO) ? AL_TRUE : AL_FALSE);
819 alSourcei(source, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
820 (eax_params->dwFlags&EAXSOURCEFLAGS_ROOMAUTO) ? AL_TRUE : AL_FALSE);
821 alSourcei(source, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
822 (eax_params->dwFlags&EAXSOURCEFLAGS_ROOMHFAUTO) ? AL_TRUE : AL_FALSE);
824 checkALError();
826 else
828 const ALuint source = buf->source;
829 const ALfloat x = (ALfloat)(buf->current.pan-DSBPAN_LEFT)/(DSBPAN_RIGHT-DSBPAN_LEFT) -
830 0.5f;
832 alSource3f(source, AL_POSITION, x, 0.0f, -sqrtf(1.0f - x*x));
833 alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
834 alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
835 alSourcef(source, AL_CONE_OUTER_GAIN, 1.0f);
836 alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f);
837 alSourcef(source, AL_MAX_DISTANCE, 1000.0f);
838 alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f);
839 alSourcef(source, AL_DOPPLER_FACTOR, 0.0f);
840 alSourcei(source, AL_CONE_INNER_ANGLE, 360);
841 alSourcei(source, AL_CONE_OUTER_ANGLE, 360);
842 alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);
843 if(HAS_EXTENSION(share, EXT_EFX))
845 alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, 0.0f);
846 alSourcef(source, AL_CONE_OUTER_GAINHF, 1.0f);
847 alSourcef(source, AL_AIR_ABSORPTION_FACTOR, 0.0f);
848 alSourcei(source, AL_DIRECT_FILTER_GAINHF_AUTO, AL_TRUE);
849 alSourcei(source, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO, AL_TRUE);
850 alSourcei(source, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO, AL_TRUE);
851 alSourcei(source, AL_DIRECT_FILTER, AL_FILTER_NULL);
852 for(i = 0;i < share->num_sends;++i)
853 alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, i, AL_FILTER_NULL);
855 if(HAS_EXTENSION(share, SOFT_SOURCE_SPATIALIZE))
857 /* Set to auto so panning works for mono, and multi-channel works
858 * as expected.
860 alSourcei(source, AL_SOURCE_SPATIALIZE_SOFT, AL_AUTO_SOFT);
862 checkALError();
865 buf->loc_status = loc_status;
866 return DS_OK;
870 static HRESULT WINAPI DSBuffer_QueryInterface(IDirectSoundBuffer8 *iface, REFIID riid, void **ppv)
872 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
873 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
874 return DSBuffer_GetInterface(This, riid, ppv);
877 static ULONG WINAPI DSBuffer_AddRef(IDirectSoundBuffer8 *iface)
879 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
880 LONG ret;
882 InterlockedIncrement(&This->all_ref);
883 ret = InterlockedIncrement(&This->ref);
884 TRACE("(%p) ref %lu\n", iface, ret);
886 return ret;
889 static ULONG WINAPI DSBuffer_Release(IDirectSoundBuffer8 *iface)
891 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
892 LONG ret;
894 ret = InterlockedDecrement(&This->ref);
895 TRACE("(%p) ref %lu\n", iface, ret);
896 if(InterlockedDecrement(&This->all_ref) == 0)
897 DSBuffer_Destroy(This);
899 return ret;
902 static HRESULT WINAPI DSBuffer_GetCaps(IDirectSoundBuffer8 *iface, DSBCAPS *caps)
904 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
905 DSData *data;
907 TRACE("(%p)->(%p)\n", iface, caps);
909 if(!caps || caps->dwSize < sizeof(*caps))
911 WARN("Invalid DSBCAPS (%p, %lu)\n", caps, (caps ? caps->dwSize : 0));
912 return DSERR_INVALIDPARAM;
914 data = This->buffer;
916 caps->dwFlags = data->dsbflags;
917 if(!(data->dsbflags&DSBCAPS_LOCDEFER))
919 if(This->loc_status == DSBSTATUS_LOCHARDWARE)
920 caps->dwFlags |= DSBCAPS_LOCHARDWARE;
921 else if(This->loc_status == DSBSTATUS_LOCSOFTWARE)
922 caps->dwFlags |= DSBCAPS_LOCSOFTWARE;
924 caps->dwBufferBytes = data->buf_size;
925 caps->dwUnlockTransferRate = 4096;
926 caps->dwPlayCpuOverhead = 0;
928 return S_OK;
931 HRESULT WINAPI DSBuffer_GetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD *playpos, DWORD *curpos)
933 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
934 ALsizei writecursor, pos;
935 DSData *data;
937 TRACE("(%p)->(%p, %p)\n", iface, playpos, curpos);
939 data = This->buffer;
940 if(This->segsize != 0)
942 ALint queued = QBUFFERS;
943 ALint status = AL_INITIAL;
944 ALint ofs = 0;
946 EnterCriticalSection(&This->share->crst);
948 if(LIKELY(This->source))
950 setALContext(This->ctx);
951 alGetSourcei(This->source, AL_BUFFERS_QUEUED, &queued);
952 alGetSourcei(This->source, AL_BYTE_OFFSET, &ofs);
953 alGetSourcei(This->source, AL_SOURCE_STATE, &status);
954 checkALError();
955 popALContext();
958 if(status == AL_STOPPED)
959 pos = This->segsize*queued + This->queue_base;
960 else
961 pos = ofs + This->queue_base;
962 if(pos >= data->buf_size)
964 if(This->islooping)
965 pos %= data->buf_size;
966 else if(This->isplaying)
968 pos = data->buf_size;
969 alSourceStop(This->source);
970 alSourcei(This->source, AL_BUFFER, 0);
971 This->curidx = 0;
972 This->isplaying = FALSE;
975 if(This->isplaying)
976 writecursor = (This->segsize*QBUFFERS + pos) % data->buf_size;
977 else
978 writecursor = pos % data->buf_size;
980 LeaveCriticalSection(&This->share->crst);
982 else
984 const WAVEFORMATEX *format = &data->format.Format;
985 ALint status = AL_INITIAL;
986 ALint ofs = 0;
988 if(LIKELY(This->source))
990 setALContext(This->ctx);
991 alGetSourcei(This->source, AL_BYTE_OFFSET, &ofs);
992 alGetSourcei(This->source, AL_SOURCE_STATE, &status);
993 checkALError();
994 popALContext();
997 if(status == AL_PLAYING)
999 pos = ofs;
1000 writecursor = format->nSamplesPerSec / This->primary->refresh;
1001 writecursor *= format->nBlockAlign;
1003 else
1005 /* AL_STOPPED means the source naturally reached its end, where
1006 * DirectSound's position should be at the end (OpenAL reports 0
1007 * for stopped sources). The Stop method correlates to pausing,
1008 * which would put the source into an AL_PAUSED state and correctly
1009 * hold its current position. AL_INITIAL means the buffer hasn't
1010 * been played since last changing location.
1012 switch(status)
1014 case AL_STOPPED: pos = data->buf_size; break;
1015 case AL_PAUSED: pos = ofs; break;
1016 case AL_INITIAL: pos = This->lastpos; break;
1017 default: pos = 0;
1019 writecursor = 0;
1021 writecursor = (writecursor + pos) % data->buf_size;
1023 TRACE("%p Play pos = %u, write pos = %u\n", This, pos, writecursor);
1025 if(pos > data->buf_size)
1027 ERR("playpos > buf_size\n");
1028 pos %= data->buf_size;
1030 if(writecursor >= data->buf_size)
1032 ERR("writepos >= buf_size\n");
1033 writecursor %= data->buf_size;
1036 if(playpos) *playpos = pos;
1037 if(curpos) *curpos = writecursor;
1039 return S_OK;
1042 static HRESULT WINAPI DSBuffer_GetFormat(IDirectSoundBuffer8 *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
1044 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1045 HRESULT hr = S_OK;
1046 UINT size;
1048 TRACE("(%p)->(%p, %lu, %p)\n", iface, wfx, allocated, written);
1050 if(!wfx && !written)
1052 WARN("Cannot report format or format size\n");
1053 return DSERR_INVALIDPARAM;
1056 size = sizeof(This->buffer->format.Format) + This->buffer->format.Format.cbSize;
1057 if(wfx)
1059 if(allocated < size)
1060 hr = DSERR_INVALIDPARAM;
1061 else
1062 memcpy(wfx, &This->buffer->format.Format, size);
1064 if(written)
1065 *written = size;
1067 return hr;
1070 static HRESULT WINAPI DSBuffer_GetVolume(IDirectSoundBuffer8 *iface, LONG *vol)
1072 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1073 HRESULT hr;
1075 TRACE("(%p)->(%p)\n", iface, vol);
1077 if(!vol)
1079 WARN("Invalid pointer\n");
1080 return DSERR_INVALIDPARAM;
1083 hr = DSERR_CONTROLUNAVAIL;
1084 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
1085 WARN("Volume control not set\n");
1086 else
1088 *vol = This->current.vol;
1089 hr = DS_OK;
1092 return hr;
1095 static HRESULT WINAPI DSBuffer_GetPan(IDirectSoundBuffer8 *iface, LONG *pan)
1097 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1098 HRESULT hr;
1100 TRACE("(%p)->(%p)\n", iface, pan);
1102 if(!pan)
1104 WARN("Invalid pointer\n");
1105 return DSERR_INVALIDPARAM;
1108 hr = DSERR_CONTROLUNAVAIL;
1109 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
1110 WARN("Panning control not set\n");
1111 else
1113 *pan = This->current.pan;
1114 hr = DS_OK;
1117 return hr;
1120 static HRESULT WINAPI DSBuffer_GetFrequency(IDirectSoundBuffer8 *iface, DWORD *freq)
1122 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1123 HRESULT hr;
1125 TRACE("(%p)->(%p)\n", iface, freq);
1127 if(!freq)
1129 WARN("Invalid pointer\n");
1130 return DSERR_INVALIDPARAM;
1133 hr = DSERR_CONTROLUNAVAIL;
1134 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
1135 WARN("Frequency control not set\n");
1136 else
1138 *freq = This->current.frequency;
1139 hr = DS_OK;
1142 return hr;
1145 HRESULT WINAPI DSBuffer_GetStatus(IDirectSoundBuffer8 *iface, DWORD *status)
1147 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1148 ALint state, looping;
1150 TRACE("(%p)->(%p)\n", iface, status);
1152 if(!status)
1154 WARN("Invalid pointer\n");
1155 return DSERR_INVALIDPARAM;
1157 *status = 0;
1159 if(This->segsize == 0)
1161 state = AL_INITIAL;
1162 looping = AL_FALSE;
1163 if(LIKELY(This->source))
1165 setALContext(This->ctx);
1166 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1167 alGetSourcei(This->source, AL_LOOPING, &looping);
1168 checkALError();
1169 popALContext();
1172 else
1174 EnterCriticalSection(&This->share->crst);
1175 state = This->isplaying ? AL_PLAYING : AL_PAUSED;
1176 looping = This->islooping;
1177 LeaveCriticalSection(&This->share->crst);
1180 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1181 *status |= This->loc_status;
1182 if(state == AL_PLAYING)
1183 *status |= DSBSTATUS_PLAYING | (looping ? DSBSTATUS_LOOPING : 0);
1185 TRACE("%p status = 0x%08lx\n", This, *status);
1186 return S_OK;
1189 HRESULT WINAPI DSBuffer_Initialize(IDirectSoundBuffer8 *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
1191 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1192 DSPrimary *prim;
1193 DSData *data;
1194 HRESULT hr;
1196 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
1198 EnterCriticalSection(&This->share->crst);
1199 setALContext(This->ctx);
1201 hr = DSERR_ALREADYINITIALIZED;
1202 if(This->init_done) goto out;
1204 prim = This->primary;
1205 if(!This->buffer)
1207 hr = DSERR_INVALIDPARAM;
1208 if(!desc)
1210 WARN("Missing DSound buffer description\n");
1211 goto out;
1213 if(!desc->lpwfxFormat)
1215 WARN("Missing buffer format (%p)\n", This);
1216 goto out;
1218 if((desc->dwFlags&DSBCAPS_CTRL3D) && desc->lpwfxFormat->nChannels != 1)
1220 if(prim->parent->is_8)
1222 /* DirectSoundBuffer8 objects aren't allowed non-mono 3D
1223 * buffers */
1224 WARN("Can't create multi-channel 3D buffers\n");
1225 goto out;
1227 else
1229 static int once = 0;
1230 if(!once++)
1231 ERR("Multi-channel 3D sounds are not spatialized\n");
1234 if((desc->dwFlags&DSBCAPS_CTRLPAN) && desc->lpwfxFormat->nChannels != 1)
1236 static int once = 0;
1237 if(!once++)
1238 ERR("Panning for multi-channel buffers is not supported\n");
1241 hr = DSData_Create(&This->buffer, desc, prim);
1242 if(FAILED(hr)) goto out;
1244 data = This->buffer;
1245 if(data->format.Format.wBitsPerSample == 8)
1246 memset(data->data, 0x80, data->buf_size);
1247 else
1248 memset(data->data, 0x00, data->buf_size);
1251 data = This->buffer;
1252 if(!(data->dsbflags&DSBCAPS_STATIC) && !HAS_EXTENSION(This->share, SOFTX_MAP_BUFFER))
1254 This->segsize = (data->format.Format.nAvgBytesPerSec+prim->refresh-1) / prim->refresh;
1255 This->segsize = clampI(This->segsize, data->format.Format.nBlockAlign, 2048);
1256 This->segsize += data->format.Format.nBlockAlign - 1;
1257 This->segsize -= This->segsize%data->format.Format.nBlockAlign;
1259 alGenBuffers(QBUFFERS, This->stream_bids);
1260 checkALError();
1262 if(!(data->dsbflags&DSBCAPS_CTRL3D))
1264 /* Non-3D sources aren't distance attenuated. */
1265 This->current.ds3d.dwMode = DS3DMODE_DISABLE;
1267 else
1269 if(HAS_EXTENSION(This->share, EXT_EFX))
1271 ALsizei i;
1273 alGenFilters(1+EAX_MAX_FXSLOTS, This->filter);
1274 alFilteri(This->filter[0], AL_FILTER_TYPE, AL_FILTER_LOWPASS);
1275 for(i = 0;i < EAX_MAX_FXSLOTS;++i)
1276 alFilteri(This->filter[1+i], AL_FILTER_TYPE, AL_FILTER_LOWPASS);
1277 if(UNLIKELY(alGetError() != AL_NO_ERROR))
1279 alDeleteFilters(1+EAX_MAX_FXSLOTS, This->filter);
1280 This->filter[0] = 0;
1281 for(i = 0;i < EAX_MAX_FXSLOTS;++i)
1282 This->filter[1+i] = 0;
1286 if(!This->current.frequency)
1287 This->current.frequency = data->format.Format.nSamplesPerSec;
1288 This->filter_mBLimit = prim->filter_mBLimit;
1290 hr = DS_OK;
1291 if(!(data->dsbflags&DSBCAPS_LOCDEFER))
1293 DWORD loc = 0;
1294 if((data->dsbflags&DSBCAPS_LOCHARDWARE)) loc = DSBSTATUS_LOCHARDWARE;
1295 else if((data->dsbflags&DSBCAPS_LOCSOFTWARE)) loc = DSBSTATUS_LOCSOFTWARE;
1296 hr = DSBuffer_SetLoc(This, loc);
1298 out:
1299 This->init_done = SUCCEEDED(hr);
1301 popALContext();
1302 LeaveCriticalSection(&This->share->crst);
1304 return hr;
1307 static HRESULT WINAPI DSBuffer_Lock(IDirectSoundBuffer8 *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
1309 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1310 DWORD remain;
1312 TRACE("(%p)->(%lu, %lu, %p, %p, %p, %p, 0x%lx)\n", This, ofs, bytes, ptr1, len1, ptr2, len2, flags);
1314 if(!ptr1 || !len1)
1316 WARN("Invalid pointer/len %p %p\n", ptr1, len1);
1317 return DSERR_INVALIDPARAM;
1320 *ptr1 = NULL;
1321 *len1 = 0;
1322 if(ptr2) *ptr2 = NULL;
1323 if(len2) *len2 = 0;
1325 if((flags&DSBLOCK_FROMWRITECURSOR))
1326 DSBuffer_GetCurrentPosition(iface, NULL, &ofs);
1327 else if(ofs >= (DWORD)This->buffer->buf_size)
1329 WARN("Invalid ofs %lu\n", ofs);
1330 return DSERR_INVALIDPARAM;
1332 if((flags&DSBLOCK_ENTIREBUFFER))
1333 bytes = This->buffer->buf_size;
1334 else if(bytes > (DWORD)This->buffer->buf_size)
1336 WARN("Invalid size %lu\n", bytes);
1337 return DSERR_INVALIDPARAM;
1340 if(InterlockedExchange(&This->buffer->locked, TRUE) == TRUE)
1342 WARN("Already locked\n");
1343 return DSERR_INVALIDPARAM;
1346 *ptr1 = This->buffer->data + ofs;
1347 if(bytes >= (DWORD)This->buffer->buf_size-ofs)
1349 *len1 = This->buffer->buf_size - ofs;
1350 remain = bytes - *len1;
1352 else
1354 *len1 = bytes;
1355 remain = 0;
1358 if(ptr2 && len2 && remain)
1360 *ptr2 = This->buffer->data;
1361 *len2 = remain;
1364 return DS_OK;
1367 static HRESULT WINAPI DSBuffer_Play(IDirectSoundBuffer8 *iface, DWORD res1, DWORD prio, DWORD flags)
1369 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1370 ALint state = AL_STOPPED;
1371 DSData *data;
1372 HRESULT hr;
1374 TRACE("(%p)->(%lu, %lu, %lu)\n", iface, res1, prio, flags);
1376 EnterCriticalSection(&This->share->crst);
1377 setALContext(This->ctx);
1379 hr = DSERR_BUFFERLOST;
1380 if(This->bufferlost)
1382 WARN("Buffer %p lost\n", This);
1383 goto out;
1386 data = This->buffer;
1387 if((data->dsbflags&DSBCAPS_LOCDEFER))
1389 DWORD loc = 0;
1391 hr = DSERR_INVALIDPARAM;
1392 if((flags&(DSBPLAY_LOCSOFTWARE|DSBPLAY_LOCHARDWARE)) == (DSBPLAY_LOCSOFTWARE|DSBPLAY_LOCHARDWARE))
1394 WARN("Both hardware and software specified\n");
1395 goto out;
1398 if((flags&DSBPLAY_LOCHARDWARE)) loc = DSBSTATUS_LOCHARDWARE;
1399 else if((flags&DSBPLAY_LOCSOFTWARE)) loc = DSBSTATUS_LOCSOFTWARE;
1401 if(loc && This->loc_status && loc != This->loc_status)
1403 if(This->segsize != 0)
1405 if(This->isplaying)
1406 state = AL_PLAYING;
1408 else
1410 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1411 checkALError();
1414 if(state == AL_PLAYING)
1416 ERR("Attemping to change location on playing buffer\n");
1417 goto out;
1421 hr = DSBuffer_SetLoc(This, loc);
1422 if(FAILED(hr)) goto out;
1424 else if(prio)
1426 ERR("Invalid priority set for non-deferred buffer %p, %lu!\n", This->buffer, prio);
1427 hr = DSERR_INVALIDPARAM;
1428 goto out;
1431 if(This->segsize != 0)
1433 This->islooping = !!(flags&DSBPLAY_LOOPING);
1434 if(This->isplaying) state = AL_PLAYING;
1436 else
1438 alSourcei(This->source, AL_LOOPING, (flags&DSBPLAY_LOOPING) ? AL_TRUE : AL_FALSE);
1439 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1440 checkALError();
1443 hr = S_OK;
1444 if(state == AL_PLAYING)
1445 goto out;
1447 if(This->segsize == 0)
1449 if(state == AL_INITIAL)
1451 alSourcei(This->source, AL_BUFFER, data->bid);
1452 alSourcei(This->source, AL_BYTE_OFFSET, This->lastpos % data->buf_size);
1454 alSourcePlay(This->source);
1456 else
1458 alSourceRewind(This->source);
1459 alSourcei(This->source, AL_BUFFER, 0);
1460 This->queue_base = This->data_offset % data->buf_size;
1461 This->curidx = 0;
1463 if(alGetError() != AL_NO_ERROR)
1465 ERR("Couldn't start source\n");
1466 hr = DSERR_GENERIC;
1467 goto out;
1469 This->isplaying = TRUE;
1471 if(This->nnotify)
1472 DSBuffer_addnotify(This);
1474 out:
1475 popALContext();
1476 LeaveCriticalSection(&This->share->crst);
1477 return hr;
1480 static HRESULT WINAPI DSBuffer_SetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD pos)
1482 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1483 DSData *data;
1485 TRACE("(%p)->(%lu)\n", iface, pos);
1487 data = This->buffer;
1488 if(pos >= (DWORD)data->buf_size)
1489 return DSERR_INVALIDPARAM;
1490 pos -= pos%data->format.Format.nBlockAlign;
1492 EnterCriticalSection(&This->share->crst);
1494 if(This->segsize != 0)
1496 if(This->isplaying)
1498 setALContext(This->ctx);
1499 /* Perform a flush, so the next timer update will restart at the
1500 * proper position */
1501 alSourceRewind(This->source);
1502 alSourcei(This->source, AL_BUFFER, 0);
1503 checkALError();
1504 popALContext();
1506 This->queue_base = This->data_offset = pos;
1507 This->curidx = 0;
1509 else
1511 if(LIKELY(This->source))
1513 setALContext(This->ctx);
1514 alSourcei(This->source, AL_BYTE_OFFSET, pos);
1515 checkALError();
1516 popALContext();
1519 This->lastpos = pos;
1521 LeaveCriticalSection(&This->share->crst);
1522 return DS_OK;
1525 static HRESULT WINAPI DSBuffer_SetFormat(IDirectSoundBuffer8 *iface, const WAVEFORMATEX *wfx)
1527 /* This call only works on primary buffers */
1528 WARN("(%p)->(%p)\n", iface, wfx);
1529 return DSERR_INVALIDCALL;
1532 static HRESULT WINAPI DSBuffer_SetVolume(IDirectSoundBuffer8 *iface, LONG vol)
1534 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1535 HRESULT hr = S_OK;
1537 TRACE("(%p)->(%ld)\n", iface, vol);
1539 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
1541 WARN("Invalid volume (%ld)\n", vol);
1542 return DSERR_INVALIDPARAM;
1545 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
1546 hr = DSERR_CONTROLUNAVAIL;
1547 else
1549 This->current.vol = vol;
1550 if(LIKELY(This->source))
1552 setALContext(This->ctx);
1553 alSourcef(This->source, AL_GAIN, mB_to_gain((float)vol));
1554 popALContext();
1558 return hr;
1561 static HRESULT WINAPI DSBuffer_SetPan(IDirectSoundBuffer8 *iface, LONG pan)
1563 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1564 HRESULT hr = S_OK;
1566 TRACE("(%p)->(%ld)\n", iface, pan);
1568 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
1570 WARN("invalid parameter: pan = %ld\n", pan);
1571 return DSERR_INVALIDPARAM;
1574 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
1575 hr = DSERR_CONTROLUNAVAIL;
1576 else
1578 This->current.pan = pan;
1579 if(LIKELY(This->source && !(This->buffer->dsbflags&DSBCAPS_CTRL3D)))
1581 ALfloat pos[3];
1582 pos[0] = (ALfloat)(pan-DSBPAN_LEFT)/(ALfloat)(DSBPAN_RIGHT-DSBPAN_LEFT) - 0.5f;
1583 pos[1] = 0.0f;
1584 /* NOTE: Strict movement along the X plane can cause the sound to
1585 * jump between left and right sharply. Using a curved path helps
1586 * smooth it out.
1588 pos[2] = -sqrtf(1.0f - pos[0]*pos[0]);
1590 setALContext(This->ctx);
1591 alSourcefv(This->source, AL_POSITION, pos);
1592 checkALError();
1593 popALContext();
1597 return hr;
1600 static HRESULT WINAPI DSBuffer_SetFrequency(IDirectSoundBuffer8 *iface, DWORD freq)
1602 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1603 DSData *data;
1604 HRESULT hr = S_OK;
1606 TRACE("(%p)->(%lu)\n", iface, freq);
1608 if(freq != 0 && (freq < DSBFREQUENCY_MIN || freq > DSBFREQUENCY_MAX))
1610 WARN("invalid parameter: freq = %lu\n", freq);
1611 return DSERR_INVALIDPARAM;
1614 data = This->buffer;
1615 if(!(data->dsbflags&DSBCAPS_CTRLFREQUENCY))
1616 hr = DSERR_CONTROLUNAVAIL;
1617 else
1619 This->current.frequency = freq ? freq : data->format.Format.nSamplesPerSec;
1620 if(LIKELY(This->source))
1622 setALContext(This->ctx);
1623 alSourcef(This->source, AL_PITCH,
1624 This->current.frequency / (ALfloat)data->format.Format.nSamplesPerSec
1626 checkALError();
1627 popALContext();
1631 return hr;
1634 static HRESULT WINAPI DSBuffer_Stop(IDirectSoundBuffer8 *iface)
1636 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1638 TRACE("(%p)->()\n", iface);
1640 EnterCriticalSection(&This->share->crst);
1641 if(LIKELY(This->source))
1643 const ALuint source = This->source;
1644 ALint state, ofs;
1646 setALContext(This->ctx);
1647 alSourcePause(source);
1648 alGetSourcei(source, AL_BYTE_OFFSET, &ofs);
1649 alGetSourcei(source, AL_SOURCE_STATE, &state);
1650 checkALError();
1652 This->isplaying = FALSE;
1653 if(This->nnotify)
1654 DSPrimary_triggernots(This->primary);
1655 /* Ensure the notification's last tracked position is updated, as well
1656 * as the queue offsets for streaming sources.
1658 if(This->segsize == 0)
1659 This->lastpos = (state == AL_STOPPED) ? This->buffer->buf_size : ofs;
1660 else
1662 DSData *data = This->buffer;
1663 ALint done = 0;
1665 alGetSourcei(This->source, AL_BUFFERS_PROCESSED, &done);
1666 This->queue_base += This->segsize*done + ofs;
1667 if(This->queue_base >= data->buf_size)
1669 if(This->islooping)
1670 This->queue_base %= data->buf_size;
1671 else
1672 This->queue_base = data->buf_size;
1674 This->lastpos = This->queue_base;
1676 alSourceRewind(This->source);
1677 alSourcei(This->source, AL_BUFFER, 0);
1678 checkALError();
1680 This->curidx = 0;
1681 This->data_offset = This->lastpos % data->buf_size;
1683 This->islooping = FALSE;
1684 popALContext();
1686 LeaveCriticalSection(&This->share->crst);
1688 return S_OK;
1691 static HRESULT WINAPI DSBuffer_Unlock(IDirectSoundBuffer8 *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
1693 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1694 DSData *buf = This->buffer;
1695 DWORD bufsize = buf->buf_size;
1696 DWORD_PTR ofs1, ofs2;
1697 DWORD_PTR boundary = (DWORD_PTR)buf->data;
1698 HRESULT hr;
1700 TRACE("(%p)->(%p, %lu, %p, %lu)\n", iface, ptr1, len1, ptr2, len2);
1702 if(InterlockedExchange(&buf->locked, FALSE) == FALSE)
1704 WARN("Not locked\n");
1705 return DSERR_INVALIDPARAM;
1708 hr = DSERR_INVALIDPARAM;
1709 /* Make sure offset is between boundary and boundary + bufsize */
1710 ofs1 = (DWORD_PTR)ptr1;
1711 ofs2 = (DWORD_PTR)ptr2;
1712 if(ofs1 < boundary || (ofs2 && ofs2 != boundary))
1713 goto out;
1714 ofs1 -= boundary;
1715 ofs2 = 0;
1716 if(bufsize-ofs1 < len1 || len2 > ofs1)
1717 goto out;
1718 if(!ptr2)
1719 len2 = 0;
1721 hr = DS_OK;
1722 if(!len1 && !len2)
1723 goto out;
1725 if(HAS_EXTENSION(This->share, SOFTX_MAP_BUFFER))
1727 setALContext(This->ctx);
1728 alFlushMappedBufferSOFT(buf->bid, 0, buf->buf_size);
1729 checkALError();
1730 popALContext();
1732 else if(This->segsize == 0)
1734 setALContext(This->ctx);
1735 alBufferData(buf->bid, buf->buf_format, buf->data, buf->buf_size,
1736 buf->format.Format.nSamplesPerSec);
1737 checkALError();
1738 popALContext();
1741 out:
1742 if(hr != S_OK)
1743 WARN("Invalid parameters (%p,%lu) (%p,%lu,%p,%lu)\n", (void*)boundary, bufsize,
1744 ptr1, len1, ptr2, len2);
1745 return hr;
1748 static HRESULT WINAPI DSBuffer_Restore(IDirectSoundBuffer8 *iface)
1750 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1751 HRESULT hr;
1753 TRACE("(%p)->()\n", iface);
1755 EnterCriticalSection(&This->share->crst);
1756 if(This->primary->parent->prio_level < DSSCL_WRITEPRIMARY ||
1757 (IDirectSoundBuffer*)&This->IDirectSoundBuffer8_iface == This->primary->write_emu)
1759 This->bufferlost = 0;
1760 hr = S_OK;
1762 else
1763 hr = DSERR_BUFFERLOST;
1764 LeaveCriticalSection(&This->share->crst);
1766 return hr;
1769 static HRESULT WINAPI DSBuffer_SetFX(IDirectSoundBuffer8 *iface, DWORD fxcount, DSEFFECTDESC *desc, DWORD *rescodes)
1771 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1772 ALenum state = AL_INITIAL;
1773 DSData *data;
1774 HRESULT hr;
1775 DWORD i;
1777 TRACE("(%p)->(%lu, %p, %p)\n", This, fxcount, desc, rescodes);
1779 data = This->buffer;
1780 if(!(data->dsbflags&DSBCAPS_CTRLFX))
1782 WARN("FX control not set\n");
1783 return DSERR_CONTROLUNAVAIL;
1786 if(data->locked)
1788 WARN("Buffer is locked\n");
1789 return DSERR_INVALIDCALL;
1792 EnterCriticalSection(&This->share->crst);
1794 setALContext(This->ctx);
1795 if(LIKELY(This->source))
1797 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1798 checkALError();
1800 popALContext();
1801 if(This->segsize != 0 && state != AL_PLAYING)
1802 state = This->isplaying ? AL_PLAYING : AL_PAUSED;
1803 if(state == AL_PLAYING)
1805 WARN("Buffer is playing\n");
1806 hr = DSERR_INVALIDCALL;
1807 goto done;
1810 hr = DSERR_INVALIDPARAM;
1811 if(fxcount == 0)
1813 if(desc || rescodes)
1815 WARN("Non-NULL desc and/or result pointer specified with no effects.\n");
1816 goto done;
1819 /* No effects; we can handle that */
1820 hr = DS_OK;
1821 goto done;
1824 if(!desc || !rescodes)
1826 WARN("NULL desc and/or result pointer specified.\n");
1827 goto done;
1830 /* We don't (currently) handle DSound effects */
1831 for(i = 0;i < fxcount;++i)
1833 FIXME("Cannot handle effect: %s\n", debugstr_guid(&desc[i].guidDSFXClass));
1834 rescodes[i] = DSFXR_FAILED;
1836 hr = DS_INCOMPLETE;
1838 done:
1839 LeaveCriticalSection(&This->share->crst);
1841 return hr;
1844 static HRESULT WINAPI DSBuffer_AcquireResources(IDirectSoundBuffer8 *iface, DWORD flags, DWORD fxcount, DWORD *rescodes)
1846 DSBuffer *This = impl_from_IDirectSoundBuffer8(iface);
1847 HRESULT hr;
1849 TRACE("(%p)->(%lu, %lu, %p)\n", This, flags, fxcount, rescodes);
1851 /* effects aren't supported at the moment.. */
1852 if(fxcount != 0 || rescodes)
1854 WARN("Non-zero effect count and/or result pointer specified with no effects.\n");
1855 return DSERR_INVALIDPARAM;
1858 EnterCriticalSection(&This->share->crst);
1859 setALContext(This->ctx);
1861 hr = DS_OK;
1862 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1864 DWORD loc = 0;
1866 hr = DSERR_INVALIDPARAM;
1867 if((flags&(DSBPLAY_LOCSOFTWARE|DSBPLAY_LOCHARDWARE)) == (DSBPLAY_LOCSOFTWARE|DSBPLAY_LOCHARDWARE))
1869 WARN("Both hardware and software specified\n");
1870 goto out;
1873 if((flags&DSBPLAY_LOCHARDWARE)) loc = DSBSTATUS_LOCHARDWARE;
1874 else if((flags&DSBPLAY_LOCSOFTWARE)) loc = DSBSTATUS_LOCSOFTWARE;
1876 if(loc && This->loc_status && loc != This->loc_status)
1878 ALint state = AL_INITIAL;
1880 if(This->segsize != 0)
1882 if(This->isplaying)
1883 state = AL_PLAYING;
1885 else
1887 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1888 checkALError();
1891 if(state == AL_PLAYING)
1893 ERR("Attemping to change location on playing buffer\n");
1894 goto out;
1898 hr = DSBuffer_SetLoc(This, loc);
1901 out:
1902 popALContext();
1903 LeaveCriticalSection(&This->share->crst);
1904 return hr;
1907 static HRESULT WINAPI DSBuffer_GetObjectInPath(IDirectSoundBuffer8 *iface, REFGUID guid, DWORD idx, REFGUID rguidiface, void **ppv)
1909 FIXME("(%p)->(%s, %lu, %s, %p) : stub!\n", iface, debugstr_guid(guid), idx, debugstr_guid(rguidiface), ppv);
1910 return E_NOTIMPL;
1913 static IDirectSoundBuffer8Vtbl DSBuffer_Vtbl = {
1914 DSBuffer_QueryInterface,
1915 DSBuffer_AddRef,
1916 DSBuffer_Release,
1917 DSBuffer_GetCaps,
1918 DSBuffer_GetCurrentPosition,
1919 DSBuffer_GetFormat,
1920 DSBuffer_GetVolume,
1921 DSBuffer_GetPan,
1922 DSBuffer_GetFrequency,
1923 DSBuffer_GetStatus,
1924 DSBuffer_Initialize,
1925 DSBuffer_Lock,
1926 DSBuffer_Play,
1927 DSBuffer_SetCurrentPosition,
1928 DSBuffer_SetFormat,
1929 DSBuffer_SetVolume,
1930 DSBuffer_SetPan,
1931 DSBuffer_SetFrequency,
1932 DSBuffer_Stop,
1933 DSBuffer_Unlock,
1934 DSBuffer_Restore,
1935 DSBuffer_SetFX,
1936 DSBuffer_AcquireResources,
1937 DSBuffer_GetObjectInPath
1941 void DSBuffer_SetParams(DSBuffer *This, const DS3DBUFFER *params, LONG flags)
1943 DSPrimary *prim = This->primary;
1944 const ALuint source = This->source;
1945 union BufferParamFlags dirty = { flags };
1946 ALsizei i;
1948 /* Copy deferred parameters first. */
1949 if(dirty.bit.pos)
1950 This->current.ds3d.vPosition = params->vPosition;
1951 if(dirty.bit.vel)
1952 This->current.ds3d.vVelocity = params->vVelocity;
1953 if(dirty.bit.cone_angles)
1955 This->current.ds3d.dwInsideConeAngle = params->dwInsideConeAngle;
1956 This->current.ds3d.dwOutsideConeAngle = params->dwOutsideConeAngle;
1958 if(dirty.bit.cone_orient)
1959 This->current.ds3d.vConeOrientation = params->vConeOrientation;
1960 if(dirty.bit.cone_outsidevolume)
1961 This->current.ds3d.lConeOutsideVolume = params->lConeOutsideVolume;
1962 if(dirty.bit.min_distance)
1963 This->current.ds3d.flMinDistance = params->flMinDistance;
1964 if(dirty.bit.max_distance)
1965 This->current.ds3d.flMaxDistance = params->flMaxDistance;
1966 if(dirty.bit.mode)
1967 This->current.ds3d.dwMode = params->dwMode;
1968 /* Always copy EAX params (they're always set deferred first, then applied
1969 * when committing all params).
1971 This->current.eax = This->deferred.eax;
1972 for(i = 0;i < EAX_MAX_ACTIVE_FXSLOTS;++i)
1973 This->current.fxslot_targets[i] = This->deferred.fxslot_targets[i];
1974 for(i = 0;i < EAX_MAX_FXSLOTS;++i)
1975 This->current.send[i] = This->deferred.send[i];
1976 This->current.eax1_reverbmix = This->deferred.eax1_reverbmix;
1978 /* Now apply what's changed to OpenAL. */
1979 if(UNLIKELY(!source)) return;
1981 if(dirty.bit.pos)
1982 alSource3f(source, AL_POSITION, params->vPosition.x, params->vPosition.y,
1983 -params->vPosition.z);
1984 if(dirty.bit.vel)
1985 alSource3f(source, AL_VELOCITY, params->vVelocity.x, params->vVelocity.y,
1986 -params->vVelocity.z);
1987 if(dirty.bit.cone_angles)
1989 alSourcei(source, AL_CONE_INNER_ANGLE, params->dwInsideConeAngle);
1990 alSourcei(source, AL_CONE_OUTER_ANGLE, params->dwOutsideConeAngle);
1992 if(dirty.bit.cone_orient)
1993 alSource3f(source, AL_DIRECTION, params->vConeOrientation.x,
1994 params->vConeOrientation.y,
1995 -params->vConeOrientation.z);
1996 if(dirty.bit.cone_outsidevolume)
1997 alSourcef(source, AL_CONE_OUTER_GAIN, mB_to_gain((float)params->lConeOutsideVolume));
1998 if(dirty.bit.min_distance)
1999 alSourcef(source, AL_REFERENCE_DISTANCE, params->flMinDistance);
2000 if(dirty.bit.max_distance)
2001 alSourcef(source, AL_MAX_DISTANCE, params->flMaxDistance);
2002 if(dirty.bit.mode)
2004 if(HAS_EXTENSION(This->share, SOFT_SOURCE_SPATIALIZE))
2005 alSourcei(source, AL_SOURCE_SPATIALIZE_SOFT,
2006 (params->dwMode==DS3DMODE_DISABLE) ? AL_FALSE : AL_TRUE
2008 alSourcei(source, AL_SOURCE_RELATIVE,
2009 (params->dwMode!=DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE
2013 if(dirty.bit.dry_filter)
2014 alSourcei(source, AL_DIRECT_FILTER, This->filter[0]);
2015 if(dirty.bit.send_filters)
2017 for(i = 0;i < EAX_MAX_ACTIVE_FXSLOTS;++i)
2019 DWORD target = This->current.fxslot_targets[i];
2020 ALuint filter=0, slot=0;
2021 if(target < FXSLOT_TARGET_NULL)
2023 ALint idx = (target == FXSLOT_TARGET_PRIMARY) ?
2024 prim->primary_idx : (ALint)target;
2025 if(idx >= 0)
2027 slot = prim->auxslot[idx];
2028 filter = This->filter[1+idx];
2031 alSource3i(source, AL_AUXILIARY_SEND_FILTER, slot, i, filter);
2034 if(dirty.bit.doppler)
2035 alSourcef(source, AL_DOPPLER_FACTOR, This->current.eax.flDopplerFactor);
2036 if(dirty.bit.rolloff)
2037 alSourcef(source, AL_ROLLOFF_FACTOR, This->current.eax.flRolloffFactor +
2038 prim->current.ds3d.flRolloffFactor);
2039 if(dirty.bit.room_rolloff)
2040 alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, This->current.eax.flRoomRolloffFactor);
2041 if(dirty.bit.cone_outsidevolumehf)
2042 alSourcef(source, AL_CONE_OUTER_GAINHF, mB_to_gain((float)This->current.eax.lOutsideVolumeHF));
2043 if(dirty.bit.air_absorb)
2044 alSourcef(source, AL_AIR_ABSORPTION_FACTOR, This->current.eax.flAirAbsorptionFactor *
2045 prim->current.ctx.flAirAbsorptionHF / -5.0f);
2046 if(dirty.bit.flags)
2048 alSourcei(source, AL_DIRECT_FILTER_GAINHF_AUTO,
2049 (This->current.eax.dwFlags&EAXSOURCEFLAGS_DIRECTHFAUTO) ? AL_TRUE : AL_FALSE);
2050 alSourcei(source, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
2051 (This->current.eax.dwFlags&EAXSOURCEFLAGS_ROOMAUTO) ? AL_TRUE : AL_FALSE);
2052 alSourcei(source, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
2053 (This->current.eax.dwFlags&EAXSOURCEFLAGS_ROOMHFAUTO) ? AL_TRUE : AL_FALSE);
2057 static HRESULT WINAPI DSBuffer3D_QueryInterface(IDirectSound3DBuffer *iface, REFIID riid, void **ppv)
2059 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2060 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2061 return DSBuffer_GetInterface(This, riid, ppv);
2064 static ULONG WINAPI DSBuffer3D_AddRef(IDirectSound3DBuffer *iface)
2066 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2067 LONG ret;
2069 InterlockedIncrement(&This->all_ref);
2070 ret = InterlockedIncrement(&This->ds3d_ref);
2071 TRACE("(%p) ref %lu\n", iface, ret);
2073 return ret;
2076 static ULONG WINAPI DSBuffer3D_Release(IDirectSound3DBuffer *iface)
2078 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2079 LONG ret;
2081 ret = InterlockedDecrement(&This->ds3d_ref);
2082 TRACE("(%p) ref %lu\n", iface, ret);
2083 if(InterlockedDecrement(&This->all_ref) == 0)
2084 DSBuffer_Destroy(This);
2086 return ret;
2089 static HRESULT WINAPI DSBuffer3D_GetConeAngles(IDirectSound3DBuffer *iface, DWORD *pdwInsideConeAngle, DWORD *pdwOutsideConeAngle)
2091 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2093 TRACE("(%p)->(%p, %p)\n", This, pdwInsideConeAngle, pdwOutsideConeAngle);
2094 if(!pdwInsideConeAngle || !pdwOutsideConeAngle)
2096 WARN("Invalid pointers (%p, %p)\n", pdwInsideConeAngle, pdwOutsideConeAngle);
2097 return DSERR_INVALIDPARAM;
2100 EnterCriticalSection(&This->share->crst);
2101 *pdwInsideConeAngle = This->current.ds3d.dwInsideConeAngle;
2102 *pdwOutsideConeAngle = This->current.ds3d.dwOutsideConeAngle;
2103 LeaveCriticalSection(&This->share->crst);
2105 return S_OK;
2108 static HRESULT WINAPI DSBuffer3D_GetConeOrientation(IDirectSound3DBuffer *iface, D3DVECTOR *orient)
2110 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2112 TRACE("(%p)->(%p)\n", This, orient);
2113 if(!orient)
2115 WARN("Invalid pointer\n");
2116 return DSERR_INVALIDPARAM;
2119 EnterCriticalSection(&This->share->crst);
2120 *orient = This->current.ds3d.vConeOrientation;
2121 LeaveCriticalSection(&This->share->crst);
2123 return S_OK;
2126 static HRESULT WINAPI DSBuffer3D_GetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG *vol)
2128 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2130 TRACE("(%p)->(%p)\n", This, vol);
2131 if(!vol)
2133 WARN("Invalid pointer\n");
2134 return DSERR_INVALIDPARAM;
2137 *vol = This->current.ds3d.lConeOutsideVolume;
2138 return S_OK;
2141 static HRESULT WINAPI DSBuffer3D_GetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE *maxdist)
2143 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2145 TRACE("(%p)->(%p)\n", This, maxdist);
2146 if(!maxdist)
2148 WARN("Invalid pointer\n");
2149 return DSERR_INVALIDPARAM;
2152 *maxdist = This->current.ds3d.flMaxDistance;
2153 return S_OK;
2156 static HRESULT WINAPI DSBuffer3D_GetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE *mindist)
2158 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2160 TRACE("(%p)->(%p)\n", This, mindist);
2161 if(!mindist)
2163 WARN("Invalid pointer\n");
2164 return DSERR_INVALIDPARAM;
2167 *mindist = This->current.ds3d.flMinDistance;
2168 return S_OK;
2171 static HRESULT WINAPI DSBuffer3D_GetMode(IDirectSound3DBuffer *iface, DWORD *mode)
2173 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2175 TRACE("(%p)->(%p)\n", This, mode);
2176 if(!mode)
2178 WARN("Invalid pointer\n");
2179 return DSERR_INVALIDPARAM;
2182 *mode = This->current.ds3d.dwMode;
2183 return S_OK;
2186 static HRESULT WINAPI DSBuffer3D_GetPosition(IDirectSound3DBuffer *iface, D3DVECTOR *pos)
2188 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2190 TRACE("(%p)->(%p)\n", This, pos);
2191 if(!pos)
2193 WARN("Invalid pointer\n");
2194 return DSERR_INVALIDPARAM;
2197 EnterCriticalSection(&This->share->crst);
2198 *pos = This->current.ds3d.vPosition;
2199 LeaveCriticalSection(&This->share->crst);
2201 return S_OK;
2204 static HRESULT WINAPI DSBuffer3D_GetVelocity(IDirectSound3DBuffer *iface, D3DVECTOR *vel)
2206 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2208 TRACE("(%p)->(%p)\n", This, vel);
2209 if(!vel)
2211 WARN("Invalid pointer\n");
2212 return DSERR_INVALIDPARAM;
2215 EnterCriticalSection(&This->share->crst);
2216 *vel = This->current.ds3d.vVelocity;
2217 LeaveCriticalSection(&This->share->crst);
2219 return S_OK;
2222 static HRESULT WINAPI DSBuffer3D_GetAllParameters(IDirectSound3DBuffer *iface, DS3DBUFFER *ds3dbuffer)
2224 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2226 TRACE("(%p)->(%p)\n", iface, ds3dbuffer);
2228 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
2230 WARN("Invalid parameters %p %lu\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
2231 return DSERR_INVALIDPARAM;
2234 EnterCriticalSection(&This->share->crst);
2235 ds3dbuffer->vPosition = This->current.ds3d.vPosition;
2236 ds3dbuffer->vVelocity = This->current.ds3d.vVelocity;
2237 ds3dbuffer->dwInsideConeAngle = This->current.ds3d.dwInsideConeAngle;
2238 ds3dbuffer->dwOutsideConeAngle = This->current.ds3d.dwOutsideConeAngle;
2239 ds3dbuffer->vConeOrientation = This->current.ds3d.vConeOrientation;
2240 ds3dbuffer->lConeOutsideVolume = This->current.ds3d.lConeOutsideVolume;
2241 ds3dbuffer->flMinDistance = This->current.ds3d.flMinDistance;
2242 ds3dbuffer->flMaxDistance = This->current.ds3d.flMaxDistance;
2243 ds3dbuffer->dwMode = This->current.ds3d.dwMode;
2244 LeaveCriticalSection(&This->share->crst);
2246 return DS_OK;
2249 static HRESULT WINAPI DSBuffer3D_SetConeAngles(IDirectSound3DBuffer *iface, DWORD dwInsideConeAngle, DWORD dwOutsideConeAngle, DWORD apply)
2251 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2253 TRACE("(%p)->(%lu, %lu, %lu)\n", This, dwInsideConeAngle, dwOutsideConeAngle, apply);
2254 if(dwInsideConeAngle > DS3D_MAXCONEANGLE || dwOutsideConeAngle > DS3D_MAXCONEANGLE)
2256 WARN("Invalid cone angles (%lu, %lu)\n", dwInsideConeAngle, dwOutsideConeAngle);
2257 return DSERR_INVALIDPARAM;
2260 EnterCriticalSection(&This->share->crst);
2261 if(apply == DS3D_DEFERRED)
2263 This->deferred.ds3d.dwInsideConeAngle = dwInsideConeAngle;
2264 This->deferred.ds3d.dwOutsideConeAngle = dwOutsideConeAngle;
2265 This->dirty.bit.cone_angles = 1;
2267 else
2269 setALContext(This->ctx);
2270 This->current.ds3d.dwInsideConeAngle = dwInsideConeAngle;
2271 This->current.ds3d.dwOutsideConeAngle = dwOutsideConeAngle;
2272 if(LIKELY(This->source))
2274 alSourcei(This->source, AL_CONE_INNER_ANGLE, dwInsideConeAngle);
2275 alSourcei(This->source, AL_CONE_OUTER_ANGLE, dwOutsideConeAngle);
2276 checkALError();
2278 popALContext();
2280 LeaveCriticalSection(&This->share->crst);
2282 return S_OK;
2285 static HRESULT WINAPI DSBuffer3D_SetConeOrientation(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2287 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2289 TRACE("(%p)->(%f, %f, %f, %lu)\n", This, x, y, z, apply);
2291 EnterCriticalSection(&This->share->crst);
2292 if(apply == DS3D_DEFERRED)
2294 This->deferred.ds3d.vConeOrientation.x = x;
2295 This->deferred.ds3d.vConeOrientation.y = y;
2296 This->deferred.ds3d.vConeOrientation.z = z;
2297 This->dirty.bit.cone_orient = 1;
2299 else
2301 setALContext(This->ctx);
2302 This->current.ds3d.vConeOrientation.x = x;
2303 This->current.ds3d.vConeOrientation.y = y;
2304 This->current.ds3d.vConeOrientation.z = z;
2305 if(LIKELY(This->source))
2307 alSource3f(This->source, AL_DIRECTION, x, y, -z);
2308 checkALError();
2310 popALContext();
2312 LeaveCriticalSection(&This->share->crst);
2314 return S_OK;
2317 static HRESULT WINAPI DSBuffer3D_SetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG vol, DWORD apply)
2319 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2321 TRACE("(%p)->(%ld, %lu)\n", This, vol, apply);
2322 if(vol < DSBVOLUME_MIN || vol > DSBVOLUME_MAX)
2324 WARN("Invalid volume (%ld)\n", vol);
2325 return DSERR_INVALIDPARAM;
2328 EnterCriticalSection(&This->share->crst);
2329 if(apply == DS3D_DEFERRED)
2331 This->deferred.ds3d.lConeOutsideVolume = vol;
2332 This->dirty.bit.cone_outsidevolume = 1;
2334 else
2336 setALContext(This->ctx);
2337 This->current.ds3d.lConeOutsideVolume = vol;
2338 if(LIKELY(This->source))
2340 alSourcef(This->source, AL_CONE_OUTER_GAIN, mB_to_gain((float)vol));
2341 checkALError();
2343 popALContext();
2345 LeaveCriticalSection(&This->share->crst);
2347 return S_OK;
2350 static HRESULT WINAPI DSBuffer3D_SetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE maxdist, DWORD apply)
2352 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2354 TRACE("(%p)->(%f, %lu)\n", This, maxdist, apply);
2355 if(maxdist < 0.0f)
2357 WARN("Invalid max distance (%f)\n", maxdist);
2358 return DSERR_INVALIDPARAM;
2361 EnterCriticalSection(&This->share->crst);
2362 if(apply == DS3D_DEFERRED)
2364 This->deferred.ds3d.flMaxDistance = maxdist;
2365 This->dirty.bit.max_distance = 1;
2367 else
2369 setALContext(This->ctx);
2370 This->current.ds3d.flMaxDistance = maxdist;
2371 if(LIKELY(This->source))
2373 alSourcef(This->source, AL_MAX_DISTANCE, maxdist);
2374 checkALError();
2376 popALContext();
2378 LeaveCriticalSection(&This->share->crst);
2380 return S_OK;
2383 static HRESULT WINAPI DSBuffer3D_SetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE mindist, DWORD apply)
2385 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2387 TRACE("(%p)->(%f, %lu)\n", This, mindist, apply);
2388 if(mindist < 0.0f)
2390 WARN("Invalid min distance (%f)\n", mindist);
2391 return DSERR_INVALIDPARAM;
2394 EnterCriticalSection(&This->share->crst);
2395 if(apply == DS3D_DEFERRED)
2397 This->deferred.ds3d.flMinDistance = mindist;
2398 This->dirty.bit.min_distance = 1;
2400 else
2402 setALContext(This->ctx);
2403 This->current.ds3d.flMinDistance = mindist;
2404 if(LIKELY(This->source))
2406 alSourcef(This->source, AL_REFERENCE_DISTANCE, mindist);
2407 checkALError();
2409 popALContext();
2411 LeaveCriticalSection(&This->share->crst);
2413 return S_OK;
2416 static HRESULT WINAPI DSBuffer3D_SetMode(IDirectSound3DBuffer *iface, DWORD mode, DWORD apply)
2418 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2420 TRACE("(%p)->(%lu, %lu)\n", This, mode, apply);
2421 if(mode != DS3DMODE_NORMAL && mode != DS3DMODE_HEADRELATIVE &&
2422 mode != DS3DMODE_DISABLE)
2424 WARN("Invalid mode (%lu)\n", mode);
2425 return DSERR_INVALIDPARAM;
2428 EnterCriticalSection(&This->share->crst);
2429 if(apply == DS3D_DEFERRED)
2431 This->deferred.ds3d.dwMode = mode;
2432 This->dirty.bit.mode = 1;
2434 else
2436 setALContext(This->ctx);
2437 This->current.ds3d.dwMode = mode;
2438 if(LIKELY(This->source))
2440 if(HAS_EXTENSION(This->share, SOFT_SOURCE_SPATIALIZE))
2441 alSourcei(This->source, AL_SOURCE_SPATIALIZE_SOFT,
2442 (mode==DS3DMODE_DISABLE) ? AL_FALSE : AL_TRUE);
2443 alSourcei(This->source, AL_SOURCE_RELATIVE,
2444 (mode != DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE);
2445 checkALError();
2447 popALContext();
2449 LeaveCriticalSection(&This->share->crst);
2451 return S_OK;
2454 static HRESULT WINAPI DSBuffer3D_SetPosition(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2456 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2458 TRACE("(%p)->(%f, %f, %f, %lu)\n", This, x, y, z, apply);
2460 EnterCriticalSection(&This->share->crst);
2461 if(apply == DS3D_DEFERRED)
2463 This->deferred.ds3d.vPosition.x = x;
2464 This->deferred.ds3d.vPosition.y = y;
2465 This->deferred.ds3d.vPosition.z = z;
2466 This->dirty.bit.pos = 1;
2468 else
2470 setALContext(This->ctx);
2471 This->current.ds3d.vPosition.x = x;
2472 This->current.ds3d.vPosition.y = y;
2473 This->current.ds3d.vPosition.z = z;
2474 if(LIKELY(This->source))
2476 alSource3f(This->source, AL_POSITION, x, y, -z);
2477 checkALError();
2479 popALContext();
2481 LeaveCriticalSection(&This->share->crst);
2483 return S_OK;
2486 static HRESULT WINAPI DSBuffer3D_SetVelocity(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2488 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2490 TRACE("(%p)->(%f, %f, %f, %lu)\n", This, x, y, z, apply);
2492 EnterCriticalSection(&This->share->crst);
2493 if(apply == DS3D_DEFERRED)
2495 This->deferred.ds3d.vVelocity.x = x;
2496 This->deferred.ds3d.vVelocity.y = y;
2497 This->deferred.ds3d.vVelocity.z = z;
2498 This->dirty.bit.vel = 1;
2500 else
2502 setALContext(This->ctx);
2503 This->current.ds3d.vVelocity.x = x;
2504 This->current.ds3d.vVelocity.y = y;
2505 This->current.ds3d.vVelocity.z = z;
2506 if(LIKELY(This->source))
2508 alSource3f(This->source, AL_VELOCITY, x, y, -z);
2509 checkALError();
2511 popALContext();
2513 LeaveCriticalSection(&This->share->crst);
2515 return S_OK;
2518 static HRESULT WINAPI DSBuffer3D_SetAllParameters(IDirectSound3DBuffer *iface, const DS3DBUFFER *ds3dbuffer, DWORD apply)
2520 DSBuffer *This = impl_from_IDirectSound3DBuffer(iface);
2521 TRACE("(%p)->(%p, %lu)\n", This, ds3dbuffer, apply);
2523 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
2525 WARN("Invalid DS3DBUFFER (%p, %lu)\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
2526 return DSERR_INVALIDPARAM;
2529 if(ds3dbuffer->dwInsideConeAngle > DS3D_MAXCONEANGLE ||
2530 ds3dbuffer->dwOutsideConeAngle > DS3D_MAXCONEANGLE)
2532 WARN("Invalid cone angles (%lu, %lu)\n",
2533 ds3dbuffer->dwInsideConeAngle, ds3dbuffer->dwOutsideConeAngle);
2534 return DSERR_INVALIDPARAM;
2537 if(ds3dbuffer->lConeOutsideVolume > DSBVOLUME_MAX ||
2538 ds3dbuffer->lConeOutsideVolume < DSBVOLUME_MIN)
2540 WARN("Invalid cone outside volume (%ld)\n", ds3dbuffer->lConeOutsideVolume);
2541 return DSERR_INVALIDPARAM;
2544 if(ds3dbuffer->flMaxDistance < 0.0f)
2546 WARN("Invalid max distance (%f)\n", ds3dbuffer->flMaxDistance);
2547 return DSERR_INVALIDPARAM;
2550 if(ds3dbuffer->flMinDistance < 0.0f)
2552 WARN("Invalid min distance (%f)\n", ds3dbuffer->flMinDistance);
2553 return DSERR_INVALIDPARAM;
2556 if(ds3dbuffer->dwMode != DS3DMODE_NORMAL &&
2557 ds3dbuffer->dwMode != DS3DMODE_HEADRELATIVE &&
2558 ds3dbuffer->dwMode != DS3DMODE_DISABLE)
2560 WARN("Invalid mode (%lu)\n", ds3dbuffer->dwMode);
2561 return DSERR_INVALIDPARAM;
2564 if(apply == DS3D_DEFERRED)
2566 EnterCriticalSection(&This->share->crst);
2567 This->deferred.ds3d = *ds3dbuffer;
2568 This->deferred.ds3d.dwSize = sizeof(This->deferred.ds3d);
2569 This->dirty.bit.pos = 1;
2570 This->dirty.bit.vel = 1;
2571 This->dirty.bit.cone_angles = 1;
2572 This->dirty.bit.cone_orient = 1;
2573 This->dirty.bit.cone_outsidevolume = 1;
2574 This->dirty.bit.min_distance = 1;
2575 This->dirty.bit.max_distance = 1;
2576 This->dirty.bit.mode = 1;
2577 LeaveCriticalSection(&This->share->crst);
2579 else
2581 union BufferParamFlags dirty = { 0 };
2582 dirty.bit.pos = 1;
2583 dirty.bit.vel = 1;
2584 dirty.bit.cone_angles = 1;
2585 dirty.bit.cone_orient = 1;
2586 dirty.bit.cone_outsidevolume = 1;
2587 dirty.bit.min_distance = 1;
2588 dirty.bit.max_distance = 1;
2589 dirty.bit.mode = 1;
2591 EnterCriticalSection(&This->share->crst);
2592 setALContext(This->ctx);
2593 DSBuffer_SetParams(This, ds3dbuffer, dirty.flags);
2594 checkALError();
2595 popALContext();
2596 LeaveCriticalSection(&This->share->crst);
2599 return S_OK;
2602 static IDirectSound3DBufferVtbl DSBuffer3d_Vtbl =
2604 DSBuffer3D_QueryInterface,
2605 DSBuffer3D_AddRef,
2606 DSBuffer3D_Release,
2607 DSBuffer3D_GetAllParameters,
2608 DSBuffer3D_GetConeAngles,
2609 DSBuffer3D_GetConeOrientation,
2610 DSBuffer3D_GetConeOutsideVolume,
2611 DSBuffer3D_GetMaxDistance,
2612 DSBuffer3D_GetMinDistance,
2613 DSBuffer3D_GetMode,
2614 DSBuffer3D_GetPosition,
2615 DSBuffer3D_GetVelocity,
2616 DSBuffer3D_SetAllParameters,
2617 DSBuffer3D_SetConeAngles,
2618 DSBuffer3D_SetConeOrientation,
2619 DSBuffer3D_SetConeOutsideVolume,
2620 DSBuffer3D_SetMaxDistance,
2621 DSBuffer3D_SetMinDistance,
2622 DSBuffer3D_SetMode,
2623 DSBuffer3D_SetPosition,
2624 DSBuffer3D_SetVelocity
2628 static HRESULT WINAPI DSBufferNot_QueryInterface(IDirectSoundNotify *iface, REFIID riid, void **ppv)
2630 DSBuffer *This = impl_from_IDirectSoundNotify(iface);
2631 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2632 return DSBuffer_GetInterface(This, riid, ppv);
2635 static ULONG WINAPI DSBufferNot_AddRef(IDirectSoundNotify *iface)
2637 DSBuffer *This = impl_from_IDirectSoundNotify(iface);
2638 LONG ret;
2640 InterlockedIncrement(&This->all_ref);
2641 ret = InterlockedIncrement(&This->not_ref);
2642 TRACE("(%p) ref %lu\n", iface, ret);
2644 return ret;
2647 static ULONG WINAPI DSBufferNot_Release(IDirectSoundNotify *iface)
2649 DSBuffer *This = impl_from_IDirectSoundNotify(iface);
2650 LONG ret;
2652 ret = InterlockedDecrement(&This->not_ref);
2653 TRACE("(%p) ref %lu\n", iface, ret);
2654 if(InterlockedDecrement(&This->all_ref) == 0)
2655 DSBuffer_Destroy(This);
2657 return ret;
2660 static HRESULT WINAPI DSBufferNot_SetNotificationPositions(IDirectSoundNotify *iface, DWORD count, const DSBPOSITIONNOTIFY *notifications)
2662 DSBuffer *This = impl_from_IDirectSoundNotify(iface);
2663 DSBPOSITIONNOTIFY *nots;
2664 DWORD state;
2665 HRESULT hr;
2667 TRACE("(%p)->(%lu, %p))\n", iface, count, notifications);
2669 EnterCriticalSection(&This->share->crst);
2670 hr = DSERR_INVALIDPARAM;
2671 if(count && !notifications)
2672 goto out;
2674 hr = DSBuffer_GetStatus(&This->IDirectSoundBuffer8_iface, &state);
2675 if(FAILED(hr)) goto out;
2677 hr = DSERR_INVALIDCALL;
2678 if((state&DSBSTATUS_PLAYING))
2679 goto out;
2681 if(!count)
2683 HeapFree(GetProcessHeap(), 0, This->notify);
2684 This->notify = 0;
2685 This->nnotify = 0;
2686 hr = S_OK;
2688 else
2690 DWORD i;
2692 hr = DSERR_INVALIDPARAM;
2693 for(i = 0;i < count;++i)
2695 if(notifications[i].dwOffset >= (DWORD)This->buffer->buf_size &&
2696 notifications[i].dwOffset != (DWORD)DSBPN_OFFSETSTOP)
2697 goto out;
2700 hr = E_OUTOFMEMORY;
2701 nots = HeapAlloc(GetProcessHeap(), 0, count*sizeof(*nots));
2702 if(!nots) goto out;
2703 memcpy(nots, notifications, count*sizeof(*nots));
2705 HeapFree(GetProcessHeap(), 0, This->notify);
2706 This->notify = nots;
2707 This->nnotify = count;
2709 hr = S_OK;
2712 out:
2713 LeaveCriticalSection(&This->share->crst);
2714 return hr;
2717 static IDirectSoundNotifyVtbl DSBufferNot_Vtbl =
2719 DSBufferNot_QueryInterface,
2720 DSBufferNot_AddRef,
2721 DSBufferNot_Release,
2722 DSBufferNot_SetNotificationPositions
2726 static const char *debug_bufferprop(const GUID *guid)
2728 #define HANDLE_ID(id) if(IsEqualGUID(guid, &(id))) return #id
2729 HANDLE_ID(EAXPROPERTYID_EAX40_Source);
2730 HANDLE_ID(DSPROPSETID_EAX30_BufferProperties);
2731 HANDLE_ID(DSPROPSETID_EAX20_BufferProperties);
2732 HANDLE_ID(EAXPROPERTYID_EAX40_FXSlot0);
2733 HANDLE_ID(EAXPROPERTYID_EAX40_FXSlot1);
2734 HANDLE_ID(EAXPROPERTYID_EAX40_FXSlot2);
2735 HANDLE_ID(EAXPROPERTYID_EAX40_FXSlot3);
2736 HANDLE_ID(DSPROPSETID_EAX30_ListenerProperties);
2737 HANDLE_ID(DSPROPSETID_EAX20_ListenerProperties);
2738 HANDLE_ID(EAXPROPERTYID_EAX40_Context);
2739 HANDLE_ID(DSPROPSETID_EAX10_BufferProperties);
2740 HANDLE_ID(DSPROPSETID_EAX10_ListenerProperties);
2741 HANDLE_ID(DSPROPSETID_VoiceManager);
2742 HANDLE_ID(DSPROPSETID_ZOOMFX_BufferProperties);
2743 HANDLE_ID(DSPROPSETID_I3DL2_ListenerProperties);
2744 HANDLE_ID(DSPROPSETID_I3DL2_BufferProperties);
2745 #undef HANDLE_ID
2746 return debugstr_guid(guid);
2749 static HRESULT WINAPI DSBufferProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
2751 DSBuffer *This = impl_from_IKsPropertySet(iface);
2752 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2753 return DSBuffer_GetInterface(This, riid, ppv);
2756 static ULONG WINAPI DSBufferProp_AddRef(IKsPropertySet *iface)
2758 DSBuffer *This = impl_from_IKsPropertySet(iface);
2759 LONG ret;
2761 InterlockedIncrement(&This->all_ref);
2762 ret = InterlockedIncrement(&This->prop_ref);
2763 TRACE("(%p) ref %lu\n", iface, ret);
2765 return ret;
2768 static ULONG WINAPI DSBufferProp_Release(IKsPropertySet *iface)
2770 DSBuffer *This = impl_from_IKsPropertySet(iface);
2771 LONG ret;
2773 ret = InterlockedDecrement(&This->prop_ref);
2774 TRACE("(%p) ref %lu\n", iface, ret);
2775 if(InterlockedDecrement(&This->all_ref) == 0)
2776 DSBuffer_Destroy(This);
2778 return ret;
2781 /* NOTE: Due to some apparent quirks in DSound, the listener properties are
2782 handled through secondary buffers. */
2783 static HRESULT WINAPI DSBufferProp_Get(IKsPropertySet *iface,
2784 REFGUID guidPropSet, ULONG dwPropID,
2785 LPVOID pInstanceData, ULONG cbInstanceData,
2786 LPVOID pPropData, ULONG cbPropData,
2787 ULONG *pcbReturned)
2789 DSBuffer *This = impl_from_IKsPropertySet(iface);
2790 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2792 TRACE("(%p)->(%s, 0x%lx, %p, %lu, %p, %lu, %p)\n", iface, debug_bufferprop(guidPropSet),
2793 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData, pcbReturned);
2795 if(!pcbReturned)
2796 return E_POINTER;
2797 *pcbReturned = 0;
2799 if(cbPropData > 0 && !pPropData)
2801 WARN("pPropData is NULL with cbPropData > 0\n");
2802 return E_POINTER;
2805 EnterCriticalSection(&This->share->crst);
2806 if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_Source))
2807 hr = EAX4Source_Get(This, dwPropID, pPropData, cbPropData, pcbReturned);
2808 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX30_BufferProperties))
2809 hr = EAX3Buffer_Get(This, dwPropID, pPropData, cbPropData, pcbReturned);
2810 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2811 hr = EAX2Buffer_Get(This, dwPropID, pPropData, cbPropData, pcbReturned);
2812 else if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot0))
2813 hr = EAX4Slot_Get(This->primary, 0, dwPropID, pPropData, cbPropData, pcbReturned);
2814 else if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot1))
2815 hr = EAX4Slot_Get(This->primary, 1, dwPropID, pPropData, cbPropData, pcbReturned);
2816 else if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot2))
2817 hr = EAX4Slot_Get(This->primary, 2, dwPropID, pPropData, cbPropData, pcbReturned);
2818 else if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot3))
2819 hr = EAX4Slot_Get(This->primary, 3, dwPropID, pPropData, cbPropData, pcbReturned);
2820 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX30_ListenerProperties))
2821 hr = EAX3_Get(This->primary, dwPropID, pPropData, cbPropData, pcbReturned);
2822 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
2823 hr = EAX2_Get(This->primary, dwPropID, pPropData, cbPropData, pcbReturned);
2824 else if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_Context))
2825 hr = EAX4Context_Get(This->primary, dwPropID, pPropData, cbPropData, pcbReturned);
2826 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX10_BufferProperties))
2827 hr = EAX1Buffer_Get(This, dwPropID, pPropData, cbPropData, pcbReturned);
2828 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX10_ListenerProperties))
2829 hr = EAX1_Get(This->primary, dwPropID, pPropData, cbPropData, pcbReturned);
2830 else
2831 FIXME("Unhandled propset: %s\n", debug_bufferprop(guidPropSet));
2832 LeaveCriticalSection(&This->share->crst);
2834 return hr;
2837 static HRESULT WINAPI DSBufferProp_Set(IKsPropertySet *iface,
2838 REFGUID guidPropSet, ULONG dwPropID,
2839 LPVOID pInstanceData, ULONG cbInstanceData,
2840 LPVOID pPropData, ULONG cbPropData)
2842 DSBuffer *This = impl_from_IKsPropertySet(iface);
2843 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2844 LONG idx;
2846 TRACE("(%p)->(%s, 0x%lx, %p, %lu, %p, %lu)\n", iface, debug_bufferprop(guidPropSet),
2847 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData);
2849 if(cbPropData > 0 && !pPropData)
2851 WARN("pPropData is NULL with cbPropData > 0\n");
2852 return E_POINTER;
2855 EnterCriticalSection(&This->share->crst);
2856 if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_Source))
2858 DWORD propid = dwPropID & ~EAXSOURCE_PARAMETER_DEFERRED;
2859 BOOL immediate = !(dwPropID&EAXSOURCE_PARAMETER_DEFERRED);
2861 setALContext(This->ctx);
2862 hr = EAX4Source_Set(This, propid, pPropData, cbPropData);
2863 if(hr == DS_OK && immediate)
2865 DSPrimary *prim = This->primary;
2866 DSPrimary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
2868 popALContext();
2870 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX30_BufferProperties))
2872 DWORD propid = dwPropID & ~DSPROPERTY_EAX30BUFFER_DEFERRED;
2873 BOOL immediate = !(dwPropID&DSPROPERTY_EAX30BUFFER_DEFERRED);
2875 setALContext(This->ctx);
2876 hr = EAX3Buffer_Set(This, propid, pPropData, cbPropData);
2877 if(hr == DS_OK && immediate)
2879 DSPrimary *prim = This->primary;
2880 DSPrimary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
2882 popALContext();
2884 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2886 DWORD propid = dwPropID & ~DSPROPERTY_EAX20BUFFER_DEFERRED;
2887 BOOL immediate = !(dwPropID&DSPROPERTY_EAX20BUFFER_DEFERRED);
2889 setALContext(This->ctx);
2890 hr = EAX2Buffer_Set(This, propid, pPropData, cbPropData);
2891 if(hr == DS_OK && immediate)
2893 DSPrimary *prim = This->primary;
2894 DSPrimary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
2896 popALContext();
2898 else if(((idx=0),IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot0)) ||
2899 ((idx=1),IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot1)) ||
2900 ((idx=2),IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot2)) ||
2901 ((idx=3),IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot3)))
2903 DSPrimary *prim = This->primary;
2904 DWORD propid = dwPropID & ~EAXFXSLOT_PARAMETER_DEFERRED;
2905 BOOL immediate = !(dwPropID&EAXFXSLOT_PARAMETER_DEFERRED);
2907 setALContext(prim->ctx);
2908 hr = EAX4Slot_Set(prim, idx, propid, pPropData, cbPropData);
2909 if(hr == DS_OK && immediate)
2910 DSPrimary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
2911 popALContext();
2913 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX30_ListenerProperties))
2915 DSPrimary *prim = This->primary;
2916 DWORD propid = dwPropID & ~DSPROPERTY_EAX30LISTENER_DEFERRED;
2917 BOOL immediate = !(dwPropID&DSPROPERTY_EAX30LISTENER_DEFERRED);
2919 setALContext(prim->ctx);
2920 hr = EAX3_Set(prim, propid, pPropData, cbPropData);
2921 if(hr == DS_OK && immediate)
2922 DSPrimary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
2923 popALContext();
2925 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
2927 DSPrimary *prim = This->primary;
2928 DWORD propid = dwPropID & ~DSPROPERTY_EAX20LISTENER_DEFERRED;
2929 BOOL immediate = !(dwPropID&DSPROPERTY_EAX20LISTENER_DEFERRED);
2931 setALContext(prim->ctx);
2932 hr = EAX2_Set(prim, propid, pPropData, cbPropData);
2933 if(hr == DS_OK && immediate)
2934 DSPrimary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
2935 popALContext();
2937 else if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_Context))
2939 DSPrimary *prim = This->primary;
2940 DWORD propid = dwPropID & ~EAXCONTEXT_PARAMETER_DEFERRED;
2941 BOOL immediate = !(dwPropID&EAXCONTEXT_PARAMETER_DEFERRED);
2943 setALContext(prim->ctx);
2944 hr = EAX4Context_Set(prim, propid, pPropData, cbPropData);
2945 if(hr == DS_OK && immediate)
2946 DSPrimary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
2947 popALContext();
2949 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX10_BufferProperties))
2951 DWORD propid = dwPropID & ~DSPROPERTY_EAX20BUFFER_DEFERRED;
2952 BOOL immediate = !(dwPropID&DSPROPERTY_EAX20BUFFER_DEFERRED);
2954 setALContext(This->ctx);
2955 hr = EAX1Buffer_Set(This, propid, pPropData, cbPropData);
2956 if(hr == DS_OK && immediate)
2958 DSPrimary *prim = This->primary;
2959 DSPrimary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
2961 popALContext();
2963 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX10_ListenerProperties))
2965 DSPrimary *prim = This->primary;
2966 DWORD propid = dwPropID & ~DSPROPERTY_EAX20LISTENER_DEFERRED;
2967 BOOL immediate = !(dwPropID&DSPROPERTY_EAX20LISTENER_DEFERRED);
2969 setALContext(prim->ctx);
2970 hr = EAX1_Set(prim, propid, pPropData, cbPropData);
2971 if(hr == DS_OK && immediate)
2972 DSPrimary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
2973 popALContext();
2975 else
2976 FIXME("Unhandled propset: %s\n", debug_bufferprop(guidPropSet));
2977 LeaveCriticalSection(&This->share->crst);
2979 return hr;
2982 static HRESULT WINAPI DSBufferProp_QuerySupport(IKsPropertySet *iface,
2983 REFGUID guidPropSet, ULONG dwPropID,
2984 ULONG *pTypeSupport)
2986 DSBuffer *This = impl_from_IKsPropertySet(iface);
2987 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2989 TRACE("(%p)->(%s, 0x%lx, %p)\n", iface, debug_bufferprop(guidPropSet), dwPropID,
2990 pTypeSupport);
2992 if(!pTypeSupport)
2993 return E_POINTER;
2994 *pTypeSupport = 0;
2996 EnterCriticalSection(&This->share->crst);
2997 if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_Source))
2998 hr = EAX4Source_Query(This, dwPropID, pTypeSupport);
2999 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX30_BufferProperties))
3000 hr = EAX3Buffer_Query(This, dwPropID, pTypeSupport);
3001 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
3002 hr = EAX2Buffer_Query(This, dwPropID, pTypeSupport);
3003 else if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot0))
3004 hr = EAX4Slot_Query(This->primary, 0, dwPropID, pTypeSupport);
3005 else if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot1))
3006 hr = EAX4Slot_Query(This->primary, 1, dwPropID, pTypeSupport);
3007 else if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot2))
3008 hr = EAX4Slot_Query(This->primary, 2, dwPropID, pTypeSupport);
3009 else if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_FXSlot3))
3010 hr = EAX4Slot_Query(This->primary, 3, dwPropID, pTypeSupport);
3011 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX30_ListenerProperties))
3012 hr = EAX3_Query(This->primary, dwPropID, pTypeSupport);
3013 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
3014 hr = EAX2_Query(This->primary, dwPropID, pTypeSupport);
3015 else if(IsEqualIID(guidPropSet, &EAXPROPERTYID_EAX40_Context))
3016 hr = EAX4Context_Query(This->primary, dwPropID, pTypeSupport);
3017 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX10_ListenerProperties))
3018 hr = EAX1_Query(This->primary, dwPropID, pTypeSupport);
3019 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX10_BufferProperties))
3020 hr = EAX1Buffer_Query(This, dwPropID, pTypeSupport);
3021 else
3022 FIXME("Unhandled propset: %s (propid: %lu)\n", debug_bufferprop(guidPropSet), dwPropID);
3023 LeaveCriticalSection(&This->share->crst);
3025 return hr;
3028 static IKsPropertySetVtbl DSBufferProp_Vtbl =
3030 DSBufferProp_QueryInterface,
3031 DSBufferProp_AddRef,
3032 DSBufferProp_Release,
3033 DSBufferProp_Get,
3034 DSBufferProp_Set,
3035 DSBufferProp_QuerySupport