Remove some locks
[wine/multimedia.git] / buffer.c
blob4187f222db3c28af1cf0bdd384f2bd68dc969d54
1 /* DirectSound COM interface
3 * Copyright 2009 Maarten Lankhorst
5 * Some code taken from the original dsound-openal implementation
6 * Copyright 2007-2009 Chris Robinson
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <stdarg.h>
25 #ifdef __WINESRC__
27 #define COBJMACROS
28 #define NONAMELESSSTRUCT
29 #define NONAMELESSUNION
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winuser.h"
33 #include "winnls.h"
34 #include "winreg.h"
35 #include "vfwmsgs.h"
36 #include "mmsystem.h"
37 #include "winternl.h"
38 #include "mmddk.h"
39 #include "wine/debug.h"
40 #include "dsound.h"
42 #include "dsound_private.h"
44 #include "ks.h"
45 #include "ksmedia.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
49 #else
51 #define WINVER 0x0600
52 #define INITGUID
53 #include <windows.h>
54 #include <dsound.h>
56 #include "dsound_private.h"
58 DEFINE_GUID(CLSID_DirectSoundPrivate,0x11ab3ec0,0x25ec,0x11d1,0xa4,0xd8,0x00,0xc0,0x4f,0xc2,0x8a,0xca);
60 DEFINE_GUID(DSPROPSETID_DirectSoundDevice,0x84624f82,0x25ec,0x11d1,0xa4,0xd8,0x00,0xc0,0x4f,0xc2,0x8a,0xca);
62 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
63 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
65 #ifndef E_PROP_ID_UNSUPPORTED
66 #define E_PROP_ID_UNSUPPORTED ((HRESULT)0x80070490)
67 #endif
69 #endif
71 #ifndef WAVE_FORMAT_IEEE_FLOAT
72 #define WAVE_FORMAT_IEEE_FLOAT 3
73 #endif
75 /* TODO: when bufferlost is set, return from all calls except initialize with
76 * DSERR_BUFFERLOST
78 static const IDirectSoundBuffer8Vtbl DS8Buffer_Vtbl;
79 static const IDirectSound3DBufferVtbl DS8Buffer3d_Vtbl;
80 static const IDirectSoundNotifyVtbl DS8BufferNot_Vtbl;
81 static const IKsPropertySetVtbl DS8BufferProp_Vtbl;
84 static inline DS8Buffer *impl_from_IDirectSoundBuffer8(IDirectSoundBuffer8 *iface)
86 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSoundBuffer8_iface);
88 /* Shares the same vtable */
89 static inline DS8Buffer *impl_from_IDirectSoundBuffer(IDirectSoundBuffer *iface)
91 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSoundBuffer8_iface);
94 static inline DS8Buffer *impl_from_IDirectSound3DBuffer(IDirectSound3DBuffer *iface)
96 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSound3DBuffer_iface);
99 static inline DS8Buffer *impl_from_IDirectSoundNotify(IDirectSoundNotify *iface)
101 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSoundNotify_iface);
104 static inline DS8Buffer *impl_from_IKsPropertySet(IKsPropertySet *iface)
106 return CONTAINING_RECORD(iface, DS8Buffer, IKsPropertySet_iface);
110 static void CALLBACK DS8Buffer_timer(UINT timerID, UINT msg, DWORD_PTR dwUser,
111 DWORD_PTR dw1, DWORD_PTR dw2)
113 (void)timerID;
114 (void)msg;
115 (void)dw1;
116 (void)dw2;
117 PostThreadMessageA(dwUser, WM_USER, 0, 0);
120 static void DS8Buffer_starttimer(DS8Primary *prim)
122 DWORD triggertime, res = DS_TIME_RES;
123 ALint refresh = FAKE_REFRESH_COUNT;
124 TIMECAPS time;
126 if(prim->timer_id)
127 return;
129 timeGetDevCaps(&time, sizeof(TIMECAPS));
131 alcGetIntegerv(prim->parent->device, ALC_REFRESH, 1, &refresh);
132 getALCError(prim->parent->device);
134 triggertime = 1000 / refresh / 2;
135 if(triggertime < time.wPeriodMin)
136 triggertime = time.wPeriodMin;
137 TRACE("Calling timer every %u ms for %i refreshes per second\n", triggertime, refresh);
139 if (res < time.wPeriodMin)
140 res = time.wPeriodMin;
141 if (timeBeginPeriod(res) == TIMERR_NOCANDO)
142 WARN("Could not set minimum resolution, don't expect sound\n");
144 prim->timer_res = res;
145 prim->timer_id = timeSetEvent(triggertime, res, DS8Buffer_timer, prim->thread_id, TIME_PERIODIC|TIME_KILL_SYNCHRONOUS);
148 /* Should be called with critsect held and context set.. */
149 static void DS8Buffer_addnotify(DS8Buffer *buf)
151 DS8Buffer **list;
152 DWORD i;
154 list = buf->primary->notifies;
155 for(i = 0; i < buf->primary->nnotifies; ++i)
157 if(buf == list[i])
159 ERR("Buffer %p already in notification list\n", buf);
160 return;
163 if(buf->primary->nnotifies == buf->primary->sizenotifies)
165 list = HeapReAlloc(GetProcessHeap(), 0, list, (buf->primary->nnotifies + 1) * sizeof(*list));
166 if(!list)
167 return;
168 buf->primary->sizenotifies++;
170 list[buf->primary->nnotifies++] = buf;
171 buf->primary->notifies = list;
175 static const char *get_fmtstr_PCM(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out)
177 out->Format = *format;
178 out->Format.cbSize = 0;
180 if(out->Format.nChannels != 1 && out->Format.nChannels != 2 &&
181 !prim->SupportedExt[EXT_MCFORMATS])
183 WARN("Multi-channel not available\n");
184 return NULL;
187 if(format->wBitsPerSample == 8)
189 switch(format->nChannels)
191 case 1: return "AL_FORMAT_MONO8";
192 case 2: return "AL_FORMAT_STEREO8";
193 case 4: return "AL_FORMAT_QUAD8";
194 case 6: return "AL_FORMAT_51CHN8";
195 case 7: return "AL_FORMAT_61CHN8";
196 case 8: return "AL_FORMAT_71CHN8";
199 else if(format->wBitsPerSample == 16)
201 switch(format->nChannels)
203 case 1: return "AL_FORMAT_MONO16";
204 case 2: return "AL_FORMAT_STEREO16";
205 case 4: return "AL_FORMAT_QUAD16";
206 case 6: return "AL_FORMAT_51CHN16";
207 case 7: return "AL_FORMAT_61CHN16";
208 case 8: return "AL_FORMAT_71CHN16";
212 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
213 format->wBitsPerSample, format->nChannels);
214 return NULL;
216 static ALenum get_fmt_PCM(const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out, ALenum *in_chans, ALenum *in_type)
218 out->Format = *format;
219 out->Format.cbSize = 0;
221 if(format->wBitsPerSample == 8)
223 *in_type = AL_UNSIGNED_BYTE;
224 switch(format->nChannels)
226 case 1: *in_chans = AL_MONO;
227 return AL_MONO8;
228 case 2: *in_chans = AL_STEREO;
229 return AL_STEREO8;
230 case 4: *in_chans = AL_QUAD;
231 return AL_QUAD8;
232 case 6: *in_chans = AL_5POINT1;
233 return AL_5POINT1_8;
234 case 7: *in_chans = AL_6POINT1;
235 return AL_6POINT1_8;
236 case 8: *in_chans = AL_7POINT1;
237 return AL_7POINT1_8;
240 else if(format->wBitsPerSample == 16)
242 *in_type = AL_SHORT;
243 switch(format->nChannels)
245 case 1: *in_chans = AL_MONO;
246 return AL_MONO16;
247 case 2: *in_chans = AL_STEREO;
248 return AL_STEREO16;
249 case 4: *in_chans = AL_QUAD;
250 return AL_QUAD16;
251 case 6: *in_chans = AL_5POINT1;
252 return AL_5POINT1_16;
253 case 7: *in_chans = AL_6POINT1;
254 return AL_6POINT1_16;
255 case 8: *in_chans = AL_7POINT1;
256 return AL_7POINT1_16;
259 #if 0 /* Will cause incorrect byte offsets */
260 else if(format->wBitsPerSample == 24)
262 *in_type = AL_BYTE3;
263 switch(format->nChannels)
265 case 1: *in_chans = AL_MONO;
266 return AL_MONO32F;
267 case 2: *in_chans = AL_STEREO;
268 return AL_STEREO32F;
269 case 4: *in_chans = AL_QUAD;
270 return AL_QUAD32F;
271 case 6: *in_chans = AL_5POINT1;
272 return AL_5POINT1_32F;
273 case 7: *in_chans = AL_6POINT1;
274 return AL_6POINT1_32F;
275 case 8: *in_chans = AL_7POINT1;
276 return AL_7POINT1_32F;
279 #endif
280 else if(format->wBitsPerSample == 32)
282 *in_type = AL_INT;
283 switch(format->nChannels)
285 case 1: *in_chans = AL_MONO;
286 return AL_MONO32F;
287 case 2: *in_chans = AL_STEREO;
288 return AL_STEREO32F;
289 case 4: *in_chans = AL_QUAD;
290 return AL_QUAD32F;
291 case 6: *in_chans = AL_5POINT1;
292 return AL_5POINT1_32F;
293 case 7: *in_chans = AL_6POINT1;
294 return AL_6POINT1_32F;
295 case 8: *in_chans = AL_7POINT1;
296 return AL_7POINT1_32F;
300 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
301 format->wBitsPerSample, format->nChannels);
302 return AL_NONE;
305 static const char *get_fmtstr_FLOAT(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out)
307 out->Format = *format;
308 out->Format.cbSize = 0;
310 if(out->Format.nChannels != 1 && out->Format.nChannels != 2 &&
311 !prim->SupportedExt[EXT_MCFORMATS])
313 WARN("Multi-channel not available\n");
314 return NULL;
317 if(format->wBitsPerSample == 32 && prim->SupportedExt[EXT_FLOAT32])
319 switch(format->nChannels)
321 case 1: return "AL_FORMAT_MONO_FLOAT32";
322 case 2: return "AL_FORMAT_STEREO_FLOAT32";
323 case 4: return "AL_FORMAT_QUAD32";
324 case 6: return "AL_FORMAT_51CHN32";
325 case 7: return "AL_FORMAT_61CHN32";
326 case 8: return "AL_FORMAT_71CHN32";
330 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
331 format->wBitsPerSample, format->nChannels);
332 return NULL;
334 static ALenum get_fmt_FLOAT(const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out, ALenum *in_chans, ALenum *in_type)
336 out->Format = *format;
337 out->Format.cbSize = 0;
339 if(format->wBitsPerSample == 32)
341 *in_type = AL_FLOAT;
342 switch(format->nChannels)
344 case 1: *in_chans = AL_MONO;
345 return AL_MONO32F;
346 case 2: *in_chans = AL_STEREO;
347 return AL_STEREO32F;
348 case 4: *in_chans = AL_QUAD;
349 return AL_QUAD32F;
350 case 6: *in_chans = AL_5POINT1;
351 return AL_5POINT1_32F;
352 case 7: *in_chans = AL_6POINT1;
353 return AL_6POINT1_32F;
354 case 8: *in_chans = AL_7POINT1;
355 return AL_7POINT1_32F;
358 #if 0 /* Will cause incorrect byte offsets */
359 else if(format->wBitsPerSample == 64)
361 *in_type = AL_DOUBLE;
362 switch(format->nChannels)
364 case 1: *in_chans = AL_MONO;
365 return AL_MONO32F;
366 case 2: *in_chans = AL_STEREO;
367 return AL_STEREO32F;
368 case 4: *in_chans = AL_QUAD;
369 return AL_QUAD32F;
370 case 6: *in_chans = AL_5POINT1;
371 return AL_5POINT1_32F;
372 case 7: *in_chans = AL_6POINT1;
373 return AL_6POINT1_32F;
374 case 8: *in_chans = AL_7POINT1;
375 return AL_7POINT1_32F;
378 #endif
380 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
381 format->wBitsPerSample, format->nChannels);
382 return AL_NONE;
385 /* Speaker configs */
386 #define MONO SPEAKER_FRONT_CENTER
387 #define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)
388 #define REAR (SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
389 #define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
390 #define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
391 #define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
392 #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)
394 static const char *get_fmtstr_EXT(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out)
396 *out = *CONTAINING_RECORD(format, const WAVEFORMATEXTENSIBLE, Format);
397 out->Format.cbSize = sizeof(*out) - sizeof(out->Format);
399 if(!out->Samples.wValidBitsPerSample)
400 out->Samples.wValidBitsPerSample = out->Format.wBitsPerSample;
401 else if(out->Samples.wValidBitsPerSample != out->Format.wBitsPerSample)
403 FIXME("Padded samples not supported (%u of %u)\n", out->Samples.wValidBitsPerSample, out->Format.wBitsPerSample);
404 return NULL;
407 if(out->dwChannelMask != MONO && out->dwChannelMask != STEREO &&
408 !prim->SupportedExt[EXT_MCFORMATS])
410 WARN("Multi-channel not available\n");
411 return NULL;
414 if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
416 if(out->Samples.wValidBitsPerSample == 8)
418 switch(out->dwChannelMask)
420 case MONO: return "AL_FORMAT_MONO8";
421 case STEREO: return "AL_FORMAT_STEREO8";
422 case REAR: return "AL_FORMAT_REAR8";
423 case QUAD: return "AL_FORMAT_QUAD8";
424 case X5DOT1: return "AL_FORMAT_51CHN8";
425 case X6DOT1: return "AL_FORMAT_61CHN8";
426 case X7DOT1: return "AL_FORMAT_71CHN8";
429 else if(out->Samples.wValidBitsPerSample == 16)
431 switch(out->dwChannelMask)
433 case MONO: return "AL_FORMAT_MONO16";
434 case STEREO: return "AL_FORMAT_STEREO16";
435 case REAR: return "AL_FORMAT_REAR16";
436 case QUAD: return "AL_FORMAT_QUAD16";
437 case X5DOT1: return "AL_FORMAT_51CHN16";
438 case X6DOT1: return "AL_FORMAT_61CHN16";
439 case X7DOT1: return "AL_FORMAT_71CHN16";
443 FIXME("Could not get OpenAL PCM format (%d-bit, channelmask %#x)\n",
444 out->Samples.wValidBitsPerSample, out->dwChannelMask);
445 return NULL;
447 else if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) &&
448 prim->SupportedExt[EXT_FLOAT32])
450 if(out->Samples.wValidBitsPerSample == 32)
452 switch(out->dwChannelMask)
454 case MONO: return "AL_FORMAT_MONO_FLOAT32";
455 case STEREO: return "AL_FORMAT_STEREO_FLOAT32";
456 case REAR: return "AL_FORMAT_REAR32";
457 case QUAD: return "AL_FORMAT_QUAD32";
458 case X5DOT1: return "AL_FORMAT_51CHN32";
459 case X6DOT1: return "AL_FORMAT_61CHN32";
460 case X7DOT1: return "AL_FORMAT_71CHN32";
463 else
465 WARN("Invalid float bits: %u\n", out->Samples.wValidBitsPerSample);
466 return NULL;
469 FIXME("Could not get OpenAL float format (%d-bit, channelmask %#x)\n",
470 out->Samples.wValidBitsPerSample, out->dwChannelMask);
471 return NULL;
473 else if(!IsEqualGUID(&out->SubFormat, &GUID_NULL))
474 ERR("Unhandled extensible format: %s\n", debugstr_guid(&out->SubFormat));
475 return NULL;
477 static ALenum get_fmt_EXT(const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out, ALenum *in_chans, ALenum *in_type)
479 *out = *CONTAINING_RECORD(format, const WAVEFORMATEXTENSIBLE, Format);
480 out->Format.cbSize = sizeof(*out) - sizeof(out->Format);
482 if(!out->Samples.wValidBitsPerSample)
483 out->Samples.wValidBitsPerSample = out->Format.wBitsPerSample;
484 else if(out->Samples.wValidBitsPerSample != out->Format.wBitsPerSample)
486 FIXME("Padded samples not supported (%u of %u)\n", out->Samples.wValidBitsPerSample, out->Format.wBitsPerSample);
487 return AL_NONE;
490 if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
492 if(out->Samples.wValidBitsPerSample == 8)
494 *in_type = AL_UNSIGNED_BYTE;
495 switch(out->dwChannelMask)
497 case MONO: *in_chans = AL_MONO;
498 return AL_MONO8;
499 case STEREO: *in_chans = AL_STEREO;
500 return AL_STEREO8;
501 case REAR: *in_chans = AL_REAR;
502 return AL_REAR8;
503 case QUAD: *in_chans = AL_QUAD;
504 return AL_QUAD8;
505 case X5DOT1: *in_chans = AL_5POINT1;
506 return AL_5POINT1_8;
507 case X6DOT1: *in_chans = AL_6POINT1;
508 return AL_6POINT1_8;
509 case X7DOT1: *in_chans = AL_7POINT1;
510 return AL_7POINT1_8;
513 else if(out->Samples.wValidBitsPerSample == 16)
515 *in_type = AL_SHORT;
516 switch(out->dwChannelMask)
518 case MONO: *in_chans = AL_MONO;
519 return AL_MONO16;
520 case STEREO: *in_chans = AL_STEREO;
521 return AL_STEREO16;
522 case REAR: *in_chans = AL_REAR;
523 return AL_REAR16;
524 case QUAD: *in_chans = AL_QUAD;
525 return AL_QUAD16;
526 case X5DOT1: *in_chans = AL_5POINT1;
527 return AL_5POINT1_16;
528 case X6DOT1: *in_chans = AL_6POINT1;
529 return AL_6POINT1_16;
530 case X7DOT1: *in_chans = AL_7POINT1;
531 return AL_7POINT1_16;
534 #if 0
535 else if(out->Samples.wValidBitsPerSample == 24)
537 *in_type = AL_BYTE3;
538 switch(out->dwChannelMask)
540 case MONO: *in_chans = AL_MONO;
541 return AL_MONO32F;
542 case STEREO: *in_chans = AL_STEREO;
543 return AL_STEREO32F;
544 case REAR: *in_chans = AL_REAR;
545 return AL_REAR32F;
546 case QUAD: *in_chans = AL_QUAD;
547 return AL_QUAD32F;
548 case X5DOT1: *in_chans = AL_5POINT1;
549 return AL_5POINT1_32F;
550 case X6DOT1: *in_chans = AL_6POINT1;
551 return AL_6POINT1_32F;
552 case X7DOT1: *in_chans = AL_7POINT1;
553 return AL_7POINT1_32F;
556 #endif
557 else if(out->Samples.wValidBitsPerSample == 32)
559 *in_type = AL_INT;
560 switch(out->dwChannelMask)
562 case MONO: *in_chans = AL_MONO;
563 return AL_MONO32F;
564 case STEREO: *in_chans = AL_STEREO;
565 return AL_STEREO32F;
566 case REAR: *in_chans = AL_REAR;
567 return AL_REAR32F;
568 case QUAD: *in_chans = AL_QUAD;
569 return AL_QUAD32F;
570 case X5DOT1: *in_chans = AL_5POINT1;
571 return AL_5POINT1_32F;
572 case X6DOT1: *in_chans = AL_6POINT1;
573 return AL_6POINT1_32F;
574 case X7DOT1: *in_chans = AL_7POINT1;
575 return AL_7POINT1_32F;
579 FIXME("Could not get OpenAL PCM format (%d-bit, channelmask %#x)\n",
580 out->Samples.wValidBitsPerSample, out->dwChannelMask);
581 return AL_NONE;
583 else if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
585 if(out->Samples.wValidBitsPerSample == 32)
587 *in_type = AL_FLOAT;
588 switch(out->dwChannelMask)
590 case MONO: *in_chans = AL_MONO;
591 return AL_MONO32F;
592 case STEREO: *in_chans = AL_STEREO;
593 return AL_STEREO32F;
594 case REAR: *in_chans = AL_REAR;
595 return AL_REAR32F;
596 case QUAD: *in_chans = AL_QUAD;
597 return AL_QUAD32F;
598 case X5DOT1: *in_chans = AL_5POINT1;
599 return AL_5POINT1_32F;
600 case X6DOT1: *in_chans = AL_6POINT1;
601 return AL_6POINT1_32F;
602 case X7DOT1: *in_chans = AL_7POINT1;
603 return AL_7POINT1_32F;
606 #if 0
607 else if(out->Samples.wValidBitsPerSample == 64)
609 *in_type = AL_DOUBLE;
610 switch(out->dwChannelMask)
612 case MONO: *in_chans = AL_MONO;
613 return AL_MONO32F;
614 case STEREO: *in_chans = AL_STEREO;
615 return AL_STEREO32F;
616 case REAR: *in_chans = AL_REAR;
617 return AL_REAR32F;
618 case QUAD: *in_chans = AL_QUAD;
619 return AL_QUAD32F;
620 case X5DOT1: *in_chans = AL_5POINT1;
621 return AL_5POINT1_32F;
622 case X6DOT1: *in_chans = AL_6POINT1;
623 return AL_6POINT1_32F;
624 case X7DOT1: *in_chans = AL_7POINT1;
625 return AL_7POINT1_32F;
628 #endif
629 else
631 WARN("Invalid float bits: %u\n", out->Samples.wValidBitsPerSample);
632 return AL_NONE;
635 FIXME("Could not get OpenAL float format (%d-bit, channelmask %#x)\n",
636 out->Samples.wValidBitsPerSample, out->dwChannelMask);
637 return AL_NONE;
639 else if(!IsEqualGUID(&out->SubFormat, &GUID_NULL))
640 ERR("Unhandled extensible format: %s\n", debugstr_guid(&out->SubFormat));
641 return AL_NONE;
644 static void DS8Data_Release(DS8Data *This);
645 static HRESULT DS8Data_Create(DS8Data **ppv, const DSBUFFERDESC *desc, DS8Primary *prim)
647 HRESULT hr = DSERR_INVALIDPARAM;
648 const WAVEFORMATEX *format;
649 DS8Data *pBuffer;
651 format = desc->lpwfxFormat;
652 TRACE("Requested buffer format:\n"
653 " FormatTag = 0x%04x\n"
654 " Channels = %d\n"
655 " SamplesPerSec = %u\n"
656 " AvgBytesPerSec = %u\n"
657 " BlockAlign = %d\n"
658 " BitsPerSample = %d\n",
659 format->wFormatTag, format->nChannels,
660 format->nSamplesPerSec, format->nAvgBytesPerSec,
661 format->nBlockAlign, format->wBitsPerSample);
663 if(format->nBlockAlign == 0)
665 WARN("Invalid BlockAlign specified\n");
666 return DSERR_INVALIDPARAM;
669 /* Generate a new buffer. Supporting the DSBCAPS_LOC* flags properly
670 * will need the EAX-RAM extension. Currently, we just tell the app it
671 * gets what it wanted. */
672 pBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pBuffer));
673 if(!pBuffer)
674 return E_OUTOFMEMORY;
675 pBuffer->ref = 1;
677 pBuffer->dsbflags = desc->dwFlags;
678 if((pBuffer->dsbflags&(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE)) == (DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE))
680 WARN("Hardware and software location requested\n");
681 goto fail;
683 if(!(pBuffer->dsbflags&(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE|DSBCAPS_LOCDEFER)))
684 pBuffer->dsbflags |= DSBCAPS_LOCHARDWARE;
686 pBuffer->buf_size = desc->dwBufferBytes + format->nBlockAlign - 1;
687 pBuffer->buf_size -= pBuffer->buf_size%format->nBlockAlign;
689 hr = DSERR_BUFFERTOOSMALL;
690 if(pBuffer->buf_size < DSBSIZE_MIN)
691 goto fail;
693 hr = DSERR_INVALIDPARAM;
694 if(pBuffer->buf_size > DSBSIZE_MAX)
695 goto fail;
697 pBuffer->numsegs = 1;
698 pBuffer->segsize = pBuffer->buf_size;
699 pBuffer->lastsegsize = pBuffer->buf_size;
701 if(!prim->SupportedExt[SOFT_BUFFER_SAMPLES])
703 const char *fmt_str;
705 if(!(pBuffer->dsbflags&DSBCAPS_STATIC) && !prim->SupportedExt[SOFT_BUFFER_SUB_DATA] &&
706 !prim->SupportedExt[EXT_STATIC_BUFFER])
708 ALCint refresh = FAKE_REFRESH_COUNT;
709 ALuint newSize;
711 alcGetIntegerv(prim->parent->device, ALC_REFRESH, 1, &refresh);
712 getALCError(prim->parent->device);
714 newSize = format->nAvgBytesPerSec/refresh + format->nBlockAlign - 1;
715 newSize -= newSize%format->nBlockAlign;
717 /* Make sure enough buffers are available */
718 if(newSize > pBuffer->buf_size/(QBUFFERS+2))
719 ERR("Buffer segments too large to stream (%u for %u)!\n",
720 newSize, pBuffer->buf_size);
721 else
723 pBuffer->numsegs = pBuffer->buf_size/newSize;
724 pBuffer->segsize = newSize;
725 pBuffer->lastsegsize = pBuffer->buf_size - (newSize*(pBuffer->numsegs-1));
726 TRACE("New streaming buffer (%u chunks, %u : %u sizes)\n",
727 pBuffer->numsegs, pBuffer->segsize, pBuffer->lastsegsize);
731 if(format->wFormatTag == WAVE_FORMAT_PCM)
732 fmt_str = get_fmtstr_PCM(prim, format, &pBuffer->format);
733 else if(format->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
734 fmt_str = get_fmtstr_FLOAT(prim, format, &pBuffer->format);
735 else if(format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
737 const WAVEFORMATEXTENSIBLE *wfe;
739 hr = DSERR_CONTROLUNAVAIL;
740 if(format->cbSize != sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) &&
741 format->cbSize != sizeof(WAVEFORMATEXTENSIBLE))
742 goto fail;
744 wfe = CONTAINING_RECORD(format, const WAVEFORMATEXTENSIBLE, Format);
745 TRACE("Extensible values:\n"
746 " Samples = %d\n"
747 " ChannelMask = 0x%x\n"
748 " SubFormat = %s\n",
749 wfe->Samples.wReserved, wfe->dwChannelMask,
750 debugstr_guid(&wfe->SubFormat));
752 fmt_str = get_fmtstr_EXT(prim, format, &pBuffer->format);
754 else
755 ERR("Unhandled formattag 0x%04x\n", format->wFormatTag);
757 hr = DSERR_INVALIDCALL;
758 if(!fmt_str)
759 goto fail;
761 pBuffer->buf_format = alGetEnumValue(fmt_str);
762 if(alGetError() != AL_NO_ERROR || pBuffer->buf_format == 0 ||
763 pBuffer->buf_format == -1)
765 WARN("Could not get OpenAL format from %s\n", fmt_str);
766 goto fail;
769 else
771 if(format->wFormatTag == WAVE_FORMAT_PCM)
772 pBuffer->buf_format = get_fmt_PCM(format, &pBuffer->format, &pBuffer->in_chans, &pBuffer->in_type);
773 else if(format->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
774 pBuffer->buf_format = get_fmt_FLOAT(format, &pBuffer->format, &pBuffer->in_chans, &pBuffer->in_type);
775 else if(format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
777 const WAVEFORMATEXTENSIBLE *wfe;
779 hr = DSERR_CONTROLUNAVAIL;
780 if(format->cbSize != sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) &&
781 format->cbSize != sizeof(WAVEFORMATEXTENSIBLE))
782 goto fail;
784 wfe = CONTAINING_RECORD(format, const WAVEFORMATEXTENSIBLE, Format);
785 TRACE("Extensible values:\n"
786 " Samples = %d\n"
787 " ChannelMask = 0x%x\n"
788 " SubFormat = %s\n",
789 wfe->Samples.wReserved, wfe->dwChannelMask,
790 debugstr_guid(&wfe->SubFormat));
792 pBuffer->buf_format = get_fmt_EXT(format, &pBuffer->format, &pBuffer->in_chans, &pBuffer->in_type);
794 else
795 ERR("Unhandled formattag 0x%04x\n", format->wFormatTag);
797 hr = DSERR_INVALIDCALL;
798 if(prim->ExtAL.IsBufferFormatSupportedSOFT(pBuffer->buf_format) == AL_FALSE)
800 WARN("Unsupported OpenAL format: 0x%x\n", pBuffer->buf_format);
801 goto fail;
805 hr = E_OUTOFMEMORY;
806 pBuffer->buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pBuffer->buffers)*pBuffer->numsegs);
807 pBuffer->data = HeapAlloc(GetProcessHeap(), 0, pBuffer->buf_size);
808 if(!pBuffer->buffers || !pBuffer->data)
809 goto fail;
811 alGenBuffers(pBuffer->numsegs, pBuffer->buffers);
812 getALError();
814 *ppv = pBuffer;
815 return S_OK;
817 fail:
818 DS8Data_Release(pBuffer);
819 return hr;
822 static void DS8Data_AddRef(DS8Data *data)
824 InterlockedIncrement(&data->ref);
827 /* This function is always called with the device lock held */
828 static void DS8Data_Release(DS8Data *This)
830 if(InterlockedDecrement(&This->ref)) return;
832 TRACE("Deleting %p\n", This);
833 if (This->buffers && This->buffers[0])
835 alDeleteBuffers(This->numsegs, This->buffers);
836 getALError();
838 HeapFree(GetProcessHeap(), 0, This->buffers);
839 HeapFree(GetProcessHeap(), 0, This->data);
840 HeapFree(GetProcessHeap(), 0, This);
843 HRESULT DS8Buffer_Create(DS8Buffer **ppv, DS8Primary *parent, IDirectSoundBuffer *orig)
845 HRESULT hr = DSERR_OUTOFMEMORY;
846 DS8Buffer *This;
847 DS8Buffer **bufs;
849 *ppv = NULL;
850 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
851 if(!This) return hr;
853 This->IDirectSoundBuffer8_iface.lpVtbl = (IDirectSoundBuffer8Vtbl*)&DS8Buffer_Vtbl;
854 This->IDirectSound3DBuffer_iface.lpVtbl = (IDirectSound3DBufferVtbl*)&DS8Buffer3d_Vtbl;
855 This->IDirectSoundNotify_iface.lpVtbl = (IDirectSoundNotifyVtbl*)&DS8BufferNot_Vtbl;
856 This->IKsPropertySet_iface.lpVtbl = (IKsPropertySetVtbl*)&DS8BufferProp_Vtbl;
858 This->primary = parent;
859 This->ctx = parent->ctx;
860 This->ExtAL = &parent->ExtAL;
861 This->crst = &parent->crst;
862 This->ref = This->all_ref = 1;
864 if(orig)
866 DS8Buffer *org = impl_from_IDirectSoundBuffer(orig);
867 hr = DSERR_BUFFERLOST;
868 if(org->bufferlost)
869 goto fail;
870 DS8Data_AddRef(org->buffer);
871 This->buffer = org->buffer;
874 /* Append to buffer list */
875 bufs = parent->buffers;
876 if(parent->nbuffers == parent->sizebuffers)
878 bufs = HeapReAlloc(GetProcessHeap(), 0, bufs, sizeof(*bufs)*(1+parent->nbuffers));
879 hr = DSERR_OUTOFMEMORY;
880 if(!bufs) goto fail;
881 parent->sizebuffers++;
883 parent->buffers = bufs;
884 bufs[parent->nbuffers++] = This;
886 /* Disable until initialized.. */
887 This->ds3dmode = DS3DMODE_DISABLE;
889 *ppv = This;
890 return S_OK;
892 fail:
893 DS8Buffer_Destroy(This);
894 return hr;
897 void DS8Buffer_Destroy(DS8Buffer *This)
899 DS8Primary *prim = This->primary;
900 DWORD idx;
902 TRACE("Destroying %p\n", This);
904 EnterCriticalSection(&prim->crst);
905 /* Remove from list, if in list */
906 for(idx = 0;idx < prim->nnotifies;++idx)
908 if(This == prim->notifies[idx])
910 prim->notifies[idx] = prim->notifies[--prim->nnotifies];
911 break;
914 for(idx = 0;idx < prim->nbuffers;++idx)
916 if(prim->buffers[idx] == This)
918 prim->buffers[idx] = prim->buffers[--prim->nbuffers];
919 break;
923 setALContext(This->ctx);
924 if(This->source)
926 ALuint *sources;
928 alSourceStop(This->source);
929 alSourcei(This->source, AL_BUFFER, 0);
930 getALError();
932 sources = prim->sources;
933 if(prim->nsources == prim->sizesources)
935 sources = HeapReAlloc(GetProcessHeap(), 0, sources, sizeof(*sources)*(prim->nsources+1));
936 if(!sources)
937 alDeleteSources(1, &This->source);
938 else
939 prim->sizesources++;
941 if(sources)
943 sources[prim->nsources++] = This->source;
944 prim->sources = sources;
946 This->source = 0;
948 LeaveCriticalSection(&prim->crst);
950 if(This->buffer)
951 DS8Data_Release(This->buffer);
953 popALContext();
955 HeapFree(GetProcessHeap(), 0, This->notify);
956 HeapFree(GetProcessHeap(), 0, This);
960 static HRESULT WINAPI DS8Buffer_QueryInterface(IDirectSoundBuffer8 *iface, REFIID riid, void **ppv)
962 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
964 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
966 *ppv = NULL;
967 if(IsEqualIID(riid, &IID_IUnknown) ||
968 IsEqualIID(riid, &IID_IDirectSoundBuffer))
969 *ppv = &This->IDirectSoundBuffer8_iface;
970 else if(IsEqualIID(riid, &IID_IDirectSoundBuffer8))
972 if(This->primary->parent->is_8)
973 *ppv = &This->IDirectSoundBuffer8_iface;
975 else if(IsEqualIID(riid, &IID_IDirectSound3DBuffer))
977 if((This->buffer->dsbflags&DSBCAPS_CTRL3D))
978 *ppv = &This->IDirectSound3DBuffer_iface;
980 else if(IsEqualIID(riid, &IID_IDirectSoundNotify))
982 if((This->buffer->dsbflags&DSBCAPS_CTRLPOSITIONNOTIFY))
983 *ppv = &This->IDirectSoundNotify_iface;
985 else if(IsEqualIID(riid, &IID_IKsPropertySet))
986 *ppv = &This->IKsPropertySet_iface;
987 else
988 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
990 if(*ppv)
992 IUnknown_AddRef((IUnknown*)*ppv);
993 return S_OK;
996 return E_NOINTERFACE;
999 static ULONG WINAPI DS8Buffer_AddRef(IDirectSoundBuffer8 *iface)
1001 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1002 LONG ret;
1004 InterlockedIncrement(&This->all_ref);
1005 ret = InterlockedIncrement(&This->ref);
1006 TRACE("new refcount %d\n", ret);
1008 return ret;
1011 static ULONG WINAPI DS8Buffer_Release(IDirectSoundBuffer8 *iface)
1013 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1014 LONG ret;
1016 ret = InterlockedDecrement(&This->ref);
1017 TRACE("new refcount %d\n", ret);
1018 if(InterlockedDecrement(&This->all_ref) == 0)
1019 DS8Buffer_Destroy(This);
1021 return ret;
1024 static HRESULT WINAPI DS8Buffer_GetCaps(IDirectSoundBuffer8 *iface, DSBCAPS *caps)
1026 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1028 TRACE("(%p)->(%p)\n", iface, caps);
1030 if(!caps || caps->dwSize < sizeof(*caps))
1032 WARN("Invalid DSBCAPS (%p, %u)\n", caps, (caps ? caps->dwSize : 0));
1033 return DSERR_INVALIDPARAM;
1036 caps->dwFlags = This->buffer->dsbflags;
1037 caps->dwBufferBytes = This->buffer->buf_size;
1038 caps->dwUnlockTransferRate = 4096;
1039 caps->dwPlayCpuOverhead = 0;
1040 return S_OK;
1043 static HRESULT WINAPI DS8Buffer_GetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD *playpos, DWORD *curpos)
1045 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1046 WAVEFORMATEX *format = &This->buffer->format.Format;
1047 UINT writecursor, pos;
1049 TRACE("(%p)->(%p, %p)\n", iface, playpos, curpos);
1051 EnterCriticalSection(This->crst);
1052 setALContext(This->ctx);
1054 if(This->buffer->numsegs > 1)
1056 ALint queued = QBUFFERS;
1057 alGetSourcei(This->source, AL_BUFFERS_QUEUED, &queued);
1058 getALError();
1060 pos = (This->curidx+This->buffer->numsegs-queued)%This->buffer->numsegs;
1061 pos *= This->buffer->segsize;
1062 writecursor = This->curidx * This->buffer->segsize;
1064 else if(This->primary->SupportedExt[SOFT_BUFFER_SUB_DATA] ||
1065 This->primary->SupportedExt[SOFT_BUFFER_SAMPLES])
1067 ALint rwpos[2] = { 0, 0 };
1069 alGetSourceiv(This->source, AL_BYTE_RW_OFFSETS_SOFT, rwpos);
1070 getALError();
1072 pos = rwpos[0];
1073 writecursor = rwpos[1];
1075 else
1077 ALint status = 0;
1078 ALint ofs = 0;
1080 alGetSourcei(This->source, AL_BYTE_OFFSET, &ofs);
1081 alGetSourcei(This->source, AL_SOURCE_STATE, &status);
1082 getALError();
1084 pos = ofs;
1085 if(status == AL_PLAYING)
1087 writecursor = format->nSamplesPerSec / 100;
1088 writecursor *= format->nBlockAlign;
1090 else
1091 writecursor = 0;
1092 writecursor = (writecursor + pos) % This->buffer->buf_size;
1094 TRACE("%p Play pos = %u, write pos = %u\n", This, pos, writecursor);
1095 if(pos >= This->buffer->buf_size)
1097 ERR("playpos >= buf_size\n");
1098 pos %= This->buffer->buf_size;
1100 if(writecursor >= This->buffer->buf_size)
1102 ERR("writepos >= buf_size\n");
1103 writecursor %= This->buffer->buf_size;
1106 if(playpos) *playpos = pos;
1107 if(curpos) *curpos = writecursor;
1109 popALContext();
1110 LeaveCriticalSection(This->crst);
1112 return S_OK;
1115 static HRESULT WINAPI DS8Buffer_GetFormat(IDirectSoundBuffer8 *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
1117 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1118 HRESULT hr = S_OK;
1119 UINT size;
1121 TRACE("(%p)->(%p, %u, %p)\n", iface, wfx, allocated, written);
1123 if(!wfx && !written)
1125 WARN("Cannot report format or format size\n");
1126 return DSERR_INVALIDPARAM;
1129 size = sizeof(This->buffer->format.Format) + This->buffer->format.Format.cbSize;
1130 if(wfx)
1132 if(allocated < size)
1133 hr = DSERR_INVALIDPARAM;
1134 else
1135 memcpy(wfx, &This->buffer->format.Format, size);
1137 if(written)
1138 *written = size;
1140 return hr;
1143 static HRESULT WINAPI DS8Buffer_GetVolume(IDirectSoundBuffer8 *iface, LONG *vol)
1145 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1146 HRESULT hr;
1148 TRACE("(%p)->(%p)\n", iface, vol);
1150 if(!vol)
1152 WARN("Invalid pointer\n");
1153 return DSERR_INVALIDPARAM;
1156 hr = DSERR_CONTROLUNAVAIL;
1157 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
1158 WARN("Volume control not set\n");
1159 else
1161 ALfloat gain = 1.0f;
1163 setALContext(This->ctx);
1164 alGetSourcef(This->source, AL_GAIN, &gain);
1165 getALError();
1166 popALContext();
1168 *vol = gain_to_mB(gain);
1169 *vol = min(*vol, DSBVOLUME_MAX);
1170 *vol = max(*vol, DSBVOLUME_MIN);
1172 hr = DS_OK;
1175 return hr;
1178 static HRESULT WINAPI DS8Buffer_GetPan(IDirectSoundBuffer8 *iface, LONG *pan)
1180 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1181 HRESULT hr;
1183 TRACE("(%p)->(%p)\n", iface, pan);
1185 if(!pan)
1187 WARN("Invalid pointer\n");
1188 return DSERR_INVALIDPARAM;
1191 hr = DSERR_CONTROLUNAVAIL;
1192 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
1193 WARN("Panning control not set\n");
1194 else
1196 ALfloat pos[3];
1198 setALContext(This->ctx);
1199 alGetSourcefv(This->source, AL_POSITION, pos);
1200 getALError();
1201 popALContext();
1203 *pan = (LONG)((pos[0]+1.0) * (DSBPAN_RIGHT-DSBPAN_LEFT) / 2.0 + 0.5) + DSBPAN_LEFT;
1204 *pan = min(*pan, DSBPAN_RIGHT);
1205 *pan = max(*pan, DSBPAN_LEFT);
1207 hr = DS_OK;
1210 return hr;
1213 static HRESULT WINAPI DS8Buffer_GetFrequency(IDirectSoundBuffer8 *iface, DWORD *freq)
1215 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1216 HRESULT hr;
1218 TRACE("(%p)->(%p)\n", iface, freq);
1220 if(!freq)
1222 WARN("Invalid pointer\n");
1223 return DSERR_INVALIDPARAM;
1226 hr = DSERR_CONTROLUNAVAIL;
1227 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
1228 WARN("Frequency control not set\n");
1229 else
1231 ALfloat pitch = 1.0f;
1233 setALContext(This->ctx);
1234 alGetSourcefv(This->source, AL_PITCH, &pitch);
1235 getALError();
1236 popALContext();
1238 *freq = (DWORD)(This->buffer->format.Format.nSamplesPerSec * pitch);
1240 hr = DS_OK;
1243 return hr;
1246 static HRESULT WINAPI DS8Buffer_GetStatus(IDirectSoundBuffer8 *iface, DWORD *status)
1248 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1249 ALint state, looping;
1251 TRACE("(%p)->(%p)\n", iface, status);
1253 if(!status)
1255 WARN("Invalid pointer\n");
1256 return DSERR_INVALIDPARAM;
1259 EnterCriticalSection(This->crst);
1261 setALContext(This->ctx);
1262 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1263 looping = This->islooping;
1264 if(This->buffer->numsegs == 1)
1265 alGetSourcei(This->source, AL_LOOPING, &looping);
1266 else if(state != AL_PLAYING)
1267 state = This->isplaying ? AL_PLAYING : AL_PAUSED;
1268 getALError();
1269 popALContext();
1271 LeaveCriticalSection(This->crst);
1273 *status = 0;
1274 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1276 if((This->buffer->dsbflags&DSBCAPS_LOCSOFTWARE))
1277 *status |= DSBSTATUS_LOCSOFTWARE;
1278 else if((This->buffer->dsbflags&DSBCAPS_LOCHARDWARE))
1279 *status |= DSBSTATUS_LOCHARDWARE;
1281 if(state == AL_PLAYING)
1282 *status |= DSBSTATUS_PLAYING | (looping ? DSBSTATUS_LOOPING : 0);
1284 return S_OK;
1287 static HRESULT WINAPI DS8Buffer_Initialize(IDirectSoundBuffer8 *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
1289 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1290 DS3DBUFFER *ds3dbuffer;
1291 HRESULT hr;
1293 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
1295 EnterCriticalSection(This->crst);
1296 setALContext(This->ctx);
1298 hr = DSERR_ALREADYINITIALIZED;
1299 if(This->source)
1300 goto out;
1302 if(!This->buffer)
1304 hr = DSERR_INVALIDPARAM;
1305 if(!desc)
1307 WARN("Missing DSound buffer description\n");
1308 goto out;
1310 if(!desc->lpwfxFormat)
1312 WARN("Missing buffer format (%p)\n", This);
1313 goto out;
1315 if((desc->dwFlags&DSBCAPS_CTRL3D) && desc->lpwfxFormat->nChannels != 1)
1317 if(This->primary->parent->is_8)
1319 /* DirectSoundBuffer8 objects aren't allowed non-mono 3D
1320 * buffers */
1321 WARN("Can't create multi-channel 3D buffers\n");
1322 goto out;
1324 ERR("Multi-channel 3D sounds are not spatialized\n");
1327 hr = DS8Data_Create(&This->buffer, desc, This->primary);
1328 if(FAILED(hr))
1329 goto out;
1330 else
1332 DS8Data *buf = This->buffer;
1334 if(buf->format.Format.wBitsPerSample == 8)
1335 memset(buf->data, 0x80, buf->buf_size);
1336 else
1337 memset(buf->data, 0x00, buf->buf_size);
1339 if(This->primary->SupportedExt[EXT_STATIC_BUFFER])
1340 This->ExtAL->BufferDataStatic(buf->buffers[0], buf->buf_format,
1341 buf->data, buf->buf_size,
1342 buf->format.Format.nSamplesPerSec);
1343 else if(This->primary->SupportedExt[SOFT_BUFFER_SAMPLES])
1344 This->ExtAL->BufferSamplesSOFT(buf->buffers[0],
1345 buf->format.Format.nSamplesPerSec, buf->buf_format,
1346 buf->buf_size/buf->format.Format.nBlockAlign,
1347 buf->in_chans, buf->in_type, buf->data);
1348 else if(This->primary->SupportedExt[SOFT_BUFFER_SUB_DATA])
1349 alBufferData(buf->buffers[0], buf->buf_format,
1350 buf->data, buf->buf_size,
1351 buf->format.Format.nSamplesPerSec);
1353 getALError();
1356 hr = DSERR_GENERIC;
1357 if(This->primary->nsources)
1359 This->source = This->primary->sources[--This->primary->nsources];
1360 alSourcef(This->source, AL_GAIN, 1.0f);
1361 alSourcef(This->source, AL_PITCH, 1.0f);
1362 getALError();
1364 else
1366 alGenSources(1, &This->source);
1367 if(alGetError() != AL_NO_ERROR)
1368 goto out;
1371 ds3dbuffer = &This->ds3dbuffer;
1372 ds3dbuffer->dwSize = sizeof(*ds3dbuffer);
1373 ds3dbuffer->vPosition.x = 0.0;
1374 ds3dbuffer->vPosition.y = 0.0;
1375 ds3dbuffer->vPosition.z = 0.0;
1376 ds3dbuffer->vVelocity.x = 0.0;
1377 ds3dbuffer->vVelocity.y = 0.0;
1378 ds3dbuffer->vVelocity.z = 0.0;
1379 ds3dbuffer->dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
1380 ds3dbuffer->dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
1381 ds3dbuffer->vConeOrientation.x = 0.0;
1382 ds3dbuffer->vConeOrientation.y = 0.0;
1383 ds3dbuffer->vConeOrientation.z = 1.0;
1384 ds3dbuffer->lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
1385 ds3dbuffer->flMinDistance = DS3D_DEFAULTMINDISTANCE;
1386 ds3dbuffer->flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
1387 ds3dbuffer->dwMode = DS3DMODE_NORMAL;
1389 if((This->buffer->dsbflags&DSBCAPS_CTRL3D))
1391 if(This->primary->auxslot != 0)
1393 alSource3i(This->source, AL_AUXILIARY_SEND_FILTER, This->primary->auxslot, 0, AL_FILTER_NULL);
1394 getALError();
1397 hr = IDirectSound3DBuffer_SetAllParameters(&This->IDirectSound3DBuffer_iface, ds3dbuffer, DS3D_IMMEDIATE);
1398 if(FAILED(hr))
1400 ERR("SetAllParameters failed\n");
1401 goto out;
1404 else
1406 ALuint source = This->source;
1408 if(This->primary->auxslot != 0)
1410 /* Simple hack to make reverb affect non-3D sounds too */
1411 alSource3i(source, AL_AUXILIARY_SEND_FILTER, This->primary->auxslot, 0, AL_FILTER_NULL);
1412 /*alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL);*/
1415 /* Non-3D sources aren't distance attenuated */
1416 This->ds3dmode = DS3DMODE_DISABLE;
1417 alSource3f(source, AL_POSITION, 0.0f, 1.0f, 0.0f);
1418 alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
1419 alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
1420 alSourcef(source, AL_CONE_OUTER_GAIN, 1.0f);
1421 alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f);
1422 alSourcef(source, AL_MAX_DISTANCE, 1000.0f);
1423 alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f);
1424 alSourcei(source, AL_CONE_INNER_ANGLE, 360);
1425 alSourcei(source, AL_CONE_OUTER_ANGLE, 360);
1426 alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);
1427 getALError();
1429 hr = S_OK;
1431 out:
1432 popALContext();
1433 LeaveCriticalSection(This->crst);
1435 return hr;
1438 static HRESULT WINAPI DS8Buffer_Lock(IDirectSoundBuffer8 *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
1440 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1441 HRESULT hr;
1442 DWORD remain;
1444 TRACE("(%p)->(%u, %u, %p, %p, %p, %p, 0x%x)\n", This, ofs, bytes, ptr1, len1, ptr2, len2, flags);
1446 if(!ptr1 || !len1)
1448 WARN("Invalid pointer/len %p %p\n", ptr1, len1);
1449 return DSERR_INVALIDPARAM;
1452 EnterCriticalSection(This->crst);
1453 setALContext(This->ctx);
1455 *ptr1 = NULL;
1456 *len1 = 0;
1457 if(ptr2) *ptr2 = NULL;
1458 if(len2) *len2 = 0;
1460 hr = DSERR_INVALIDPARAM;
1461 if((flags&DSBLOCK_FROMWRITECURSOR))
1462 DS8Buffer_GetCurrentPosition(iface, NULL, &ofs);
1463 else if(ofs >= This->buffer->buf_size)
1465 WARN("Invalid ofs %u\n", ofs);
1466 goto out;
1468 if((flags&DSBLOCK_ENTIREBUFFER))
1469 bytes = This->buffer->buf_size;
1470 else if(bytes > This->buffer->buf_size)
1472 WARN("Invalid size %u\n", bytes);
1473 goto out;
1476 *ptr1 = This->buffer->data + ofs;
1477 if(ofs+bytes >= This->buffer->buf_size)
1479 *len1 = This->buffer->buf_size - ofs;
1480 remain = bytes - *len1;
1482 else
1484 *len1 = bytes;
1485 remain = 0;
1488 This->buffer->locked = TRUE;
1490 if(ptr2 && len2 && remain)
1492 *ptr2 = This->buffer->data;
1493 *len2 = remain;
1495 hr = S_OK;
1497 out:
1498 popALContext();
1499 LeaveCriticalSection(This->crst);
1500 return hr;
1503 static HRESULT WINAPI DS8Buffer_Play(IDirectSoundBuffer8 *iface, DWORD res1, DWORD prio, DWORD flags)
1505 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1506 ALint type, state = AL_STOPPED;
1507 HRESULT hr;
1508 (void)res1;
1510 TRACE("%p\n", This);
1512 EnterCriticalSection(This->crst);
1513 setALContext(This->ctx);
1515 hr = DSERR_BUFFERLOST;
1516 if(This->bufferlost)
1518 WARN("Buffer %p lost\n", This);
1519 goto out;
1522 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1524 if(!(This->buffer->dsbflags&(DSBCAPS_LOCHARDWARE|DSBCAPS_LOCSOFTWARE)))
1526 if(flags & DSBPLAY_LOCSOFTWARE)
1527 This->buffer->dsbflags |= DSBCAPS_LOCSOFTWARE;
1528 else
1529 This->buffer->dsbflags |= DSBCAPS_LOCHARDWARE;
1532 else if(prio)
1534 ERR("Invalid priority set for non-deferred buffer %p, %u!\n", This->buffer, prio);
1535 hr = DSERR_INVALIDPARAM;
1536 goto out;
1539 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1540 if(This->buffer->numsegs > 1)
1542 This->islooping = !!(flags&DSBPLAY_LOOPING);
1543 if(state != AL_PLAYING && This->isplaying)
1544 state = AL_PLAYING;
1546 else
1548 alGetSourcei(This->source, AL_SOURCE_TYPE, &type);
1549 alSourcei(This->source, AL_LOOPING, (flags&DSBPLAY_LOOPING) ? AL_TRUE : AL_FALSE);
1551 getALError();
1553 hr = S_OK;
1554 if(state == AL_PLAYING)
1555 goto out;
1557 /* alSourceQueueBuffers will implicitly set type to streaming */
1558 if(This->buffer->numsegs == 1)
1560 if(type != AL_STATIC)
1561 alSourcei(This->source, AL_BUFFER, This->buffer->buffers[0]);
1562 alSourcePlay(This->source);
1564 if(alGetError() != AL_NO_ERROR)
1566 ERR("Couldn't start source\n");
1567 This->curidx = (This->buffer->numsegs-1+This->curidx)%This->buffer->numsegs;
1568 alSourcei(This->source, AL_BUFFER, 0);
1569 getALError();
1570 hr = DSERR_GENERIC;
1571 goto out;
1573 This->isplaying = TRUE;
1575 if(This->nnotify)
1577 DS8Buffer_addnotify(This);
1578 DS8Buffer_starttimer(This->primary);
1580 else if(This->buffer->numsegs > 1)
1581 DS8Buffer_starttimer(This->primary);
1583 out:
1584 popALContext();
1585 LeaveCriticalSection(This->crst);
1586 return hr;
1589 static HRESULT WINAPI DS8Buffer_SetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD pos)
1591 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1593 TRACE("(%p)->(%u)\n", iface, (UINT)pos);
1595 if(pos >= This->buffer->buf_size)
1596 return DSERR_INVALIDPARAM;
1598 EnterCriticalSection(This->crst);
1600 if(This->buffer->numsegs > 1)
1602 DS8Data *buf = This->buffer;
1603 This->curidx = pos/buf->segsize;
1604 if(This->curidx >= buf->numsegs)
1605 This->curidx = buf->numsegs - 1;
1606 if(This->isplaying)
1608 setALContext(This->ctx);
1609 /* Perform a flush, so the next timer update will restart at the
1610 * proper position */
1611 alSourceStop(This->source);
1612 getALError();
1613 popALContext();
1616 else
1618 setALContext(This->ctx);
1619 alSourcei(This->source, AL_BYTE_OFFSET, pos);
1620 popALContext();
1622 This->lastpos = pos;
1624 LeaveCriticalSection(This->crst);
1625 return DS_OK;
1628 static HRESULT WINAPI DS8Buffer_SetFormat(IDirectSoundBuffer8 *iface, const WAVEFORMATEX *wfx)
1630 /* This call only works on primary buffers */
1631 WARN("(%p)->(%p)\n", iface, wfx);
1632 return DSERR_INVALIDCALL;
1635 static HRESULT WINAPI DS8Buffer_SetVolume(IDirectSoundBuffer8 *iface, LONG vol)
1637 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1638 HRESULT hr = S_OK;
1640 TRACE("(%p)->(%d)\n", iface, vol);
1642 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
1644 WARN("Invalid volume (%d)\n", vol);
1645 return DSERR_INVALIDPARAM;
1648 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
1649 hr = DSERR_CONTROLUNAVAIL;
1650 if(SUCCEEDED(hr))
1652 ALfloat fvol = mB_to_gain(vol);
1653 setALContext(This->ctx);
1654 alSourcef(This->source, AL_GAIN, fvol);
1655 popALContext();
1658 return hr;
1661 static HRESULT WINAPI DS8Buffer_SetPan(IDirectSoundBuffer8 *iface, LONG pan)
1663 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1664 HRESULT hr = S_OK;
1666 TRACE("(%p)->(%d)\n", iface, pan);
1668 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
1670 WARN("invalid parameter: pan = %d\n", pan);
1671 return DSERR_INVALIDPARAM;
1674 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
1675 hr = DSERR_CONTROLUNAVAIL;
1676 else
1678 ALfloat pos[3];
1679 pos[0] = (pan-DSBPAN_LEFT) * 2.0 / (ALfloat)(DSBPAN_RIGHT-DSBPAN_LEFT) - 1.0;
1680 /* NOTE: Strict movement along the X plane can cause the sound to jump
1681 * between left and right sharply. Using a curved path helps smooth it
1682 * out */
1683 pos[1] = sqrt(1.0 - pos[0]*pos[0]);
1684 pos[2] = 0.0;
1686 setALContext(This->ctx);
1687 alSourcefv(This->source, AL_POSITION, pos);
1688 getALError();
1689 popALContext();
1691 if(pan != 0 && This->buffer->format.Format.nChannels > 1)
1692 FIXME("Panning for multi-channel buffers is not supported\n");
1695 return hr;
1698 static HRESULT WINAPI DS8Buffer_SetFrequency(IDirectSoundBuffer8 *iface, DWORD freq)
1700 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1701 HRESULT hr = S_OK;
1703 TRACE("(%p)->(%u)\n", iface, freq);
1705 if(freq < DSBFREQUENCY_MIN || freq > DSBFREQUENCY_MAX)
1707 WARN("invalid parameter: freq = %d\n", freq);
1708 return DSERR_INVALIDPARAM;
1711 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
1712 hr = DSERR_CONTROLUNAVAIL;
1713 else
1715 ALfloat pitch = 1.0f;
1716 if(freq != DSBFREQUENCY_ORIGINAL)
1717 pitch = freq / (ALfloat)This->buffer->format.Format.nSamplesPerSec;
1719 setALContext(This->ctx);
1720 alSourcef(This->source, AL_PITCH, pitch);
1721 getALError();
1722 popALContext();
1725 return hr;
1728 static HRESULT WINAPI DS8Buffer_Stop(IDirectSoundBuffer8 *iface)
1730 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1731 ALint state;
1733 TRACE("(%p)->()\n", iface);
1735 EnterCriticalSection(This->crst);
1736 setALContext(This->ctx);
1738 alSourcePause(This->source);
1739 getALError();
1740 /* Mac OS X doesn't immediately report state change
1741 * if Play() is immediately called after Stop, this can be fatal,
1742 * the buffer would never be restarted
1744 do {
1745 state = AL_PAUSED;
1746 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1747 if(state != AL_PLAYING)
1748 break;
1749 Sleep(1);
1750 } while(1);
1752 This->isplaying = FALSE;
1754 popALContext();
1755 LeaveCriticalSection(This->crst);
1757 return S_OK;
1760 static HRESULT WINAPI DS8Buffer_Unlock(IDirectSoundBuffer8 *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
1762 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1763 DS8Data *buf = This->buffer;
1764 DWORD bufsize = buf->buf_size;
1765 DWORD_PTR ofs1, ofs2;
1766 DWORD_PTR boundary = (DWORD_PTR)buf->data;
1767 HRESULT hr;
1769 TRACE("(%p)->(%p, %u, %p, %u)\n", iface, ptr1, len1, ptr2, len2);
1771 EnterCriticalSection(This->crst);
1772 setALContext(This->ctx);
1774 This->buffer->locked = 0;
1775 hr = DSERR_INVALIDPARAM;
1777 /* Make sure offset is between boundary and boundary + bufsize */
1778 ofs1 = (DWORD_PTR)ptr1;
1779 ofs2 = (DWORD_PTR)ptr2;
1780 if(ofs1 < boundary)
1781 goto out;
1782 if(ofs2 && ofs2 != boundary)
1783 goto out;
1784 ofs1 -= boundary;
1785 ofs2 = 0;
1786 if(bufsize-ofs1 < len1 || len2 > ofs1)
1787 goto out;
1788 if(!ptr2)
1789 len2 = 0;
1791 hr = S_OK;
1792 if(!len1 && !len2)
1793 goto out;
1795 if(This->primary->SupportedExt[EXT_STATIC_BUFFER])
1796 goto out;
1798 if(This->primary->SupportedExt[SOFT_BUFFER_SAMPLES])
1800 const WAVEFORMATEX *format = &buf->format.Format;
1802 ptr1 = (BYTE*)ptr1 - (ofs1%format->nBlockAlign);
1803 ofs1 /= format->nBlockAlign;
1804 len1 /= format->nBlockAlign;
1805 if(len1 > 0)
1806 This->ExtAL->BufferSubSamplesSOFT(buf->buffers[0], ofs1, len1,
1807 buf->in_chans, buf->in_type, ptr1);
1808 ptr2 = (BYTE*)ptr2 - (ofs2%format->nBlockAlign);
1809 ofs2 /= format->nBlockAlign;
1810 len2 /= format->nBlockAlign;
1811 if(len2 > 0)
1812 This->ExtAL->BufferSubSamplesSOFT(buf->buffers[0], ofs2, len2,
1813 buf->in_chans, buf->in_type, ptr2);
1814 getALError();
1816 else if(This->primary->SupportedExt[SOFT_BUFFER_SUB_DATA])
1818 const WAVEFORMATEX *format = &buf->format.Format;
1820 len1 -= len1%format->nBlockAlign;
1821 if(len1 > 0)
1822 This->ExtAL->BufferSubData(buf->buffers[0], buf->buf_format, ptr1,
1823 ofs1, len1);
1824 len2 -= len2%format->nBlockAlign;
1825 if(len2 > 0)
1826 This->ExtAL->BufferSubData(buf->buffers[0], buf->buf_format, ptr2,
1827 ofs2, len2);
1828 getALError();
1830 else
1832 alBufferData(buf->buffers[0], buf->buf_format,
1833 buf->data, buf->buf_size,
1834 buf->format.Format.nSamplesPerSec);
1835 getALError();
1838 out:
1839 if(hr != S_OK)
1840 WARN("Invalid parameters (0x%lx,%u) (%p,%u,%p,%u)\n", boundary, bufsize, ptr1, len1, ptr2, len2);
1841 popALContext();
1842 LeaveCriticalSection(This->crst);
1843 return hr;
1846 static HRESULT WINAPI DS8Buffer_Restore(IDirectSoundBuffer8 *iface)
1848 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1849 HRESULT hr;
1851 TRACE("(%p)->()\n", iface);
1853 EnterCriticalSection(This->crst);
1854 if(This->primary->parent->prio_level < DSSCL_WRITEPRIMARY ||
1855 iface == This->primary->write_emu)
1857 This->bufferlost = 0;
1858 hr = S_OK;
1860 else
1861 hr = DSERR_BUFFERLOST;
1862 LeaveCriticalSection(This->crst);
1864 return hr;
1867 static HRESULT WINAPI DS8Buffer_SetFX(IDirectSoundBuffer8 *iface, DWORD fxcount, DSEFFECTDESC *desc, DWORD *rescodes)
1869 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1870 DWORD i;
1872 TRACE("(%p)->(%u, %p, %p)\n", This, fxcount, desc, rescodes);
1874 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFX))
1876 WARN("FX control not set\n");
1877 return DSERR_CONTROLUNAVAIL;
1880 if(fxcount == 0)
1882 if(desc || rescodes)
1884 WARN("Non-NULL desc and/or result pointer specified with no effects.\n");
1885 return DSERR_INVALIDPARAM;
1888 /* No effects; we can handle that */
1889 return DS_OK;
1892 if(!desc || !rescodes)
1894 WARN("NULL desc and/or result pointer specified.\n");
1895 return DSERR_INVALIDPARAM;
1898 /* We don't (currently) handle DSound effects */
1899 for(i = 0;i < fxcount;++i)
1901 FIXME("Cannot handle effect: %s\n", debugstr_guid(&desc[i].guidDSFXClass));
1902 rescodes[i] = DSFXR_FAILED;
1905 return DS_INCOMPLETE;
1908 static HRESULT WINAPI DS8Buffer_AcquireResources(IDirectSoundBuffer8 *iface, DWORD flags, DWORD fxcount, DWORD *rescodes)
1910 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1912 TRACE("(%p)->(%u, %u, %p)\n", This, flags, fxcount, rescodes);
1914 /* effects aren't supported at the moment.. */
1915 if(fxcount != 0 || rescodes)
1917 WARN("Non-zero effect count and/or result pointer specified with no effects.\n");
1918 return DSERR_INVALIDPARAM;
1921 EnterCriticalSection(This->crst);
1922 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1924 This->buffer->dsbflags &= ~(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE);
1925 if((flags&DSBPLAY_LOCSOFTWARE))
1926 This->buffer->dsbflags |= DSBCAPS_LOCSOFTWARE;
1927 else
1928 This->buffer->dsbflags |= DSBCAPS_LOCHARDWARE;
1930 LeaveCriticalSection(This->crst);
1932 return S_OK;
1935 static HRESULT WINAPI DS8Buffer_GetObjectInPath(IDirectSoundBuffer8 *iface, REFGUID guid, DWORD idx, REFGUID rguidiface, void **ppv)
1937 FIXME("(%p)->(%s, %u, %s, %p) : stub!\n", iface, debugstr_guid(guid), idx, debugstr_guid(rguidiface), ppv);
1938 return E_NOTIMPL;
1941 static const IDirectSoundBuffer8Vtbl DS8Buffer_Vtbl =
1943 DS8Buffer_QueryInterface,
1944 DS8Buffer_AddRef,
1945 DS8Buffer_Release,
1946 DS8Buffer_GetCaps,
1947 DS8Buffer_GetCurrentPosition,
1948 DS8Buffer_GetFormat,
1949 DS8Buffer_GetVolume,
1950 DS8Buffer_GetPan,
1951 DS8Buffer_GetFrequency,
1952 DS8Buffer_GetStatus,
1953 DS8Buffer_Initialize,
1954 DS8Buffer_Lock,
1955 DS8Buffer_Play,
1956 DS8Buffer_SetCurrentPosition,
1957 DS8Buffer_SetFormat,
1958 DS8Buffer_SetVolume,
1959 DS8Buffer_SetPan,
1960 DS8Buffer_SetFrequency,
1961 DS8Buffer_Stop,
1962 DS8Buffer_Unlock,
1963 DS8Buffer_Restore,
1964 DS8Buffer_SetFX,
1965 DS8Buffer_AcquireResources,
1966 DS8Buffer_GetObjectInPath
1970 static HRESULT WINAPI DS8Buffer3D_QueryInterface(IDirectSound3DBuffer *iface, REFIID riid, void **ppv)
1972 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1973 return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
1976 static ULONG WINAPI DS8Buffer3D_AddRef(IDirectSound3DBuffer *iface)
1978 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1979 LONG ret;
1981 InterlockedIncrement(&This->all_ref);
1982 ret = InterlockedIncrement(&This->ds3d_ref);
1983 TRACE("new refcount %d\n", ret);
1985 return ret;
1988 static ULONG WINAPI DS8Buffer3D_Release(IDirectSound3DBuffer *iface)
1990 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1991 LONG ret;
1993 ret = InterlockedDecrement(&This->ds3d_ref);
1994 TRACE("new refcount %d\n", ret);
1995 if(InterlockedDecrement(&This->all_ref) == 0)
1996 DS8Buffer_Destroy(This);
1998 return ret;
2001 static HRESULT WINAPI DS8Buffer3D_GetAllParameters(IDirectSound3DBuffer *iface, DS3DBUFFER *ds3dbuffer)
2003 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2004 DS3DBUFFER ds3dbuf;
2005 HRESULT hr;
2007 TRACE("%p\n", This);
2009 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
2011 WARN("Invalid parameters %p %u\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
2012 return DSERR_INVALIDPARAM;
2014 ds3dbuf.dwSize = sizeof(ds3dbuf);
2016 EnterCriticalSection(This->crst);
2017 setALContext(This->ctx);
2019 hr = IDirectSound3DBuffer_GetPosition(iface, &ds3dbuf.vPosition);
2020 if(SUCCEEDED(hr))
2021 hr = IDirectSound3DBuffer_GetVelocity(iface, &ds3dbuf.vVelocity);
2022 if(SUCCEEDED(hr))
2023 hr = IDirectSound3DBuffer_GetConeAngles(iface, &ds3dbuf.dwInsideConeAngle, &ds3dbuf.dwOutsideConeAngle);
2024 if(SUCCEEDED(hr))
2025 hr = IDirectSound3DBuffer_GetConeOrientation(iface, &ds3dbuf.vConeOrientation);
2026 if(SUCCEEDED(hr))
2027 hr = IDirectSound3DBuffer_GetConeOutsideVolume(iface, &ds3dbuf.lConeOutsideVolume);
2028 if(SUCCEEDED(hr))
2029 hr = IDirectSound3DBuffer_GetMinDistance(iface, &ds3dbuf.flMinDistance);
2030 if(SUCCEEDED(hr))
2031 hr = IDirectSound3DBuffer_GetMaxDistance(iface, &ds3dbuf.flMaxDistance);
2032 if(SUCCEEDED(hr))
2033 hr = IDirectSound3DBuffer_GetMode(iface, &ds3dbuf.dwMode);
2034 if(SUCCEEDED(hr))
2035 memcpy(ds3dbuffer, &ds3dbuf, sizeof(ds3dbuf));
2037 popALContext();
2038 LeaveCriticalSection(This->crst);
2040 return hr;
2043 static HRESULT WINAPI DS8Buffer3D_GetConeAngles(IDirectSound3DBuffer *iface, DWORD *pdwInsideConeAngle, DWORD *pdwOutsideConeAngle)
2045 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2046 ALint inangle, outangle;
2048 TRACE("(%p)->(%p, %p)\n", This, pdwInsideConeAngle, pdwOutsideConeAngle);
2049 if(!pdwInsideConeAngle || !pdwOutsideConeAngle)
2051 WARN("Invalid pointers (%p, %p)\n", pdwInsideConeAngle, pdwOutsideConeAngle);
2052 return DSERR_INVALIDPARAM;
2055 EnterCriticalSection(This->crst);
2056 setALContext(This->ctx);
2058 alGetSourcei(This->source, AL_CONE_INNER_ANGLE, &inangle);
2059 alGetSourcei(This->source, AL_CONE_OUTER_ANGLE, &outangle);
2060 getALError();
2061 *pdwInsideConeAngle = inangle;
2062 *pdwOutsideConeAngle = outangle;
2064 popALContext();
2065 LeaveCriticalSection(This->crst);
2067 return S_OK;
2070 static HRESULT WINAPI DS8Buffer3D_GetConeOrientation(IDirectSound3DBuffer *iface, D3DVECTOR *orient)
2072 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2073 ALfloat dir[3];
2075 TRACE("(%p)->(%p)\n", This, orient);
2076 if(!orient)
2078 WARN("Invalid pointer\n");
2079 return DSERR_INVALIDPARAM;
2082 EnterCriticalSection(This->crst);
2083 setALContext(This->ctx);
2085 alGetSourcefv(This->source, AL_DIRECTION, dir);
2086 getALError();
2087 orient->x = dir[0];
2088 orient->y = dir[1];
2089 orient->z = -dir[2];
2091 popALContext();
2092 LeaveCriticalSection(This->crst);
2094 return S_OK;
2097 static HRESULT WINAPI DS8Buffer3D_GetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG *vol)
2099 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2100 ALfloat gain;
2102 TRACE("(%p)->(%p)\n", This, vol);
2103 if(!vol)
2105 WARN("Invalid pointer\n");
2106 return DSERR_INVALIDPARAM;
2109 EnterCriticalSection(This->crst);
2110 setALContext(This->ctx);
2112 alGetSourcef(This->source, AL_CONE_OUTER_GAIN, &gain);
2113 getALError();
2114 *vol = gain_to_mB(gain);
2115 *vol = max(*vol, DSBVOLUME_MIN);
2116 *vol = min(*vol, DSBVOLUME_MAX);
2118 popALContext();
2119 LeaveCriticalSection(This->crst);
2120 return S_OK;
2123 static HRESULT WINAPI DS8Buffer3D_GetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE *maxdist)
2125 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2126 ALfloat dist;
2128 TRACE("(%p)->(%p)\n", This, maxdist);
2129 if(!maxdist)
2131 WARN("Invalid pointer\n");
2132 return DSERR_INVALIDPARAM;
2135 EnterCriticalSection(This->crst);
2136 setALContext(This->ctx);
2138 alGetSourcef(This->source, AL_MAX_DISTANCE, &dist);
2139 getALError();
2140 *maxdist = dist;
2142 popALContext();
2143 LeaveCriticalSection(This->crst);
2145 return S_OK;
2148 static HRESULT WINAPI DS8Buffer3D_GetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE *mindist)
2150 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2151 ALfloat dist;
2153 TRACE("(%p)->(%p)\n", This, mindist);
2154 if(!mindist)
2156 WARN("Invalid pointer\n");
2157 return DSERR_INVALIDPARAM;
2160 EnterCriticalSection(This->crst);
2161 setALContext(This->ctx);
2163 alGetSourcef(This->source, AL_REFERENCE_DISTANCE, &dist);
2164 getALError();
2165 *mindist = dist;
2167 popALContext();
2168 LeaveCriticalSection(This->crst);
2170 return S_OK;
2173 static HRESULT WINAPI DS8Buffer3D_GetMode(IDirectSound3DBuffer *iface, DWORD *mode)
2175 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2177 TRACE("(%p)->(%p)\n", This, mode);
2178 if(!mode)
2180 WARN("Invalid pointer\n");
2181 return DSERR_INVALIDPARAM;
2184 EnterCriticalSection(This->crst);
2185 *mode = This->ds3dmode;
2186 LeaveCriticalSection(This->crst);
2188 return S_OK;
2191 static HRESULT WINAPI DS8Buffer3D_GetPosition(IDirectSound3DBuffer *iface, D3DVECTOR *pos)
2193 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2194 ALfloat alpos[3];
2196 TRACE("(%p)->(%p)\n", This, pos);
2197 if(!pos)
2199 WARN("Invalid pointer\n");
2200 return DSERR_INVALIDPARAM;
2203 EnterCriticalSection(This->crst);
2204 setALContext(This->ctx);
2206 alGetSourcefv(This->source, AL_POSITION, alpos);
2207 getALError();
2208 pos->x = alpos[0];
2209 pos->y = alpos[1];
2210 pos->z = -alpos[2];
2212 popALContext();
2213 LeaveCriticalSection(This->crst);
2215 return S_OK;
2218 static HRESULT WINAPI DS8Buffer3D_GetVelocity(IDirectSound3DBuffer *iface, D3DVECTOR *vel)
2220 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2221 ALfloat alvel[3];
2223 TRACE("(%p)->(%p)\n", This, vel);
2224 if(!vel)
2226 WARN("Invalid pointer\n");
2227 return DSERR_INVALIDPARAM;
2230 EnterCriticalSection(This->crst);
2231 setALContext(This->ctx);
2233 alGetSourcefv(This->source, AL_VELOCITY, alvel);
2234 getALError();
2235 vel->x = alvel[0];
2236 vel->y = alvel[1];
2237 vel->z = -alvel[2];
2239 popALContext();
2240 LeaveCriticalSection(This->crst);
2242 return S_OK;
2245 static HRESULT WINAPI DS8Buffer3D_SetAllParameters(IDirectSound3DBuffer *iface, const DS3DBUFFER *ds3dbuffer, DWORD apply)
2247 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2248 TRACE("(%p)->(%p, %u)\n", This, ds3dbuffer, apply);
2250 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
2252 WARN("Invalid DS3DBUFFER (%p, %u)\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
2253 return DSERR_INVALIDPARAM;
2256 if(ds3dbuffer->dwInsideConeAngle > DS3D_MAXCONEANGLE ||
2257 ds3dbuffer->dwOutsideConeAngle > DS3D_MAXCONEANGLE)
2259 WARN("Invalid cone angles (%u, %u)\n", ds3dbuffer->dwInsideConeAngle,
2260 ds3dbuffer->dwOutsideConeAngle);
2261 return DSERR_INVALIDPARAM;
2264 if(ds3dbuffer->lConeOutsideVolume > DSBVOLUME_MAX ||
2265 ds3dbuffer->lConeOutsideVolume < DSBVOLUME_MIN)
2267 WARN("Invalid cone outside volume (%d)\n", ds3dbuffer->lConeOutsideVolume);
2268 return DSERR_INVALIDPARAM;
2271 if(ds3dbuffer->flMaxDistance < 0.0f)
2273 WARN("Invalid max distance (%f)\n", ds3dbuffer->flMaxDistance);
2274 return DSERR_INVALIDPARAM;
2277 if(ds3dbuffer->flMinDistance < 0.0f)
2279 WARN("Invalid min distance (%f)\n", ds3dbuffer->flMinDistance);
2280 return DSERR_INVALIDPARAM;
2283 if(ds3dbuffer->dwMode != DS3DMODE_NORMAL &&
2284 ds3dbuffer->dwMode != DS3DMODE_HEADRELATIVE &&
2285 ds3dbuffer->dwMode != DS3DMODE_DISABLE)
2287 WARN("Invalid mode (%u)\n", ds3dbuffer->dwMode);
2288 return DSERR_INVALIDPARAM;
2291 EnterCriticalSection(This->crst);
2292 setALContext(This->ctx);
2293 IDirectSound3DBuffer_SetPosition(iface, ds3dbuffer->vPosition.x, ds3dbuffer->vPosition.y, ds3dbuffer->vPosition.z, apply);
2294 IDirectSound3DBuffer_SetVelocity(iface, ds3dbuffer->vVelocity.x, ds3dbuffer->vVelocity.y, ds3dbuffer->vVelocity.z, apply);
2295 IDirectSound3DBuffer_SetConeAngles(iface, ds3dbuffer->dwInsideConeAngle, ds3dbuffer->dwOutsideConeAngle, apply);
2296 IDirectSound3DBuffer_SetConeOrientation(iface, ds3dbuffer->vConeOrientation.x, ds3dbuffer->vConeOrientation.y, ds3dbuffer->vConeOrientation.z, apply);
2297 IDirectSound3DBuffer_SetConeOutsideVolume(iface, ds3dbuffer->lConeOutsideVolume, apply);
2298 IDirectSound3DBuffer_SetMinDistance(iface, ds3dbuffer->flMinDistance, apply);
2299 IDirectSound3DBuffer_SetMaxDistance(iface, ds3dbuffer->flMaxDistance, apply);
2300 IDirectSound3DBuffer_SetMode(iface, ds3dbuffer->dwMode, apply);
2301 popALContext();
2302 LeaveCriticalSection(This->crst);
2304 return S_OK;
2307 static HRESULT WINAPI DS8Buffer3D_SetConeAngles(IDirectSound3DBuffer *iface, DWORD dwInsideConeAngle, DWORD dwOutsideConeAngle, DWORD apply)
2309 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2311 TRACE("(%p)->(%u, %u, %u)\n", This, dwInsideConeAngle, dwOutsideConeAngle, apply);
2312 if(dwInsideConeAngle > DS3D_MAXCONEANGLE ||
2313 dwOutsideConeAngle > DS3D_MAXCONEANGLE)
2315 WARN("Invalid cone angles (%u, %u)\n", dwInsideConeAngle, dwOutsideConeAngle);
2316 return DSERR_INVALIDPARAM;
2319 EnterCriticalSection(This->crst);
2320 if(apply == DS3D_DEFERRED)
2322 This->ds3dbuffer.dwInsideConeAngle = dwInsideConeAngle;
2323 This->ds3dbuffer.dwOutsideConeAngle = dwOutsideConeAngle;
2324 This->dirty.bit.cone_angles = 1;
2326 else
2328 setALContext(This->ctx);
2329 alSourcei(This->source, AL_CONE_INNER_ANGLE, dwInsideConeAngle);
2330 alSourcei(This->source, AL_CONE_OUTER_ANGLE, dwOutsideConeAngle);
2331 getALError();
2332 popALContext();
2334 LeaveCriticalSection(This->crst);
2336 return S_OK;
2339 static HRESULT WINAPI DS8Buffer3D_SetConeOrientation(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2341 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2343 TRACE("(%p)->(%f, %f, %f, %u)\n", This, x, y, z, apply);
2345 EnterCriticalSection(This->crst);
2346 if(apply == DS3D_DEFERRED)
2348 This->ds3dbuffer.vConeOrientation.x = x;
2349 This->ds3dbuffer.vConeOrientation.y = y;
2350 This->ds3dbuffer.vConeOrientation.z = z;
2351 This->dirty.bit.cone_orient = 1;
2353 else
2355 setALContext(This->ctx);
2356 alSource3f(This->source, AL_DIRECTION, x, y, -z);
2357 getALError();
2358 popALContext();
2360 LeaveCriticalSection(This->crst);
2362 return S_OK;
2365 static HRESULT WINAPI DS8Buffer3D_SetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG vol, DWORD apply)
2367 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2369 TRACE("(%p)->(%u, %u)\n", This, vol, apply);
2370 if(vol < DSBVOLUME_MIN || vol > DSBVOLUME_MAX)
2372 WARN("Invalid volume (%u)\n", vol);
2373 return DSERR_INVALIDPARAM;
2376 EnterCriticalSection(This->crst);
2377 if(apply == DS3D_DEFERRED)
2379 This->ds3dbuffer.lConeOutsideVolume = vol;
2380 This->dirty.bit.cone_outsidevolume = 1;
2382 else
2384 setALContext(This->ctx);
2385 alSourcef(This->source, AL_CONE_OUTER_GAIN, mB_to_gain(vol));
2386 getALError();
2387 popALContext();
2389 LeaveCriticalSection(This->crst);
2391 return S_OK;
2394 static HRESULT WINAPI DS8Buffer3D_SetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE maxdist, DWORD apply)
2396 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2398 TRACE("(%p)->(%f, %u)\n", This, maxdist, apply);
2399 if(maxdist < 0.0f)
2401 WARN("Invalid max distance (%f)\n", maxdist);
2402 return DSERR_INVALIDPARAM;
2405 EnterCriticalSection(This->crst);
2406 if(apply == DS3D_DEFERRED)
2408 This->ds3dbuffer.flMaxDistance = maxdist;
2409 This->dirty.bit.max_distance = 1;
2411 else
2413 setALContext(This->ctx);
2414 alSourcef(This->source, AL_MAX_DISTANCE, maxdist);
2415 getALError();
2416 popALContext();
2418 LeaveCriticalSection(This->crst);
2420 return S_OK;
2423 static HRESULT WINAPI DS8Buffer3D_SetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE mindist, DWORD apply)
2425 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2427 TRACE("(%p)->(%f, %u)\n", This, mindist, apply);
2428 if(mindist < 0.0f)
2430 WARN("Invalid min distance (%f)\n", mindist);
2431 return DSERR_INVALIDPARAM;
2434 EnterCriticalSection(This->crst);
2435 if(apply == DS3D_DEFERRED)
2437 This->ds3dbuffer.flMinDistance = mindist;
2438 This->dirty.bit.min_distance = 1;
2440 else
2442 setALContext(This->ctx);
2443 alSourcef(This->source, AL_REFERENCE_DISTANCE, mindist);
2444 getALError();
2445 popALContext();
2447 LeaveCriticalSection(This->crst);
2449 return S_OK;
2452 static HRESULT WINAPI DS8Buffer3D_SetMode(IDirectSound3DBuffer *iface, DWORD mode, DWORD apply)
2454 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2456 TRACE("(%p)->(%u, %u)\n", This, mode, apply);
2457 if(mode != DS3DMODE_NORMAL && mode != DS3DMODE_HEADRELATIVE &&
2458 mode != DS3DMODE_DISABLE)
2460 WARN("Invalid mode (%u)\n", mode);
2461 return DSERR_INVALIDPARAM;
2464 EnterCriticalSection(This->crst);
2465 if(apply == DS3D_DEFERRED)
2467 This->ds3dbuffer.dwMode = mode;
2468 This->dirty.bit.mode = 1;
2470 else
2472 setALContext(This->ctx);
2473 alSourcei(This->source, AL_SOURCE_RELATIVE,
2474 (mode != DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE);
2475 alSourcef(This->source, AL_ROLLOFF_FACTOR,
2476 (mode == DS3DMODE_DISABLE) ? 0.0f : This->primary->rollofffactor);
2477 This->ds3dmode = mode;
2478 getALError();
2479 popALContext();
2481 LeaveCriticalSection(This->crst);
2483 return S_OK;
2486 static HRESULT WINAPI DS8Buffer3D_SetPosition(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2488 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2490 TRACE("(%p)->(%f, %f, %f, %u)\n", This, x, y, z, apply);
2492 EnterCriticalSection(This->crst);
2493 if(apply == DS3D_DEFERRED)
2495 This->ds3dbuffer.vPosition.x = x;
2496 This->ds3dbuffer.vPosition.y = y;
2497 This->ds3dbuffer.vPosition.z = z;
2498 This->dirty.bit.pos = 1;
2500 else
2502 setALContext(This->ctx);
2503 alSource3f(This->source, AL_POSITION, x, y, -z);
2504 getALError();
2505 popALContext();
2507 LeaveCriticalSection(This->crst);
2509 return S_OK;
2512 static HRESULT WINAPI DS8Buffer3D_SetVelocity(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2514 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2516 TRACE("(%p)->(%f, %f, %f, %u)\n", This, x, y, z, apply);
2518 EnterCriticalSection(This->crst);
2519 if(apply == DS3D_DEFERRED)
2521 This->ds3dbuffer.vVelocity.x = x;
2522 This->ds3dbuffer.vVelocity.y = y;
2523 This->ds3dbuffer.vVelocity.z = z;
2524 This->dirty.bit.vel = 1;
2526 else
2528 setALContext(This->ctx);
2529 alSource3f(This->source, AL_VELOCITY, x, y, -z);
2530 getALError();
2531 popALContext();
2533 LeaveCriticalSection(This->crst);
2535 return S_OK;
2538 static const IDirectSound3DBufferVtbl DS8Buffer3d_Vtbl =
2540 DS8Buffer3D_QueryInterface,
2541 DS8Buffer3D_AddRef,
2542 DS8Buffer3D_Release,
2543 DS8Buffer3D_GetAllParameters,
2544 DS8Buffer3D_GetConeAngles,
2545 DS8Buffer3D_GetConeOrientation,
2546 DS8Buffer3D_GetConeOutsideVolume,
2547 DS8Buffer3D_GetMaxDistance,
2548 DS8Buffer3D_GetMinDistance,
2549 DS8Buffer3D_GetMode,
2550 DS8Buffer3D_GetPosition,
2551 DS8Buffer3D_GetVelocity,
2552 DS8Buffer3D_SetAllParameters,
2553 DS8Buffer3D_SetConeAngles,
2554 DS8Buffer3D_SetConeOrientation,
2555 DS8Buffer3D_SetConeOutsideVolume,
2556 DS8Buffer3D_SetMaxDistance,
2557 DS8Buffer3D_SetMinDistance,
2558 DS8Buffer3D_SetMode,
2559 DS8Buffer3D_SetPosition,
2560 DS8Buffer3D_SetVelocity
2564 static HRESULT WINAPI DS8BufferNot_QueryInterface(IDirectSoundNotify *iface, REFIID riid, void **ppv)
2566 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2567 return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2570 static ULONG WINAPI DS8BufferNot_AddRef(IDirectSoundNotify *iface)
2572 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2573 LONG ret;
2575 InterlockedIncrement(&This->all_ref);
2576 ret = InterlockedIncrement(&This->not_ref);
2577 TRACE("new refcount %d\n", ret);
2579 return ret;
2582 static ULONG WINAPI DS8BufferNot_Release(IDirectSoundNotify *iface)
2584 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2585 LONG ret;
2587 ret = InterlockedDecrement(&This->not_ref);
2588 TRACE("new refcount %d\n", ret);
2589 if(InterlockedDecrement(&This->all_ref) == 0)
2590 DS8Buffer_Destroy(This);
2592 return ret;
2595 static HRESULT WINAPI DS8BufferNot_SetNotificationPositions(IDirectSoundNotify *iface, DWORD count, const DSBPOSITIONNOTIFY *notifications)
2597 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2598 DSBPOSITIONNOTIFY *nots;
2599 DWORD state;
2600 HRESULT hr;
2602 EnterCriticalSection(This->crst);
2603 hr = DSERR_INVALIDPARAM;
2604 if(count && !notifications)
2605 goto out;
2607 hr = IDirectSoundBuffer8_GetStatus(&This->IDirectSoundBuffer8_iface, &state);
2608 if(FAILED(hr))
2609 goto out;
2611 hr = DSERR_INVALIDCALL;
2612 if((state&DSBSTATUS_PLAYING))
2613 goto out;
2615 if(!count)
2617 HeapFree(GetProcessHeap(), 0, This->notify);
2618 This->notify = 0;
2619 This->nnotify = 0;
2620 hr = S_OK;
2622 else
2624 DWORD i;
2626 hr = DSERR_INVALIDPARAM;
2627 for(i = 0;i < count;++i)
2629 if(notifications[i].dwOffset >= This->buffer->buf_size &&
2630 notifications[i].dwOffset != (DWORD)DSBPN_OFFSETSTOP)
2631 goto out;
2634 hr = E_OUTOFMEMORY;
2635 nots = HeapAlloc(GetProcessHeap(), 0, count*sizeof(*nots));
2636 if(!nots)
2637 goto out;
2638 memcpy(nots, notifications, count*sizeof(*nots));
2640 HeapFree(GetProcessHeap(), 0, This->notify);
2641 This->notify = nots;
2642 This->nnotify = count;
2644 hr = S_OK;
2647 out:
2648 LeaveCriticalSection(This->crst);
2649 return hr;
2652 static const IDirectSoundNotifyVtbl DS8BufferNot_Vtbl =
2654 DS8BufferNot_QueryInterface,
2655 DS8BufferNot_AddRef,
2656 DS8BufferNot_Release,
2657 DS8BufferNot_SetNotificationPositions
2661 static HRESULT WINAPI DS8BufferProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
2663 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2664 return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2667 static ULONG WINAPI DS8BufferProp_AddRef(IKsPropertySet *iface)
2669 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2670 LONG ret;
2672 InterlockedIncrement(&This->all_ref);
2673 ret = InterlockedIncrement(&This->prop_ref);
2674 TRACE("new refcount %d\n", ret);
2676 return ret;
2679 static ULONG WINAPI DS8BufferProp_Release(IKsPropertySet *iface)
2681 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2682 LONG ret;
2684 ret = InterlockedDecrement(&This->prop_ref);
2685 TRACE("new refcount %d\n", ret);
2686 if(InterlockedDecrement(&This->all_ref) == 0)
2687 DS8Buffer_Destroy(This);
2689 return ret;
2692 /* NOTE: Due to some apparent quirks in DSound, the listener properties are
2693 handled through secondary buffers. */
2694 static HRESULT WINAPI DS8BufferProp_Get(IKsPropertySet *iface,
2695 REFGUID guidPropSet, ULONG dwPropID,
2696 LPVOID pInstanceData, ULONG cbInstanceData,
2697 LPVOID pPropData, ULONG cbPropData,
2698 PULONG pcbReturned)
2700 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2701 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2703 TRACE("(%p)->(%s, %u, %p, %u, %p, %u, %p)\n", iface, debugstr_guid(guidPropSet),
2704 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData, pcbReturned);
2706 if(!pcbReturned)
2707 return E_POINTER;
2708 *pcbReturned = 0;
2710 #if 0
2711 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2714 else
2715 #endif
2717 /* Not a known buffer/source property. Pass it to the listener */
2718 hr = IKsPropertySet_Get(&This->primary->IKsPropertySet_iface, guidPropSet,
2719 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData,
2720 pcbReturned);
2723 return hr;
2726 static HRESULT WINAPI DS8BufferProp_Set(IKsPropertySet *iface,
2727 REFGUID guidPropSet, ULONG dwPropID,
2728 LPVOID pInstanceData, ULONG cbInstanceData,
2729 LPVOID pPropData, ULONG cbPropData)
2731 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2732 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2734 TRACE("(%p)->(%s, %u, %p, %u, %p, %u)\n", iface, debugstr_guid(guidPropSet),
2735 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData);
2737 #if 0
2738 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2741 else
2742 #endif
2744 /* Not a known buffer/source property. Pass it to the listener */
2745 hr = IKsPropertySet_Set(&This->primary->IKsPropertySet_iface, guidPropSet,
2746 dwPropID, pInstanceData, cbInstanceData, pPropData,
2747 cbPropData);
2750 return hr;
2753 static HRESULT WINAPI DS8BufferProp_QuerySupport(IKsPropertySet *iface,
2754 REFGUID guidPropSet, ULONG dwPropID,
2755 PULONG pTypeSupport)
2757 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2758 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2760 TRACE("(%p)->(%s, %u, %p)\n", iface, debugstr_guid(guidPropSet), dwPropID, pTypeSupport);
2762 if(!pTypeSupport)
2763 return E_POINTER;
2764 *pTypeSupport = 0;
2766 #if 0
2767 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2770 else
2771 #endif
2773 /* Not a known buffer/source property. Pass it to the listener */
2774 hr = IKsPropertySet_QuerySupport(&This->primary->IKsPropertySet_iface,
2775 guidPropSet, dwPropID, pTypeSupport);
2778 return hr;
2781 static const IKsPropertySetVtbl DS8BufferProp_Vtbl =
2783 DS8BufferProp_QueryInterface,
2784 DS8BufferProp_AddRef,
2785 DS8BufferProp_Release,
2786 DS8BufferProp_Get,
2787 DS8BufferProp_Set,
2788 DS8BufferProp_QuerySupport