Check for the extension to determine support instead of the function
[dsound-openal.git] / buffer.c
blob59069cf0f76efb556c5d1a9161c43b1f96fdee8e
1 /* DirectSound COM interface
3 * Copyright 2009 Maarten Lankhorst
5 * Some code taken from the original dsound-openal implementation
6 * Copyright 2007-2009 Chris Robinson
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <stdarg.h>
25 #ifdef __WINESRC__
27 #define COBJMACROS
28 #define NONAMELESSSTRUCT
29 #define NONAMELESSUNION
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winuser.h"
33 #include "winnls.h"
34 #include "winreg.h"
35 #include "vfwmsgs.h"
36 #include "mmsystem.h"
37 #include "winternl.h"
38 #include "mmddk.h"
39 #include "wine/debug.h"
40 #include "dsound.h"
42 #include "dsound_private.h"
44 #include "ks.h"
45 #include "ksmedia.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
49 #else
51 #define WINVER 0x0600
52 #define INITGUID
53 #include <windows.h>
54 #include <dsound.h>
56 #include "dsound_private.h"
58 DEFINE_GUID(CLSID_DirectSoundPrivate,0x11ab3ec0,0x25ec,0x11d1,0xa4,0xd8,0x00,0xc0,0x4f,0xc2,0x8a,0xca);
60 DEFINE_GUID(DSPROPSETID_DirectSoundDevice,0x84624f82,0x25ec,0x11d1,0xa4,0xd8,0x00,0xc0,0x4f,0xc2,0x8a,0xca);
62 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
63 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
65 #ifndef E_PROP_ID_UNSUPPORTED
66 #define E_PROP_ID_UNSUPPORTED ((HRESULT)0x80070490)
67 #endif
69 #endif
71 #ifndef WAVE_FORMAT_IEEE_FLOAT
72 #define WAVE_FORMAT_IEEE_FLOAT 3
73 #endif
75 /* TODO: when bufferlost is set, return from all calls except initialize with
76 * DSERR_BUFFERLOST
78 static const IDirectSoundBuffer8Vtbl DS8Buffer_Vtbl;
79 static const IDirectSound3DBufferVtbl DS8Buffer3d_Vtbl;
80 static const IDirectSoundNotifyVtbl DS8BufferNot_Vtbl;
81 static const IKsPropertySetVtbl DS8BufferProp_Vtbl;
84 static inline DS8Buffer *impl_from_IDirectSoundBuffer8(IDirectSoundBuffer8 *iface)
86 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSoundBuffer8_iface);
88 /* Shares the same vtable */
89 static inline DS8Buffer *impl_from_IDirectSoundBuffer(IDirectSoundBuffer *iface)
91 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSoundBuffer8_iface);
94 static inline DS8Buffer *impl_from_IDirectSound3DBuffer(IDirectSound3DBuffer *iface)
96 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSound3DBuffer_iface);
99 static inline DS8Buffer *impl_from_IDirectSoundNotify(IDirectSoundNotify *iface)
101 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSoundNotify_iface);
104 static inline DS8Buffer *impl_from_IKsPropertySet(IKsPropertySet *iface)
106 return CONTAINING_RECORD(iface, DS8Buffer, IKsPropertySet_iface);
110 static void CALLBACK DS8Buffer_timer(UINT timerID, UINT msg, DWORD_PTR dwUser,
111 DWORD_PTR dw1, DWORD_PTR dw2)
113 (void)timerID;
114 (void)msg;
115 (void)dw1;
116 (void)dw2;
117 PostThreadMessageA(dwUser, WM_USER, 0, 0);
120 static void DS8Buffer_starttimer(DS8Primary *prim)
122 DWORD triggertime, res = DS_TIME_RES;
123 ALint refresh = FAKE_REFRESH_COUNT;
124 TIMECAPS time;
126 if(prim->timer_id)
127 return;
129 timeGetDevCaps(&time, sizeof(TIMECAPS));
131 alcGetIntegerv(prim->parent->device, ALC_REFRESH, 1, &refresh);
132 getALCError(prim->parent->device);
134 triggertime = 1000 / refresh / 2;
135 if(triggertime < time.wPeriodMin)
136 triggertime = time.wPeriodMin;
137 TRACE("Calling timer every %u ms for %i refreshes per second\n", triggertime, refresh);
139 if (res < time.wPeriodMin)
140 res = time.wPeriodMin;
141 if (timeBeginPeriod(res) == TIMERR_NOCANDO)
142 WARN("Could not set minimum resolution, don't expect sound\n");
144 prim->timer_res = res;
145 prim->timer_id = timeSetEvent(triggertime, res, DS8Buffer_timer, prim->thread_id, TIME_PERIODIC|TIME_KILL_SYNCHRONOUS);
148 /* Should be called with critsect held and context set.. */
149 static void DS8Buffer_addnotify(DS8Buffer *buf)
151 DS8Buffer **list;
152 DWORD i;
154 list = buf->primary->notifies;
155 for(i = 0; i < buf->primary->nnotifies; ++i)
157 if(buf == list[i])
159 ERR("Buffer %p already in notification list\n", buf);
160 return;
163 if(buf->primary->nnotifies == buf->primary->sizenotifies)
165 list = HeapReAlloc(GetProcessHeap(), 0, list, (buf->primary->nnotifies + 1) * sizeof(*list));
166 if(!list)
167 return;
168 buf->primary->sizenotifies++;
170 list[buf->primary->nnotifies++] = buf;
171 buf->primary->notifies = list;
175 static const char *get_fmtstr_PCM(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out)
177 out->Format = *format;
178 out->Format.cbSize = 0;
180 if(out->Format.nChannels != 1 && out->Format.nChannels != 2 &&
181 !prim->SupportedExt[EXT_MCFORMATS])
183 WARN("Multi-channel not available\n");
184 return NULL;
187 if(format->wBitsPerSample == 8)
189 switch(format->nChannels)
191 case 1: return "AL_FORMAT_MONO8";
192 case 2: return "AL_FORMAT_STEREO8";
193 case 4: return "AL_FORMAT_QUAD8";
194 case 6: return "AL_FORMAT_51CHN8";
195 case 7: return "AL_FORMAT_61CHN8";
196 case 8: return "AL_FORMAT_71CHN8";
197 default: break;
200 else if(format->wBitsPerSample == 16)
202 switch(format->nChannels)
204 case 1: return "AL_FORMAT_MONO16";
205 case 2: return "AL_FORMAT_STEREO16";
206 case 4: return "AL_FORMAT_QUAD16";
207 case 6: return "AL_FORMAT_51CHN16";
208 case 7: return "AL_FORMAT_61CHN16";
209 case 8: return "AL_FORMAT_71CHN16";
210 default: break;
214 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
215 format->wBitsPerSample, format->nChannels);
216 return NULL;
218 static ALenum get_fmt_PCM(const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out, ALenum *in_chans, ALenum *in_type)
220 out->Format = *format;
221 out->Format.cbSize = 0;
223 if(format->wBitsPerSample == 8)
225 *in_type = AL_UNSIGNED_BYTE;
226 switch(format->nChannels)
228 case 1: *in_chans = AL_MONO;
229 return AL_MONO8;
230 case 2: *in_chans = AL_STEREO;
231 return AL_STEREO8;
232 case 4: *in_chans = AL_QUAD;
233 return AL_QUAD8;
234 case 6: *in_chans = AL_5POINT1;
235 return AL_5POINT1_8;
236 case 7: *in_chans = AL_6POINT1;
237 return AL_6POINT1_8;
238 case 8: *in_chans = AL_7POINT1;
239 return AL_7POINT1_8;
240 default: break;
243 else if(format->wBitsPerSample == 16)
245 *in_type = AL_SHORT;
246 switch(format->nChannels)
248 case 1: *in_chans = AL_MONO;
249 return AL_MONO16;
250 case 2: *in_chans = AL_STEREO;
251 return AL_STEREO16;
252 case 4: *in_chans = AL_QUAD;
253 return AL_QUAD16;
254 case 6: *in_chans = AL_5POINT1;
255 return AL_5POINT1_16;
256 case 7: *in_chans = AL_6POINT1;
257 return AL_6POINT1_16;
258 case 8: *in_chans = AL_7POINT1;
259 return AL_7POINT1_16;
260 default: break;
263 #if 0 /* Will cause incorrect byte offsets */
264 else if(format->wBitsPerSample == 24)
266 *in_type = AL_BYTE3;
267 switch(format->nChannels)
269 case 1: *in_chans = AL_MONO;
270 return AL_MONO32F;
271 case 2: *in_chans = AL_STEREO;
272 return AL_STEREO32F;
273 case 4: *in_chans = AL_QUAD;
274 return AL_QUAD32F;
275 case 6: *in_chans = AL_5POINT1;
276 return AL_5POINT1_32F;
277 case 7: *in_chans = AL_6POINT1;
278 return AL_6POINT1_32F;
279 case 8: *in_chans = AL_7POINT1;
280 return AL_7POINT1_32F;
281 default: break;
284 #endif
285 else if(format->wBitsPerSample == 32)
287 *in_type = AL_INT;
288 switch(format->nChannels)
290 case 1: *in_chans = AL_MONO;
291 return AL_MONO32F;
292 case 2: *in_chans = AL_STEREO;
293 return AL_STEREO32F;
294 case 4: *in_chans = AL_QUAD;
295 return AL_QUAD32F;
296 case 6: *in_chans = AL_5POINT1;
297 return AL_5POINT1_32F;
298 case 7: *in_chans = AL_6POINT1;
299 return AL_6POINT1_32F;
300 case 8: *in_chans = AL_7POINT1;
301 return AL_7POINT1_32F;
302 default: break;
306 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
307 format->wBitsPerSample, format->nChannels);
308 return AL_NONE;
311 static const char *get_fmtstr_FLOAT(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out)
313 out->Format = *format;
314 out->Format.cbSize = 0;
316 if(out->Format.nChannels != 1 && out->Format.nChannels != 2 &&
317 !prim->SupportedExt[EXT_MCFORMATS])
319 WARN("Multi-channel not available\n");
320 return NULL;
323 if(format->wBitsPerSample == 32 && prim->SupportedExt[EXT_FLOAT32])
325 switch(format->nChannels)
327 case 1: return "AL_FORMAT_MONO_FLOAT32";
328 case 2: return "AL_FORMAT_STEREO_FLOAT32";
329 case 4: return "AL_FORMAT_QUAD32";
330 case 6: return "AL_FORMAT_51CHN32";
331 case 7: return "AL_FORMAT_61CHN32";
332 case 8: return "AL_FORMAT_71CHN32";
333 default: break;
337 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
338 format->wBitsPerSample, format->nChannels);
339 return NULL;
341 static ALenum get_fmt_FLOAT(const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out, ALenum *in_chans, ALenum *in_type)
343 out->Format = *format;
344 out->Format.cbSize = 0;
346 if(format->wBitsPerSample == 32)
348 *in_type = AL_FLOAT;
349 switch(format->nChannels)
351 case 1: *in_chans = AL_MONO;
352 return AL_MONO32F;
353 case 2: *in_chans = AL_STEREO;
354 return AL_STEREO32F;
355 case 4: *in_chans = AL_QUAD;
356 return AL_QUAD32F;
357 case 6: *in_chans = AL_5POINT1;
358 return AL_5POINT1_32F;
359 case 7: *in_chans = AL_6POINT1;
360 return AL_6POINT1_32F;
361 case 8: *in_chans = AL_7POINT1;
362 return AL_7POINT1_32F;
363 default: break;
366 #if 0 /* Will cause incorrect byte offsets */
367 else if(format->wBitsPerSample == 64)
369 *in_type = AL_DOUBLE;
370 switch(format->nChannels)
372 case 1: *in_chans = AL_MONO;
373 return AL_MONO32F;
374 case 2: *in_chans = AL_STEREO;
375 return AL_STEREO32F;
376 case 4: *in_chans = AL_QUAD;
377 return AL_QUAD32F;
378 case 6: *in_chans = AL_5POINT1;
379 return AL_5POINT1_32F;
380 case 7: *in_chans = AL_6POINT1;
381 return AL_6POINT1_32F;
382 case 8: *in_chans = AL_7POINT1;
383 return AL_7POINT1_32F;
384 default: break;
387 #endif
389 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
390 format->wBitsPerSample, format->nChannels);
391 return AL_NONE;
394 /* Speaker configs */
395 #define MONO SPEAKER_FRONT_CENTER
396 #define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)
397 #define REAR (SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
398 #define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
399 #define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
400 #define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
401 #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)
403 static const char *get_fmtstr_EXT(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out)
405 *out = *CONTAINING_RECORD(format, const WAVEFORMATEXTENSIBLE, Format);
406 out->Format.cbSize = sizeof(*out) - sizeof(out->Format);
408 if(!out->Samples.wValidBitsPerSample)
409 out->Samples.wValidBitsPerSample = out->Format.wBitsPerSample;
410 else if(out->Samples.wValidBitsPerSample != out->Format.wBitsPerSample)
412 FIXME("Padded samples not supported (%u of %u)\n", out->Samples.wValidBitsPerSample, out->Format.wBitsPerSample);
413 return NULL;
416 if(out->dwChannelMask != MONO && out->dwChannelMask != STEREO &&
417 !prim->SupportedExt[EXT_MCFORMATS])
419 WARN("Multi-channel not available\n");
420 return NULL;
423 if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
425 if(out->Samples.wValidBitsPerSample == 8)
427 switch(out->dwChannelMask)
429 case MONO: return "AL_FORMAT_MONO8";
430 case STEREO: return "AL_FORMAT_STEREO8";
431 case REAR: return "AL_FORMAT_REAR8";
432 case QUAD: return "AL_FORMAT_QUAD8";
433 case X5DOT1: return "AL_FORMAT_51CHN8";
434 case X6DOT1: return "AL_FORMAT_61CHN8";
435 case X7DOT1: return "AL_FORMAT_71CHN8";
436 default: break;
439 else if(out->Samples.wValidBitsPerSample == 16)
441 switch(out->dwChannelMask)
443 case MONO: return "AL_FORMAT_MONO16";
444 case STEREO: return "AL_FORMAT_STEREO16";
445 case REAR: return "AL_FORMAT_REAR16";
446 case QUAD: return "AL_FORMAT_QUAD16";
447 case X5DOT1: return "AL_FORMAT_51CHN16";
448 case X6DOT1: return "AL_FORMAT_61CHN16";
449 case X7DOT1: return "AL_FORMAT_71CHN16";
450 default: break;
454 FIXME("Could not get OpenAL PCM format (%d-bit, channelmask %#x)\n",
455 out->Samples.wValidBitsPerSample, out->dwChannelMask);
456 return NULL;
458 else if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) &&
459 prim->SupportedExt[EXT_FLOAT32])
461 if(out->Samples.wValidBitsPerSample == 32)
463 switch(out->dwChannelMask)
465 case MONO: return "AL_FORMAT_MONO_FLOAT32";
466 case STEREO: return "AL_FORMAT_STEREO_FLOAT32";
467 case REAR: return "AL_FORMAT_REAR32";
468 case QUAD: return "AL_FORMAT_QUAD32";
469 case X5DOT1: return "AL_FORMAT_51CHN32";
470 case X6DOT1: return "AL_FORMAT_61CHN32";
471 case X7DOT1: return "AL_FORMAT_71CHN32";
472 default: break;
475 else
477 WARN("Invalid float bits: %u\n", out->Samples.wValidBitsPerSample);
478 return NULL;
481 FIXME("Could not get OpenAL float format (%d-bit, channelmask %#x)\n",
482 out->Samples.wValidBitsPerSample, out->dwChannelMask);
483 return NULL;
485 else if(!IsEqualGUID(&out->SubFormat, &GUID_NULL))
486 ERR("Unhandled extensible format: %s\n", debugstr_guid(&out->SubFormat));
487 return NULL;
489 static ALenum get_fmt_EXT(const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out, ALenum *in_chans, ALenum *in_type)
491 *out = *CONTAINING_RECORD(format, const WAVEFORMATEXTENSIBLE, Format);
492 out->Format.cbSize = sizeof(*out) - sizeof(out->Format);
494 if(!out->Samples.wValidBitsPerSample)
495 out->Samples.wValidBitsPerSample = out->Format.wBitsPerSample;
496 else if(out->Samples.wValidBitsPerSample != out->Format.wBitsPerSample)
498 FIXME("Padded samples not supported (%u of %u)\n", out->Samples.wValidBitsPerSample, out->Format.wBitsPerSample);
499 return AL_NONE;
502 if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
504 if(out->Samples.wValidBitsPerSample == 8)
506 *in_type = AL_UNSIGNED_BYTE;
507 switch(out->dwChannelMask)
509 case MONO: *in_chans = AL_MONO;
510 return AL_MONO8;
511 case STEREO: *in_chans = AL_STEREO;
512 return AL_STEREO8;
513 case REAR: *in_chans = AL_REAR;
514 return AL_REAR8;
515 case QUAD: *in_chans = AL_QUAD;
516 return AL_QUAD8;
517 case X5DOT1: *in_chans = AL_5POINT1;
518 return AL_5POINT1_8;
519 case X6DOT1: *in_chans = AL_6POINT1;
520 return AL_6POINT1_8;
521 case X7DOT1: *in_chans = AL_7POINT1;
522 return AL_7POINT1_8;
523 default: break;
526 else if(out->Samples.wValidBitsPerSample == 16)
528 *in_type = AL_SHORT;
529 switch(out->dwChannelMask)
531 case MONO: *in_chans = AL_MONO;
532 return AL_MONO16;
533 case STEREO: *in_chans = AL_STEREO;
534 return AL_STEREO16;
535 case REAR: *in_chans = AL_REAR;
536 return AL_REAR16;
537 case QUAD: *in_chans = AL_QUAD;
538 return AL_QUAD16;
539 case X5DOT1: *in_chans = AL_5POINT1;
540 return AL_5POINT1_16;
541 case X6DOT1: *in_chans = AL_6POINT1;
542 return AL_6POINT1_16;
543 case X7DOT1: *in_chans = AL_7POINT1;
544 return AL_7POINT1_16;
545 default: break;
548 #if 0
549 else if(out->Samples.wValidBitsPerSample == 24)
551 *in_type = AL_BYTE3;
552 switch(out->dwChannelMask)
554 case MONO: *in_chans = AL_MONO;
555 return AL_MONO32F;
556 case STEREO: *in_chans = AL_STEREO;
557 return AL_STEREO32F;
558 case REAR: *in_chans = AL_REAR;
559 return AL_REAR32F;
560 case QUAD: *in_chans = AL_QUAD;
561 return AL_QUAD32F;
562 case X5DOT1: *in_chans = AL_5POINT1;
563 return AL_5POINT1_32F;
564 case X6DOT1: *in_chans = AL_6POINT1;
565 return AL_6POINT1_32F;
566 case X7DOT1: *in_chans = AL_7POINT1;
567 return AL_7POINT1_32F;
568 default: break;
571 #endif
572 else if(out->Samples.wValidBitsPerSample == 32)
574 *in_type = AL_INT;
575 switch(out->dwChannelMask)
577 case MONO: *in_chans = AL_MONO;
578 return AL_MONO32F;
579 case STEREO: *in_chans = AL_STEREO;
580 return AL_STEREO32F;
581 case REAR: *in_chans = AL_REAR;
582 return AL_REAR32F;
583 case QUAD: *in_chans = AL_QUAD;
584 return AL_QUAD32F;
585 case X5DOT1: *in_chans = AL_5POINT1;
586 return AL_5POINT1_32F;
587 case X6DOT1: *in_chans = AL_6POINT1;
588 return AL_6POINT1_32F;
589 case X7DOT1: *in_chans = AL_7POINT1;
590 return AL_7POINT1_32F;
591 default: break;
595 FIXME("Could not get OpenAL PCM format (%d-bit, channelmask %#x)\n",
596 out->Samples.wValidBitsPerSample, out->dwChannelMask);
597 return AL_NONE;
599 else if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
601 if(out->Samples.wValidBitsPerSample == 32)
603 *in_type = AL_FLOAT;
604 switch(out->dwChannelMask)
606 case MONO: *in_chans = AL_MONO;
607 return AL_MONO32F;
608 case STEREO: *in_chans = AL_STEREO;
609 return AL_STEREO32F;
610 case REAR: *in_chans = AL_REAR;
611 return AL_REAR32F;
612 case QUAD: *in_chans = AL_QUAD;
613 return AL_QUAD32F;
614 case X5DOT1: *in_chans = AL_5POINT1;
615 return AL_5POINT1_32F;
616 case X6DOT1: *in_chans = AL_6POINT1;
617 return AL_6POINT1_32F;
618 case X7DOT1: *in_chans = AL_7POINT1;
619 return AL_7POINT1_32F;
620 default: break;
623 #if 0
624 else if(out->Samples.wValidBitsPerSample == 64)
626 *in_type = AL_DOUBLE;
627 switch(out->dwChannelMask)
629 case MONO: *in_chans = AL_MONO;
630 return AL_MONO32F;
631 case STEREO: *in_chans = AL_STEREO;
632 return AL_STEREO32F;
633 case REAR: *in_chans = AL_REAR;
634 return AL_REAR32F;
635 case QUAD: *in_chans = AL_QUAD;
636 return AL_QUAD32F;
637 case X5DOT1: *in_chans = AL_5POINT1;
638 return AL_5POINT1_32F;
639 case X6DOT1: *in_chans = AL_6POINT1;
640 return AL_6POINT1_32F;
641 case X7DOT1: *in_chans = AL_7POINT1;
642 return AL_7POINT1_32F;
643 default: break;
646 #endif
647 else
649 WARN("Invalid float bits: %u\n", out->Samples.wValidBitsPerSample);
650 return AL_NONE;
653 FIXME("Could not get OpenAL float format (%d-bit, channelmask %#x)\n",
654 out->Samples.wValidBitsPerSample, out->dwChannelMask);
655 return AL_NONE;
657 else if(!IsEqualGUID(&out->SubFormat, &GUID_NULL))
658 ERR("Unhandled extensible format: %s\n", debugstr_guid(&out->SubFormat));
659 return AL_NONE;
662 static void DS8Data_Release(DS8Data *This);
663 static HRESULT DS8Data_Create(DS8Data **ppv, const DSBUFFERDESC *desc, DS8Primary *prim)
665 HRESULT hr = DSERR_INVALIDPARAM;
666 const WAVEFORMATEX *format;
667 DS8Data *pBuffer;
669 format = desc->lpwfxFormat;
670 TRACE("Requested buffer format:\n"
671 " FormatTag = 0x%04x\n"
672 " Channels = %d\n"
673 " SamplesPerSec = %u\n"
674 " AvgBytesPerSec = %u\n"
675 " BlockAlign = %d\n"
676 " BitsPerSample = %d\n",
677 format->wFormatTag, format->nChannels,
678 format->nSamplesPerSec, format->nAvgBytesPerSec,
679 format->nBlockAlign, format->wBitsPerSample);
681 if(format->nBlockAlign == 0)
683 WARN("Invalid BlockAlign specified\n");
684 return DSERR_INVALIDPARAM;
687 /* Generate a new buffer. Supporting the DSBCAPS_LOC* flags properly
688 * will need the EAX-RAM extension. Currently, we just tell the app it
689 * gets what it wanted. */
690 pBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pBuffer));
691 if(!pBuffer)
692 return E_OUTOFMEMORY;
693 pBuffer->ref = 1;
695 pBuffer->dsbflags = desc->dwFlags;
696 if((pBuffer->dsbflags&(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE)) == (DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE))
698 WARN("Hardware and software location requested\n");
699 goto fail;
701 if(!(pBuffer->dsbflags&(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE|DSBCAPS_LOCDEFER)))
702 pBuffer->dsbflags |= DSBCAPS_LOCHARDWARE;
704 pBuffer->buf_size = desc->dwBufferBytes + format->nBlockAlign - 1;
705 pBuffer->buf_size -= pBuffer->buf_size%format->nBlockAlign;
707 hr = DSERR_BUFFERTOOSMALL;
708 if(pBuffer->buf_size < DSBSIZE_MIN)
709 goto fail;
711 hr = DSERR_INVALIDPARAM;
712 if(pBuffer->buf_size > DSBSIZE_MAX)
713 goto fail;
715 pBuffer->numsegs = 1;
716 pBuffer->segsize = pBuffer->buf_size;
717 pBuffer->lastsegsize = pBuffer->buf_size;
719 if(!prim->SupportedExt[SOFT_BUFFER_SAMPLES])
721 const char *fmt_str;
723 if(!(pBuffer->dsbflags&DSBCAPS_STATIC) && !prim->SupportedExt[SOFT_BUFFER_SUB_DATA] &&
724 !prim->SupportedExt[EXT_STATIC_BUFFER])
726 ALCint refresh = FAKE_REFRESH_COUNT;
727 ALuint newSize;
729 alcGetIntegerv(prim->parent->device, ALC_REFRESH, 1, &refresh);
730 getALCError(prim->parent->device);
732 newSize = format->nAvgBytesPerSec/refresh + format->nBlockAlign - 1;
733 newSize -= newSize%format->nBlockAlign;
735 /* Make sure enough buffers are available */
736 if(newSize > pBuffer->buf_size/(QBUFFERS+2))
737 ERR("Buffer segments too large to stream (%u for %u)!\n",
738 newSize, pBuffer->buf_size);
739 else
741 pBuffer->numsegs = pBuffer->buf_size/newSize;
742 pBuffer->segsize = newSize;
743 pBuffer->lastsegsize = pBuffer->buf_size - (newSize*(pBuffer->numsegs-1));
744 TRACE("New streaming buffer (%u chunks, %u : %u sizes)\n",
745 pBuffer->numsegs, pBuffer->segsize, pBuffer->lastsegsize);
749 if(format->wFormatTag == WAVE_FORMAT_PCM)
750 fmt_str = get_fmtstr_PCM(prim, format, &pBuffer->format);
751 else if(format->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
752 fmt_str = get_fmtstr_FLOAT(prim, format, &pBuffer->format);
753 else if(format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
755 const WAVEFORMATEXTENSIBLE *wfe;
757 hr = DSERR_CONTROLUNAVAIL;
758 if(format->cbSize != sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) &&
759 format->cbSize != sizeof(WAVEFORMATEXTENSIBLE))
760 goto fail;
762 wfe = CONTAINING_RECORD(format, const WAVEFORMATEXTENSIBLE, Format);
763 TRACE("Extensible values:\n"
764 " Samples = %d\n"
765 " ChannelMask = 0x%x\n"
766 " SubFormat = %s\n",
767 wfe->Samples.wReserved, wfe->dwChannelMask,
768 debugstr_guid(&wfe->SubFormat));
770 fmt_str = get_fmtstr_EXT(prim, format, &pBuffer->format);
772 else
773 ERR("Unhandled formattag 0x%04x\n", format->wFormatTag);
775 hr = DSERR_INVALIDCALL;
776 if(!fmt_str)
777 goto fail;
779 pBuffer->buf_format = alGetEnumValue(fmt_str);
780 if(alGetError() != AL_NO_ERROR || pBuffer->buf_format == 0 ||
781 pBuffer->buf_format == -1)
783 WARN("Could not get OpenAL format from %s\n", fmt_str);
784 goto fail;
787 else
789 if(format->wFormatTag == WAVE_FORMAT_PCM)
790 pBuffer->buf_format = get_fmt_PCM(format, &pBuffer->format, &pBuffer->in_chans, &pBuffer->in_type);
791 else if(format->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
792 pBuffer->buf_format = get_fmt_FLOAT(format, &pBuffer->format, &pBuffer->in_chans, &pBuffer->in_type);
793 else if(format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
795 const WAVEFORMATEXTENSIBLE *wfe;
797 hr = DSERR_CONTROLUNAVAIL;
798 if(format->cbSize != sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) &&
799 format->cbSize != sizeof(WAVEFORMATEXTENSIBLE))
800 goto fail;
802 wfe = CONTAINING_RECORD(format, const WAVEFORMATEXTENSIBLE, Format);
803 TRACE("Extensible values:\n"
804 " Samples = %d\n"
805 " ChannelMask = 0x%x\n"
806 " SubFormat = %s\n",
807 wfe->Samples.wReserved, wfe->dwChannelMask,
808 debugstr_guid(&wfe->SubFormat));
810 pBuffer->buf_format = get_fmt_EXT(format, &pBuffer->format, &pBuffer->in_chans, &pBuffer->in_type);
812 else
813 ERR("Unhandled formattag 0x%04x\n", format->wFormatTag);
815 hr = DSERR_INVALIDCALL;
816 if(prim->ExtAL.IsBufferFormatSupportedSOFT(pBuffer->buf_format) == AL_FALSE)
818 WARN("Unsupported OpenAL format: 0x%x\n", pBuffer->buf_format);
819 goto fail;
823 hr = E_OUTOFMEMORY;
824 pBuffer->buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pBuffer->buffers)*pBuffer->numsegs);
825 pBuffer->data = HeapAlloc(GetProcessHeap(), 0, pBuffer->buf_size);
826 if(!pBuffer->buffers || !pBuffer->data)
827 goto fail;
829 alGenBuffers(pBuffer->numsegs, pBuffer->buffers);
830 getALError();
832 *ppv = pBuffer;
833 return S_OK;
835 fail:
836 DS8Data_Release(pBuffer);
837 return hr;
840 static void DS8Data_AddRef(DS8Data *data)
842 InterlockedIncrement(&data->ref);
845 /* This function is always called with the device lock held */
846 static void DS8Data_Release(DS8Data *This)
848 if(InterlockedDecrement(&This->ref)) return;
850 TRACE("Deleting %p\n", This);
851 if (This->buffers && This->buffers[0])
853 alDeleteBuffers(This->numsegs, This->buffers);
854 getALError();
856 HeapFree(GetProcessHeap(), 0, This->buffers);
857 HeapFree(GetProcessHeap(), 0, This->data);
858 HeapFree(GetProcessHeap(), 0, This);
861 HRESULT DS8Buffer_Create(DS8Buffer **ppv, DS8Primary *parent, IDirectSoundBuffer *orig)
863 HRESULT hr = DSERR_OUTOFMEMORY;
864 DS8Buffer *This;
865 DS8Buffer **bufs;
867 *ppv = NULL;
868 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
869 if(!This) return hr;
871 This->IDirectSoundBuffer8_iface.lpVtbl = (IDirectSoundBuffer8Vtbl*)&DS8Buffer_Vtbl;
872 This->IDirectSound3DBuffer_iface.lpVtbl = (IDirectSound3DBufferVtbl*)&DS8Buffer3d_Vtbl;
873 This->IDirectSoundNotify_iface.lpVtbl = (IDirectSoundNotifyVtbl*)&DS8BufferNot_Vtbl;
874 This->IKsPropertySet_iface.lpVtbl = (IKsPropertySetVtbl*)&DS8BufferProp_Vtbl;
876 This->primary = parent;
877 This->ctx = parent->ctx;
878 This->ExtAL = &parent->ExtAL;
879 This->crst = &parent->crst;
880 This->ref = This->all_ref = 1;
882 if(orig)
884 DS8Buffer *org = impl_from_IDirectSoundBuffer(orig);
885 hr = DSERR_BUFFERLOST;
886 if(org->bufferlost)
887 goto fail;
888 DS8Data_AddRef(org->buffer);
889 This->buffer = org->buffer;
892 /* Append to buffer list */
893 bufs = parent->buffers;
894 if(parent->nbuffers == parent->sizebuffers)
896 bufs = HeapReAlloc(GetProcessHeap(), 0, bufs, sizeof(*bufs)*(1+parent->nbuffers));
897 hr = DSERR_OUTOFMEMORY;
898 if(!bufs) goto fail;
899 parent->sizebuffers++;
901 parent->buffers = bufs;
902 bufs[parent->nbuffers++] = This;
904 /* Disable until initialized.. */
905 This->ds3dmode = DS3DMODE_DISABLE;
907 *ppv = This;
908 return S_OK;
910 fail:
911 DS8Buffer_Destroy(This);
912 return hr;
915 void DS8Buffer_Destroy(DS8Buffer *This)
917 DS8Primary *prim = This->primary;
918 DWORD idx;
920 TRACE("Destroying %p\n", This);
922 EnterCriticalSection(&prim->crst);
923 /* Remove from list, if in list */
924 for(idx = 0;idx < prim->nnotifies;++idx)
926 if(This == prim->notifies[idx])
928 prim->notifies[idx] = prim->notifies[--prim->nnotifies];
929 break;
932 for(idx = 0;idx < prim->nbuffers;++idx)
934 if(prim->buffers[idx] == This)
936 prim->buffers[idx] = prim->buffers[--prim->nbuffers];
937 break;
941 setALContext(This->ctx);
942 if(This->source)
944 ALuint *sources;
946 alSourceStop(This->source);
947 alSourcei(This->source, AL_BUFFER, 0);
948 getALError();
950 sources = prim->sources;
951 if(prim->nsources == prim->sizesources)
953 sources = HeapReAlloc(GetProcessHeap(), 0, sources, sizeof(*sources)*(prim->nsources+1));
954 if(!sources)
955 alDeleteSources(1, &This->source);
956 else
957 prim->sizesources++;
959 if(sources)
961 sources[prim->nsources++] = This->source;
962 prim->sources = sources;
964 This->source = 0;
966 LeaveCriticalSection(&prim->crst);
968 if(This->buffer)
969 DS8Data_Release(This->buffer);
971 popALContext();
973 HeapFree(GetProcessHeap(), 0, This->notify);
974 HeapFree(GetProcessHeap(), 0, This);
978 static HRESULT WINAPI DS8Buffer_QueryInterface(IDirectSoundBuffer8 *iface, REFIID riid, void **ppv)
980 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
982 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
984 *ppv = NULL;
985 if(IsEqualIID(riid, &IID_IUnknown) ||
986 IsEqualIID(riid, &IID_IDirectSoundBuffer))
987 *ppv = &This->IDirectSoundBuffer8_iface;
988 else if(IsEqualIID(riid, &IID_IDirectSoundBuffer8))
990 if(This->primary->parent->is_8)
991 *ppv = &This->IDirectSoundBuffer8_iface;
993 else if(IsEqualIID(riid, &IID_IDirectSound3DBuffer))
995 if((This->buffer->dsbflags&DSBCAPS_CTRL3D))
996 *ppv = &This->IDirectSound3DBuffer_iface;
998 else if(IsEqualIID(riid, &IID_IDirectSoundNotify))
1000 if((This->buffer->dsbflags&DSBCAPS_CTRLPOSITIONNOTIFY))
1001 *ppv = &This->IDirectSoundNotify_iface;
1003 else if(IsEqualIID(riid, &IID_IKsPropertySet))
1004 *ppv = &This->IKsPropertySet_iface;
1005 else
1006 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
1008 if(*ppv)
1010 IUnknown_AddRef((IUnknown*)*ppv);
1011 return S_OK;
1014 return E_NOINTERFACE;
1017 static ULONG WINAPI DS8Buffer_AddRef(IDirectSoundBuffer8 *iface)
1019 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1020 LONG ret;
1022 InterlockedIncrement(&This->all_ref);
1023 ret = InterlockedIncrement(&This->ref);
1024 TRACE("new refcount %d\n", ret);
1026 return ret;
1029 static ULONG WINAPI DS8Buffer_Release(IDirectSoundBuffer8 *iface)
1031 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1032 LONG ret;
1034 ret = InterlockedDecrement(&This->ref);
1035 TRACE("new refcount %d\n", ret);
1036 if(InterlockedDecrement(&This->all_ref) == 0)
1037 DS8Buffer_Destroy(This);
1039 return ret;
1042 static HRESULT WINAPI DS8Buffer_GetCaps(IDirectSoundBuffer8 *iface, DSBCAPS *caps)
1044 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1046 TRACE("(%p)->(%p)\n", iface, caps);
1048 if(!caps || caps->dwSize < sizeof(*caps))
1050 WARN("Invalid DSBCAPS (%p, %u)\n", caps, (caps ? caps->dwSize : 0));
1051 return DSERR_INVALIDPARAM;
1054 caps->dwFlags = This->buffer->dsbflags;
1055 caps->dwBufferBytes = This->buffer->buf_size;
1056 caps->dwUnlockTransferRate = 4096;
1057 caps->dwPlayCpuOverhead = 0;
1058 return S_OK;
1061 static HRESULT WINAPI DS8Buffer_GetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD *playpos, DWORD *curpos)
1063 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1064 WAVEFORMATEX *format = &This->buffer->format.Format;
1065 UINT writecursor, pos;
1067 TRACE("(%p)->(%p, %p)\n", iface, playpos, curpos);
1069 EnterCriticalSection(This->crst);
1070 setALContext(This->ctx);
1072 if(This->buffer->numsegs > 1)
1074 ALint queued = QBUFFERS;
1075 alGetSourcei(This->source, AL_BUFFERS_QUEUED, &queued);
1076 getALError();
1078 pos = (This->curidx+This->buffer->numsegs-queued)%This->buffer->numsegs;
1079 pos *= This->buffer->segsize;
1080 writecursor = This->curidx * This->buffer->segsize;
1082 else if(This->primary->SupportedExt[SOFT_BUFFER_SUB_DATA] ||
1083 This->primary->SupportedExt[SOFT_BUFFER_SAMPLES])
1085 ALint rwpos[2] = { 0, 0 };
1087 alGetSourceiv(This->source, AL_BYTE_RW_OFFSETS_SOFT, rwpos);
1088 getALError();
1090 pos = rwpos[0];
1091 writecursor = rwpos[1];
1093 else
1095 ALint status = 0;
1096 ALint ofs = 0;
1098 alGetSourcei(This->source, AL_BYTE_OFFSET, &ofs);
1099 alGetSourcei(This->source, AL_SOURCE_STATE, &status);
1100 getALError();
1102 pos = ofs;
1103 if(status == AL_PLAYING)
1105 writecursor = format->nSamplesPerSec / 100;
1106 writecursor *= format->nBlockAlign;
1108 else
1109 writecursor = 0;
1110 writecursor = (writecursor + pos) % This->buffer->buf_size;
1112 TRACE("%p Play pos = %u, write pos = %u\n", This, pos, writecursor);
1113 if(pos >= This->buffer->buf_size)
1115 ERR("playpos >= buf_size\n");
1116 pos %= This->buffer->buf_size;
1118 if(writecursor >= This->buffer->buf_size)
1120 ERR("writepos >= buf_size\n");
1121 writecursor %= This->buffer->buf_size;
1124 if(playpos) *playpos = pos;
1125 if(curpos) *curpos = writecursor;
1127 popALContext();
1128 LeaveCriticalSection(This->crst);
1130 return S_OK;
1133 static HRESULT WINAPI DS8Buffer_GetFormat(IDirectSoundBuffer8 *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
1135 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1136 HRESULT hr = S_OK;
1137 UINT size;
1139 TRACE("(%p)->(%p, %u, %p)\n", iface, wfx, allocated, written);
1141 if(!wfx && !written)
1143 WARN("Cannot report format or format size\n");
1144 return DSERR_INVALIDPARAM;
1147 EnterCriticalSection(This->crst);
1148 size = sizeof(This->buffer->format.Format) + This->buffer->format.Format.cbSize;
1149 if(wfx)
1151 if(allocated < size)
1152 hr = DSERR_INVALIDPARAM;
1153 else
1154 memcpy(wfx, &This->buffer->format.Format, size);
1156 if(written)
1157 *written = size;
1158 LeaveCriticalSection(This->crst);
1160 return hr;
1163 static HRESULT WINAPI DS8Buffer_GetVolume(IDirectSoundBuffer8 *iface, LONG *vol)
1165 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1166 HRESULT hr;
1168 TRACE("(%p)->(%p)\n", iface, vol);
1170 if(!vol)
1172 WARN("Invalid pointer\n");
1173 return DSERR_INVALIDPARAM;
1176 EnterCriticalSection(This->crst);
1178 hr = DSERR_CONTROLUNAVAIL;
1179 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
1180 WARN("Volume control not set\n");
1181 else
1183 ALfloat gain = 1.0f;
1185 setALContext(This->ctx);
1186 alGetSourcef(This->source, AL_GAIN, &gain);
1187 getALError();
1188 popALContext();
1190 *vol = gain_to_mB(gain);
1191 *vol = min(*vol, DSBVOLUME_MAX);
1192 *vol = max(*vol, DSBVOLUME_MIN);
1194 hr = DS_OK;
1197 LeaveCriticalSection(This->crst);
1198 return hr;
1201 static HRESULT WINAPI DS8Buffer_GetPan(IDirectSoundBuffer8 *iface, LONG *pan)
1203 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1204 HRESULT hr;
1206 TRACE("(%p)->(%p)\n", iface, pan);
1208 if(!pan)
1210 WARN("Invalid pointer\n");
1211 return DSERR_INVALIDPARAM;
1214 EnterCriticalSection(This->crst);
1216 hr = DSERR_CONTROLUNAVAIL;
1217 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
1218 WARN("Panning control not set\n");
1219 else
1221 ALfloat pos[3];
1223 setALContext(This->ctx);
1224 alGetSourcefv(This->source, AL_POSITION, pos);
1225 getALError();
1226 popALContext();
1228 *pan = (LONG)((pos[0]+1.0) * (DSBPAN_RIGHT-DSBPAN_LEFT) / 2.0 + 0.5) + DSBPAN_LEFT;
1229 *pan = min(*pan, DSBPAN_RIGHT);
1230 *pan = max(*pan, DSBPAN_LEFT);
1232 hr = DS_OK;
1235 LeaveCriticalSection(This->crst);
1236 return hr;
1239 static HRESULT WINAPI DS8Buffer_GetFrequency(IDirectSoundBuffer8 *iface, DWORD *freq)
1241 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1242 HRESULT hr;
1244 TRACE("(%p)->(%p)\n", iface, freq);
1246 if(!freq)
1248 WARN("Invalid pointer\n");
1249 return DSERR_INVALIDPARAM;
1252 EnterCriticalSection(This->crst);
1254 hr = DSERR_CONTROLUNAVAIL;
1255 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
1256 WARN("Frequency control not set\n");
1257 else
1259 ALfloat pitch = 1.0f;
1261 setALContext(This->ctx);
1262 alGetSourcefv(This->source, AL_PITCH, &pitch);
1263 getALError();
1264 popALContext();
1266 *freq = (DWORD)(This->buffer->format.Format.nSamplesPerSec * pitch);
1268 hr = DS_OK;
1271 LeaveCriticalSection(This->crst);
1272 return hr;
1275 static HRESULT WINAPI DS8Buffer_GetStatus(IDirectSoundBuffer8 *iface, DWORD *status)
1277 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1278 ALint state, looping;
1280 TRACE("(%p)->(%p)\n", iface, status);
1282 if(!status)
1284 WARN("Invalid pointer\n");
1285 return DSERR_INVALIDPARAM;
1288 EnterCriticalSection(This->crst);
1290 setALContext(This->ctx);
1291 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1292 looping = This->islooping;
1293 if(This->buffer->numsegs == 1)
1294 alGetSourcei(This->source, AL_LOOPING, &looping);
1295 else if(state != AL_PLAYING)
1296 state = This->isplaying ? AL_PLAYING : AL_PAUSED;
1297 getALError();
1298 popALContext();
1300 *status = 0;
1301 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1303 if((This->buffer->dsbflags&DSBCAPS_LOCSOFTWARE))
1304 *status |= DSBSTATUS_LOCSOFTWARE;
1305 else if((This->buffer->dsbflags&DSBCAPS_LOCHARDWARE))
1306 *status |= DSBSTATUS_LOCHARDWARE;
1308 if(state == AL_PLAYING)
1309 *status |= DSBSTATUS_PLAYING | (looping ? DSBSTATUS_LOOPING : 0);
1311 LeaveCriticalSection(This->crst);
1313 return S_OK;
1316 static HRESULT WINAPI DS8Buffer_Initialize(IDirectSoundBuffer8 *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
1318 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1319 DS3DBUFFER *ds3dbuffer;
1320 HRESULT hr;
1322 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
1324 EnterCriticalSection(This->crst);
1325 setALContext(This->ctx);
1327 hr = DSERR_ALREADYINITIALIZED;
1328 if(This->source)
1329 goto out;
1331 if(!This->buffer)
1333 hr = DSERR_INVALIDPARAM;
1334 if(!desc)
1336 WARN("Missing DSound buffer description\n");
1337 goto out;
1339 if(!desc->lpwfxFormat)
1341 WARN("Missing buffer format (%p)\n", This);
1342 goto out;
1344 if((desc->dwFlags&DSBCAPS_CTRL3D) && desc->lpwfxFormat->nChannels != 1)
1346 if(This->primary->parent->is_8)
1348 /* DirectSoundBuffer8 objects aren't allowed non-mono 3D
1349 * buffers */
1350 WARN("Can't create multi-channel 3D buffers\n");
1351 goto out;
1353 ERR("Multi-channel 3D sounds are not spatialized\n");
1356 hr = DS8Data_Create(&This->buffer, desc, This->primary);
1357 if(FAILED(hr))
1358 goto out;
1359 else
1361 DS8Data *buf = This->buffer;
1363 if(buf->format.Format.wBitsPerSample == 8)
1364 memset(buf->data, 0x80, buf->buf_size);
1365 else
1366 memset(buf->data, 0x00, buf->buf_size);
1368 if(This->primary->SupportedExt[EXT_STATIC_BUFFER])
1369 This->ExtAL->BufferDataStatic(buf->buffers[0], buf->buf_format,
1370 buf->data, buf->buf_size,
1371 buf->format.Format.nSamplesPerSec);
1372 else if(This->primary->SupportedExt[SOFT_BUFFER_SAMPLES])
1373 This->ExtAL->BufferSamplesSOFT(buf->buffers[0],
1374 buf->format.Format.nSamplesPerSec, buf->buf_format,
1375 buf->buf_size/buf->format.Format.nBlockAlign,
1376 buf->in_chans, buf->in_type, buf->data);
1377 else if(This->primary->SupportedExt[SOFT_BUFFER_SUB_DATA])
1378 alBufferData(buf->buffers[0], buf->buf_format,
1379 buf->data, buf->buf_size,
1380 buf->format.Format.nSamplesPerSec);
1382 getALError();
1385 hr = DSERR_GENERIC;
1386 if(This->primary->nsources)
1388 This->source = This->primary->sources[--This->primary->nsources];
1389 alSourcef(This->source, AL_GAIN, 1.0f);
1390 alSourcef(This->source, AL_PITCH, 1.0f);
1391 getALError();
1393 else
1395 alGenSources(1, &This->source);
1396 if(alGetError() != AL_NO_ERROR)
1397 goto out;
1400 ds3dbuffer = &This->ds3dbuffer;
1401 ds3dbuffer->dwSize = sizeof(*ds3dbuffer);
1402 ds3dbuffer->vPosition.x = 0.0;
1403 ds3dbuffer->vPosition.y = 0.0;
1404 ds3dbuffer->vPosition.z = 0.0;
1405 ds3dbuffer->vVelocity.x = 0.0;
1406 ds3dbuffer->vVelocity.y = 0.0;
1407 ds3dbuffer->vVelocity.z = 0.0;
1408 ds3dbuffer->dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
1409 ds3dbuffer->dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
1410 ds3dbuffer->vConeOrientation.x = 0.0;
1411 ds3dbuffer->vConeOrientation.y = 0.0;
1412 ds3dbuffer->vConeOrientation.z = 1.0;
1413 ds3dbuffer->lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
1414 ds3dbuffer->flMinDistance = DS3D_DEFAULTMINDISTANCE;
1415 ds3dbuffer->flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
1416 ds3dbuffer->dwMode = DS3DMODE_NORMAL;
1418 if((This->buffer->dsbflags&DSBCAPS_CTRL3D))
1420 if(This->primary->auxslot != 0)
1422 alSource3i(This->source, AL_AUXILIARY_SEND_FILTER, This->primary->auxslot, 0, AL_FILTER_NULL);
1423 getALError();
1426 hr = IDirectSound3DBuffer_SetAllParameters(&This->IDirectSound3DBuffer_iface, ds3dbuffer, DS3D_IMMEDIATE);
1427 if(FAILED(hr))
1429 ERR("SetAllParameters failed\n");
1430 goto out;
1433 else
1435 ALuint source = This->source;
1437 if(This->primary->auxslot != 0)
1439 /* Simple hack to make reverb affect non-3D sounds too */
1440 alSource3i(source, AL_AUXILIARY_SEND_FILTER, This->primary->auxslot, 0, AL_FILTER_NULL);
1441 /*alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL);*/
1444 /* Non-3D sources aren't distance attenuated */
1445 This->ds3dmode = DS3DMODE_DISABLE;
1446 alSource3f(source, AL_POSITION, 0.0f, 1.0f, 0.0f);
1447 alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
1448 alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
1449 alSourcef(source, AL_CONE_OUTER_GAIN, 1.0f);
1450 alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f);
1451 alSourcef(source, AL_MAX_DISTANCE, 1000.0f);
1452 alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f);
1453 alSourcei(source, AL_CONE_INNER_ANGLE, 360);
1454 alSourcei(source, AL_CONE_OUTER_ANGLE, 360);
1455 alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);
1456 getALError();
1458 hr = S_OK;
1460 out:
1461 popALContext();
1462 LeaveCriticalSection(This->crst);
1464 return hr;
1467 static HRESULT WINAPI DS8Buffer_Lock(IDirectSoundBuffer8 *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
1469 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1470 HRESULT hr;
1471 DWORD remain;
1473 TRACE("(%p)->(%u, %u, %p, %p, %p, %p, 0x%x)\n", This, ofs, bytes, ptr1, len1, ptr2, len2, flags);
1475 if(!ptr1 || !len1)
1477 WARN("Invalid pointer/len %p %p\n", ptr1, len1);
1478 return DSERR_INVALIDPARAM;
1481 EnterCriticalSection(This->crst);
1482 setALContext(This->ctx);
1484 *ptr1 = NULL;
1485 *len1 = 0;
1486 if(ptr2) *ptr2 = NULL;
1487 if(len2) *len2 = 0;
1489 hr = DSERR_INVALIDPARAM;
1490 if((flags&DSBLOCK_FROMWRITECURSOR))
1491 DS8Buffer_GetCurrentPosition(iface, NULL, &ofs);
1492 else if(ofs >= This->buffer->buf_size)
1494 WARN("Invalid ofs %u\n", ofs);
1495 goto out;
1497 if((flags&DSBLOCK_ENTIREBUFFER))
1498 bytes = This->buffer->buf_size;
1499 else if(bytes > This->buffer->buf_size)
1501 WARN("Invalid size %u\n", bytes);
1502 goto out;
1505 *ptr1 = This->buffer->data + ofs;
1506 if(ofs+bytes >= This->buffer->buf_size)
1508 *len1 = This->buffer->buf_size - ofs;
1509 remain = bytes - *len1;
1511 else
1513 *len1 = bytes;
1514 remain = 0;
1517 This->buffer->locked = TRUE;
1519 if(ptr2 && len2 && remain)
1521 *ptr2 = This->buffer->data;
1522 *len2 = remain;
1524 hr = S_OK;
1526 out:
1527 popALContext();
1528 LeaveCriticalSection(This->crst);
1529 return hr;
1532 static HRESULT WINAPI DS8Buffer_Play(IDirectSoundBuffer8 *iface, DWORD res1, DWORD prio, DWORD flags)
1534 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1535 ALint type, state = AL_STOPPED;
1536 HRESULT hr;
1537 (void)res1;
1539 TRACE("%p\n", This);
1541 EnterCriticalSection(This->crst);
1542 setALContext(This->ctx);
1544 hr = DSERR_BUFFERLOST;
1545 if(This->bufferlost)
1547 WARN("Buffer %p lost\n", This);
1548 goto out;
1551 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1553 if(!(This->buffer->dsbflags&(DSBCAPS_LOCHARDWARE|DSBCAPS_LOCSOFTWARE)))
1555 if(flags & DSBPLAY_LOCSOFTWARE)
1556 This->buffer->dsbflags |= DSBCAPS_LOCSOFTWARE;
1557 else
1558 This->buffer->dsbflags |= DSBCAPS_LOCHARDWARE;
1561 else if(prio)
1563 ERR("Invalid priority set for non-deferred buffer %p, %u!\n", This->buffer, prio);
1564 hr = DSERR_INVALIDPARAM;
1565 goto out;
1568 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1569 if(This->buffer->numsegs > 1)
1571 This->islooping = !!(flags&DSBPLAY_LOOPING);
1572 if(state != AL_PLAYING && This->isplaying)
1573 state = AL_PLAYING;
1575 else
1577 alGetSourcei(This->source, AL_SOURCE_TYPE, &type);
1578 alSourcei(This->source, AL_LOOPING, (flags&DSBPLAY_LOOPING) ? AL_TRUE : AL_FALSE);
1580 getALError();
1582 hr = S_OK;
1583 if(state == AL_PLAYING)
1584 goto out;
1586 /* alSourceQueueBuffers will implicitly set type to streaming */
1587 if(This->buffer->numsegs == 1)
1589 if(type != AL_STATIC)
1590 alSourcei(This->source, AL_BUFFER, This->buffer->buffers[0]);
1591 alSourcePlay(This->source);
1593 if(alGetError() != AL_NO_ERROR)
1595 ERR("Couldn't start source\n");
1596 This->curidx = (This->buffer->numsegs-1+This->curidx)%This->buffer->numsegs;
1597 alSourcei(This->source, AL_BUFFER, 0);
1598 getALError();
1599 hr = DSERR_GENERIC;
1600 goto out;
1602 This->isplaying = TRUE;
1604 if(This->nnotify)
1606 DS8Buffer_addnotify(This);
1607 DS8Buffer_starttimer(This->primary);
1609 else if(This->buffer->numsegs > 1)
1610 DS8Buffer_starttimer(This->primary);
1612 out:
1613 popALContext();
1614 LeaveCriticalSection(This->crst);
1615 return hr;
1618 static HRESULT WINAPI DS8Buffer_SetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD pos)
1620 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1621 HRESULT hr;
1623 TRACE("(%p)->(%u)\n", iface, (UINT)pos);
1625 EnterCriticalSection(This->crst);
1626 setALContext(This->ctx);
1628 hr = DSERR_INVALIDPARAM;
1629 if(pos >= This->buffer->buf_size)
1630 goto out;
1632 if(This->buffer->numsegs > 1)
1634 DS8Data *buf = This->buffer;
1635 This->curidx = pos/buf->segsize;
1636 if(This->curidx >= buf->numsegs)
1637 This->curidx = buf->numsegs - 1;
1638 if(This->isplaying)
1640 /* Perform a flush, so the next timer update will restart at the
1641 * proper position */
1642 alSourceStop(This->source);
1643 alSourcei(This->source, AL_BUFFER, 0);
1644 getALError();
1647 else
1648 alSourcei(This->source, AL_BYTE_OFFSET, pos);
1649 This->lastpos = pos;
1650 hr = S_OK;
1652 out:
1653 popALContext();
1654 LeaveCriticalSection(This->crst);
1655 return hr;
1658 static HRESULT WINAPI DS8Buffer_SetFormat(IDirectSoundBuffer8 *iface, const WAVEFORMATEX *wfx)
1660 /* This call only works on primary buffers */
1661 WARN("(%p)->(%p)\n", iface, wfx);
1662 return DSERR_INVALIDCALL;
1665 static HRESULT WINAPI DS8Buffer_SetVolume(IDirectSoundBuffer8 *iface, LONG vol)
1667 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1668 HRESULT hr = S_OK;
1670 TRACE("(%p)->(%d)\n", iface, vol);
1672 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
1674 WARN("Invalid volume (%d)\n", vol);
1675 return DSERR_INVALIDPARAM;
1678 EnterCriticalSection(This->crst);
1679 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
1680 hr = DSERR_CONTROLUNAVAIL;
1681 if(SUCCEEDED(hr))
1683 ALfloat fvol = mB_to_gain(vol);
1684 setALContext(This->ctx);
1685 alSourcef(This->source, AL_GAIN, fvol);
1686 popALContext();
1688 LeaveCriticalSection(This->crst);
1690 return hr;
1693 static HRESULT WINAPI DS8Buffer_SetPan(IDirectSoundBuffer8 *iface, LONG pan)
1695 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1696 HRESULT hr = S_OK;
1698 TRACE("(%p)->(%d)\n", iface, pan);
1700 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
1702 WARN("invalid parameter: pan = %d\n", pan);
1703 return DSERR_INVALIDPARAM;
1706 EnterCriticalSection(This->crst);
1707 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
1708 hr = DSERR_CONTROLUNAVAIL;
1709 else
1711 ALfloat pos[3];
1712 pos[0] = (pan-DSBPAN_LEFT) * 2.0 / (ALfloat)(DSBPAN_RIGHT-DSBPAN_LEFT) - 1.0;
1713 /* NOTE: Strict movement along the X plane can cause the sound to jump
1714 * between left and right sharply. Using a curved path helps smooth it
1715 * out */
1716 pos[1] = sqrt(1.0 - pos[0]*pos[0]);
1717 pos[2] = 0.0;
1719 setALContext(This->ctx);
1720 alSourcefv(This->source, AL_POSITION, pos);
1721 getALError();
1722 popALContext();
1724 if(pan != 0 && This->buffer->format.Format.nChannels > 1)
1725 FIXME("Panning for multi-channel buffers is not supported\n");
1727 LeaveCriticalSection(This->crst);
1729 return hr;
1732 static HRESULT WINAPI DS8Buffer_SetFrequency(IDirectSoundBuffer8 *iface, DWORD freq)
1734 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1735 HRESULT hr = S_OK;
1737 TRACE("(%p)->(%u)\n", iface, freq);
1739 if(freq < DSBFREQUENCY_MIN || freq > DSBFREQUENCY_MAX)
1741 WARN("invalid parameter: freq = %d\n", freq);
1742 return DSERR_INVALIDPARAM;
1745 EnterCriticalSection(This->crst);
1746 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
1747 hr = DSERR_CONTROLUNAVAIL;
1748 else
1750 ALfloat pitch = 1.0f;
1751 if(freq != DSBFREQUENCY_ORIGINAL)
1752 pitch = freq / (ALfloat)This->buffer->format.Format.nSamplesPerSec;
1754 setALContext(This->ctx);
1755 alSourcef(This->source, AL_PITCH, pitch);
1756 getALError();
1757 popALContext();
1759 LeaveCriticalSection(This->crst);
1760 return hr;
1763 static HRESULT WINAPI DS8Buffer_Stop(IDirectSoundBuffer8 *iface)
1765 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1766 ALint state;
1768 TRACE("(%p)->()\n", iface);
1770 EnterCriticalSection(This->crst);
1771 setALContext(This->ctx);
1773 alSourcePause(This->source);
1774 getALError();
1775 /* Mac OS X doesn't immediately report state change
1776 * if Play() is immediately called after Stop, this can be fatal,
1777 * the buffer would never be restarted
1779 do {
1780 state = AL_PAUSED;
1781 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1782 if(state != AL_PLAYING)
1783 break;
1784 Sleep(1);
1785 } while(1);
1787 This->isplaying = FALSE;
1789 popALContext();
1790 LeaveCriticalSection(This->crst);
1792 return S_OK;
1795 static HRESULT WINAPI DS8Buffer_Unlock(IDirectSoundBuffer8 *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
1797 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1798 DS8Data *buf = This->buffer;
1799 DWORD bufsize = buf->buf_size;
1800 DWORD_PTR ofs1, ofs2;
1801 DWORD_PTR boundary = (DWORD_PTR)buf->data;
1802 HRESULT hr;
1804 TRACE("(%p)->(%p, %u, %p, %u)\n", iface, ptr1, len1, ptr2, len2);
1806 EnterCriticalSection(This->crst);
1807 setALContext(This->ctx);
1809 This->buffer->locked = 0;
1810 hr = DSERR_INVALIDPARAM;
1812 /* Make sure offset is between boundary and boundary + bufsize */
1813 ofs1 = (DWORD_PTR)ptr1;
1814 ofs2 = (DWORD_PTR)ptr2;
1815 if(ofs1 < boundary)
1816 goto out;
1817 if(ofs2 && ofs2 != boundary)
1818 goto out;
1819 ofs1 -= boundary;
1820 ofs2 = 0;
1821 if(bufsize-ofs1 < len1 || len2 > ofs1)
1822 goto out;
1823 if(!ptr2)
1824 len2 = 0;
1826 hr = S_OK;
1827 if(!len1 && !len2)
1828 goto out;
1830 if(This->primary->SupportedExt[EXT_STATIC_BUFFER])
1831 goto out;
1833 if(This->primary->SupportedExt[SOFT_BUFFER_SAMPLES])
1835 const WAVEFORMATEX *format = &buf->format.Format;
1837 ptr1 = (BYTE*)ptr1 - (ofs1%format->nBlockAlign);
1838 ofs1 /= format->nBlockAlign;
1839 len1 /= format->nBlockAlign;
1840 if(len1 > 0)
1841 This->ExtAL->BufferSubSamplesSOFT(buf->buffers[0], ofs1, len1,
1842 buf->in_chans, buf->in_type, ptr1);
1843 ptr2 = (BYTE*)ptr2 - (ofs2%format->nBlockAlign);
1844 ofs2 /= format->nBlockAlign;
1845 len2 /= format->nBlockAlign;
1846 if(len2 > 0)
1847 This->ExtAL->BufferSubSamplesSOFT(buf->buffers[0], ofs2, len2,
1848 buf->in_chans, buf->in_type, ptr2);
1849 getALError();
1851 else if(This->primary->SupportedExt[SOFT_BUFFER_SUB_DATA])
1853 const WAVEFORMATEX *format = &buf->format.Format;
1855 len1 -= len1%format->nBlockAlign;
1856 if(len1 > 0)
1857 This->ExtAL->BufferSubData(buf->buffers[0], buf->buf_format, ptr1,
1858 ofs1, len1);
1859 len2 -= len2%format->nBlockAlign;
1860 if(len2 > 0)
1861 This->ExtAL->BufferSubData(buf->buffers[0], buf->buf_format, ptr2,
1862 ofs2, len2);
1863 getALError();
1865 else
1867 alBufferData(buf->buffers[0], buf->buf_format,
1868 buf->data, buf->buf_size,
1869 buf->format.Format.nSamplesPerSec);
1870 getALError();
1873 out:
1874 if(hr != S_OK)
1875 WARN("Invalid parameters (0x%lx,%u) (%p,%u,%p,%u)\n", boundary, bufsize, ptr1, len1, ptr2, len2);
1876 popALContext();
1877 LeaveCriticalSection(This->crst);
1878 return hr;
1881 static HRESULT WINAPI DS8Buffer_Restore(IDirectSoundBuffer8 *iface)
1883 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1884 HRESULT hr;
1886 TRACE("(%p)->()\n", iface);
1888 EnterCriticalSection(This->crst);
1889 if(This->primary->parent->prio_level < DSSCL_WRITEPRIMARY ||
1890 iface == This->primary->write_emu)
1892 This->bufferlost = 0;
1893 hr = S_OK;
1895 else
1896 hr = DSERR_BUFFERLOST;
1897 LeaveCriticalSection(This->crst);
1899 return hr;
1902 static HRESULT WINAPI DS8Buffer_SetFX(IDirectSoundBuffer8 *iface, DWORD fxcount, DSEFFECTDESC *desc, DWORD *rescodes)
1904 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1905 DWORD i;
1907 TRACE("(%p)->(%u, %p, %p)\n", This, fxcount, desc, rescodes);
1909 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFX))
1911 WARN("FX control not set\n");
1912 return DSERR_CONTROLUNAVAIL;
1915 if(fxcount == 0)
1917 if(desc || rescodes)
1919 WARN("Non-NULL desc and/or result pointer specified with no effects.\n");
1920 return DSERR_INVALIDPARAM;
1923 /* No effects; we can handle that */
1924 return DS_OK;
1927 if(!desc || !rescodes)
1929 WARN("NULL desc and/or result pointer specified.\n");
1930 return DSERR_INVALIDPARAM;
1933 /* We don't (currently) handle DSound effects */
1934 for(i = 0;i < fxcount;++i)
1936 FIXME("Cannot handle effect: %s\n", debugstr_guid(&desc[i].guidDSFXClass));
1937 rescodes[i] = DSFXR_FAILED;
1940 return DS_INCOMPLETE;
1943 static HRESULT WINAPI DS8Buffer_AcquireResources(IDirectSoundBuffer8 *iface, DWORD flags, DWORD fxcount, DWORD *rescodes)
1945 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1947 TRACE("(%p)->(%u, %u, %p)\n", This, flags, fxcount, rescodes);
1949 /* effects aren't supported at the moment.. */
1950 if(fxcount != 0 || rescodes)
1952 WARN("Non-zero effect count and/or result pointer specified with no effects.\n");
1953 return DSERR_INVALIDPARAM;
1956 EnterCriticalSection(This->crst);
1957 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1959 This->buffer->dsbflags &= ~(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE);
1960 if((flags&DSBPLAY_LOCSOFTWARE))
1961 This->buffer->dsbflags |= DSBCAPS_LOCSOFTWARE;
1962 else
1963 This->buffer->dsbflags |= DSBCAPS_LOCHARDWARE;
1965 LeaveCriticalSection(This->crst);
1967 return S_OK;
1970 static HRESULT WINAPI DS8Buffer_GetObjectInPath(IDirectSoundBuffer8 *iface, REFGUID guid, DWORD idx, REFGUID rguidiface, void **ppv)
1972 FIXME("(%p)->(%s, %u, %s, %p) : stub!\n", iface, debugstr_guid(guid), idx, debugstr_guid(rguidiface), ppv);
1973 return E_NOTIMPL;
1976 static const IDirectSoundBuffer8Vtbl DS8Buffer_Vtbl =
1978 DS8Buffer_QueryInterface,
1979 DS8Buffer_AddRef,
1980 DS8Buffer_Release,
1981 DS8Buffer_GetCaps,
1982 DS8Buffer_GetCurrentPosition,
1983 DS8Buffer_GetFormat,
1984 DS8Buffer_GetVolume,
1985 DS8Buffer_GetPan,
1986 DS8Buffer_GetFrequency,
1987 DS8Buffer_GetStatus,
1988 DS8Buffer_Initialize,
1989 DS8Buffer_Lock,
1990 DS8Buffer_Play,
1991 DS8Buffer_SetCurrentPosition,
1992 DS8Buffer_SetFormat,
1993 DS8Buffer_SetVolume,
1994 DS8Buffer_SetPan,
1995 DS8Buffer_SetFrequency,
1996 DS8Buffer_Stop,
1997 DS8Buffer_Unlock,
1998 DS8Buffer_Restore,
1999 DS8Buffer_SetFX,
2000 DS8Buffer_AcquireResources,
2001 DS8Buffer_GetObjectInPath
2005 static HRESULT WINAPI DS8Buffer3D_QueryInterface(IDirectSound3DBuffer *iface, REFIID riid, void **ppv)
2007 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2008 return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2011 static ULONG WINAPI DS8Buffer3D_AddRef(IDirectSound3DBuffer *iface)
2013 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2014 LONG ret;
2016 InterlockedIncrement(&This->all_ref);
2017 ret = InterlockedIncrement(&This->ds3d_ref);
2018 TRACE("new refcount %d\n", ret);
2020 return ret;
2023 static ULONG WINAPI DS8Buffer3D_Release(IDirectSound3DBuffer *iface)
2025 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2026 LONG ret;
2028 ret = InterlockedDecrement(&This->ds3d_ref);
2029 TRACE("new refcount %d\n", ret);
2030 if(InterlockedDecrement(&This->all_ref) == 0)
2031 DS8Buffer_Destroy(This);
2033 return ret;
2036 static HRESULT WINAPI DS8Buffer3D_GetAllParameters(IDirectSound3DBuffer *iface, DS3DBUFFER *ds3dbuffer)
2038 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2039 DS3DBUFFER ds3dbuf;
2040 HRESULT hr;
2042 TRACE("%p\n", This);
2044 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
2046 WARN("Invalid parameters %p %u\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
2047 return DSERR_INVALIDPARAM;
2049 ds3dbuf.dwSize = sizeof(ds3dbuf);
2051 EnterCriticalSection(This->crst);
2052 setALContext(This->ctx);
2054 hr = IDirectSound3DBuffer_GetPosition(iface, &ds3dbuf.vPosition);
2055 if(SUCCEEDED(hr))
2056 hr = IDirectSound3DBuffer_GetVelocity(iface, &ds3dbuf.vVelocity);
2057 if(SUCCEEDED(hr))
2058 hr = IDirectSound3DBuffer_GetConeAngles(iface, &ds3dbuf.dwInsideConeAngle, &ds3dbuf.dwOutsideConeAngle);
2059 if(SUCCEEDED(hr))
2060 hr = IDirectSound3DBuffer_GetConeOrientation(iface, &ds3dbuf.vConeOrientation);
2061 if(SUCCEEDED(hr))
2062 hr = IDirectSound3DBuffer_GetConeOutsideVolume(iface, &ds3dbuf.lConeOutsideVolume);
2063 if(SUCCEEDED(hr))
2064 hr = IDirectSound3DBuffer_GetMinDistance(iface, &ds3dbuf.flMinDistance);
2065 if(SUCCEEDED(hr))
2066 hr = IDirectSound3DBuffer_GetMaxDistance(iface, &ds3dbuf.flMaxDistance);
2067 if(SUCCEEDED(hr))
2068 hr = IDirectSound3DBuffer_GetMode(iface, &ds3dbuf.dwMode);
2069 if(SUCCEEDED(hr))
2070 memcpy(ds3dbuffer, &ds3dbuf, sizeof(ds3dbuf));
2072 popALContext();
2073 LeaveCriticalSection(This->crst);
2075 return hr;
2078 static HRESULT WINAPI DS8Buffer3D_GetConeAngles(IDirectSound3DBuffer *iface, DWORD *pdwInsideConeAngle, DWORD *pdwOutsideConeAngle)
2080 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2081 ALint inangle, outangle;
2083 TRACE("(%p)->(%p, %p)\n", This, pdwInsideConeAngle, pdwOutsideConeAngle);
2084 if(!pdwInsideConeAngle || !pdwOutsideConeAngle)
2086 WARN("Invalid pointers (%p, %p)\n", pdwInsideConeAngle, pdwOutsideConeAngle);
2087 return DSERR_INVALIDPARAM;
2090 EnterCriticalSection(This->crst);
2091 setALContext(This->ctx);
2093 alGetSourcei(This->source, AL_CONE_INNER_ANGLE, &inangle);
2094 alGetSourcei(This->source, AL_CONE_OUTER_ANGLE, &outangle);
2095 getALError();
2096 *pdwInsideConeAngle = inangle;
2097 *pdwOutsideConeAngle = outangle;
2099 popALContext();
2100 LeaveCriticalSection(This->crst);
2102 return S_OK;
2105 static HRESULT WINAPI DS8Buffer3D_GetConeOrientation(IDirectSound3DBuffer *iface, D3DVECTOR *orient)
2107 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2108 ALfloat dir[3];
2110 TRACE("(%p)->(%p)\n", This, orient);
2111 if(!orient)
2113 WARN("Invalid pointer\n");
2114 return DSERR_INVALIDPARAM;
2117 EnterCriticalSection(This->crst);
2118 setALContext(This->ctx);
2120 alGetSourcefv(This->source, AL_DIRECTION, dir);
2121 getALError();
2122 orient->x = dir[0];
2123 orient->y = dir[1];
2124 orient->z = -dir[2];
2126 popALContext();
2127 LeaveCriticalSection(This->crst);
2129 return S_OK;
2132 static HRESULT WINAPI DS8Buffer3D_GetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG *vol)
2134 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2135 ALfloat gain;
2137 TRACE("(%p)->(%p)\n", This, vol);
2138 if(!vol)
2140 WARN("Invalid pointer\n");
2141 return DSERR_INVALIDPARAM;
2144 EnterCriticalSection(This->crst);
2145 setALContext(This->ctx);
2147 alGetSourcef(This->source, AL_CONE_OUTER_GAIN, &gain);
2148 getALError();
2149 *vol = gain_to_mB(gain);
2150 *vol = max(*vol, DSBVOLUME_MIN);
2151 *vol = min(*vol, DSBVOLUME_MAX);
2153 popALContext();
2154 LeaveCriticalSection(This->crst);
2155 return S_OK;
2158 static HRESULT WINAPI DS8Buffer3D_GetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE *maxdist)
2160 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2161 ALfloat dist;
2163 TRACE("(%p)->(%p)\n", This, maxdist);
2164 if(!maxdist)
2166 WARN("Invalid pointer\n");
2167 return DSERR_INVALIDPARAM;
2170 EnterCriticalSection(This->crst);
2171 setALContext(This->ctx);
2173 alGetSourcef(This->source, AL_MAX_DISTANCE, &dist);
2174 getALError();
2175 *maxdist = dist;
2177 popALContext();
2178 LeaveCriticalSection(This->crst);
2180 return S_OK;
2183 static HRESULT WINAPI DS8Buffer3D_GetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE *mindist)
2185 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2186 ALfloat dist;
2188 TRACE("(%p)->(%p)\n", This, mindist);
2189 if(!mindist)
2191 WARN("Invalid pointer\n");
2192 return DSERR_INVALIDPARAM;
2195 EnterCriticalSection(This->crst);
2196 setALContext(This->ctx);
2198 alGetSourcef(This->source, AL_REFERENCE_DISTANCE, &dist);
2199 getALError();
2200 *mindist = dist;
2202 popALContext();
2203 LeaveCriticalSection(This->crst);
2205 return S_OK;
2208 static HRESULT WINAPI DS8Buffer3D_GetMode(IDirectSound3DBuffer *iface, DWORD *mode)
2210 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2212 TRACE("(%p)->(%p)\n", This, mode);
2213 if(!mode)
2215 WARN("Invalid pointer\n");
2216 return DSERR_INVALIDPARAM;
2219 EnterCriticalSection(This->crst);
2220 *mode = This->ds3dmode;
2221 LeaveCriticalSection(This->crst);
2223 return S_OK;
2226 static HRESULT WINAPI DS8Buffer3D_GetPosition(IDirectSound3DBuffer *iface, D3DVECTOR *pos)
2228 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2229 ALfloat alpos[3];
2231 TRACE("(%p)->(%p)\n", This, pos);
2232 if(!pos)
2234 WARN("Invalid pointer\n");
2235 return DSERR_INVALIDPARAM;
2238 EnterCriticalSection(This->crst);
2239 setALContext(This->ctx);
2241 alGetSourcefv(This->source, AL_POSITION, alpos);
2242 getALError();
2243 pos->x = alpos[0];
2244 pos->y = alpos[1];
2245 pos->z = -alpos[2];
2247 popALContext();
2248 LeaveCriticalSection(This->crst);
2250 return S_OK;
2253 static HRESULT WINAPI DS8Buffer3D_GetVelocity(IDirectSound3DBuffer *iface, D3DVECTOR *vel)
2255 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2256 ALfloat alvel[3];
2258 TRACE("(%p)->(%p)\n", This, vel);
2259 if(!vel)
2261 WARN("Invalid pointer\n");
2262 return DSERR_INVALIDPARAM;
2265 EnterCriticalSection(This->crst);
2266 setALContext(This->ctx);
2268 alGetSourcefv(This->source, AL_VELOCITY, alvel);
2269 getALError();
2270 vel->x = alvel[0];
2271 vel->y = alvel[1];
2272 vel->z = -alvel[2];
2274 popALContext();
2275 LeaveCriticalSection(This->crst);
2277 return S_OK;
2280 static HRESULT WINAPI DS8Buffer3D_SetAllParameters(IDirectSound3DBuffer *iface, const DS3DBUFFER *ds3dbuffer, DWORD apply)
2282 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2283 TRACE("(%p)->(%p, %u)\n", This, ds3dbuffer, apply);
2285 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
2287 WARN("Invalid DS3DBUFFER (%p, %u)\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
2288 return DSERR_INVALIDPARAM;
2291 if(ds3dbuffer->dwInsideConeAngle > DS3D_MAXCONEANGLE ||
2292 ds3dbuffer->dwOutsideConeAngle > DS3D_MAXCONEANGLE)
2294 WARN("Invalid cone angles (%u, %u)\n", ds3dbuffer->dwInsideConeAngle,
2295 ds3dbuffer->dwOutsideConeAngle);
2296 return DSERR_INVALIDPARAM;
2299 if(ds3dbuffer->lConeOutsideVolume > DSBVOLUME_MAX ||
2300 ds3dbuffer->lConeOutsideVolume < DSBVOLUME_MIN)
2302 WARN("Invalid cone outside volume (%d)\n", ds3dbuffer->lConeOutsideVolume);
2303 return DSERR_INVALIDPARAM;
2306 if(ds3dbuffer->flMaxDistance < 0.0f)
2308 WARN("Invalid max distance (%f)\n", ds3dbuffer->flMaxDistance);
2309 return DSERR_INVALIDPARAM;
2312 if(ds3dbuffer->flMinDistance < 0.0f)
2314 WARN("Invalid min distance (%f)\n", ds3dbuffer->flMinDistance);
2315 return DSERR_INVALIDPARAM;
2318 if(ds3dbuffer->dwMode != DS3DMODE_NORMAL &&
2319 ds3dbuffer->dwMode != DS3DMODE_HEADRELATIVE &&
2320 ds3dbuffer->dwMode != DS3DMODE_DISABLE)
2322 WARN("Invalid mode (%u)\n", ds3dbuffer->dwMode);
2323 return DSERR_INVALIDPARAM;
2326 EnterCriticalSection(This->crst);
2327 setALContext(This->ctx);
2328 IDirectSound3DBuffer_SetPosition(iface, ds3dbuffer->vPosition.x, ds3dbuffer->vPosition.y, ds3dbuffer->vPosition.z, apply);
2329 IDirectSound3DBuffer_SetVelocity(iface, ds3dbuffer->vVelocity.x, ds3dbuffer->vVelocity.y, ds3dbuffer->vVelocity.z, apply);
2330 IDirectSound3DBuffer_SetConeAngles(iface, ds3dbuffer->dwInsideConeAngle, ds3dbuffer->dwOutsideConeAngle, apply);
2331 IDirectSound3DBuffer_SetConeOrientation(iface, ds3dbuffer->vConeOrientation.x, ds3dbuffer->vConeOrientation.y, ds3dbuffer->vConeOrientation.z, apply);
2332 IDirectSound3DBuffer_SetConeOutsideVolume(iface, ds3dbuffer->lConeOutsideVolume, apply);
2333 IDirectSound3DBuffer_SetMinDistance(iface, ds3dbuffer->flMinDistance, apply);
2334 IDirectSound3DBuffer_SetMaxDistance(iface, ds3dbuffer->flMaxDistance, apply);
2335 IDirectSound3DBuffer_SetMode(iface, ds3dbuffer->dwMode, apply);
2336 popALContext();
2337 LeaveCriticalSection(This->crst);
2339 return S_OK;
2342 static HRESULT WINAPI DS8Buffer3D_SetConeAngles(IDirectSound3DBuffer *iface, DWORD dwInsideConeAngle, DWORD dwOutsideConeAngle, DWORD apply)
2344 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2346 TRACE("(%p)->(%u, %u, %u)\n", This, dwInsideConeAngle, dwOutsideConeAngle, apply);
2347 if(dwInsideConeAngle > DS3D_MAXCONEANGLE ||
2348 dwOutsideConeAngle > DS3D_MAXCONEANGLE)
2350 WARN("Invalid cone angles (%u, %u)\n", dwInsideConeAngle, dwOutsideConeAngle);
2351 return DSERR_INVALIDPARAM;
2354 EnterCriticalSection(This->crst);
2355 if(apply == DS3D_DEFERRED)
2357 This->ds3dbuffer.dwInsideConeAngle = dwInsideConeAngle;
2358 This->ds3dbuffer.dwOutsideConeAngle = dwOutsideConeAngle;
2359 This->dirty.bit.cone_angles = 1;
2361 else
2363 setALContext(This->ctx);
2364 alSourcei(This->source, AL_CONE_INNER_ANGLE, dwInsideConeAngle);
2365 alSourcei(This->source, AL_CONE_OUTER_ANGLE, dwOutsideConeAngle);
2366 getALError();
2367 popALContext();
2369 LeaveCriticalSection(This->crst);
2371 return S_OK;
2374 static HRESULT WINAPI DS8Buffer3D_SetConeOrientation(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2376 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2378 TRACE("(%p)->(%f, %f, %f, %u)\n", This, x, y, z, apply);
2380 EnterCriticalSection(This->crst);
2381 if(apply == DS3D_DEFERRED)
2383 This->ds3dbuffer.vConeOrientation.x = x;
2384 This->ds3dbuffer.vConeOrientation.y = y;
2385 This->ds3dbuffer.vConeOrientation.z = z;
2386 This->dirty.bit.cone_orient = 1;
2388 else
2390 setALContext(This->ctx);
2391 alSource3f(This->source, AL_DIRECTION, x, y, -z);
2392 getALError();
2393 popALContext();
2395 LeaveCriticalSection(This->crst);
2397 return S_OK;
2400 static HRESULT WINAPI DS8Buffer3D_SetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG vol, DWORD apply)
2402 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2404 TRACE("(%p)->(%u, %u)\n", This, vol, apply);
2405 if(vol < DSBVOLUME_MIN || vol > DSBVOLUME_MAX)
2407 WARN("Invalid volume (%u)\n", vol);
2408 return DSERR_INVALIDPARAM;
2411 EnterCriticalSection(This->crst);
2412 if(apply == DS3D_DEFERRED)
2414 This->ds3dbuffer.lConeOutsideVolume = vol;
2415 This->dirty.bit.cone_outsidevolume = 1;
2417 else
2419 setALContext(This->ctx);
2420 alSourcef(This->source, AL_CONE_OUTER_GAIN, mB_to_gain(vol));
2421 getALError();
2422 popALContext();
2424 LeaveCriticalSection(This->crst);
2426 return S_OK;
2429 static HRESULT WINAPI DS8Buffer3D_SetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE maxdist, DWORD apply)
2431 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2433 TRACE("(%p)->(%f, %u)\n", This, maxdist, apply);
2434 if(maxdist < 0.0f)
2436 WARN("Invalid max distance (%f)\n", maxdist);
2437 return DSERR_INVALIDPARAM;
2440 EnterCriticalSection(This->crst);
2441 if(apply == DS3D_DEFERRED)
2443 This->ds3dbuffer.flMaxDistance = maxdist;
2444 This->dirty.bit.max_distance = 1;
2446 else
2448 setALContext(This->ctx);
2449 alSourcef(This->source, AL_MAX_DISTANCE, maxdist);
2450 getALError();
2451 popALContext();
2453 LeaveCriticalSection(This->crst);
2455 return S_OK;
2458 static HRESULT WINAPI DS8Buffer3D_SetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE mindist, DWORD apply)
2460 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2462 TRACE("(%p)->(%f, %u)\n", This, mindist, apply);
2463 if(mindist < 0.0f)
2465 WARN("Invalid min distance (%f)\n", mindist);
2466 return DSERR_INVALIDPARAM;
2469 EnterCriticalSection(This->crst);
2470 if(apply == DS3D_DEFERRED)
2472 This->ds3dbuffer.flMinDistance = mindist;
2473 This->dirty.bit.min_distance = 1;
2475 else
2477 setALContext(This->ctx);
2478 alSourcef(This->source, AL_REFERENCE_DISTANCE, mindist);
2479 getALError();
2480 popALContext();
2482 LeaveCriticalSection(This->crst);
2484 return S_OK;
2487 static HRESULT WINAPI DS8Buffer3D_SetMode(IDirectSound3DBuffer *iface, DWORD mode, DWORD apply)
2489 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2491 TRACE("(%p)->(%u, %u)\n", This, mode, apply);
2492 if(mode != DS3DMODE_NORMAL && mode != DS3DMODE_HEADRELATIVE &&
2493 mode != DS3DMODE_DISABLE)
2495 WARN("Invalid mode (%u)\n", mode);
2496 return DSERR_INVALIDPARAM;
2499 EnterCriticalSection(This->crst);
2500 if(apply == DS3D_DEFERRED)
2502 This->ds3dbuffer.dwMode = mode;
2503 This->dirty.bit.mode = 1;
2505 else
2507 setALContext(This->ctx);
2508 alSourcei(This->source, AL_SOURCE_RELATIVE,
2509 (mode != DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE);
2510 alSourcef(This->source, AL_ROLLOFF_FACTOR,
2511 (mode == DS3DMODE_DISABLE) ? 0.0f : This->primary->rollofffactor);
2512 This->ds3dmode = mode;
2513 getALError();
2514 popALContext();
2516 LeaveCriticalSection(This->crst);
2518 return S_OK;
2521 static HRESULT WINAPI DS8Buffer3D_SetPosition(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2523 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2525 TRACE("(%p)->(%f, %f, %f, %u)\n", This, x, y, z, apply);
2527 EnterCriticalSection(This->crst);
2528 if(apply == DS3D_DEFERRED)
2530 This->ds3dbuffer.vPosition.x = x;
2531 This->ds3dbuffer.vPosition.y = y;
2532 This->ds3dbuffer.vPosition.z = z;
2533 This->dirty.bit.pos = 1;
2535 else
2537 setALContext(This->ctx);
2538 alSource3f(This->source, AL_POSITION, x, y, -z);
2539 getALError();
2540 popALContext();
2542 LeaveCriticalSection(This->crst);
2544 return S_OK;
2547 static HRESULT WINAPI DS8Buffer3D_SetVelocity(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2549 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2551 TRACE("(%p)->(%f, %f, %f, %u)\n", This, x, y, z, apply);
2553 EnterCriticalSection(This->crst);
2554 if(apply == DS3D_DEFERRED)
2556 This->ds3dbuffer.vVelocity.x = x;
2557 This->ds3dbuffer.vVelocity.y = y;
2558 This->ds3dbuffer.vVelocity.z = z;
2559 This->dirty.bit.vel = 1;
2561 else
2563 setALContext(This->ctx);
2564 alSource3f(This->source, AL_VELOCITY, x, y, -z);
2565 getALError();
2566 popALContext();
2568 LeaveCriticalSection(This->crst);
2570 return S_OK;
2573 static const IDirectSound3DBufferVtbl DS8Buffer3d_Vtbl =
2575 DS8Buffer3D_QueryInterface,
2576 DS8Buffer3D_AddRef,
2577 DS8Buffer3D_Release,
2578 DS8Buffer3D_GetAllParameters,
2579 DS8Buffer3D_GetConeAngles,
2580 DS8Buffer3D_GetConeOrientation,
2581 DS8Buffer3D_GetConeOutsideVolume,
2582 DS8Buffer3D_GetMaxDistance,
2583 DS8Buffer3D_GetMinDistance,
2584 DS8Buffer3D_GetMode,
2585 DS8Buffer3D_GetPosition,
2586 DS8Buffer3D_GetVelocity,
2587 DS8Buffer3D_SetAllParameters,
2588 DS8Buffer3D_SetConeAngles,
2589 DS8Buffer3D_SetConeOrientation,
2590 DS8Buffer3D_SetConeOutsideVolume,
2591 DS8Buffer3D_SetMaxDistance,
2592 DS8Buffer3D_SetMinDistance,
2593 DS8Buffer3D_SetMode,
2594 DS8Buffer3D_SetPosition,
2595 DS8Buffer3D_SetVelocity
2599 static HRESULT WINAPI DS8BufferNot_QueryInterface(IDirectSoundNotify *iface, REFIID riid, void **ppv)
2601 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2602 return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2605 static ULONG WINAPI DS8BufferNot_AddRef(IDirectSoundNotify *iface)
2607 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2608 LONG ret;
2610 InterlockedIncrement(&This->all_ref);
2611 ret = InterlockedIncrement(&This->not_ref);
2612 TRACE("new refcount %d\n", ret);
2614 return ret;
2617 static ULONG WINAPI DS8BufferNot_Release(IDirectSoundNotify *iface)
2619 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2620 LONG ret;
2622 ret = InterlockedDecrement(&This->not_ref);
2623 TRACE("new refcount %d\n", ret);
2624 if(InterlockedDecrement(&This->all_ref) == 0)
2625 DS8Buffer_Destroy(This);
2627 return ret;
2630 static HRESULT WINAPI DS8BufferNot_SetNotificationPositions(IDirectSoundNotify *iface, DWORD count, const DSBPOSITIONNOTIFY *notifications)
2632 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2633 DSBPOSITIONNOTIFY *nots;
2634 DWORD state;
2635 HRESULT hr;
2637 EnterCriticalSection(This->crst);
2638 hr = DSERR_INVALIDPARAM;
2639 if(count && !notifications)
2640 goto out;
2642 hr = IDirectSoundBuffer8_GetStatus(&This->IDirectSoundBuffer8_iface, &state);
2643 if(FAILED(hr))
2644 goto out;
2646 hr = DSERR_INVALIDCALL;
2647 if((state&DSBSTATUS_PLAYING))
2648 goto out;
2650 if(!count)
2652 HeapFree(GetProcessHeap(), 0, This->notify);
2653 This->notify = 0;
2654 This->nnotify = 0;
2655 hr = S_OK;
2657 else
2659 DWORD i;
2661 hr = DSERR_INVALIDPARAM;
2662 for(i = 0;i < count;++i)
2664 if(notifications[i].dwOffset >= This->buffer->buf_size &&
2665 notifications[i].dwOffset != (DWORD)DSBPN_OFFSETSTOP)
2666 goto out;
2669 hr = E_OUTOFMEMORY;
2670 nots = HeapAlloc(GetProcessHeap(), 0, count*sizeof(*nots));
2671 if(!nots)
2672 goto out;
2673 memcpy(nots, notifications, count*sizeof(*nots));
2675 HeapFree(GetProcessHeap(), 0, This->notify);
2676 This->notify = nots;
2677 This->nnotify = count;
2679 hr = S_OK;
2682 out:
2683 LeaveCriticalSection(This->crst);
2684 return hr;
2687 static const IDirectSoundNotifyVtbl DS8BufferNot_Vtbl =
2689 DS8BufferNot_QueryInterface,
2690 DS8BufferNot_AddRef,
2691 DS8BufferNot_Release,
2692 DS8BufferNot_SetNotificationPositions
2696 static HRESULT WINAPI DS8BufferProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
2698 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2699 return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2702 static ULONG WINAPI DS8BufferProp_AddRef(IKsPropertySet *iface)
2704 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2705 LONG ret;
2707 InterlockedIncrement(&This->all_ref);
2708 ret = InterlockedIncrement(&This->prop_ref);
2709 TRACE("new refcount %d\n", ret);
2711 return ret;
2714 static ULONG WINAPI DS8BufferProp_Release(IKsPropertySet *iface)
2716 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2717 LONG ret;
2719 ret = InterlockedDecrement(&This->prop_ref);
2720 TRACE("new refcount %d\n", ret);
2721 if(InterlockedDecrement(&This->all_ref) == 0)
2722 DS8Buffer_Destroy(This);
2724 return ret;
2727 /* NOTE: Due to some apparent quirks in DSound, the listener properties are
2728 handled through secondary buffers. */
2729 static HRESULT WINAPI DS8BufferProp_Get(IKsPropertySet *iface,
2730 REFGUID guidPropSet, ULONG dwPropID,
2731 LPVOID pInstanceData, ULONG cbInstanceData,
2732 LPVOID pPropData, ULONG cbPropData,
2733 PULONG pcbReturned)
2735 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2736 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2738 TRACE("(%p)->(%s, %u, %p, %u, %p, %u, %p)\n", iface, debugstr_guid(guidPropSet),
2739 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData, pcbReturned);
2741 if(!pcbReturned)
2742 return E_POINTER;
2743 *pcbReturned = 0;
2745 #if 0
2746 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2749 else
2750 #endif
2752 /* Not a known buffer/source property. Pass it to the listener */
2753 hr = IKsPropertySet_Get(&This->primary->IKsPropertySet_iface, guidPropSet,
2754 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData,
2755 pcbReturned);
2758 return hr;
2761 static HRESULT WINAPI DS8BufferProp_Set(IKsPropertySet *iface,
2762 REFGUID guidPropSet, ULONG dwPropID,
2763 LPVOID pInstanceData, ULONG cbInstanceData,
2764 LPVOID pPropData, ULONG cbPropData)
2766 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2767 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2769 TRACE("(%p)->(%s, %u, %p, %u, %p, %u)\n", iface, debugstr_guid(guidPropSet),
2770 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData);
2772 #if 0
2773 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2776 else
2777 #endif
2779 /* Not a known buffer/source property. Pass it to the listener */
2780 hr = IKsPropertySet_Set(&This->primary->IKsPropertySet_iface, guidPropSet,
2781 dwPropID, pInstanceData, cbInstanceData, pPropData,
2782 cbPropData);
2785 return hr;
2788 static HRESULT WINAPI DS8BufferProp_QuerySupport(IKsPropertySet *iface,
2789 REFGUID guidPropSet, ULONG dwPropID,
2790 PULONG pTypeSupport)
2792 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2793 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2795 TRACE("(%p)->(%s, %u, %p)\n", iface, debugstr_guid(guidPropSet), dwPropID, pTypeSupport);
2797 if(!pTypeSupport)
2798 return E_POINTER;
2799 *pTypeSupport = 0;
2801 #if 0
2802 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2805 else
2806 #endif
2808 /* Not a known buffer/source property. Pass it to the listener */
2809 hr = IKsPropertySet_QuerySupport(&This->primary->IKsPropertySet_iface,
2810 guidPropSet, dwPropID, pTypeSupport);
2813 return hr;
2816 static const IKsPropertySetVtbl DS8BufferProp_Vtbl =
2818 DS8BufferProp_QueryInterface,
2819 DS8BufferProp_AddRef,
2820 DS8BufferProp_Release,
2821 DS8BufferProp_Get,
2822 DS8BufferProp_Set,
2823 DS8BufferProp_QuerySupport