Add a .gitignore to ignore the build directory
[dsound-openal.git] / buffer.c
blob270a7f649c2a19e4dc510c9a67ce545dfb2af852
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 0x6100
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;
145 EnterCriticalSection(&prim->crst);
146 setALContext(prim->ctx);
148 /* OpenAL doesn't support our lovely buffer extensions
149 * so just make sure enough buffers are queued
151 if(!prim->ExtAL.BufferSamplesSOFT && !prim->ExtAL.BufferSubData &&
152 !prim->ExtAL.BufferDataStatic)
154 /* FIXME: Should probably use this logic to also
155 * call trigger_notifies
157 for (i = 0; i < prim->nbuffers; ++i)
159 DS8Buffer *buf = prim->buffers[i];
160 ALint done = 0, queued = QBUFFERS, state = AL_PLAYING;
161 ALuint which, ofs;
163 if (buf->buffer->numsegs == 1 || !buf->isplaying)
164 continue;
166 alGetSourcei(buf->source, AL_SOURCE_STATE, &state);
167 alGetSourcei(buf->source, AL_BUFFERS_QUEUED, &queued);
168 alGetSourcei(buf->source, AL_BUFFERS_PROCESSED, &done);
170 queued -= done;
171 while (done--)
172 alSourceUnqueueBuffers(buf->source, 1, &which);
173 while (queued < QBUFFERS)
175 which = buf->buffer->buffers[buf->curidx];
176 ofs = buf->curidx*buf->buffer->segsize;
177 if(buf->curidx < buf->buffer->numsegs-1)
178 alBufferData(which, buf->buffer->buf_format,
179 buf->buffer->data + ofs, buf->buffer->segsize,
180 buf->buffer->format.Format.nSamplesPerSec);
181 else
182 alBufferData(which, buf->buffer->buf_format,
183 buf->buffer->data + ofs, buf->buffer->lastsegsize,
184 buf->buffer->format.Format.nSamplesPerSec);
186 alSourceQueueBuffers(buf->source, 1, &which);
187 buf->curidx = (buf->curidx+1)%buf->buffer->numsegs;
188 queued++;
190 if (!buf->curidx && !buf->islooping)
192 buf->isplaying = FALSE;
193 break;
196 if (state != AL_PLAYING)
198 if (!queued)
200 IDirectSoundBuffer8_Stop(&buf->IDirectSoundBuffer8_iface);
201 continue;
203 alSourcePlay(buf->source);
205 getALError();
209 for (i = 0; i < prim->nnotifies ; )
211 DS8Buffer *buf = prim->notifies[i];
212 IDirectSoundBuffer8 *dsb = &buf->IDirectSoundBuffer8_iface;
213 DWORD status, curpos;
214 HRESULT hr;
216 hr = IDirectSoundBuffer8_GetStatus(dsb, &status);
217 if (SUCCEEDED(hr))
219 if (!(status & DSBSTATUS_PLAYING))
221 /* Stop will remove this buffer from list,
222 * and put another at the current position
223 * don't increment i
225 IDirectSoundBuffer8_Stop(dsb);
226 continue;
228 hr = IDirectSoundBuffer8_GetCurrentPosition(dsb, &curpos, NULL);
229 if (SUCCEEDED(hr))
231 trigger_notifies(buf, buf->lastpos, curpos, FALSE);
232 buf->lastpos = curpos;
235 i++;
237 popALContext();
238 LeaveCriticalSection(&prim->crst);
241 static void DS8Buffer_starttimer(DS8Primary *prim)
243 TIMECAPS time;
244 ALint refresh = FAKE_REFRESH_COUNT;
245 DWORD triggertime, res = DS_TIME_RES;
247 if(prim->timer_id)
248 return;
250 timeGetDevCaps(&time, sizeof(TIMECAPS));
252 alcGetIntegerv(prim->parent->device, ALC_REFRESH, 1, &refresh);
253 getALCError(prim->parent->device);
255 triggertime = 1000 / refresh;
256 if(triggertime < time.wPeriodMin)
257 triggertime = time.wPeriodMin;
258 TRACE("Calling timer every %u ms for %i refreshes per second\n", triggertime, refresh);
260 if (res < time.wPeriodMin)
261 res = time.wPeriodMin;
262 if (timeBeginPeriod(res) == TIMERR_NOCANDO)
263 WARN("Could not set minimum resolution, don't expect sound\n");
265 prim->timer_res = res;
266 prim->timer_id = timeSetEvent(triggertime, res, DS8Buffer_timer, (DWORD_PTR)prim, TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
269 /* Should be called with critsect held and context set.. */
270 static void DS8Buffer_addnotify(DS8Buffer *buf)
272 DS8Buffer **list;
273 DWORD i;
275 list = buf->primary->notifies;
276 for(i = 0; i < buf->primary->nnotifies; ++i)
278 if(buf == list[i])
280 ERR("Buffer %p already in notification list\n", buf);
281 return;
284 if(buf->primary->nnotifies == buf->primary->sizenotifies)
286 list = HeapReAlloc(GetProcessHeap(), 0, list, (buf->primary->nnotifies + 1) * sizeof(*list));
287 if(!list)
288 return;
289 buf->primary->sizenotifies++;
291 list[buf->primary->nnotifies++] = buf;
292 buf->primary->notifies = list;
295 static void DS8Buffer_removenotify(DS8Buffer *buf)
297 DWORD i;
298 for(i = 0; i < buf->primary->nnotifies; ++i)
300 if(buf == buf->primary->notifies[i])
302 buf->primary->notifies[i] =
303 buf->primary->notifies[--buf->primary->nnotifies];
304 return;
309 static const char *get_fmtstr_PCM(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out, ALenum *in_chans, ALenum *in_type)
311 out->Format = *format;
312 out->Format.cbSize = 0;
314 if(format->wBitsPerSample == 8)
316 *in_type = AL_UNSIGNED_BYTE;
317 switch(format->nChannels)
319 case 1: *in_chans = AL_MONO;
320 return "AL_FORMAT_MONO8";
321 case 2: *in_chans = AL_STEREO;
322 return "AL_FORMAT_STEREO8";
323 case 4: *in_chans = AL_QUAD;
324 return "AL_FORMAT_QUAD8";
325 case 6: *in_chans = AL_5POINT1;
326 return "AL_FORMAT_51CHN8";
327 case 7: *in_chans = AL_6POINT1;
328 return "AL_FORMAT_61CHN8";
329 case 8: *in_chans = AL_7POINT1;
330 return "AL_FORMAT_71CHN8";
331 default: break;
334 else if(format->wBitsPerSample == 16)
336 *in_type = AL_SHORT;
337 switch(format->nChannels)
339 case 1: *in_chans = AL_MONO;
340 return "AL_FORMAT_MONO16";
341 case 2: *in_chans = AL_STEREO;
342 return "AL_FORMAT_STEREO16";
343 case 4: *in_chans = AL_QUAD;
344 return "AL_FORMAT_QUAD16";
345 case 6: *in_chans = AL_5POINT1;
346 return "AL_FORMAT_51CHN16";
347 case 7: *in_chans = AL_6POINT1;
348 return "AL_FORMAT_61CHN16";
349 case 8: *in_chans = AL_7POINT1;
350 return "AL_FORMAT_71CHN16";
351 default: break;
354 #if 0 /* Will cause incorrect byte offsets */
355 else if(format->wBitsPerSample == 24 && prim->SupportedExt[SOFT_BUFFER_SAMPLES])
357 *in_type = AL_BYTE3;
358 switch(format->nChannels)
360 case 1: *in_chans = AL_MONO;
361 return "AL_MONO32F";
362 case 2: *in_chans = AL_STEREO;
363 return "AL_STEREO32F";
364 case 4: *in_chans = AL_QUAD;
365 return "AL_QUAD32F";
366 case 6: *in_chans = AL_5POINT1;
367 return "AL_5POINT1_32F";
368 case 7: *in_chans = AL_6POINT1;
369 return "AL_6POINT1_32F";
370 case 8: *in_chans = AL_7POINT1;
371 return "AL_7POINT1_32F";
372 default: break;
375 #endif
376 else if(format->wBitsPerSample == 32 && prim->SupportedExt[SOFT_BUFFER_SAMPLES])
378 *in_type = AL_INT;
379 switch(format->nChannels)
381 case 1: *in_chans = AL_MONO;
382 return "AL_MONO32F";
383 case 2: *in_chans = AL_STEREO;
384 return "AL_STEREO32F";
385 case 4: *in_chans = AL_QUAD;
386 return "AL_QUAD32F";
387 case 6: *in_chans = AL_5POINT1;
388 return "AL_5POINT1_32F";
389 case 7: *in_chans = AL_6POINT1;
390 return "AL_6POINT1_32F";
391 case 8: *in_chans = AL_7POINT1;
392 return "AL_7POINT1_32F";
393 default: break;
397 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
398 format->wBitsPerSample, format->nChannels);
399 return NULL;
402 static const char *get_fmtstr_FLOAT(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out, ALenum *in_chans, ALenum *in_type)
404 out->Format = *format;
405 out->Format.cbSize = 0;
407 if(format->wBitsPerSample == 32 &&
408 (prim->SupportedExt[EXT_FLOAT32] || prim->SupportedExt[SOFT_BUFFER_SAMPLES]))
410 *in_type = AL_FLOAT;
411 switch(format->nChannels)
413 case 1: *in_chans = AL_MONO;
414 return "AL_FORMAT_MONO_FLOAT32";
415 case 2: *in_chans = AL_STEREO;
416 return "AL_FORMAT_STEREO_FLOAT32";
417 case 4: *in_chans = AL_QUAD;
418 return "AL_FORMAT_QUAD32";
419 case 6: *in_chans = AL_5POINT1;
420 return "AL_FORMAT_51CHN32";
421 case 7: *in_chans = AL_6POINT1;
422 return "AL_FORMAT_61CHN32";
423 case 8: *in_chans = AL_7POINT1;
424 return "AL_FORMAT_71CHN32";
425 default: break;
428 #if 0 /* Will cause incorrect byte offsets */
429 else if(format->wBitsPerSample == 64 && prim->SupportedExt[SOFT_BUFFER_SAMPLES])
431 *in_type = AL_DOUBLE;
432 switch(format->nChannels)
434 case 1: *in_chans = AL_MONO;
435 return "AL_MONO32F";
436 case 2: *in_chans = AL_STEREO;
437 return "AL_STEREO32F";
438 case 4: *in_chans = AL_QUAD;
439 return "AL_QUAD32F";
440 case 6: *in_chans = AL_5POINT1;
441 return "AL_5POINT1_32F";
442 case 7: *in_chans = AL_6POINT1;
443 return "AL_6POINT1_32F";
444 case 8: *in_chans = AL_7POINT1;
445 return "AL_7POINT1_32F";
446 default: break;
449 #endif
451 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
452 format->wBitsPerSample, format->nChannels);
453 return NULL;
456 /* Speaker configs */
457 #define MONO SPEAKER_FRONT_CENTER
458 #define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)
459 #define REAR (SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
460 #define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
461 #define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
462 #define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
463 #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)
465 static const char *get_fmtstr_EXT(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out, ALenum *in_chans, ALenum *in_type)
467 *out = *(const WAVEFORMATEXTENSIBLE*)format;
468 out->Format.cbSize = sizeof(*out) - sizeof(out->Format);
470 if(!out->Samples.wValidBitsPerSample)
471 out->Samples.wValidBitsPerSample = out->Format.wBitsPerSample;
472 else if(out->Samples.wValidBitsPerSample != out->Format.wBitsPerSample)
474 FIXME("Padded samples not supported (%u of %u)\n", out->Samples.wValidBitsPerSample, out->Format.wBitsPerSample);
475 return NULL;
478 if(out->dwChannelMask != MONO && out->dwChannelMask != STEREO &&
479 !prim->SupportedExt[EXT_MCFORMATS] && !prim->SupportedExt[SOFT_BUFFER_SAMPLES])
481 WARN("Multi-channel not available\n");
482 return NULL;
485 if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
487 if(out->Samples.wValidBitsPerSample == 8)
489 *in_type = AL_UNSIGNED_BYTE;
490 switch(out->dwChannelMask)
492 case MONO: *in_chans = AL_MONO;
493 return "AL_FORMAT_MONO8";
494 case STEREO: *in_chans = AL_STEREO;
495 return "AL_FORMAT_STEREO8";
496 case REAR: *in_chans = AL_REAR;
497 return "AL_FORMAT_REAR8";
498 case QUAD: *in_chans = AL_QUAD;
499 return "AL_FORMAT_QUAD8";
500 case X5DOT1: *in_chans = AL_5POINT1;
501 return "AL_FORMAT_51CHN8";
502 case X6DOT1: *in_chans = AL_6POINT1;
503 return "AL_FORMAT_61CHN8";
504 case X7DOT1: *in_chans = AL_7POINT1;
505 return "AL_FORMAT_71CHN8";
506 default: break;
509 else if(out->Samples.wValidBitsPerSample == 16)
511 *in_type = AL_SHORT;
512 switch(out->dwChannelMask)
514 case MONO: *in_chans = AL_MONO;
515 return "AL_FORMAT_MONO16";
516 case STEREO: *in_chans = AL_STEREO;
517 return "AL_FORMAT_STEREO16";
518 case REAR: *in_chans = AL_REAR;
519 return "AL_FORMAT_REAR16";
520 case QUAD: *in_chans = AL_QUAD;
521 return "AL_FORMAT_QUAD16";
522 case X5DOT1: *in_chans = AL_5POINT1;
523 return "AL_FORMAT_51CHN16";
524 case X6DOT1: *in_chans = AL_6POINT1;
525 return "AL_FORMAT_61CHN16";
526 case X7DOT1: *in_chans = AL_7POINT1;
527 return "AL_FORMAT_71CHN16";
528 default: break;
531 #if 0
532 else if(out->Samples.wValidBitsPerSample == 24 &&
533 prim->SupportedExt[SOFT_BUFFER_SAMPLES])
535 *in_type = AL_BYTE3;
536 switch(out->dwChannelMask)
538 case MONO: *in_chans = AL_MONO;
539 return "AL_MONO32F";
540 case STEREO: *in_chans = AL_STEREO;
541 return "AL_STEREO32F";
542 case REAR: *in_chans = AL_REAR;
543 return "AL_REAR32F";
544 case QUAD: *in_chans = AL_QUAD;
545 return "AL_QUAD32F";
546 case X5DOT1: *in_chans = AL_5POINT1;
547 return "AL_5POINT1_32F";
548 case X6DOT1: *in_chans = AL_6POINT1;
549 return "AL_6POINT1_32F";
550 case X7DOT1: *in_chans = AL_7POINT1;
551 return "AL_7POINT1_32F";
552 default: break;
555 #endif
556 else if(out->Samples.wValidBitsPerSample == 32 &&
557 prim->SupportedExt[SOFT_BUFFER_SAMPLES])
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";
576 default: break;
580 FIXME("Could not get OpenAL PCM format (%d-bit, channelmask %#x)\n",
581 out->Samples.wValidBitsPerSample, out->dwChannelMask);
582 return NULL;
584 else if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) &&
585 (prim->SupportedExt[EXT_FLOAT32] || prim->SupportedExt[SOFT_BUFFER_SAMPLES]))
587 if(out->Samples.wValidBitsPerSample == 32)
589 *in_type = AL_FLOAT;
590 switch(out->dwChannelMask)
592 case MONO: *in_chans = AL_MONO;
593 return "AL_FORMAT_MONO_FLOAT32";
594 case STEREO: *in_chans = AL_STEREO;
595 return "AL_FORMAT_STEREO_FLOAT32";
596 case REAR: *in_chans = AL_REAR;
597 return "AL_FORMAT_REAR32";
598 case QUAD: *in_chans = AL_QUAD;
599 return "AL_FORMAT_QUAD32";
600 case X5DOT1: *in_chans = AL_5POINT1;
601 return "AL_FORMAT_51CHN32";
602 case X6DOT1: *in_chans = AL_6POINT1;
603 return "AL_FORMAT_61CHN32";
604 case X7DOT1: *in_chans = AL_7POINT1;
605 return "AL_FORMAT_71CHN32";
606 default: break;
609 #if 0
610 else if(out->Samples.wValidBitsPerSample == 64 &&
611 prim->SupportedExt[SOFT_BUFFER_SAMPLES])
613 *in_type = AL_DOUBLE;
614 switch(out->dwChannelMask)
616 case MONO: *in_chans = AL_MONO;
617 return "AL_MONO32F";
618 case STEREO: *in_chans = AL_STEREO;
619 return "AL_STEREO32F";
620 case REAR: *in_chans = AL_REAR;
621 return "AL_REAR32F";
622 case QUAD: *in_chans = AL_QUAD;
623 return "AL_QUAD32F";
624 case X5DOT1: *in_chans = AL_5POINT1;
625 return "AL_5POINT1_32F";
626 case X6DOT1: *in_chans = AL_6POINT1;
627 return "AL_6POINT1_32F";
628 case X7DOT1: *in_chans = AL_7POINT1;
629 return "AL_7POINT1_32F";
630 default: break;
633 #endif
634 else
636 WARN("Invalid float bits: %u\n", out->Samples.wValidBitsPerSample);
637 return NULL;
640 FIXME("Could not get OpenAL float format (%d-bit, channelmask %#x)\n",
641 out->Samples.wValidBitsPerSample, out->dwChannelMask);
642 return NULL;
644 else if(!IsEqualGUID(&out->SubFormat, &GUID_NULL))
645 ERR("Unhandled extensible format: %s\n", debugstr_guid(&out->SubFormat));
646 return NULL;
649 static void DS8Data_Release(DS8Data *This);
650 static HRESULT DS8Data_Create(DS8Data **ppv, const DSBUFFERDESC *desc, DS8Primary *prim)
652 HRESULT hr = DSERR_INVALIDPARAM;
653 const WAVEFORMATEX *format;
654 const char *fmt_str = NULL;
655 DS8Data *pBuffer;
657 format = desc->lpwfxFormat;
658 TRACE("Requested buffer format:\n"
659 " FormatTag = 0x%04x\n"
660 " Channels = %d\n"
661 " SamplesPerSec = %u\n"
662 " AvgBytesPerSec = %u\n"
663 " BlockAlign = %d\n"
664 " BitsPerSample = %d\n",
665 format->wFormatTag, format->nChannels,
666 format->nSamplesPerSec, format->nAvgBytesPerSec,
667 format->nBlockAlign, format->wBitsPerSample);
669 if(format->nBlockAlign == 0)
671 WARN("Invalid BlockAlign specified\n");
672 return DSERR_INVALIDPARAM;
675 /* Generate a new buffer. Supporting the DSBCAPS_LOC* flags properly
676 * will need the EAX-RAM extension. Currently, we just tell the app it
677 * gets what it wanted. */
678 pBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pBuffer));
679 if(!pBuffer)
680 return E_OUTOFMEMORY;
681 pBuffer->ref = 1;
683 pBuffer->dsbflags = desc->dwFlags;
684 if((pBuffer->dsbflags&(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE)) == (DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE))
686 WARN("Hardware and software location requested\n");
687 goto fail;
689 if(!(pBuffer->dsbflags&(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE|DSBCAPS_LOCDEFER)))
690 pBuffer->dsbflags |= DSBCAPS_LOCHARDWARE;
692 pBuffer->buf_size = desc->dwBufferBytes + format->nBlockAlign - 1;
693 pBuffer->buf_size -= pBuffer->buf_size%format->nBlockAlign;
695 hr = DSERR_BUFFERTOOSMALL;
696 if(pBuffer->buf_size < DSBSIZE_MIN)
697 goto fail;
699 hr = DSERR_INVALIDPARAM;
700 if(pBuffer->buf_size > DSBSIZE_MAX)
701 goto fail;
703 pBuffer->numsegs = 1;
704 pBuffer->segsize = pBuffer->buf_size;
705 pBuffer->lastsegsize = pBuffer->buf_size;
707 if(!(pBuffer->dsbflags&DSBCAPS_STATIC) && !prim->ExtAL.BufferSubData &&
708 !prim->ExtAL.BufferSamplesSOFT && !prim->ExtAL.BufferDataStatic)
710 ALCint refresh = FAKE_REFRESH_COUNT;
711 ALuint newSize;
713 alcGetIntegerv(prim->parent->device, ALC_REFRESH, 1, &refresh);
714 getALCError(prim->parent->device);
716 newSize = format->nAvgBytesPerSec/refresh + format->nBlockAlign - 1;
717 newSize -= newSize%format->nBlockAlign;
719 /* Make sure enough buffers are available */
720 if(newSize > pBuffer->buf_size/(QBUFFERS+2))
721 ERR("Buffer segments too large to stream (%u for %u)!\n",
722 newSize, pBuffer->buf_size);
723 else
725 pBuffer->numsegs = pBuffer->buf_size/newSize;
726 pBuffer->segsize = newSize;
727 pBuffer->lastsegsize = pBuffer->buf_size - (newSize*(pBuffer->numsegs-1));
728 TRACE("New streaming buffer (%u chunks, %u : %u sizes)\n",
729 pBuffer->numsegs, pBuffer->segsize, pBuffer->lastsegsize);
733 if(format->wFormatTag == WAVE_FORMAT_PCM)
734 fmt_str = get_fmtstr_PCM(prim, format, &pBuffer->format, &pBuffer->in_chans, &pBuffer->in_type);
735 else if(format->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
736 fmt_str = get_fmtstr_FLOAT(prim, format, &pBuffer->format, &pBuffer->in_chans, &pBuffer->in_type);
737 else if(format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
739 const WAVEFORMATEXTENSIBLE *wfe;
741 hr = DSERR_CONTROLUNAVAIL;
742 if(format->cbSize != sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) &&
743 format->cbSize != sizeof(WAVEFORMATEXTENSIBLE))
744 goto fail;
746 wfe = (const WAVEFORMATEXTENSIBLE*)format;
747 TRACE("Extensible values:\n"
748 " Samples = %d\n"
749 " ChannelMask = %#x\n"
750 " SubFormat = %s\n",
751 wfe->Samples.wReserved, wfe->dwChannelMask,
752 debugstr_guid(&wfe->SubFormat));
754 hr = DSERR_INVALIDCALL;
755 fmt_str = get_fmtstr_EXT(prim, format, &pBuffer->format, &pBuffer->in_chans, &pBuffer->in_type);
757 else
758 ERR("Unhandled formattag 0x%04x\n", format->wFormatTag);
760 if(!fmt_str)
761 goto fail;
763 pBuffer->buf_format = alGetEnumValue(fmt_str);
764 if(alGetError() != AL_NO_ERROR || pBuffer->buf_format == 0 ||
765 pBuffer->buf_format == -1)
767 WARN("Could not get OpenAL format from %s\n", fmt_str);
768 goto fail;
771 hr = E_OUTOFMEMORY;
772 pBuffer->buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pBuffer->buffers)*pBuffer->numsegs);
773 pBuffer->data = HeapAlloc(GetProcessHeap(), 0, pBuffer->buf_size);
774 if(!pBuffer->buffers || !pBuffer->data)
775 goto fail;
777 alGenBuffers(pBuffer->numsegs, pBuffer->buffers);
778 getALError();
780 *ppv = pBuffer;
781 return S_OK;
783 fail:
784 DS8Data_Release(pBuffer);
785 return hr;
788 static void DS8Data_AddRef(DS8Data *data)
790 InterlockedIncrement(&data->ref);
793 /* This function is always called with the device lock held */
794 static void DS8Data_Release(DS8Data *This)
796 if(InterlockedDecrement(&This->ref)) return;
798 TRACE("Deleting %p\n", This);
799 if (This->buffers && This->buffers[0])
801 alDeleteBuffers(This->numsegs, This->buffers);
802 getALError();
804 HeapFree(GetProcessHeap(), 0, This->buffers);
805 HeapFree(GetProcessHeap(), 0, This->data);
806 HeapFree(GetProcessHeap(), 0, This);
809 HRESULT DS8Buffer_Create(DS8Buffer **ppv, DS8Primary *parent, DS8Buffer *orig)
811 HRESULT hr = DSERR_OUTOFMEMORY;
812 DS8Buffer *This;
813 DS8Buffer **bufs;
815 *ppv = NULL;
816 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
817 if(!This) return hr;
819 This->primary = parent;
820 This->IDirectSoundBuffer8_iface.lpVtbl = &DS8Buffer_Vtbl;
821 This->IDirectSound3DBuffer_iface.lpVtbl = &DS8Buffer3d_Vtbl;
822 This->IDirectSoundNotify_iface.lpVtbl = &DS8BufferNot_Vtbl;
823 This->IKsPropertySet_iface.lpVtbl = &DS8BufferProp_Vtbl;
824 This->ctx = parent->ctx;
825 This->ExtAL = &parent->ExtAL;
826 This->crst = &parent->crst;
827 This->ref = This->all_ref = 1;
829 if(orig)
831 This->buffer = orig->buffer;
832 DS8Data_AddRef(This->buffer);
835 /* Append to buffer list */
836 bufs = parent->buffers;
837 if(parent->nbuffers == parent->sizebuffers)
839 bufs = HeapReAlloc(GetProcessHeap(), 0, bufs, sizeof(*bufs)*(1+parent->nbuffers));
840 if(!bufs) goto fail;
841 parent->sizebuffers++;
843 parent->buffers = bufs;
844 bufs[parent->nbuffers++] = This;
846 /* Disable until initialized.. */
847 This->ds3dmode = DS3DMODE_DISABLE;
849 *ppv = This;
850 return S_OK;
852 fail:
853 DS8Buffer_Destroy(This);
854 return hr;
857 void DS8Buffer_Destroy(DS8Buffer *This)
859 DWORD idx;
860 TRACE("Destroying %p\n", This);
862 DS8Buffer_removenotify(This);
864 /* Remove from list, if in list */
865 for(idx = 0;idx < This->primary->nbuffers;++idx)
867 if(This->primary->buffers[idx] == This)
869 This->primary->buffers[idx] = This->primary->buffers[This->primary->nbuffers-1];
870 This->primary->nbuffers--;
871 break;
874 setALContext(This->ctx);
875 if(This->source)
877 ALuint *sources;
879 alSourceStop(This->source);
880 alSourcei(This->source, AL_BUFFER, 0);
881 getALError();
883 sources = This->primary->sources;
884 if(This->primary->nsources == This->primary->sizesources)
886 sources = HeapReAlloc(GetProcessHeap(), 0, sources, sizeof(*sources)*(1+This->primary->nsources));
887 if(!sources)
888 alDeleteSources(1, &This->source);
889 else
890 This->primary->sizesources++;
892 if(sources)
894 sources[This->primary->nsources++] = This->source;
895 This->primary->sources = sources;
898 HeapFree(GetProcessHeap(), 0, This->notify);
899 This->source = 0;
900 if(This->buffer)
901 DS8Data_Release(This->buffer);
902 popALContext();
903 HeapFree(GetProcessHeap(), 0, This);
906 static inline DS8Buffer *impl_from_IDirectSoundBuffer8(IDirectSoundBuffer8 *iface)
908 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSoundBuffer8_iface);
911 static HRESULT WINAPI DS8Buffer_QueryInterface(IDirectSoundBuffer8 *iface, REFIID riid, void **ppv)
913 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
915 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
917 *ppv = NULL;
918 if(IsEqualIID(riid, &IID_IUnknown) ||
919 IsEqualIID(riid, &IID_IDirectSoundBuffer))
920 *ppv = &This->IDirectSoundBuffer8_iface;
921 else if(IsEqualIID(riid, &IID_IDirectSoundBuffer8))
923 if(This->primary->parent->is_8)
924 *ppv = &This->IDirectSoundBuffer8_iface;
926 else if(IsEqualIID(riid, &IID_IDirectSound3DBuffer))
928 if((This->buffer->dsbflags&DSBCAPS_CTRL3D))
929 *ppv = &This->IDirectSound3DBuffer_iface;
931 else if(IsEqualIID(riid, &IID_IDirectSoundNotify))
933 if((This->buffer->dsbflags&DSBCAPS_CTRLPOSITIONNOTIFY))
934 *ppv = &This->IDirectSoundNotify_iface;
936 else if(IsEqualIID(riid, &IID_IKsPropertySet))
937 *ppv = &This->IKsPropertySet_iface;
938 else
939 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
941 if(*ppv)
943 IUnknown_AddRef((IUnknown*)*ppv);
944 return S_OK;
947 return E_NOINTERFACE;
950 static ULONG WINAPI DS8Buffer_AddRef(IDirectSoundBuffer8 *iface)
952 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
953 LONG ret;
955 InterlockedIncrement(&This->all_ref);
956 ret = InterlockedIncrement(&This->ref);
957 TRACE("new refcount %d\n", ret);
959 return ret;
962 static ULONG WINAPI DS8Buffer_Release(IDirectSoundBuffer8 *iface)
964 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
965 LONG ret;
967 ret = InterlockedDecrement(&This->ref);
968 TRACE("new refcount %d\n", ret);
969 if(InterlockedDecrement(&This->all_ref) == 0)
970 DS8Buffer_Destroy(This);
972 return ret;
975 static HRESULT WINAPI DS8Buffer_GetCaps(IDirectSoundBuffer8 *iface, DSBCAPS *caps)
977 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
979 TRACE("(%p)->(%p)\n", iface, caps);
981 if(!caps || caps->dwSize < sizeof(*caps))
983 WARN("Invalid DSBCAPS (%p, %u)\n", caps, (caps ? caps->dwSize : 0));
984 return DSERR_INVALIDPARAM;
987 caps->dwFlags = This->buffer->dsbflags;
988 caps->dwBufferBytes = This->buffer->buf_size;
989 caps->dwUnlockTransferRate = 4096;
990 caps->dwPlayCpuOverhead = 0;
991 return S_OK;
994 static HRESULT WINAPI DS8Buffer_GetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD *playpos, DWORD *curpos)
996 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
997 WAVEFORMATEX *format = &This->buffer->format.Format;
998 UINT writecursor, pos;
1000 TRACE("(%p)->(%p, %p)\n", iface, playpos, curpos);
1002 EnterCriticalSection(This->crst);
1003 setALContext(This->ctx);
1005 if(This->buffer->numsegs > 1)
1007 ALint queued = QBUFFERS;
1008 alGetSourcei(This->source, AL_BUFFERS_QUEUED, &queued);
1009 getALError();
1011 pos = (This->curidx+This->buffer->numsegs-queued)%This->buffer->numsegs;
1012 pos *= This->buffer->segsize;
1013 writecursor = This->curidx * This->buffer->segsize;
1015 else if(This->ExtAL->BufferSubData || This->ExtAL->BufferSamplesSOFT)
1017 ALint rwpos[2] = { 0, 0 };
1019 alGetSourceiv(This->source, AL_BYTE_RW_OFFSETS_SOFT, rwpos);
1020 getALError();
1022 pos = rwpos[0];
1023 writecursor = rwpos[1];
1025 else
1027 ALint status = 0;
1028 ALint ofs = 0;
1030 alGetSourcei(This->source, AL_BYTE_OFFSET, &ofs);
1031 alGetSourcei(This->source, AL_SOURCE_STATE, &status);
1032 getALError();
1034 pos = ofs;
1035 if(status == AL_PLAYING)
1037 writecursor = format->nSamplesPerSec / 100;
1038 writecursor *= format->nBlockAlign;
1040 else
1041 writecursor = 0;
1042 writecursor = (writecursor + pos) % This->buffer->buf_size;
1044 TRACE("%p Play pos = %u, write pos = %u\n", This, pos, writecursor);
1045 if(pos >= This->buffer->buf_size)
1047 ERR("playpos >= buf_size\n");
1048 pos %= This->buffer->buf_size;
1050 if(writecursor >= This->buffer->buf_size)
1052 ERR("writepos >= buf_size\n");
1053 writecursor %= This->buffer->buf_size;
1056 if(playpos) *playpos = pos;
1057 if(curpos) *curpos = writecursor;
1059 popALContext();
1060 LeaveCriticalSection(This->crst);
1062 return S_OK;
1065 static HRESULT WINAPI DS8Buffer_GetFormat(IDirectSoundBuffer8 *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
1067 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1068 HRESULT hr = S_OK;
1069 UINT size;
1071 TRACE("(%p)->(%p, %u, %p)\n", iface, wfx, allocated, written);
1073 if(!wfx && !written)
1075 WARN("Cannot report format or format size\n");
1076 return DSERR_INVALIDPARAM;
1079 EnterCriticalSection(This->crst);
1080 size = sizeof(This->buffer->format.Format) + This->buffer->format.Format.cbSize;
1081 if(wfx)
1083 if(allocated < size)
1084 hr = DSERR_INVALIDPARAM;
1085 else
1086 memcpy(wfx, &This->buffer->format.Format, size);
1088 if(written)
1089 *written = size;
1090 LeaveCriticalSection(This->crst);
1092 return hr;
1095 static HRESULT WINAPI DS8Buffer_GetVolume(IDirectSoundBuffer8 *iface, LONG *vol)
1097 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1098 HRESULT hr;
1100 TRACE("(%p)->(%p)\n", iface, vol);
1102 if(!vol)
1104 WARN("Invalid pointer\n");
1105 return DSERR_INVALIDPARAM;
1108 EnterCriticalSection(This->crst);
1110 hr = DSERR_CONTROLUNAVAIL;
1111 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
1112 WARN("Volume control not set\n");
1113 else
1115 ALfloat gain = 1.0f;
1117 setALContext(This->ctx);
1118 alGetSourcef(This->source, AL_GAIN, &gain);
1119 getALError();
1120 popALContext();
1122 *vol = gain_to_mB(gain);
1123 *vol = min(*vol, DSBVOLUME_MAX);
1124 *vol = max(*vol, DSBVOLUME_MIN);
1126 hr = DS_OK;
1129 LeaveCriticalSection(This->crst);
1130 return hr;
1133 static HRESULT WINAPI DS8Buffer_GetPan(IDirectSoundBuffer8 *iface, LONG *pan)
1135 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1136 HRESULT hr;
1138 TRACE("(%p)->(%p)\n", iface, pan);
1140 if(!pan)
1142 WARN("Invalid pointer\n");
1143 return DSERR_INVALIDPARAM;
1146 EnterCriticalSection(This->crst);
1148 hr = DSERR_CONTROLUNAVAIL;
1149 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
1150 WARN("Panning control not set\n");
1151 else
1153 ALfloat pos[3];
1155 setALContext(This->ctx);
1156 alGetSourcefv(This->source, AL_POSITION, pos);
1157 getALError();
1158 popALContext();
1160 *pan = (LONG)((pos[0]+1.0) * (DSBPAN_RIGHT-DSBPAN_LEFT) / 2.0 + 0.5) + DSBPAN_LEFT;
1161 *pan = min(*pan, DSBPAN_RIGHT);
1162 *pan = max(*pan, DSBPAN_LEFT);
1164 hr = DS_OK;
1167 LeaveCriticalSection(This->crst);
1168 return hr;
1171 static HRESULT WINAPI DS8Buffer_GetFrequency(IDirectSoundBuffer8 *iface, DWORD *freq)
1173 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1174 HRESULT hr;
1176 TRACE("(%p)->(%p)\n", iface, freq);
1178 if(!freq)
1180 WARN("Invalid pointer\n");
1181 return DSERR_INVALIDPARAM;
1184 EnterCriticalSection(This->crst);
1186 hr = DSERR_CONTROLUNAVAIL;
1187 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
1188 WARN("Frequency control not set\n");
1189 else
1191 ALfloat pitch = 1.0f;
1193 setALContext(This->ctx);
1194 alGetSourcefv(This->source, AL_PITCH, &pitch);
1195 getALError();
1196 popALContext();
1198 *freq = (DWORD)(This->buffer->format.Format.nSamplesPerSec * pitch);
1200 hr = DS_OK;
1203 LeaveCriticalSection(This->crst);
1204 return hr;
1207 static HRESULT WINAPI DS8Buffer_GetStatus(IDirectSoundBuffer8 *iface, DWORD *status)
1209 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1210 ALint state, looping;
1212 TRACE("(%p)->(%p)\n", iface, status);
1214 if(!status)
1216 WARN("Invalid pointer\n");
1217 return DSERR_INVALIDPARAM;
1220 EnterCriticalSection(This->crst);
1222 setALContext(This->ctx);
1223 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1224 looping = This->islooping;
1225 if(This->buffer->numsegs == 1)
1226 alGetSourcei(This->source, AL_LOOPING, &looping);
1227 else if(state != AL_PLAYING)
1228 state = This->isplaying ? AL_PLAYING : AL_PAUSED;
1229 getALError();
1230 popALContext();
1232 *status = 0;
1233 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1235 if((This->buffer->dsbflags&DSBCAPS_LOCSOFTWARE))
1236 *status |= DSBSTATUS_LOCSOFTWARE;
1237 else if((This->buffer->dsbflags&DSBCAPS_LOCHARDWARE))
1238 *status |= DSBSTATUS_LOCHARDWARE;
1240 if(state == AL_PLAYING)
1241 *status |= DSBSTATUS_PLAYING | (looping ? DSBSTATUS_LOOPING : 0);
1243 LeaveCriticalSection(This->crst);
1245 return S_OK;
1248 static HRESULT WINAPI DS8Buffer_Initialize(IDirectSoundBuffer8 *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
1250 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1251 DS3DBUFFER *ds3dbuffer;
1252 HRESULT hr;
1254 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
1256 EnterCriticalSection(This->crst);
1257 setALContext(This->ctx);
1259 hr = DSERR_ALREADYINITIALIZED;
1260 if(This->source)
1261 goto out;
1263 if(!This->buffer)
1265 hr = DSERR_INVALIDPARAM;
1266 if(!desc)
1268 WARN("Missing DSound buffer description\n");
1269 goto out;
1271 if(!desc->lpwfxFormat)
1273 WARN("Missing buffer format (%p)\n", This);
1274 goto out;
1276 if((desc->dwFlags&DSBCAPS_CTRL3D) && desc->lpwfxFormat->nChannels != 1)
1278 if(This->primary->parent->is_8)
1280 /* DirectSoundBuffer8 objects aren't allowed non-mono 3D
1281 * buffers */
1282 WARN("Can't create multi-channel 3D buffers\n");
1283 goto out;
1285 ERR("Multi-channel 3D sounds are not spatialized\n");
1288 hr = DS8Data_Create(&This->buffer, desc, This->primary);
1289 if(FAILED(hr))
1290 goto out;
1291 else
1293 DS8Data *buf = This->buffer;
1295 if(buf->in_type == AL_UNSIGNED_BYTE)
1296 memset(buf->data, 0x80, buf->buf_size);
1297 else
1298 memset(buf->data, 0x00, buf->buf_size);
1300 if(This->ExtAL->BufferDataStatic)
1301 This->ExtAL->BufferDataStatic(buf->buffers[0], buf->buf_format,
1302 buf->data, buf->buf_size,
1303 buf->format.Format.nSamplesPerSec);
1304 else if(This->ExtAL->BufferSamplesSOFT)
1305 This->ExtAL->BufferSamplesSOFT(buf->buffers[0],
1306 buf->format.Format.nSamplesPerSec, buf->buf_format,
1307 buf->buf_size/buf->format.Format.nBlockAlign,
1308 buf->in_chans, buf->in_type, buf->data);
1309 else if(This->ExtAL->BufferSubData)
1310 alBufferData(buf->buffers[0], buf->buf_format,
1311 buf->data, buf->buf_size,
1312 buf->format.Format.nSamplesPerSec);
1314 getALError();
1317 hr = DSERR_GENERIC;
1318 if(This->primary->nsources)
1320 This->source = This->primary->sources[--This->primary->nsources];
1321 alSourcef(This->source, AL_GAIN, 1.0f);
1322 alSourcef(This->source, AL_PITCH, 1.0f);
1323 getALError();
1325 else
1327 alGenSources(1, &This->source);
1328 if(alGetError() != AL_NO_ERROR)
1329 goto out;
1332 ds3dbuffer = &This->ds3dbuffer;
1333 ds3dbuffer->dwSize = sizeof(*ds3dbuffer);
1334 ds3dbuffer->vPosition.x = 0.0;
1335 ds3dbuffer->vPosition.y = 0.0;
1336 ds3dbuffer->vPosition.z = 0.0;
1337 ds3dbuffer->vVelocity.x = 0.0;
1338 ds3dbuffer->vVelocity.y = 0.0;
1339 ds3dbuffer->vVelocity.z = 0.0;
1340 ds3dbuffer->dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
1341 ds3dbuffer->dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
1342 ds3dbuffer->vConeOrientation.x = 0.0;
1343 ds3dbuffer->vConeOrientation.y = 0.0;
1344 ds3dbuffer->vConeOrientation.z = 1.0;
1345 ds3dbuffer->lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
1346 ds3dbuffer->flMinDistance = DS3D_DEFAULTMINDISTANCE;
1347 ds3dbuffer->flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
1348 ds3dbuffer->dwMode = DS3DMODE_NORMAL;
1350 if((This->buffer->dsbflags&DSBCAPS_CTRL3D))
1352 if(This->primary->auxslot != 0)
1354 alSource3i(This->source, AL_AUXILIARY_SEND_FILTER, This->primary->auxslot, 0, AL_FILTER_NULL);
1355 getALError();
1358 hr = IDirectSound3DBuffer_SetAllParameters(&This->IDirectSound3DBuffer_iface, ds3dbuffer, DS3D_IMMEDIATE);
1359 if(FAILED(hr))
1361 ERR("SetAllParameters failed\n");
1362 goto out;
1365 else
1367 ALuint source = This->source;
1369 if(This->primary->auxslot != 0)
1371 /* Simple hack to make reverb affect non-3D sounds too */
1372 alSource3i(source, AL_AUXILIARY_SEND_FILTER, This->primary->auxslot, 0, AL_FILTER_NULL);
1373 /*alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL);*/
1376 /* Non-3D sources aren't distance attenuated */
1377 This->ds3dmode = DS3DMODE_DISABLE;
1378 alSource3f(source, AL_POSITION, 0.0f, 1.0f, 0.0f);
1379 alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
1380 alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
1381 alSourcef(source, AL_CONE_OUTER_GAIN, 1.0f);
1382 alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f);
1383 alSourcef(source, AL_MAX_DISTANCE, 1000.0f);
1384 alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f);
1385 alSourcei(source, AL_CONE_INNER_ANGLE, 360);
1386 alSourcei(source, AL_CONE_OUTER_ANGLE, 360);
1387 alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);
1388 getALError();
1390 hr = S_OK;
1392 out:
1393 popALContext();
1394 LeaveCriticalSection(This->crst);
1396 return hr;
1399 static HRESULT WINAPI DS8Buffer_Lock(IDirectSoundBuffer8 *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
1401 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1402 HRESULT hr;
1403 DWORD remain;
1405 TRACE("(%p)->(%u, %u, %p, %p, %p, %p, 0x%x)\n", This, ofs, bytes, ptr1, len1, ptr2, len2, flags);
1407 if(!ptr1 || !len1)
1409 WARN("Invalid pointer/len %p %p\n", ptr1, len1);
1410 return DSERR_INVALIDPARAM;
1413 EnterCriticalSection(This->crst);
1414 setALContext(This->ctx);
1416 *ptr1 = NULL;
1417 *len1 = 0;
1418 if(ptr2) *ptr2 = NULL;
1419 if(len2) *len2 = 0;
1421 hr = DSERR_INVALIDPARAM;
1422 if((flags&DSBLOCK_FROMWRITECURSOR))
1423 DS8Buffer_GetCurrentPosition(iface, NULL, &ofs);
1424 else if(ofs >= This->buffer->buf_size)
1426 WARN("Invalid ofs %u\n", ofs);
1427 goto out;
1429 if((flags&DSBLOCK_ENTIREBUFFER))
1430 bytes = This->buffer->buf_size;
1431 else if(bytes > This->buffer->buf_size)
1433 WARN("Invalid size %u\n", bytes);
1434 goto out;
1437 *ptr1 = This->buffer->data + ofs;
1438 if(ofs+bytes >= This->buffer->buf_size)
1440 *len1 = This->buffer->buf_size - ofs;
1441 remain = bytes - *len1;
1443 else
1445 *len1 = bytes;
1446 remain = 0;
1449 This->buffer->locked = TRUE;
1451 if(ptr2 && len2 && remain)
1453 *ptr2 = This->buffer->data;
1454 *len2 = remain;
1456 hr = S_OK;
1458 out:
1459 popALContext();
1460 LeaveCriticalSection(This->crst);
1461 return hr;
1464 static HRESULT WINAPI DS8Buffer_Play(IDirectSoundBuffer8 *iface, DWORD res1, DWORD prio, DWORD flags)
1466 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1467 ALint type, state = AL_STOPPED;
1468 HRESULT hr;
1470 TRACE("%p\n", This);
1472 EnterCriticalSection(This->crst);
1473 setALContext(This->ctx);
1475 hr = DSERR_BUFFERLOST;
1476 if(This->bufferlost)
1478 WARN("Buffer %p lost\n", This);
1479 goto out;
1482 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1484 if(!(This->buffer->dsbflags&(DSBCAPS_LOCHARDWARE|DSBCAPS_LOCSOFTWARE)))
1486 if(flags & DSBPLAY_LOCSOFTWARE)
1487 This->buffer->dsbflags |= DSBCAPS_LOCSOFTWARE;
1488 else
1489 This->buffer->dsbflags |= DSBCAPS_LOCHARDWARE;
1492 else if(prio)
1494 ERR("Invalid priority set for non-deferred buffer %p, %u!\n", This->buffer, prio);
1495 hr = DSERR_INVALIDPARAM;
1496 goto out;
1499 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1500 if(This->buffer->numsegs > 1)
1502 This->islooping = !!(flags&DSBPLAY_LOOPING);
1503 if(state != AL_PLAYING && This->isplaying)
1504 state = AL_PLAYING;
1506 else
1508 alGetSourcei(This->source, AL_SOURCE_TYPE, &type);
1509 alSourcei(This->source, AL_LOOPING, (flags&DSBPLAY_LOOPING) ? AL_TRUE : AL_FALSE);
1511 getALError();
1513 hr = S_OK;
1514 if(state == AL_PLAYING)
1515 goto out;
1517 /* alSourceQueueBuffers will implicitly set type to streaming */
1518 if(This->buffer->numsegs == 1)
1520 if(type != AL_STATIC)
1521 alSourcei(This->source, AL_BUFFER, This->buffer->buffers[0]);
1522 alSourcePlay(This->source);
1524 if(alGetError() != AL_NO_ERROR)
1526 ERR("Couldn't start source\n");
1527 This->curidx = (This->buffer->numsegs-1+This->curidx)%This->buffer->numsegs;
1528 alSourcei(This->source, AL_BUFFER, 0);
1529 getALError();
1530 hr = DSERR_GENERIC;
1531 goto out;
1533 This->isplaying = TRUE;
1535 if(This->nnotify)
1537 DS8Buffer_addnotify(This);
1538 DS8Buffer_starttimer(This->primary);
1540 else if(This->buffer->numsegs > 1)
1541 DS8Buffer_starttimer(This->primary);
1543 out:
1544 popALContext();
1545 LeaveCriticalSection(This->crst);
1546 return hr;
1549 static HRESULT WINAPI DS8Buffer_SetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD pos)
1551 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1552 HRESULT hr;
1553 TRACE("%p\n", This);
1555 EnterCriticalSection(This->crst);
1556 setALContext(This->ctx);
1558 hr = DSERR_INVALIDPARAM;
1559 if(pos >= This->buffer->buf_size)
1560 goto out;
1562 if(This->buffer->numsegs > 1)
1564 DS8Data *buf = This->buffer;
1565 This->curidx = pos/buf->segsize;
1566 if(This->curidx >= buf->numsegs)
1567 This->curidx = buf->numsegs - 1;
1568 if(This->isplaying)
1570 alSourceStop(This->source);
1571 alSourcei(This->source, AL_BUFFER, 0);
1572 getALError();
1575 else
1576 alSourcei(This->source, AL_BYTE_OFFSET, pos);
1577 This->lastpos = pos;
1578 hr = S_OK;
1580 out:
1581 popALContext();
1582 LeaveCriticalSection(This->crst);
1583 return hr;
1586 static HRESULT WINAPI DS8Buffer_SetFormat(IDirectSoundBuffer8 *iface, const WAVEFORMATEX *wfx)
1588 /* This call only works on primary buffers */
1589 WARN("(%p)->(%p)\n", iface, wfx);
1590 return DSERR_INVALIDCALL;
1593 static HRESULT WINAPI DS8Buffer_SetVolume(IDirectSoundBuffer8 *iface, LONG vol)
1595 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1596 HRESULT hr = S_OK;
1598 TRACE("(%p)->(%d)\n", iface, vol);
1600 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
1602 WARN("Invalid volume (%d)\n", vol);
1603 return DSERR_INVALIDPARAM;
1606 EnterCriticalSection(This->crst);
1607 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
1608 hr = DSERR_CONTROLUNAVAIL;
1609 if(SUCCEEDED(hr))
1611 ALfloat fvol = mB_to_gain(vol);
1612 setALContext(This->ctx);
1613 alSourcef(This->source, AL_GAIN, fvol);
1614 popALContext();
1616 LeaveCriticalSection(This->crst);
1618 return hr;
1621 static HRESULT WINAPI DS8Buffer_SetPan(IDirectSoundBuffer8 *iface, LONG pan)
1623 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1624 HRESULT hr = S_OK;
1626 TRACE("(%p)->(%d)\n", iface, pan);
1628 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
1630 WARN("invalid parameter: pan = %d\n", pan);
1631 return DSERR_INVALIDPARAM;
1634 EnterCriticalSection(This->crst);
1635 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
1636 hr = DSERR_CONTROLUNAVAIL;
1637 else
1639 ALfloat pos[3];
1640 pos[0] = (pan-DSBPAN_LEFT) * 2.0 / (ALfloat)(DSBPAN_RIGHT-DSBPAN_LEFT) - 1.0;
1641 /* NOTE: Strict movement along the X plane can cause the sound to jump
1642 * between left and right sharply. Using a curved path helps smooth it
1643 * out */
1644 pos[1] = sqrt(1.0 - pos[0]*pos[0]);
1645 pos[2] = 0.0;
1647 setALContext(This->ctx);
1648 alSourcefv(This->source, AL_POSITION, pos);
1649 getALError();
1650 popALContext();
1652 if(pan != 0 && This->buffer->format.Format.nChannels > 1)
1653 FIXME("Panning for multi-channel buffers is not supported\n");
1655 LeaveCriticalSection(This->crst);
1657 return hr;
1660 static HRESULT WINAPI DS8Buffer_SetFrequency(IDirectSoundBuffer8 *iface, DWORD freq)
1662 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1663 HRESULT hr = S_OK;
1665 TRACE("(%p)->(%u)\n", iface, freq);
1667 if(freq < DSBFREQUENCY_MIN || freq > DSBFREQUENCY_MAX)
1669 WARN("invalid parameter: freq = %d\n", freq);
1670 return DSERR_INVALIDPARAM;
1673 EnterCriticalSection(This->crst);
1674 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
1675 hr = DSERR_CONTROLUNAVAIL;
1676 else
1678 ALfloat pitch = 1.0f;
1679 if(freq != DSBFREQUENCY_ORIGINAL)
1680 pitch = freq / (ALfloat)This->buffer->format.Format.nSamplesPerSec;
1682 setALContext(This->ctx);
1683 alSourcef(This->source, AL_PITCH, pitch);
1684 getALError();
1685 popALContext();
1687 LeaveCriticalSection(This->crst);
1688 return hr;
1691 static HRESULT WINAPI DS8Buffer_Stop(IDirectSoundBuffer8 *iface)
1693 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1694 ALint state;
1696 TRACE("(%p)->()\n", iface);
1698 EnterCriticalSection(This->crst);
1699 setALContext(This->ctx);
1701 alSourcePause(This->source);
1702 getALError();
1703 /* Mac OS X doesn't immediately report state change
1704 * if Play() is immediately called after Stop, this can be fatal,
1705 * the buffer would never be restarted
1707 do {
1708 state = AL_PAUSED;
1709 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1710 if(state != AL_PLAYING)
1711 break;
1712 Sleep(1);
1713 } while(1);
1715 /* Stopped, remove from notify list */
1716 if(This->nnotify)
1718 HRESULT hr;
1719 DWORD pos = This->lastpos;
1720 hr = IDirectSoundBuffer8_GetCurrentPosition(iface, &pos, NULL);
1721 if(FAILED(hr))
1722 ERR("Own getcurrentposition failed!\n");
1723 trigger_notifies(This, This->lastpos, pos, TRUE);
1724 This->lastpos = pos;
1725 DS8Buffer_removenotify(This);
1728 This->isplaying = FALSE;
1730 popALContext();
1731 LeaveCriticalSection(This->crst);
1733 return S_OK;
1736 static HRESULT WINAPI DS8Buffer_Unlock(IDirectSoundBuffer8 *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
1738 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1739 DS8Data *buf = This->buffer;
1740 DWORD bufsize = buf->buf_size;
1741 DWORD_PTR ofs1, ofs2;
1742 DWORD_PTR boundary = (DWORD_PTR)buf->data;
1743 HRESULT hr;
1745 TRACE("(%p)->(%p, %u, %p, %u)\n", iface, ptr1, len1, ptr2, len2);
1747 EnterCriticalSection(This->crst);
1748 setALContext(This->ctx);
1750 This->buffer->locked = 0;
1751 hr = DSERR_INVALIDPARAM;
1753 /* Make sure offset is between boundary and boundary + bufsize */
1754 ofs1 = (DWORD_PTR)ptr1;
1755 ofs2 = (DWORD_PTR)ptr2;
1756 if(ofs1 < boundary)
1757 goto out;
1758 if(ofs2 && ofs2 != boundary)
1759 goto out;
1760 ofs1 -= boundary;
1761 ofs2 = 0;
1762 if(bufsize-ofs1 < len1 || len2 > ofs1)
1763 goto out;
1764 if(!ptr2)
1765 len2 = 0;
1767 hr = S_OK;
1768 if(!len1 && !len2)
1769 goto out;
1771 if(This->ExtAL->BufferDataStatic)
1772 goto out;
1774 if(This->ExtAL->BufferSubSamplesSOFT)
1776 WAVEFORMATEX *format = &buf->format.Format;
1778 ptr1 = (BYTE*)ptr1 - (ofs1%format->nBlockAlign);
1779 ofs1 /= format->nBlockAlign;
1780 len1 /= format->nBlockAlign;
1781 if(len1 > 0)
1782 This->ExtAL->BufferSubSamplesSOFT(buf->buffers[0], ofs1, len1,
1783 buf->in_chans, buf->in_type, ptr1);
1784 ptr2 = (BYTE*)ptr2 - (ofs2%format->nBlockAlign);
1785 ofs2 /= format->nBlockAlign;
1786 len2 /= format->nBlockAlign;
1787 if(len2 > 0)
1788 This->ExtAL->BufferSubSamplesSOFT(buf->buffers[0], ofs2, len2,
1789 buf->in_chans, buf->in_type, ptr2);
1790 getALError();
1792 else if(This->ExtAL->BufferSubData)
1794 WAVEFORMATEX *format = &buf->format.Format;
1796 len1 -= len1%format->nBlockAlign;
1797 if(len1 > 0)
1798 This->ExtAL->BufferSubData(buf->buffers[0], buf->buf_format, ptr1,
1799 ofs1, len1);
1800 len2 -= len2%format->nBlockAlign;
1801 if(len2 > 0)
1802 This->ExtAL->BufferSubData(buf->buffers[0], buf->buf_format, ptr2,
1803 ofs2, len2);
1804 getALError();
1806 else
1808 alBufferData(buf->buffers[0], buf->buf_format,
1809 buf->data, buf->buf_size,
1810 buf->format.Format.nSamplesPerSec);
1811 getALError();
1814 out:
1815 if(hr != S_OK)
1816 WARN("Invalid parameters (0x%lx,%u) (%p,%u,%p,%u)\n", boundary, bufsize, ptr1, len1, ptr2, len2);
1817 popALContext();
1818 LeaveCriticalSection(This->crst);
1819 return hr;
1822 static HRESULT WINAPI DS8Buffer_Restore(IDirectSoundBuffer8 *iface)
1824 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1825 HRESULT hr;
1827 TRACE("(%p)->()\n", iface);
1829 EnterCriticalSection(This->crst);
1830 if(This->primary->parent->prio_level < DSSCL_WRITEPRIMARY ||
1831 iface == This->primary->write_emu)
1833 This->bufferlost = 0;
1834 hr = S_OK;
1836 else
1837 hr = DSERR_BUFFERLOST;
1838 LeaveCriticalSection(This->crst);
1840 return hr;
1843 static HRESULT WINAPI DS8Buffer_SetFX(IDirectSoundBuffer8 *iface, DWORD fxcount, DSEFFECTDESC *desc, DWORD *rescodes)
1845 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1846 DWORD i;
1848 TRACE("(%p)->(%u, %p, %p)\n", This, fxcount, desc, rescodes);
1850 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFX))
1852 WARN("FX control not set\n");
1853 return DSERR_CONTROLUNAVAIL;
1856 if(fxcount == 0)
1858 if(desc || rescodes)
1860 WARN("Non-NULL desc and/or result pointer specified with no effects.\n");
1861 return DSERR_INVALIDPARAM;
1864 /* No effects; we can handle that */
1865 return DS_OK;
1868 if(!desc || !rescodes)
1870 WARN("NULL desc and/or result pointer specified.\n");
1871 return DSERR_INVALIDPARAM;
1874 /* We don't (currently) handle DSound effects */
1875 for(i = 0;i < fxcount;++i)
1877 FIXME("Cannot handle effect: %s\n", debugstr_guid(&desc[i].guidDSFXClass));
1878 rescodes[i] = DSFXR_FAILED;
1881 return DSERR_INVALIDPARAM;
1884 static HRESULT WINAPI DS8Buffer_AcquireResources(IDirectSoundBuffer8 *iface, DWORD flags, DWORD fxcount, DWORD *rescodes)
1886 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1888 TRACE("(%p)->(%u, %u, %p)\n", This, flags, fxcount, rescodes);
1890 /* effects aren't supported at the moment.. */
1891 if(fxcount != 0 || rescodes)
1893 WARN("Non-zero effect count and/or result pointer specified with no effects.\n");
1894 return DSERR_INVALIDPARAM;
1897 EnterCriticalSection(This->crst);
1898 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1900 This->buffer->dsbflags &= ~(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE);
1901 if((flags&DSBPLAY_LOCSOFTWARE))
1902 This->buffer->dsbflags |= DSBCAPS_LOCSOFTWARE;
1903 else
1904 This->buffer->dsbflags |= DSBCAPS_LOCHARDWARE;
1906 LeaveCriticalSection(This->crst);
1908 return S_OK;
1911 static HRESULT WINAPI DS8Buffer_GetObjectInPath(IDirectSoundBuffer8 *iface, REFGUID guid, DWORD idx, REFGUID rguidiface, void **ppv)
1913 FIXME("(%p)->(%s, %u, %s, %p) : stub!\n", iface, debugstr_guid(guid), idx, debugstr_guid(rguidiface), ppv);
1914 return E_NOTIMPL;
1917 static const IDirectSoundBuffer8Vtbl DS8Buffer_Vtbl =
1919 DS8Buffer_QueryInterface,
1920 DS8Buffer_AddRef,
1921 DS8Buffer_Release,
1922 DS8Buffer_GetCaps,
1923 DS8Buffer_GetCurrentPosition,
1924 DS8Buffer_GetFormat,
1925 DS8Buffer_GetVolume,
1926 DS8Buffer_GetPan,
1927 DS8Buffer_GetFrequency,
1928 DS8Buffer_GetStatus,
1929 DS8Buffer_Initialize,
1930 DS8Buffer_Lock,
1931 DS8Buffer_Play,
1932 DS8Buffer_SetCurrentPosition,
1933 DS8Buffer_SetFormat,
1934 DS8Buffer_SetVolume,
1935 DS8Buffer_SetPan,
1936 DS8Buffer_SetFrequency,
1937 DS8Buffer_Stop,
1938 DS8Buffer_Unlock,
1939 DS8Buffer_Restore,
1940 DS8Buffer_SetFX,
1941 DS8Buffer_AcquireResources,
1942 DS8Buffer_GetObjectInPath
1945 static inline DS8Buffer *impl_from_IDirectSound3DBuffer(IDirectSound3DBuffer *iface)
1947 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSound3DBuffer_iface);
1950 static HRESULT WINAPI DS8Buffer3D_QueryInterface(IDirectSound3DBuffer *iface, REFIID riid, void **ppv)
1952 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1953 return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
1956 static ULONG WINAPI DS8Buffer3D_AddRef(IDirectSound3DBuffer *iface)
1958 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1959 LONG ret;
1961 InterlockedIncrement(&This->all_ref);
1962 ret = InterlockedIncrement(&This->ds3d_ref);
1963 TRACE("new refcount %d\n", ret);
1965 return ret;
1968 static ULONG WINAPI DS8Buffer3D_Release(IDirectSound3DBuffer *iface)
1970 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1971 LONG ret;
1973 ret = InterlockedDecrement(&This->ds3d_ref);
1974 TRACE("new refcount %d\n", ret);
1975 if(InterlockedDecrement(&This->all_ref) == 0)
1976 DS8Buffer_Destroy(This);
1978 return ret;
1981 static HRESULT WINAPI DS8Buffer3D_GetAllParameters(IDirectSound3DBuffer *iface, DS3DBUFFER *ds3dbuffer)
1983 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1984 DS3DBUFFER ds3dbuf;
1985 HRESULT hr;
1987 TRACE("%p\n", This);
1989 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
1991 WARN("Invalid parameters %p %u\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
1992 return DSERR_INVALIDPARAM;
1994 ds3dbuf.dwSize = sizeof(ds3dbuf);
1996 EnterCriticalSection(This->crst);
1997 setALContext(This->ctx);
1999 hr = IDirectSound3DBuffer_GetPosition(iface, &ds3dbuf.vPosition);
2000 if(SUCCEEDED(hr))
2001 hr = IDirectSound3DBuffer_GetVelocity(iface, &ds3dbuf.vVelocity);
2002 if(SUCCEEDED(hr))
2003 hr = IDirectSound3DBuffer_GetConeAngles(iface, &ds3dbuf.dwInsideConeAngle, &ds3dbuf.dwOutsideConeAngle);
2004 if(SUCCEEDED(hr))
2005 hr = IDirectSound3DBuffer_GetConeOrientation(iface, &ds3dbuf.vConeOrientation);
2006 if(SUCCEEDED(hr))
2007 hr = IDirectSound3DBuffer_GetConeOutsideVolume(iface, &ds3dbuf.lConeOutsideVolume);
2008 if(SUCCEEDED(hr))
2009 hr = IDirectSound3DBuffer_GetMinDistance(iface, &ds3dbuf.flMinDistance);
2010 if(SUCCEEDED(hr))
2011 hr = IDirectSound3DBuffer_GetMaxDistance(iface, &ds3dbuf.flMaxDistance);
2012 if(SUCCEEDED(hr))
2013 hr = IDirectSound3DBuffer_GetMode(iface, &ds3dbuf.dwMode);
2014 if(SUCCEEDED(hr))
2015 memcpy(ds3dbuffer, &ds3dbuf, sizeof(ds3dbuf));
2017 popALContext();
2018 LeaveCriticalSection(This->crst);
2020 return hr;
2023 static HRESULT WINAPI DS8Buffer3D_GetConeAngles(IDirectSound3DBuffer *iface, DWORD *pdwInsideConeAngle, DWORD *pdwOutsideConeAngle)
2025 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2026 ALint inangle, outangle;
2028 TRACE("(%p)->(%p, %p)\n", This, pdwInsideConeAngle, pdwOutsideConeAngle);
2029 if(!pdwInsideConeAngle || !pdwOutsideConeAngle)
2031 WARN("Invalid pointers (%p, %p)\n", pdwInsideConeAngle, pdwOutsideConeAngle);
2032 return DSERR_INVALIDPARAM;
2035 EnterCriticalSection(This->crst);
2036 setALContext(This->ctx);
2038 alGetSourcei(This->source, AL_CONE_INNER_ANGLE, &inangle);
2039 alGetSourcei(This->source, AL_CONE_OUTER_ANGLE, &outangle);
2040 getALError();
2041 *pdwInsideConeAngle = inangle;
2042 *pdwOutsideConeAngle = outangle;
2044 popALContext();
2045 LeaveCriticalSection(This->crst);
2047 return S_OK;
2050 static HRESULT WINAPI DS8Buffer3D_GetConeOrientation(IDirectSound3DBuffer *iface, D3DVECTOR *orient)
2052 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2053 ALfloat dir[3];
2055 TRACE("(%p)->(%p)\n", This, orient);
2056 if(!orient)
2058 WARN("Invalid pointer\n");
2059 return DSERR_INVALIDPARAM;
2062 EnterCriticalSection(This->crst);
2063 setALContext(This->ctx);
2065 alGetSourcefv(This->source, AL_DIRECTION, dir);
2066 getALError();
2067 orient->x = dir[0];
2068 orient->y = dir[1];
2069 orient->z = -dir[2];
2071 popALContext();
2072 LeaveCriticalSection(This->crst);
2074 return S_OK;
2077 static HRESULT WINAPI DS8Buffer3D_GetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG *vol)
2079 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2080 ALfloat gain;
2082 TRACE("(%p)->(%p)\n", This, vol);
2083 if(!vol)
2085 WARN("Invalid pointer\n");
2086 return DSERR_INVALIDPARAM;
2089 EnterCriticalSection(This->crst);
2090 setALContext(This->ctx);
2092 alGetSourcef(This->source, AL_CONE_OUTER_GAIN, &gain);
2093 getALError();
2094 *vol = gain_to_mB(gain);
2095 *vol = max(*vol, DSBVOLUME_MIN);
2096 *vol = min(*vol, DSBVOLUME_MAX);
2098 popALContext();
2099 LeaveCriticalSection(This->crst);
2100 return S_OK;
2103 static HRESULT WINAPI DS8Buffer3D_GetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE *maxdist)
2105 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2106 ALfloat dist;
2108 TRACE("(%p)->(%p)\n", This, maxdist);
2109 if(!maxdist)
2111 WARN("Invalid pointer\n");
2112 return DSERR_INVALIDPARAM;
2115 EnterCriticalSection(This->crst);
2116 setALContext(This->ctx);
2118 alGetSourcef(This->source, AL_MAX_DISTANCE, &dist);
2119 getALError();
2120 *maxdist = dist;
2122 popALContext();
2123 LeaveCriticalSection(This->crst);
2125 return S_OK;
2128 static HRESULT WINAPI DS8Buffer3D_GetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE *mindist)
2130 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2131 ALfloat dist;
2133 TRACE("(%p)->(%p)\n", This, mindist);
2134 if(!mindist)
2136 WARN("Invalid pointer\n");
2137 return DSERR_INVALIDPARAM;
2140 EnterCriticalSection(This->crst);
2141 setALContext(This->ctx);
2143 alGetSourcef(This->source, AL_REFERENCE_DISTANCE, &dist);
2144 getALError();
2145 *mindist = dist;
2147 popALContext();
2148 LeaveCriticalSection(This->crst);
2150 return S_OK;
2153 static HRESULT WINAPI DS8Buffer3D_GetMode(IDirectSound3DBuffer *iface, DWORD *mode)
2155 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2157 TRACE("(%p)->(%p)\n", This, mode);
2158 if(!mode)
2160 WARN("Invalid pointer\n");
2161 return DSERR_INVALIDPARAM;
2164 EnterCriticalSection(This->crst);
2165 *mode = This->ds3dmode;
2166 LeaveCriticalSection(This->crst);
2168 return S_OK;
2171 static HRESULT WINAPI DS8Buffer3D_GetPosition(IDirectSound3DBuffer *iface, D3DVECTOR *pos)
2173 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2174 ALfloat alpos[3];
2176 TRACE("(%p)->(%p)\n", This, pos);
2177 if(!pos)
2179 WARN("Invalid pointer\n");
2180 return DSERR_INVALIDPARAM;
2183 EnterCriticalSection(This->crst);
2184 setALContext(This->ctx);
2186 alGetSourcefv(This->source, AL_POSITION, alpos);
2187 getALError();
2188 pos->x = alpos[0];
2189 pos->y = alpos[1];
2190 pos->z = -alpos[2];
2192 popALContext();
2193 LeaveCriticalSection(This->crst);
2195 return S_OK;
2198 static HRESULT WINAPI DS8Buffer3D_GetVelocity(IDirectSound3DBuffer *iface, D3DVECTOR *vel)
2200 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2201 ALfloat alvel[3];
2203 TRACE("(%p)->(%p)\n", This, vel);
2204 if(!vel)
2206 WARN("Invalid pointer\n");
2207 return DSERR_INVALIDPARAM;
2210 EnterCriticalSection(This->crst);
2211 setALContext(This->ctx);
2213 alGetSourcefv(This->source, AL_VELOCITY, alvel);
2214 getALError();
2215 vel->x = alvel[0];
2216 vel->y = alvel[1];
2217 vel->z = -alvel[2];
2219 popALContext();
2220 LeaveCriticalSection(This->crst);
2222 return S_OK;
2225 static HRESULT WINAPI DS8Buffer3D_SetAllParameters(IDirectSound3DBuffer *iface, const DS3DBUFFER *ds3dbuffer, DWORD apply)
2227 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2228 TRACE("(%p)->(%p, %u)\n", This, ds3dbuffer, apply);
2230 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
2232 WARN("Invalid DS3DBUFFER (%p, %u)\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
2233 return DSERR_INVALIDPARAM;
2236 if(ds3dbuffer->dwInsideConeAngle > DS3D_MAXCONEANGLE ||
2237 ds3dbuffer->dwOutsideConeAngle > DS3D_MAXCONEANGLE)
2239 WARN("Invalid cone angles (%u, %u)\n", ds3dbuffer->dwInsideConeAngle,
2240 ds3dbuffer->dwOutsideConeAngle);
2241 return DSERR_INVALIDPARAM;
2244 if(ds3dbuffer->lConeOutsideVolume > DSBVOLUME_MAX ||
2245 ds3dbuffer->lConeOutsideVolume < DSBVOLUME_MIN)
2247 WARN("Invalid cone outside volume (%d)\n", ds3dbuffer->lConeOutsideVolume);
2248 return DSERR_INVALIDPARAM;
2251 if(ds3dbuffer->flMaxDistance < 0.0f)
2253 WARN("Invalid max distance (%f)\n", ds3dbuffer->flMaxDistance);
2254 return DSERR_INVALIDPARAM;
2257 if(ds3dbuffer->flMinDistance < 0.0f)
2259 WARN("Invalid min distance (%f)\n", ds3dbuffer->flMinDistance);
2260 return DSERR_INVALIDPARAM;
2263 if(ds3dbuffer->dwMode != DS3DMODE_NORMAL &&
2264 ds3dbuffer->dwMode != DS3DMODE_HEADRELATIVE &&
2265 ds3dbuffer->dwMode != DS3DMODE_DISABLE)
2267 WARN("Invalid mode (%u)\n", ds3dbuffer->dwMode);
2268 return DSERR_INVALIDPARAM;
2271 EnterCriticalSection(This->crst);
2272 setALContext(This->ctx);
2273 IDirectSound3DBuffer_SetPosition(iface, ds3dbuffer->vPosition.x, ds3dbuffer->vPosition.y, ds3dbuffer->vPosition.z, apply);
2274 IDirectSound3DBuffer_SetVelocity(iface, ds3dbuffer->vVelocity.x, ds3dbuffer->vVelocity.y, ds3dbuffer->vVelocity.z, apply);
2275 IDirectSound3DBuffer_SetConeAngles(iface, ds3dbuffer->dwInsideConeAngle, ds3dbuffer->dwOutsideConeAngle, apply);
2276 IDirectSound3DBuffer_SetConeOrientation(iface, ds3dbuffer->vConeOrientation.x, ds3dbuffer->vConeOrientation.y, ds3dbuffer->vConeOrientation.z, apply);
2277 IDirectSound3DBuffer_SetConeOutsideVolume(iface, ds3dbuffer->lConeOutsideVolume, apply);
2278 IDirectSound3DBuffer_SetMinDistance(iface, ds3dbuffer->flMinDistance, apply);
2279 IDirectSound3DBuffer_SetMaxDistance(iface, ds3dbuffer->flMaxDistance, apply);
2280 IDirectSound3DBuffer_SetMode(iface, ds3dbuffer->dwMode, apply);
2281 popALContext();
2282 LeaveCriticalSection(This->crst);
2284 return S_OK;
2287 static HRESULT WINAPI DS8Buffer3D_SetConeAngles(IDirectSound3DBuffer *iface, DWORD dwInsideConeAngle, DWORD dwOutsideConeAngle, DWORD apply)
2289 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2291 TRACE("(%p)->(%u, %u, %u)\n", This, dwInsideConeAngle, dwOutsideConeAngle, apply);
2292 if(dwInsideConeAngle > DS3D_MAXCONEANGLE ||
2293 dwOutsideConeAngle > DS3D_MAXCONEANGLE)
2295 WARN("Invalid cone angles (%u, %u)\n", dwInsideConeAngle, dwOutsideConeAngle);
2296 return DSERR_INVALIDPARAM;
2299 EnterCriticalSection(This->crst);
2300 if(apply == DS3D_DEFERRED)
2302 This->ds3dbuffer.dwInsideConeAngle = dwInsideConeAngle;
2303 This->ds3dbuffer.dwOutsideConeAngle = dwOutsideConeAngle;
2304 This->dirty.bit.cone_angles = 1;
2306 else
2308 setALContext(This->ctx);
2309 alSourcei(This->source, AL_CONE_INNER_ANGLE, dwInsideConeAngle);
2310 alSourcei(This->source, AL_CONE_OUTER_ANGLE, dwOutsideConeAngle);
2311 getALError();
2312 popALContext();
2314 LeaveCriticalSection(This->crst);
2316 return S_OK;
2319 static HRESULT WINAPI DS8Buffer3D_SetConeOrientation(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2321 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2323 TRACE("(%p)->(%f, %f, %f, %u)\n", This, x, y, z, apply);
2325 EnterCriticalSection(This->crst);
2326 if(apply == DS3D_DEFERRED)
2328 This->ds3dbuffer.vConeOrientation.x = x;
2329 This->ds3dbuffer.vConeOrientation.y = y;
2330 This->ds3dbuffer.vConeOrientation.z = z;
2331 This->dirty.bit.cone_orient = 1;
2333 else
2335 setALContext(This->ctx);
2336 alSource3f(This->source, AL_DIRECTION, x, y, -z);
2337 getALError();
2338 popALContext();
2340 LeaveCriticalSection(This->crst);
2342 return S_OK;
2345 static HRESULT WINAPI DS8Buffer3D_SetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG vol, DWORD apply)
2347 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2349 TRACE("(%p)->(%u, %u)\n", This, vol, apply);
2350 if(vol < DSBVOLUME_MIN || vol > DSBVOLUME_MAX)
2352 WARN("Invalid volume (%u)\n", vol);
2353 return DSERR_INVALIDPARAM;
2356 EnterCriticalSection(This->crst);
2357 if(apply == DS3D_DEFERRED)
2359 This->ds3dbuffer.lConeOutsideVolume = vol;
2360 This->dirty.bit.cone_outsidevolume = 1;
2362 else
2364 setALContext(This->ctx);
2365 alSourcef(This->source, AL_CONE_OUTER_GAIN, mB_to_gain(vol));
2366 getALError();
2367 popALContext();
2369 LeaveCriticalSection(This->crst);
2371 return S_OK;
2374 static HRESULT WINAPI DS8Buffer3D_SetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE maxdist, DWORD apply)
2376 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2378 TRACE("(%p)->(%f, %u)\n", This, maxdist, apply);
2379 if(maxdist < 0.0f)
2381 WARN("Invalid max distance (%f)\n", maxdist);
2382 return DSERR_INVALIDPARAM;
2385 EnterCriticalSection(This->crst);
2386 if(apply == DS3D_DEFERRED)
2388 This->ds3dbuffer.flMaxDistance = maxdist;
2389 This->dirty.bit.max_distance = 1;
2391 else
2393 setALContext(This->ctx);
2394 alSourcef(This->source, AL_MAX_DISTANCE, maxdist);
2395 getALError();
2396 popALContext();
2398 LeaveCriticalSection(This->crst);
2400 return S_OK;
2403 static HRESULT WINAPI DS8Buffer3D_SetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE mindist, DWORD apply)
2405 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2407 TRACE("(%p)->(%f, %u)\n", This, mindist, apply);
2408 if(mindist < 0.0f)
2410 WARN("Invalid min distance (%f)\n", mindist);
2411 return DSERR_INVALIDPARAM;
2414 EnterCriticalSection(This->crst);
2415 if(apply == DS3D_DEFERRED)
2417 This->ds3dbuffer.flMinDistance = mindist;
2418 This->dirty.bit.min_distance = 1;
2420 else
2422 setALContext(This->ctx);
2423 alSourcef(This->source, AL_REFERENCE_DISTANCE, mindist);
2424 getALError();
2425 popALContext();
2427 LeaveCriticalSection(This->crst);
2429 return S_OK;
2432 static HRESULT WINAPI DS8Buffer3D_SetMode(IDirectSound3DBuffer *iface, DWORD mode, DWORD apply)
2434 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2436 TRACE("(%p)->(%u, %u)\n", This, mode, apply);
2437 if(mode != DS3DMODE_NORMAL && mode != DS3DMODE_HEADRELATIVE &&
2438 mode != DS3DMODE_DISABLE)
2440 WARN("Invalid mode (%u)\n", mode);
2441 return DSERR_INVALIDPARAM;
2444 EnterCriticalSection(This->crst);
2445 if(apply == DS3D_DEFERRED)
2447 This->ds3dbuffer.dwMode = mode;
2448 This->dirty.bit.mode = 1;
2450 else
2452 setALContext(This->ctx);
2453 alSourcei(This->source, AL_SOURCE_RELATIVE,
2454 (mode != DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE);
2455 alSourcef(This->source, AL_ROLLOFF_FACTOR,
2456 (mode == DS3DMODE_DISABLE) ? 0.0f : This->primary->rollofffactor);
2457 This->ds3dmode = mode;
2458 getALError();
2459 popALContext();
2461 LeaveCriticalSection(This->crst);
2463 return S_OK;
2466 static HRESULT WINAPI DS8Buffer3D_SetPosition(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2468 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2470 TRACE("(%p)->(%f, %f, %f, %u)\n", This, x, y, z, apply);
2472 EnterCriticalSection(This->crst);
2473 if(apply == DS3D_DEFERRED)
2475 This->ds3dbuffer.vPosition.x = x;
2476 This->ds3dbuffer.vPosition.y = y;
2477 This->ds3dbuffer.vPosition.z = z;
2478 This->dirty.bit.pos = 1;
2480 else
2482 setALContext(This->ctx);
2483 alSource3f(This->source, AL_POSITION, x, y, -z);
2484 getALError();
2485 popALContext();
2487 LeaveCriticalSection(This->crst);
2489 return S_OK;
2492 static HRESULT WINAPI DS8Buffer3D_SetVelocity(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2494 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2496 TRACE("(%p)->(%f, %f, %f, %u)\n", This, x, y, z, apply);
2498 EnterCriticalSection(This->crst);
2499 if(apply == DS3D_DEFERRED)
2501 This->ds3dbuffer.vVelocity.x = x;
2502 This->ds3dbuffer.vVelocity.y = y;
2503 This->ds3dbuffer.vVelocity.z = z;
2504 This->dirty.bit.vel = 1;
2506 else
2508 setALContext(This->ctx);
2509 alSource3f(This->source, AL_VELOCITY, x, y, -z);
2510 getALError();
2511 popALContext();
2513 LeaveCriticalSection(This->crst);
2515 return S_OK;
2518 static const IDirectSound3DBufferVtbl DS8Buffer3d_Vtbl =
2520 DS8Buffer3D_QueryInterface,
2521 DS8Buffer3D_AddRef,
2522 DS8Buffer3D_Release,
2523 DS8Buffer3D_GetAllParameters,
2524 DS8Buffer3D_GetConeAngles,
2525 DS8Buffer3D_GetConeOrientation,
2526 DS8Buffer3D_GetConeOutsideVolume,
2527 DS8Buffer3D_GetMaxDistance,
2528 DS8Buffer3D_GetMinDistance,
2529 DS8Buffer3D_GetMode,
2530 DS8Buffer3D_GetPosition,
2531 DS8Buffer3D_GetVelocity,
2532 DS8Buffer3D_SetAllParameters,
2533 DS8Buffer3D_SetConeAngles,
2534 DS8Buffer3D_SetConeOrientation,
2535 DS8Buffer3D_SetConeOutsideVolume,
2536 DS8Buffer3D_SetMaxDistance,
2537 DS8Buffer3D_SetMinDistance,
2538 DS8Buffer3D_SetMode,
2539 DS8Buffer3D_SetPosition,
2540 DS8Buffer3D_SetVelocity
2543 static inline DS8Buffer *impl_from_IDirectSoundNotify(IDirectSoundNotify *iface)
2545 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSoundNotify_iface);
2548 static HRESULT WINAPI DS8BufferNot_QueryInterface(IDirectSoundNotify *iface, REFIID riid, void **ppv)
2550 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2551 return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2554 static ULONG WINAPI DS8BufferNot_AddRef(IDirectSoundNotify *iface)
2556 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2557 LONG ret;
2559 InterlockedIncrement(&This->all_ref);
2560 ret = InterlockedIncrement(&This->not_ref);
2561 TRACE("new refcount %d\n", ret);
2563 return ret;
2566 static ULONG WINAPI DS8BufferNot_Release(IDirectSoundNotify *iface)
2568 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2569 LONG ret;
2571 ret = InterlockedDecrement(&This->not_ref);
2572 TRACE("new refcount %d\n", ret);
2573 if(InterlockedDecrement(&This->all_ref) == 0)
2574 DS8Buffer_Destroy(This);
2576 return ret;
2579 static HRESULT WINAPI DS8BufferNot_SetNotificationPositions(IDirectSoundNotify *iface, DWORD count, const DSBPOSITIONNOTIFY *notifications)
2581 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2582 DSBPOSITIONNOTIFY *nots;
2583 DWORD state;
2584 HRESULT hr;
2586 EnterCriticalSection(This->crst);
2587 hr = DSERR_INVALIDPARAM;
2588 if(count && !notifications)
2589 goto out;
2591 hr = IDirectSoundBuffer8_GetStatus(&This->IDirectSoundBuffer8_iface, &state);
2592 if(FAILED(hr))
2593 goto out;
2595 hr = DSERR_INVALIDCALL;
2596 if((state&DSBSTATUS_PLAYING))
2597 goto out;
2599 if(!count)
2601 HeapFree(GetProcessHeap(), 0, This->notify);
2602 This->notify = 0;
2603 This->nnotify = 0;
2604 hr = S_OK;
2606 else
2608 DWORD i;
2610 hr = DSERR_INVALIDPARAM;
2611 for(i = 0;i < count;++i)
2613 if(notifications[i].dwOffset >= This->buffer->buf_size &&
2614 notifications[i].dwOffset != (DWORD)DSBPN_OFFSETSTOP)
2615 goto out;
2618 hr = E_OUTOFMEMORY;
2619 nots = HeapAlloc(GetProcessHeap(), 0, count*sizeof(*nots));
2620 if(!nots)
2621 goto out;
2622 memcpy(nots, notifications, count*sizeof(*nots));
2624 HeapFree(GetProcessHeap(), 0, This->notify);
2625 This->notify = nots;
2626 This->nnotify = count;
2628 hr = S_OK;
2631 out:
2632 LeaveCriticalSection(This->crst);
2633 return hr;
2636 static const IDirectSoundNotifyVtbl DS8BufferNot_Vtbl =
2638 DS8BufferNot_QueryInterface,
2639 DS8BufferNot_AddRef,
2640 DS8BufferNot_Release,
2641 DS8BufferNot_SetNotificationPositions
2644 /* NOTE: Due to some apparent quirks in DSound, the listener properties are
2645 handled through secondary buffers. */
2646 static inline DS8Buffer *impl_from_IKsPropertySet(IKsPropertySet *iface)
2648 return CONTAINING_RECORD(iface, DS8Buffer, IKsPropertySet_iface);
2651 static HRESULT WINAPI DS8BufferProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
2653 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2654 return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2657 static ULONG WINAPI DS8BufferProp_AddRef(IKsPropertySet *iface)
2659 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2660 LONG ret;
2662 InterlockedIncrement(&This->all_ref);
2663 ret = InterlockedIncrement(&This->prop_ref);
2664 TRACE("new refcount %d\n", ret);
2666 return ret;
2669 static ULONG WINAPI DS8BufferProp_Release(IKsPropertySet *iface)
2671 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2672 LONG ret;
2674 ret = InterlockedDecrement(&This->prop_ref);
2675 TRACE("new refcount %d\n", ret);
2676 if(InterlockedDecrement(&This->all_ref) == 0)
2677 DS8Buffer_Destroy(This);
2679 return ret;
2682 static HRESULT WINAPI DS8BufferProp_Get(IKsPropertySet *iface,
2683 REFGUID guidPropSet, ULONG dwPropID,
2684 LPVOID pInstanceData, ULONG cbInstanceData,
2685 LPVOID pPropData, ULONG cbPropData,
2686 PULONG pcbReturned)
2688 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2689 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2691 TRACE("(%p)->(%s, %u, %p, %u, %p, %u, %p)\n", iface, debugstr_guid(guidPropSet),
2692 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData, pcbReturned);
2694 if(!pcbReturned)
2695 return E_POINTER;
2696 *pcbReturned = 0;
2698 #if 0
2699 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2702 else
2703 #endif
2705 /* Not a known buffer/source property. Pass it to the listener */
2706 hr = IKsPropertySet_Get(&This->primary->IKsPropertySet_iface, guidPropSet,
2707 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData,
2708 pcbReturned);
2711 return hr;
2714 static HRESULT WINAPI DS8BufferProp_Set(IKsPropertySet *iface,
2715 REFGUID guidPropSet, ULONG dwPropID,
2716 LPVOID pInstanceData, ULONG cbInstanceData,
2717 LPVOID pPropData, ULONG cbPropData)
2719 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2720 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2722 TRACE("(%p)->(%s, %u, %p, %u, %p, %u)\n", iface, debugstr_guid(guidPropSet),
2723 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData);
2725 #if 0
2726 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2729 else
2730 #endif
2732 /* Not a known buffer/source property. Pass it to the listener */
2733 hr = IKsPropertySet_Set(&This->primary->IKsPropertySet_iface, guidPropSet,
2734 dwPropID, pInstanceData, cbInstanceData, pPropData,
2735 cbPropData);
2738 return hr;
2741 static HRESULT WINAPI DS8BufferProp_QuerySupport(IKsPropertySet *iface,
2742 REFGUID guidPropSet, ULONG dwPropID,
2743 PULONG pTypeSupport)
2745 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2746 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2748 TRACE("(%p)->(%s, %u, %p)\n", iface, debugstr_guid(guidPropSet), dwPropID, pTypeSupport);
2750 if(!pTypeSupport)
2751 return E_POINTER;
2752 *pTypeSupport = 0;
2754 #if 0
2755 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2758 else
2759 #endif
2761 /* Not a known buffer/source property. Pass it to the listener */
2762 hr = IKsPropertySet_QuerySupport(&This->primary->IKsPropertySet_iface,
2763 guidPropSet, dwPropID, pTypeSupport);
2766 return hr;
2769 static const IKsPropertySetVtbl DS8BufferProp_Vtbl =
2771 DS8BufferProp_QueryInterface,
2772 DS8BufferProp_AddRef,
2773 DS8BufferProp_Release,
2774 DS8BufferProp_Get,
2775 DS8BufferProp_Set,
2776 DS8BufferProp_QuerySupport