Add EAX 2.0 buffer properties
[dsound-openal.git] / buffer.c
blob9e954b651b8dde24cde18d1e56065de0d93ad52e
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 /* Should be called with critsect held and context set.. */
112 static void DS8Buffer_addnotify(DS8Buffer *buf)
114 DS8Buffer **list;
115 DWORD i;
117 list = buf->primary->notifies;
118 for(i = 0; i < buf->primary->nnotifies; ++i)
120 if(buf == list[i])
122 ERR("Buffer %p already in notification list\n", buf);
123 return;
126 if(buf->primary->nnotifies == buf->primary->sizenotifies)
128 list = HeapReAlloc(GetProcessHeap(), 0, list, (buf->primary->nnotifies + 1) * sizeof(*list));
129 if(!list)
130 return;
131 buf->primary->sizenotifies++;
133 list[buf->primary->nnotifies++] = buf;
134 buf->primary->notifies = list;
138 static const char *get_fmtstr_PCM(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out)
140 out->Format = *format;
141 out->Format.cbSize = 0;
143 if(out->Format.nChannels != 1 && out->Format.nChannels != 2 &&
144 !prim->SupportedExt[EXT_MCFORMATS])
146 WARN("Multi-channel not available\n");
147 return NULL;
150 if(format->wBitsPerSample == 8)
152 switch(format->nChannels)
154 case 1: return "AL_FORMAT_MONO8";
155 case 2: return "AL_FORMAT_STEREO8";
156 case 4: return "AL_FORMAT_QUAD8";
157 case 6: return "AL_FORMAT_51CHN8";
158 case 7: return "AL_FORMAT_61CHN8";
159 case 8: return "AL_FORMAT_71CHN8";
162 else if(format->wBitsPerSample == 16)
164 switch(format->nChannels)
166 case 1: return "AL_FORMAT_MONO16";
167 case 2: return "AL_FORMAT_STEREO16";
168 case 4: return "AL_FORMAT_QUAD16";
169 case 6: return "AL_FORMAT_51CHN16";
170 case 7: return "AL_FORMAT_61CHN16";
171 case 8: return "AL_FORMAT_71CHN16";
175 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
176 format->wBitsPerSample, format->nChannels);
177 return NULL;
179 static ALenum get_fmt_PCM(const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out, ALenum *in_chans, ALenum *in_type)
181 out->Format = *format;
182 out->Format.cbSize = 0;
184 if(format->wBitsPerSample == 8)
186 *in_type = AL_UNSIGNED_BYTE;
187 switch(format->nChannels)
189 case 1: *in_chans = AL_MONO;
190 return AL_MONO8;
191 case 2: *in_chans = AL_STEREO;
192 return AL_STEREO8;
193 case 4: *in_chans = AL_QUAD;
194 return AL_QUAD8;
195 case 6: *in_chans = AL_5POINT1;
196 return AL_5POINT1_8;
197 case 7: *in_chans = AL_6POINT1;
198 return AL_6POINT1_8;
199 case 8: *in_chans = AL_7POINT1;
200 return AL_7POINT1_8;
203 else if(format->wBitsPerSample == 16)
205 *in_type = AL_SHORT;
206 switch(format->nChannels)
208 case 1: *in_chans = AL_MONO;
209 return AL_MONO16;
210 case 2: *in_chans = AL_STEREO;
211 return AL_STEREO16;
212 case 4: *in_chans = AL_QUAD;
213 return AL_QUAD16;
214 case 6: *in_chans = AL_5POINT1;
215 return AL_5POINT1_16;
216 case 7: *in_chans = AL_6POINT1;
217 return AL_6POINT1_16;
218 case 8: *in_chans = AL_7POINT1;
219 return AL_7POINT1_16;
222 #if 0 /* Will cause incorrect byte offsets */
223 else if(format->wBitsPerSample == 24)
225 *in_type = AL_BYTE3;
226 switch(format->nChannels)
228 case 1: *in_chans = AL_MONO;
229 return AL_MONO32F;
230 case 2: *in_chans = AL_STEREO;
231 return AL_STEREO32F;
232 case 4: *in_chans = AL_QUAD;
233 return AL_QUAD32F;
234 case 6: *in_chans = AL_5POINT1;
235 return AL_5POINT1_32F;
236 case 7: *in_chans = AL_6POINT1;
237 return AL_6POINT1_32F;
238 case 8: *in_chans = AL_7POINT1;
239 return AL_7POINT1_32F;
242 #endif
243 else if(format->wBitsPerSample == 32)
245 *in_type = AL_INT;
246 switch(format->nChannels)
248 case 1: *in_chans = AL_MONO;
249 return AL_MONO32F;
250 case 2: *in_chans = AL_STEREO;
251 return AL_STEREO32F;
252 case 4: *in_chans = AL_QUAD;
253 return AL_QUAD32F;
254 case 6: *in_chans = AL_5POINT1;
255 return AL_5POINT1_32F;
256 case 7: *in_chans = AL_6POINT1;
257 return AL_6POINT1_32F;
258 case 8: *in_chans = AL_7POINT1;
259 return AL_7POINT1_32F;
263 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
264 format->wBitsPerSample, format->nChannels);
265 return AL_NONE;
268 static const char *get_fmtstr_FLOAT(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out)
270 out->Format = *format;
271 out->Format.cbSize = 0;
273 if(out->Format.nChannels != 1 && out->Format.nChannels != 2 &&
274 !prim->SupportedExt[EXT_MCFORMATS])
276 WARN("Multi-channel not available\n");
277 return NULL;
280 if(format->wBitsPerSample == 32 && prim->SupportedExt[EXT_FLOAT32])
282 switch(format->nChannels)
284 case 1: return "AL_FORMAT_MONO_FLOAT32";
285 case 2: return "AL_FORMAT_STEREO_FLOAT32";
286 case 4: return "AL_FORMAT_QUAD32";
287 case 6: return "AL_FORMAT_51CHN32";
288 case 7: return "AL_FORMAT_61CHN32";
289 case 8: return "AL_FORMAT_71CHN32";
293 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
294 format->wBitsPerSample, format->nChannels);
295 return NULL;
297 static ALenum get_fmt_FLOAT(const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out, ALenum *in_chans, ALenum *in_type)
299 out->Format = *format;
300 out->Format.cbSize = 0;
302 if(format->wBitsPerSample == 32)
304 *in_type = AL_FLOAT;
305 switch(format->nChannels)
307 case 1: *in_chans = AL_MONO;
308 return AL_MONO32F;
309 case 2: *in_chans = AL_STEREO;
310 return AL_STEREO32F;
311 case 4: *in_chans = AL_QUAD;
312 return AL_QUAD32F;
313 case 6: *in_chans = AL_5POINT1;
314 return AL_5POINT1_32F;
315 case 7: *in_chans = AL_6POINT1;
316 return AL_6POINT1_32F;
317 case 8: *in_chans = AL_7POINT1;
318 return AL_7POINT1_32F;
321 #if 0 /* Will cause incorrect byte offsets */
322 else if(format->wBitsPerSample == 64)
324 *in_type = AL_DOUBLE;
325 switch(format->nChannels)
327 case 1: *in_chans = AL_MONO;
328 return AL_MONO32F;
329 case 2: *in_chans = AL_STEREO;
330 return AL_STEREO32F;
331 case 4: *in_chans = AL_QUAD;
332 return AL_QUAD32F;
333 case 6: *in_chans = AL_5POINT1;
334 return AL_5POINT1_32F;
335 case 7: *in_chans = AL_6POINT1;
336 return AL_6POINT1_32F;
337 case 8: *in_chans = AL_7POINT1;
338 return AL_7POINT1_32F;
341 #endif
343 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
344 format->wBitsPerSample, format->nChannels);
345 return AL_NONE;
348 /* Speaker configs */
349 #define MONO SPEAKER_FRONT_CENTER
350 #define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)
351 #define REAR (SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
352 #define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
353 #define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
354 #define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
355 #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)
357 static const char *get_fmtstr_EXT(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out)
359 *out = *CONTAINING_RECORD(format, const WAVEFORMATEXTENSIBLE, Format);
360 out->Format.cbSize = sizeof(*out) - sizeof(out->Format);
362 if(!out->Samples.wValidBitsPerSample)
363 out->Samples.wValidBitsPerSample = out->Format.wBitsPerSample;
364 else if(out->Samples.wValidBitsPerSample != out->Format.wBitsPerSample)
366 FIXME("Padded samples not supported (%u of %u)\n", out->Samples.wValidBitsPerSample, out->Format.wBitsPerSample);
367 return NULL;
370 if(out->dwChannelMask != MONO && out->dwChannelMask != STEREO &&
371 !prim->SupportedExt[EXT_MCFORMATS])
373 WARN("Multi-channel not available\n");
374 return NULL;
377 if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
379 if(out->Samples.wValidBitsPerSample == 8)
381 switch(out->dwChannelMask)
383 case MONO: return "AL_FORMAT_MONO8";
384 case STEREO: return "AL_FORMAT_STEREO8";
385 case REAR: return "AL_FORMAT_REAR8";
386 case QUAD: return "AL_FORMAT_QUAD8";
387 case X5DOT1: return "AL_FORMAT_51CHN8";
388 case X6DOT1: return "AL_FORMAT_61CHN8";
389 case X7DOT1: return "AL_FORMAT_71CHN8";
392 else if(out->Samples.wValidBitsPerSample == 16)
394 switch(out->dwChannelMask)
396 case MONO: return "AL_FORMAT_MONO16";
397 case STEREO: return "AL_FORMAT_STEREO16";
398 case REAR: return "AL_FORMAT_REAR16";
399 case QUAD: return "AL_FORMAT_QUAD16";
400 case X5DOT1: return "AL_FORMAT_51CHN16";
401 case X6DOT1: return "AL_FORMAT_61CHN16";
402 case X7DOT1: return "AL_FORMAT_71CHN16";
406 FIXME("Could not get OpenAL PCM format (%d-bit, channelmask %#"LONGFMT"x)\n",
407 out->Samples.wValidBitsPerSample, out->dwChannelMask);
408 return NULL;
410 else if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) &&
411 prim->SupportedExt[EXT_FLOAT32])
413 if(out->Samples.wValidBitsPerSample == 32)
415 switch(out->dwChannelMask)
417 case MONO: return "AL_FORMAT_MONO_FLOAT32";
418 case STEREO: return "AL_FORMAT_STEREO_FLOAT32";
419 case REAR: return "AL_FORMAT_REAR32";
420 case QUAD: return "AL_FORMAT_QUAD32";
421 case X5DOT1: return "AL_FORMAT_51CHN32";
422 case X6DOT1: return "AL_FORMAT_61CHN32";
423 case X7DOT1: return "AL_FORMAT_71CHN32";
426 else
428 WARN("Invalid float bits: %u\n", out->Samples.wValidBitsPerSample);
429 return NULL;
432 FIXME("Could not get OpenAL float format (%d-bit, channelmask %#"LONGFMT"x)\n",
433 out->Samples.wValidBitsPerSample, out->dwChannelMask);
434 return NULL;
436 else if(!IsEqualGUID(&out->SubFormat, &GUID_NULL))
437 ERR("Unhandled extensible format: %s\n", debugstr_guid(&out->SubFormat));
438 return NULL;
440 static ALenum get_fmt_EXT(const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out, ALenum *in_chans, ALenum *in_type)
442 *out = *CONTAINING_RECORD(format, const WAVEFORMATEXTENSIBLE, Format);
443 out->Format.cbSize = sizeof(*out) - sizeof(out->Format);
445 if(!out->Samples.wValidBitsPerSample)
446 out->Samples.wValidBitsPerSample = out->Format.wBitsPerSample;
447 else if(out->Samples.wValidBitsPerSample != out->Format.wBitsPerSample)
449 FIXME("Padded samples not supported (%u of %u)\n", out->Samples.wValidBitsPerSample, out->Format.wBitsPerSample);
450 return AL_NONE;
453 if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
455 if(out->Samples.wValidBitsPerSample == 8)
457 *in_type = AL_UNSIGNED_BYTE;
458 switch(out->dwChannelMask)
460 case MONO: *in_chans = AL_MONO;
461 return AL_MONO8;
462 case STEREO: *in_chans = AL_STEREO;
463 return AL_STEREO8;
464 case REAR: *in_chans = AL_REAR;
465 return AL_REAR8;
466 case QUAD: *in_chans = AL_QUAD;
467 return AL_QUAD8;
468 case X5DOT1: *in_chans = AL_5POINT1;
469 return AL_5POINT1_8;
470 case X6DOT1: *in_chans = AL_6POINT1;
471 return AL_6POINT1_8;
472 case X7DOT1: *in_chans = AL_7POINT1;
473 return AL_7POINT1_8;
476 else if(out->Samples.wValidBitsPerSample == 16)
478 *in_type = AL_SHORT;
479 switch(out->dwChannelMask)
481 case MONO: *in_chans = AL_MONO;
482 return AL_MONO16;
483 case STEREO: *in_chans = AL_STEREO;
484 return AL_STEREO16;
485 case REAR: *in_chans = AL_REAR;
486 return AL_REAR16;
487 case QUAD: *in_chans = AL_QUAD;
488 return AL_QUAD16;
489 case X5DOT1: *in_chans = AL_5POINT1;
490 return AL_5POINT1_16;
491 case X6DOT1: *in_chans = AL_6POINT1;
492 return AL_6POINT1_16;
493 case X7DOT1: *in_chans = AL_7POINT1;
494 return AL_7POINT1_16;
497 #if 0
498 else if(out->Samples.wValidBitsPerSample == 24)
500 *in_type = AL_BYTE3;
501 switch(out->dwChannelMask)
503 case MONO: *in_chans = AL_MONO;
504 return AL_MONO32F;
505 case STEREO: *in_chans = AL_STEREO;
506 return AL_STEREO32F;
507 case REAR: *in_chans = AL_REAR;
508 return AL_REAR32F;
509 case QUAD: *in_chans = AL_QUAD;
510 return AL_QUAD32F;
511 case X5DOT1: *in_chans = AL_5POINT1;
512 return AL_5POINT1_32F;
513 case X6DOT1: *in_chans = AL_6POINT1;
514 return AL_6POINT1_32F;
515 case X7DOT1: *in_chans = AL_7POINT1;
516 return AL_7POINT1_32F;
519 #endif
520 else if(out->Samples.wValidBitsPerSample == 32)
522 *in_type = AL_INT;
523 switch(out->dwChannelMask)
525 case MONO: *in_chans = AL_MONO;
526 return AL_MONO32F;
527 case STEREO: *in_chans = AL_STEREO;
528 return AL_STEREO32F;
529 case REAR: *in_chans = AL_REAR;
530 return AL_REAR32F;
531 case QUAD: *in_chans = AL_QUAD;
532 return AL_QUAD32F;
533 case X5DOT1: *in_chans = AL_5POINT1;
534 return AL_5POINT1_32F;
535 case X6DOT1: *in_chans = AL_6POINT1;
536 return AL_6POINT1_32F;
537 case X7DOT1: *in_chans = AL_7POINT1;
538 return AL_7POINT1_32F;
542 FIXME("Could not get OpenAL PCM format (%d-bit, channelmask %#"LONGFMT"x)\n",
543 out->Samples.wValidBitsPerSample, out->dwChannelMask);
544 return AL_NONE;
546 else if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
548 if(out->Samples.wValidBitsPerSample == 32)
550 *in_type = AL_FLOAT;
551 switch(out->dwChannelMask)
553 case MONO: *in_chans = AL_MONO;
554 return AL_MONO32F;
555 case STEREO: *in_chans = AL_STEREO;
556 return AL_STEREO32F;
557 case REAR: *in_chans = AL_REAR;
558 return AL_REAR32F;
559 case QUAD: *in_chans = AL_QUAD;
560 return AL_QUAD32F;
561 case X5DOT1: *in_chans = AL_5POINT1;
562 return AL_5POINT1_32F;
563 case X6DOT1: *in_chans = AL_6POINT1;
564 return AL_6POINT1_32F;
565 case X7DOT1: *in_chans = AL_7POINT1;
566 return AL_7POINT1_32F;
569 #if 0
570 else if(out->Samples.wValidBitsPerSample == 64)
572 *in_type = AL_DOUBLE;
573 switch(out->dwChannelMask)
575 case MONO: *in_chans = AL_MONO;
576 return AL_MONO32F;
577 case STEREO: *in_chans = AL_STEREO;
578 return AL_STEREO32F;
579 case REAR: *in_chans = AL_REAR;
580 return AL_REAR32F;
581 case QUAD: *in_chans = AL_QUAD;
582 return AL_QUAD32F;
583 case X5DOT1: *in_chans = AL_5POINT1;
584 return AL_5POINT1_32F;
585 case X6DOT1: *in_chans = AL_6POINT1;
586 return AL_6POINT1_32F;
587 case X7DOT1: *in_chans = AL_7POINT1;
588 return AL_7POINT1_32F;
591 #endif
592 else
594 WARN("Invalid float bits: %u\n", out->Samples.wValidBitsPerSample);
595 return AL_NONE;
598 FIXME("Could not get OpenAL float format (%d-bit, channelmask %#"LONGFMT"x)\n",
599 out->Samples.wValidBitsPerSample, out->dwChannelMask);
600 return AL_NONE;
602 else if(!IsEqualGUID(&out->SubFormat, &GUID_NULL))
603 ERR("Unhandled extensible format: %s\n", debugstr_guid(&out->SubFormat));
604 return AL_NONE;
607 static void DS8Data_Release(DS8Data *This);
608 static HRESULT DS8Data_Create(DS8Data **ppv, const DSBUFFERDESC *desc, DS8Primary *prim)
610 HRESULT hr = DSERR_INVALIDPARAM;
611 const WAVEFORMATEX *format;
612 DS8Data *pBuffer;
614 format = desc->lpwfxFormat;
615 TRACE("Requested buffer format:\n"
616 " FormatTag = 0x%04x\n"
617 " Channels = %d\n"
618 " SamplesPerSec = %"LONGFMT"u\n"
619 " AvgBytesPerSec = %"LONGFMT"u\n"
620 " BlockAlign = %d\n"
621 " BitsPerSample = %d\n",
622 format->wFormatTag, format->nChannels,
623 format->nSamplesPerSec, format->nAvgBytesPerSec,
624 format->nBlockAlign, format->wBitsPerSample);
626 if(format->nBlockAlign == 0)
628 WARN("Invalid BlockAlign specified\n");
629 return DSERR_INVALIDPARAM;
632 /* Generate a new buffer. Supporting the DSBCAPS_LOC* flags properly
633 * will need the EAX-RAM extension. Currently, we just tell the app it
634 * gets what it wanted. */
635 pBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pBuffer));
636 if(!pBuffer)
637 return E_OUTOFMEMORY;
638 pBuffer->ref = 1;
640 pBuffer->dsbflags = desc->dwFlags;
641 if((pBuffer->dsbflags&(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE)) == (DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE))
643 WARN("Hardware and software location requested\n");
644 goto fail;
646 if(!(pBuffer->dsbflags&(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE|DSBCAPS_LOCDEFER)))
647 pBuffer->dsbflags |= DSBCAPS_LOCHARDWARE;
649 pBuffer->buf_size = desc->dwBufferBytes + format->nBlockAlign - 1;
650 pBuffer->buf_size -= pBuffer->buf_size%format->nBlockAlign;
652 hr = DSERR_BUFFERTOOSMALL;
653 if(pBuffer->buf_size < DSBSIZE_MIN)
654 goto fail;
656 hr = DSERR_INVALIDPARAM;
657 if(pBuffer->buf_size > DSBSIZE_MAX)
658 goto fail;
660 pBuffer->numsegs = 1;
661 pBuffer->segsize = pBuffer->buf_size;
662 pBuffer->lastsegsize = pBuffer->buf_size;
664 if(!prim->SupportedExt[SOFT_BUFFER_SAMPLES])
666 const char *fmt_str = NULL;
668 if(!(pBuffer->dsbflags&DSBCAPS_STATIC) &&
669 !prim->SupportedExt[SOFT_BUFFER_SUB_DATA] &&
670 !prim->SupportedExt[EXT_STATIC_BUFFER])
672 ALCint refresh = FAKE_REFRESH_COUNT;
673 ALuint newSize;
675 alcGetIntegerv(prim->parent->device, ALC_REFRESH, 1, &refresh);
676 checkALCError(prim->parent->device);
678 newSize = format->nAvgBytesPerSec/refresh + format->nBlockAlign - 1;
679 newSize -= newSize%format->nBlockAlign;
681 /* Make sure enough buffers are available */
682 if(newSize > pBuffer->buf_size/(QBUFFERS+2))
683 ERR("Buffer segments too large to stream (%u for %u)!\n",
684 newSize, pBuffer->buf_size);
685 else
687 pBuffer->numsegs = pBuffer->buf_size/newSize;
688 pBuffer->segsize = newSize;
689 pBuffer->lastsegsize = pBuffer->buf_size - (newSize*(pBuffer->numsegs-1));
690 TRACE("New streaming buffer (%u chunks, %u : %u sizes)\n",
691 pBuffer->numsegs, pBuffer->segsize, pBuffer->lastsegsize);
695 if(format->wFormatTag == WAVE_FORMAT_PCM)
696 fmt_str = get_fmtstr_PCM(prim, format, &pBuffer->format);
697 else if(format->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
698 fmt_str = get_fmtstr_FLOAT(prim, format, &pBuffer->format);
699 else if(format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
701 const WAVEFORMATEXTENSIBLE *wfe;
703 hr = DSERR_CONTROLUNAVAIL;
704 if(format->cbSize != sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) &&
705 format->cbSize != sizeof(WAVEFORMATEXTENSIBLE))
706 goto fail;
708 wfe = CONTAINING_RECORD(format, const WAVEFORMATEXTENSIBLE, Format);
709 TRACE("Extensible values:\n"
710 " Samples = %d\n"
711 " ChannelMask = 0x%"LONGFMT"x\n"
712 " SubFormat = %s\n",
713 wfe->Samples.wReserved, wfe->dwChannelMask,
714 debugstr_guid(&wfe->SubFormat));
716 fmt_str = get_fmtstr_EXT(prim, format, &pBuffer->format);
718 else
719 ERR("Unhandled formattag 0x%04x\n", format->wFormatTag);
721 hr = DSERR_INVALIDCALL;
722 if(!fmt_str)
723 goto fail;
725 pBuffer->buf_format = alGetEnumValue(fmt_str);
726 if(alGetError() != AL_NO_ERROR || pBuffer->buf_format == 0 ||
727 pBuffer->buf_format == -1)
729 WARN("Could not get OpenAL format from %s\n", fmt_str);
730 goto fail;
733 else
735 if(format->wFormatTag == WAVE_FORMAT_PCM)
736 pBuffer->buf_format = get_fmt_PCM(format, &pBuffer->format, &pBuffer->in_chans, &pBuffer->in_type);
737 else if(format->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
738 pBuffer->buf_format = get_fmt_FLOAT(format, &pBuffer->format, &pBuffer->in_chans, &pBuffer->in_type);
739 else if(format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
741 const WAVEFORMATEXTENSIBLE *wfe;
743 hr = DSERR_CONTROLUNAVAIL;
744 if(format->cbSize != sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) &&
745 format->cbSize != sizeof(WAVEFORMATEXTENSIBLE))
746 goto fail;
748 wfe = CONTAINING_RECORD(format, const WAVEFORMATEXTENSIBLE, Format);
749 TRACE("Extensible values:\n"
750 " Samples = %d\n"
751 " ChannelMask = 0x%"LONGFMT"x\n"
752 " SubFormat = %s\n",
753 wfe->Samples.wReserved, wfe->dwChannelMask,
754 debugstr_guid(&wfe->SubFormat));
756 pBuffer->buf_format = get_fmt_EXT(format, &pBuffer->format, &pBuffer->in_chans, &pBuffer->in_type);
758 else
759 ERR("Unhandled formattag 0x%04x\n", format->wFormatTag);
761 hr = DSERR_INVALIDCALL;
762 if(prim->ExtAL->IsBufferFormatSupportedSOFT(pBuffer->buf_format) == AL_FALSE)
764 WARN("Unsupported OpenAL format: 0x%x\n", pBuffer->buf_format);
765 goto fail;
769 hr = E_OUTOFMEMORY;
770 pBuffer->buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pBuffer->buffers)*pBuffer->numsegs);
771 pBuffer->data = HeapAlloc(GetProcessHeap(), 0, pBuffer->buf_size);
772 if(!pBuffer->buffers || !pBuffer->data)
773 goto fail;
775 alGenBuffers(pBuffer->numsegs, pBuffer->buffers);
776 checkALError();
778 *ppv = pBuffer;
779 return S_OK;
781 fail:
782 DS8Data_Release(pBuffer);
783 return hr;
786 static void DS8Data_AddRef(DS8Data *data)
788 InterlockedIncrement(&data->ref);
791 /* This function is always called with the device lock held */
792 static void DS8Data_Release(DS8Data *This)
794 if(InterlockedDecrement(&This->ref)) return;
796 TRACE("Deleting %p\n", This);
797 if (This->buffers && This->buffers[0])
799 alDeleteBuffers(This->numsegs, This->buffers);
800 checkALError();
802 HeapFree(GetProcessHeap(), 0, This->buffers);
803 HeapFree(GetProcessHeap(), 0, This->data);
804 HeapFree(GetProcessHeap(), 0, This);
807 HRESULT DS8Buffer_Create(DS8Buffer **ppv, DS8Primary *prim, IDirectSoundBuffer *orig)
809 DS8Buffer *This;
810 HRESULT hr;
812 *ppv = NULL;
813 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
814 if(!This) return DSERR_OUTOFMEMORY;
816 This->IDirectSoundBuffer8_iface.lpVtbl = (IDirectSoundBuffer8Vtbl*)&DS8Buffer_Vtbl;
817 This->IDirectSoundBuffer_iface.lpVtbl = (IDirectSoundBufferVtbl*)&DSBuffer_Vtbl;
818 This->IDirectSound3DBuffer_iface.lpVtbl = (IDirectSound3DBufferVtbl*)&DS8Buffer3d_Vtbl;
819 This->IDirectSoundNotify_iface.lpVtbl = (IDirectSoundNotifyVtbl*)&DS8BufferNot_Vtbl;
820 This->IKsPropertySet_iface.lpVtbl = (IKsPropertySetVtbl*)&DS8BufferProp_Vtbl;
822 This->primary = prim;
823 This->ctx = prim->ctx;
824 This->ExtAL = prim->ExtAL;
825 This->crst = prim->crst;
826 This->ref = This->all_ref = 1;
828 if(orig)
830 DS8Buffer *org = impl_from_IDirectSoundBuffer(orig);
831 hr = DSERR_BUFFERLOST;
832 if(org->bufferlost)
833 goto fail;
834 DS8Data_AddRef(org->buffer);
835 This->buffer = org->buffer;
838 /* Append to buffer list */
839 if(prim->nbuffers == prim->sizebuffers)
841 void *bufs;
843 hr = DSERR_OUTOFMEMORY;
844 bufs = HeapReAlloc(GetProcessHeap(), 0, prim->buffers, sizeof(*bufs)*(prim->nbuffers+1));
845 if(!bufs) goto fail;
847 prim->buffers = bufs;
848 prim->sizebuffers++;
850 prim->buffers[prim->nbuffers++] = This;
852 /* Disable until initialized.. */
853 This->ds3dmode = DS3DMODE_DISABLE;
855 *ppv = This;
856 return DS_OK;
858 fail:
859 DS8Buffer_Destroy(This);
860 return hr;
863 void DS8Buffer_Destroy(DS8Buffer *This)
865 DS8Primary *prim = This->primary;
866 DWORD idx;
868 TRACE("Destroying %p\n", This);
870 EnterCriticalSection(prim->crst);
871 /* Remove from list, if in list */
872 for(idx = 0;idx < prim->nnotifies;++idx)
874 if(This == prim->notifies[idx])
876 prim->notifies[idx] = prim->notifies[--prim->nnotifies];
877 break;
880 for(idx = 0;idx < prim->nbuffers;++idx)
882 if(prim->buffers[idx] == This)
884 prim->buffers[idx] = prim->buffers[--prim->nbuffers];
885 break;
889 setALContext(This->ctx);
890 if(This->source)
892 alSourceStop(This->source);
893 alSourcei(This->source, AL_BUFFER, 0);
894 checkALError();
896 prim->sources[prim->parent->share->nsources++] = This->source;
897 This->source = 0;
899 LeaveCriticalSection(prim->crst);
901 if(This->buffer)
902 DS8Data_Release(This->buffer);
904 popALContext();
906 HeapFree(GetProcessHeap(), 0, This->notify);
907 HeapFree(GetProcessHeap(), 0, This);
911 static HRESULT WINAPI DS8Buffer_QueryInterface(IDirectSoundBuffer8 *iface, REFIID riid, void **ppv)
913 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
915 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
917 *ppv = NULL;
918 if(IsEqualIID(riid, &IID_IUnknown))
919 *ppv = &This->IDirectSoundBuffer8_iface;
920 else if(IsEqualIID(riid, &IID_IDirectSoundBuffer))
921 *ppv = &This->IDirectSoundBuffer_iface;
922 else if(IsEqualIID(riid, &IID_IDirectSoundBuffer8))
924 if(This->primary->parent->is_8)
925 *ppv = &This->IDirectSoundBuffer8_iface;
927 else if(IsEqualIID(riid, &IID_IDirectSound3DBuffer))
929 if((This->buffer->dsbflags&DSBCAPS_CTRL3D))
930 *ppv = &This->IDirectSound3DBuffer_iface;
932 else if(IsEqualIID(riid, &IID_IDirectSoundNotify))
934 if((This->buffer->dsbflags&DSBCAPS_CTRLPOSITIONNOTIFY))
935 *ppv = &This->IDirectSoundNotify_iface;
937 else if(IsEqualIID(riid, &IID_IKsPropertySet))
938 *ppv = &This->IKsPropertySet_iface;
939 else
940 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
942 if(*ppv)
944 IUnknown_AddRef((IUnknown*)*ppv);
945 return S_OK;
948 return E_NOINTERFACE;
951 static ULONG WINAPI DS8Buffer_AddRef(IDirectSoundBuffer8 *iface)
953 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
954 LONG ret;
956 InterlockedIncrement(&This->all_ref);
957 ret = InterlockedIncrement(&This->ref);
958 TRACE("new refcount %"LONGFMT"d\n", ret);
960 return ret;
963 static ULONG WINAPI DS8Buffer_Release(IDirectSoundBuffer8 *iface)
965 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
966 LONG ret;
968 ret = InterlockedDecrement(&This->ref);
969 TRACE("new refcount %"LONGFMT"d\n", ret);
970 if(InterlockedDecrement(&This->all_ref) == 0)
971 DS8Buffer_Destroy(This);
973 return ret;
976 static HRESULT WINAPI DS8Buffer_GetCaps(IDirectSoundBuffer8 *iface, DSBCAPS *caps)
978 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
980 TRACE("(%p)->(%p)\n", iface, caps);
982 if(!caps || caps->dwSize < sizeof(*caps))
984 WARN("Invalid DSBCAPS (%p, %"LONGFMT"u)\n", caps, (caps ? caps->dwSize : 0));
985 return DSERR_INVALIDPARAM;
988 caps->dwFlags = This->buffer->dsbflags;
989 caps->dwBufferBytes = This->buffer->buf_size;
990 caps->dwUnlockTransferRate = 4096;
991 caps->dwPlayCpuOverhead = 0;
992 return S_OK;
995 static HRESULT WINAPI DS8Buffer_GetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD *playpos, DWORD *curpos)
997 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
998 UINT writecursor, pos;
1000 TRACE("(%p)->(%p, %p)\n", iface, playpos, curpos);
1002 if(This->buffer->numsegs > 1)
1004 ALint queued = QBUFFERS;
1006 EnterCriticalSection(This->crst);
1008 setALContext(This->ctx);
1009 alGetSourcei(This->source, AL_BUFFERS_QUEUED, &queued);
1010 checkALError();
1011 popALContext();
1013 pos = (This->curidx+This->buffer->numsegs-queued)%This->buffer->numsegs;
1014 pos *= This->buffer->segsize;
1015 writecursor = This->curidx * This->buffer->segsize;
1017 LeaveCriticalSection(This->crst);
1019 else if(This->primary->SupportedExt[SOFT_BUFFER_SUB_DATA] ||
1020 This->primary->SupportedExt[SOFT_BUFFER_SAMPLES])
1022 ALint rwpos[2] = { 0, 0 };
1024 setALContext(This->ctx);
1025 alGetSourceiv(This->source, AL_BYTE_RW_OFFSETS_SOFT, rwpos);
1026 checkALError();
1027 popALContext();
1029 pos = rwpos[0];
1030 writecursor = rwpos[1];
1032 else
1034 const WAVEFORMATEX *format = &This->buffer->format.Format;
1035 ALint status = 0;
1036 ALint ofs = 0;
1038 setALContext(This->ctx);
1039 alGetSourcei(This->source, AL_BYTE_OFFSET, &ofs);
1040 alGetSourcei(This->source, AL_SOURCE_STATE, &status);
1041 checkALError();
1042 popALContext();
1044 pos = ofs;
1045 if(status == AL_PLAYING)
1047 writecursor = format->nSamplesPerSec / 100;
1048 writecursor *= format->nBlockAlign;
1050 else
1051 writecursor = 0;
1052 writecursor = (writecursor + pos) % This->buffer->buf_size;
1054 TRACE("%p Play pos = %u, write pos = %u\n", This, pos, writecursor);
1056 if(pos >= This->buffer->buf_size)
1058 ERR("playpos >= buf_size\n");
1059 pos %= This->buffer->buf_size;
1061 if(writecursor >= This->buffer->buf_size)
1063 ERR("writepos >= buf_size\n");
1064 writecursor %= This->buffer->buf_size;
1067 if(playpos) *playpos = pos;
1068 if(curpos) *curpos = writecursor;
1070 return S_OK;
1073 static HRESULT WINAPI DS8Buffer_GetFormat(IDirectSoundBuffer8 *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
1075 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1076 HRESULT hr = S_OK;
1077 UINT size;
1079 TRACE("(%p)->(%p, %"LONGFMT"u, %p)\n", iface, wfx, allocated, written);
1081 if(!wfx && !written)
1083 WARN("Cannot report format or format size\n");
1084 return DSERR_INVALIDPARAM;
1087 size = sizeof(This->buffer->format.Format) + This->buffer->format.Format.cbSize;
1088 if(wfx)
1090 if(allocated < size)
1091 hr = DSERR_INVALIDPARAM;
1092 else
1093 memcpy(wfx, &This->buffer->format.Format, size);
1095 if(written)
1096 *written = size;
1098 return hr;
1101 static HRESULT WINAPI DS8Buffer_GetVolume(IDirectSoundBuffer8 *iface, LONG *vol)
1103 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1104 HRESULT hr;
1106 TRACE("(%p)->(%p)\n", iface, vol);
1108 if(!vol)
1110 WARN("Invalid pointer\n");
1111 return DSERR_INVALIDPARAM;
1114 hr = DSERR_CONTROLUNAVAIL;
1115 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
1116 WARN("Volume control not set\n");
1117 else
1119 ALfloat gain = 1.0f;
1121 setALContext(This->ctx);
1122 alGetSourcef(This->source, AL_GAIN, &gain);
1123 checkALError();
1124 popALContext();
1126 *vol = clampI(gain_to_mB(gain), DSBVOLUME_MIN, DSBVOLUME_MAX);
1127 hr = DS_OK;
1130 return hr;
1133 static HRESULT WINAPI DS8Buffer_GetPan(IDirectSoundBuffer8 *iface, LONG *pan)
1135 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1136 HRESULT hr;
1138 TRACE("(%p)->(%p)\n", iface, pan);
1140 if(!pan)
1142 WARN("Invalid pointer\n");
1143 return DSERR_INVALIDPARAM;
1146 hr = DSERR_CONTROLUNAVAIL;
1147 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
1148 WARN("Panning control not set\n");
1149 else
1151 ALfloat pos[3];
1153 setALContext(This->ctx);
1154 alGetSourcefv(This->source, AL_POSITION, pos);
1155 checkALError();
1156 popALContext();
1158 *pan = clampI(((pos[0]+1.0) * (DSBPAN_RIGHT-DSBPAN_LEFT) / 2.0 + 0.5) + DSBPAN_LEFT, DSBPAN_LEFT, DSBPAN_RIGHT);
1159 hr = DS_OK;
1162 return hr;
1165 static HRESULT WINAPI DS8Buffer_GetFrequency(IDirectSoundBuffer8 *iface, DWORD *freq)
1167 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1168 HRESULT hr;
1170 TRACE("(%p)->(%p)\n", iface, freq);
1172 if(!freq)
1174 WARN("Invalid pointer\n");
1175 return DSERR_INVALIDPARAM;
1178 hr = DSERR_CONTROLUNAVAIL;
1179 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
1180 WARN("Frequency control not set\n");
1181 else
1183 ALfloat pitch = 1.0f;
1185 setALContext(This->ctx);
1186 alGetSourcefv(This->source, AL_PITCH, &pitch);
1187 checkALError();
1188 popALContext();
1190 *freq = (DWORD)(This->buffer->format.Format.nSamplesPerSec * pitch);
1191 hr = DS_OK;
1194 return hr;
1197 static HRESULT WINAPI DS8Buffer_GetStatus(IDirectSoundBuffer8 *iface, DWORD *status)
1199 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1200 ALint state, looping;
1202 TRACE("(%p)->(%p)\n", iface, status);
1204 if(!status)
1206 WARN("Invalid pointer\n");
1207 return DSERR_INVALIDPARAM;
1209 *status = 0;
1211 if(This->buffer->numsegs == 1)
1213 setALContext(This->ctx);
1214 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1215 alGetSourcei(This->source, AL_LOOPING, &looping);
1216 checkALError();
1217 popALContext();
1219 else
1221 EnterCriticalSection(This->crst);
1223 setALContext(This->ctx);
1224 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1225 checkALError();
1226 popALContext();
1228 if(state != AL_PLAYING)
1229 state = This->isplaying ? AL_PLAYING : AL_PAUSED;
1230 looping = This->islooping;
1232 LeaveCriticalSection(This->crst);
1235 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1237 if((This->buffer->dsbflags&DSBCAPS_LOCSOFTWARE))
1238 *status |= DSBSTATUS_LOCSOFTWARE;
1239 else if((This->buffer->dsbflags&DSBCAPS_LOCHARDWARE))
1240 *status |= DSBSTATUS_LOCHARDWARE;
1242 if(state == AL_PLAYING)
1243 *status |= DSBSTATUS_PLAYING | (looping ? DSBSTATUS_LOOPING : 0);
1245 TRACE("%p status = 0x%08"LONGFMT"x\n", This, *status);
1246 return S_OK;
1249 static HRESULT WINAPI DS8Buffer_Initialize(IDirectSoundBuffer8 *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
1251 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1252 DS3DBUFFER *ds3dbuffer;
1253 HRESULT hr;
1255 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
1257 EnterCriticalSection(This->crst);
1258 setALContext(This->ctx);
1260 hr = DSERR_ALREADYINITIALIZED;
1261 if(This->source)
1262 goto out;
1264 if(!This->buffer)
1266 hr = DSERR_INVALIDPARAM;
1267 if(!desc)
1269 WARN("Missing DSound buffer description\n");
1270 goto out;
1272 if(!desc->lpwfxFormat)
1274 WARN("Missing buffer format (%p)\n", This);
1275 goto out;
1277 if((desc->dwFlags&DSBCAPS_CTRL3D) && desc->lpwfxFormat->nChannels != 1)
1279 if(This->primary->parent->is_8)
1281 /* DirectSoundBuffer8 objects aren't allowed non-mono 3D
1282 * buffers */
1283 WARN("Can't create multi-channel 3D buffers\n");
1284 goto out;
1286 ERR("Multi-channel 3D sounds are not spatialized\n");
1289 hr = DS8Data_Create(&This->buffer, desc, This->primary);
1290 if(FAILED(hr))
1291 goto out;
1292 else
1294 DS8Data *buf = This->buffer;
1296 if(buf->format.Format.wBitsPerSample == 8)
1297 memset(buf->data, 0x80, buf->buf_size);
1298 else
1299 memset(buf->data, 0x00, buf->buf_size);
1301 if(This->primary->SupportedExt[EXT_STATIC_BUFFER])
1302 This->ExtAL->BufferDataStatic(buf->buffers[0], buf->buf_format,
1303 buf->data, buf->buf_size,
1304 buf->format.Format.nSamplesPerSec);
1305 else if(This->primary->SupportedExt[SOFT_BUFFER_SAMPLES])
1306 This->ExtAL->BufferSamplesSOFT(buf->buffers[0],
1307 buf->format.Format.nSamplesPerSec, buf->buf_format,
1308 buf->buf_size/buf->format.Format.nBlockAlign,
1309 buf->in_chans, buf->in_type, buf->data);
1310 else if(This->primary->SupportedExt[SOFT_BUFFER_SUB_DATA])
1311 alBufferData(buf->buffers[0], buf->buf_format,
1312 buf->data, buf->buf_size,
1313 buf->format.Format.nSamplesPerSec);
1315 checkALError();
1318 hr = DSERR_GENERIC;
1319 if(This->primary->parent->share->nsources)
1321 This->source = This->primary->sources[--(This->primary->parent->share->nsources)];
1322 alSourcef(This->source, AL_GAIN, 1.0f);
1323 alSourcef(This->source, AL_PITCH, 1.0f);
1324 checkALError();
1326 else
1327 goto out;
1329 ds3dbuffer = &This->params;
1330 ds3dbuffer->dwSize = sizeof(This->params);
1331 ds3dbuffer->vPosition.x = 0.0;
1332 ds3dbuffer->vPosition.y = 0.0;
1333 ds3dbuffer->vPosition.z = 0.0;
1334 ds3dbuffer->vVelocity.x = 0.0;
1335 ds3dbuffer->vVelocity.y = 0.0;
1336 ds3dbuffer->vVelocity.z = 0.0;
1337 ds3dbuffer->dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
1338 ds3dbuffer->dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
1339 ds3dbuffer->vConeOrientation.x = 0.0;
1340 ds3dbuffer->vConeOrientation.y = 0.0;
1341 ds3dbuffer->vConeOrientation.z = 1.0;
1342 ds3dbuffer->lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
1343 ds3dbuffer->flMinDistance = DS3D_DEFAULTMINDISTANCE;
1344 ds3dbuffer->flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
1345 ds3dbuffer->dwMode = DS3DMODE_NORMAL;
1347 if((This->buffer->dsbflags&DSBCAPS_CTRL3D))
1349 if(This->primary->auxslot != 0)
1351 alSource3i(This->source, AL_AUXILIARY_SEND_FILTER, This->primary->auxslot, 0, AL_FILTER_NULL);
1352 checkALError();
1355 hr = IDirectSound3DBuffer_SetAllParameters(&This->IDirectSound3DBuffer_iface, ds3dbuffer, DS3D_IMMEDIATE);
1356 if(FAILED(hr))
1358 ERR("SetAllParameters failed\n");
1359 goto out;
1362 else
1364 ALuint source = This->source;
1366 if(This->primary->auxslot != 0)
1368 /* Simple hack to make reverb affect non-3D sounds too */
1369 alSource3i(source, AL_AUXILIARY_SEND_FILTER, This->primary->auxslot, 0, AL_FILTER_NULL);
1370 /*alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL);*/
1373 /* Non-3D sources aren't distance attenuated */
1374 This->ds3dmode = DS3DMODE_DISABLE;
1375 alSource3f(source, AL_POSITION, 0.0f, 1.0f, 0.0f);
1376 alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
1377 alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
1378 alSourcef(source, AL_CONE_OUTER_GAIN, 1.0f);
1379 alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f);
1380 alSourcef(source, AL_MAX_DISTANCE, 1000.0f);
1381 alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f);
1382 alSourcei(source, AL_CONE_INNER_ANGLE, 360);
1383 alSourcei(source, AL_CONE_OUTER_ANGLE, 360);
1384 alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);
1385 checkALError();
1387 hr = S_OK;
1389 out:
1390 popALContext();
1391 LeaveCriticalSection(This->crst);
1393 return hr;
1396 static HRESULT WINAPI DS8Buffer_Lock(IDirectSoundBuffer8 *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
1398 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1399 DWORD remain;
1401 TRACE("(%p)->(%"LONGFMT"u, %"LONGFMT"u, %p, %p, %p, %p, 0x%"LONGFMT"x)\n", This, ofs, bytes, ptr1, len1, ptr2, len2, flags);
1403 if(!ptr1 || !len1)
1405 WARN("Invalid pointer/len %p %p\n", ptr1, len1);
1406 return DSERR_INVALIDPARAM;
1409 *ptr1 = NULL;
1410 *len1 = 0;
1411 if(ptr2) *ptr2 = NULL;
1412 if(len2) *len2 = 0;
1414 if((flags&DSBLOCK_FROMWRITECURSOR))
1415 DS8Buffer_GetCurrentPosition(iface, NULL, &ofs);
1416 else if(ofs >= This->buffer->buf_size)
1418 WARN("Invalid ofs %"LONGFMT"u\n", ofs);
1419 return DSERR_INVALIDPARAM;
1421 if((flags&DSBLOCK_ENTIREBUFFER))
1422 bytes = This->buffer->buf_size;
1423 else if(bytes > This->buffer->buf_size)
1425 WARN("Invalid size %"LONGFMT"u\n", bytes);
1426 return DSERR_INVALIDPARAM;
1429 if(InterlockedExchange(&This->buffer->locked, TRUE) == TRUE)
1431 WARN("Already locked\n");
1432 return DSERR_INVALIDPARAM;
1435 *ptr1 = This->buffer->data + ofs;
1436 if(ofs+bytes >= This->buffer->buf_size)
1438 *len1 = This->buffer->buf_size - ofs;
1439 remain = bytes - *len1;
1441 else
1443 *len1 = bytes;
1444 remain = 0;
1447 if(ptr2 && len2 && remain)
1449 *ptr2 = This->buffer->data;
1450 *len2 = remain;
1453 return DS_OK;
1456 static HRESULT WINAPI DS8Buffer_Play(IDirectSoundBuffer8 *iface, DWORD res1, DWORD prio, DWORD flags)
1458 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1459 ALint type, state = AL_STOPPED;
1460 HRESULT hr;
1462 TRACE("(%p)->(%"LONGFMT"u, %"LONGFMT"u, %"LONGFMT"u)\n", iface, res1, prio, flags);
1464 EnterCriticalSection(This->crst);
1465 setALContext(This->ctx);
1467 hr = DSERR_BUFFERLOST;
1468 if(This->bufferlost)
1470 WARN("Buffer %p lost\n", This);
1471 goto out;
1474 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1476 if(!(This->buffer->dsbflags&(DSBCAPS_LOCHARDWARE|DSBCAPS_LOCSOFTWARE)))
1478 if(flags & DSBPLAY_LOCSOFTWARE)
1479 This->buffer->dsbflags |= DSBCAPS_LOCSOFTWARE;
1480 else
1481 This->buffer->dsbflags |= DSBCAPS_LOCHARDWARE;
1484 else if(prio)
1486 ERR("Invalid priority set for non-deferred buffer %p, %"LONGFMT"u!\n", This->buffer, prio);
1487 hr = DSERR_INVALIDPARAM;
1488 goto out;
1491 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1492 if(This->buffer->numsegs > 1)
1494 This->islooping = !!(flags&DSBPLAY_LOOPING);
1495 if(state != AL_PLAYING && This->isplaying)
1496 state = AL_PLAYING;
1498 else
1500 alGetSourcei(This->source, AL_SOURCE_TYPE, &type);
1501 alSourcei(This->source, AL_LOOPING, (flags&DSBPLAY_LOOPING) ? AL_TRUE : AL_FALSE);
1503 checkALError();
1505 hr = S_OK;
1506 if(state == AL_PLAYING)
1507 goto out;
1509 /* alSourceQueueBuffers will implicitly set type to streaming */
1510 if(This->buffer->numsegs == 1)
1512 if(type != AL_STATIC)
1513 alSourcei(This->source, AL_BUFFER, This->buffer->buffers[0]);
1514 alSourcePlay(This->source);
1516 if(alGetError() != AL_NO_ERROR)
1518 ERR("Couldn't start source\n");
1519 This->curidx = (This->buffer->numsegs-1+This->curidx)%This->buffer->numsegs;
1520 alSourcei(This->source, AL_BUFFER, 0);
1521 checkALError();
1522 hr = DSERR_GENERIC;
1523 goto out;
1525 This->isplaying = TRUE;
1527 if(This->nnotify)
1529 DS8Buffer_addnotify(This);
1530 DS8Primary_starttimer(This->primary);
1532 else if(This->buffer->numsegs > 1)
1533 DS8Primary_starttimer(This->primary);
1535 out:
1536 popALContext();
1537 LeaveCriticalSection(This->crst);
1538 return hr;
1541 static HRESULT WINAPI DS8Buffer_SetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD pos)
1543 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1545 TRACE("(%p)->(%"LONGFMT"u)\n", iface, pos);
1547 if(pos >= This->buffer->buf_size)
1548 return DSERR_INVALIDPARAM;
1550 EnterCriticalSection(This->crst);
1552 if(This->buffer->numsegs > 1)
1554 DS8Data *buf = This->buffer;
1555 This->curidx = pos/buf->segsize;
1556 if(This->curidx >= buf->numsegs)
1557 This->curidx = buf->numsegs - 1;
1558 if(This->isplaying)
1560 setALContext(This->ctx);
1561 /* Perform a flush, so the next timer update will restart at the
1562 * proper position */
1563 alSourceStop(This->source);
1564 alSourcei(This->source, AL_BUFFER, 0);
1565 checkALError();
1566 popALContext();
1569 else
1571 setALContext(This->ctx);
1572 alSourcei(This->source, AL_BYTE_OFFSET, pos);
1573 popALContext();
1575 This->lastpos = pos;
1577 LeaveCriticalSection(This->crst);
1578 return DS_OK;
1581 static HRESULT WINAPI DS8Buffer_SetFormat(IDirectSoundBuffer8 *iface, const WAVEFORMATEX *wfx)
1583 /* This call only works on primary buffers */
1584 WARN("(%p)->(%p)\n", iface, wfx);
1585 return DSERR_INVALIDCALL;
1588 static HRESULT WINAPI DS8Buffer_SetVolume(IDirectSoundBuffer8 *iface, LONG vol)
1590 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1591 HRESULT hr = S_OK;
1593 TRACE("(%p)->(%"LONGFMT"d)\n", iface, vol);
1595 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
1597 WARN("Invalid volume (%"LONGFMT"d)\n", vol);
1598 return DSERR_INVALIDPARAM;
1601 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
1602 hr = DSERR_CONTROLUNAVAIL;
1603 if(SUCCEEDED(hr))
1605 ALfloat fvol = mB_to_gain(vol);
1606 setALContext(This->ctx);
1607 alSourcef(This->source, AL_GAIN, fvol);
1608 popALContext();
1611 return hr;
1614 static HRESULT WINAPI DS8Buffer_SetPan(IDirectSoundBuffer8 *iface, LONG pan)
1616 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1617 HRESULT hr = S_OK;
1619 TRACE("(%p)->(%"LONGFMT"d)\n", iface, pan);
1621 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
1623 WARN("invalid parameter: pan = %"LONGFMT"d\n", pan);
1624 return DSERR_INVALIDPARAM;
1627 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
1628 hr = DSERR_CONTROLUNAVAIL;
1629 else
1631 ALfloat pos[3];
1632 pos[0] = (pan-DSBPAN_LEFT) * 2.0 / (ALfloat)(DSBPAN_RIGHT-DSBPAN_LEFT) - 1.0;
1633 /* NOTE: Strict movement along the X plane can cause the sound to jump
1634 * between left and right sharply. Using a curved path helps smooth it
1635 * out */
1636 pos[1] = sqrt(1.0 - pos[0]*pos[0]);
1637 pos[2] = 0.0;
1639 setALContext(This->ctx);
1640 alSourcefv(This->source, AL_POSITION, pos);
1641 checkALError();
1642 popALContext();
1644 if(pan != 0 && This->buffer->format.Format.nChannels > 1)
1645 FIXME("Panning for multi-channel buffers is not supported\n");
1648 return hr;
1651 static HRESULT WINAPI DS8Buffer_SetFrequency(IDirectSoundBuffer8 *iface, DWORD freq)
1653 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1654 HRESULT hr = S_OK;
1656 TRACE("(%p)->(%"LONGFMT"u)\n", iface, freq);
1658 if(freq < DSBFREQUENCY_MIN || freq > DSBFREQUENCY_MAX)
1660 WARN("invalid parameter: freq = %"LONGFMT"u\n", freq);
1661 return DSERR_INVALIDPARAM;
1664 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
1665 hr = DSERR_CONTROLUNAVAIL;
1666 else
1668 ALfloat pitch = 1.0f;
1669 if(freq != DSBFREQUENCY_ORIGINAL)
1670 pitch = freq / (ALfloat)This->buffer->format.Format.nSamplesPerSec;
1672 setALContext(This->ctx);
1673 alSourcef(This->source, AL_PITCH, pitch);
1674 checkALError();
1675 popALContext();
1678 return hr;
1681 static HRESULT WINAPI DS8Buffer_Stop(IDirectSoundBuffer8 *iface)
1683 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1684 ALint state;
1686 TRACE("(%p)->()\n", iface);
1688 EnterCriticalSection(This->crst);
1689 setALContext(This->ctx);
1691 alSourcePause(This->source);
1692 checkALError();
1693 /* Mac OS X doesn't immediately report state change
1694 * if Play() is immediately called after Stop, this can be fatal,
1695 * the buffer would never be restarted
1697 do {
1698 state = AL_PAUSED;
1699 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1700 if(state != AL_PLAYING)
1701 break;
1702 Sleep(1);
1703 } while(1);
1705 This->isplaying = FALSE;
1707 popALContext();
1708 LeaveCriticalSection(This->crst);
1710 return S_OK;
1713 static HRESULT WINAPI DS8Buffer_Unlock(IDirectSoundBuffer8 *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
1715 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1716 DS8Data *buf = This->buffer;
1717 DWORD bufsize = buf->buf_size;
1718 DWORD_PTR ofs1, ofs2;
1719 DWORD_PTR boundary = (DWORD_PTR)buf->data;
1720 HRESULT hr;
1722 TRACE("(%p)->(%p, %"LONGFMT"u, %p, %"LONGFMT"u)\n", iface, ptr1, len1, ptr2, len2);
1724 if(InterlockedExchange(&This->buffer->locked, FALSE) == FALSE)
1726 WARN("Not locked\n");
1727 return DSERR_INVALIDPARAM;
1730 hr = DSERR_INVALIDPARAM;
1731 /* Make sure offset is between boundary and boundary + bufsize */
1732 ofs1 = (DWORD_PTR)ptr1;
1733 ofs2 = (DWORD_PTR)ptr2;
1734 if(ofs1 < boundary)
1735 goto out;
1736 if(ofs2 && ofs2 != boundary)
1737 goto out;
1738 ofs1 -= boundary;
1739 ofs2 = 0;
1740 if(bufsize-ofs1 < len1 || len2 > ofs1)
1741 goto out;
1742 if(!ptr2)
1743 len2 = 0;
1745 hr = DS_OK;
1746 if(!len1 && !len2)
1747 goto out;
1748 if(This->primary->SupportedExt[EXT_STATIC_BUFFER])
1749 goto out;
1751 setALContext(This->ctx);
1752 if(This->primary->SupportedExt[SOFT_BUFFER_SAMPLES])
1754 const WAVEFORMATEX *format = &buf->format.Format;
1756 ptr1 = (BYTE*)ptr1 - (ofs1%format->nBlockAlign);
1757 ofs1 /= format->nBlockAlign;
1758 len1 /= format->nBlockAlign;
1759 if(len1 > 0)
1760 This->ExtAL->BufferSubSamplesSOFT(buf->buffers[0], ofs1, len1,
1761 buf->in_chans, buf->in_type, ptr1);
1762 ptr2 = (BYTE*)ptr2 - (ofs2%format->nBlockAlign);
1763 ofs2 /= format->nBlockAlign;
1764 len2 /= format->nBlockAlign;
1765 if(len2 > 0)
1766 This->ExtAL->BufferSubSamplesSOFT(buf->buffers[0], ofs2, len2,
1767 buf->in_chans, buf->in_type, ptr2);
1768 checkALError();
1770 else if(This->primary->SupportedExt[SOFT_BUFFER_SUB_DATA])
1772 const WAVEFORMATEX *format = &buf->format.Format;
1774 len1 -= len1%format->nBlockAlign;
1775 if(len1 > 0)
1776 This->ExtAL->BufferSubData(buf->buffers[0], buf->buf_format, ptr1,
1777 ofs1, len1);
1778 len2 -= len2%format->nBlockAlign;
1779 if(len2 > 0)
1780 This->ExtAL->BufferSubData(buf->buffers[0], buf->buf_format, ptr2,
1781 ofs2, len2);
1782 checkALError();
1784 else
1786 alBufferData(buf->buffers[0], buf->buf_format,
1787 buf->data, buf->buf_size,
1788 buf->format.Format.nSamplesPerSec);
1789 checkALError();
1791 popALContext();
1793 out:
1794 if(hr != S_OK)
1795 WARN("Invalid parameters (0x%lx,%"LONGFMT"u) (%p,%"LONGFMT"u,%p,%"LONGFMT"u)\n", boundary, bufsize, ptr1, len1, ptr2, len2);
1796 return hr;
1799 static HRESULT WINAPI DS8Buffer_Restore(IDirectSoundBuffer8 *iface)
1801 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1802 HRESULT hr;
1804 TRACE("(%p)->()\n", iface);
1806 EnterCriticalSection(This->crst);
1807 if(This->primary->parent->prio_level < DSSCL_WRITEPRIMARY ||
1808 iface == This->primary->write_emu)
1810 This->bufferlost = 0;
1811 hr = S_OK;
1813 else
1814 hr = DSERR_BUFFERLOST;
1815 LeaveCriticalSection(This->crst);
1817 return hr;
1820 static HRESULT WINAPI DS8Buffer_SetFX(IDirectSoundBuffer8 *iface, DWORD fxcount, DSEFFECTDESC *desc, DWORD *rescodes)
1822 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1823 DWORD i;
1825 TRACE("(%p)->(%"LONGFMT"u, %p, %p)\n", This, fxcount, desc, rescodes);
1827 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFX))
1829 WARN("FX control not set\n");
1830 return DSERR_CONTROLUNAVAIL;
1833 if(fxcount == 0)
1835 if(desc || rescodes)
1837 WARN("Non-NULL desc and/or result pointer specified with no effects.\n");
1838 return DSERR_INVALIDPARAM;
1841 /* No effects; we can handle that */
1842 return DS_OK;
1845 if(!desc || !rescodes)
1847 WARN("NULL desc and/or result pointer specified.\n");
1848 return DSERR_INVALIDPARAM;
1851 /* We don't (currently) handle DSound effects */
1852 for(i = 0;i < fxcount;++i)
1854 FIXME("Cannot handle effect: %s\n", debugstr_guid(&desc[i].guidDSFXClass));
1855 rescodes[i] = DSFXR_FAILED;
1858 return DS_INCOMPLETE;
1861 static HRESULT WINAPI DS8Buffer_AcquireResources(IDirectSoundBuffer8 *iface, DWORD flags, DWORD fxcount, DWORD *rescodes)
1863 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1865 TRACE("(%p)->(%"LONGFMT"u, %"LONGFMT"u, %p)\n", This, flags, fxcount, rescodes);
1867 /* effects aren't supported at the moment.. */
1868 if(fxcount != 0 || rescodes)
1870 WARN("Non-zero effect count and/or result pointer specified with no effects.\n");
1871 return DSERR_INVALIDPARAM;
1874 EnterCriticalSection(This->crst);
1875 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1877 This->buffer->dsbflags &= ~(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE);
1878 if((flags&DSBPLAY_LOCSOFTWARE))
1879 This->buffer->dsbflags |= DSBCAPS_LOCSOFTWARE;
1880 else
1881 This->buffer->dsbflags |= DSBCAPS_LOCHARDWARE;
1883 LeaveCriticalSection(This->crst);
1885 return S_OK;
1888 static HRESULT WINAPI DS8Buffer_GetObjectInPath(IDirectSoundBuffer8 *iface, REFGUID guid, DWORD idx, REFGUID rguidiface, void **ppv)
1890 FIXME("(%p)->(%s, %"LONGFMT"u, %s, %p) : stub!\n", iface, debugstr_guid(guid), idx, debugstr_guid(rguidiface), ppv);
1891 return E_NOTIMPL;
1894 static const IDirectSoundBuffer8Vtbl DS8Buffer_Vtbl = {
1895 DS8Buffer_QueryInterface,
1896 DS8Buffer_AddRef,
1897 DS8Buffer_Release,
1898 DS8Buffer_GetCaps,
1899 DS8Buffer_GetCurrentPosition,
1900 DS8Buffer_GetFormat,
1901 DS8Buffer_GetVolume,
1902 DS8Buffer_GetPan,
1903 DS8Buffer_GetFrequency,
1904 DS8Buffer_GetStatus,
1905 DS8Buffer_Initialize,
1906 DS8Buffer_Lock,
1907 DS8Buffer_Play,
1908 DS8Buffer_SetCurrentPosition,
1909 DS8Buffer_SetFormat,
1910 DS8Buffer_SetVolume,
1911 DS8Buffer_SetPan,
1912 DS8Buffer_SetFrequency,
1913 DS8Buffer_Stop,
1914 DS8Buffer_Unlock,
1915 DS8Buffer_Restore,
1916 DS8Buffer_SetFX,
1917 DS8Buffer_AcquireResources,
1918 DS8Buffer_GetObjectInPath
1922 static HRESULT WINAPI DSBuffer_QueryInterface(IDirectSoundBuffer *iface, REFIID riid, void **ppv)
1924 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1925 return DS8Buffer_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
1928 static ULONG WINAPI DSBuffer_AddRef(IDirectSoundBuffer *iface)
1930 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1931 return DS8Buffer_AddRef(&This->IDirectSoundBuffer8_iface);
1934 static ULONG WINAPI DSBuffer_Release(IDirectSoundBuffer *iface)
1936 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1937 return DS8Buffer_Release(&This->IDirectSoundBuffer8_iface);
1940 static HRESULT WINAPI DSBuffer_GetCaps(IDirectSoundBuffer *iface, DSBCAPS *caps)
1942 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1943 return DS8Buffer_GetCaps(&This->IDirectSoundBuffer8_iface, caps);
1946 static HRESULT WINAPI DSBuffer_GetCurrentPosition(IDirectSoundBuffer *iface, DWORD *playpos, DWORD *curpos)
1948 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1949 return DS8Buffer_GetCurrentPosition(&This->IDirectSoundBuffer8_iface, playpos, curpos);
1952 static HRESULT WINAPI DSBuffer_GetFormat(IDirectSoundBuffer *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
1954 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1955 return DS8Buffer_GetFormat(&This->IDirectSoundBuffer8_iface, wfx, allocated, written);
1958 static HRESULT WINAPI DSBuffer_GetVolume(IDirectSoundBuffer *iface, LONG *vol)
1960 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1961 return DS8Buffer_GetVolume(&This->IDirectSoundBuffer8_iface, vol);
1964 static HRESULT WINAPI DSBuffer_GetPan(IDirectSoundBuffer *iface, LONG *pan)
1966 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1967 return DS8Buffer_GetPan(&This->IDirectSoundBuffer8_iface, pan);
1970 static HRESULT WINAPI DSBuffer_GetFrequency(IDirectSoundBuffer *iface, DWORD *freq)
1972 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1973 return DS8Buffer_GetFrequency(&This->IDirectSoundBuffer8_iface, freq);
1976 static HRESULT WINAPI DSBuffer_GetStatus(IDirectSoundBuffer *iface, DWORD *status)
1978 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1979 return DS8Buffer_GetStatus(&This->IDirectSoundBuffer8_iface, status);
1982 static HRESULT WINAPI DSBuffer_Initialize(IDirectSoundBuffer *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
1984 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1985 return DS8Buffer_Initialize(&This->IDirectSoundBuffer8_iface, ds, desc);
1988 static HRESULT WINAPI DSBuffer_Lock(IDirectSoundBuffer *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
1990 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1991 return DS8Buffer_Lock(&This->IDirectSoundBuffer8_iface, ofs, bytes, ptr1, len1, ptr2, len2, flags);
1994 static HRESULT WINAPI DSBuffer_Play(IDirectSoundBuffer *iface, DWORD res1, DWORD prio, DWORD flags)
1996 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1997 return DS8Buffer_Play(&This->IDirectSoundBuffer8_iface, res1, prio, flags);
2000 static HRESULT WINAPI DSBuffer_SetCurrentPosition(IDirectSoundBuffer *iface, DWORD pos)
2002 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
2003 return DS8Buffer_SetCurrentPosition(&This->IDirectSoundBuffer8_iface, pos);
2006 static HRESULT WINAPI DSBuffer_SetFormat(IDirectSoundBuffer *iface, const WAVEFORMATEX *wfx)
2008 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
2009 return DS8Buffer_SetFormat(&This->IDirectSoundBuffer8_iface, wfx);
2012 static HRESULT WINAPI DSBuffer_SetVolume(IDirectSoundBuffer *iface, LONG vol)
2014 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
2015 return DS8Buffer_SetVolume(&This->IDirectSoundBuffer8_iface, vol);
2018 static HRESULT WINAPI DSBuffer_SetPan(IDirectSoundBuffer *iface, LONG pan)
2020 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
2021 return DS8Buffer_SetPan(&This->IDirectSoundBuffer8_iface, pan);
2024 static HRESULT WINAPI DSBuffer_SetFrequency(IDirectSoundBuffer *iface, DWORD freq)
2026 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
2027 return DS8Buffer_SetFrequency(&This->IDirectSoundBuffer8_iface, freq);
2030 static HRESULT WINAPI DSBuffer_Stop(IDirectSoundBuffer *iface)
2032 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
2033 return DS8Buffer_Stop(&This->IDirectSoundBuffer8_iface);
2036 static HRESULT WINAPI DSBuffer_Unlock(IDirectSoundBuffer *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
2038 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
2039 return DS8Buffer_Unlock(&This->IDirectSoundBuffer8_iface, ptr1, len1, ptr2, len2);
2042 static HRESULT WINAPI DSBuffer_Restore(IDirectSoundBuffer *iface)
2044 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
2045 return DS8Buffer_Restore(&This->IDirectSoundBuffer8_iface);
2048 static const IDirectSoundBufferVtbl DSBuffer_Vtbl = {
2049 DSBuffer_QueryInterface,
2050 DSBuffer_AddRef,
2051 DSBuffer_Release,
2052 DSBuffer_GetCaps,
2053 DSBuffer_GetCurrentPosition,
2054 DSBuffer_GetFormat,
2055 DSBuffer_GetVolume,
2056 DSBuffer_GetPan,
2057 DSBuffer_GetFrequency,
2058 DSBuffer_GetStatus,
2059 DSBuffer_Initialize,
2060 DSBuffer_Lock,
2061 DSBuffer_Play,
2062 DSBuffer_SetCurrentPosition,
2063 DSBuffer_SetFormat,
2064 DSBuffer_SetVolume,
2065 DSBuffer_SetPan,
2066 DSBuffer_SetFrequency,
2067 DSBuffer_Stop,
2068 DSBuffer_Unlock,
2069 DSBuffer_Restore
2073 void DS8Buffer_SetParams(DS8Buffer *This, const DS3DBUFFER *params, LONG flags)
2075 const ALuint source = This->source;
2076 union BufferParamFlags dirty = { flags };
2078 if(dirty.bit.pos)
2079 alSource3f(source, AL_POSITION, params->vPosition.x, params->vPosition.y,
2080 -params->vPosition.z);
2081 if(dirty.bit.vel)
2082 alSource3f(source, AL_VELOCITY, params->vVelocity.x, params->vVelocity.y,
2083 -params->vVelocity.z);
2084 if(dirty.bit.cone_angles)
2086 alSourcei(source, AL_CONE_INNER_ANGLE, params->dwInsideConeAngle);
2087 alSourcei(source, AL_CONE_OUTER_ANGLE, params->dwOutsideConeAngle);
2089 if(dirty.bit.cone_orient)
2090 alSource3f(source, AL_DIRECTION, params->vConeOrientation.x,
2091 params->vConeOrientation.y,
2092 -params->vConeOrientation.z);
2093 if(dirty.bit.cone_outsidevolume)
2094 alSourcef(source, AL_CONE_OUTER_GAIN, mB_to_gain(params->lConeOutsideVolume));
2095 if(dirty.bit.min_distance)
2096 alSourcef(source, AL_REFERENCE_DISTANCE, params->flMinDistance);
2097 if(dirty.bit.max_distance)
2098 alSourcef(source, AL_MAX_DISTANCE, params->flMaxDistance);
2099 if(dirty.bit.mode)
2101 This->ds3dmode = params->dwMode;
2102 alSourcei(source, AL_SOURCE_RELATIVE, (params->dwMode!=DS3DMODE_NORMAL) ?
2103 AL_TRUE : AL_FALSE);
2104 alSourcef(source, AL_ROLLOFF_FACTOR, (params->dwMode==DS3DMODE_DISABLE) ?
2105 0.0f : This->primary->rollofffactor);
2109 static HRESULT WINAPI DS8Buffer3D_QueryInterface(IDirectSound3DBuffer *iface, REFIID riid, void **ppv)
2111 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2112 return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2115 static ULONG WINAPI DS8Buffer3D_AddRef(IDirectSound3DBuffer *iface)
2117 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2118 LONG ret;
2120 InterlockedIncrement(&This->all_ref);
2121 ret = InterlockedIncrement(&This->ds3d_ref);
2122 TRACE("new refcount %"LONGFMT"d\n", ret);
2124 return ret;
2127 static ULONG WINAPI DS8Buffer3D_Release(IDirectSound3DBuffer *iface)
2129 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2130 LONG ret;
2132 ret = InterlockedDecrement(&This->ds3d_ref);
2133 TRACE("new refcount %"LONGFMT"d\n", ret);
2134 if(InterlockedDecrement(&This->all_ref) == 0)
2135 DS8Buffer_Destroy(This);
2137 return ret;
2140 static HRESULT WINAPI DS8Buffer3D_GetAllParameters(IDirectSound3DBuffer *iface, DS3DBUFFER *ds3dbuffer)
2142 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2144 TRACE("(%p)->(%p)\n", iface, ds3dbuffer);
2146 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
2148 WARN("Invalid parameters %p %"LONGFMT"u\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
2149 return DSERR_INVALIDPARAM;
2152 EnterCriticalSection(This->crst);
2153 setALContext(This->ctx);
2155 IDirectSound3DBuffer_GetPosition(iface, &ds3dbuffer->vPosition);
2156 IDirectSound3DBuffer_GetVelocity(iface, &ds3dbuffer->vVelocity);
2157 IDirectSound3DBuffer_GetConeAngles(iface, &ds3dbuffer->dwInsideConeAngle, &ds3dbuffer->dwOutsideConeAngle);
2158 IDirectSound3DBuffer_GetConeOrientation(iface, &ds3dbuffer->vConeOrientation);
2159 IDirectSound3DBuffer_GetConeOutsideVolume(iface, &ds3dbuffer->lConeOutsideVolume);
2160 IDirectSound3DBuffer_GetMinDistance(iface, &ds3dbuffer->flMinDistance);
2161 IDirectSound3DBuffer_GetMaxDistance(iface, &ds3dbuffer->flMaxDistance);
2162 IDirectSound3DBuffer_GetMode(iface, &ds3dbuffer->dwMode);
2164 popALContext();
2165 LeaveCriticalSection(This->crst);
2167 return DS_OK;
2170 static HRESULT WINAPI DS8Buffer3D_GetConeAngles(IDirectSound3DBuffer *iface, DWORD *pdwInsideConeAngle, DWORD *pdwOutsideConeAngle)
2172 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2173 ALint inangle, outangle;
2175 TRACE("(%p)->(%p, %p)\n", This, pdwInsideConeAngle, pdwOutsideConeAngle);
2176 if(!pdwInsideConeAngle || !pdwOutsideConeAngle)
2178 WARN("Invalid pointers (%p, %p)\n", pdwInsideConeAngle, pdwOutsideConeAngle);
2179 return DSERR_INVALIDPARAM;
2182 EnterCriticalSection(This->crst);
2183 setALContext(This->ctx);
2185 alGetSourcei(This->source, AL_CONE_INNER_ANGLE, &inangle);
2186 alGetSourcei(This->source, AL_CONE_OUTER_ANGLE, &outangle);
2187 checkALError();
2189 popALContext();
2190 LeaveCriticalSection(This->crst);
2192 *pdwInsideConeAngle = inangle;
2193 *pdwOutsideConeAngle = outangle;
2194 return S_OK;
2197 static HRESULT WINAPI DS8Buffer3D_GetConeOrientation(IDirectSound3DBuffer *iface, D3DVECTOR *orient)
2199 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2200 ALfloat dir[3];
2202 TRACE("(%p)->(%p)\n", This, orient);
2203 if(!orient)
2205 WARN("Invalid pointer\n");
2206 return DSERR_INVALIDPARAM;
2209 setALContext(This->ctx);
2210 alGetSourcefv(This->source, AL_DIRECTION, dir);
2211 checkALError();
2212 popALContext();
2214 orient->x = dir[0];
2215 orient->y = dir[1];
2216 orient->z = -dir[2];
2217 return S_OK;
2220 static HRESULT WINAPI DS8Buffer3D_GetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG *vol)
2222 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2223 ALfloat gain;
2225 TRACE("(%p)->(%p)\n", This, vol);
2226 if(!vol)
2228 WARN("Invalid pointer\n");
2229 return DSERR_INVALIDPARAM;
2232 setALContext(This->ctx);
2233 alGetSourcef(This->source, AL_CONE_OUTER_GAIN, &gain);
2234 checkALError();
2235 popALContext();
2237 *vol = clampI(gain_to_mB(gain), DSBVOLUME_MIN, DSBVOLUME_MAX);
2238 return S_OK;
2241 static HRESULT WINAPI DS8Buffer3D_GetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE *maxdist)
2243 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2244 ALfloat dist;
2246 TRACE("(%p)->(%p)\n", This, maxdist);
2247 if(!maxdist)
2249 WARN("Invalid pointer\n");
2250 return DSERR_INVALIDPARAM;
2253 setALContext(This->ctx);
2254 alGetSourcef(This->source, AL_MAX_DISTANCE, &dist);
2255 checkALError();
2256 popALContext();
2258 *maxdist = dist;
2259 return S_OK;
2262 static HRESULT WINAPI DS8Buffer3D_GetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE *mindist)
2264 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2265 ALfloat dist;
2267 TRACE("(%p)->(%p)\n", This, mindist);
2268 if(!mindist)
2270 WARN("Invalid pointer\n");
2271 return DSERR_INVALIDPARAM;
2274 setALContext(This->ctx);
2275 alGetSourcef(This->source, AL_REFERENCE_DISTANCE, &dist);
2276 checkALError();
2277 popALContext();
2279 *mindist = dist;
2280 return S_OK;
2283 static HRESULT WINAPI DS8Buffer3D_GetMode(IDirectSound3DBuffer *iface, DWORD *mode)
2285 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2287 TRACE("(%p)->(%p)\n", This, mode);
2288 if(!mode)
2290 WARN("Invalid pointer\n");
2291 return DSERR_INVALIDPARAM;
2294 EnterCriticalSection(This->crst);
2295 *mode = This->ds3dmode;
2296 LeaveCriticalSection(This->crst);
2298 return S_OK;
2301 static HRESULT WINAPI DS8Buffer3D_GetPosition(IDirectSound3DBuffer *iface, D3DVECTOR *pos)
2303 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2304 ALfloat alpos[3];
2306 TRACE("(%p)->(%p)\n", This, pos);
2307 if(!pos)
2309 WARN("Invalid pointer\n");
2310 return DSERR_INVALIDPARAM;
2313 setALContext(This->ctx);
2314 alGetSourcefv(This->source, AL_POSITION, alpos);
2315 checkALError();
2316 popALContext();
2318 pos->x = alpos[0];
2319 pos->y = alpos[1];
2320 pos->z = -alpos[2];
2321 return S_OK;
2324 static HRESULT WINAPI DS8Buffer3D_GetVelocity(IDirectSound3DBuffer *iface, D3DVECTOR *vel)
2326 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2327 ALfloat alvel[3];
2329 TRACE("(%p)->(%p)\n", This, vel);
2330 if(!vel)
2332 WARN("Invalid pointer\n");
2333 return DSERR_INVALIDPARAM;
2336 setALContext(This->ctx);
2337 alGetSourcefv(This->source, AL_VELOCITY, alvel);
2338 checkALError();
2339 popALContext();
2341 vel->x = alvel[0];
2342 vel->y = alvel[1];
2343 vel->z = -alvel[2];
2344 return S_OK;
2347 static HRESULT WINAPI DS8Buffer3D_SetAllParameters(IDirectSound3DBuffer *iface, const DS3DBUFFER *ds3dbuffer, DWORD apply)
2349 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2350 TRACE("(%p)->(%p, %"LONGFMT"u)\n", This, ds3dbuffer, apply);
2352 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
2354 WARN("Invalid DS3DBUFFER (%p, %"LONGFMT"u)\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
2355 return DSERR_INVALIDPARAM;
2358 if(ds3dbuffer->dwInsideConeAngle > DS3D_MAXCONEANGLE ||
2359 ds3dbuffer->dwOutsideConeAngle > DS3D_MAXCONEANGLE)
2361 WARN("Invalid cone angles (%"LONGFMT"u, %"LONGFMT"u)\n",
2362 ds3dbuffer->dwInsideConeAngle, ds3dbuffer->dwOutsideConeAngle);
2363 return DSERR_INVALIDPARAM;
2366 if(ds3dbuffer->lConeOutsideVolume > DSBVOLUME_MAX ||
2367 ds3dbuffer->lConeOutsideVolume < DSBVOLUME_MIN)
2369 WARN("Invalid cone outside volume (%"LONGFMT"d)\n", ds3dbuffer->lConeOutsideVolume);
2370 return DSERR_INVALIDPARAM;
2373 if(ds3dbuffer->flMaxDistance < 0.0f)
2375 WARN("Invalid max distance (%f)\n", ds3dbuffer->flMaxDistance);
2376 return DSERR_INVALIDPARAM;
2379 if(ds3dbuffer->flMinDistance < 0.0f)
2381 WARN("Invalid min distance (%f)\n", ds3dbuffer->flMinDistance);
2382 return DSERR_INVALIDPARAM;
2385 if(ds3dbuffer->dwMode != DS3DMODE_NORMAL &&
2386 ds3dbuffer->dwMode != DS3DMODE_HEADRELATIVE &&
2387 ds3dbuffer->dwMode != DS3DMODE_DISABLE)
2389 WARN("Invalid mode (%"LONGFMT"u)\n", ds3dbuffer->dwMode);
2390 return DSERR_INVALIDPARAM;
2393 if(apply == DS3D_DEFERRED)
2395 EnterCriticalSection(This->crst);
2396 This->params = *ds3dbuffer;
2397 This->params.dwSize = sizeof(This->params);
2398 This->dirty.bit.pos = 1;
2399 This->dirty.bit.vel = 1;
2400 This->dirty.bit.cone_angles = 1;
2401 This->dirty.bit.cone_orient = 1;
2402 This->dirty.bit.cone_outsidevolume = 1;
2403 This->dirty.bit.min_distance = 1;
2404 This->dirty.bit.max_distance = 1;
2405 This->dirty.bit.mode = 1;
2406 LeaveCriticalSection(This->crst);
2408 else
2410 union BufferParamFlags dirty = { 0 };
2411 dirty.bit.pos = 1;
2412 dirty.bit.vel = 1;
2413 dirty.bit.cone_angles = 1;
2414 dirty.bit.cone_orient = 1;
2415 dirty.bit.cone_outsidevolume = 1;
2416 dirty.bit.min_distance = 1;
2417 dirty.bit.max_distance = 1;
2418 dirty.bit.mode = 1;
2420 EnterCriticalSection(This->crst);
2421 setALContext(This->ctx);
2422 DS8Buffer_SetParams(This, ds3dbuffer, dirty.flags);
2423 checkALError();
2424 popALContext();
2425 LeaveCriticalSection(This->crst);
2428 return S_OK;
2431 static HRESULT WINAPI DS8Buffer3D_SetConeAngles(IDirectSound3DBuffer *iface, DWORD dwInsideConeAngle, DWORD dwOutsideConeAngle, DWORD apply)
2433 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2435 TRACE("(%p)->(%"LONGFMT"u, %"LONGFMT"u, %"LONGFMT"u)\n", This, dwInsideConeAngle, dwOutsideConeAngle, apply);
2436 if(dwInsideConeAngle > DS3D_MAXCONEANGLE ||
2437 dwOutsideConeAngle > DS3D_MAXCONEANGLE)
2439 WARN("Invalid cone angles (%"LONGFMT"u, %"LONGFMT"u)\n", dwInsideConeAngle, dwOutsideConeAngle);
2440 return DSERR_INVALIDPARAM;
2443 EnterCriticalSection(This->crst);
2444 if(apply == DS3D_DEFERRED)
2446 This->params.dwInsideConeAngle = dwInsideConeAngle;
2447 This->params.dwOutsideConeAngle = dwOutsideConeAngle;
2448 This->dirty.bit.cone_angles = 1;
2450 else
2452 setALContext(This->ctx);
2453 alSourcei(This->source, AL_CONE_INNER_ANGLE, dwInsideConeAngle);
2454 alSourcei(This->source, AL_CONE_OUTER_ANGLE, dwOutsideConeAngle);
2455 checkALError();
2456 popALContext();
2458 LeaveCriticalSection(This->crst);
2460 return S_OK;
2463 static HRESULT WINAPI DS8Buffer3D_SetConeOrientation(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2465 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2467 TRACE("(%p)->(%f, %f, %f, %"LONGFMT"u)\n", This, x, y, z, apply);
2469 if(apply == DS3D_DEFERRED)
2471 EnterCriticalSection(This->crst);
2472 This->params.vConeOrientation.x = x;
2473 This->params.vConeOrientation.y = y;
2474 This->params.vConeOrientation.z = z;
2475 This->dirty.bit.cone_orient = 1;
2476 LeaveCriticalSection(This->crst);
2478 else
2480 setALContext(This->ctx);
2481 alSource3f(This->source, AL_DIRECTION, x, y, -z);
2482 checkALError();
2483 popALContext();
2486 return S_OK;
2489 static HRESULT WINAPI DS8Buffer3D_SetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG vol, DWORD apply)
2491 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2493 TRACE("(%p)->(%"LONGFMT"d, %"LONGFMT"u)\n", This, vol, apply);
2494 if(vol < DSBVOLUME_MIN || vol > DSBVOLUME_MAX)
2496 WARN("Invalid volume (%"LONGFMT"d)\n", vol);
2497 return DSERR_INVALIDPARAM;
2500 if(apply == DS3D_DEFERRED)
2502 EnterCriticalSection(This->crst);
2503 This->params.lConeOutsideVolume = vol;
2504 This->dirty.bit.cone_outsidevolume = 1;
2505 LeaveCriticalSection(This->crst);
2507 else
2509 setALContext(This->ctx);
2510 alSourcef(This->source, AL_CONE_OUTER_GAIN, mB_to_gain(vol));
2511 checkALError();
2512 popALContext();
2515 return S_OK;
2518 static HRESULT WINAPI DS8Buffer3D_SetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE maxdist, DWORD apply)
2520 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2522 TRACE("(%p)->(%f, %"LONGFMT"u)\n", This, maxdist, apply);
2523 if(maxdist < 0.0f)
2525 WARN("Invalid max distance (%f)\n", maxdist);
2526 return DSERR_INVALIDPARAM;
2529 if(apply == DS3D_DEFERRED)
2531 EnterCriticalSection(This->crst);
2532 This->params.flMaxDistance = maxdist;
2533 This->dirty.bit.max_distance = 1;
2534 LeaveCriticalSection(This->crst);
2536 else
2538 setALContext(This->ctx);
2539 alSourcef(This->source, AL_MAX_DISTANCE, maxdist);
2540 checkALError();
2541 popALContext();
2544 return S_OK;
2547 static HRESULT WINAPI DS8Buffer3D_SetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE mindist, DWORD apply)
2549 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2551 TRACE("(%p)->(%f, %"LONGFMT"u)\n", This, mindist, apply);
2552 if(mindist < 0.0f)
2554 WARN("Invalid min distance (%f)\n", mindist);
2555 return DSERR_INVALIDPARAM;
2558 if(apply == DS3D_DEFERRED)
2560 EnterCriticalSection(This->crst);
2561 This->params.flMinDistance = mindist;
2562 This->dirty.bit.min_distance = 1;
2563 LeaveCriticalSection(This->crst);
2565 else
2567 setALContext(This->ctx);
2568 alSourcef(This->source, AL_REFERENCE_DISTANCE, mindist);
2569 checkALError();
2570 popALContext();
2573 return S_OK;
2576 static HRESULT WINAPI DS8Buffer3D_SetMode(IDirectSound3DBuffer *iface, DWORD mode, DWORD apply)
2578 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2580 TRACE("(%p)->(%"LONGFMT"u, %"LONGFMT"u)\n", This, mode, apply);
2581 if(mode != DS3DMODE_NORMAL && mode != DS3DMODE_HEADRELATIVE &&
2582 mode != DS3DMODE_DISABLE)
2584 WARN("Invalid mode (%"LONGFMT"u)\n", mode);
2585 return DSERR_INVALIDPARAM;
2588 EnterCriticalSection(This->crst);
2589 if(apply == DS3D_DEFERRED)
2591 This->params.dwMode = mode;
2592 This->dirty.bit.mode = 1;
2594 else
2596 setALContext(This->ctx);
2597 alSourcei(This->source, AL_SOURCE_RELATIVE,
2598 (mode != DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE);
2599 alSourcef(This->source, AL_ROLLOFF_FACTOR,
2600 (mode == DS3DMODE_DISABLE) ? 0.0f : This->primary->rollofffactor);
2601 This->ds3dmode = mode;
2602 checkALError();
2603 popALContext();
2605 LeaveCriticalSection(This->crst);
2607 return S_OK;
2610 static HRESULT WINAPI DS8Buffer3D_SetPosition(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2612 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2614 TRACE("(%p)->(%f, %f, %f, %"LONGFMT"u)\n", This, x, y, z, apply);
2616 if(apply == DS3D_DEFERRED)
2618 EnterCriticalSection(This->crst);
2619 This->params.vPosition.x = x;
2620 This->params.vPosition.y = y;
2621 This->params.vPosition.z = z;
2622 This->dirty.bit.pos = 1;
2623 LeaveCriticalSection(This->crst);
2625 else
2627 setALContext(This->ctx);
2628 alSource3f(This->source, AL_POSITION, x, y, -z);
2629 checkALError();
2630 popALContext();
2633 return S_OK;
2636 static HRESULT WINAPI DS8Buffer3D_SetVelocity(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2638 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2640 TRACE("(%p)->(%f, %f, %f, %"LONGFMT"u)\n", This, x, y, z, apply);
2642 if(apply == DS3D_DEFERRED)
2644 EnterCriticalSection(This->crst);
2645 This->params.vVelocity.x = x;
2646 This->params.vVelocity.y = y;
2647 This->params.vVelocity.z = z;
2648 This->dirty.bit.vel = 1;
2649 LeaveCriticalSection(This->crst);
2651 else
2653 setALContext(This->ctx);
2654 alSource3f(This->source, AL_VELOCITY, x, y, -z);
2655 checkALError();
2656 popALContext();
2659 return S_OK;
2662 static const IDirectSound3DBufferVtbl DS8Buffer3d_Vtbl =
2664 DS8Buffer3D_QueryInterface,
2665 DS8Buffer3D_AddRef,
2666 DS8Buffer3D_Release,
2667 DS8Buffer3D_GetAllParameters,
2668 DS8Buffer3D_GetConeAngles,
2669 DS8Buffer3D_GetConeOrientation,
2670 DS8Buffer3D_GetConeOutsideVolume,
2671 DS8Buffer3D_GetMaxDistance,
2672 DS8Buffer3D_GetMinDistance,
2673 DS8Buffer3D_GetMode,
2674 DS8Buffer3D_GetPosition,
2675 DS8Buffer3D_GetVelocity,
2676 DS8Buffer3D_SetAllParameters,
2677 DS8Buffer3D_SetConeAngles,
2678 DS8Buffer3D_SetConeOrientation,
2679 DS8Buffer3D_SetConeOutsideVolume,
2680 DS8Buffer3D_SetMaxDistance,
2681 DS8Buffer3D_SetMinDistance,
2682 DS8Buffer3D_SetMode,
2683 DS8Buffer3D_SetPosition,
2684 DS8Buffer3D_SetVelocity
2688 static HRESULT WINAPI DS8BufferNot_QueryInterface(IDirectSoundNotify *iface, REFIID riid, void **ppv)
2690 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2691 return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2694 static ULONG WINAPI DS8BufferNot_AddRef(IDirectSoundNotify *iface)
2696 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2697 LONG ret;
2699 InterlockedIncrement(&This->all_ref);
2700 ret = InterlockedIncrement(&This->not_ref);
2701 TRACE("new refcount %"LONGFMT"d\n", ret);
2703 return ret;
2706 static ULONG WINAPI DS8BufferNot_Release(IDirectSoundNotify *iface)
2708 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2709 LONG ret;
2711 ret = InterlockedDecrement(&This->not_ref);
2712 TRACE("new refcount %"LONGFMT"d\n", ret);
2713 if(InterlockedDecrement(&This->all_ref) == 0)
2714 DS8Buffer_Destroy(This);
2716 return ret;
2719 static HRESULT WINAPI DS8BufferNot_SetNotificationPositions(IDirectSoundNotify *iface, DWORD count, const DSBPOSITIONNOTIFY *notifications)
2721 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2722 DSBPOSITIONNOTIFY *nots;
2723 DWORD state;
2724 HRESULT hr;
2726 TRACE("(%p)->(%"LONGFMT"u, %p))\n", iface, count, notifications);
2728 EnterCriticalSection(This->crst);
2729 hr = DSERR_INVALIDPARAM;
2730 if(count && !notifications)
2731 goto out;
2733 hr = IDirectSoundBuffer8_GetStatus(&This->IDirectSoundBuffer8_iface, &state);
2734 if(FAILED(hr))
2735 goto out;
2737 hr = DSERR_INVALIDCALL;
2738 if((state&DSBSTATUS_PLAYING))
2739 goto out;
2741 if(!count)
2743 HeapFree(GetProcessHeap(), 0, This->notify);
2744 This->notify = 0;
2745 This->nnotify = 0;
2746 hr = S_OK;
2748 else
2750 DWORD i;
2752 hr = DSERR_INVALIDPARAM;
2753 for(i = 0;i < count;++i)
2755 if(notifications[i].dwOffset >= This->buffer->buf_size &&
2756 notifications[i].dwOffset != (DWORD)DSBPN_OFFSETSTOP)
2757 goto out;
2760 hr = E_OUTOFMEMORY;
2761 nots = HeapAlloc(GetProcessHeap(), 0, count*sizeof(*nots));
2762 if(!nots)
2763 goto out;
2764 memcpy(nots, notifications, count*sizeof(*nots));
2766 HeapFree(GetProcessHeap(), 0, This->notify);
2767 This->notify = nots;
2768 This->nnotify = count;
2770 hr = S_OK;
2773 out:
2774 LeaveCriticalSection(This->crst);
2775 return hr;
2778 static const IDirectSoundNotifyVtbl DS8BufferNot_Vtbl =
2780 DS8BufferNot_QueryInterface,
2781 DS8BufferNot_AddRef,
2782 DS8BufferNot_Release,
2783 DS8BufferNot_SetNotificationPositions
2787 static HRESULT WINAPI DS8BufferProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
2789 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2790 return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2793 static ULONG WINAPI DS8BufferProp_AddRef(IKsPropertySet *iface)
2795 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2796 LONG ret;
2798 InterlockedIncrement(&This->all_ref);
2799 ret = InterlockedIncrement(&This->prop_ref);
2800 TRACE("new refcount %"LONGFMT"d\n", ret);
2802 return ret;
2805 static ULONG WINAPI DS8BufferProp_Release(IKsPropertySet *iface)
2807 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2808 LONG ret;
2810 ret = InterlockedDecrement(&This->prop_ref);
2811 TRACE("new refcount %"LONGFMT"d\n", ret);
2812 if(InterlockedDecrement(&This->all_ref) == 0)
2813 DS8Buffer_Destroy(This);
2815 return ret;
2818 /* NOTE: Due to some apparent quirks in DSound, the listener properties are
2819 handled through secondary buffers. */
2820 static HRESULT WINAPI DS8BufferProp_Get(IKsPropertySet *iface,
2821 REFGUID guidPropSet, ULONG dwPropID,
2822 LPVOID pInstanceData, ULONG cbInstanceData,
2823 LPVOID pPropData, ULONG cbPropData,
2824 PULONG pcbReturned)
2826 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2827 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2829 TRACE("(%p)->(%s, %"LONGFMT"u, %p, %"LONGFMT"u, %p, %"LONGFMT"u, %p)\n", iface, debugstr_guid(guidPropSet),
2830 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData, pcbReturned);
2832 if(!pcbReturned)
2833 return E_POINTER;
2834 *pcbReturned = 0;
2836 #if 0
2837 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2840 else
2841 #endif
2843 /* Not a known buffer/source property. Pass it to the listener */
2844 hr = IKsPropertySet_Get(&This->primary->IKsPropertySet_iface, guidPropSet,
2845 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData,
2846 pcbReturned);
2849 return hr;
2852 static HRESULT WINAPI DS8BufferProp_Set(IKsPropertySet *iface,
2853 REFGUID guidPropSet, ULONG dwPropID,
2854 LPVOID pInstanceData, ULONG cbInstanceData,
2855 LPVOID pPropData, ULONG cbPropData)
2857 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2858 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2860 TRACE("(%p)->(%s, %"LONGFMT"u, %p, %"LONGFMT"u, %p, %"LONGFMT"u)\n", iface, debugstr_guid(guidPropSet),
2861 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData);
2863 #if 0
2864 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2867 else
2868 #endif
2870 /* Not a known buffer/source property. Pass it to the listener */
2871 hr = IKsPropertySet_Set(&This->primary->IKsPropertySet_iface, guidPropSet,
2872 dwPropID, pInstanceData, cbInstanceData, pPropData,
2873 cbPropData);
2876 return hr;
2879 static HRESULT WINAPI DS8BufferProp_QuerySupport(IKsPropertySet *iface,
2880 REFGUID guidPropSet, ULONG dwPropID,
2881 PULONG pTypeSupport)
2883 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2884 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2886 TRACE("(%p)->(%s, %"LONGFMT"u, %p)\n", iface, debugstr_guid(guidPropSet), dwPropID, pTypeSupport);
2888 if(!pTypeSupport)
2889 return E_POINTER;
2890 *pTypeSupport = 0;
2892 #if 0
2893 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2896 else
2897 #endif
2899 /* Not a known buffer/source property. Pass it to the listener */
2900 hr = IKsPropertySet_QuerySupport(&This->primary->IKsPropertySet_iface,
2901 guidPropSet, dwPropID, pTypeSupport);
2904 return hr;
2907 static const IKsPropertySetVtbl DS8BufferProp_Vtbl =
2909 DS8BufferProp_QueryInterface,
2910 DS8BufferProp_AddRef,
2911 DS8BufferProp_Release,
2912 DS8BufferProp_Get,
2913 DS8BufferProp_Set,
2914 DS8BufferProp_QuerySupport