Constify some pointers that won't change after initialization
[wine/multimedia.git] / buffer.c
bloba4f515d0600adad7e784c7be6acd73fa4e4dd68a
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 IDirectSoundBufferVtbl DSBuffer_Vtbl;
80 static const IDirectSound3DBufferVtbl DS8Buffer3d_Vtbl;
81 static const IDirectSoundNotifyVtbl DS8BufferNot_Vtbl;
82 static const IKsPropertySetVtbl DS8BufferProp_Vtbl;
85 static inline DS8Buffer *impl_from_IDirectSoundBuffer8(IDirectSoundBuffer8 *iface)
87 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSoundBuffer8_iface);
90 static inline DS8Buffer *impl_from_IDirectSoundBuffer(IDirectSoundBuffer *iface)
92 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSoundBuffer_iface);
95 static inline DS8Buffer *impl_from_IDirectSound3DBuffer(IDirectSound3DBuffer *iface)
97 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSound3DBuffer_iface);
100 static inline DS8Buffer *impl_from_IDirectSoundNotify(IDirectSoundNotify *iface)
102 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSoundNotify_iface);
105 static inline DS8Buffer *impl_from_IKsPropertySet(IKsPropertySet *iface)
107 return CONTAINING_RECORD(iface, DS8Buffer, IKsPropertySet_iface);
111 static void CALLBACK DS8Buffer_timer(UINT timerID, UINT msg, DWORD_PTR dwUser,
112 DWORD_PTR dw1, DWORD_PTR dw2)
114 (void)timerID;
115 (void)msg;
116 (void)dw1;
117 (void)dw2;
118 PostThreadMessageA(dwUser, WM_USER, 0, 0);
121 static void DS8Buffer_starttimer(DS8Primary *prim)
123 DWORD triggertime, res = DS_TIME_RES;
124 ALint refresh = FAKE_REFRESH_COUNT;
125 TIMECAPS time;
127 if(prim->timer_id)
128 return;
130 timeGetDevCaps(&time, sizeof(TIMECAPS));
132 alcGetIntegerv(prim->parent->device, ALC_REFRESH, 1, &refresh);
133 checkALCError(prim->parent->device);
135 triggertime = 1000 / refresh / 2;
136 if(triggertime < time.wPeriodMin)
137 triggertime = time.wPeriodMin;
138 TRACE("Calling timer every %"LONGFMT"u ms for %i refreshes per second\n", triggertime, refresh);
140 if (res < time.wPeriodMin)
141 res = time.wPeriodMin;
142 if (timeBeginPeriod(res) == TIMERR_NOCANDO)
143 WARN("Could not set minimum resolution, don't expect sound\n");
145 prim->timer_res = res;
146 prim->timer_id = timeSetEvent(triggertime, res, DS8Buffer_timer, prim->thread_id, TIME_PERIODIC|TIME_KILL_SYNCHRONOUS);
149 /* Should be called with critsect held and context set.. */
150 static void DS8Buffer_addnotify(DS8Buffer *buf)
152 DS8Buffer **list;
153 DWORD i;
155 list = buf->primary->notifies;
156 for(i = 0; i < buf->primary->nnotifies; ++i)
158 if(buf == list[i])
160 ERR("Buffer %p already in notification list\n", buf);
161 return;
164 if(buf->primary->nnotifies == buf->primary->sizenotifies)
166 list = HeapReAlloc(GetProcessHeap(), 0, list, (buf->primary->nnotifies + 1) * sizeof(*list));
167 if(!list)
168 return;
169 buf->primary->sizenotifies++;
171 list[buf->primary->nnotifies++] = buf;
172 buf->primary->notifies = list;
176 static const char *get_fmtstr_PCM(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out)
178 out->Format = *format;
179 out->Format.cbSize = 0;
181 if(out->Format.nChannels != 1 && out->Format.nChannels != 2 &&
182 !prim->SupportedExt[EXT_MCFORMATS])
184 WARN("Multi-channel not available\n");
185 return NULL;
188 if(format->wBitsPerSample == 8)
190 switch(format->nChannels)
192 case 1: return "AL_FORMAT_MONO8";
193 case 2: return "AL_FORMAT_STEREO8";
194 case 4: return "AL_FORMAT_QUAD8";
195 case 6: return "AL_FORMAT_51CHN8";
196 case 7: return "AL_FORMAT_61CHN8";
197 case 8: return "AL_FORMAT_71CHN8";
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";
213 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
214 format->wBitsPerSample, format->nChannels);
215 return NULL;
217 static ALenum get_fmt_PCM(const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out, ALenum *in_chans, ALenum *in_type)
219 out->Format = *format;
220 out->Format.cbSize = 0;
222 if(format->wBitsPerSample == 8)
224 *in_type = AL_UNSIGNED_BYTE;
225 switch(format->nChannels)
227 case 1: *in_chans = AL_MONO;
228 return AL_MONO8;
229 case 2: *in_chans = AL_STEREO;
230 return AL_STEREO8;
231 case 4: *in_chans = AL_QUAD;
232 return AL_QUAD8;
233 case 6: *in_chans = AL_5POINT1;
234 return AL_5POINT1_8;
235 case 7: *in_chans = AL_6POINT1;
236 return AL_6POINT1_8;
237 case 8: *in_chans = AL_7POINT1;
238 return AL_7POINT1_8;
241 else if(format->wBitsPerSample == 16)
243 *in_type = AL_SHORT;
244 switch(format->nChannels)
246 case 1: *in_chans = AL_MONO;
247 return AL_MONO16;
248 case 2: *in_chans = AL_STEREO;
249 return AL_STEREO16;
250 case 4: *in_chans = AL_QUAD;
251 return AL_QUAD16;
252 case 6: *in_chans = AL_5POINT1;
253 return AL_5POINT1_16;
254 case 7: *in_chans = AL_6POINT1;
255 return AL_6POINT1_16;
256 case 8: *in_chans = AL_7POINT1;
257 return AL_7POINT1_16;
260 #if 0 /* Will cause incorrect byte offsets */
261 else if(format->wBitsPerSample == 24)
263 *in_type = AL_BYTE3;
264 switch(format->nChannels)
266 case 1: *in_chans = AL_MONO;
267 return AL_MONO32F;
268 case 2: *in_chans = AL_STEREO;
269 return AL_STEREO32F;
270 case 4: *in_chans = AL_QUAD;
271 return AL_QUAD32F;
272 case 6: *in_chans = AL_5POINT1;
273 return AL_5POINT1_32F;
274 case 7: *in_chans = AL_6POINT1;
275 return AL_6POINT1_32F;
276 case 8: *in_chans = AL_7POINT1;
277 return AL_7POINT1_32F;
280 #endif
281 else if(format->wBitsPerSample == 32)
283 *in_type = AL_INT;
284 switch(format->nChannels)
286 case 1: *in_chans = AL_MONO;
287 return AL_MONO32F;
288 case 2: *in_chans = AL_STEREO;
289 return AL_STEREO32F;
290 case 4: *in_chans = AL_QUAD;
291 return AL_QUAD32F;
292 case 6: *in_chans = AL_5POINT1;
293 return AL_5POINT1_32F;
294 case 7: *in_chans = AL_6POINT1;
295 return AL_6POINT1_32F;
296 case 8: *in_chans = AL_7POINT1;
297 return AL_7POINT1_32F;
301 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
302 format->wBitsPerSample, format->nChannels);
303 return AL_NONE;
306 static const char *get_fmtstr_FLOAT(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out)
308 out->Format = *format;
309 out->Format.cbSize = 0;
311 if(out->Format.nChannels != 1 && out->Format.nChannels != 2 &&
312 !prim->SupportedExt[EXT_MCFORMATS])
314 WARN("Multi-channel not available\n");
315 return NULL;
318 if(format->wBitsPerSample == 32 && prim->SupportedExt[EXT_FLOAT32])
320 switch(format->nChannels)
322 case 1: return "AL_FORMAT_MONO_FLOAT32";
323 case 2: return "AL_FORMAT_STEREO_FLOAT32";
324 case 4: return "AL_FORMAT_QUAD32";
325 case 6: return "AL_FORMAT_51CHN32";
326 case 7: return "AL_FORMAT_61CHN32";
327 case 8: return "AL_FORMAT_71CHN32";
331 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
332 format->wBitsPerSample, format->nChannels);
333 return NULL;
335 static ALenum get_fmt_FLOAT(const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out, ALenum *in_chans, ALenum *in_type)
337 out->Format = *format;
338 out->Format.cbSize = 0;
340 if(format->wBitsPerSample == 32)
342 *in_type = AL_FLOAT;
343 switch(format->nChannels)
345 case 1: *in_chans = AL_MONO;
346 return AL_MONO32F;
347 case 2: *in_chans = AL_STEREO;
348 return AL_STEREO32F;
349 case 4: *in_chans = AL_QUAD;
350 return AL_QUAD32F;
351 case 6: *in_chans = AL_5POINT1;
352 return AL_5POINT1_32F;
353 case 7: *in_chans = AL_6POINT1;
354 return AL_6POINT1_32F;
355 case 8: *in_chans = AL_7POINT1;
356 return AL_7POINT1_32F;
359 #if 0 /* Will cause incorrect byte offsets */
360 else if(format->wBitsPerSample == 64)
362 *in_type = AL_DOUBLE;
363 switch(format->nChannels)
365 case 1: *in_chans = AL_MONO;
366 return AL_MONO32F;
367 case 2: *in_chans = AL_STEREO;
368 return AL_STEREO32F;
369 case 4: *in_chans = AL_QUAD;
370 return AL_QUAD32F;
371 case 6: *in_chans = AL_5POINT1;
372 return AL_5POINT1_32F;
373 case 7: *in_chans = AL_6POINT1;
374 return AL_6POINT1_32F;
375 case 8: *in_chans = AL_7POINT1;
376 return AL_7POINT1_32F;
379 #endif
381 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
382 format->wBitsPerSample, format->nChannels);
383 return AL_NONE;
386 /* Speaker configs */
387 #define MONO SPEAKER_FRONT_CENTER
388 #define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)
389 #define REAR (SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
390 #define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
391 #define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
392 #define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
393 #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)
395 static const char *get_fmtstr_EXT(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out)
397 *out = *CONTAINING_RECORD(format, const WAVEFORMATEXTENSIBLE, Format);
398 out->Format.cbSize = sizeof(*out) - sizeof(out->Format);
400 if(!out->Samples.wValidBitsPerSample)
401 out->Samples.wValidBitsPerSample = out->Format.wBitsPerSample;
402 else if(out->Samples.wValidBitsPerSample != out->Format.wBitsPerSample)
404 FIXME("Padded samples not supported (%u of %u)\n", out->Samples.wValidBitsPerSample, out->Format.wBitsPerSample);
405 return NULL;
408 if(out->dwChannelMask != MONO && out->dwChannelMask != STEREO &&
409 !prim->SupportedExt[EXT_MCFORMATS])
411 WARN("Multi-channel not available\n");
412 return NULL;
415 if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
417 if(out->Samples.wValidBitsPerSample == 8)
419 switch(out->dwChannelMask)
421 case MONO: return "AL_FORMAT_MONO8";
422 case STEREO: return "AL_FORMAT_STEREO8";
423 case REAR: return "AL_FORMAT_REAR8";
424 case QUAD: return "AL_FORMAT_QUAD8";
425 case X5DOT1: return "AL_FORMAT_51CHN8";
426 case X6DOT1: return "AL_FORMAT_61CHN8";
427 case X7DOT1: return "AL_FORMAT_71CHN8";
430 else if(out->Samples.wValidBitsPerSample == 16)
432 switch(out->dwChannelMask)
434 case MONO: return "AL_FORMAT_MONO16";
435 case STEREO: return "AL_FORMAT_STEREO16";
436 case REAR: return "AL_FORMAT_REAR16";
437 case QUAD: return "AL_FORMAT_QUAD16";
438 case X5DOT1: return "AL_FORMAT_51CHN16";
439 case X6DOT1: return "AL_FORMAT_61CHN16";
440 case X7DOT1: return "AL_FORMAT_71CHN16";
444 FIXME("Could not get OpenAL PCM format (%d-bit, channelmask %#"LONGFMT"x)\n",
445 out->Samples.wValidBitsPerSample, out->dwChannelMask);
446 return NULL;
448 else if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) &&
449 prim->SupportedExt[EXT_FLOAT32])
451 if(out->Samples.wValidBitsPerSample == 32)
453 switch(out->dwChannelMask)
455 case MONO: return "AL_FORMAT_MONO_FLOAT32";
456 case STEREO: return "AL_FORMAT_STEREO_FLOAT32";
457 case REAR: return "AL_FORMAT_REAR32";
458 case QUAD: return "AL_FORMAT_QUAD32";
459 case X5DOT1: return "AL_FORMAT_51CHN32";
460 case X6DOT1: return "AL_FORMAT_61CHN32";
461 case X7DOT1: return "AL_FORMAT_71CHN32";
464 else
466 WARN("Invalid float bits: %u\n", out->Samples.wValidBitsPerSample);
467 return NULL;
470 FIXME("Could not get OpenAL float format (%d-bit, channelmask %#"LONGFMT"x)\n",
471 out->Samples.wValidBitsPerSample, out->dwChannelMask);
472 return NULL;
474 else if(!IsEqualGUID(&out->SubFormat, &GUID_NULL))
475 ERR("Unhandled extensible format: %s\n", debugstr_guid(&out->SubFormat));
476 return NULL;
478 static ALenum get_fmt_EXT(const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out, ALenum *in_chans, ALenum *in_type)
480 *out = *CONTAINING_RECORD(format, const WAVEFORMATEXTENSIBLE, Format);
481 out->Format.cbSize = sizeof(*out) - sizeof(out->Format);
483 if(!out->Samples.wValidBitsPerSample)
484 out->Samples.wValidBitsPerSample = out->Format.wBitsPerSample;
485 else if(out->Samples.wValidBitsPerSample != out->Format.wBitsPerSample)
487 FIXME("Padded samples not supported (%u of %u)\n", out->Samples.wValidBitsPerSample, out->Format.wBitsPerSample);
488 return AL_NONE;
491 if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
493 if(out->Samples.wValidBitsPerSample == 8)
495 *in_type = AL_UNSIGNED_BYTE;
496 switch(out->dwChannelMask)
498 case MONO: *in_chans = AL_MONO;
499 return AL_MONO8;
500 case STEREO: *in_chans = AL_STEREO;
501 return AL_STEREO8;
502 case REAR: *in_chans = AL_REAR;
503 return AL_REAR8;
504 case QUAD: *in_chans = AL_QUAD;
505 return AL_QUAD8;
506 case X5DOT1: *in_chans = AL_5POINT1;
507 return AL_5POINT1_8;
508 case X6DOT1: *in_chans = AL_6POINT1;
509 return AL_6POINT1_8;
510 case X7DOT1: *in_chans = AL_7POINT1;
511 return AL_7POINT1_8;
514 else if(out->Samples.wValidBitsPerSample == 16)
516 *in_type = AL_SHORT;
517 switch(out->dwChannelMask)
519 case MONO: *in_chans = AL_MONO;
520 return AL_MONO16;
521 case STEREO: *in_chans = AL_STEREO;
522 return AL_STEREO16;
523 case REAR: *in_chans = AL_REAR;
524 return AL_REAR16;
525 case QUAD: *in_chans = AL_QUAD;
526 return AL_QUAD16;
527 case X5DOT1: *in_chans = AL_5POINT1;
528 return AL_5POINT1_16;
529 case X6DOT1: *in_chans = AL_6POINT1;
530 return AL_6POINT1_16;
531 case X7DOT1: *in_chans = AL_7POINT1;
532 return AL_7POINT1_16;
535 #if 0
536 else if(out->Samples.wValidBitsPerSample == 24)
538 *in_type = AL_BYTE3;
539 switch(out->dwChannelMask)
541 case MONO: *in_chans = AL_MONO;
542 return AL_MONO32F;
543 case STEREO: *in_chans = AL_STEREO;
544 return AL_STEREO32F;
545 case REAR: *in_chans = AL_REAR;
546 return AL_REAR32F;
547 case QUAD: *in_chans = AL_QUAD;
548 return AL_QUAD32F;
549 case X5DOT1: *in_chans = AL_5POINT1;
550 return AL_5POINT1_32F;
551 case X6DOT1: *in_chans = AL_6POINT1;
552 return AL_6POINT1_32F;
553 case X7DOT1: *in_chans = AL_7POINT1;
554 return AL_7POINT1_32F;
557 #endif
558 else if(out->Samples.wValidBitsPerSample == 32)
560 *in_type = AL_INT;
561 switch(out->dwChannelMask)
563 case MONO: *in_chans = AL_MONO;
564 return AL_MONO32F;
565 case STEREO: *in_chans = AL_STEREO;
566 return AL_STEREO32F;
567 case REAR: *in_chans = AL_REAR;
568 return AL_REAR32F;
569 case QUAD: *in_chans = AL_QUAD;
570 return AL_QUAD32F;
571 case X5DOT1: *in_chans = AL_5POINT1;
572 return AL_5POINT1_32F;
573 case X6DOT1: *in_chans = AL_6POINT1;
574 return AL_6POINT1_32F;
575 case X7DOT1: *in_chans = AL_7POINT1;
576 return AL_7POINT1_32F;
580 FIXME("Could not get OpenAL PCM format (%d-bit, channelmask %#"LONGFMT"x)\n",
581 out->Samples.wValidBitsPerSample, out->dwChannelMask);
582 return AL_NONE;
584 else if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
586 if(out->Samples.wValidBitsPerSample == 32)
588 *in_type = AL_FLOAT;
589 switch(out->dwChannelMask)
591 case MONO: *in_chans = AL_MONO;
592 return AL_MONO32F;
593 case STEREO: *in_chans = AL_STEREO;
594 return AL_STEREO32F;
595 case REAR: *in_chans = AL_REAR;
596 return AL_REAR32F;
597 case QUAD: *in_chans = AL_QUAD;
598 return AL_QUAD32F;
599 case X5DOT1: *in_chans = AL_5POINT1;
600 return AL_5POINT1_32F;
601 case X6DOT1: *in_chans = AL_6POINT1;
602 return AL_6POINT1_32F;
603 case X7DOT1: *in_chans = AL_7POINT1;
604 return AL_7POINT1_32F;
607 #if 0
608 else if(out->Samples.wValidBitsPerSample == 64)
610 *in_type = AL_DOUBLE;
611 switch(out->dwChannelMask)
613 case MONO: *in_chans = AL_MONO;
614 return AL_MONO32F;
615 case STEREO: *in_chans = AL_STEREO;
616 return AL_STEREO32F;
617 case REAR: *in_chans = AL_REAR;
618 return AL_REAR32F;
619 case QUAD: *in_chans = AL_QUAD;
620 return AL_QUAD32F;
621 case X5DOT1: *in_chans = AL_5POINT1;
622 return AL_5POINT1_32F;
623 case X6DOT1: *in_chans = AL_6POINT1;
624 return AL_6POINT1_32F;
625 case X7DOT1: *in_chans = AL_7POINT1;
626 return AL_7POINT1_32F;
629 #endif
630 else
632 WARN("Invalid float bits: %u\n", out->Samples.wValidBitsPerSample);
633 return AL_NONE;
636 FIXME("Could not get OpenAL float format (%d-bit, channelmask %#"LONGFMT"x)\n",
637 out->Samples.wValidBitsPerSample, out->dwChannelMask);
638 return AL_NONE;
640 else if(!IsEqualGUID(&out->SubFormat, &GUID_NULL))
641 ERR("Unhandled extensible format: %s\n", debugstr_guid(&out->SubFormat));
642 return AL_NONE;
645 static void DS8Data_Release(DS8Data *This);
646 static HRESULT DS8Data_Create(DS8Data **ppv, const DSBUFFERDESC *desc, DS8Primary *prim)
648 HRESULT hr = DSERR_INVALIDPARAM;
649 const WAVEFORMATEX *format;
650 DS8Data *pBuffer;
652 format = desc->lpwfxFormat;
653 TRACE("Requested buffer format:\n"
654 " FormatTag = 0x%04x\n"
655 " Channels = %d\n"
656 " SamplesPerSec = %"LONGFMT"u\n"
657 " AvgBytesPerSec = %"LONGFMT"u\n"
658 " BlockAlign = %d\n"
659 " BitsPerSample = %d\n",
660 format->wFormatTag, format->nChannels,
661 format->nSamplesPerSec, format->nAvgBytesPerSec,
662 format->nBlockAlign, format->wBitsPerSample);
664 if(format->nBlockAlign == 0)
666 WARN("Invalid BlockAlign specified\n");
667 return DSERR_INVALIDPARAM;
670 /* Generate a new buffer. Supporting the DSBCAPS_LOC* flags properly
671 * will need the EAX-RAM extension. Currently, we just tell the app it
672 * gets what it wanted. */
673 pBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pBuffer));
674 if(!pBuffer)
675 return E_OUTOFMEMORY;
676 pBuffer->ref = 1;
678 pBuffer->dsbflags = desc->dwFlags;
679 if((pBuffer->dsbflags&(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE)) == (DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE))
681 WARN("Hardware and software location requested\n");
682 goto fail;
684 if(!(pBuffer->dsbflags&(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE|DSBCAPS_LOCDEFER)))
685 pBuffer->dsbflags |= DSBCAPS_LOCHARDWARE;
687 pBuffer->buf_size = desc->dwBufferBytes + format->nBlockAlign - 1;
688 pBuffer->buf_size -= pBuffer->buf_size%format->nBlockAlign;
690 hr = DSERR_BUFFERTOOSMALL;
691 if(pBuffer->buf_size < DSBSIZE_MIN)
692 goto fail;
694 hr = DSERR_INVALIDPARAM;
695 if(pBuffer->buf_size > DSBSIZE_MAX)
696 goto fail;
698 pBuffer->numsegs = 1;
699 pBuffer->segsize = pBuffer->buf_size;
700 pBuffer->lastsegsize = pBuffer->buf_size;
702 if(!prim->SupportedExt[SOFT_BUFFER_SAMPLES])
704 const char *fmt_str = NULL;
706 if(!(pBuffer->dsbflags&DSBCAPS_STATIC) &&
707 !prim->SupportedExt[SOFT_BUFFER_SUB_DATA] &&
708 !prim->SupportedExt[EXT_STATIC_BUFFER])
710 ALCint refresh = FAKE_REFRESH_COUNT;
711 ALuint newSize;
713 alcGetIntegerv(prim->parent->device, ALC_REFRESH, 1, &refresh);
714 checkALCError(prim->parent->device);
716 newSize = format->nAvgBytesPerSec/refresh + format->nBlockAlign - 1;
717 newSize -= newSize%format->nBlockAlign;
719 /* Make sure enough buffers are available */
720 if(newSize > pBuffer->buf_size/(QBUFFERS+2))
721 ERR("Buffer segments too large to stream (%u for %u)!\n",
722 newSize, pBuffer->buf_size);
723 else
725 pBuffer->numsegs = pBuffer->buf_size/newSize;
726 pBuffer->segsize = newSize;
727 pBuffer->lastsegsize = pBuffer->buf_size - (newSize*(pBuffer->numsegs-1));
728 TRACE("New streaming buffer (%u chunks, %u : %u sizes)\n",
729 pBuffer->numsegs, pBuffer->segsize, pBuffer->lastsegsize);
733 if(format->wFormatTag == WAVE_FORMAT_PCM)
734 fmt_str = get_fmtstr_PCM(prim, format, &pBuffer->format);
735 else if(format->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
736 fmt_str = get_fmtstr_FLOAT(prim, format, &pBuffer->format);
737 else if(format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
739 const WAVEFORMATEXTENSIBLE *wfe;
741 hr = DSERR_CONTROLUNAVAIL;
742 if(format->cbSize != sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) &&
743 format->cbSize != sizeof(WAVEFORMATEXTENSIBLE))
744 goto fail;
746 wfe = CONTAINING_RECORD(format, const WAVEFORMATEXTENSIBLE, Format);
747 TRACE("Extensible values:\n"
748 " Samples = %d\n"
749 " ChannelMask = 0x%"LONGFMT"x\n"
750 " SubFormat = %s\n",
751 wfe->Samples.wReserved, wfe->dwChannelMask,
752 debugstr_guid(&wfe->SubFormat));
754 fmt_str = get_fmtstr_EXT(prim, format, &pBuffer->format);
756 else
757 ERR("Unhandled formattag 0x%04x\n", format->wFormatTag);
759 hr = DSERR_INVALIDCALL;
760 if(!fmt_str)
761 goto fail;
763 pBuffer->buf_format = alGetEnumValue(fmt_str);
764 if(alGetError() != AL_NO_ERROR || pBuffer->buf_format == 0 ||
765 pBuffer->buf_format == -1)
767 WARN("Could not get OpenAL format from %s\n", fmt_str);
768 goto fail;
771 else
773 if(format->wFormatTag == WAVE_FORMAT_PCM)
774 pBuffer->buf_format = get_fmt_PCM(format, &pBuffer->format, &pBuffer->in_chans, &pBuffer->in_type);
775 else if(format->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
776 pBuffer->buf_format = get_fmt_FLOAT(format, &pBuffer->format, &pBuffer->in_chans, &pBuffer->in_type);
777 else if(format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
779 const WAVEFORMATEXTENSIBLE *wfe;
781 hr = DSERR_CONTROLUNAVAIL;
782 if(format->cbSize != sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) &&
783 format->cbSize != sizeof(WAVEFORMATEXTENSIBLE))
784 goto fail;
786 wfe = CONTAINING_RECORD(format, const WAVEFORMATEXTENSIBLE, Format);
787 TRACE("Extensible values:\n"
788 " Samples = %d\n"
789 " ChannelMask = 0x%"LONGFMT"x\n"
790 " SubFormat = %s\n",
791 wfe->Samples.wReserved, wfe->dwChannelMask,
792 debugstr_guid(&wfe->SubFormat));
794 pBuffer->buf_format = get_fmt_EXT(format, &pBuffer->format, &pBuffer->in_chans, &pBuffer->in_type);
796 else
797 ERR("Unhandled formattag 0x%04x\n", format->wFormatTag);
799 hr = DSERR_INVALIDCALL;
800 if(prim->ExtAL->IsBufferFormatSupportedSOFT(pBuffer->buf_format) == AL_FALSE)
802 WARN("Unsupported OpenAL format: 0x%x\n", pBuffer->buf_format);
803 goto fail;
807 hr = E_OUTOFMEMORY;
808 pBuffer->buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pBuffer->buffers)*pBuffer->numsegs);
809 pBuffer->data = HeapAlloc(GetProcessHeap(), 0, pBuffer->buf_size);
810 if(!pBuffer->buffers || !pBuffer->data)
811 goto fail;
813 alGenBuffers(pBuffer->numsegs, pBuffer->buffers);
814 checkALError();
816 *ppv = pBuffer;
817 return S_OK;
819 fail:
820 DS8Data_Release(pBuffer);
821 return hr;
824 static void DS8Data_AddRef(DS8Data *data)
826 InterlockedIncrement(&data->ref);
829 /* This function is always called with the device lock held */
830 static void DS8Data_Release(DS8Data *This)
832 if(InterlockedDecrement(&This->ref)) return;
834 TRACE("Deleting %p\n", This);
835 if (This->buffers && This->buffers[0])
837 alDeleteBuffers(This->numsegs, This->buffers);
838 checkALError();
840 HeapFree(GetProcessHeap(), 0, This->buffers);
841 HeapFree(GetProcessHeap(), 0, This->data);
842 HeapFree(GetProcessHeap(), 0, This);
845 HRESULT DS8Buffer_Create(DS8Buffer **ppv, DS8Primary *prim, IDirectSoundBuffer *orig)
847 DS8Buffer *This;
848 HRESULT hr;
850 *ppv = NULL;
851 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
852 if(!This) return DSERR_OUTOFMEMORY;
854 This->IDirectSoundBuffer8_iface.lpVtbl = (IDirectSoundBuffer8Vtbl*)&DS8Buffer_Vtbl;
855 This->IDirectSoundBuffer_iface.lpVtbl = (IDirectSoundBufferVtbl*)&DSBuffer_Vtbl;
856 This->IDirectSound3DBuffer_iface.lpVtbl = (IDirectSound3DBufferVtbl*)&DS8Buffer3d_Vtbl;
857 This->IDirectSoundNotify_iface.lpVtbl = (IDirectSoundNotifyVtbl*)&DS8BufferNot_Vtbl;
858 This->IKsPropertySet_iface.lpVtbl = (IKsPropertySetVtbl*)&DS8BufferProp_Vtbl;
860 This->primary = prim;
861 This->ctx = prim->ctx;
862 This->ExtAL = prim->ExtAL;
863 This->crst = prim->crst;
864 This->ref = This->all_ref = 1;
866 if(orig)
868 DS8Buffer *org = impl_from_IDirectSoundBuffer(orig);
869 hr = DSERR_BUFFERLOST;
870 if(org->bufferlost)
871 goto fail;
872 DS8Data_AddRef(org->buffer);
873 This->buffer = org->buffer;
876 /* Append to buffer list */
877 if(prim->nbuffers == prim->sizebuffers)
879 void *bufs;
881 hr = DSERR_OUTOFMEMORY;
882 bufs = HeapReAlloc(GetProcessHeap(), 0, prim->buffers, sizeof(*bufs)*(prim->nbuffers+1));
883 if(!bufs) goto fail;
885 prim->buffers = bufs;
886 prim->sizebuffers++;
888 prim->buffers[prim->nbuffers++] = This;
890 /* Disable until initialized.. */
891 This->ds3dmode = DS3DMODE_DISABLE;
893 *ppv = This;
894 return DS_OK;
896 fail:
897 DS8Buffer_Destroy(This);
898 return hr;
901 void DS8Buffer_Destroy(DS8Buffer *This)
903 DS8Primary *prim = This->primary;
904 DWORD idx;
906 TRACE("Destroying %p\n", This);
908 EnterCriticalSection(prim->crst);
909 /* Remove from list, if in list */
910 for(idx = 0;idx < prim->nnotifies;++idx)
912 if(This == prim->notifies[idx])
914 prim->notifies[idx] = prim->notifies[--prim->nnotifies];
915 break;
918 for(idx = 0;idx < prim->nbuffers;++idx)
920 if(prim->buffers[idx] == This)
922 prim->buffers[idx] = prim->buffers[--prim->nbuffers];
923 break;
927 setALContext(This->ctx);
928 if(This->source)
930 alSourceStop(This->source);
931 alSourcei(This->source, AL_BUFFER, 0);
932 checkALError();
934 prim->sources[prim->parent->share->nsources++] = This->source;
935 This->source = 0;
937 LeaveCriticalSection(prim->crst);
939 if(This->buffer)
940 DS8Data_Release(This->buffer);
942 popALContext();
944 HeapFree(GetProcessHeap(), 0, This->notify);
945 HeapFree(GetProcessHeap(), 0, This);
949 static HRESULT WINAPI DS8Buffer_QueryInterface(IDirectSoundBuffer8 *iface, REFIID riid, void **ppv)
951 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
953 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
955 *ppv = NULL;
956 if(IsEqualIID(riid, &IID_IUnknown))
957 *ppv = &This->IDirectSoundBuffer8_iface;
958 else if(IsEqualIID(riid, &IID_IDirectSoundBuffer))
959 *ppv = &This->IDirectSoundBuffer_iface;
960 else if(IsEqualIID(riid, &IID_IDirectSoundBuffer8))
962 if(This->primary->parent->is_8)
963 *ppv = &This->IDirectSoundBuffer8_iface;
965 else if(IsEqualIID(riid, &IID_IDirectSound3DBuffer))
967 if((This->buffer->dsbflags&DSBCAPS_CTRL3D))
968 *ppv = &This->IDirectSound3DBuffer_iface;
970 else if(IsEqualIID(riid, &IID_IDirectSoundNotify))
972 if((This->buffer->dsbflags&DSBCAPS_CTRLPOSITIONNOTIFY))
973 *ppv = &This->IDirectSoundNotify_iface;
975 else if(IsEqualIID(riid, &IID_IKsPropertySet))
976 *ppv = &This->IKsPropertySet_iface;
977 else
978 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
980 if(*ppv)
982 IUnknown_AddRef((IUnknown*)*ppv);
983 return S_OK;
986 return E_NOINTERFACE;
989 static ULONG WINAPI DS8Buffer_AddRef(IDirectSoundBuffer8 *iface)
991 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
992 LONG ret;
994 InterlockedIncrement(&This->all_ref);
995 ret = InterlockedIncrement(&This->ref);
996 TRACE("new refcount %"LONGFMT"d\n", ret);
998 return ret;
1001 static ULONG WINAPI DS8Buffer_Release(IDirectSoundBuffer8 *iface)
1003 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1004 LONG ret;
1006 ret = InterlockedDecrement(&This->ref);
1007 TRACE("new refcount %"LONGFMT"d\n", ret);
1008 if(InterlockedDecrement(&This->all_ref) == 0)
1009 DS8Buffer_Destroy(This);
1011 return ret;
1014 static HRESULT WINAPI DS8Buffer_GetCaps(IDirectSoundBuffer8 *iface, DSBCAPS *caps)
1016 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1018 TRACE("(%p)->(%p)\n", iface, caps);
1020 if(!caps || caps->dwSize < sizeof(*caps))
1022 WARN("Invalid DSBCAPS (%p, %"LONGFMT"u)\n", caps, (caps ? caps->dwSize : 0));
1023 return DSERR_INVALIDPARAM;
1026 caps->dwFlags = This->buffer->dsbflags;
1027 caps->dwBufferBytes = This->buffer->buf_size;
1028 caps->dwUnlockTransferRate = 4096;
1029 caps->dwPlayCpuOverhead = 0;
1030 return S_OK;
1033 static HRESULT WINAPI DS8Buffer_GetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD *playpos, DWORD *curpos)
1035 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1036 WAVEFORMATEX *format = &This->buffer->format.Format;
1037 UINT writecursor, pos;
1039 TRACE("(%p)->(%p, %p)\n", iface, playpos, curpos);
1041 EnterCriticalSection(This->crst);
1042 setALContext(This->ctx);
1044 if(This->buffer->numsegs > 1)
1046 ALint queued = QBUFFERS;
1047 alGetSourcei(This->source, AL_BUFFERS_QUEUED, &queued);
1048 checkALError();
1050 pos = (This->curidx+This->buffer->numsegs-queued)%This->buffer->numsegs;
1051 pos *= This->buffer->segsize;
1052 writecursor = This->curidx * This->buffer->segsize;
1054 else if(This->primary->SupportedExt[SOFT_BUFFER_SUB_DATA] ||
1055 This->primary->SupportedExt[SOFT_BUFFER_SAMPLES])
1057 ALint rwpos[2] = { 0, 0 };
1059 alGetSourceiv(This->source, AL_BYTE_RW_OFFSETS_SOFT, rwpos);
1060 checkALError();
1062 pos = rwpos[0];
1063 writecursor = rwpos[1];
1065 else
1067 ALint status = 0;
1068 ALint ofs = 0;
1070 alGetSourcei(This->source, AL_BYTE_OFFSET, &ofs);
1071 alGetSourcei(This->source, AL_SOURCE_STATE, &status);
1072 checkALError();
1074 pos = ofs;
1075 if(status == AL_PLAYING)
1077 writecursor = format->nSamplesPerSec / 100;
1078 writecursor *= format->nBlockAlign;
1080 else
1081 writecursor = 0;
1082 writecursor = (writecursor + pos) % This->buffer->buf_size;
1084 TRACE("%p Play pos = %u, write pos = %u\n", This, pos, writecursor);
1085 if(pos >= This->buffer->buf_size)
1087 ERR("playpos >= buf_size\n");
1088 pos %= This->buffer->buf_size;
1090 if(writecursor >= This->buffer->buf_size)
1092 ERR("writepos >= buf_size\n");
1093 writecursor %= This->buffer->buf_size;
1096 if(playpos) *playpos = pos;
1097 if(curpos) *curpos = writecursor;
1099 popALContext();
1100 LeaveCriticalSection(This->crst);
1102 return S_OK;
1105 static HRESULT WINAPI DS8Buffer_GetFormat(IDirectSoundBuffer8 *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
1107 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1108 HRESULT hr = S_OK;
1109 UINT size;
1111 TRACE("(%p)->(%p, %"LONGFMT"u, %p)\n", iface, wfx, allocated, written);
1113 if(!wfx && !written)
1115 WARN("Cannot report format or format size\n");
1116 return DSERR_INVALIDPARAM;
1119 size = sizeof(This->buffer->format.Format) + This->buffer->format.Format.cbSize;
1120 if(wfx)
1122 if(allocated < size)
1123 hr = DSERR_INVALIDPARAM;
1124 else
1125 memcpy(wfx, &This->buffer->format.Format, size);
1127 if(written)
1128 *written = size;
1130 return hr;
1133 static HRESULT WINAPI DS8Buffer_GetVolume(IDirectSoundBuffer8 *iface, LONG *vol)
1135 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1136 HRESULT hr;
1138 TRACE("(%p)->(%p)\n", iface, vol);
1140 if(!vol)
1142 WARN("Invalid pointer\n");
1143 return DSERR_INVALIDPARAM;
1146 hr = DSERR_CONTROLUNAVAIL;
1147 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
1148 WARN("Volume control not set\n");
1149 else
1151 ALfloat gain = 1.0f;
1153 setALContext(This->ctx);
1154 alGetSourcef(This->source, AL_GAIN, &gain);
1155 checkALError();
1156 popALContext();
1158 *vol = clampI(gain_to_mB(gain), DSBVOLUME_MIN, DSBVOLUME_MAX);
1159 hr = DS_OK;
1162 return hr;
1165 static HRESULT WINAPI DS8Buffer_GetPan(IDirectSoundBuffer8 *iface, LONG *pan)
1167 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1168 HRESULT hr;
1170 TRACE("(%p)->(%p)\n", iface, pan);
1172 if(!pan)
1174 WARN("Invalid pointer\n");
1175 return DSERR_INVALIDPARAM;
1178 hr = DSERR_CONTROLUNAVAIL;
1179 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
1180 WARN("Panning control not set\n");
1181 else
1183 ALfloat pos[3];
1185 setALContext(This->ctx);
1186 alGetSourcefv(This->source, AL_POSITION, pos);
1187 checkALError();
1188 popALContext();
1190 *pan = clampI(((pos[0]+1.0) * (DSBPAN_RIGHT-DSBPAN_LEFT) / 2.0 + 0.5) + DSBPAN_LEFT, DSBPAN_LEFT, DSBPAN_RIGHT);
1191 hr = DS_OK;
1194 return hr;
1197 static HRESULT WINAPI DS8Buffer_GetFrequency(IDirectSoundBuffer8 *iface, DWORD *freq)
1199 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1200 HRESULT hr;
1202 TRACE("(%p)->(%p)\n", iface, freq);
1204 if(!freq)
1206 WARN("Invalid pointer\n");
1207 return DSERR_INVALIDPARAM;
1210 hr = DSERR_CONTROLUNAVAIL;
1211 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
1212 WARN("Frequency control not set\n");
1213 else
1215 ALfloat pitch = 1.0f;
1217 setALContext(This->ctx);
1218 alGetSourcefv(This->source, AL_PITCH, &pitch);
1219 checkALError();
1220 popALContext();
1222 *freq = (DWORD)(This->buffer->format.Format.nSamplesPerSec * pitch);
1223 hr = DS_OK;
1226 return hr;
1229 static HRESULT WINAPI DS8Buffer_GetStatus(IDirectSoundBuffer8 *iface, DWORD *status)
1231 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1232 ALint state, looping;
1234 TRACE("(%p)->(%p)\n", iface, status);
1236 if(!status)
1238 WARN("Invalid pointer\n");
1239 return DSERR_INVALIDPARAM;
1242 EnterCriticalSection(This->crst);
1244 setALContext(This->ctx);
1245 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1246 looping = This->islooping;
1247 if(This->buffer->numsegs == 1)
1248 alGetSourcei(This->source, AL_LOOPING, &looping);
1249 else if(state != AL_PLAYING)
1250 state = This->isplaying ? AL_PLAYING : AL_PAUSED;
1251 checkALError();
1252 popALContext();
1254 LeaveCriticalSection(This->crst);
1256 *status = 0;
1257 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1259 if((This->buffer->dsbflags&DSBCAPS_LOCSOFTWARE))
1260 *status |= DSBSTATUS_LOCSOFTWARE;
1261 else if((This->buffer->dsbflags&DSBCAPS_LOCHARDWARE))
1262 *status |= DSBSTATUS_LOCHARDWARE;
1264 if(state == AL_PLAYING)
1265 *status |= DSBSTATUS_PLAYING | (looping ? DSBSTATUS_LOOPING : 0);
1267 return S_OK;
1270 static HRESULT WINAPI DS8Buffer_Initialize(IDirectSoundBuffer8 *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
1272 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1273 DS3DBUFFER *ds3dbuffer;
1274 HRESULT hr;
1276 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
1278 EnterCriticalSection(This->crst);
1279 setALContext(This->ctx);
1281 hr = DSERR_ALREADYINITIALIZED;
1282 if(This->source)
1283 goto out;
1285 if(!This->buffer)
1287 hr = DSERR_INVALIDPARAM;
1288 if(!desc)
1290 WARN("Missing DSound buffer description\n");
1291 goto out;
1293 if(!desc->lpwfxFormat)
1295 WARN("Missing buffer format (%p)\n", This);
1296 goto out;
1298 if((desc->dwFlags&DSBCAPS_CTRL3D) && desc->lpwfxFormat->nChannels != 1)
1300 if(This->primary->parent->is_8)
1302 /* DirectSoundBuffer8 objects aren't allowed non-mono 3D
1303 * buffers */
1304 WARN("Can't create multi-channel 3D buffers\n");
1305 goto out;
1307 ERR("Multi-channel 3D sounds are not spatialized\n");
1310 hr = DS8Data_Create(&This->buffer, desc, This->primary);
1311 if(FAILED(hr))
1312 goto out;
1313 else
1315 DS8Data *buf = This->buffer;
1317 if(buf->format.Format.wBitsPerSample == 8)
1318 memset(buf->data, 0x80, buf->buf_size);
1319 else
1320 memset(buf->data, 0x00, buf->buf_size);
1322 if(This->primary->SupportedExt[EXT_STATIC_BUFFER])
1323 This->ExtAL->BufferDataStatic(buf->buffers[0], buf->buf_format,
1324 buf->data, buf->buf_size,
1325 buf->format.Format.nSamplesPerSec);
1326 else if(This->primary->SupportedExt[SOFT_BUFFER_SAMPLES])
1327 This->ExtAL->BufferSamplesSOFT(buf->buffers[0],
1328 buf->format.Format.nSamplesPerSec, buf->buf_format,
1329 buf->buf_size/buf->format.Format.nBlockAlign,
1330 buf->in_chans, buf->in_type, buf->data);
1331 else if(This->primary->SupportedExt[SOFT_BUFFER_SUB_DATA])
1332 alBufferData(buf->buffers[0], buf->buf_format,
1333 buf->data, buf->buf_size,
1334 buf->format.Format.nSamplesPerSec);
1336 checkALError();
1339 hr = DSERR_GENERIC;
1340 if(This->primary->parent->share->nsources)
1342 This->source = This->primary->sources[--(This->primary->parent->share->nsources)];
1343 alSourcef(This->source, AL_GAIN, 1.0f);
1344 alSourcef(This->source, AL_PITCH, 1.0f);
1345 checkALError();
1347 else
1348 goto out;
1350 ds3dbuffer = &This->ds3dbuffer;
1351 ds3dbuffer->dwSize = sizeof(*ds3dbuffer);
1352 ds3dbuffer->vPosition.x = 0.0;
1353 ds3dbuffer->vPosition.y = 0.0;
1354 ds3dbuffer->vPosition.z = 0.0;
1355 ds3dbuffer->vVelocity.x = 0.0;
1356 ds3dbuffer->vVelocity.y = 0.0;
1357 ds3dbuffer->vVelocity.z = 0.0;
1358 ds3dbuffer->dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
1359 ds3dbuffer->dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
1360 ds3dbuffer->vConeOrientation.x = 0.0;
1361 ds3dbuffer->vConeOrientation.y = 0.0;
1362 ds3dbuffer->vConeOrientation.z = 1.0;
1363 ds3dbuffer->lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
1364 ds3dbuffer->flMinDistance = DS3D_DEFAULTMINDISTANCE;
1365 ds3dbuffer->flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
1366 ds3dbuffer->dwMode = DS3DMODE_NORMAL;
1368 if((This->buffer->dsbflags&DSBCAPS_CTRL3D))
1370 if(This->primary->auxslot != 0)
1372 alSource3i(This->source, AL_AUXILIARY_SEND_FILTER, This->primary->auxslot, 0, AL_FILTER_NULL);
1373 checkALError();
1376 hr = IDirectSound3DBuffer_SetAllParameters(&This->IDirectSound3DBuffer_iface, ds3dbuffer, DS3D_IMMEDIATE);
1377 if(FAILED(hr))
1379 ERR("SetAllParameters failed\n");
1380 goto out;
1383 else
1385 ALuint source = This->source;
1387 if(This->primary->auxslot != 0)
1389 /* Simple hack to make reverb affect non-3D sounds too */
1390 alSource3i(source, AL_AUXILIARY_SEND_FILTER, This->primary->auxslot, 0, AL_FILTER_NULL);
1391 /*alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL);*/
1394 /* Non-3D sources aren't distance attenuated */
1395 This->ds3dmode = DS3DMODE_DISABLE;
1396 alSource3f(source, AL_POSITION, 0.0f, 1.0f, 0.0f);
1397 alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
1398 alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
1399 alSourcef(source, AL_CONE_OUTER_GAIN, 1.0f);
1400 alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f);
1401 alSourcef(source, AL_MAX_DISTANCE, 1000.0f);
1402 alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f);
1403 alSourcei(source, AL_CONE_INNER_ANGLE, 360);
1404 alSourcei(source, AL_CONE_OUTER_ANGLE, 360);
1405 alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);
1406 checkALError();
1408 hr = S_OK;
1410 out:
1411 popALContext();
1412 LeaveCriticalSection(This->crst);
1414 return hr;
1417 static HRESULT WINAPI DS8Buffer_Lock(IDirectSoundBuffer8 *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
1419 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1420 DWORD remain;
1422 TRACE("(%p)->(%"LONGFMT"u, %"LONGFMT"u, %p, %p, %p, %p, 0x%"LONGFMT"x)\n", This, ofs, bytes, ptr1, len1, ptr2, len2, flags);
1424 if(!ptr1 || !len1)
1426 WARN("Invalid pointer/len %p %p\n", ptr1, len1);
1427 return DSERR_INVALIDPARAM;
1430 *ptr1 = NULL;
1431 *len1 = 0;
1432 if(ptr2) *ptr2 = NULL;
1433 if(len2) *len2 = 0;
1435 if((flags&DSBLOCK_FROMWRITECURSOR))
1436 DS8Buffer_GetCurrentPosition(iface, NULL, &ofs);
1437 else if(ofs >= This->buffer->buf_size)
1439 WARN("Invalid ofs %"LONGFMT"u\n", ofs);
1440 return DSERR_INVALIDPARAM;
1442 if((flags&DSBLOCK_ENTIREBUFFER))
1443 bytes = This->buffer->buf_size;
1444 else if(bytes > This->buffer->buf_size)
1446 WARN("Invalid size %"LONGFMT"u\n", bytes);
1447 return DSERR_INVALIDPARAM;
1450 if(InterlockedExchange(&This->buffer->locked, TRUE) == TRUE)
1452 WARN("Already locked\n");
1453 return DSERR_INVALIDPARAM;
1456 *ptr1 = This->buffer->data + ofs;
1457 if(ofs+bytes >= This->buffer->buf_size)
1459 *len1 = This->buffer->buf_size - ofs;
1460 remain = bytes - *len1;
1462 else
1464 *len1 = bytes;
1465 remain = 0;
1468 if(ptr2 && len2 && remain)
1470 *ptr2 = This->buffer->data;
1471 *len2 = remain;
1474 return DS_OK;
1477 static HRESULT WINAPI DS8Buffer_Play(IDirectSoundBuffer8 *iface, DWORD res1, DWORD prio, DWORD flags)
1479 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1480 ALint type, state = AL_STOPPED;
1481 HRESULT hr;
1483 TRACE("(%p)->(%"LONGFMT"u, %"LONGFMT"u, %"LONGFMT"u\n", iface, res1, prio, flags);
1485 EnterCriticalSection(This->crst);
1486 setALContext(This->ctx);
1488 hr = DSERR_BUFFERLOST;
1489 if(This->bufferlost)
1491 WARN("Buffer %p lost\n", This);
1492 goto out;
1495 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1497 if(!(This->buffer->dsbflags&(DSBCAPS_LOCHARDWARE|DSBCAPS_LOCSOFTWARE)))
1499 if(flags & DSBPLAY_LOCSOFTWARE)
1500 This->buffer->dsbflags |= DSBCAPS_LOCSOFTWARE;
1501 else
1502 This->buffer->dsbflags |= DSBCAPS_LOCHARDWARE;
1505 else if(prio)
1507 ERR("Invalid priority set for non-deferred buffer %p, %"LONGFMT"u!\n", This->buffer, prio);
1508 hr = DSERR_INVALIDPARAM;
1509 goto out;
1512 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1513 if(This->buffer->numsegs > 1)
1515 This->islooping = !!(flags&DSBPLAY_LOOPING);
1516 if(state != AL_PLAYING && This->isplaying)
1517 state = AL_PLAYING;
1519 else
1521 alGetSourcei(This->source, AL_SOURCE_TYPE, &type);
1522 alSourcei(This->source, AL_LOOPING, (flags&DSBPLAY_LOOPING) ? AL_TRUE : AL_FALSE);
1524 checkALError();
1526 hr = S_OK;
1527 if(state == AL_PLAYING)
1528 goto out;
1530 /* alSourceQueueBuffers will implicitly set type to streaming */
1531 if(This->buffer->numsegs == 1)
1533 if(type != AL_STATIC)
1534 alSourcei(This->source, AL_BUFFER, This->buffer->buffers[0]);
1535 alSourcePlay(This->source);
1537 if(alGetError() != AL_NO_ERROR)
1539 ERR("Couldn't start source\n");
1540 This->curidx = (This->buffer->numsegs-1+This->curidx)%This->buffer->numsegs;
1541 alSourcei(This->source, AL_BUFFER, 0);
1542 checkALError();
1543 hr = DSERR_GENERIC;
1544 goto out;
1546 This->isplaying = TRUE;
1548 if(This->nnotify)
1550 DS8Buffer_addnotify(This);
1551 DS8Buffer_starttimer(This->primary);
1553 else if(This->buffer->numsegs > 1)
1554 DS8Buffer_starttimer(This->primary);
1556 out:
1557 popALContext();
1558 LeaveCriticalSection(This->crst);
1559 return hr;
1562 static HRESULT WINAPI DS8Buffer_SetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD pos)
1564 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1566 TRACE("(%p)->(%"LONGFMT"u)\n", iface, pos);
1568 if(pos >= This->buffer->buf_size)
1569 return DSERR_INVALIDPARAM;
1571 EnterCriticalSection(This->crst);
1573 if(This->buffer->numsegs > 1)
1575 DS8Data *buf = This->buffer;
1576 This->curidx = pos/buf->segsize;
1577 if(This->curidx >= buf->numsegs)
1578 This->curidx = buf->numsegs - 1;
1579 if(This->isplaying)
1581 setALContext(This->ctx);
1582 /* Perform a flush, so the next timer update will restart at the
1583 * proper position */
1584 alSourceStop(This->source);
1585 alSourcei(This->source, AL_BUFFER, 0);
1586 checkALError();
1587 popALContext();
1590 else
1592 setALContext(This->ctx);
1593 alSourcei(This->source, AL_BYTE_OFFSET, pos);
1594 popALContext();
1596 This->lastpos = pos;
1598 LeaveCriticalSection(This->crst);
1599 return DS_OK;
1602 static HRESULT WINAPI DS8Buffer_SetFormat(IDirectSoundBuffer8 *iface, const WAVEFORMATEX *wfx)
1604 /* This call only works on primary buffers */
1605 WARN("(%p)->(%p)\n", iface, wfx);
1606 return DSERR_INVALIDCALL;
1609 static HRESULT WINAPI DS8Buffer_SetVolume(IDirectSoundBuffer8 *iface, LONG vol)
1611 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1612 HRESULT hr = S_OK;
1614 TRACE("(%p)->(%"LONGFMT"d)\n", iface, vol);
1616 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
1618 WARN("Invalid volume (%"LONGFMT"d)\n", vol);
1619 return DSERR_INVALIDPARAM;
1622 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
1623 hr = DSERR_CONTROLUNAVAIL;
1624 if(SUCCEEDED(hr))
1626 ALfloat fvol = mB_to_gain(vol);
1627 setALContext(This->ctx);
1628 alSourcef(This->source, AL_GAIN, fvol);
1629 popALContext();
1632 return hr;
1635 static HRESULT WINAPI DS8Buffer_SetPan(IDirectSoundBuffer8 *iface, LONG pan)
1637 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1638 HRESULT hr = S_OK;
1640 TRACE("(%p)->(%"LONGFMT"d)\n", iface, pan);
1642 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
1644 WARN("invalid parameter: pan = %"LONGFMT"d\n", pan);
1645 return DSERR_INVALIDPARAM;
1648 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
1649 hr = DSERR_CONTROLUNAVAIL;
1650 else
1652 ALfloat pos[3];
1653 pos[0] = (pan-DSBPAN_LEFT) * 2.0 / (ALfloat)(DSBPAN_RIGHT-DSBPAN_LEFT) - 1.0;
1654 /* NOTE: Strict movement along the X plane can cause the sound to jump
1655 * between left and right sharply. Using a curved path helps smooth it
1656 * out */
1657 pos[1] = sqrt(1.0 - pos[0]*pos[0]);
1658 pos[2] = 0.0;
1660 setALContext(This->ctx);
1661 alSourcefv(This->source, AL_POSITION, pos);
1662 checkALError();
1663 popALContext();
1665 if(pan != 0 && This->buffer->format.Format.nChannels > 1)
1666 FIXME("Panning for multi-channel buffers is not supported\n");
1669 return hr;
1672 static HRESULT WINAPI DS8Buffer_SetFrequency(IDirectSoundBuffer8 *iface, DWORD freq)
1674 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1675 HRESULT hr = S_OK;
1677 TRACE("(%p)->(%"LONGFMT"u)\n", iface, freq);
1679 if(freq < DSBFREQUENCY_MIN || freq > DSBFREQUENCY_MAX)
1681 WARN("invalid parameter: freq = %"LONGFMT"u\n", freq);
1682 return DSERR_INVALIDPARAM;
1685 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
1686 hr = DSERR_CONTROLUNAVAIL;
1687 else
1689 ALfloat pitch = 1.0f;
1690 if(freq != DSBFREQUENCY_ORIGINAL)
1691 pitch = freq / (ALfloat)This->buffer->format.Format.nSamplesPerSec;
1693 setALContext(This->ctx);
1694 alSourcef(This->source, AL_PITCH, pitch);
1695 checkALError();
1696 popALContext();
1699 return hr;
1702 static HRESULT WINAPI DS8Buffer_Stop(IDirectSoundBuffer8 *iface)
1704 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1705 ALint state;
1707 TRACE("(%p)->()\n", iface);
1709 EnterCriticalSection(This->crst);
1710 setALContext(This->ctx);
1712 alSourcePause(This->source);
1713 checkALError();
1714 /* Mac OS X doesn't immediately report state change
1715 * if Play() is immediately called after Stop, this can be fatal,
1716 * the buffer would never be restarted
1718 do {
1719 state = AL_PAUSED;
1720 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1721 if(state != AL_PLAYING)
1722 break;
1723 Sleep(1);
1724 } while(1);
1726 This->isplaying = FALSE;
1728 popALContext();
1729 LeaveCriticalSection(This->crst);
1731 return S_OK;
1734 static HRESULT WINAPI DS8Buffer_Unlock(IDirectSoundBuffer8 *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
1736 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1737 DS8Data *buf = This->buffer;
1738 DWORD bufsize = buf->buf_size;
1739 DWORD_PTR ofs1, ofs2;
1740 DWORD_PTR boundary = (DWORD_PTR)buf->data;
1741 HRESULT hr;
1743 TRACE("(%p)->(%p, %"LONGFMT"u, %p, %"LONGFMT"u)\n", iface, ptr1, len1, ptr2, len2);
1745 if(InterlockedExchange(&This->buffer->locked, FALSE) == FALSE)
1747 WARN("Not locked\n");
1748 return DSERR_INVALIDPARAM;
1751 hr = DSERR_INVALIDPARAM;
1752 /* Make sure offset is between boundary and boundary + bufsize */
1753 ofs1 = (DWORD_PTR)ptr1;
1754 ofs2 = (DWORD_PTR)ptr2;
1755 if(ofs1 < boundary)
1756 goto out;
1757 if(ofs2 && ofs2 != boundary)
1758 goto out;
1759 ofs1 -= boundary;
1760 ofs2 = 0;
1761 if(bufsize-ofs1 < len1 || len2 > ofs1)
1762 goto out;
1763 if(!ptr2)
1764 len2 = 0;
1766 hr = DS_OK;
1767 if(!len1 && !len2)
1768 goto out;
1769 if(This->primary->SupportedExt[EXT_STATIC_BUFFER])
1770 goto out;
1772 setALContext(This->ctx);
1773 if(This->primary->SupportedExt[SOFT_BUFFER_SAMPLES])
1775 const WAVEFORMATEX *format = &buf->format.Format;
1777 ptr1 = (BYTE*)ptr1 - (ofs1%format->nBlockAlign);
1778 ofs1 /= format->nBlockAlign;
1779 len1 /= format->nBlockAlign;
1780 if(len1 > 0)
1781 This->ExtAL->BufferSubSamplesSOFT(buf->buffers[0], ofs1, len1,
1782 buf->in_chans, buf->in_type, ptr1);
1783 ptr2 = (BYTE*)ptr2 - (ofs2%format->nBlockAlign);
1784 ofs2 /= format->nBlockAlign;
1785 len2 /= format->nBlockAlign;
1786 if(len2 > 0)
1787 This->ExtAL->BufferSubSamplesSOFT(buf->buffers[0], ofs2, len2,
1788 buf->in_chans, buf->in_type, ptr2);
1789 checkALError();
1791 else if(This->primary->SupportedExt[SOFT_BUFFER_SUB_DATA])
1793 const WAVEFORMATEX *format = &buf->format.Format;
1795 len1 -= len1%format->nBlockAlign;
1796 if(len1 > 0)
1797 This->ExtAL->BufferSubData(buf->buffers[0], buf->buf_format, ptr1,
1798 ofs1, len1);
1799 len2 -= len2%format->nBlockAlign;
1800 if(len2 > 0)
1801 This->ExtAL->BufferSubData(buf->buffers[0], buf->buf_format, ptr2,
1802 ofs2, len2);
1803 checkALError();
1805 else
1807 alBufferData(buf->buffers[0], buf->buf_format,
1808 buf->data, buf->buf_size,
1809 buf->format.Format.nSamplesPerSec);
1810 checkALError();
1812 popALContext();
1814 out:
1815 if(hr != S_OK)
1816 WARN("Invalid parameters (0x%lx,%"LONGFMT"u) (%p,%"LONGFMT"u,%p,%"LONGFMT"u)\n", boundary, bufsize, ptr1, len1, ptr2, len2);
1817 return hr;
1820 static HRESULT WINAPI DS8Buffer_Restore(IDirectSoundBuffer8 *iface)
1822 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1823 HRESULT hr;
1825 TRACE("(%p)->()\n", iface);
1827 EnterCriticalSection(This->crst);
1828 if(This->primary->parent->prio_level < DSSCL_WRITEPRIMARY ||
1829 iface == This->primary->write_emu)
1831 This->bufferlost = 0;
1832 hr = S_OK;
1834 else
1835 hr = DSERR_BUFFERLOST;
1836 LeaveCriticalSection(This->crst);
1838 return hr;
1841 static HRESULT WINAPI DS8Buffer_SetFX(IDirectSoundBuffer8 *iface, DWORD fxcount, DSEFFECTDESC *desc, DWORD *rescodes)
1843 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1844 DWORD i;
1846 TRACE("(%p)->(%"LONGFMT"u, %p, %p)\n", This, fxcount, desc, rescodes);
1848 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFX))
1850 WARN("FX control not set\n");
1851 return DSERR_CONTROLUNAVAIL;
1854 if(fxcount == 0)
1856 if(desc || rescodes)
1858 WARN("Non-NULL desc and/or result pointer specified with no effects.\n");
1859 return DSERR_INVALIDPARAM;
1862 /* No effects; we can handle that */
1863 return DS_OK;
1866 if(!desc || !rescodes)
1868 WARN("NULL desc and/or result pointer specified.\n");
1869 return DSERR_INVALIDPARAM;
1872 /* We don't (currently) handle DSound effects */
1873 for(i = 0;i < fxcount;++i)
1875 FIXME("Cannot handle effect: %s\n", debugstr_guid(&desc[i].guidDSFXClass));
1876 rescodes[i] = DSFXR_FAILED;
1879 return DS_INCOMPLETE;
1882 static HRESULT WINAPI DS8Buffer_AcquireResources(IDirectSoundBuffer8 *iface, DWORD flags, DWORD fxcount, DWORD *rescodes)
1884 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1886 TRACE("(%p)->(%"LONGFMT"u, %"LONGFMT"u, %p)\n", This, flags, fxcount, rescodes);
1888 /* effects aren't supported at the moment.. */
1889 if(fxcount != 0 || rescodes)
1891 WARN("Non-zero effect count and/or result pointer specified with no effects.\n");
1892 return DSERR_INVALIDPARAM;
1895 EnterCriticalSection(This->crst);
1896 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1898 This->buffer->dsbflags &= ~(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE);
1899 if((flags&DSBPLAY_LOCSOFTWARE))
1900 This->buffer->dsbflags |= DSBCAPS_LOCSOFTWARE;
1901 else
1902 This->buffer->dsbflags |= DSBCAPS_LOCHARDWARE;
1904 LeaveCriticalSection(This->crst);
1906 return S_OK;
1909 static HRESULT WINAPI DS8Buffer_GetObjectInPath(IDirectSoundBuffer8 *iface, REFGUID guid, DWORD idx, REFGUID rguidiface, void **ppv)
1911 FIXME("(%p)->(%s, %"LONGFMT"u, %s, %p) : stub!\n", iface, debugstr_guid(guid), idx, debugstr_guid(rguidiface), ppv);
1912 return E_NOTIMPL;
1915 static const IDirectSoundBuffer8Vtbl DS8Buffer_Vtbl = {
1916 DS8Buffer_QueryInterface,
1917 DS8Buffer_AddRef,
1918 DS8Buffer_Release,
1919 DS8Buffer_GetCaps,
1920 DS8Buffer_GetCurrentPosition,
1921 DS8Buffer_GetFormat,
1922 DS8Buffer_GetVolume,
1923 DS8Buffer_GetPan,
1924 DS8Buffer_GetFrequency,
1925 DS8Buffer_GetStatus,
1926 DS8Buffer_Initialize,
1927 DS8Buffer_Lock,
1928 DS8Buffer_Play,
1929 DS8Buffer_SetCurrentPosition,
1930 DS8Buffer_SetFormat,
1931 DS8Buffer_SetVolume,
1932 DS8Buffer_SetPan,
1933 DS8Buffer_SetFrequency,
1934 DS8Buffer_Stop,
1935 DS8Buffer_Unlock,
1936 DS8Buffer_Restore,
1937 DS8Buffer_SetFX,
1938 DS8Buffer_AcquireResources,
1939 DS8Buffer_GetObjectInPath
1943 static HRESULT WINAPI DSBuffer_QueryInterface(IDirectSoundBuffer *iface, REFIID riid, void **ppv)
1945 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1946 return DS8Buffer_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
1949 static ULONG WINAPI DSBuffer_AddRef(IDirectSoundBuffer *iface)
1951 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1952 return DS8Buffer_AddRef(&This->IDirectSoundBuffer8_iface);
1955 static ULONG WINAPI DSBuffer_Release(IDirectSoundBuffer *iface)
1957 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1958 return DS8Buffer_Release(&This->IDirectSoundBuffer8_iface);
1961 static HRESULT WINAPI DSBuffer_GetCaps(IDirectSoundBuffer *iface, DSBCAPS *caps)
1963 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1964 return DS8Buffer_GetCaps(&This->IDirectSoundBuffer8_iface, caps);
1967 static HRESULT WINAPI DSBuffer_GetCurrentPosition(IDirectSoundBuffer *iface, DWORD *playpos, DWORD *curpos)
1969 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1970 return DS8Buffer_GetCurrentPosition(&This->IDirectSoundBuffer8_iface, playpos, curpos);
1973 static HRESULT WINAPI DSBuffer_GetFormat(IDirectSoundBuffer *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
1975 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1976 return DS8Buffer_GetFormat(&This->IDirectSoundBuffer8_iface, wfx, allocated, written);
1979 static HRESULT WINAPI DSBuffer_GetVolume(IDirectSoundBuffer *iface, LONG *vol)
1981 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1982 return DS8Buffer_GetVolume(&This->IDirectSoundBuffer8_iface, vol);
1985 static HRESULT WINAPI DSBuffer_GetPan(IDirectSoundBuffer *iface, LONG *pan)
1987 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1988 return DS8Buffer_GetPan(&This->IDirectSoundBuffer8_iface, pan);
1991 static HRESULT WINAPI DSBuffer_GetFrequency(IDirectSoundBuffer *iface, DWORD *freq)
1993 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1994 return DS8Buffer_GetFrequency(&This->IDirectSoundBuffer8_iface, freq);
1997 static HRESULT WINAPI DSBuffer_GetStatus(IDirectSoundBuffer *iface, DWORD *status)
1999 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
2000 return DS8Buffer_GetStatus(&This->IDirectSoundBuffer8_iface, status);
2003 static HRESULT WINAPI DSBuffer_Initialize(IDirectSoundBuffer *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
2005 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
2006 return DS8Buffer_Initialize(&This->IDirectSoundBuffer8_iface, ds, desc);
2009 static HRESULT WINAPI DSBuffer_Lock(IDirectSoundBuffer *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
2011 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
2012 return DS8Buffer_Lock(&This->IDirectSoundBuffer8_iface, ofs, bytes, ptr1, len1, ptr2, len2, flags);
2015 static HRESULT WINAPI DSBuffer_Play(IDirectSoundBuffer *iface, DWORD res1, DWORD prio, DWORD flags)
2017 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
2018 return DS8Buffer_Play(&This->IDirectSoundBuffer8_iface, res1, prio, flags);
2021 static HRESULT WINAPI DSBuffer_SetCurrentPosition(IDirectSoundBuffer *iface, DWORD pos)
2023 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
2024 return DS8Buffer_SetCurrentPosition(&This->IDirectSoundBuffer8_iface, pos);
2027 static HRESULT WINAPI DSBuffer_SetFormat(IDirectSoundBuffer *iface, const WAVEFORMATEX *wfx)
2029 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
2030 return DS8Buffer_SetFormat(&This->IDirectSoundBuffer8_iface, wfx);
2033 static HRESULT WINAPI DSBuffer_SetVolume(IDirectSoundBuffer *iface, LONG vol)
2035 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
2036 return DS8Buffer_SetVolume(&This->IDirectSoundBuffer8_iface, vol);
2039 static HRESULT WINAPI DSBuffer_SetPan(IDirectSoundBuffer *iface, LONG pan)
2041 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
2042 return DS8Buffer_SetPan(&This->IDirectSoundBuffer8_iface, pan);
2045 static HRESULT WINAPI DSBuffer_SetFrequency(IDirectSoundBuffer *iface, DWORD freq)
2047 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
2048 return DS8Buffer_SetFrequency(&This->IDirectSoundBuffer8_iface, freq);
2051 static HRESULT WINAPI DSBuffer_Stop(IDirectSoundBuffer *iface)
2053 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
2054 return DS8Buffer_Stop(&This->IDirectSoundBuffer8_iface);
2057 static HRESULT WINAPI DSBuffer_Unlock(IDirectSoundBuffer *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
2059 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
2060 return DS8Buffer_Unlock(&This->IDirectSoundBuffer8_iface, ptr1, len1, ptr2, len2);
2063 static HRESULT WINAPI DSBuffer_Restore(IDirectSoundBuffer *iface)
2065 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
2066 return DS8Buffer_Restore(&This->IDirectSoundBuffer8_iface);
2069 static const IDirectSoundBufferVtbl DSBuffer_Vtbl = {
2070 DSBuffer_QueryInterface,
2071 DSBuffer_AddRef,
2072 DSBuffer_Release,
2073 DSBuffer_GetCaps,
2074 DSBuffer_GetCurrentPosition,
2075 DSBuffer_GetFormat,
2076 DSBuffer_GetVolume,
2077 DSBuffer_GetPan,
2078 DSBuffer_GetFrequency,
2079 DSBuffer_GetStatus,
2080 DSBuffer_Initialize,
2081 DSBuffer_Lock,
2082 DSBuffer_Play,
2083 DSBuffer_SetCurrentPosition,
2084 DSBuffer_SetFormat,
2085 DSBuffer_SetVolume,
2086 DSBuffer_SetPan,
2087 DSBuffer_SetFrequency,
2088 DSBuffer_Stop,
2089 DSBuffer_Unlock,
2090 DSBuffer_Restore
2094 static HRESULT WINAPI DS8Buffer3D_QueryInterface(IDirectSound3DBuffer *iface, REFIID riid, void **ppv)
2096 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2097 return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2100 static ULONG WINAPI DS8Buffer3D_AddRef(IDirectSound3DBuffer *iface)
2102 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2103 LONG ret;
2105 InterlockedIncrement(&This->all_ref);
2106 ret = InterlockedIncrement(&This->ds3d_ref);
2107 TRACE("new refcount %"LONGFMT"d\n", ret);
2109 return ret;
2112 static ULONG WINAPI DS8Buffer3D_Release(IDirectSound3DBuffer *iface)
2114 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2115 LONG ret;
2117 ret = InterlockedDecrement(&This->ds3d_ref);
2118 TRACE("new refcount %"LONGFMT"d\n", ret);
2119 if(InterlockedDecrement(&This->all_ref) == 0)
2120 DS8Buffer_Destroy(This);
2122 return ret;
2125 static HRESULT WINAPI DS8Buffer3D_GetAllParameters(IDirectSound3DBuffer *iface, DS3DBUFFER *ds3dbuffer)
2127 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2128 DS3DBUFFER ds3dbuf;
2129 HRESULT hr;
2131 TRACE("%p\n", This);
2133 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
2135 WARN("Invalid parameters %p %"LONGFMT"u\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
2136 return DSERR_INVALIDPARAM;
2138 ds3dbuf.dwSize = sizeof(ds3dbuf);
2140 EnterCriticalSection(This->crst);
2141 setALContext(This->ctx);
2143 hr = IDirectSound3DBuffer_GetPosition(iface, &ds3dbuf.vPosition);
2144 if(SUCCEEDED(hr))
2145 hr = IDirectSound3DBuffer_GetVelocity(iface, &ds3dbuf.vVelocity);
2146 if(SUCCEEDED(hr))
2147 hr = IDirectSound3DBuffer_GetConeAngles(iface, &ds3dbuf.dwInsideConeAngle, &ds3dbuf.dwOutsideConeAngle);
2148 if(SUCCEEDED(hr))
2149 hr = IDirectSound3DBuffer_GetConeOrientation(iface, &ds3dbuf.vConeOrientation);
2150 if(SUCCEEDED(hr))
2151 hr = IDirectSound3DBuffer_GetConeOutsideVolume(iface, &ds3dbuf.lConeOutsideVolume);
2152 if(SUCCEEDED(hr))
2153 hr = IDirectSound3DBuffer_GetMinDistance(iface, &ds3dbuf.flMinDistance);
2154 if(SUCCEEDED(hr))
2155 hr = IDirectSound3DBuffer_GetMaxDistance(iface, &ds3dbuf.flMaxDistance);
2156 if(SUCCEEDED(hr))
2157 hr = IDirectSound3DBuffer_GetMode(iface, &ds3dbuf.dwMode);
2158 if(SUCCEEDED(hr))
2159 memcpy(ds3dbuffer, &ds3dbuf, sizeof(ds3dbuf));
2161 popALContext();
2162 LeaveCriticalSection(This->crst);
2164 return hr;
2167 static HRESULT WINAPI DS8Buffer3D_GetConeAngles(IDirectSound3DBuffer *iface, DWORD *pdwInsideConeAngle, DWORD *pdwOutsideConeAngle)
2169 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2170 ALint inangle, outangle;
2172 TRACE("(%p)->(%p, %p)\n", This, pdwInsideConeAngle, pdwOutsideConeAngle);
2173 if(!pdwInsideConeAngle || !pdwOutsideConeAngle)
2175 WARN("Invalid pointers (%p, %p)\n", pdwInsideConeAngle, pdwOutsideConeAngle);
2176 return DSERR_INVALIDPARAM;
2179 EnterCriticalSection(This->crst);
2180 setALContext(This->ctx);
2182 alGetSourcei(This->source, AL_CONE_INNER_ANGLE, &inangle);
2183 alGetSourcei(This->source, AL_CONE_OUTER_ANGLE, &outangle);
2184 checkALError();
2185 *pdwInsideConeAngle = inangle;
2186 *pdwOutsideConeAngle = outangle;
2188 popALContext();
2189 LeaveCriticalSection(This->crst);
2191 return S_OK;
2194 static HRESULT WINAPI DS8Buffer3D_GetConeOrientation(IDirectSound3DBuffer *iface, D3DVECTOR *orient)
2196 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2197 ALfloat dir[3];
2199 TRACE("(%p)->(%p)\n", This, orient);
2200 if(!orient)
2202 WARN("Invalid pointer\n");
2203 return DSERR_INVALIDPARAM;
2206 EnterCriticalSection(This->crst);
2207 setALContext(This->ctx);
2209 alGetSourcefv(This->source, AL_DIRECTION, dir);
2210 checkALError();
2211 orient->x = dir[0];
2212 orient->y = dir[1];
2213 orient->z = -dir[2];
2215 popALContext();
2216 LeaveCriticalSection(This->crst);
2218 return S_OK;
2221 static HRESULT WINAPI DS8Buffer3D_GetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG *vol)
2223 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2224 ALfloat gain;
2226 TRACE("(%p)->(%p)\n", This, vol);
2227 if(!vol)
2229 WARN("Invalid pointer\n");
2230 return DSERR_INVALIDPARAM;
2233 EnterCriticalSection(This->crst);
2234 setALContext(This->ctx);
2236 alGetSourcef(This->source, AL_CONE_OUTER_GAIN, &gain);
2237 checkALError();
2239 popALContext();
2240 LeaveCriticalSection(This->crst);
2242 *vol = clampI(gain_to_mB(gain), DSBVOLUME_MIN, DSBVOLUME_MAX);
2243 return S_OK;
2246 static HRESULT WINAPI DS8Buffer3D_GetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE *maxdist)
2248 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2249 ALfloat dist;
2251 TRACE("(%p)->(%p)\n", This, maxdist);
2252 if(!maxdist)
2254 WARN("Invalid pointer\n");
2255 return DSERR_INVALIDPARAM;
2258 EnterCriticalSection(This->crst);
2259 setALContext(This->ctx);
2261 alGetSourcef(This->source, AL_MAX_DISTANCE, &dist);
2262 checkALError();
2264 popALContext();
2265 LeaveCriticalSection(This->crst);
2267 *maxdist = dist;
2268 return S_OK;
2271 static HRESULT WINAPI DS8Buffer3D_GetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE *mindist)
2273 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2274 ALfloat dist;
2276 TRACE("(%p)->(%p)\n", This, mindist);
2277 if(!mindist)
2279 WARN("Invalid pointer\n");
2280 return DSERR_INVALIDPARAM;
2283 EnterCriticalSection(This->crst);
2284 setALContext(This->ctx);
2286 alGetSourcef(This->source, AL_REFERENCE_DISTANCE, &dist);
2287 checkALError();
2288 *mindist = dist;
2290 popALContext();
2291 LeaveCriticalSection(This->crst);
2293 return S_OK;
2296 static HRESULT WINAPI DS8Buffer3D_GetMode(IDirectSound3DBuffer *iface, DWORD *mode)
2298 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2300 TRACE("(%p)->(%p)\n", This, mode);
2301 if(!mode)
2303 WARN("Invalid pointer\n");
2304 return DSERR_INVALIDPARAM;
2307 EnterCriticalSection(This->crst);
2308 *mode = This->ds3dmode;
2309 LeaveCriticalSection(This->crst);
2311 return S_OK;
2314 static HRESULT WINAPI DS8Buffer3D_GetPosition(IDirectSound3DBuffer *iface, D3DVECTOR *pos)
2316 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2317 ALfloat alpos[3];
2319 TRACE("(%p)->(%p)\n", This, pos);
2320 if(!pos)
2322 WARN("Invalid pointer\n");
2323 return DSERR_INVALIDPARAM;
2326 EnterCriticalSection(This->crst);
2327 setALContext(This->ctx);
2329 alGetSourcefv(This->source, AL_POSITION, alpos);
2330 checkALError();
2331 pos->x = alpos[0];
2332 pos->y = alpos[1];
2333 pos->z = -alpos[2];
2335 popALContext();
2336 LeaveCriticalSection(This->crst);
2338 return S_OK;
2341 static HRESULT WINAPI DS8Buffer3D_GetVelocity(IDirectSound3DBuffer *iface, D3DVECTOR *vel)
2343 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2344 ALfloat alvel[3];
2346 TRACE("(%p)->(%p)\n", This, vel);
2347 if(!vel)
2349 WARN("Invalid pointer\n");
2350 return DSERR_INVALIDPARAM;
2353 EnterCriticalSection(This->crst);
2354 setALContext(This->ctx);
2356 alGetSourcefv(This->source, AL_VELOCITY, alvel);
2357 checkALError();
2358 vel->x = alvel[0];
2359 vel->y = alvel[1];
2360 vel->z = -alvel[2];
2362 popALContext();
2363 LeaveCriticalSection(This->crst);
2365 return S_OK;
2368 static HRESULT WINAPI DS8Buffer3D_SetAllParameters(IDirectSound3DBuffer *iface, const DS3DBUFFER *ds3dbuffer, DWORD apply)
2370 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2371 TRACE("(%p)->(%p, %"LONGFMT"u)\n", This, ds3dbuffer, apply);
2373 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
2375 WARN("Invalid DS3DBUFFER (%p, %"LONGFMT"u)\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
2376 return DSERR_INVALIDPARAM;
2379 if(ds3dbuffer->dwInsideConeAngle > DS3D_MAXCONEANGLE ||
2380 ds3dbuffer->dwOutsideConeAngle > DS3D_MAXCONEANGLE)
2382 WARN("Invalid cone angles (%"LONGFMT"u, %"LONGFMT"u)\n", ds3dbuffer->dwInsideConeAngle,
2383 ds3dbuffer->dwOutsideConeAngle);
2384 return DSERR_INVALIDPARAM;
2387 if(ds3dbuffer->lConeOutsideVolume > DSBVOLUME_MAX ||
2388 ds3dbuffer->lConeOutsideVolume < DSBVOLUME_MIN)
2390 WARN("Invalid cone outside volume (%"LONGFMT"d)\n", ds3dbuffer->lConeOutsideVolume);
2391 return DSERR_INVALIDPARAM;
2394 if(ds3dbuffer->flMaxDistance < 0.0f)
2396 WARN("Invalid max distance (%f)\n", ds3dbuffer->flMaxDistance);
2397 return DSERR_INVALIDPARAM;
2400 if(ds3dbuffer->flMinDistance < 0.0f)
2402 WARN("Invalid min distance (%f)\n", ds3dbuffer->flMinDistance);
2403 return DSERR_INVALIDPARAM;
2406 if(ds3dbuffer->dwMode != DS3DMODE_NORMAL &&
2407 ds3dbuffer->dwMode != DS3DMODE_HEADRELATIVE &&
2408 ds3dbuffer->dwMode != DS3DMODE_DISABLE)
2410 WARN("Invalid mode (%"LONGFMT"u)\n", ds3dbuffer->dwMode);
2411 return DSERR_INVALIDPARAM;
2414 EnterCriticalSection(This->crst);
2415 setALContext(This->ctx);
2416 IDirectSound3DBuffer_SetPosition(iface, ds3dbuffer->vPosition.x, ds3dbuffer->vPosition.y, ds3dbuffer->vPosition.z, apply);
2417 IDirectSound3DBuffer_SetVelocity(iface, ds3dbuffer->vVelocity.x, ds3dbuffer->vVelocity.y, ds3dbuffer->vVelocity.z, apply);
2418 IDirectSound3DBuffer_SetConeAngles(iface, ds3dbuffer->dwInsideConeAngle, ds3dbuffer->dwOutsideConeAngle, apply);
2419 IDirectSound3DBuffer_SetConeOrientation(iface, ds3dbuffer->vConeOrientation.x, ds3dbuffer->vConeOrientation.y, ds3dbuffer->vConeOrientation.z, apply);
2420 IDirectSound3DBuffer_SetConeOutsideVolume(iface, ds3dbuffer->lConeOutsideVolume, apply);
2421 IDirectSound3DBuffer_SetMinDistance(iface, ds3dbuffer->flMinDistance, apply);
2422 IDirectSound3DBuffer_SetMaxDistance(iface, ds3dbuffer->flMaxDistance, apply);
2423 IDirectSound3DBuffer_SetMode(iface, ds3dbuffer->dwMode, apply);
2424 popALContext();
2425 LeaveCriticalSection(This->crst);
2427 return S_OK;
2430 static HRESULT WINAPI DS8Buffer3D_SetConeAngles(IDirectSound3DBuffer *iface, DWORD dwInsideConeAngle, DWORD dwOutsideConeAngle, DWORD apply)
2432 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2434 TRACE("(%p)->(%"LONGFMT"u, %"LONGFMT"u, %"LONGFMT"u)\n", This, dwInsideConeAngle, dwOutsideConeAngle, apply);
2435 if(dwInsideConeAngle > DS3D_MAXCONEANGLE ||
2436 dwOutsideConeAngle > DS3D_MAXCONEANGLE)
2438 WARN("Invalid cone angles (%"LONGFMT"u, %"LONGFMT"u)\n", dwInsideConeAngle, dwOutsideConeAngle);
2439 return DSERR_INVALIDPARAM;
2442 EnterCriticalSection(This->crst);
2443 if(apply == DS3D_DEFERRED)
2445 This->ds3dbuffer.dwInsideConeAngle = dwInsideConeAngle;
2446 This->ds3dbuffer.dwOutsideConeAngle = dwOutsideConeAngle;
2447 This->dirty.bit.cone_angles = 1;
2449 else
2451 setALContext(This->ctx);
2452 alSourcei(This->source, AL_CONE_INNER_ANGLE, dwInsideConeAngle);
2453 alSourcei(This->source, AL_CONE_OUTER_ANGLE, dwOutsideConeAngle);
2454 checkALError();
2455 popALContext();
2457 LeaveCriticalSection(This->crst);
2459 return S_OK;
2462 static HRESULT WINAPI DS8Buffer3D_SetConeOrientation(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2464 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2466 TRACE("(%p)->(%f, %f, %f, %"LONGFMT"u)\n", This, x, y, z, apply);
2468 EnterCriticalSection(This->crst);
2469 if(apply == DS3D_DEFERRED)
2471 This->ds3dbuffer.vConeOrientation.x = x;
2472 This->ds3dbuffer.vConeOrientation.y = y;
2473 This->ds3dbuffer.vConeOrientation.z = z;
2474 This->dirty.bit.cone_orient = 1;
2476 else
2478 setALContext(This->ctx);
2479 alSource3f(This->source, AL_DIRECTION, x, y, -z);
2480 checkALError();
2481 popALContext();
2483 LeaveCriticalSection(This->crst);
2485 return S_OK;
2488 static HRESULT WINAPI DS8Buffer3D_SetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG vol, DWORD apply)
2490 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2492 TRACE("(%p)->(%"LONGFMT"d, %"LONGFMT"u)\n", This, vol, apply);
2493 if(vol < DSBVOLUME_MIN || vol > DSBVOLUME_MAX)
2495 WARN("Invalid volume (%"LONGFMT"d)\n", vol);
2496 return DSERR_INVALIDPARAM;
2499 EnterCriticalSection(This->crst);
2500 if(apply == DS3D_DEFERRED)
2502 This->ds3dbuffer.lConeOutsideVolume = vol;
2503 This->dirty.bit.cone_outsidevolume = 1;
2505 else
2507 setALContext(This->ctx);
2508 alSourcef(This->source, AL_CONE_OUTER_GAIN, mB_to_gain(vol));
2509 checkALError();
2510 popALContext();
2512 LeaveCriticalSection(This->crst);
2514 return S_OK;
2517 static HRESULT WINAPI DS8Buffer3D_SetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE maxdist, DWORD apply)
2519 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2521 TRACE("(%p)->(%f, %"LONGFMT"u)\n", This, maxdist, apply);
2522 if(maxdist < 0.0f)
2524 WARN("Invalid max distance (%f)\n", maxdist);
2525 return DSERR_INVALIDPARAM;
2528 EnterCriticalSection(This->crst);
2529 if(apply == DS3D_DEFERRED)
2531 This->ds3dbuffer.flMaxDistance = maxdist;
2532 This->dirty.bit.max_distance = 1;
2534 else
2536 setALContext(This->ctx);
2537 alSourcef(This->source, AL_MAX_DISTANCE, maxdist);
2538 checkALError();
2539 popALContext();
2541 LeaveCriticalSection(This->crst);
2543 return S_OK;
2546 static HRESULT WINAPI DS8Buffer3D_SetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE mindist, DWORD apply)
2548 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2550 TRACE("(%p)->(%f, %"LONGFMT"u)\n", This, mindist, apply);
2551 if(mindist < 0.0f)
2553 WARN("Invalid min distance (%f)\n", mindist);
2554 return DSERR_INVALIDPARAM;
2557 EnterCriticalSection(This->crst);
2558 if(apply == DS3D_DEFERRED)
2560 This->ds3dbuffer.flMinDistance = mindist;
2561 This->dirty.bit.min_distance = 1;
2563 else
2565 setALContext(This->ctx);
2566 alSourcef(This->source, AL_REFERENCE_DISTANCE, mindist);
2567 checkALError();
2568 popALContext();
2570 LeaveCriticalSection(This->crst);
2572 return S_OK;
2575 static HRESULT WINAPI DS8Buffer3D_SetMode(IDirectSound3DBuffer *iface, DWORD mode, DWORD apply)
2577 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2579 TRACE("(%p)->(%"LONGFMT"u, %"LONGFMT"u)\n", This, mode, apply);
2580 if(mode != DS3DMODE_NORMAL && mode != DS3DMODE_HEADRELATIVE &&
2581 mode != DS3DMODE_DISABLE)
2583 WARN("Invalid mode (%"LONGFMT"u)\n", mode);
2584 return DSERR_INVALIDPARAM;
2587 EnterCriticalSection(This->crst);
2588 if(apply == DS3D_DEFERRED)
2590 This->ds3dbuffer.dwMode = mode;
2591 This->dirty.bit.mode = 1;
2593 else
2595 setALContext(This->ctx);
2596 alSourcei(This->source, AL_SOURCE_RELATIVE,
2597 (mode != DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE);
2598 alSourcef(This->source, AL_ROLLOFF_FACTOR,
2599 (mode == DS3DMODE_DISABLE) ? 0.0f : This->primary->rollofffactor);
2600 This->ds3dmode = mode;
2601 checkALError();
2602 popALContext();
2604 LeaveCriticalSection(This->crst);
2606 return S_OK;
2609 static HRESULT WINAPI DS8Buffer3D_SetPosition(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2611 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2613 TRACE("(%p)->(%f, %f, %f, %"LONGFMT"u)\n", This, x, y, z, apply);
2615 EnterCriticalSection(This->crst);
2616 if(apply == DS3D_DEFERRED)
2618 This->ds3dbuffer.vPosition.x = x;
2619 This->ds3dbuffer.vPosition.y = y;
2620 This->ds3dbuffer.vPosition.z = z;
2621 This->dirty.bit.pos = 1;
2623 else
2625 setALContext(This->ctx);
2626 alSource3f(This->source, AL_POSITION, x, y, -z);
2627 checkALError();
2628 popALContext();
2630 LeaveCriticalSection(This->crst);
2632 return S_OK;
2635 static HRESULT WINAPI DS8Buffer3D_SetVelocity(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2637 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2639 TRACE("(%p)->(%f, %f, %f, %"LONGFMT"u)\n", This, x, y, z, apply);
2641 EnterCriticalSection(This->crst);
2642 if(apply == DS3D_DEFERRED)
2644 This->ds3dbuffer.vVelocity.x = x;
2645 This->ds3dbuffer.vVelocity.y = y;
2646 This->ds3dbuffer.vVelocity.z = z;
2647 This->dirty.bit.vel = 1;
2649 else
2651 setALContext(This->ctx);
2652 alSource3f(This->source, AL_VELOCITY, x, y, -z);
2653 checkALError();
2654 popALContext();
2656 LeaveCriticalSection(This->crst);
2658 return S_OK;
2661 static const IDirectSound3DBufferVtbl DS8Buffer3d_Vtbl =
2663 DS8Buffer3D_QueryInterface,
2664 DS8Buffer3D_AddRef,
2665 DS8Buffer3D_Release,
2666 DS8Buffer3D_GetAllParameters,
2667 DS8Buffer3D_GetConeAngles,
2668 DS8Buffer3D_GetConeOrientation,
2669 DS8Buffer3D_GetConeOutsideVolume,
2670 DS8Buffer3D_GetMaxDistance,
2671 DS8Buffer3D_GetMinDistance,
2672 DS8Buffer3D_GetMode,
2673 DS8Buffer3D_GetPosition,
2674 DS8Buffer3D_GetVelocity,
2675 DS8Buffer3D_SetAllParameters,
2676 DS8Buffer3D_SetConeAngles,
2677 DS8Buffer3D_SetConeOrientation,
2678 DS8Buffer3D_SetConeOutsideVolume,
2679 DS8Buffer3D_SetMaxDistance,
2680 DS8Buffer3D_SetMinDistance,
2681 DS8Buffer3D_SetMode,
2682 DS8Buffer3D_SetPosition,
2683 DS8Buffer3D_SetVelocity
2687 static HRESULT WINAPI DS8BufferNot_QueryInterface(IDirectSoundNotify *iface, REFIID riid, void **ppv)
2689 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2690 return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2693 static ULONG WINAPI DS8BufferNot_AddRef(IDirectSoundNotify *iface)
2695 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2696 LONG ret;
2698 InterlockedIncrement(&This->all_ref);
2699 ret = InterlockedIncrement(&This->not_ref);
2700 TRACE("new refcount %"LONGFMT"d\n", ret);
2702 return ret;
2705 static ULONG WINAPI DS8BufferNot_Release(IDirectSoundNotify *iface)
2707 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2708 LONG ret;
2710 ret = InterlockedDecrement(&This->not_ref);
2711 TRACE("new refcount %"LONGFMT"d\n", ret);
2712 if(InterlockedDecrement(&This->all_ref) == 0)
2713 DS8Buffer_Destroy(This);
2715 return ret;
2718 static HRESULT WINAPI DS8BufferNot_SetNotificationPositions(IDirectSoundNotify *iface, DWORD count, const DSBPOSITIONNOTIFY *notifications)
2720 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2721 DSBPOSITIONNOTIFY *nots;
2722 DWORD state;
2723 HRESULT hr;
2725 EnterCriticalSection(This->crst);
2726 hr = DSERR_INVALIDPARAM;
2727 if(count && !notifications)
2728 goto out;
2730 hr = IDirectSoundBuffer8_GetStatus(&This->IDirectSoundBuffer8_iface, &state);
2731 if(FAILED(hr))
2732 goto out;
2734 hr = DSERR_INVALIDCALL;
2735 if((state&DSBSTATUS_PLAYING))
2736 goto out;
2738 if(!count)
2740 HeapFree(GetProcessHeap(), 0, This->notify);
2741 This->notify = 0;
2742 This->nnotify = 0;
2743 hr = S_OK;
2745 else
2747 DWORD i;
2749 hr = DSERR_INVALIDPARAM;
2750 for(i = 0;i < count;++i)
2752 if(notifications[i].dwOffset >= This->buffer->buf_size &&
2753 notifications[i].dwOffset != (DWORD)DSBPN_OFFSETSTOP)
2754 goto out;
2757 hr = E_OUTOFMEMORY;
2758 nots = HeapAlloc(GetProcessHeap(), 0, count*sizeof(*nots));
2759 if(!nots)
2760 goto out;
2761 memcpy(nots, notifications, count*sizeof(*nots));
2763 HeapFree(GetProcessHeap(), 0, This->notify);
2764 This->notify = nots;
2765 This->nnotify = count;
2767 hr = S_OK;
2770 out:
2771 LeaveCriticalSection(This->crst);
2772 return hr;
2775 static const IDirectSoundNotifyVtbl DS8BufferNot_Vtbl =
2777 DS8BufferNot_QueryInterface,
2778 DS8BufferNot_AddRef,
2779 DS8BufferNot_Release,
2780 DS8BufferNot_SetNotificationPositions
2784 static HRESULT WINAPI DS8BufferProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
2786 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2787 return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2790 static ULONG WINAPI DS8BufferProp_AddRef(IKsPropertySet *iface)
2792 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2793 LONG ret;
2795 InterlockedIncrement(&This->all_ref);
2796 ret = InterlockedIncrement(&This->prop_ref);
2797 TRACE("new refcount %"LONGFMT"d\n", ret);
2799 return ret;
2802 static ULONG WINAPI DS8BufferProp_Release(IKsPropertySet *iface)
2804 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2805 LONG ret;
2807 ret = InterlockedDecrement(&This->prop_ref);
2808 TRACE("new refcount %"LONGFMT"d\n", ret);
2809 if(InterlockedDecrement(&This->all_ref) == 0)
2810 DS8Buffer_Destroy(This);
2812 return ret;
2815 /* NOTE: Due to some apparent quirks in DSound, the listener properties are
2816 handled through secondary buffers. */
2817 static HRESULT WINAPI DS8BufferProp_Get(IKsPropertySet *iface,
2818 REFGUID guidPropSet, ULONG dwPropID,
2819 LPVOID pInstanceData, ULONG cbInstanceData,
2820 LPVOID pPropData, ULONG cbPropData,
2821 PULONG pcbReturned)
2823 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2824 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2826 TRACE("(%p)->(%s, %"LONGFMT"u, %p, %"LONGFMT"u, %p, %"LONGFMT"u, %p)\n", iface, debugstr_guid(guidPropSet),
2827 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData, pcbReturned);
2829 if(!pcbReturned)
2830 return E_POINTER;
2831 *pcbReturned = 0;
2833 #if 0
2834 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2837 else
2838 #endif
2840 /* Not a known buffer/source property. Pass it to the listener */
2841 hr = IKsPropertySet_Get(&This->primary->IKsPropertySet_iface, guidPropSet,
2842 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData,
2843 pcbReturned);
2846 return hr;
2849 static HRESULT WINAPI DS8BufferProp_Set(IKsPropertySet *iface,
2850 REFGUID guidPropSet, ULONG dwPropID,
2851 LPVOID pInstanceData, ULONG cbInstanceData,
2852 LPVOID pPropData, ULONG cbPropData)
2854 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2855 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2857 TRACE("(%p)->(%s, %"LONGFMT"u, %p, %"LONGFMT"u, %p, %"LONGFMT"u)\n", iface, debugstr_guid(guidPropSet),
2858 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData);
2860 #if 0
2861 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2864 else
2865 #endif
2867 /* Not a known buffer/source property. Pass it to the listener */
2868 hr = IKsPropertySet_Set(&This->primary->IKsPropertySet_iface, guidPropSet,
2869 dwPropID, pInstanceData, cbInstanceData, pPropData,
2870 cbPropData);
2873 return hr;
2876 static HRESULT WINAPI DS8BufferProp_QuerySupport(IKsPropertySet *iface,
2877 REFGUID guidPropSet, ULONG dwPropID,
2878 PULONG pTypeSupport)
2880 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2881 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2883 TRACE("(%p)->(%s, %"LONGFMT"u, %p)\n", iface, debugstr_guid(guidPropSet), dwPropID, pTypeSupport);
2885 if(!pTypeSupport)
2886 return E_POINTER;
2887 *pTypeSupport = 0;
2889 #if 0
2890 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2893 else
2894 #endif
2896 /* Not a known buffer/source property. Pass it to the listener */
2897 hr = IKsPropertySet_QuerySupport(&This->primary->IKsPropertySet_iface,
2898 guidPropSet, dwPropID, pTypeSupport);
2901 return hr;
2904 static const IKsPropertySetVtbl DS8BufferProp_Vtbl =
2906 DS8BufferProp_QueryInterface,
2907 DS8BufferProp_AddRef,
2908 DS8BufferProp_Release,
2909 DS8BufferProp_Get,
2910 DS8BufferProp_Set,
2911 DS8BufferProp_QuerySupport