Remove unnecessary braces
[wine/multimedia.git] / buffer.c
blob65d377d23eb47397038b7346d07c5baf34698eb4
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;
83 /* Amount of buffers that have to be queued when
84 * bufferdatastatic and buffersubdata are not available */
85 #define QBUFFERS 3
87 struct DS8Data
89 LONG ref;
91 /* Lock was called and unlock isn't? */
92 BOOL locked;
94 WAVEFORMATEXTENSIBLE format;
96 ALuint buf_size;
97 ALenum buf_format;
98 ALenum in_type, in_chans;
99 DWORD dsbflags;
100 BYTE *data;
101 ALuint *buffers;
102 ALuint numsegs;
103 ALuint segsize;
104 ALuint lastsegsize;
107 static void trigger_notifies(DS8Buffer *buf, DWORD lastpos, DWORD curpos, BOOL stopping)
109 DWORD i;
110 if (lastpos == curpos && !stopping)
111 return;
112 for (i = 0; i < buf->nnotify; ++i)
114 DSBPOSITIONNOTIFY *not = &buf->notify[i];
115 HANDLE event = not->hEventNotify;
116 DWORD ofs = not->dwOffset;
118 if (ofs == (DWORD)DSBPN_OFFSETSTOP)
120 if (stopping)
121 SetEvent(event);
122 continue;
125 /* Wraparound case */
126 if (curpos < lastpos)
128 if (ofs < curpos || ofs >= lastpos)
129 SetEvent(event);
130 continue;
133 /* Normal case */
134 if (ofs >= lastpos && ofs < curpos)
135 SetEvent(event);
139 static void CALLBACK DS8Buffer_timer(UINT timerID, UINT msg, DWORD_PTR dwUser,
140 DWORD_PTR dw1, DWORD_PTR dw2)
142 DS8Primary *prim = (DS8Primary*)dwUser;
143 DWORD i;
144 (void)timerID;
145 (void)msg;
146 (void)dw1;
147 (void)dw2;
149 EnterCriticalSection(&prim->crst);
150 setALContext(prim->ctx);
152 /* OpenAL doesn't support our lovely buffer extensions
153 * so just make sure enough buffers are queued
155 if(!prim->ExtAL.BufferSamplesSOFT && !prim->ExtAL.BufferSubData &&
156 !prim->ExtAL.BufferDataStatic)
158 /* FIXME: Should probably use this logic to also
159 * call trigger_notifies
161 for (i = 0; i < prim->nbuffers; ++i)
163 DS8Buffer *buf = prim->buffers[i];
164 ALint done = 0, queued = QBUFFERS, state = AL_PLAYING;
165 ALuint which, ofs;
167 if (buf->buffer->numsegs == 1 || !buf->isplaying)
168 continue;
170 alGetSourcei(buf->source, AL_SOURCE_STATE, &state);
171 alGetSourcei(buf->source, AL_BUFFERS_QUEUED, &queued);
172 alGetSourcei(buf->source, AL_BUFFERS_PROCESSED, &done);
174 queued -= done;
175 while (done--)
176 alSourceUnqueueBuffers(buf->source, 1, &which);
177 while (queued < QBUFFERS)
179 which = buf->buffer->buffers[buf->curidx];
180 ofs = buf->curidx*buf->buffer->segsize;
181 if(buf->curidx < buf->buffer->numsegs-1)
182 alBufferData(which, buf->buffer->buf_format,
183 buf->buffer->data + ofs, buf->buffer->segsize,
184 buf->buffer->format.Format.nSamplesPerSec);
185 else
186 alBufferData(which, buf->buffer->buf_format,
187 buf->buffer->data + ofs, buf->buffer->lastsegsize,
188 buf->buffer->format.Format.nSamplesPerSec);
190 alSourceQueueBuffers(buf->source, 1, &which);
191 buf->curidx = (buf->curidx+1)%buf->buffer->numsegs;
192 queued++;
194 if (!buf->curidx && !buf->islooping)
196 buf->isplaying = FALSE;
197 break;
200 if (state != AL_PLAYING)
202 if (!queued)
204 IDirectSoundBuffer8_Stop(&buf->IDirectSoundBuffer8_iface);
205 continue;
207 alSourcePlay(buf->source);
209 getALError();
213 for (i = 0; i < prim->nnotifies ; )
215 DS8Buffer *buf = prim->notifies[i];
216 IDirectSoundBuffer8 *dsb = &buf->IDirectSoundBuffer8_iface;
217 DWORD status, curpos;
218 HRESULT hr;
220 hr = IDirectSoundBuffer8_GetStatus(dsb, &status);
221 if (SUCCEEDED(hr))
223 if (!(status & DSBSTATUS_PLAYING))
225 /* Stop will remove this buffer from list,
226 * and put another at the current position
227 * don't increment i
229 IDirectSoundBuffer8_Stop(dsb);
230 continue;
232 hr = IDirectSoundBuffer8_GetCurrentPosition(dsb, &curpos, NULL);
233 if (SUCCEEDED(hr))
235 trigger_notifies(buf, buf->lastpos, curpos, FALSE);
236 buf->lastpos = curpos;
239 i++;
241 popALContext();
242 LeaveCriticalSection(&prim->crst);
245 static void DS8Buffer_starttimer(DS8Primary *prim)
247 TIMECAPS time;
248 ALint refresh = FAKE_REFRESH_COUNT;
249 DWORD triggertime, res = DS_TIME_RES;
251 if(prim->timer_id)
252 return;
254 timeGetDevCaps(&time, sizeof(TIMECAPS));
256 alcGetIntegerv(prim->parent->device, ALC_REFRESH, 1, &refresh);
257 getALCError(prim->parent->device);
259 triggertime = 1000 / refresh;
260 if(triggertime < time.wPeriodMin)
261 triggertime = time.wPeriodMin;
262 TRACE("Calling timer every %u ms for %i refreshes per second\n", triggertime, refresh);
264 if (res < time.wPeriodMin)
265 res = time.wPeriodMin;
266 if (timeBeginPeriod(res) == TIMERR_NOCANDO)
267 WARN("Could not set minimum resolution, don't expect sound\n");
269 prim->timer_res = res;
270 prim->timer_id = timeSetEvent(triggertime, res, DS8Buffer_timer, (DWORD_PTR)prim, TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
273 /* Should be called with critsect held and context set.. */
274 static void DS8Buffer_addnotify(DS8Buffer *buf)
276 DS8Buffer **list;
277 DWORD i;
279 list = buf->primary->notifies;
280 for(i = 0; i < buf->primary->nnotifies; ++i)
282 if(buf == list[i])
284 ERR("Buffer %p already in notification list\n", buf);
285 return;
288 if(buf->primary->nnotifies == buf->primary->sizenotifies)
290 list = HeapReAlloc(GetProcessHeap(), 0, list, (buf->primary->nnotifies + 1) * sizeof(*list));
291 if(!list)
292 return;
293 buf->primary->sizenotifies++;
295 list[buf->primary->nnotifies++] = buf;
296 buf->primary->notifies = list;
299 static void DS8Buffer_removenotify(DS8Buffer *buf)
301 DWORD i;
302 for(i = 0; i < buf->primary->nnotifies; ++i)
304 if(buf == buf->primary->notifies[i])
306 buf->primary->notifies[i] =
307 buf->primary->notifies[--buf->primary->nnotifies];
308 return;
313 static const char *get_fmtstr_PCM(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out, ALenum *in_chans, ALenum *in_type)
315 out->Format = *format;
316 out->Format.cbSize = 0;
318 if(format->wBitsPerSample == 8)
320 *in_type = AL_UNSIGNED_BYTE;
321 switch(format->nChannels)
323 case 1: *in_chans = AL_MONO;
324 return "AL_FORMAT_MONO8";
325 case 2: *in_chans = AL_STEREO;
326 return "AL_FORMAT_STEREO8";
327 case 4: *in_chans = AL_QUAD;
328 return "AL_FORMAT_QUAD8";
329 case 6: *in_chans = AL_5POINT1;
330 return "AL_FORMAT_51CHN8";
331 case 7: *in_chans = AL_6POINT1;
332 return "AL_FORMAT_61CHN8";
333 case 8: *in_chans = AL_7POINT1;
334 return "AL_FORMAT_71CHN8";
335 default: break;
338 else if(format->wBitsPerSample == 16)
340 *in_type = AL_SHORT;
341 switch(format->nChannels)
343 case 1: *in_chans = AL_MONO;
344 return "AL_FORMAT_MONO16";
345 case 2: *in_chans = AL_STEREO;
346 return "AL_FORMAT_STEREO16";
347 case 4: *in_chans = AL_QUAD;
348 return "AL_FORMAT_QUAD16";
349 case 6: *in_chans = AL_5POINT1;
350 return "AL_FORMAT_51CHN16";
351 case 7: *in_chans = AL_6POINT1;
352 return "AL_FORMAT_61CHN16";
353 case 8: *in_chans = AL_7POINT1;
354 return "AL_FORMAT_71CHN16";
355 default: break;
358 #if 0 /* Will cause incorrect byte offsets */
359 else if(format->wBitsPerSample == 24 && prim->SupportedExt[SOFT_BUFFER_SAMPLES])
361 *in_type = AL_BYTE3;
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";
376 default: break;
379 #endif
380 else if(format->wBitsPerSample == 32 && prim->SupportedExt[SOFT_BUFFER_SAMPLES])
382 *in_type = AL_INT;
383 switch(format->nChannels)
385 case 1: *in_chans = AL_MONO;
386 return "AL_MONO32F";
387 case 2: *in_chans = AL_STEREO;
388 return "AL_STEREO32F";
389 case 4: *in_chans = AL_QUAD;
390 return "AL_QUAD32F";
391 case 6: *in_chans = AL_5POINT1;
392 return "AL_5POINT1_32F";
393 case 7: *in_chans = AL_6POINT1;
394 return "AL_6POINT1_32F";
395 case 8: *in_chans = AL_7POINT1;
396 return "AL_7POINT1_32F";
397 default: break;
401 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
402 format->wBitsPerSample, format->nChannels);
403 return NULL;
406 static const char *get_fmtstr_FLOAT(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out, ALenum *in_chans, ALenum *in_type)
408 out->Format = *format;
409 out->Format.cbSize = 0;
411 if(format->wBitsPerSample == 32 &&
412 (prim->SupportedExt[EXT_FLOAT32] || prim->SupportedExt[SOFT_BUFFER_SAMPLES]))
414 *in_type = AL_FLOAT;
415 switch(format->nChannels)
417 case 1: *in_chans = AL_MONO;
418 return "AL_FORMAT_MONO_FLOAT32";
419 case 2: *in_chans = AL_STEREO;
420 return "AL_FORMAT_STEREO_FLOAT32";
421 case 4: *in_chans = AL_QUAD;
422 return "AL_FORMAT_QUAD32";
423 case 6: *in_chans = AL_5POINT1;
424 return "AL_FORMAT_51CHN32";
425 case 7: *in_chans = AL_6POINT1;
426 return "AL_FORMAT_61CHN32";
427 case 8: *in_chans = AL_7POINT1;
428 return "AL_FORMAT_71CHN32";
429 default: break;
432 #if 0 /* Will cause incorrect byte offsets */
433 else if(format->wBitsPerSample == 64 && prim->SupportedExt[SOFT_BUFFER_SAMPLES])
435 *in_type = AL_DOUBLE;
436 switch(format->nChannels)
438 case 1: *in_chans = AL_MONO;
439 return "AL_MONO32F";
440 case 2: *in_chans = AL_STEREO;
441 return "AL_STEREO32F";
442 case 4: *in_chans = AL_QUAD;
443 return "AL_QUAD32F";
444 case 6: *in_chans = AL_5POINT1;
445 return "AL_5POINT1_32F";
446 case 7: *in_chans = AL_6POINT1;
447 return "AL_6POINT1_32F";
448 case 8: *in_chans = AL_7POINT1;
449 return "AL_7POINT1_32F";
450 default: break;
453 #endif
455 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
456 format->wBitsPerSample, format->nChannels);
457 return NULL;
460 /* Speaker configs */
461 #define MONO SPEAKER_FRONT_CENTER
462 #define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)
463 #define REAR (SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
464 #define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
465 #define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
466 #define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
467 #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)
469 static const char *get_fmtstr_EXT(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out, ALenum *in_chans, ALenum *in_type)
471 *out = *(const WAVEFORMATEXTENSIBLE*)format;
472 out->Format.cbSize = sizeof(*out) - sizeof(out->Format);
474 if(!out->Samples.wValidBitsPerSample)
475 out->Samples.wValidBitsPerSample = out->Format.wBitsPerSample;
476 else if(out->Samples.wValidBitsPerSample != out->Format.wBitsPerSample)
478 FIXME("Padded samples not supported (%u of %u)\n", out->Samples.wValidBitsPerSample, out->Format.wBitsPerSample);
479 return NULL;
482 if(out->dwChannelMask != MONO && out->dwChannelMask != STEREO &&
483 !prim->SupportedExt[EXT_MCFORMATS] && !prim->SupportedExt[SOFT_BUFFER_SAMPLES])
485 WARN("Multi-channel not available\n");
486 return NULL;
489 if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
491 if(out->Samples.wValidBitsPerSample == 8)
493 *in_type = AL_UNSIGNED_BYTE;
494 switch(out->dwChannelMask)
496 case MONO: *in_chans = AL_MONO;
497 return "AL_FORMAT_MONO8";
498 case STEREO: *in_chans = AL_STEREO;
499 return "AL_FORMAT_STEREO8";
500 case REAR: *in_chans = AL_REAR;
501 return "AL_FORMAT_REAR8";
502 case QUAD: *in_chans = AL_QUAD;
503 return "AL_FORMAT_QUAD8";
504 case X5DOT1: *in_chans = AL_5POINT1;
505 return "AL_FORMAT_51CHN8";
506 case X6DOT1: *in_chans = AL_6POINT1;
507 return "AL_FORMAT_61CHN8";
508 case X7DOT1: *in_chans = AL_7POINT1;
509 return "AL_FORMAT_71CHN8";
510 default: break;
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_FORMAT_MONO16";
520 case STEREO: *in_chans = AL_STEREO;
521 return "AL_FORMAT_STEREO16";
522 case REAR: *in_chans = AL_REAR;
523 return "AL_FORMAT_REAR16";
524 case QUAD: *in_chans = AL_QUAD;
525 return "AL_FORMAT_QUAD16";
526 case X5DOT1: *in_chans = AL_5POINT1;
527 return "AL_FORMAT_51CHN16";
528 case X6DOT1: *in_chans = AL_6POINT1;
529 return "AL_FORMAT_61CHN16";
530 case X7DOT1: *in_chans = AL_7POINT1;
531 return "AL_FORMAT_71CHN16";
532 default: break;
535 #if 0
536 else if(out->Samples.wValidBitsPerSample == 24 &&
537 prim->SupportedExt[SOFT_BUFFER_SAMPLES])
539 *in_type = AL_BYTE3;
540 switch(out->dwChannelMask)
542 case MONO: *in_chans = AL_MONO;
543 return "AL_MONO32F";
544 case STEREO: *in_chans = AL_STEREO;
545 return "AL_STEREO32F";
546 case REAR: *in_chans = AL_REAR;
547 return "AL_REAR32F";
548 case QUAD: *in_chans = AL_QUAD;
549 return "AL_QUAD32F";
550 case X5DOT1: *in_chans = AL_5POINT1;
551 return "AL_5POINT1_32F";
552 case X6DOT1: *in_chans = AL_6POINT1;
553 return "AL_6POINT1_32F";
554 case X7DOT1: *in_chans = AL_7POINT1;
555 return "AL_7POINT1_32F";
556 default: break;
559 #endif
560 else if(out->Samples.wValidBitsPerSample == 32 &&
561 prim->SupportedExt[SOFT_BUFFER_SAMPLES])
563 *in_type = AL_INT;
564 switch(out->dwChannelMask)
566 case MONO: *in_chans = AL_MONO;
567 return "AL_MONO32F";
568 case STEREO: *in_chans = AL_STEREO;
569 return "AL_STEREO32F";
570 case REAR: *in_chans = AL_REAR;
571 return "AL_REAR32F";
572 case QUAD: *in_chans = AL_QUAD;
573 return "AL_QUAD32F";
574 case X5DOT1: *in_chans = AL_5POINT1;
575 return "AL_5POINT1_32F";
576 case X6DOT1: *in_chans = AL_6POINT1;
577 return "AL_6POINT1_32F";
578 case X7DOT1: *in_chans = AL_7POINT1;
579 return "AL_7POINT1_32F";
580 default: break;
584 FIXME("Could not get OpenAL PCM format (%d-bit, channelmask %#x)\n",
585 out->Samples.wValidBitsPerSample, out->dwChannelMask);
586 return NULL;
588 else if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) &&
589 (prim->SupportedExt[EXT_FLOAT32] || prim->SupportedExt[SOFT_BUFFER_SAMPLES]))
591 if(out->Samples.wValidBitsPerSample == 32)
593 *in_type = AL_FLOAT;
594 switch(out->dwChannelMask)
596 case MONO: *in_chans = AL_MONO;
597 return "AL_FORMAT_MONO_FLOAT32";
598 case STEREO: *in_chans = AL_STEREO;
599 return "AL_FORMAT_STEREO_FLOAT32";
600 case REAR: *in_chans = AL_REAR;
601 return "AL_FORMAT_REAR32";
602 case QUAD: *in_chans = AL_QUAD;
603 return "AL_FORMAT_QUAD32";
604 case X5DOT1: *in_chans = AL_5POINT1;
605 return "AL_FORMAT_51CHN32";
606 case X6DOT1: *in_chans = AL_6POINT1;
607 return "AL_FORMAT_61CHN32";
608 case X7DOT1: *in_chans = AL_7POINT1;
609 return "AL_FORMAT_71CHN32";
610 default: break;
613 #if 0
614 else if(out->Samples.wValidBitsPerSample == 64 &&
615 prim->SupportedExt[SOFT_BUFFER_SAMPLES])
617 *in_type = AL_DOUBLE;
618 switch(out->dwChannelMask)
620 case MONO: *in_chans = AL_MONO;
621 return "AL_MONO32F";
622 case STEREO: *in_chans = AL_STEREO;
623 return "AL_STEREO32F";
624 case REAR: *in_chans = AL_REAR;
625 return "AL_REAR32F";
626 case QUAD: *in_chans = AL_QUAD;
627 return "AL_QUAD32F";
628 case X5DOT1: *in_chans = AL_5POINT1;
629 return "AL_5POINT1_32F";
630 case X6DOT1: *in_chans = AL_6POINT1;
631 return "AL_6POINT1_32F";
632 case X7DOT1: *in_chans = AL_7POINT1;
633 return "AL_7POINT1_32F";
634 default: break;
637 #endif
638 else
640 WARN("Invalid float bits: %u\n", out->Samples.wValidBitsPerSample);
641 return NULL;
644 FIXME("Could not get OpenAL float format (%d-bit, channelmask %#x)\n",
645 out->Samples.wValidBitsPerSample, out->dwChannelMask);
646 return NULL;
648 else if(!IsEqualGUID(&out->SubFormat, &GUID_NULL))
649 ERR("Unhandled extensible format: %s\n", debugstr_guid(&out->SubFormat));
650 return NULL;
653 static void DS8Data_Release(DS8Data *This);
654 static HRESULT DS8Data_Create(DS8Data **ppv, const DSBUFFERDESC *desc, DS8Primary *prim)
656 HRESULT hr = DSERR_INVALIDPARAM;
657 const WAVEFORMATEX *format;
658 const char *fmt_str = NULL;
659 DS8Data *pBuffer;
661 format = desc->lpwfxFormat;
662 TRACE("Requested buffer format:\n"
663 " FormatTag = 0x%04x\n"
664 " Channels = %d\n"
665 " SamplesPerSec = %u\n"
666 " AvgBytesPerSec = %u\n"
667 " BlockAlign = %d\n"
668 " BitsPerSample = %d\n",
669 format->wFormatTag, format->nChannels,
670 format->nSamplesPerSec, format->nAvgBytesPerSec,
671 format->nBlockAlign, format->wBitsPerSample);
673 if(format->nBlockAlign == 0)
675 WARN("Invalid BlockAlign specified\n");
676 return DSERR_INVALIDPARAM;
679 /* Generate a new buffer. Supporting the DSBCAPS_LOC* flags properly
680 * will need the EAX-RAM extension. Currently, we just tell the app it
681 * gets what it wanted. */
682 pBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pBuffer));
683 if(!pBuffer)
684 return E_OUTOFMEMORY;
685 pBuffer->ref = 1;
687 pBuffer->dsbflags = desc->dwFlags;
688 if((pBuffer->dsbflags&(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE)) == (DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE))
690 WARN("Hardware and software location requested\n");
691 goto fail;
693 if(!(pBuffer->dsbflags&(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE|DSBCAPS_LOCDEFER)))
694 pBuffer->dsbflags |= DSBCAPS_LOCHARDWARE;
696 pBuffer->buf_size = desc->dwBufferBytes + format->nBlockAlign - 1;
697 pBuffer->buf_size -= pBuffer->buf_size%format->nBlockAlign;
699 hr = DSERR_BUFFERTOOSMALL;
700 if(pBuffer->buf_size < DSBSIZE_MIN)
701 goto fail;
703 hr = DSERR_INVALIDPARAM;
704 if(pBuffer->buf_size > DSBSIZE_MAX)
705 goto fail;
707 pBuffer->numsegs = 1;
708 pBuffer->segsize = pBuffer->buf_size;
709 pBuffer->lastsegsize = pBuffer->buf_size;
711 if(!(pBuffer->dsbflags&DSBCAPS_STATIC) && !prim->ExtAL.BufferSubData &&
712 !prim->ExtAL.BufferSamplesSOFT && !prim->ExtAL.BufferDataStatic)
714 ALCint refresh = FAKE_REFRESH_COUNT;
715 ALuint newSize;
717 alcGetIntegerv(prim->parent->device, ALC_REFRESH, 1, &refresh);
718 getALCError(prim->parent->device);
720 newSize = format->nAvgBytesPerSec/refresh + format->nBlockAlign - 1;
721 newSize -= newSize%format->nBlockAlign;
723 /* Make sure enough buffers are available */
724 if(newSize > pBuffer->buf_size/(QBUFFERS+2))
725 ERR("Buffer segments too large to stream (%u for %u)!\n",
726 newSize, pBuffer->buf_size);
727 else
729 pBuffer->numsegs = pBuffer->buf_size/newSize;
730 pBuffer->segsize = newSize;
731 pBuffer->lastsegsize = pBuffer->buf_size - (newSize*(pBuffer->numsegs-1));
732 TRACE("New streaming buffer (%u chunks, %u : %u sizes)\n",
733 pBuffer->numsegs, pBuffer->segsize, pBuffer->lastsegsize);
737 if(format->wFormatTag == WAVE_FORMAT_PCM)
738 fmt_str = get_fmtstr_PCM(prim, format, &pBuffer->format, &pBuffer->in_chans, &pBuffer->in_type);
739 else if(format->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
740 fmt_str = get_fmtstr_FLOAT(prim, format, &pBuffer->format, &pBuffer->in_chans, &pBuffer->in_type);
741 else if(format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
743 const WAVEFORMATEXTENSIBLE *wfe;
745 hr = DSERR_CONTROLUNAVAIL;
746 if(format->cbSize != sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) &&
747 format->cbSize != sizeof(WAVEFORMATEXTENSIBLE))
748 goto fail;
750 wfe = (const WAVEFORMATEXTENSIBLE*)format;
751 TRACE("Extensible values:\n"
752 " Samples = %d\n"
753 " ChannelMask = %#x\n"
754 " SubFormat = %s\n",
755 wfe->Samples.wReserved, wfe->dwChannelMask,
756 debugstr_guid(&wfe->SubFormat));
758 hr = DSERR_INVALIDCALL;
759 fmt_str = get_fmtstr_EXT(prim, format, &pBuffer->format, &pBuffer->in_chans, &pBuffer->in_type);
761 else
762 ERR("Unhandled formattag 0x%04x\n", format->wFormatTag);
764 if(!fmt_str)
765 goto fail;
767 pBuffer->buf_format = alGetEnumValue(fmt_str);
768 if(alGetError() != AL_NO_ERROR || pBuffer->buf_format == 0 ||
769 pBuffer->buf_format == -1)
771 WARN("Could not get OpenAL format from %s\n", fmt_str);
772 goto fail;
775 hr = E_OUTOFMEMORY;
776 pBuffer->buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pBuffer->buffers)*pBuffer->numsegs);
777 pBuffer->data = HeapAlloc(GetProcessHeap(), 0, pBuffer->buf_size);
778 if(!pBuffer->buffers || !pBuffer->data)
779 goto fail;
781 alGenBuffers(pBuffer->numsegs, pBuffer->buffers);
782 getALError();
784 *ppv = pBuffer;
785 return S_OK;
787 fail:
788 DS8Data_Release(pBuffer);
789 return hr;
792 static void DS8Data_AddRef(DS8Data *data)
794 InterlockedIncrement(&data->ref);
797 /* This function is always called with the device lock held */
798 static void DS8Data_Release(DS8Data *This)
800 if(InterlockedDecrement(&This->ref)) return;
802 TRACE("Deleting %p\n", This);
803 if (This->buffers && This->buffers[0])
805 alDeleteBuffers(This->numsegs, This->buffers);
806 getALError();
808 HeapFree(GetProcessHeap(), 0, This->buffers);
809 HeapFree(GetProcessHeap(), 0, This->data);
810 HeapFree(GetProcessHeap(), 0, This);
813 HRESULT DS8Buffer_Create(DS8Buffer **ppv, DS8Primary *parent, DS8Buffer *orig)
815 HRESULT hr = DSERR_OUTOFMEMORY;
816 DS8Buffer *This;
817 DS8Buffer **bufs;
819 *ppv = NULL;
820 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
821 if(!This) return hr;
823 This->IDirectSoundBuffer8_iface.lpVtbl = (IDirectSoundBuffer8Vtbl*)&DS8Buffer_Vtbl;
824 This->IDirectSound3DBuffer_iface.lpVtbl = (IDirectSound3DBufferVtbl*)&DS8Buffer3d_Vtbl;
825 This->IDirectSoundNotify_iface.lpVtbl = (IDirectSoundNotifyVtbl*)&DS8BufferNot_Vtbl;
826 This->IKsPropertySet_iface.lpVtbl = (IKsPropertySetVtbl*)&DS8BufferProp_Vtbl;
828 This->primary = parent;
829 This->ctx = parent->ctx;
830 This->ExtAL = &parent->ExtAL;
831 This->crst = &parent->crst;
832 This->ref = This->all_ref = 1;
834 if(orig)
836 This->buffer = orig->buffer;
837 DS8Data_AddRef(This->buffer);
840 /* Append to buffer list */
841 bufs = parent->buffers;
842 if(parent->nbuffers == parent->sizebuffers)
844 bufs = HeapReAlloc(GetProcessHeap(), 0, bufs, sizeof(*bufs)*(1+parent->nbuffers));
845 if(!bufs) goto fail;
846 parent->sizebuffers++;
848 parent->buffers = bufs;
849 bufs[parent->nbuffers++] = This;
851 /* Disable until initialized.. */
852 This->ds3dmode = DS3DMODE_DISABLE;
854 *ppv = This;
855 return S_OK;
857 fail:
858 DS8Buffer_Destroy(This);
859 return hr;
862 void DS8Buffer_Destroy(DS8Buffer *This)
864 DWORD idx;
865 TRACE("Destroying %p\n", This);
867 DS8Buffer_removenotify(This);
869 /* Remove from list, if in list */
870 for(idx = 0;idx < This->primary->nbuffers;++idx)
872 if(This->primary->buffers[idx] == This)
874 This->primary->buffers[idx] = This->primary->buffers[This->primary->nbuffers-1];
875 This->primary->nbuffers--;
876 break;
879 setALContext(This->ctx);
880 if(This->source)
882 ALuint *sources;
884 alSourceStop(This->source);
885 alSourcei(This->source, AL_BUFFER, 0);
886 getALError();
888 sources = This->primary->sources;
889 if(This->primary->nsources == This->primary->sizesources)
891 sources = HeapReAlloc(GetProcessHeap(), 0, sources, sizeof(*sources)*(1+This->primary->nsources));
892 if(!sources)
893 alDeleteSources(1, &This->source);
894 else
895 This->primary->sizesources++;
897 if(sources)
899 sources[This->primary->nsources++] = This->source;
900 This->primary->sources = sources;
903 HeapFree(GetProcessHeap(), 0, This->notify);
904 This->source = 0;
905 if(This->buffer)
906 DS8Data_Release(This->buffer);
907 popALContext();
908 HeapFree(GetProcessHeap(), 0, This);
911 static inline DS8Buffer *impl_from_IDirectSoundBuffer8(IDirectSoundBuffer8 *iface)
913 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSoundBuffer8_iface);
916 static HRESULT WINAPI DS8Buffer_QueryInterface(IDirectSoundBuffer8 *iface, REFIID riid, void **ppv)
918 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
920 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
922 *ppv = NULL;
923 if(IsEqualIID(riid, &IID_IUnknown) ||
924 IsEqualIID(riid, &IID_IDirectSoundBuffer))
925 *ppv = &This->IDirectSoundBuffer8_iface;
926 else if(IsEqualIID(riid, &IID_IDirectSoundBuffer8))
928 if(This->primary->parent->is_8)
929 *ppv = &This->IDirectSoundBuffer8_iface;
931 else if(IsEqualIID(riid, &IID_IDirectSound3DBuffer))
933 if((This->buffer->dsbflags&DSBCAPS_CTRL3D))
934 *ppv = &This->IDirectSound3DBuffer_iface;
936 else if(IsEqualIID(riid, &IID_IDirectSoundNotify))
938 if((This->buffer->dsbflags&DSBCAPS_CTRLPOSITIONNOTIFY))
939 *ppv = &This->IDirectSoundNotify_iface;
941 else if(IsEqualIID(riid, &IID_IKsPropertySet))
942 *ppv = &This->IKsPropertySet_iface;
943 else
944 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
946 if(*ppv)
948 IUnknown_AddRef((IUnknown*)*ppv);
949 return S_OK;
952 return E_NOINTERFACE;
955 static ULONG WINAPI DS8Buffer_AddRef(IDirectSoundBuffer8 *iface)
957 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
958 LONG ret;
960 InterlockedIncrement(&This->all_ref);
961 ret = InterlockedIncrement(&This->ref);
962 TRACE("new refcount %d\n", ret);
964 return ret;
967 static ULONG WINAPI DS8Buffer_Release(IDirectSoundBuffer8 *iface)
969 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
970 LONG ret;
972 ret = InterlockedDecrement(&This->ref);
973 TRACE("new refcount %d\n", ret);
974 if(InterlockedDecrement(&This->all_ref) == 0)
975 DS8Buffer_Destroy(This);
977 return ret;
980 static HRESULT WINAPI DS8Buffer_GetCaps(IDirectSoundBuffer8 *iface, DSBCAPS *caps)
982 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
984 TRACE("(%p)->(%p)\n", iface, caps);
986 if(!caps || caps->dwSize < sizeof(*caps))
988 WARN("Invalid DSBCAPS (%p, %u)\n", caps, (caps ? caps->dwSize : 0));
989 return DSERR_INVALIDPARAM;
992 caps->dwFlags = This->buffer->dsbflags;
993 caps->dwBufferBytes = This->buffer->buf_size;
994 caps->dwUnlockTransferRate = 4096;
995 caps->dwPlayCpuOverhead = 0;
996 return S_OK;
999 static HRESULT WINAPI DS8Buffer_GetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD *playpos, DWORD *curpos)
1001 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1002 WAVEFORMATEX *format = &This->buffer->format.Format;
1003 UINT writecursor, pos;
1005 TRACE("(%p)->(%p, %p)\n", iface, playpos, curpos);
1007 EnterCriticalSection(This->crst);
1008 setALContext(This->ctx);
1010 if(This->buffer->numsegs > 1)
1012 ALint queued = QBUFFERS;
1013 alGetSourcei(This->source, AL_BUFFERS_QUEUED, &queued);
1014 getALError();
1016 pos = (This->curidx+This->buffer->numsegs-queued)%This->buffer->numsegs;
1017 pos *= This->buffer->segsize;
1018 writecursor = This->curidx * This->buffer->segsize;
1020 else if(This->ExtAL->BufferSubData || This->ExtAL->BufferSamplesSOFT)
1022 ALint rwpos[2] = { 0, 0 };
1024 alGetSourceiv(This->source, AL_BYTE_RW_OFFSETS_SOFT, rwpos);
1025 getALError();
1027 pos = rwpos[0];
1028 writecursor = rwpos[1];
1030 else
1032 ALint status = 0;
1033 ALint ofs = 0;
1035 alGetSourcei(This->source, AL_BYTE_OFFSET, &ofs);
1036 alGetSourcei(This->source, AL_SOURCE_STATE, &status);
1037 getALError();
1039 pos = ofs;
1040 if(status == AL_PLAYING)
1042 writecursor = format->nSamplesPerSec / 100;
1043 writecursor *= format->nBlockAlign;
1045 else
1046 writecursor = 0;
1047 writecursor = (writecursor + pos) % This->buffer->buf_size;
1049 TRACE("%p Play pos = %u, write pos = %u\n", This, pos, writecursor);
1050 if(pos >= This->buffer->buf_size)
1052 ERR("playpos >= buf_size\n");
1053 pos %= This->buffer->buf_size;
1055 if(writecursor >= This->buffer->buf_size)
1057 ERR("writepos >= buf_size\n");
1058 writecursor %= This->buffer->buf_size;
1061 if(playpos) *playpos = pos;
1062 if(curpos) *curpos = writecursor;
1064 popALContext();
1065 LeaveCriticalSection(This->crst);
1067 return S_OK;
1070 static HRESULT WINAPI DS8Buffer_GetFormat(IDirectSoundBuffer8 *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
1072 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1073 HRESULT hr = S_OK;
1074 UINT size;
1076 TRACE("(%p)->(%p, %u, %p)\n", iface, wfx, allocated, written);
1078 if(!wfx && !written)
1080 WARN("Cannot report format or format size\n");
1081 return DSERR_INVALIDPARAM;
1084 EnterCriticalSection(This->crst);
1085 size = sizeof(This->buffer->format.Format) + This->buffer->format.Format.cbSize;
1086 if(wfx)
1088 if(allocated < size)
1089 hr = DSERR_INVALIDPARAM;
1090 else
1091 memcpy(wfx, &This->buffer->format.Format, size);
1093 if(written)
1094 *written = size;
1095 LeaveCriticalSection(This->crst);
1097 return hr;
1100 static HRESULT WINAPI DS8Buffer_GetVolume(IDirectSoundBuffer8 *iface, LONG *vol)
1102 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1103 HRESULT hr;
1105 TRACE("(%p)->(%p)\n", iface, vol);
1107 if(!vol)
1109 WARN("Invalid pointer\n");
1110 return DSERR_INVALIDPARAM;
1113 EnterCriticalSection(This->crst);
1115 hr = DSERR_CONTROLUNAVAIL;
1116 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
1117 WARN("Volume control not set\n");
1118 else
1120 ALfloat gain = 1.0f;
1122 setALContext(This->ctx);
1123 alGetSourcef(This->source, AL_GAIN, &gain);
1124 getALError();
1125 popALContext();
1127 *vol = gain_to_mB(gain);
1128 *vol = min(*vol, DSBVOLUME_MAX);
1129 *vol = max(*vol, DSBVOLUME_MIN);
1131 hr = DS_OK;
1134 LeaveCriticalSection(This->crst);
1135 return hr;
1138 static HRESULT WINAPI DS8Buffer_GetPan(IDirectSoundBuffer8 *iface, LONG *pan)
1140 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1141 HRESULT hr;
1143 TRACE("(%p)->(%p)\n", iface, pan);
1145 if(!pan)
1147 WARN("Invalid pointer\n");
1148 return DSERR_INVALIDPARAM;
1151 EnterCriticalSection(This->crst);
1153 hr = DSERR_CONTROLUNAVAIL;
1154 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
1155 WARN("Panning control not set\n");
1156 else
1158 ALfloat pos[3];
1160 setALContext(This->ctx);
1161 alGetSourcefv(This->source, AL_POSITION, pos);
1162 getALError();
1163 popALContext();
1165 *pan = (LONG)((pos[0]+1.0) * (DSBPAN_RIGHT-DSBPAN_LEFT) / 2.0 + 0.5) + DSBPAN_LEFT;
1166 *pan = min(*pan, DSBPAN_RIGHT);
1167 *pan = max(*pan, DSBPAN_LEFT);
1169 hr = DS_OK;
1172 LeaveCriticalSection(This->crst);
1173 return hr;
1176 static HRESULT WINAPI DS8Buffer_GetFrequency(IDirectSoundBuffer8 *iface, DWORD *freq)
1178 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1179 HRESULT hr;
1181 TRACE("(%p)->(%p)\n", iface, freq);
1183 if(!freq)
1185 WARN("Invalid pointer\n");
1186 return DSERR_INVALIDPARAM;
1189 EnterCriticalSection(This->crst);
1191 hr = DSERR_CONTROLUNAVAIL;
1192 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
1193 WARN("Frequency control not set\n");
1194 else
1196 ALfloat pitch = 1.0f;
1198 setALContext(This->ctx);
1199 alGetSourcefv(This->source, AL_PITCH, &pitch);
1200 getALError();
1201 popALContext();
1203 *freq = (DWORD)(This->buffer->format.Format.nSamplesPerSec * pitch);
1205 hr = DS_OK;
1208 LeaveCriticalSection(This->crst);
1209 return hr;
1212 static HRESULT WINAPI DS8Buffer_GetStatus(IDirectSoundBuffer8 *iface, DWORD *status)
1214 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1215 ALint state, looping;
1217 TRACE("(%p)->(%p)\n", iface, status);
1219 if(!status)
1221 WARN("Invalid pointer\n");
1222 return DSERR_INVALIDPARAM;
1225 EnterCriticalSection(This->crst);
1227 setALContext(This->ctx);
1228 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1229 looping = This->islooping;
1230 if(This->buffer->numsegs == 1)
1231 alGetSourcei(This->source, AL_LOOPING, &looping);
1232 else if(state != AL_PLAYING)
1233 state = This->isplaying ? AL_PLAYING : AL_PAUSED;
1234 getALError();
1235 popALContext();
1237 *status = 0;
1238 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1240 if((This->buffer->dsbflags&DSBCAPS_LOCSOFTWARE))
1241 *status |= DSBSTATUS_LOCSOFTWARE;
1242 else if((This->buffer->dsbflags&DSBCAPS_LOCHARDWARE))
1243 *status |= DSBSTATUS_LOCHARDWARE;
1245 if(state == AL_PLAYING)
1246 *status |= DSBSTATUS_PLAYING | (looping ? DSBSTATUS_LOOPING : 0);
1248 LeaveCriticalSection(This->crst);
1250 return S_OK;
1253 static HRESULT WINAPI DS8Buffer_Initialize(IDirectSoundBuffer8 *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
1255 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1256 DS3DBUFFER *ds3dbuffer;
1257 HRESULT hr;
1259 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
1261 EnterCriticalSection(This->crst);
1262 setALContext(This->ctx);
1264 hr = DSERR_ALREADYINITIALIZED;
1265 if(This->source)
1266 goto out;
1268 if(!This->buffer)
1270 hr = DSERR_INVALIDPARAM;
1271 if(!desc)
1273 WARN("Missing DSound buffer description\n");
1274 goto out;
1276 if(!desc->lpwfxFormat)
1278 WARN("Missing buffer format (%p)\n", This);
1279 goto out;
1281 if((desc->dwFlags&DSBCAPS_CTRL3D) && desc->lpwfxFormat->nChannels != 1)
1283 if(This->primary->parent->is_8)
1285 /* DirectSoundBuffer8 objects aren't allowed non-mono 3D
1286 * buffers */
1287 WARN("Can't create multi-channel 3D buffers\n");
1288 goto out;
1290 ERR("Multi-channel 3D sounds are not spatialized\n");
1293 hr = DS8Data_Create(&This->buffer, desc, This->primary);
1294 if(FAILED(hr))
1295 goto out;
1296 else
1298 DS8Data *buf = This->buffer;
1300 if(buf->in_type == AL_UNSIGNED_BYTE)
1301 memset(buf->data, 0x80, buf->buf_size);
1302 else
1303 memset(buf->data, 0x00, buf->buf_size);
1305 if(This->ExtAL->BufferDataStatic)
1306 This->ExtAL->BufferDataStatic(buf->buffers[0], buf->buf_format,
1307 buf->data, buf->buf_size,
1308 buf->format.Format.nSamplesPerSec);
1309 else if(This->ExtAL->BufferSamplesSOFT)
1310 This->ExtAL->BufferSamplesSOFT(buf->buffers[0],
1311 buf->format.Format.nSamplesPerSec, buf->buf_format,
1312 buf->buf_size/buf->format.Format.nBlockAlign,
1313 buf->in_chans, buf->in_type, buf->data);
1314 else if(This->ExtAL->BufferSubData)
1315 alBufferData(buf->buffers[0], buf->buf_format,
1316 buf->data, buf->buf_size,
1317 buf->format.Format.nSamplesPerSec);
1319 getALError();
1322 hr = DSERR_GENERIC;
1323 if(This->primary->nsources)
1325 This->source = This->primary->sources[--This->primary->nsources];
1326 alSourcef(This->source, AL_GAIN, 1.0f);
1327 alSourcef(This->source, AL_PITCH, 1.0f);
1328 getALError();
1330 else
1332 alGenSources(1, &This->source);
1333 if(alGetError() != AL_NO_ERROR)
1334 goto out;
1337 ds3dbuffer = &This->ds3dbuffer;
1338 ds3dbuffer->dwSize = sizeof(*ds3dbuffer);
1339 ds3dbuffer->vPosition.x = 0.0;
1340 ds3dbuffer->vPosition.y = 0.0;
1341 ds3dbuffer->vPosition.z = 0.0;
1342 ds3dbuffer->vVelocity.x = 0.0;
1343 ds3dbuffer->vVelocity.y = 0.0;
1344 ds3dbuffer->vVelocity.z = 0.0;
1345 ds3dbuffer->dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
1346 ds3dbuffer->dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
1347 ds3dbuffer->vConeOrientation.x = 0.0;
1348 ds3dbuffer->vConeOrientation.y = 0.0;
1349 ds3dbuffer->vConeOrientation.z = 1.0;
1350 ds3dbuffer->lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
1351 ds3dbuffer->flMinDistance = DS3D_DEFAULTMINDISTANCE;
1352 ds3dbuffer->flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
1353 ds3dbuffer->dwMode = DS3DMODE_NORMAL;
1355 if((This->buffer->dsbflags&DSBCAPS_CTRL3D))
1357 if(This->primary->auxslot != 0)
1359 alSource3i(This->source, AL_AUXILIARY_SEND_FILTER, This->primary->auxslot, 0, AL_FILTER_NULL);
1360 getALError();
1363 hr = IDirectSound3DBuffer_SetAllParameters(&This->IDirectSound3DBuffer_iface, ds3dbuffer, DS3D_IMMEDIATE);
1364 if(FAILED(hr))
1366 ERR("SetAllParameters failed\n");
1367 goto out;
1370 else
1372 ALuint source = This->source;
1374 if(This->primary->auxslot != 0)
1376 /* Simple hack to make reverb affect non-3D sounds too */
1377 alSource3i(source, AL_AUXILIARY_SEND_FILTER, This->primary->auxslot, 0, AL_FILTER_NULL);
1378 /*alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL);*/
1381 /* Non-3D sources aren't distance attenuated */
1382 This->ds3dmode = DS3DMODE_DISABLE;
1383 alSource3f(source, AL_POSITION, 0.0f, 1.0f, 0.0f);
1384 alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
1385 alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
1386 alSourcef(source, AL_CONE_OUTER_GAIN, 1.0f);
1387 alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f);
1388 alSourcef(source, AL_MAX_DISTANCE, 1000.0f);
1389 alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f);
1390 alSourcei(source, AL_CONE_INNER_ANGLE, 360);
1391 alSourcei(source, AL_CONE_OUTER_ANGLE, 360);
1392 alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);
1393 getALError();
1395 hr = S_OK;
1397 out:
1398 popALContext();
1399 LeaveCriticalSection(This->crst);
1401 return hr;
1404 static HRESULT WINAPI DS8Buffer_Lock(IDirectSoundBuffer8 *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
1406 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1407 HRESULT hr;
1408 DWORD remain;
1410 TRACE("(%p)->(%u, %u, %p, %p, %p, %p, 0x%x)\n", This, ofs, bytes, ptr1, len1, ptr2, len2, flags);
1412 if(!ptr1 || !len1)
1414 WARN("Invalid pointer/len %p %p\n", ptr1, len1);
1415 return DSERR_INVALIDPARAM;
1418 EnterCriticalSection(This->crst);
1419 setALContext(This->ctx);
1421 *ptr1 = NULL;
1422 *len1 = 0;
1423 if(ptr2) *ptr2 = NULL;
1424 if(len2) *len2 = 0;
1426 hr = DSERR_INVALIDPARAM;
1427 if((flags&DSBLOCK_FROMWRITECURSOR))
1428 DS8Buffer_GetCurrentPosition(iface, NULL, &ofs);
1429 else if(ofs >= This->buffer->buf_size)
1431 WARN("Invalid ofs %u\n", ofs);
1432 goto out;
1434 if((flags&DSBLOCK_ENTIREBUFFER))
1435 bytes = This->buffer->buf_size;
1436 else if(bytes > This->buffer->buf_size)
1438 WARN("Invalid size %u\n", bytes);
1439 goto out;
1442 *ptr1 = This->buffer->data + ofs;
1443 if(ofs+bytes >= This->buffer->buf_size)
1445 *len1 = This->buffer->buf_size - ofs;
1446 remain = bytes - *len1;
1448 else
1450 *len1 = bytes;
1451 remain = 0;
1454 This->buffer->locked = TRUE;
1456 if(ptr2 && len2 && remain)
1458 *ptr2 = This->buffer->data;
1459 *len2 = remain;
1461 hr = S_OK;
1463 out:
1464 popALContext();
1465 LeaveCriticalSection(This->crst);
1466 return hr;
1469 static HRESULT WINAPI DS8Buffer_Play(IDirectSoundBuffer8 *iface, DWORD res1, DWORD prio, DWORD flags)
1471 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1472 ALint type, state = AL_STOPPED;
1473 HRESULT hr;
1474 (void)res1;
1476 TRACE("%p\n", This);
1478 EnterCriticalSection(This->crst);
1479 setALContext(This->ctx);
1481 hr = DSERR_BUFFERLOST;
1482 if(This->bufferlost)
1484 WARN("Buffer %p lost\n", This);
1485 goto out;
1488 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1490 if(!(This->buffer->dsbflags&(DSBCAPS_LOCHARDWARE|DSBCAPS_LOCSOFTWARE)))
1492 if(flags & DSBPLAY_LOCSOFTWARE)
1493 This->buffer->dsbflags |= DSBCAPS_LOCSOFTWARE;
1494 else
1495 This->buffer->dsbflags |= DSBCAPS_LOCHARDWARE;
1498 else if(prio)
1500 ERR("Invalid priority set for non-deferred buffer %p, %u!\n", This->buffer, prio);
1501 hr = DSERR_INVALIDPARAM;
1502 goto out;
1505 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1506 if(This->buffer->numsegs > 1)
1508 This->islooping = !!(flags&DSBPLAY_LOOPING);
1509 if(state != AL_PLAYING && This->isplaying)
1510 state = AL_PLAYING;
1512 else
1514 alGetSourcei(This->source, AL_SOURCE_TYPE, &type);
1515 alSourcei(This->source, AL_LOOPING, (flags&DSBPLAY_LOOPING) ? AL_TRUE : AL_FALSE);
1517 getALError();
1519 hr = S_OK;
1520 if(state == AL_PLAYING)
1521 goto out;
1523 /* alSourceQueueBuffers will implicitly set type to streaming */
1524 if(This->buffer->numsegs == 1)
1526 if(type != AL_STATIC)
1527 alSourcei(This->source, AL_BUFFER, This->buffer->buffers[0]);
1528 alSourcePlay(This->source);
1530 if(alGetError() != AL_NO_ERROR)
1532 ERR("Couldn't start source\n");
1533 This->curidx = (This->buffer->numsegs-1+This->curidx)%This->buffer->numsegs;
1534 alSourcei(This->source, AL_BUFFER, 0);
1535 getALError();
1536 hr = DSERR_GENERIC;
1537 goto out;
1539 This->isplaying = TRUE;
1541 if(This->nnotify)
1543 DS8Buffer_addnotify(This);
1544 DS8Buffer_starttimer(This->primary);
1546 else if(This->buffer->numsegs > 1)
1547 DS8Buffer_starttimer(This->primary);
1549 out:
1550 popALContext();
1551 LeaveCriticalSection(This->crst);
1552 return hr;
1555 static HRESULT WINAPI DS8Buffer_SetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD pos)
1557 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1558 HRESULT hr;
1559 TRACE("%p\n", This);
1561 EnterCriticalSection(This->crst);
1562 setALContext(This->ctx);
1564 hr = DSERR_INVALIDPARAM;
1565 if(pos >= This->buffer->buf_size)
1566 goto out;
1568 if(This->buffer->numsegs > 1)
1570 DS8Data *buf = This->buffer;
1571 This->curidx = pos/buf->segsize;
1572 if(This->curidx >= buf->numsegs)
1573 This->curidx = buf->numsegs - 1;
1574 if(This->isplaying)
1576 alSourceStop(This->source);
1577 alSourcei(This->source, AL_BUFFER, 0);
1578 getALError();
1581 else
1582 alSourcei(This->source, AL_BYTE_OFFSET, pos);
1583 This->lastpos = pos;
1584 hr = S_OK;
1586 out:
1587 popALContext();
1588 LeaveCriticalSection(This->crst);
1589 return hr;
1592 static HRESULT WINAPI DS8Buffer_SetFormat(IDirectSoundBuffer8 *iface, const WAVEFORMATEX *wfx)
1594 /* This call only works on primary buffers */
1595 WARN("(%p)->(%p)\n", iface, wfx);
1596 return DSERR_INVALIDCALL;
1599 static HRESULT WINAPI DS8Buffer_SetVolume(IDirectSoundBuffer8 *iface, LONG vol)
1601 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1602 HRESULT hr = S_OK;
1604 TRACE("(%p)->(%d)\n", iface, vol);
1606 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
1608 WARN("Invalid volume (%d)\n", vol);
1609 return DSERR_INVALIDPARAM;
1612 EnterCriticalSection(This->crst);
1613 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
1614 hr = DSERR_CONTROLUNAVAIL;
1615 if(SUCCEEDED(hr))
1617 ALfloat fvol = mB_to_gain(vol);
1618 setALContext(This->ctx);
1619 alSourcef(This->source, AL_GAIN, fvol);
1620 popALContext();
1622 LeaveCriticalSection(This->crst);
1624 return hr;
1627 static HRESULT WINAPI DS8Buffer_SetPan(IDirectSoundBuffer8 *iface, LONG pan)
1629 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1630 HRESULT hr = S_OK;
1632 TRACE("(%p)->(%d)\n", iface, pan);
1634 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
1636 WARN("invalid parameter: pan = %d\n", pan);
1637 return DSERR_INVALIDPARAM;
1640 EnterCriticalSection(This->crst);
1641 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
1642 hr = DSERR_CONTROLUNAVAIL;
1643 else
1645 ALfloat pos[3];
1646 pos[0] = (pan-DSBPAN_LEFT) * 2.0 / (ALfloat)(DSBPAN_RIGHT-DSBPAN_LEFT) - 1.0;
1647 /* NOTE: Strict movement along the X plane can cause the sound to jump
1648 * between left and right sharply. Using a curved path helps smooth it
1649 * out */
1650 pos[1] = sqrt(1.0 - pos[0]*pos[0]);
1651 pos[2] = 0.0;
1653 setALContext(This->ctx);
1654 alSourcefv(This->source, AL_POSITION, pos);
1655 getALError();
1656 popALContext();
1658 if(pan != 0 && This->buffer->format.Format.nChannels > 1)
1659 FIXME("Panning for multi-channel buffers is not supported\n");
1661 LeaveCriticalSection(This->crst);
1663 return hr;
1666 static HRESULT WINAPI DS8Buffer_SetFrequency(IDirectSoundBuffer8 *iface, DWORD freq)
1668 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1669 HRESULT hr = S_OK;
1671 TRACE("(%p)->(%u)\n", iface, freq);
1673 if(freq < DSBFREQUENCY_MIN || freq > DSBFREQUENCY_MAX)
1675 WARN("invalid parameter: freq = %d\n", freq);
1676 return DSERR_INVALIDPARAM;
1679 EnterCriticalSection(This->crst);
1680 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
1681 hr = DSERR_CONTROLUNAVAIL;
1682 else
1684 ALfloat pitch = 1.0f;
1685 if(freq != DSBFREQUENCY_ORIGINAL)
1686 pitch = freq / (ALfloat)This->buffer->format.Format.nSamplesPerSec;
1688 setALContext(This->ctx);
1689 alSourcef(This->source, AL_PITCH, pitch);
1690 getALError();
1691 popALContext();
1693 LeaveCriticalSection(This->crst);
1694 return hr;
1697 static HRESULT WINAPI DS8Buffer_Stop(IDirectSoundBuffer8 *iface)
1699 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1700 ALint state;
1702 TRACE("(%p)->()\n", iface);
1704 EnterCriticalSection(This->crst);
1705 setALContext(This->ctx);
1707 alSourcePause(This->source);
1708 getALError();
1709 /* Mac OS X doesn't immediately report state change
1710 * if Play() is immediately called after Stop, this can be fatal,
1711 * the buffer would never be restarted
1713 do {
1714 state = AL_PAUSED;
1715 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1716 if(state != AL_PLAYING)
1717 break;
1718 Sleep(1);
1719 } while(1);
1721 /* Stopped, remove from notify list */
1722 if(This->nnotify)
1724 HRESULT hr;
1725 DWORD pos = This->lastpos;
1726 hr = IDirectSoundBuffer8_GetCurrentPosition(iface, &pos, NULL);
1727 if(FAILED(hr))
1728 ERR("Own getcurrentposition failed!\n");
1729 trigger_notifies(This, This->lastpos, pos, TRUE);
1730 This->lastpos = pos;
1731 DS8Buffer_removenotify(This);
1734 This->isplaying = FALSE;
1736 popALContext();
1737 LeaveCriticalSection(This->crst);
1739 return S_OK;
1742 static HRESULT WINAPI DS8Buffer_Unlock(IDirectSoundBuffer8 *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
1744 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1745 DS8Data *buf = This->buffer;
1746 DWORD bufsize = buf->buf_size;
1747 DWORD_PTR ofs1, ofs2;
1748 DWORD_PTR boundary = (DWORD_PTR)buf->data;
1749 HRESULT hr;
1751 TRACE("(%p)->(%p, %u, %p, %u)\n", iface, ptr1, len1, ptr2, len2);
1753 EnterCriticalSection(This->crst);
1754 setALContext(This->ctx);
1756 This->buffer->locked = 0;
1757 hr = DSERR_INVALIDPARAM;
1759 /* Make sure offset is between boundary and boundary + bufsize */
1760 ofs1 = (DWORD_PTR)ptr1;
1761 ofs2 = (DWORD_PTR)ptr2;
1762 if(ofs1 < boundary)
1763 goto out;
1764 if(ofs2 && ofs2 != boundary)
1765 goto out;
1766 ofs1 -= boundary;
1767 ofs2 = 0;
1768 if(bufsize-ofs1 < len1 || len2 > ofs1)
1769 goto out;
1770 if(!ptr2)
1771 len2 = 0;
1773 hr = S_OK;
1774 if(!len1 && !len2)
1775 goto out;
1777 if(This->ExtAL->BufferDataStatic)
1778 goto out;
1780 if(This->ExtAL->BufferSubSamplesSOFT)
1782 WAVEFORMATEX *format = &buf->format.Format;
1784 ptr1 = (BYTE*)ptr1 - (ofs1%format->nBlockAlign);
1785 ofs1 /= format->nBlockAlign;
1786 len1 /= format->nBlockAlign;
1787 if(len1 > 0)
1788 This->ExtAL->BufferSubSamplesSOFT(buf->buffers[0], ofs1, len1,
1789 buf->in_chans, buf->in_type, ptr1);
1790 ptr2 = (BYTE*)ptr2 - (ofs2%format->nBlockAlign);
1791 ofs2 /= format->nBlockAlign;
1792 len2 /= format->nBlockAlign;
1793 if(len2 > 0)
1794 This->ExtAL->BufferSubSamplesSOFT(buf->buffers[0], ofs2, len2,
1795 buf->in_chans, buf->in_type, ptr2);
1796 getALError();
1798 else if(This->ExtAL->BufferSubData)
1800 WAVEFORMATEX *format = &buf->format.Format;
1802 len1 -= len1%format->nBlockAlign;
1803 if(len1 > 0)
1804 This->ExtAL->BufferSubData(buf->buffers[0], buf->buf_format, ptr1,
1805 ofs1, len1);
1806 len2 -= len2%format->nBlockAlign;
1807 if(len2 > 0)
1808 This->ExtAL->BufferSubData(buf->buffers[0], buf->buf_format, ptr2,
1809 ofs2, len2);
1810 getALError();
1812 else
1814 alBufferData(buf->buffers[0], buf->buf_format,
1815 buf->data, buf->buf_size,
1816 buf->format.Format.nSamplesPerSec);
1817 getALError();
1820 out:
1821 if(hr != S_OK)
1822 WARN("Invalid parameters (0x%lx,%u) (%p,%u,%p,%u)\n", boundary, bufsize, ptr1, len1, ptr2, len2);
1823 popALContext();
1824 LeaveCriticalSection(This->crst);
1825 return hr;
1828 static HRESULT WINAPI DS8Buffer_Restore(IDirectSoundBuffer8 *iface)
1830 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1831 HRESULT hr;
1833 TRACE("(%p)->()\n", iface);
1835 EnterCriticalSection(This->crst);
1836 if(This->primary->parent->prio_level < DSSCL_WRITEPRIMARY ||
1837 iface == This->primary->write_emu)
1839 This->bufferlost = 0;
1840 hr = S_OK;
1842 else
1843 hr = DSERR_BUFFERLOST;
1844 LeaveCriticalSection(This->crst);
1846 return hr;
1849 static HRESULT WINAPI DS8Buffer_SetFX(IDirectSoundBuffer8 *iface, DWORD fxcount, DSEFFECTDESC *desc, DWORD *rescodes)
1851 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1852 DWORD i;
1854 TRACE("(%p)->(%u, %p, %p)\n", This, fxcount, desc, rescodes);
1856 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFX))
1858 WARN("FX control not set\n");
1859 return DSERR_CONTROLUNAVAIL;
1862 if(fxcount == 0)
1864 if(desc || rescodes)
1866 WARN("Non-NULL desc and/or result pointer specified with no effects.\n");
1867 return DSERR_INVALIDPARAM;
1870 /* No effects; we can handle that */
1871 return DS_OK;
1874 if(!desc || !rescodes)
1876 WARN("NULL desc and/or result pointer specified.\n");
1877 return DSERR_INVALIDPARAM;
1880 /* We don't (currently) handle DSound effects */
1881 for(i = 0;i < fxcount;++i)
1883 FIXME("Cannot handle effect: %s\n", debugstr_guid(&desc[i].guidDSFXClass));
1884 rescodes[i] = DSFXR_FAILED;
1887 return DSERR_INVALIDPARAM;
1890 static HRESULT WINAPI DS8Buffer_AcquireResources(IDirectSoundBuffer8 *iface, DWORD flags, DWORD fxcount, DWORD *rescodes)
1892 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1894 TRACE("(%p)->(%u, %u, %p)\n", This, flags, fxcount, rescodes);
1896 /* effects aren't supported at the moment.. */
1897 if(fxcount != 0 || rescodes)
1899 WARN("Non-zero effect count and/or result pointer specified with no effects.\n");
1900 return DSERR_INVALIDPARAM;
1903 EnterCriticalSection(This->crst);
1904 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1906 This->buffer->dsbflags &= ~(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE);
1907 if((flags&DSBPLAY_LOCSOFTWARE))
1908 This->buffer->dsbflags |= DSBCAPS_LOCSOFTWARE;
1909 else
1910 This->buffer->dsbflags |= DSBCAPS_LOCHARDWARE;
1912 LeaveCriticalSection(This->crst);
1914 return S_OK;
1917 static HRESULT WINAPI DS8Buffer_GetObjectInPath(IDirectSoundBuffer8 *iface, REFGUID guid, DWORD idx, REFGUID rguidiface, void **ppv)
1919 FIXME("(%p)->(%s, %u, %s, %p) : stub!\n", iface, debugstr_guid(guid), idx, debugstr_guid(rguidiface), ppv);
1920 return E_NOTIMPL;
1923 static const IDirectSoundBuffer8Vtbl DS8Buffer_Vtbl =
1925 DS8Buffer_QueryInterface,
1926 DS8Buffer_AddRef,
1927 DS8Buffer_Release,
1928 DS8Buffer_GetCaps,
1929 DS8Buffer_GetCurrentPosition,
1930 DS8Buffer_GetFormat,
1931 DS8Buffer_GetVolume,
1932 DS8Buffer_GetPan,
1933 DS8Buffer_GetFrequency,
1934 DS8Buffer_GetStatus,
1935 DS8Buffer_Initialize,
1936 DS8Buffer_Lock,
1937 DS8Buffer_Play,
1938 DS8Buffer_SetCurrentPosition,
1939 DS8Buffer_SetFormat,
1940 DS8Buffer_SetVolume,
1941 DS8Buffer_SetPan,
1942 DS8Buffer_SetFrequency,
1943 DS8Buffer_Stop,
1944 DS8Buffer_Unlock,
1945 DS8Buffer_Restore,
1946 DS8Buffer_SetFX,
1947 DS8Buffer_AcquireResources,
1948 DS8Buffer_GetObjectInPath
1951 static inline DS8Buffer *impl_from_IDirectSound3DBuffer(IDirectSound3DBuffer *iface)
1953 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSound3DBuffer_iface);
1956 static HRESULT WINAPI DS8Buffer3D_QueryInterface(IDirectSound3DBuffer *iface, REFIID riid, void **ppv)
1958 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1959 return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
1962 static ULONG WINAPI DS8Buffer3D_AddRef(IDirectSound3DBuffer *iface)
1964 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1965 LONG ret;
1967 InterlockedIncrement(&This->all_ref);
1968 ret = InterlockedIncrement(&This->ds3d_ref);
1969 TRACE("new refcount %d\n", ret);
1971 return ret;
1974 static ULONG WINAPI DS8Buffer3D_Release(IDirectSound3DBuffer *iface)
1976 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1977 LONG ret;
1979 ret = InterlockedDecrement(&This->ds3d_ref);
1980 TRACE("new refcount %d\n", ret);
1981 if(InterlockedDecrement(&This->all_ref) == 0)
1982 DS8Buffer_Destroy(This);
1984 return ret;
1987 static HRESULT WINAPI DS8Buffer3D_GetAllParameters(IDirectSound3DBuffer *iface, DS3DBUFFER *ds3dbuffer)
1989 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1990 DS3DBUFFER ds3dbuf;
1991 HRESULT hr;
1993 TRACE("%p\n", This);
1995 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
1997 WARN("Invalid parameters %p %u\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
1998 return DSERR_INVALIDPARAM;
2000 ds3dbuf.dwSize = sizeof(ds3dbuf);
2002 EnterCriticalSection(This->crst);
2003 setALContext(This->ctx);
2005 hr = IDirectSound3DBuffer_GetPosition(iface, &ds3dbuf.vPosition);
2006 if(SUCCEEDED(hr))
2007 hr = IDirectSound3DBuffer_GetVelocity(iface, &ds3dbuf.vVelocity);
2008 if(SUCCEEDED(hr))
2009 hr = IDirectSound3DBuffer_GetConeAngles(iface, &ds3dbuf.dwInsideConeAngle, &ds3dbuf.dwOutsideConeAngle);
2010 if(SUCCEEDED(hr))
2011 hr = IDirectSound3DBuffer_GetConeOrientation(iface, &ds3dbuf.vConeOrientation);
2012 if(SUCCEEDED(hr))
2013 hr = IDirectSound3DBuffer_GetConeOutsideVolume(iface, &ds3dbuf.lConeOutsideVolume);
2014 if(SUCCEEDED(hr))
2015 hr = IDirectSound3DBuffer_GetMinDistance(iface, &ds3dbuf.flMinDistance);
2016 if(SUCCEEDED(hr))
2017 hr = IDirectSound3DBuffer_GetMaxDistance(iface, &ds3dbuf.flMaxDistance);
2018 if(SUCCEEDED(hr))
2019 hr = IDirectSound3DBuffer_GetMode(iface, &ds3dbuf.dwMode);
2020 if(SUCCEEDED(hr))
2021 memcpy(ds3dbuffer, &ds3dbuf, sizeof(ds3dbuf));
2023 popALContext();
2024 LeaveCriticalSection(This->crst);
2026 return hr;
2029 static HRESULT WINAPI DS8Buffer3D_GetConeAngles(IDirectSound3DBuffer *iface, DWORD *pdwInsideConeAngle, DWORD *pdwOutsideConeAngle)
2031 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2032 ALint inangle, outangle;
2034 TRACE("(%p)->(%p, %p)\n", This, pdwInsideConeAngle, pdwOutsideConeAngle);
2035 if(!pdwInsideConeAngle || !pdwOutsideConeAngle)
2037 WARN("Invalid pointers (%p, %p)\n", pdwInsideConeAngle, pdwOutsideConeAngle);
2038 return DSERR_INVALIDPARAM;
2041 EnterCriticalSection(This->crst);
2042 setALContext(This->ctx);
2044 alGetSourcei(This->source, AL_CONE_INNER_ANGLE, &inangle);
2045 alGetSourcei(This->source, AL_CONE_OUTER_ANGLE, &outangle);
2046 getALError();
2047 *pdwInsideConeAngle = inangle;
2048 *pdwOutsideConeAngle = outangle;
2050 popALContext();
2051 LeaveCriticalSection(This->crst);
2053 return S_OK;
2056 static HRESULT WINAPI DS8Buffer3D_GetConeOrientation(IDirectSound3DBuffer *iface, D3DVECTOR *orient)
2058 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2059 ALfloat dir[3];
2061 TRACE("(%p)->(%p)\n", This, orient);
2062 if(!orient)
2064 WARN("Invalid pointer\n");
2065 return DSERR_INVALIDPARAM;
2068 EnterCriticalSection(This->crst);
2069 setALContext(This->ctx);
2071 alGetSourcefv(This->source, AL_DIRECTION, dir);
2072 getALError();
2073 orient->x = dir[0];
2074 orient->y = dir[1];
2075 orient->z = -dir[2];
2077 popALContext();
2078 LeaveCriticalSection(This->crst);
2080 return S_OK;
2083 static HRESULT WINAPI DS8Buffer3D_GetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG *vol)
2085 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2086 ALfloat gain;
2088 TRACE("(%p)->(%p)\n", This, vol);
2089 if(!vol)
2091 WARN("Invalid pointer\n");
2092 return DSERR_INVALIDPARAM;
2095 EnterCriticalSection(This->crst);
2096 setALContext(This->ctx);
2098 alGetSourcef(This->source, AL_CONE_OUTER_GAIN, &gain);
2099 getALError();
2100 *vol = gain_to_mB(gain);
2101 *vol = max(*vol, DSBVOLUME_MIN);
2102 *vol = min(*vol, DSBVOLUME_MAX);
2104 popALContext();
2105 LeaveCriticalSection(This->crst);
2106 return S_OK;
2109 static HRESULT WINAPI DS8Buffer3D_GetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE *maxdist)
2111 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2112 ALfloat dist;
2114 TRACE("(%p)->(%p)\n", This, maxdist);
2115 if(!maxdist)
2117 WARN("Invalid pointer\n");
2118 return DSERR_INVALIDPARAM;
2121 EnterCriticalSection(This->crst);
2122 setALContext(This->ctx);
2124 alGetSourcef(This->source, AL_MAX_DISTANCE, &dist);
2125 getALError();
2126 *maxdist = dist;
2128 popALContext();
2129 LeaveCriticalSection(This->crst);
2131 return S_OK;
2134 static HRESULT WINAPI DS8Buffer3D_GetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE *mindist)
2136 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2137 ALfloat dist;
2139 TRACE("(%p)->(%p)\n", This, mindist);
2140 if(!mindist)
2142 WARN("Invalid pointer\n");
2143 return DSERR_INVALIDPARAM;
2146 EnterCriticalSection(This->crst);
2147 setALContext(This->ctx);
2149 alGetSourcef(This->source, AL_REFERENCE_DISTANCE, &dist);
2150 getALError();
2151 *mindist = dist;
2153 popALContext();
2154 LeaveCriticalSection(This->crst);
2156 return S_OK;
2159 static HRESULT WINAPI DS8Buffer3D_GetMode(IDirectSound3DBuffer *iface, DWORD *mode)
2161 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2163 TRACE("(%p)->(%p)\n", This, mode);
2164 if(!mode)
2166 WARN("Invalid pointer\n");
2167 return DSERR_INVALIDPARAM;
2170 EnterCriticalSection(This->crst);
2171 *mode = This->ds3dmode;
2172 LeaveCriticalSection(This->crst);
2174 return S_OK;
2177 static HRESULT WINAPI DS8Buffer3D_GetPosition(IDirectSound3DBuffer *iface, D3DVECTOR *pos)
2179 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2180 ALfloat alpos[3];
2182 TRACE("(%p)->(%p)\n", This, pos);
2183 if(!pos)
2185 WARN("Invalid pointer\n");
2186 return DSERR_INVALIDPARAM;
2189 EnterCriticalSection(This->crst);
2190 setALContext(This->ctx);
2192 alGetSourcefv(This->source, AL_POSITION, alpos);
2193 getALError();
2194 pos->x = alpos[0];
2195 pos->y = alpos[1];
2196 pos->z = -alpos[2];
2198 popALContext();
2199 LeaveCriticalSection(This->crst);
2201 return S_OK;
2204 static HRESULT WINAPI DS8Buffer3D_GetVelocity(IDirectSound3DBuffer *iface, D3DVECTOR *vel)
2206 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2207 ALfloat alvel[3];
2209 TRACE("(%p)->(%p)\n", This, vel);
2210 if(!vel)
2212 WARN("Invalid pointer\n");
2213 return DSERR_INVALIDPARAM;
2216 EnterCriticalSection(This->crst);
2217 setALContext(This->ctx);
2219 alGetSourcefv(This->source, AL_VELOCITY, alvel);
2220 getALError();
2221 vel->x = alvel[0];
2222 vel->y = alvel[1];
2223 vel->z = -alvel[2];
2225 popALContext();
2226 LeaveCriticalSection(This->crst);
2228 return S_OK;
2231 static HRESULT WINAPI DS8Buffer3D_SetAllParameters(IDirectSound3DBuffer *iface, const DS3DBUFFER *ds3dbuffer, DWORD apply)
2233 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2234 TRACE("(%p)->(%p, %u)\n", This, ds3dbuffer, apply);
2236 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
2238 WARN("Invalid DS3DBUFFER (%p, %u)\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
2239 return DSERR_INVALIDPARAM;
2242 if(ds3dbuffer->dwInsideConeAngle > DS3D_MAXCONEANGLE ||
2243 ds3dbuffer->dwOutsideConeAngle > DS3D_MAXCONEANGLE)
2245 WARN("Invalid cone angles (%u, %u)\n", ds3dbuffer->dwInsideConeAngle,
2246 ds3dbuffer->dwOutsideConeAngle);
2247 return DSERR_INVALIDPARAM;
2250 if(ds3dbuffer->lConeOutsideVolume > DSBVOLUME_MAX ||
2251 ds3dbuffer->lConeOutsideVolume < DSBVOLUME_MIN)
2253 WARN("Invalid cone outside volume (%d)\n", ds3dbuffer->lConeOutsideVolume);
2254 return DSERR_INVALIDPARAM;
2257 if(ds3dbuffer->flMaxDistance < 0.0f)
2259 WARN("Invalid max distance (%f)\n", ds3dbuffer->flMaxDistance);
2260 return DSERR_INVALIDPARAM;
2263 if(ds3dbuffer->flMinDistance < 0.0f)
2265 WARN("Invalid min distance (%f)\n", ds3dbuffer->flMinDistance);
2266 return DSERR_INVALIDPARAM;
2269 if(ds3dbuffer->dwMode != DS3DMODE_NORMAL &&
2270 ds3dbuffer->dwMode != DS3DMODE_HEADRELATIVE &&
2271 ds3dbuffer->dwMode != DS3DMODE_DISABLE)
2273 WARN("Invalid mode (%u)\n", ds3dbuffer->dwMode);
2274 return DSERR_INVALIDPARAM;
2277 EnterCriticalSection(This->crst);
2278 setALContext(This->ctx);
2279 IDirectSound3DBuffer_SetPosition(iface, ds3dbuffer->vPosition.x, ds3dbuffer->vPosition.y, ds3dbuffer->vPosition.z, apply);
2280 IDirectSound3DBuffer_SetVelocity(iface, ds3dbuffer->vVelocity.x, ds3dbuffer->vVelocity.y, ds3dbuffer->vVelocity.z, apply);
2281 IDirectSound3DBuffer_SetConeAngles(iface, ds3dbuffer->dwInsideConeAngle, ds3dbuffer->dwOutsideConeAngle, apply);
2282 IDirectSound3DBuffer_SetConeOrientation(iface, ds3dbuffer->vConeOrientation.x, ds3dbuffer->vConeOrientation.y, ds3dbuffer->vConeOrientation.z, apply);
2283 IDirectSound3DBuffer_SetConeOutsideVolume(iface, ds3dbuffer->lConeOutsideVolume, apply);
2284 IDirectSound3DBuffer_SetMinDistance(iface, ds3dbuffer->flMinDistance, apply);
2285 IDirectSound3DBuffer_SetMaxDistance(iface, ds3dbuffer->flMaxDistance, apply);
2286 IDirectSound3DBuffer_SetMode(iface, ds3dbuffer->dwMode, apply);
2287 popALContext();
2288 LeaveCriticalSection(This->crst);
2290 return S_OK;
2293 static HRESULT WINAPI DS8Buffer3D_SetConeAngles(IDirectSound3DBuffer *iface, DWORD dwInsideConeAngle, DWORD dwOutsideConeAngle, DWORD apply)
2295 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2297 TRACE("(%p)->(%u, %u, %u)\n", This, dwInsideConeAngle, dwOutsideConeAngle, apply);
2298 if(dwInsideConeAngle > DS3D_MAXCONEANGLE ||
2299 dwOutsideConeAngle > DS3D_MAXCONEANGLE)
2301 WARN("Invalid cone angles (%u, %u)\n", dwInsideConeAngle, dwOutsideConeAngle);
2302 return DSERR_INVALIDPARAM;
2305 EnterCriticalSection(This->crst);
2306 if(apply == DS3D_DEFERRED)
2308 This->ds3dbuffer.dwInsideConeAngle = dwInsideConeAngle;
2309 This->ds3dbuffer.dwOutsideConeAngle = dwOutsideConeAngle;
2310 This->dirty.bit.cone_angles = 1;
2312 else
2314 setALContext(This->ctx);
2315 alSourcei(This->source, AL_CONE_INNER_ANGLE, dwInsideConeAngle);
2316 alSourcei(This->source, AL_CONE_OUTER_ANGLE, dwOutsideConeAngle);
2317 getALError();
2318 popALContext();
2320 LeaveCriticalSection(This->crst);
2322 return S_OK;
2325 static HRESULT WINAPI DS8Buffer3D_SetConeOrientation(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2327 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2329 TRACE("(%p)->(%f, %f, %f, %u)\n", This, x, y, z, apply);
2331 EnterCriticalSection(This->crst);
2332 if(apply == DS3D_DEFERRED)
2334 This->ds3dbuffer.vConeOrientation.x = x;
2335 This->ds3dbuffer.vConeOrientation.y = y;
2336 This->ds3dbuffer.vConeOrientation.z = z;
2337 This->dirty.bit.cone_orient = 1;
2339 else
2341 setALContext(This->ctx);
2342 alSource3f(This->source, AL_DIRECTION, x, y, -z);
2343 getALError();
2344 popALContext();
2346 LeaveCriticalSection(This->crst);
2348 return S_OK;
2351 static HRESULT WINAPI DS8Buffer3D_SetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG vol, DWORD apply)
2353 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2355 TRACE("(%p)->(%u, %u)\n", This, vol, apply);
2356 if(vol < DSBVOLUME_MIN || vol > DSBVOLUME_MAX)
2358 WARN("Invalid volume (%u)\n", vol);
2359 return DSERR_INVALIDPARAM;
2362 EnterCriticalSection(This->crst);
2363 if(apply == DS3D_DEFERRED)
2365 This->ds3dbuffer.lConeOutsideVolume = vol;
2366 This->dirty.bit.cone_outsidevolume = 1;
2368 else
2370 setALContext(This->ctx);
2371 alSourcef(This->source, AL_CONE_OUTER_GAIN, mB_to_gain(vol));
2372 getALError();
2373 popALContext();
2375 LeaveCriticalSection(This->crst);
2377 return S_OK;
2380 static HRESULT WINAPI DS8Buffer3D_SetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE maxdist, DWORD apply)
2382 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2384 TRACE("(%p)->(%f, %u)\n", This, maxdist, apply);
2385 if(maxdist < 0.0f)
2387 WARN("Invalid max distance (%f)\n", maxdist);
2388 return DSERR_INVALIDPARAM;
2391 EnterCriticalSection(This->crst);
2392 if(apply == DS3D_DEFERRED)
2394 This->ds3dbuffer.flMaxDistance = maxdist;
2395 This->dirty.bit.max_distance = 1;
2397 else
2399 setALContext(This->ctx);
2400 alSourcef(This->source, AL_MAX_DISTANCE, maxdist);
2401 getALError();
2402 popALContext();
2404 LeaveCriticalSection(This->crst);
2406 return S_OK;
2409 static HRESULT WINAPI DS8Buffer3D_SetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE mindist, DWORD apply)
2411 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2413 TRACE("(%p)->(%f, %u)\n", This, mindist, apply);
2414 if(mindist < 0.0f)
2416 WARN("Invalid min distance (%f)\n", mindist);
2417 return DSERR_INVALIDPARAM;
2420 EnterCriticalSection(This->crst);
2421 if(apply == DS3D_DEFERRED)
2423 This->ds3dbuffer.flMinDistance = mindist;
2424 This->dirty.bit.min_distance = 1;
2426 else
2428 setALContext(This->ctx);
2429 alSourcef(This->source, AL_REFERENCE_DISTANCE, mindist);
2430 getALError();
2431 popALContext();
2433 LeaveCriticalSection(This->crst);
2435 return S_OK;
2438 static HRESULT WINAPI DS8Buffer3D_SetMode(IDirectSound3DBuffer *iface, DWORD mode, DWORD apply)
2440 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2442 TRACE("(%p)->(%u, %u)\n", This, mode, apply);
2443 if(mode != DS3DMODE_NORMAL && mode != DS3DMODE_HEADRELATIVE &&
2444 mode != DS3DMODE_DISABLE)
2446 WARN("Invalid mode (%u)\n", mode);
2447 return DSERR_INVALIDPARAM;
2450 EnterCriticalSection(This->crst);
2451 if(apply == DS3D_DEFERRED)
2453 This->ds3dbuffer.dwMode = mode;
2454 This->dirty.bit.mode = 1;
2456 else
2458 setALContext(This->ctx);
2459 alSourcei(This->source, AL_SOURCE_RELATIVE,
2460 (mode != DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE);
2461 alSourcef(This->source, AL_ROLLOFF_FACTOR,
2462 (mode == DS3DMODE_DISABLE) ? 0.0f : This->primary->rollofffactor);
2463 This->ds3dmode = mode;
2464 getALError();
2465 popALContext();
2467 LeaveCriticalSection(This->crst);
2469 return S_OK;
2472 static HRESULT WINAPI DS8Buffer3D_SetPosition(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2474 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2476 TRACE("(%p)->(%f, %f, %f, %u)\n", This, x, y, z, apply);
2478 EnterCriticalSection(This->crst);
2479 if(apply == DS3D_DEFERRED)
2481 This->ds3dbuffer.vPosition.x = x;
2482 This->ds3dbuffer.vPosition.y = y;
2483 This->ds3dbuffer.vPosition.z = z;
2484 This->dirty.bit.pos = 1;
2486 else
2488 setALContext(This->ctx);
2489 alSource3f(This->source, AL_POSITION, x, y, -z);
2490 getALError();
2491 popALContext();
2493 LeaveCriticalSection(This->crst);
2495 return S_OK;
2498 static HRESULT WINAPI DS8Buffer3D_SetVelocity(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2500 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2502 TRACE("(%p)->(%f, %f, %f, %u)\n", This, x, y, z, apply);
2504 EnterCriticalSection(This->crst);
2505 if(apply == DS3D_DEFERRED)
2507 This->ds3dbuffer.vVelocity.x = x;
2508 This->ds3dbuffer.vVelocity.y = y;
2509 This->ds3dbuffer.vVelocity.z = z;
2510 This->dirty.bit.vel = 1;
2512 else
2514 setALContext(This->ctx);
2515 alSource3f(This->source, AL_VELOCITY, x, y, -z);
2516 getALError();
2517 popALContext();
2519 LeaveCriticalSection(This->crst);
2521 return S_OK;
2524 static const IDirectSound3DBufferVtbl DS8Buffer3d_Vtbl =
2526 DS8Buffer3D_QueryInterface,
2527 DS8Buffer3D_AddRef,
2528 DS8Buffer3D_Release,
2529 DS8Buffer3D_GetAllParameters,
2530 DS8Buffer3D_GetConeAngles,
2531 DS8Buffer3D_GetConeOrientation,
2532 DS8Buffer3D_GetConeOutsideVolume,
2533 DS8Buffer3D_GetMaxDistance,
2534 DS8Buffer3D_GetMinDistance,
2535 DS8Buffer3D_GetMode,
2536 DS8Buffer3D_GetPosition,
2537 DS8Buffer3D_GetVelocity,
2538 DS8Buffer3D_SetAllParameters,
2539 DS8Buffer3D_SetConeAngles,
2540 DS8Buffer3D_SetConeOrientation,
2541 DS8Buffer3D_SetConeOutsideVolume,
2542 DS8Buffer3D_SetMaxDistance,
2543 DS8Buffer3D_SetMinDistance,
2544 DS8Buffer3D_SetMode,
2545 DS8Buffer3D_SetPosition,
2546 DS8Buffer3D_SetVelocity
2549 static inline DS8Buffer *impl_from_IDirectSoundNotify(IDirectSoundNotify *iface)
2551 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSoundNotify_iface);
2554 static HRESULT WINAPI DS8BufferNot_QueryInterface(IDirectSoundNotify *iface, REFIID riid, void **ppv)
2556 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2557 return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2560 static ULONG WINAPI DS8BufferNot_AddRef(IDirectSoundNotify *iface)
2562 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2563 LONG ret;
2565 InterlockedIncrement(&This->all_ref);
2566 ret = InterlockedIncrement(&This->not_ref);
2567 TRACE("new refcount %d\n", ret);
2569 return ret;
2572 static ULONG WINAPI DS8BufferNot_Release(IDirectSoundNotify *iface)
2574 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2575 LONG ret;
2577 ret = InterlockedDecrement(&This->not_ref);
2578 TRACE("new refcount %d\n", ret);
2579 if(InterlockedDecrement(&This->all_ref) == 0)
2580 DS8Buffer_Destroy(This);
2582 return ret;
2585 static HRESULT WINAPI DS8BufferNot_SetNotificationPositions(IDirectSoundNotify *iface, DWORD count, const DSBPOSITIONNOTIFY *notifications)
2587 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2588 DSBPOSITIONNOTIFY *nots;
2589 DWORD state;
2590 HRESULT hr;
2592 EnterCriticalSection(This->crst);
2593 hr = DSERR_INVALIDPARAM;
2594 if(count && !notifications)
2595 goto out;
2597 hr = IDirectSoundBuffer8_GetStatus(&This->IDirectSoundBuffer8_iface, &state);
2598 if(FAILED(hr))
2599 goto out;
2601 hr = DSERR_INVALIDCALL;
2602 if((state&DSBSTATUS_PLAYING))
2603 goto out;
2605 if(!count)
2607 HeapFree(GetProcessHeap(), 0, This->notify);
2608 This->notify = 0;
2609 This->nnotify = 0;
2610 hr = S_OK;
2612 else
2614 DWORD i;
2616 hr = DSERR_INVALIDPARAM;
2617 for(i = 0;i < count;++i)
2619 if(notifications[i].dwOffset >= This->buffer->buf_size &&
2620 notifications[i].dwOffset != (DWORD)DSBPN_OFFSETSTOP)
2621 goto out;
2624 hr = E_OUTOFMEMORY;
2625 nots = HeapAlloc(GetProcessHeap(), 0, count*sizeof(*nots));
2626 if(!nots)
2627 goto out;
2628 memcpy(nots, notifications, count*sizeof(*nots));
2630 HeapFree(GetProcessHeap(), 0, This->notify);
2631 This->notify = nots;
2632 This->nnotify = count;
2634 hr = S_OK;
2637 out:
2638 LeaveCriticalSection(This->crst);
2639 return hr;
2642 static const IDirectSoundNotifyVtbl DS8BufferNot_Vtbl =
2644 DS8BufferNot_QueryInterface,
2645 DS8BufferNot_AddRef,
2646 DS8BufferNot_Release,
2647 DS8BufferNot_SetNotificationPositions
2650 /* NOTE: Due to some apparent quirks in DSound, the listener properties are
2651 handled through secondary buffers. */
2652 static inline DS8Buffer *impl_from_IKsPropertySet(IKsPropertySet *iface)
2654 return CONTAINING_RECORD(iface, DS8Buffer, IKsPropertySet_iface);
2657 static HRESULT WINAPI DS8BufferProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
2659 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2660 return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2663 static ULONG WINAPI DS8BufferProp_AddRef(IKsPropertySet *iface)
2665 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2666 LONG ret;
2668 InterlockedIncrement(&This->all_ref);
2669 ret = InterlockedIncrement(&This->prop_ref);
2670 TRACE("new refcount %d\n", ret);
2672 return ret;
2675 static ULONG WINAPI DS8BufferProp_Release(IKsPropertySet *iface)
2677 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2678 LONG ret;
2680 ret = InterlockedDecrement(&This->prop_ref);
2681 TRACE("new refcount %d\n", ret);
2682 if(InterlockedDecrement(&This->all_ref) == 0)
2683 DS8Buffer_Destroy(This);
2685 return ret;
2688 static HRESULT WINAPI DS8BufferProp_Get(IKsPropertySet *iface,
2689 REFGUID guidPropSet, ULONG dwPropID,
2690 LPVOID pInstanceData, ULONG cbInstanceData,
2691 LPVOID pPropData, ULONG cbPropData,
2692 PULONG pcbReturned)
2694 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2695 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2697 TRACE("(%p)->(%s, %u, %p, %u, %p, %u, %p)\n", iface, debugstr_guid(guidPropSet),
2698 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData, pcbReturned);
2700 if(!pcbReturned)
2701 return E_POINTER;
2702 *pcbReturned = 0;
2704 #if 0
2705 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2708 else
2709 #endif
2711 /* Not a known buffer/source property. Pass it to the listener */
2712 hr = IKsPropertySet_Get(&This->primary->IKsPropertySet_iface, guidPropSet,
2713 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData,
2714 pcbReturned);
2717 return hr;
2720 static HRESULT WINAPI DS8BufferProp_Set(IKsPropertySet *iface,
2721 REFGUID guidPropSet, ULONG dwPropID,
2722 LPVOID pInstanceData, ULONG cbInstanceData,
2723 LPVOID pPropData, ULONG cbPropData)
2725 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2726 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2728 TRACE("(%p)->(%s, %u, %p, %u, %p, %u)\n", iface, debugstr_guid(guidPropSet),
2729 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData);
2731 #if 0
2732 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2735 else
2736 #endif
2738 /* Not a known buffer/source property. Pass it to the listener */
2739 hr = IKsPropertySet_Set(&This->primary->IKsPropertySet_iface, guidPropSet,
2740 dwPropID, pInstanceData, cbInstanceData, pPropData,
2741 cbPropData);
2744 return hr;
2747 static HRESULT WINAPI DS8BufferProp_QuerySupport(IKsPropertySet *iface,
2748 REFGUID guidPropSet, ULONG dwPropID,
2749 PULONG pTypeSupport)
2751 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2752 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2754 TRACE("(%p)->(%s, %u, %p)\n", iface, debugstr_guid(guidPropSet), dwPropID, pTypeSupport);
2756 if(!pTypeSupport)
2757 return E_POINTER;
2758 *pTypeSupport = 0;
2760 #if 0
2761 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2764 else
2765 #endif
2767 /* Not a known buffer/source property. Pass it to the listener */
2768 hr = IKsPropertySet_QuerySupport(&This->primary->IKsPropertySet_iface,
2769 guidPropSet, dwPropID, pTypeSupport);
2772 return hr;
2775 static const IKsPropertySetVtbl DS8BufferProp_Vtbl =
2777 DS8BufferProp_QueryInterface,
2778 DS8BufferProp_AddRef,
2779 DS8BufferProp_Release,
2780 DS8BufferProp_Get,
2781 DS8BufferProp_Set,
2782 DS8BufferProp_QuerySupport