Use a switch instead of a series of else ifs
[dsound-openal.git] / buffer.c
blobb8c0b20acb41ffc55fb98d435e1f7780b040fb59
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 getALCError(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) && !prim->SupportedExt[SOFT_BUFFER_SUB_DATA] &&
707 !prim->SupportedExt[EXT_STATIC_BUFFER])
709 ALCint refresh = FAKE_REFRESH_COUNT;
710 ALuint newSize;
712 alcGetIntegerv(prim->parent->device, ALC_REFRESH, 1, &refresh);
713 getALCError(prim->parent->device);
715 newSize = format->nAvgBytesPerSec/refresh + format->nBlockAlign - 1;
716 newSize -= newSize%format->nBlockAlign;
718 /* Make sure enough buffers are available */
719 if(newSize > pBuffer->buf_size/(QBUFFERS+2))
720 ERR("Buffer segments too large to stream (%u for %u)!\n",
721 newSize, pBuffer->buf_size);
722 else
724 pBuffer->numsegs = pBuffer->buf_size/newSize;
725 pBuffer->segsize = newSize;
726 pBuffer->lastsegsize = pBuffer->buf_size - (newSize*(pBuffer->numsegs-1));
727 TRACE("New streaming buffer (%u chunks, %u : %u sizes)\n",
728 pBuffer->numsegs, pBuffer->segsize, pBuffer->lastsegsize);
732 if(format->wFormatTag == WAVE_FORMAT_PCM)
733 fmt_str = get_fmtstr_PCM(prim, format, &pBuffer->format);
734 else if(format->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
735 fmt_str = get_fmtstr_FLOAT(prim, format, &pBuffer->format);
736 else if(format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
738 const WAVEFORMATEXTENSIBLE *wfe;
740 hr = DSERR_CONTROLUNAVAIL;
741 if(format->cbSize != sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) &&
742 format->cbSize != sizeof(WAVEFORMATEXTENSIBLE))
743 goto fail;
745 wfe = CONTAINING_RECORD(format, const WAVEFORMATEXTENSIBLE, Format);
746 TRACE("Extensible values:\n"
747 " Samples = %d\n"
748 " ChannelMask = 0x%"LONGFMT"x\n"
749 " SubFormat = %s\n",
750 wfe->Samples.wReserved, wfe->dwChannelMask,
751 debugstr_guid(&wfe->SubFormat));
753 fmt_str = get_fmtstr_EXT(prim, format, &pBuffer->format);
755 else
756 ERR("Unhandled formattag 0x%04x\n", format->wFormatTag);
758 hr = DSERR_INVALIDCALL;
759 if(!fmt_str)
760 goto fail;
762 pBuffer->buf_format = alGetEnumValue(fmt_str);
763 if(alGetError() != AL_NO_ERROR || pBuffer->buf_format == 0 ||
764 pBuffer->buf_format == -1)
766 WARN("Could not get OpenAL format from %s\n", fmt_str);
767 goto fail;
770 else
772 if(format->wFormatTag == WAVE_FORMAT_PCM)
773 pBuffer->buf_format = get_fmt_PCM(format, &pBuffer->format, &pBuffer->in_chans, &pBuffer->in_type);
774 else if(format->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
775 pBuffer->buf_format = get_fmt_FLOAT(format, &pBuffer->format, &pBuffer->in_chans, &pBuffer->in_type);
776 else if(format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
778 const WAVEFORMATEXTENSIBLE *wfe;
780 hr = DSERR_CONTROLUNAVAIL;
781 if(format->cbSize != sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) &&
782 format->cbSize != sizeof(WAVEFORMATEXTENSIBLE))
783 goto fail;
785 wfe = CONTAINING_RECORD(format, const WAVEFORMATEXTENSIBLE, Format);
786 TRACE("Extensible values:\n"
787 " Samples = %d\n"
788 " ChannelMask = 0x%"LONGFMT"x\n"
789 " SubFormat = %s\n",
790 wfe->Samples.wReserved, wfe->dwChannelMask,
791 debugstr_guid(&wfe->SubFormat));
793 pBuffer->buf_format = get_fmt_EXT(format, &pBuffer->format, &pBuffer->in_chans, &pBuffer->in_type);
795 else
796 ERR("Unhandled formattag 0x%04x\n", format->wFormatTag);
798 hr = DSERR_INVALIDCALL;
799 if(prim->ExtAL.IsBufferFormatSupportedSOFT(pBuffer->buf_format) == AL_FALSE)
801 WARN("Unsupported OpenAL format: 0x%x\n", pBuffer->buf_format);
802 goto fail;
806 hr = E_OUTOFMEMORY;
807 pBuffer->buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pBuffer->buffers)*pBuffer->numsegs);
808 pBuffer->data = HeapAlloc(GetProcessHeap(), 0, pBuffer->buf_size);
809 if(!pBuffer->buffers || !pBuffer->data)
810 goto fail;
812 alGenBuffers(pBuffer->numsegs, pBuffer->buffers);
813 getALError();
815 *ppv = pBuffer;
816 return S_OK;
818 fail:
819 DS8Data_Release(pBuffer);
820 return hr;
823 static void DS8Data_AddRef(DS8Data *data)
825 InterlockedIncrement(&data->ref);
828 /* This function is always called with the device lock held */
829 static void DS8Data_Release(DS8Data *This)
831 if(InterlockedDecrement(&This->ref)) return;
833 TRACE("Deleting %p\n", This);
834 if (This->buffers && This->buffers[0])
836 alDeleteBuffers(This->numsegs, This->buffers);
837 getALError();
839 HeapFree(GetProcessHeap(), 0, This->buffers);
840 HeapFree(GetProcessHeap(), 0, This->data);
841 HeapFree(GetProcessHeap(), 0, This);
844 HRESULT DS8Buffer_Create(DS8Buffer **ppv, DS8Primary *prim, IDirectSoundBuffer *orig)
846 DS8Buffer *This;
847 HRESULT hr;
849 *ppv = NULL;
850 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
851 if(!This) return DSERR_OUTOFMEMORY;
853 This->IDirectSoundBuffer8_iface.lpVtbl = (IDirectSoundBuffer8Vtbl*)&DS8Buffer_Vtbl;
854 This->IDirectSoundBuffer_iface.lpVtbl = (IDirectSoundBufferVtbl*)&DSBuffer_Vtbl;
855 This->IDirectSound3DBuffer_iface.lpVtbl = (IDirectSound3DBufferVtbl*)&DS8Buffer3d_Vtbl;
856 This->IDirectSoundNotify_iface.lpVtbl = (IDirectSoundNotifyVtbl*)&DS8BufferNot_Vtbl;
857 This->IKsPropertySet_iface.lpVtbl = (IKsPropertySetVtbl*)&DS8BufferProp_Vtbl;
859 This->primary = prim;
860 This->ctx = prim->ctx;
861 This->ExtAL = &prim->ExtAL;
862 This->crst = &prim->crst;
863 This->ref = This->all_ref = 1;
865 if(orig)
867 DS8Buffer *org = impl_from_IDirectSoundBuffer(orig);
868 hr = DSERR_BUFFERLOST;
869 if(org->bufferlost)
870 goto fail;
871 DS8Data_AddRef(org->buffer);
872 This->buffer = org->buffer;
875 /* Append to buffer list */
876 if(prim->nbuffers == prim->sizebuffers)
878 void *bufs;
880 hr = DSERR_OUTOFMEMORY;
881 bufs = HeapReAlloc(GetProcessHeap(), 0, prim->buffers, sizeof(*bufs)*(prim->nbuffers+1));
882 if(!bufs) goto fail;
884 prim->buffers = bufs;
885 prim->sizebuffers++;
887 prim->buffers[prim->nbuffers++] = This;
889 /* Disable until initialized.. */
890 This->ds3dmode = DS3DMODE_DISABLE;
892 *ppv = This;
893 return DS_OK;
895 fail:
896 DS8Buffer_Destroy(This);
897 return hr;
900 void DS8Buffer_Destroy(DS8Buffer *This)
902 DS8Primary *prim = This->primary;
903 DWORD idx;
905 TRACE("Destroying %p\n", This);
907 EnterCriticalSection(&prim->crst);
908 /* Remove from list, if in list */
909 for(idx = 0;idx < prim->nnotifies;++idx)
911 if(This == prim->notifies[idx])
913 prim->notifies[idx] = prim->notifies[--prim->nnotifies];
914 break;
917 for(idx = 0;idx < prim->nbuffers;++idx)
919 if(prim->buffers[idx] == This)
921 prim->buffers[idx] = prim->buffers[--prim->nbuffers];
922 break;
926 setALContext(This->ctx);
927 if(This->source)
929 ALuint *sources;
931 alSourceStop(This->source);
932 alSourcei(This->source, AL_BUFFER, 0);
933 getALError();
935 sources = prim->sources;
936 if(prim->nsources == prim->sizesources)
938 sources = HeapReAlloc(GetProcessHeap(), 0, sources, sizeof(*sources)*(prim->nsources+1));
939 if(!sources)
940 alDeleteSources(1, &This->source);
941 else
942 prim->sizesources++;
944 if(sources)
946 sources[prim->nsources++] = This->source;
947 prim->sources = sources;
949 This->source = 0;
951 LeaveCriticalSection(&prim->crst);
953 if(This->buffer)
954 DS8Data_Release(This->buffer);
956 popALContext();
958 HeapFree(GetProcessHeap(), 0, This->notify);
959 HeapFree(GetProcessHeap(), 0, This);
963 static HRESULT WINAPI DS8Buffer_QueryInterface(IDirectSoundBuffer8 *iface, REFIID riid, void **ppv)
965 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
967 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
969 *ppv = NULL;
970 if(IsEqualIID(riid, &IID_IUnknown))
971 *ppv = &This->IDirectSoundBuffer8_iface;
972 else if(IsEqualIID(riid, &IID_IDirectSoundBuffer))
973 *ppv = &This->IDirectSoundBuffer_iface;
974 else if(IsEqualIID(riid, &IID_IDirectSoundBuffer8))
976 if(This->primary->parent->is_8)
977 *ppv = &This->IDirectSoundBuffer8_iface;
979 else if(IsEqualIID(riid, &IID_IDirectSound3DBuffer))
981 if((This->buffer->dsbflags&DSBCAPS_CTRL3D))
982 *ppv = &This->IDirectSound3DBuffer_iface;
984 else if(IsEqualIID(riid, &IID_IDirectSoundNotify))
986 if((This->buffer->dsbflags&DSBCAPS_CTRLPOSITIONNOTIFY))
987 *ppv = &This->IDirectSoundNotify_iface;
989 else if(IsEqualIID(riid, &IID_IKsPropertySet))
990 *ppv = &This->IKsPropertySet_iface;
991 else
992 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
994 if(*ppv)
996 IUnknown_AddRef((IUnknown*)*ppv);
997 return S_OK;
1000 return E_NOINTERFACE;
1003 static ULONG WINAPI DS8Buffer_AddRef(IDirectSoundBuffer8 *iface)
1005 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1006 LONG ret;
1008 InterlockedIncrement(&This->all_ref);
1009 ret = InterlockedIncrement(&This->ref);
1010 TRACE("new refcount %"LONGFMT"d\n", ret);
1012 return ret;
1015 static ULONG WINAPI DS8Buffer_Release(IDirectSoundBuffer8 *iface)
1017 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1018 LONG ret;
1020 ret = InterlockedDecrement(&This->ref);
1021 TRACE("new refcount %"LONGFMT"d\n", ret);
1022 if(InterlockedDecrement(&This->all_ref) == 0)
1023 DS8Buffer_Destroy(This);
1025 return ret;
1028 static HRESULT WINAPI DS8Buffer_GetCaps(IDirectSoundBuffer8 *iface, DSBCAPS *caps)
1030 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1032 TRACE("(%p)->(%p)\n", iface, caps);
1034 if(!caps || caps->dwSize < sizeof(*caps))
1036 WARN("Invalid DSBCAPS (%p, %"LONGFMT"u)\n", caps, (caps ? caps->dwSize : 0));
1037 return DSERR_INVALIDPARAM;
1040 caps->dwFlags = This->buffer->dsbflags;
1041 caps->dwBufferBytes = This->buffer->buf_size;
1042 caps->dwUnlockTransferRate = 4096;
1043 caps->dwPlayCpuOverhead = 0;
1044 return S_OK;
1047 static HRESULT WINAPI DS8Buffer_GetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD *playpos, DWORD *curpos)
1049 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1050 WAVEFORMATEX *format = &This->buffer->format.Format;
1051 UINT writecursor, pos;
1053 TRACE("(%p)->(%p, %p)\n", iface, playpos, curpos);
1055 EnterCriticalSection(This->crst);
1056 setALContext(This->ctx);
1058 if(This->buffer->numsegs > 1)
1060 ALint queued = QBUFFERS;
1061 alGetSourcei(This->source, AL_BUFFERS_QUEUED, &queued);
1062 getALError();
1064 pos = (This->curidx+This->buffer->numsegs-queued)%This->buffer->numsegs;
1065 pos *= This->buffer->segsize;
1066 writecursor = This->curidx * This->buffer->segsize;
1068 else if(This->primary->SupportedExt[SOFT_BUFFER_SUB_DATA] ||
1069 This->primary->SupportedExt[SOFT_BUFFER_SAMPLES])
1071 ALint rwpos[2] = { 0, 0 };
1073 alGetSourceiv(This->source, AL_BYTE_RW_OFFSETS_SOFT, rwpos);
1074 getALError();
1076 pos = rwpos[0];
1077 writecursor = rwpos[1];
1079 else
1081 ALint status = 0;
1082 ALint ofs = 0;
1084 alGetSourcei(This->source, AL_BYTE_OFFSET, &ofs);
1085 alGetSourcei(This->source, AL_SOURCE_STATE, &status);
1086 getALError();
1088 pos = ofs;
1089 if(status == AL_PLAYING)
1091 writecursor = format->nSamplesPerSec / 100;
1092 writecursor *= format->nBlockAlign;
1094 else
1095 writecursor = 0;
1096 writecursor = (writecursor + pos) % This->buffer->buf_size;
1098 TRACE("%p Play pos = %u, write pos = %u\n", This, pos, writecursor);
1099 if(pos >= This->buffer->buf_size)
1101 ERR("playpos >= buf_size\n");
1102 pos %= This->buffer->buf_size;
1104 if(writecursor >= This->buffer->buf_size)
1106 ERR("writepos >= buf_size\n");
1107 writecursor %= This->buffer->buf_size;
1110 if(playpos) *playpos = pos;
1111 if(curpos) *curpos = writecursor;
1113 popALContext();
1114 LeaveCriticalSection(This->crst);
1116 return S_OK;
1119 static HRESULT WINAPI DS8Buffer_GetFormat(IDirectSoundBuffer8 *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
1121 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1122 HRESULT hr = S_OK;
1123 UINT size;
1125 TRACE("(%p)->(%p, %"LONGFMT"u, %p)\n", iface, wfx, allocated, written);
1127 if(!wfx && !written)
1129 WARN("Cannot report format or format size\n");
1130 return DSERR_INVALIDPARAM;
1133 size = sizeof(This->buffer->format.Format) + This->buffer->format.Format.cbSize;
1134 if(wfx)
1136 if(allocated < size)
1137 hr = DSERR_INVALIDPARAM;
1138 else
1139 memcpy(wfx, &This->buffer->format.Format, size);
1141 if(written)
1142 *written = size;
1144 return hr;
1147 static HRESULT WINAPI DS8Buffer_GetVolume(IDirectSoundBuffer8 *iface, LONG *vol)
1149 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1150 HRESULT hr;
1152 TRACE("(%p)->(%p)\n", iface, vol);
1154 if(!vol)
1156 WARN("Invalid pointer\n");
1157 return DSERR_INVALIDPARAM;
1160 hr = DSERR_CONTROLUNAVAIL;
1161 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
1162 WARN("Volume control not set\n");
1163 else
1165 ALfloat gain = 1.0f;
1167 setALContext(This->ctx);
1168 alGetSourcef(This->source, AL_GAIN, &gain);
1169 getALError();
1170 popALContext();
1172 *vol = clampI(gain_to_mB(gain), DSBVOLUME_MIN, DSBVOLUME_MAX);
1173 hr = DS_OK;
1176 return hr;
1179 static HRESULT WINAPI DS8Buffer_GetPan(IDirectSoundBuffer8 *iface, LONG *pan)
1181 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1182 HRESULT hr;
1184 TRACE("(%p)->(%p)\n", iface, pan);
1186 if(!pan)
1188 WARN("Invalid pointer\n");
1189 return DSERR_INVALIDPARAM;
1192 hr = DSERR_CONTROLUNAVAIL;
1193 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
1194 WARN("Panning control not set\n");
1195 else
1197 ALfloat pos[3];
1199 setALContext(This->ctx);
1200 alGetSourcefv(This->source, AL_POSITION, pos);
1201 getALError();
1202 popALContext();
1204 *pan = clampI(((pos[0]+1.0) * (DSBPAN_RIGHT-DSBPAN_LEFT) / 2.0 + 0.5) + DSBPAN_LEFT, DSBPAN_LEFT, DSBPAN_RIGHT);
1205 hr = DS_OK;
1208 return hr;
1211 static HRESULT WINAPI DS8Buffer_GetFrequency(IDirectSoundBuffer8 *iface, DWORD *freq)
1213 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1214 HRESULT hr;
1216 TRACE("(%p)->(%p)\n", iface, freq);
1218 if(!freq)
1220 WARN("Invalid pointer\n");
1221 return DSERR_INVALIDPARAM;
1224 hr = DSERR_CONTROLUNAVAIL;
1225 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
1226 WARN("Frequency control not set\n");
1227 else
1229 ALfloat pitch = 1.0f;
1231 setALContext(This->ctx);
1232 alGetSourcefv(This->source, AL_PITCH, &pitch);
1233 getALError();
1234 popALContext();
1236 *freq = (DWORD)(This->buffer->format.Format.nSamplesPerSec * pitch);
1237 hr = DS_OK;
1240 return hr;
1243 static HRESULT WINAPI DS8Buffer_GetStatus(IDirectSoundBuffer8 *iface, DWORD *status)
1245 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1246 ALint state, looping;
1248 TRACE("(%p)->(%p)\n", iface, status);
1250 if(!status)
1252 WARN("Invalid pointer\n");
1253 return DSERR_INVALIDPARAM;
1256 EnterCriticalSection(This->crst);
1258 setALContext(This->ctx);
1259 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1260 looping = This->islooping;
1261 if(This->buffer->numsegs == 1)
1262 alGetSourcei(This->source, AL_LOOPING, &looping);
1263 else if(state != AL_PLAYING)
1264 state = This->isplaying ? AL_PLAYING : AL_PAUSED;
1265 getALError();
1266 popALContext();
1268 LeaveCriticalSection(This->crst);
1270 *status = 0;
1271 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1273 if((This->buffer->dsbflags&DSBCAPS_LOCSOFTWARE))
1274 *status |= DSBSTATUS_LOCSOFTWARE;
1275 else if((This->buffer->dsbflags&DSBCAPS_LOCHARDWARE))
1276 *status |= DSBSTATUS_LOCHARDWARE;
1278 if(state == AL_PLAYING)
1279 *status |= DSBSTATUS_PLAYING | (looping ? DSBSTATUS_LOOPING : 0);
1281 return S_OK;
1284 static HRESULT WINAPI DS8Buffer_Initialize(IDirectSoundBuffer8 *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
1286 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1287 DS3DBUFFER *ds3dbuffer;
1288 HRESULT hr;
1290 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
1292 EnterCriticalSection(This->crst);
1293 setALContext(This->ctx);
1295 hr = DSERR_ALREADYINITIALIZED;
1296 if(This->source)
1297 goto out;
1299 if(!This->buffer)
1301 hr = DSERR_INVALIDPARAM;
1302 if(!desc)
1304 WARN("Missing DSound buffer description\n");
1305 goto out;
1307 if(!desc->lpwfxFormat)
1309 WARN("Missing buffer format (%p)\n", This);
1310 goto out;
1312 if((desc->dwFlags&DSBCAPS_CTRL3D) && desc->lpwfxFormat->nChannels != 1)
1314 if(This->primary->parent->is_8)
1316 /* DirectSoundBuffer8 objects aren't allowed non-mono 3D
1317 * buffers */
1318 WARN("Can't create multi-channel 3D buffers\n");
1319 goto out;
1321 ERR("Multi-channel 3D sounds are not spatialized\n");
1324 hr = DS8Data_Create(&This->buffer, desc, This->primary);
1325 if(FAILED(hr))
1326 goto out;
1327 else
1329 DS8Data *buf = This->buffer;
1331 if(buf->format.Format.wBitsPerSample == 8)
1332 memset(buf->data, 0x80, buf->buf_size);
1333 else
1334 memset(buf->data, 0x00, buf->buf_size);
1336 if(This->primary->SupportedExt[EXT_STATIC_BUFFER])
1337 This->ExtAL->BufferDataStatic(buf->buffers[0], buf->buf_format,
1338 buf->data, buf->buf_size,
1339 buf->format.Format.nSamplesPerSec);
1340 else if(This->primary->SupportedExt[SOFT_BUFFER_SAMPLES])
1341 This->ExtAL->BufferSamplesSOFT(buf->buffers[0],
1342 buf->format.Format.nSamplesPerSec, buf->buf_format,
1343 buf->buf_size/buf->format.Format.nBlockAlign,
1344 buf->in_chans, buf->in_type, buf->data);
1345 else if(This->primary->SupportedExt[SOFT_BUFFER_SUB_DATA])
1346 alBufferData(buf->buffers[0], buf->buf_format,
1347 buf->data, buf->buf_size,
1348 buf->format.Format.nSamplesPerSec);
1350 getALError();
1353 hr = DSERR_GENERIC;
1354 if(This->primary->nsources)
1356 This->source = This->primary->sources[--This->primary->nsources];
1357 alSourcef(This->source, AL_GAIN, 1.0f);
1358 alSourcef(This->source, AL_PITCH, 1.0f);
1359 getALError();
1361 else
1363 alGenSources(1, &This->source);
1364 if(alGetError() != AL_NO_ERROR)
1365 goto out;
1368 ds3dbuffer = &This->ds3dbuffer;
1369 ds3dbuffer->dwSize = sizeof(*ds3dbuffer);
1370 ds3dbuffer->vPosition.x = 0.0;
1371 ds3dbuffer->vPosition.y = 0.0;
1372 ds3dbuffer->vPosition.z = 0.0;
1373 ds3dbuffer->vVelocity.x = 0.0;
1374 ds3dbuffer->vVelocity.y = 0.0;
1375 ds3dbuffer->vVelocity.z = 0.0;
1376 ds3dbuffer->dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
1377 ds3dbuffer->dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
1378 ds3dbuffer->vConeOrientation.x = 0.0;
1379 ds3dbuffer->vConeOrientation.y = 0.0;
1380 ds3dbuffer->vConeOrientation.z = 1.0;
1381 ds3dbuffer->lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
1382 ds3dbuffer->flMinDistance = DS3D_DEFAULTMINDISTANCE;
1383 ds3dbuffer->flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
1384 ds3dbuffer->dwMode = DS3DMODE_NORMAL;
1386 if((This->buffer->dsbflags&DSBCAPS_CTRL3D))
1388 if(This->primary->auxslot != 0)
1390 alSource3i(This->source, AL_AUXILIARY_SEND_FILTER, This->primary->auxslot, 0, AL_FILTER_NULL);
1391 getALError();
1394 hr = IDirectSound3DBuffer_SetAllParameters(&This->IDirectSound3DBuffer_iface, ds3dbuffer, DS3D_IMMEDIATE);
1395 if(FAILED(hr))
1397 ERR("SetAllParameters failed\n");
1398 goto out;
1401 else
1403 ALuint source = This->source;
1405 if(This->primary->auxslot != 0)
1407 /* Simple hack to make reverb affect non-3D sounds too */
1408 alSource3i(source, AL_AUXILIARY_SEND_FILTER, This->primary->auxslot, 0, AL_FILTER_NULL);
1409 /*alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL);*/
1412 /* Non-3D sources aren't distance attenuated */
1413 This->ds3dmode = DS3DMODE_DISABLE;
1414 alSource3f(source, AL_POSITION, 0.0f, 1.0f, 0.0f);
1415 alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
1416 alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
1417 alSourcef(source, AL_CONE_OUTER_GAIN, 1.0f);
1418 alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f);
1419 alSourcef(source, AL_MAX_DISTANCE, 1000.0f);
1420 alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f);
1421 alSourcei(source, AL_CONE_INNER_ANGLE, 360);
1422 alSourcei(source, AL_CONE_OUTER_ANGLE, 360);
1423 alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);
1424 getALError();
1426 hr = S_OK;
1428 out:
1429 popALContext();
1430 LeaveCriticalSection(This->crst);
1432 return hr;
1435 static HRESULT WINAPI DS8Buffer_Lock(IDirectSoundBuffer8 *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
1437 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1438 DWORD remain;
1440 TRACE("(%p)->(%"LONGFMT"u, %"LONGFMT"u, %p, %p, %p, %p, 0x%"LONGFMT"x)\n", This, ofs, bytes, ptr1, len1, ptr2, len2, flags);
1442 if(!ptr1 || !len1)
1444 WARN("Invalid pointer/len %p %p\n", ptr1, len1);
1445 return DSERR_INVALIDPARAM;
1448 *ptr1 = NULL;
1449 *len1 = 0;
1450 if(ptr2) *ptr2 = NULL;
1451 if(len2) *len2 = 0;
1453 if((flags&DSBLOCK_FROMWRITECURSOR))
1454 DS8Buffer_GetCurrentPosition(iface, NULL, &ofs);
1455 else if(ofs >= This->buffer->buf_size)
1457 WARN("Invalid ofs %"LONGFMT"u\n", ofs);
1458 return DSERR_INVALIDPARAM;
1460 if((flags&DSBLOCK_ENTIREBUFFER))
1461 bytes = This->buffer->buf_size;
1462 else if(bytes > This->buffer->buf_size)
1464 WARN("Invalid size %"LONGFMT"u\n", bytes);
1465 return DSERR_INVALIDPARAM;
1468 if(InterlockedExchange(&This->buffer->locked, TRUE) == TRUE)
1470 WARN("Already locked\n");
1471 return DSERR_INVALIDPARAM;
1474 *ptr1 = This->buffer->data + ofs;
1475 if(ofs+bytes >= This->buffer->buf_size)
1477 *len1 = This->buffer->buf_size - ofs;
1478 remain = bytes - *len1;
1480 else
1482 *len1 = bytes;
1483 remain = 0;
1486 if(ptr2 && len2 && remain)
1488 *ptr2 = This->buffer->data;
1489 *len2 = remain;
1492 return DS_OK;
1495 static HRESULT WINAPI DS8Buffer_Play(IDirectSoundBuffer8 *iface, DWORD res1, DWORD prio, DWORD flags)
1497 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1498 ALint type, state = AL_STOPPED;
1499 HRESULT hr;
1501 TRACE("(%p)->(%"LONGFMT"u, %"LONGFMT"u, %"LONGFMT"u\n", iface, res1, prio, flags);
1503 EnterCriticalSection(This->crst);
1504 setALContext(This->ctx);
1506 hr = DSERR_BUFFERLOST;
1507 if(This->bufferlost)
1509 WARN("Buffer %p lost\n", This);
1510 goto out;
1513 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1515 if(!(This->buffer->dsbflags&(DSBCAPS_LOCHARDWARE|DSBCAPS_LOCSOFTWARE)))
1517 if(flags & DSBPLAY_LOCSOFTWARE)
1518 This->buffer->dsbflags |= DSBCAPS_LOCSOFTWARE;
1519 else
1520 This->buffer->dsbflags |= DSBCAPS_LOCHARDWARE;
1523 else if(prio)
1525 ERR("Invalid priority set for non-deferred buffer %p, %"LONGFMT"u!\n", This->buffer, prio);
1526 hr = DSERR_INVALIDPARAM;
1527 goto out;
1530 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1531 if(This->buffer->numsegs > 1)
1533 This->islooping = !!(flags&DSBPLAY_LOOPING);
1534 if(state != AL_PLAYING && This->isplaying)
1535 state = AL_PLAYING;
1537 else
1539 alGetSourcei(This->source, AL_SOURCE_TYPE, &type);
1540 alSourcei(This->source, AL_LOOPING, (flags&DSBPLAY_LOOPING) ? AL_TRUE : AL_FALSE);
1542 getALError();
1544 hr = S_OK;
1545 if(state == AL_PLAYING)
1546 goto out;
1548 /* alSourceQueueBuffers will implicitly set type to streaming */
1549 if(This->buffer->numsegs == 1)
1551 if(type != AL_STATIC)
1552 alSourcei(This->source, AL_BUFFER, This->buffer->buffers[0]);
1553 alSourcePlay(This->source);
1555 if(alGetError() != AL_NO_ERROR)
1557 ERR("Couldn't start source\n");
1558 This->curidx = (This->buffer->numsegs-1+This->curidx)%This->buffer->numsegs;
1559 alSourcei(This->source, AL_BUFFER, 0);
1560 getALError();
1561 hr = DSERR_GENERIC;
1562 goto out;
1564 This->isplaying = TRUE;
1566 if(This->nnotify)
1568 DS8Buffer_addnotify(This);
1569 DS8Buffer_starttimer(This->primary);
1571 else if(This->buffer->numsegs > 1)
1572 DS8Buffer_starttimer(This->primary);
1574 out:
1575 popALContext();
1576 LeaveCriticalSection(This->crst);
1577 return hr;
1580 static HRESULT WINAPI DS8Buffer_SetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD pos)
1582 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1584 TRACE("(%p)->(%"LONGFMT"u)\n", iface, pos);
1586 if(pos >= This->buffer->buf_size)
1587 return DSERR_INVALIDPARAM;
1589 EnterCriticalSection(This->crst);
1591 if(This->buffer->numsegs > 1)
1593 DS8Data *buf = This->buffer;
1594 This->curidx = pos/buf->segsize;
1595 if(This->curidx >= buf->numsegs)
1596 This->curidx = buf->numsegs - 1;
1597 if(This->isplaying)
1599 setALContext(This->ctx);
1600 /* Perform a flush, so the next timer update will restart at the
1601 * proper position */
1602 alSourceStop(This->source);
1603 alSourcei(This->source, AL_BUFFER, 0);
1604 getALError();
1605 popALContext();
1608 else
1610 setALContext(This->ctx);
1611 alSourcei(This->source, AL_BYTE_OFFSET, pos);
1612 popALContext();
1614 This->lastpos = pos;
1616 LeaveCriticalSection(This->crst);
1617 return DS_OK;
1620 static HRESULT WINAPI DS8Buffer_SetFormat(IDirectSoundBuffer8 *iface, const WAVEFORMATEX *wfx)
1622 /* This call only works on primary buffers */
1623 WARN("(%p)->(%p)\n", iface, wfx);
1624 return DSERR_INVALIDCALL;
1627 static HRESULT WINAPI DS8Buffer_SetVolume(IDirectSoundBuffer8 *iface, LONG vol)
1629 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1630 HRESULT hr = S_OK;
1632 TRACE("(%p)->(%"LONGFMT"d)\n", iface, vol);
1634 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
1636 WARN("Invalid volume (%"LONGFMT"d)\n", vol);
1637 return DSERR_INVALIDPARAM;
1640 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
1641 hr = DSERR_CONTROLUNAVAIL;
1642 if(SUCCEEDED(hr))
1644 ALfloat fvol = mB_to_gain(vol);
1645 setALContext(This->ctx);
1646 alSourcef(This->source, AL_GAIN, fvol);
1647 popALContext();
1650 return hr;
1653 static HRESULT WINAPI DS8Buffer_SetPan(IDirectSoundBuffer8 *iface, LONG pan)
1655 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1656 HRESULT hr = S_OK;
1658 TRACE("(%p)->(%"LONGFMT"d)\n", iface, pan);
1660 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
1662 WARN("invalid parameter: pan = %"LONGFMT"d\n", pan);
1663 return DSERR_INVALIDPARAM;
1666 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
1667 hr = DSERR_CONTROLUNAVAIL;
1668 else
1670 ALfloat pos[3];
1671 pos[0] = (pan-DSBPAN_LEFT) * 2.0 / (ALfloat)(DSBPAN_RIGHT-DSBPAN_LEFT) - 1.0;
1672 /* NOTE: Strict movement along the X plane can cause the sound to jump
1673 * between left and right sharply. Using a curved path helps smooth it
1674 * out */
1675 pos[1] = sqrt(1.0 - pos[0]*pos[0]);
1676 pos[2] = 0.0;
1678 setALContext(This->ctx);
1679 alSourcefv(This->source, AL_POSITION, pos);
1680 getALError();
1681 popALContext();
1683 if(pan != 0 && This->buffer->format.Format.nChannels > 1)
1684 FIXME("Panning for multi-channel buffers is not supported\n");
1687 return hr;
1690 static HRESULT WINAPI DS8Buffer_SetFrequency(IDirectSoundBuffer8 *iface, DWORD freq)
1692 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1693 HRESULT hr = S_OK;
1695 TRACE("(%p)->(%"LONGFMT"u)\n", iface, freq);
1697 if(freq < DSBFREQUENCY_MIN || freq > DSBFREQUENCY_MAX)
1699 WARN("invalid parameter: freq = %"LONGFMT"u\n", freq);
1700 return DSERR_INVALIDPARAM;
1703 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
1704 hr = DSERR_CONTROLUNAVAIL;
1705 else
1707 ALfloat pitch = 1.0f;
1708 if(freq != DSBFREQUENCY_ORIGINAL)
1709 pitch = freq / (ALfloat)This->buffer->format.Format.nSamplesPerSec;
1711 setALContext(This->ctx);
1712 alSourcef(This->source, AL_PITCH, pitch);
1713 getALError();
1714 popALContext();
1717 return hr;
1720 static HRESULT WINAPI DS8Buffer_Stop(IDirectSoundBuffer8 *iface)
1722 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1723 ALint state;
1725 TRACE("(%p)->()\n", iface);
1727 EnterCriticalSection(This->crst);
1728 setALContext(This->ctx);
1730 alSourcePause(This->source);
1731 getALError();
1732 /* Mac OS X doesn't immediately report state change
1733 * if Play() is immediately called after Stop, this can be fatal,
1734 * the buffer would never be restarted
1736 do {
1737 state = AL_PAUSED;
1738 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1739 if(state != AL_PLAYING)
1740 break;
1741 Sleep(1);
1742 } while(1);
1744 This->isplaying = FALSE;
1746 popALContext();
1747 LeaveCriticalSection(This->crst);
1749 return S_OK;
1752 static HRESULT WINAPI DS8Buffer_Unlock(IDirectSoundBuffer8 *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
1754 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1755 DS8Data *buf = This->buffer;
1756 DWORD bufsize = buf->buf_size;
1757 DWORD_PTR ofs1, ofs2;
1758 DWORD_PTR boundary = (DWORD_PTR)buf->data;
1759 HRESULT hr;
1761 TRACE("(%p)->(%p, %"LONGFMT"u, %p, %"LONGFMT"u)\n", iface, ptr1, len1, ptr2, len2);
1763 if(InterlockedExchange(&This->buffer->locked, FALSE) == FALSE)
1765 WARN("Not locked\n");
1766 return DSERR_INVALIDPARAM;
1769 hr = DSERR_INVALIDPARAM;
1770 /* Make sure offset is between boundary and boundary + bufsize */
1771 ofs1 = (DWORD_PTR)ptr1;
1772 ofs2 = (DWORD_PTR)ptr2;
1773 if(ofs1 < boundary)
1774 goto out;
1775 if(ofs2 && ofs2 != boundary)
1776 goto out;
1777 ofs1 -= boundary;
1778 ofs2 = 0;
1779 if(bufsize-ofs1 < len1 || len2 > ofs1)
1780 goto out;
1781 if(!ptr2)
1782 len2 = 0;
1784 hr = DS_OK;
1785 if(!len1 && !len2)
1786 goto out;
1787 if(This->primary->SupportedExt[EXT_STATIC_BUFFER])
1788 goto out;
1790 setALContext(This->ctx);
1791 if(This->primary->SupportedExt[SOFT_BUFFER_SAMPLES])
1793 const WAVEFORMATEX *format = &buf->format.Format;
1795 ptr1 = (BYTE*)ptr1 - (ofs1%format->nBlockAlign);
1796 ofs1 /= format->nBlockAlign;
1797 len1 /= format->nBlockAlign;
1798 if(len1 > 0)
1799 This->ExtAL->BufferSubSamplesSOFT(buf->buffers[0], ofs1, len1,
1800 buf->in_chans, buf->in_type, ptr1);
1801 ptr2 = (BYTE*)ptr2 - (ofs2%format->nBlockAlign);
1802 ofs2 /= format->nBlockAlign;
1803 len2 /= format->nBlockAlign;
1804 if(len2 > 0)
1805 This->ExtAL->BufferSubSamplesSOFT(buf->buffers[0], ofs2, len2,
1806 buf->in_chans, buf->in_type, ptr2);
1807 getALError();
1809 else if(This->primary->SupportedExt[SOFT_BUFFER_SUB_DATA])
1811 const WAVEFORMATEX *format = &buf->format.Format;
1813 len1 -= len1%format->nBlockAlign;
1814 if(len1 > 0)
1815 This->ExtAL->BufferSubData(buf->buffers[0], buf->buf_format, ptr1,
1816 ofs1, len1);
1817 len2 -= len2%format->nBlockAlign;
1818 if(len2 > 0)
1819 This->ExtAL->BufferSubData(buf->buffers[0], buf->buf_format, ptr2,
1820 ofs2, len2);
1821 getALError();
1823 else
1825 alBufferData(buf->buffers[0], buf->buf_format,
1826 buf->data, buf->buf_size,
1827 buf->format.Format.nSamplesPerSec);
1828 getALError();
1830 popALContext();
1832 out:
1833 if(hr != S_OK)
1834 WARN("Invalid parameters (0x%lx,%"LONGFMT"u) (%p,%"LONGFMT"u,%p,%"LONGFMT"u)\n", boundary, bufsize, ptr1, len1, ptr2, len2);
1835 return hr;
1838 static HRESULT WINAPI DS8Buffer_Restore(IDirectSoundBuffer8 *iface)
1840 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1841 HRESULT hr;
1843 TRACE("(%p)->()\n", iface);
1845 EnterCriticalSection(This->crst);
1846 if(This->primary->parent->prio_level < DSSCL_WRITEPRIMARY ||
1847 iface == This->primary->write_emu)
1849 This->bufferlost = 0;
1850 hr = S_OK;
1852 else
1853 hr = DSERR_BUFFERLOST;
1854 LeaveCriticalSection(This->crst);
1856 return hr;
1859 static HRESULT WINAPI DS8Buffer_SetFX(IDirectSoundBuffer8 *iface, DWORD fxcount, DSEFFECTDESC *desc, DWORD *rescodes)
1861 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1862 DWORD i;
1864 TRACE("(%p)->(%"LONGFMT"u, %p, %p)\n", This, fxcount, desc, rescodes);
1866 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFX))
1868 WARN("FX control not set\n");
1869 return DSERR_CONTROLUNAVAIL;
1872 if(fxcount == 0)
1874 if(desc || rescodes)
1876 WARN("Non-NULL desc and/or result pointer specified with no effects.\n");
1877 return DSERR_INVALIDPARAM;
1880 /* No effects; we can handle that */
1881 return DS_OK;
1884 if(!desc || !rescodes)
1886 WARN("NULL desc and/or result pointer specified.\n");
1887 return DSERR_INVALIDPARAM;
1890 /* We don't (currently) handle DSound effects */
1891 for(i = 0;i < fxcount;++i)
1893 FIXME("Cannot handle effect: %s\n", debugstr_guid(&desc[i].guidDSFXClass));
1894 rescodes[i] = DSFXR_FAILED;
1897 return DS_INCOMPLETE;
1900 static HRESULT WINAPI DS8Buffer_AcquireResources(IDirectSoundBuffer8 *iface, DWORD flags, DWORD fxcount, DWORD *rescodes)
1902 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1904 TRACE("(%p)->(%"LONGFMT"u, %"LONGFMT"u, %p)\n", This, flags, fxcount, rescodes);
1906 /* effects aren't supported at the moment.. */
1907 if(fxcount != 0 || rescodes)
1909 WARN("Non-zero effect count and/or result pointer specified with no effects.\n");
1910 return DSERR_INVALIDPARAM;
1913 EnterCriticalSection(This->crst);
1914 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1916 This->buffer->dsbflags &= ~(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE);
1917 if((flags&DSBPLAY_LOCSOFTWARE))
1918 This->buffer->dsbflags |= DSBCAPS_LOCSOFTWARE;
1919 else
1920 This->buffer->dsbflags |= DSBCAPS_LOCHARDWARE;
1922 LeaveCriticalSection(This->crst);
1924 return S_OK;
1927 static HRESULT WINAPI DS8Buffer_GetObjectInPath(IDirectSoundBuffer8 *iface, REFGUID guid, DWORD idx, REFGUID rguidiface, void **ppv)
1929 FIXME("(%p)->(%s, %"LONGFMT"u, %s, %p) : stub!\n", iface, debugstr_guid(guid), idx, debugstr_guid(rguidiface), ppv);
1930 return E_NOTIMPL;
1933 static const IDirectSoundBuffer8Vtbl DS8Buffer_Vtbl = {
1934 DS8Buffer_QueryInterface,
1935 DS8Buffer_AddRef,
1936 DS8Buffer_Release,
1937 DS8Buffer_GetCaps,
1938 DS8Buffer_GetCurrentPosition,
1939 DS8Buffer_GetFormat,
1940 DS8Buffer_GetVolume,
1941 DS8Buffer_GetPan,
1942 DS8Buffer_GetFrequency,
1943 DS8Buffer_GetStatus,
1944 DS8Buffer_Initialize,
1945 DS8Buffer_Lock,
1946 DS8Buffer_Play,
1947 DS8Buffer_SetCurrentPosition,
1948 DS8Buffer_SetFormat,
1949 DS8Buffer_SetVolume,
1950 DS8Buffer_SetPan,
1951 DS8Buffer_SetFrequency,
1952 DS8Buffer_Stop,
1953 DS8Buffer_Unlock,
1954 DS8Buffer_Restore,
1955 DS8Buffer_SetFX,
1956 DS8Buffer_AcquireResources,
1957 DS8Buffer_GetObjectInPath
1961 static HRESULT WINAPI DSBuffer_QueryInterface(IDirectSoundBuffer *iface, REFIID riid, void **ppv)
1963 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1964 return DS8Buffer_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
1967 static ULONG WINAPI DSBuffer_AddRef(IDirectSoundBuffer *iface)
1969 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1970 return DS8Buffer_AddRef(&This->IDirectSoundBuffer8_iface);
1973 static ULONG WINAPI DSBuffer_Release(IDirectSoundBuffer *iface)
1975 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1976 return DS8Buffer_Release(&This->IDirectSoundBuffer8_iface);
1979 static HRESULT WINAPI DSBuffer_GetCaps(IDirectSoundBuffer *iface, DSBCAPS *caps)
1981 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1982 return DS8Buffer_GetCaps(&This->IDirectSoundBuffer8_iface, caps);
1985 static HRESULT WINAPI DSBuffer_GetCurrentPosition(IDirectSoundBuffer *iface, DWORD *playpos, DWORD *curpos)
1987 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1988 return DS8Buffer_GetCurrentPosition(&This->IDirectSoundBuffer8_iface, playpos, curpos);
1991 static HRESULT WINAPI DSBuffer_GetFormat(IDirectSoundBuffer *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
1993 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1994 return DS8Buffer_GetFormat(&This->IDirectSoundBuffer8_iface, wfx, allocated, written);
1997 static HRESULT WINAPI DSBuffer_GetVolume(IDirectSoundBuffer *iface, LONG *vol)
1999 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
2000 return DS8Buffer_GetVolume(&This->IDirectSoundBuffer8_iface, vol);
2003 static HRESULT WINAPI DSBuffer_GetPan(IDirectSoundBuffer *iface, LONG *pan)
2005 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
2006 return DS8Buffer_GetPan(&This->IDirectSoundBuffer8_iface, pan);
2009 static HRESULT WINAPI DSBuffer_GetFrequency(IDirectSoundBuffer *iface, DWORD *freq)
2011 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
2012 return DS8Buffer_GetFrequency(&This->IDirectSoundBuffer8_iface, freq);
2015 static HRESULT WINAPI DSBuffer_GetStatus(IDirectSoundBuffer *iface, DWORD *status)
2017 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
2018 return DS8Buffer_GetStatus(&This->IDirectSoundBuffer8_iface, status);
2021 static HRESULT WINAPI DSBuffer_Initialize(IDirectSoundBuffer *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
2023 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
2024 return DS8Buffer_Initialize(&This->IDirectSoundBuffer8_iface, ds, desc);
2027 static HRESULT WINAPI DSBuffer_Lock(IDirectSoundBuffer *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
2029 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
2030 return DS8Buffer_Lock(&This->IDirectSoundBuffer8_iface, ofs, bytes, ptr1, len1, ptr2, len2, flags);
2033 static HRESULT WINAPI DSBuffer_Play(IDirectSoundBuffer *iface, DWORD res1, DWORD prio, DWORD flags)
2035 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
2036 return DS8Buffer_Play(&This->IDirectSoundBuffer8_iface, res1, prio, flags);
2039 static HRESULT WINAPI DSBuffer_SetCurrentPosition(IDirectSoundBuffer *iface, DWORD pos)
2041 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
2042 return DS8Buffer_SetCurrentPosition(&This->IDirectSoundBuffer8_iface, pos);
2045 static HRESULT WINAPI DSBuffer_SetFormat(IDirectSoundBuffer *iface, const WAVEFORMATEX *wfx)
2047 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
2048 return DS8Buffer_SetFormat(&This->IDirectSoundBuffer8_iface, wfx);
2051 static HRESULT WINAPI DSBuffer_SetVolume(IDirectSoundBuffer *iface, LONG vol)
2053 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
2054 return DS8Buffer_SetVolume(&This->IDirectSoundBuffer8_iface, vol);
2057 static HRESULT WINAPI DSBuffer_SetPan(IDirectSoundBuffer *iface, LONG pan)
2059 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
2060 return DS8Buffer_SetPan(&This->IDirectSoundBuffer8_iface, pan);
2063 static HRESULT WINAPI DSBuffer_SetFrequency(IDirectSoundBuffer *iface, DWORD freq)
2065 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
2066 return DS8Buffer_SetFrequency(&This->IDirectSoundBuffer8_iface, freq);
2069 static HRESULT WINAPI DSBuffer_Stop(IDirectSoundBuffer *iface)
2071 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
2072 return DS8Buffer_Stop(&This->IDirectSoundBuffer8_iface);
2075 static HRESULT WINAPI DSBuffer_Unlock(IDirectSoundBuffer *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
2077 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
2078 return DS8Buffer_Unlock(&This->IDirectSoundBuffer8_iface, ptr1, len1, ptr2, len2);
2081 static HRESULT WINAPI DSBuffer_Restore(IDirectSoundBuffer *iface)
2083 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
2084 return DS8Buffer_Restore(&This->IDirectSoundBuffer8_iface);
2087 static const IDirectSoundBufferVtbl DSBuffer_Vtbl = {
2088 DSBuffer_QueryInterface,
2089 DSBuffer_AddRef,
2090 DSBuffer_Release,
2091 DSBuffer_GetCaps,
2092 DSBuffer_GetCurrentPosition,
2093 DSBuffer_GetFormat,
2094 DSBuffer_GetVolume,
2095 DSBuffer_GetPan,
2096 DSBuffer_GetFrequency,
2097 DSBuffer_GetStatus,
2098 DSBuffer_Initialize,
2099 DSBuffer_Lock,
2100 DSBuffer_Play,
2101 DSBuffer_SetCurrentPosition,
2102 DSBuffer_SetFormat,
2103 DSBuffer_SetVolume,
2104 DSBuffer_SetPan,
2105 DSBuffer_SetFrequency,
2106 DSBuffer_Stop,
2107 DSBuffer_Unlock,
2108 DSBuffer_Restore
2112 static HRESULT WINAPI DS8Buffer3D_QueryInterface(IDirectSound3DBuffer *iface, REFIID riid, void **ppv)
2114 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2115 return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2118 static ULONG WINAPI DS8Buffer3D_AddRef(IDirectSound3DBuffer *iface)
2120 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2121 LONG ret;
2123 InterlockedIncrement(&This->all_ref);
2124 ret = InterlockedIncrement(&This->ds3d_ref);
2125 TRACE("new refcount %"LONGFMT"d\n", ret);
2127 return ret;
2130 static ULONG WINAPI DS8Buffer3D_Release(IDirectSound3DBuffer *iface)
2132 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2133 LONG ret;
2135 ret = InterlockedDecrement(&This->ds3d_ref);
2136 TRACE("new refcount %"LONGFMT"d\n", ret);
2137 if(InterlockedDecrement(&This->all_ref) == 0)
2138 DS8Buffer_Destroy(This);
2140 return ret;
2143 static HRESULT WINAPI DS8Buffer3D_GetAllParameters(IDirectSound3DBuffer *iface, DS3DBUFFER *ds3dbuffer)
2145 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2146 DS3DBUFFER ds3dbuf;
2147 HRESULT hr;
2149 TRACE("%p\n", This);
2151 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
2153 WARN("Invalid parameters %p %"LONGFMT"u\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
2154 return DSERR_INVALIDPARAM;
2156 ds3dbuf.dwSize = sizeof(ds3dbuf);
2158 EnterCriticalSection(This->crst);
2159 setALContext(This->ctx);
2161 hr = IDirectSound3DBuffer_GetPosition(iface, &ds3dbuf.vPosition);
2162 if(SUCCEEDED(hr))
2163 hr = IDirectSound3DBuffer_GetVelocity(iface, &ds3dbuf.vVelocity);
2164 if(SUCCEEDED(hr))
2165 hr = IDirectSound3DBuffer_GetConeAngles(iface, &ds3dbuf.dwInsideConeAngle, &ds3dbuf.dwOutsideConeAngle);
2166 if(SUCCEEDED(hr))
2167 hr = IDirectSound3DBuffer_GetConeOrientation(iface, &ds3dbuf.vConeOrientation);
2168 if(SUCCEEDED(hr))
2169 hr = IDirectSound3DBuffer_GetConeOutsideVolume(iface, &ds3dbuf.lConeOutsideVolume);
2170 if(SUCCEEDED(hr))
2171 hr = IDirectSound3DBuffer_GetMinDistance(iface, &ds3dbuf.flMinDistance);
2172 if(SUCCEEDED(hr))
2173 hr = IDirectSound3DBuffer_GetMaxDistance(iface, &ds3dbuf.flMaxDistance);
2174 if(SUCCEEDED(hr))
2175 hr = IDirectSound3DBuffer_GetMode(iface, &ds3dbuf.dwMode);
2176 if(SUCCEEDED(hr))
2177 memcpy(ds3dbuffer, &ds3dbuf, sizeof(ds3dbuf));
2179 popALContext();
2180 LeaveCriticalSection(This->crst);
2182 return hr;
2185 static HRESULT WINAPI DS8Buffer3D_GetConeAngles(IDirectSound3DBuffer *iface, DWORD *pdwInsideConeAngle, DWORD *pdwOutsideConeAngle)
2187 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2188 ALint inangle, outangle;
2190 TRACE("(%p)->(%p, %p)\n", This, pdwInsideConeAngle, pdwOutsideConeAngle);
2191 if(!pdwInsideConeAngle || !pdwOutsideConeAngle)
2193 WARN("Invalid pointers (%p, %p)\n", pdwInsideConeAngle, pdwOutsideConeAngle);
2194 return DSERR_INVALIDPARAM;
2197 EnterCriticalSection(This->crst);
2198 setALContext(This->ctx);
2200 alGetSourcei(This->source, AL_CONE_INNER_ANGLE, &inangle);
2201 alGetSourcei(This->source, AL_CONE_OUTER_ANGLE, &outangle);
2202 getALError();
2203 *pdwInsideConeAngle = inangle;
2204 *pdwOutsideConeAngle = outangle;
2206 popALContext();
2207 LeaveCriticalSection(This->crst);
2209 return S_OK;
2212 static HRESULT WINAPI DS8Buffer3D_GetConeOrientation(IDirectSound3DBuffer *iface, D3DVECTOR *orient)
2214 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2215 ALfloat dir[3];
2217 TRACE("(%p)->(%p)\n", This, orient);
2218 if(!orient)
2220 WARN("Invalid pointer\n");
2221 return DSERR_INVALIDPARAM;
2224 EnterCriticalSection(This->crst);
2225 setALContext(This->ctx);
2227 alGetSourcefv(This->source, AL_DIRECTION, dir);
2228 getALError();
2229 orient->x = dir[0];
2230 orient->y = dir[1];
2231 orient->z = -dir[2];
2233 popALContext();
2234 LeaveCriticalSection(This->crst);
2236 return S_OK;
2239 static HRESULT WINAPI DS8Buffer3D_GetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG *vol)
2241 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2242 ALfloat gain;
2244 TRACE("(%p)->(%p)\n", This, vol);
2245 if(!vol)
2247 WARN("Invalid pointer\n");
2248 return DSERR_INVALIDPARAM;
2251 EnterCriticalSection(This->crst);
2252 setALContext(This->ctx);
2254 alGetSourcef(This->source, AL_CONE_OUTER_GAIN, &gain);
2255 getALError();
2257 popALContext();
2258 LeaveCriticalSection(This->crst);
2260 *vol = clampI(gain_to_mB(gain), DSBVOLUME_MIN, DSBVOLUME_MAX);
2261 return S_OK;
2264 static HRESULT WINAPI DS8Buffer3D_GetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE *maxdist)
2266 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2267 ALfloat dist;
2269 TRACE("(%p)->(%p)\n", This, maxdist);
2270 if(!maxdist)
2272 WARN("Invalid pointer\n");
2273 return DSERR_INVALIDPARAM;
2276 EnterCriticalSection(This->crst);
2277 setALContext(This->ctx);
2279 alGetSourcef(This->source, AL_MAX_DISTANCE, &dist);
2280 getALError();
2282 popALContext();
2283 LeaveCriticalSection(This->crst);
2285 *maxdist = dist;
2286 return S_OK;
2289 static HRESULT WINAPI DS8Buffer3D_GetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE *mindist)
2291 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2292 ALfloat dist;
2294 TRACE("(%p)->(%p)\n", This, mindist);
2295 if(!mindist)
2297 WARN("Invalid pointer\n");
2298 return DSERR_INVALIDPARAM;
2301 EnterCriticalSection(This->crst);
2302 setALContext(This->ctx);
2304 alGetSourcef(This->source, AL_REFERENCE_DISTANCE, &dist);
2305 getALError();
2306 *mindist = dist;
2308 popALContext();
2309 LeaveCriticalSection(This->crst);
2311 return S_OK;
2314 static HRESULT WINAPI DS8Buffer3D_GetMode(IDirectSound3DBuffer *iface, DWORD *mode)
2316 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2318 TRACE("(%p)->(%p)\n", This, mode);
2319 if(!mode)
2321 WARN("Invalid pointer\n");
2322 return DSERR_INVALIDPARAM;
2325 EnterCriticalSection(This->crst);
2326 *mode = This->ds3dmode;
2327 LeaveCriticalSection(This->crst);
2329 return S_OK;
2332 static HRESULT WINAPI DS8Buffer3D_GetPosition(IDirectSound3DBuffer *iface, D3DVECTOR *pos)
2334 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2335 ALfloat alpos[3];
2337 TRACE("(%p)->(%p)\n", This, pos);
2338 if(!pos)
2340 WARN("Invalid pointer\n");
2341 return DSERR_INVALIDPARAM;
2344 EnterCriticalSection(This->crst);
2345 setALContext(This->ctx);
2347 alGetSourcefv(This->source, AL_POSITION, alpos);
2348 getALError();
2349 pos->x = alpos[0];
2350 pos->y = alpos[1];
2351 pos->z = -alpos[2];
2353 popALContext();
2354 LeaveCriticalSection(This->crst);
2356 return S_OK;
2359 static HRESULT WINAPI DS8Buffer3D_GetVelocity(IDirectSound3DBuffer *iface, D3DVECTOR *vel)
2361 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2362 ALfloat alvel[3];
2364 TRACE("(%p)->(%p)\n", This, vel);
2365 if(!vel)
2367 WARN("Invalid pointer\n");
2368 return DSERR_INVALIDPARAM;
2371 EnterCriticalSection(This->crst);
2372 setALContext(This->ctx);
2374 alGetSourcefv(This->source, AL_VELOCITY, alvel);
2375 getALError();
2376 vel->x = alvel[0];
2377 vel->y = alvel[1];
2378 vel->z = -alvel[2];
2380 popALContext();
2381 LeaveCriticalSection(This->crst);
2383 return S_OK;
2386 static HRESULT WINAPI DS8Buffer3D_SetAllParameters(IDirectSound3DBuffer *iface, const DS3DBUFFER *ds3dbuffer, DWORD apply)
2388 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2389 TRACE("(%p)->(%p, %"LONGFMT"u)\n", This, ds3dbuffer, apply);
2391 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
2393 WARN("Invalid DS3DBUFFER (%p, %"LONGFMT"u)\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
2394 return DSERR_INVALIDPARAM;
2397 if(ds3dbuffer->dwInsideConeAngle > DS3D_MAXCONEANGLE ||
2398 ds3dbuffer->dwOutsideConeAngle > DS3D_MAXCONEANGLE)
2400 WARN("Invalid cone angles (%"LONGFMT"u, %"LONGFMT"u)\n", ds3dbuffer->dwInsideConeAngle,
2401 ds3dbuffer->dwOutsideConeAngle);
2402 return DSERR_INVALIDPARAM;
2405 if(ds3dbuffer->lConeOutsideVolume > DSBVOLUME_MAX ||
2406 ds3dbuffer->lConeOutsideVolume < DSBVOLUME_MIN)
2408 WARN("Invalid cone outside volume (%"LONGFMT"d)\n", ds3dbuffer->lConeOutsideVolume);
2409 return DSERR_INVALIDPARAM;
2412 if(ds3dbuffer->flMaxDistance < 0.0f)
2414 WARN("Invalid max distance (%f)\n", ds3dbuffer->flMaxDistance);
2415 return DSERR_INVALIDPARAM;
2418 if(ds3dbuffer->flMinDistance < 0.0f)
2420 WARN("Invalid min distance (%f)\n", ds3dbuffer->flMinDistance);
2421 return DSERR_INVALIDPARAM;
2424 if(ds3dbuffer->dwMode != DS3DMODE_NORMAL &&
2425 ds3dbuffer->dwMode != DS3DMODE_HEADRELATIVE &&
2426 ds3dbuffer->dwMode != DS3DMODE_DISABLE)
2428 WARN("Invalid mode (%"LONGFMT"u)\n", ds3dbuffer->dwMode);
2429 return DSERR_INVALIDPARAM;
2432 EnterCriticalSection(This->crst);
2433 setALContext(This->ctx);
2434 IDirectSound3DBuffer_SetPosition(iface, ds3dbuffer->vPosition.x, ds3dbuffer->vPosition.y, ds3dbuffer->vPosition.z, apply);
2435 IDirectSound3DBuffer_SetVelocity(iface, ds3dbuffer->vVelocity.x, ds3dbuffer->vVelocity.y, ds3dbuffer->vVelocity.z, apply);
2436 IDirectSound3DBuffer_SetConeAngles(iface, ds3dbuffer->dwInsideConeAngle, ds3dbuffer->dwOutsideConeAngle, apply);
2437 IDirectSound3DBuffer_SetConeOrientation(iface, ds3dbuffer->vConeOrientation.x, ds3dbuffer->vConeOrientation.y, ds3dbuffer->vConeOrientation.z, apply);
2438 IDirectSound3DBuffer_SetConeOutsideVolume(iface, ds3dbuffer->lConeOutsideVolume, apply);
2439 IDirectSound3DBuffer_SetMinDistance(iface, ds3dbuffer->flMinDistance, apply);
2440 IDirectSound3DBuffer_SetMaxDistance(iface, ds3dbuffer->flMaxDistance, apply);
2441 IDirectSound3DBuffer_SetMode(iface, ds3dbuffer->dwMode, apply);
2442 popALContext();
2443 LeaveCriticalSection(This->crst);
2445 return S_OK;
2448 static HRESULT WINAPI DS8Buffer3D_SetConeAngles(IDirectSound3DBuffer *iface, DWORD dwInsideConeAngle, DWORD dwOutsideConeAngle, DWORD apply)
2450 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2452 TRACE("(%p)->(%"LONGFMT"u, %"LONGFMT"u, %"LONGFMT"u)\n", This, dwInsideConeAngle, dwOutsideConeAngle, apply);
2453 if(dwInsideConeAngle > DS3D_MAXCONEANGLE ||
2454 dwOutsideConeAngle > DS3D_MAXCONEANGLE)
2456 WARN("Invalid cone angles (%"LONGFMT"u, %"LONGFMT"u)\n", dwInsideConeAngle, dwOutsideConeAngle);
2457 return DSERR_INVALIDPARAM;
2460 EnterCriticalSection(This->crst);
2461 if(apply == DS3D_DEFERRED)
2463 This->ds3dbuffer.dwInsideConeAngle = dwInsideConeAngle;
2464 This->ds3dbuffer.dwOutsideConeAngle = dwOutsideConeAngle;
2465 This->dirty.bit.cone_angles = 1;
2467 else
2469 setALContext(This->ctx);
2470 alSourcei(This->source, AL_CONE_INNER_ANGLE, dwInsideConeAngle);
2471 alSourcei(This->source, AL_CONE_OUTER_ANGLE, dwOutsideConeAngle);
2472 getALError();
2473 popALContext();
2475 LeaveCriticalSection(This->crst);
2477 return S_OK;
2480 static HRESULT WINAPI DS8Buffer3D_SetConeOrientation(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2482 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2484 TRACE("(%p)->(%f, %f, %f, %"LONGFMT"u)\n", This, x, y, z, apply);
2486 EnterCriticalSection(This->crst);
2487 if(apply == DS3D_DEFERRED)
2489 This->ds3dbuffer.vConeOrientation.x = x;
2490 This->ds3dbuffer.vConeOrientation.y = y;
2491 This->ds3dbuffer.vConeOrientation.z = z;
2492 This->dirty.bit.cone_orient = 1;
2494 else
2496 setALContext(This->ctx);
2497 alSource3f(This->source, AL_DIRECTION, x, y, -z);
2498 getALError();
2499 popALContext();
2501 LeaveCriticalSection(This->crst);
2503 return S_OK;
2506 static HRESULT WINAPI DS8Buffer3D_SetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG vol, DWORD apply)
2508 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2510 TRACE("(%p)->(%"LONGFMT"d, %"LONGFMT"u)\n", This, vol, apply);
2511 if(vol < DSBVOLUME_MIN || vol > DSBVOLUME_MAX)
2513 WARN("Invalid volume (%"LONGFMT"d)\n", vol);
2514 return DSERR_INVALIDPARAM;
2517 EnterCriticalSection(This->crst);
2518 if(apply == DS3D_DEFERRED)
2520 This->ds3dbuffer.lConeOutsideVolume = vol;
2521 This->dirty.bit.cone_outsidevolume = 1;
2523 else
2525 setALContext(This->ctx);
2526 alSourcef(This->source, AL_CONE_OUTER_GAIN, mB_to_gain(vol));
2527 getALError();
2528 popALContext();
2530 LeaveCriticalSection(This->crst);
2532 return S_OK;
2535 static HRESULT WINAPI DS8Buffer3D_SetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE maxdist, DWORD apply)
2537 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2539 TRACE("(%p)->(%f, %"LONGFMT"u)\n", This, maxdist, apply);
2540 if(maxdist < 0.0f)
2542 WARN("Invalid max distance (%f)\n", maxdist);
2543 return DSERR_INVALIDPARAM;
2546 EnterCriticalSection(This->crst);
2547 if(apply == DS3D_DEFERRED)
2549 This->ds3dbuffer.flMaxDistance = maxdist;
2550 This->dirty.bit.max_distance = 1;
2552 else
2554 setALContext(This->ctx);
2555 alSourcef(This->source, AL_MAX_DISTANCE, maxdist);
2556 getALError();
2557 popALContext();
2559 LeaveCriticalSection(This->crst);
2561 return S_OK;
2564 static HRESULT WINAPI DS8Buffer3D_SetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE mindist, DWORD apply)
2566 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2568 TRACE("(%p)->(%f, %"LONGFMT"u)\n", This, mindist, apply);
2569 if(mindist < 0.0f)
2571 WARN("Invalid min distance (%f)\n", mindist);
2572 return DSERR_INVALIDPARAM;
2575 EnterCriticalSection(This->crst);
2576 if(apply == DS3D_DEFERRED)
2578 This->ds3dbuffer.flMinDistance = mindist;
2579 This->dirty.bit.min_distance = 1;
2581 else
2583 setALContext(This->ctx);
2584 alSourcef(This->source, AL_REFERENCE_DISTANCE, mindist);
2585 getALError();
2586 popALContext();
2588 LeaveCriticalSection(This->crst);
2590 return S_OK;
2593 static HRESULT WINAPI DS8Buffer3D_SetMode(IDirectSound3DBuffer *iface, DWORD mode, DWORD apply)
2595 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2597 TRACE("(%p)->(%"LONGFMT"u, %"LONGFMT"u)\n", This, mode, apply);
2598 if(mode != DS3DMODE_NORMAL && mode != DS3DMODE_HEADRELATIVE &&
2599 mode != DS3DMODE_DISABLE)
2601 WARN("Invalid mode (%"LONGFMT"u)\n", mode);
2602 return DSERR_INVALIDPARAM;
2605 EnterCriticalSection(This->crst);
2606 if(apply == DS3D_DEFERRED)
2608 This->ds3dbuffer.dwMode = mode;
2609 This->dirty.bit.mode = 1;
2611 else
2613 setALContext(This->ctx);
2614 alSourcei(This->source, AL_SOURCE_RELATIVE,
2615 (mode != DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE);
2616 alSourcef(This->source, AL_ROLLOFF_FACTOR,
2617 (mode == DS3DMODE_DISABLE) ? 0.0f : This->primary->rollofffactor);
2618 This->ds3dmode = mode;
2619 getALError();
2620 popALContext();
2622 LeaveCriticalSection(This->crst);
2624 return S_OK;
2627 static HRESULT WINAPI DS8Buffer3D_SetPosition(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2629 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2631 TRACE("(%p)->(%f, %f, %f, %"LONGFMT"u)\n", This, x, y, z, apply);
2633 EnterCriticalSection(This->crst);
2634 if(apply == DS3D_DEFERRED)
2636 This->ds3dbuffer.vPosition.x = x;
2637 This->ds3dbuffer.vPosition.y = y;
2638 This->ds3dbuffer.vPosition.z = z;
2639 This->dirty.bit.pos = 1;
2641 else
2643 setALContext(This->ctx);
2644 alSource3f(This->source, AL_POSITION, x, y, -z);
2645 getALError();
2646 popALContext();
2648 LeaveCriticalSection(This->crst);
2650 return S_OK;
2653 static HRESULT WINAPI DS8Buffer3D_SetVelocity(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2655 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2657 TRACE("(%p)->(%f, %f, %f, %"LONGFMT"u)\n", This, x, y, z, apply);
2659 EnterCriticalSection(This->crst);
2660 if(apply == DS3D_DEFERRED)
2662 This->ds3dbuffer.vVelocity.x = x;
2663 This->ds3dbuffer.vVelocity.y = y;
2664 This->ds3dbuffer.vVelocity.z = z;
2665 This->dirty.bit.vel = 1;
2667 else
2669 setALContext(This->ctx);
2670 alSource3f(This->source, AL_VELOCITY, x, y, -z);
2671 getALError();
2672 popALContext();
2674 LeaveCriticalSection(This->crst);
2676 return S_OK;
2679 static const IDirectSound3DBufferVtbl DS8Buffer3d_Vtbl =
2681 DS8Buffer3D_QueryInterface,
2682 DS8Buffer3D_AddRef,
2683 DS8Buffer3D_Release,
2684 DS8Buffer3D_GetAllParameters,
2685 DS8Buffer3D_GetConeAngles,
2686 DS8Buffer3D_GetConeOrientation,
2687 DS8Buffer3D_GetConeOutsideVolume,
2688 DS8Buffer3D_GetMaxDistance,
2689 DS8Buffer3D_GetMinDistance,
2690 DS8Buffer3D_GetMode,
2691 DS8Buffer3D_GetPosition,
2692 DS8Buffer3D_GetVelocity,
2693 DS8Buffer3D_SetAllParameters,
2694 DS8Buffer3D_SetConeAngles,
2695 DS8Buffer3D_SetConeOrientation,
2696 DS8Buffer3D_SetConeOutsideVolume,
2697 DS8Buffer3D_SetMaxDistance,
2698 DS8Buffer3D_SetMinDistance,
2699 DS8Buffer3D_SetMode,
2700 DS8Buffer3D_SetPosition,
2701 DS8Buffer3D_SetVelocity
2705 static HRESULT WINAPI DS8BufferNot_QueryInterface(IDirectSoundNotify *iface, REFIID riid, void **ppv)
2707 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2708 return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2711 static ULONG WINAPI DS8BufferNot_AddRef(IDirectSoundNotify *iface)
2713 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2714 LONG ret;
2716 InterlockedIncrement(&This->all_ref);
2717 ret = InterlockedIncrement(&This->not_ref);
2718 TRACE("new refcount %"LONGFMT"d\n", ret);
2720 return ret;
2723 static ULONG WINAPI DS8BufferNot_Release(IDirectSoundNotify *iface)
2725 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2726 LONG ret;
2728 ret = InterlockedDecrement(&This->not_ref);
2729 TRACE("new refcount %"LONGFMT"d\n", ret);
2730 if(InterlockedDecrement(&This->all_ref) == 0)
2731 DS8Buffer_Destroy(This);
2733 return ret;
2736 static HRESULT WINAPI DS8BufferNot_SetNotificationPositions(IDirectSoundNotify *iface, DWORD count, const DSBPOSITIONNOTIFY *notifications)
2738 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2739 DSBPOSITIONNOTIFY *nots;
2740 DWORD state;
2741 HRESULT hr;
2743 EnterCriticalSection(This->crst);
2744 hr = DSERR_INVALIDPARAM;
2745 if(count && !notifications)
2746 goto out;
2748 hr = IDirectSoundBuffer8_GetStatus(&This->IDirectSoundBuffer8_iface, &state);
2749 if(FAILED(hr))
2750 goto out;
2752 hr = DSERR_INVALIDCALL;
2753 if((state&DSBSTATUS_PLAYING))
2754 goto out;
2756 if(!count)
2758 HeapFree(GetProcessHeap(), 0, This->notify);
2759 This->notify = 0;
2760 This->nnotify = 0;
2761 hr = S_OK;
2763 else
2765 DWORD i;
2767 hr = DSERR_INVALIDPARAM;
2768 for(i = 0;i < count;++i)
2770 if(notifications[i].dwOffset >= This->buffer->buf_size &&
2771 notifications[i].dwOffset != (DWORD)DSBPN_OFFSETSTOP)
2772 goto out;
2775 hr = E_OUTOFMEMORY;
2776 nots = HeapAlloc(GetProcessHeap(), 0, count*sizeof(*nots));
2777 if(!nots)
2778 goto out;
2779 memcpy(nots, notifications, count*sizeof(*nots));
2781 HeapFree(GetProcessHeap(), 0, This->notify);
2782 This->notify = nots;
2783 This->nnotify = count;
2785 hr = S_OK;
2788 out:
2789 LeaveCriticalSection(This->crst);
2790 return hr;
2793 static const IDirectSoundNotifyVtbl DS8BufferNot_Vtbl =
2795 DS8BufferNot_QueryInterface,
2796 DS8BufferNot_AddRef,
2797 DS8BufferNot_Release,
2798 DS8BufferNot_SetNotificationPositions
2802 static HRESULT WINAPI DS8BufferProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
2804 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2805 return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2808 static ULONG WINAPI DS8BufferProp_AddRef(IKsPropertySet *iface)
2810 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2811 LONG ret;
2813 InterlockedIncrement(&This->all_ref);
2814 ret = InterlockedIncrement(&This->prop_ref);
2815 TRACE("new refcount %"LONGFMT"d\n", ret);
2817 return ret;
2820 static ULONG WINAPI DS8BufferProp_Release(IKsPropertySet *iface)
2822 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2823 LONG ret;
2825 ret = InterlockedDecrement(&This->prop_ref);
2826 TRACE("new refcount %"LONGFMT"d\n", ret);
2827 if(InterlockedDecrement(&This->all_ref) == 0)
2828 DS8Buffer_Destroy(This);
2830 return ret;
2833 /* NOTE: Due to some apparent quirks in DSound, the listener properties are
2834 handled through secondary buffers. */
2835 static HRESULT WINAPI DS8BufferProp_Get(IKsPropertySet *iface,
2836 REFGUID guidPropSet, ULONG dwPropID,
2837 LPVOID pInstanceData, ULONG cbInstanceData,
2838 LPVOID pPropData, ULONG cbPropData,
2839 PULONG pcbReturned)
2841 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2842 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2844 TRACE("(%p)->(%s, %"LONGFMT"u, %p, %"LONGFMT"u, %p, %"LONGFMT"u, %p)\n", iface, debugstr_guid(guidPropSet),
2845 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData, pcbReturned);
2847 if(!pcbReturned)
2848 return E_POINTER;
2849 *pcbReturned = 0;
2851 #if 0
2852 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2855 else
2856 #endif
2858 /* Not a known buffer/source property. Pass it to the listener */
2859 hr = IKsPropertySet_Get(&This->primary->IKsPropertySet_iface, guidPropSet,
2860 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData,
2861 pcbReturned);
2864 return hr;
2867 static HRESULT WINAPI DS8BufferProp_Set(IKsPropertySet *iface,
2868 REFGUID guidPropSet, ULONG dwPropID,
2869 LPVOID pInstanceData, ULONG cbInstanceData,
2870 LPVOID pPropData, ULONG cbPropData)
2872 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2873 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2875 TRACE("(%p)->(%s, %"LONGFMT"u, %p, %"LONGFMT"u, %p, %"LONGFMT"u)\n", iface, debugstr_guid(guidPropSet),
2876 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData);
2878 #if 0
2879 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2882 else
2883 #endif
2885 /* Not a known buffer/source property. Pass it to the listener */
2886 hr = IKsPropertySet_Set(&This->primary->IKsPropertySet_iface, guidPropSet,
2887 dwPropID, pInstanceData, cbInstanceData, pPropData,
2888 cbPropData);
2891 return hr;
2894 static HRESULT WINAPI DS8BufferProp_QuerySupport(IKsPropertySet *iface,
2895 REFGUID guidPropSet, ULONG dwPropID,
2896 PULONG pTypeSupport)
2898 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2899 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2901 TRACE("(%p)->(%s, %"LONGFMT"u, %p)\n", iface, debugstr_guid(guidPropSet), dwPropID, pTypeSupport);
2903 if(!pTypeSupport)
2904 return E_POINTER;
2905 *pTypeSupport = 0;
2907 #if 0
2908 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2911 else
2912 #endif
2914 /* Not a known buffer/source property. Pass it to the listener */
2915 hr = IKsPropertySet_QuerySupport(&This->primary->IKsPropertySet_iface,
2916 guidPropSet, dwPropID, pTypeSupport);
2919 return hr;
2922 static const IKsPropertySetVtbl DS8BufferProp_Vtbl =
2924 DS8BufferProp_QueryInterface,
2925 DS8BufferProp_AddRef,
2926 DS8BufferProp_Release,
2927 DS8BufferProp_Get,
2928 DS8BufferProp_Set,
2929 DS8BufferProp_QuerySupport