source: trunk/src/dsound/OS2PrimBuff.cpp@ 5120

Last change on this file since 5120 was 3925, checked in by bird, 25 years ago

Added the CVS keyword Id.

File size: 16.7 KB
Line 
1/* $Id: OS2PrimBuff.cpp,v 1.4 2000-08-02 15:48:26 bird Exp $ */
2/*
3 * DirectSound Primary Buffer
4 *
5 * Copyright 1999-2000 Kevin Langman
6 *
7 * Project Odin Software License can be found in LICENSE.TXT
8 *
9 *
10 */
11
12
13/* NOTES:
14
15 Here is how the buffers, GetPosition and Locking works:
16 Dart is allocated many little buffers. These buffers are filled
17 when dart has finished playing one of the buffer, from a 32kb buffer
18 that the Win32 program can write to. The GetPosition function will
19 determine what buffer is being played, and return the offset to the
20 end of this buffer.
21
22 The Lock function will call the GetCurrentPosition function to determine
23 where the end of the currently playing buffer is and allow the Win32
24 program to lock between that location and 15ms from there
25 (15ms should be past the next buffer).
26
27*/
28
29#define INCL_DOSMISC
30#include <os2win.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34
35#define INITGUID
36#include <dsound.h>
37
38//#include "DSound.h"
39#include "OS2DSound.h"
40#include "OS2SndBuffer.h"
41#include "OS2PrimBuff.h"
42#include "OS23DListener.h"
43
44#include "dart.h"
45
46#undef THIS
47#define THIS VOID*This
48
49#undef THIS_
50#define THIS_ VOID*This,
51
52//******************************************************************************
53//******************************************************************************
54OS2PrimBuff::OS2PrimBuff(OS2IDirectSound *DSound, const DSBUFFERDESC *lpDSBufferDesc )
55{
56 LONG rc;
57
58 lpVtbl = &Vtbl;
59 Vtbl.AddRef = PrimBufAddRef;
60 Vtbl.Release = PrimBufRelease;
61 Vtbl.QueryInterface = PrimBufQueryInterface;
62 Vtbl.GetCaps = PrimBufGetCaps;
63 Vtbl.GetFormat = PrimBufGetFormat;
64 Vtbl.GetVolume = PrimBufGetVolume;
65 Vtbl.GetStatus = PrimBufGetStatus;
66 Vtbl.GetCurrentPosition = PrimBufGetCurrentPosition;
67 Vtbl.GetPan = PrimBufGetPan;
68 Vtbl.GetFrequency = PrimBufGetFrequency;
69 Vtbl.Initialize = PrimBufInitialize;
70 Vtbl.Restore = PrimBufRestore;
71 Vtbl.SetFormat = PrimBufSetFormat;
72 Vtbl.SetVolume = PrimBufSetVolume;
73 Vtbl.SetCurrentPosition = PrimBufSetCurrentPosition;
74 Vtbl.SetPan = PrimBufSetPan;
75 Vtbl.SetFrequency = PrimBufSetFrequency;
76 Vtbl.Lock = PrimBufLock;
77 Vtbl.Unlock = PrimBufUnlock;
78 Vtbl.Stop = PrimBufStop;
79 Vtbl.Play = PrimBufPlay;
80
81 dprintf(("DSOUND-PrimBuff: Constructor"));
82
83 parentDS = DSound;
84 fPlaying = FALSE;
85 playpos = 0;
86 fPrimary = TRUE;
87 Referenced = 0;
88 listener = NULL;
89
90 lpfxFormat = (WAVEFORMATEX *)malloc(/*bufferdesc.lpwfxFormat->cbSize +*/ sizeof(WAVEFORMATEX));
91 lpfxFormat->wBitsPerSample = bps = 16;
92 lpfxFormat->nChannels = channels = 2;
93 lpfxFormat->nSamplesPerSec = rate = 22500;
94
95 bufferdesc.dwBufferBytes = BUFFER_SIZE;
96
97 lastError = Dart_Open_Device(&usDeviceID, &vpMixBuffer, &vpMixSetup,
98 &vpBuffParms, (PVOID*)&lpBuffer );
99
100 if (lastError == DS_OK)
101 primary = this;
102}
103
104//******************************************************************************
105//******************************************************************************
106OS2PrimBuff::~OS2PrimBuff()
107{
108 dprintf(("DSOUND-PrimBuff: Destructor"));
109
110 if (fPlaying)
111 Dart_Stop(usDeviceID);
112
113 lastError = Dart_Close_Device(usDeviceID, vpMixBuffer, vpMixSetup,
114 vpBuffParms );
115
116 dprintf(("DSOUND-PrimBuff: Freeing Memory"));
117 free(lpfxFormat);
118 //free( *vpMixBuffer );
119 //free( *vpMixSetup );
120 //free( *vpBuffParms );
121 //free( vpGenericParms );
122
123 dprintf(("DSOUND-PrimBuff: Destructor Complete"));
124
125 primary = NULL;
126}
127
128//******************************************************************************
129//******************************************************************************
130HRESULT WIN32API PrimBufQueryInterface(THIS, REFIID riid, LPVOID * ppvObj)
131{
132 dprintf(("DSOUND-PrimBuff: QueryInterface"));
133
134 if (This == NULL) {
135 return DSERR_INVALIDPARAM;
136 }
137 *ppvObj = NULL;
138
139 if (IsEqualGUID(riid, IID_IDirectSoundBuffer)) {
140 *ppvObj = This;
141 PrimBufAddRef(This);
142 return DS_OK;
143 }
144
145
146 if (IsEqualGUID(riid, IID_IDirectSound3DListener)) {
147 OS2PrimBuff *me = (OS2PrimBuff *)This;
148 OS2IDirectSound3DListener *listener;
149
150 listener = new OS2IDirectSound3DListener(me);
151 *ppvObj = listener;
152 listener->Vtbl.AddRef((IDirectSound3DListener *)listener);
153 return DS_OK;
154 }
155
156 // I guess a Notify object should be creaed for the Primary Buffer also..
157 // Does windows DSound have a notify object for Primary buffer???
158
159 return E_NOINTERFACE;
160}
161
162//******************************************************************************
163//******************************************************************************
164ULONG WIN32API PrimBufAddRef(THIS)
165{
166 OS2PrimBuff *me = (OS2PrimBuff *)This;
167
168 dprintf(("DSOUND-PrimBuff: AddRef %d", me->Referenced+1));
169
170 if (me == NULL) {
171 return DS_OK;
172 }
173 return ++me->Referenced;
174}
175
176//******************************************************************************
177//******************************************************************************
178ULONG WIN32API PrimBufRelease(THIS)
179{
180 OS2PrimBuff *me = (OS2PrimBuff *)This;
181
182 dprintf(("DSOUND-PrimBuff: Release %d", me->Referenced-1));
183
184 if (me == NULL) {
185 return DS_OK;
186 }
187 if (me->Referenced) {
188 me->Referenced--;
189 if (me->Referenced == 0) {
190 delete me;
191 return DS_OK;
192 }
193 else
194 return me->Referenced;
195 }
196 else
197 return DS_OK;
198}
199
200//******************************************************************************
201//******************************************************************************
202HRESULT __stdcall PrimBufGetCaps(THIS_ LPDSBCAPS lpDSCaps )
203{
204 OS2PrimBuff *me = (OS2PrimBuff *)This;
205
206 dprintf(("DSOUND-PrimBuff: GetCaps"));
207 if(me == NULL || lpDSCaps == NULL)
208 {
209 return DSERR_INVALIDPARAM;
210 }
211
212 lpDSCaps->dwFlags = DSBCAPS_PRIMARYBUFFER;
213 lpDSCaps->dwBufferBytes = BUFFER_SIZE;
214 lpDSCaps->dwUnlockTransferRate = 0;
215 lpDSCaps->dwPlayCpuOverhead = 0;
216
217 return DS_OK;
218}
219
220//******************************************************************************
221//******************************************************************************
222HRESULT __stdcall PrimBufGetCurrentPosition(THIS_ LPDWORD lpdwCurrentPlayCursor,LPDWORD lpdwCurrentWriteCursor )
223{
224 OS2PrimBuff *me = (OS2PrimBuff *)This;
225 LONG lDartPos;
226 LONG lBytesPerSec;
227
228 dprintf(("DSOUND-PrimBuff: GetCurrentPosition"));
229
230 if (me == NULL || lpdwCurrentPlayCursor == NULL || lpdwCurrentWriteCursor == NULL) {
231 return DSERR_INVALIDPARAM;
232 }
233
234 if (me->fPlaying == FALSE) {
235 *lpdwCurrentPlayCursor = 0;
236 *lpdwCurrentWriteCursor = 0;
237 return DS_OK;
238 }
239
240
241 Dart_GetPosition( me->usDeviceID, &lDartPos ); // Returns the Playing Buffer * 'Bytes Per Dart Bufer'
242
243 *lpdwCurrentPlayCursor = lDartPos;
244
245 // Calculate the Write Cursor as 15ms from the current play cursor.
246 // NOTE: This may need to be changed to insure that the write cursor is always beyond the
247 // point where the next buffer will read from.
248 *lpdwCurrentWriteCursor = (lDartPos + (me->rate * me->channels * (me->bps/8) * 15 / 1000) ) % BUFFER_SIZE;
249
250 return DS_OK;
251}
252
253
254//******************************************************************************
255//******************************************************************************
256HRESULT __stdcall PrimBufGetFormat(THIS_ LPWAVEFORMATEX lpfxFormat, DWORD dwSizeAllocated , LPDWORD lpdwSizeWritten )
257{
258 OS2PrimBuff *me = (OS2PrimBuff *)This;
259 long copysize;
260
261 dprintf(("DSOUND-PrimBuff: GetFormat"));
262
263 if( me == NULL || lpfxFormat == NULL || dwSizeAllocated == 0)
264 {
265 return DSERR_INVALIDPARAM;
266 }
267
268 copysize = min(dwSizeAllocated, (me->lpfxFormat->cbSize + sizeof(WAVEFORMATEX)));
269 memcpy(lpfxFormat, me->lpfxFormat, copysize);
270
271 if(lpdwSizeWritten)
272 {
273 *lpdwSizeWritten = copysize;
274 }
275 return DS_OK;
276}
277
278//******************************************************************************
279//******************************************************************************
280HRESULT __stdcall PrimBufGetVolume(THIS_ LPLONG )
281{
282 dprintf(("DSOUND-PrimBuff: GetVolume"));
283
284 return DSERR_INVALIDCALL;
285}
286
287//******************************************************************************
288//******************************************************************************
289HRESULT __stdcall PrimBufGetPan(THIS_ LPLONG )
290{
291 dprintf(("DSOUND-PrimBuff: GetPan"));
292
293 return DSERR_INVALIDCALL;
294}
295
296//******************************************************************************
297//******************************************************************************
298HRESULT __stdcall PrimBufGetFrequency(THIS_ LPDWORD )
299{
300 dprintf(("DSOUND-PrimBuff: GetGrequency"));
301
302 return DSERR_INVALIDCALL;
303}
304
305//******************************************************************************
306//******************************************************************************
307HRESULT __stdcall PrimBufGetStatus(THIS_ LPDWORD lpdwStatus )
308{
309 OS2PrimBuff *me = (OS2PrimBuff *)This;
310 dprintf(("DSOUND-PrimBuff: GetStatus"));
311
312 if (me == NULL || lpdwStatus == NULL) {
313 return(DSERR_INVALIDPARAM);
314 }
315
316 *lpdwStatus = DSBSTATUS_LOOPING /*| DSBSTATUS_LOCSOFTWARE*/;
317 if (me->fPlaying == TRUE)
318 *lpdwStatus |= DSBSTATUS_PLAYING;
319
320 return DS_OK;
321}
322
323//******************************************************************************
324//******************************************************************************
325HRESULT __stdcall PrimBufInitialize(THIS_ LPDIRECTSOUND, LPDSBUFFERDESC )
326{
327 OS2PrimBuff *me = (OS2PrimBuff *)This;
328 dprintf(("DSOUND-PrimBuff: Initialize"));
329
330 if (me == NULL) {
331 return DSERR_INVALIDPARAM;
332 }
333 return DSERR_ALREADYINITIALIZED; //todo: for future extensions (dx5/6 ??) ??
334}
335
336//******************************************************************************
337//******************************************************************************
338HRESULT __stdcall PrimBufLock(THIS_ DWORD dwWriteCursor, DWORD dwWriteBytes,
339 LPVOID lplpAudioPtr1, LPDWORD lpdwAudioBytes1,
340 LPVOID lplpAudioPtr2, LPDWORD lpdwAudioBytes2,
341 DWORD dwFlags)
342{
343 OS2PrimBuff *me = (OS2PrimBuff *)This;
344 DWORD dwCurPlayPos, dwCurWritePos;
345 LONG rc;
346
347 dprintf(("DSOUND-PrimBuff: Lock"));
348
349 if (me == NULL || !lplpAudioPtr1 || !lpdwAudioBytes1) {
350 return DSERR_INVALIDPARAM;
351 }
352 //not sure if this is an error, but it's certainly a smart thing to do (cond. == true)
353 if (dwWriteBytes > BUFFER_SIZE) {
354 dprintf(("SoundBufLock: dwWriteBytes > me->bufferdesc.dwBufferBytes"));
355 return DSERR_INVALIDPARAM;
356 }
357
358 if (me->fPlaying == FALSE) {
359 *(DWORD*)lplpAudioPtr1 = (DWORD)(me->lpBuffer);
360 *lpdwAudioBytes1 = dwWriteBytes;
361 if (lplpAudioPtr2 != NULL) {
362 *(DWORD*)lplpAudioPtr2 = NULL;
363 *lpdwAudioBytes2 = 0;
364 }
365 return DS_OK;
366 }
367
368 rc = PrimBufGetCurrentPosition( me, &dwCurPlayPos, &dwCurWritePos );
369 if (rc != DS_OK) {
370 return DSERR_GENERIC;
371 }
372
373 /* Debugging */
374 dprintf(("DSOUND-PrimBuff: CurPlay = %d, CurWrite = %d", dwCurPlayPos, dwCurWritePos));
375
376 if (dwFlags & DSBLOCK_FROMWRITECURSOR) {
377 dprintf(("DSOUND-PrimBuff: Locking FromCursor"));
378 dwWriteCursor = dwCurWritePos;
379 }
380
381 *(DWORD*)lplpAudioPtr1 = (DWORD)(me->lpBuffer + dwWriteCursor);
382
383 if (dwWriteCursor > dwCurPlayPos) {
384 if (dwWriteCursor + dwWriteBytes > BUFFER_SIZE) {
385 *lpdwAudioBytes1 = BUFFER_SIZE - dwWriteCursor;
386 if (lplpAudioPtr2!=NULL) {
387 *(DWORD*)lplpAudioPtr2 = (DWORD)me->lpBuffer;
388 if (dwWriteBytes - *lpdwAudioBytes1 > dwCurPlayPos) {
389 *lpdwAudioBytes2 = dwCurPlayPos;
390 } else {
391 *lpdwAudioBytes2 = dwWriteBytes - *lpdwAudioBytes1;
392 }
393 }
394 } else {
395 *lpdwAudioBytes1 = dwWriteBytes;
396 if (lplpAudioPtr2!=NULL) {
397 *(DWORD*)lplpAudioPtr2 = NULL;
398 *lpdwAudioBytes2 = 0;
399 }
400 }
401 } else { // The WriteCursor is behind of the PlayCursor
402 if (lplpAudioPtr2!=NULL) {
403 *(DWORD*)lplpAudioPtr2 = NULL;
404 *lpdwAudioBytes2 = 0;
405 }
406 if (dwWriteCursor + dwWriteBytes > dwCurPlayPos) {
407 *lpdwAudioBytes1 = dwWriteCursor - dwCurPlayPos;
408 } else {
409 *lpdwAudioBytes1 = dwWriteBytes;
410 }
411 }
412
413 return DS_OK;
414}
415
416//******************************************************************************
417//******************************************************************************
418HRESULT __stdcall PrimBufPlay(THIS_ DWORD dwRes1,DWORD dwRes2,DWORD dwFlags )
419{
420 long rc;
421 OS2PrimBuff *me = (OS2PrimBuff *)This;
422
423 if (me == NULL || !(dwFlags & DSBPLAY_LOOPING) ) {
424 return DSERR_INVALIDPARAM;
425 }
426
427 if (me->fPlaying)
428 return DS_OK;
429
430 dprintf(("DSOUND-PrimBuff: Play"));
431
432 rc = Dart_Play(me->usDeviceID, me->vpMixSetup, me->vpMixBuffer, me->fPlaying);
433 me->fPlaying = TRUE;
434 return rc;
435}
436
437//******************************************************************************
438//******************************************************************************
439HRESULT __stdcall PrimBufSetCurrentPosition(THIS_ DWORD )
440{
441 dprintf(("DSOUND-PrimBuff: SetCurrentPosition"));
442
443 return DSERR_INVALIDCALL;
444}
445
446//******************************************************************************
447//******************************************************************************
448HRESULT __stdcall PrimBufSetFormat(THIS_ LPWAVEFORMATEX lpfxFormat )
449{
450 dprintf(("DSOUND-PrimBuff: SetFormat"));
451 OS2PrimBuff *me = (OS2PrimBuff *)This;
452
453 if (me == NULL || lpfxFormat == NULL) {
454 return DSERR_INVALIDPARAM;
455 }
456
457 /* Note: the software mixer doesn't really support mono output but */
458 /* we can safely mix in stereo anyway */
459 if (lpfxFormat->nChannels == 1) {
460 if (me->parentDS->GetCoopLevel() != DSSCL_WRITEPRIMARY)
461 lpfxFormat->nChannels = 2;
462 }
463
464 memcpy( me->lpfxFormat, lpfxFormat, sizeof(WAVEFORMATEX) );
465
466 me->bps = lpfxFormat->wBitsPerSample;
467 me->rate = lpfxFormat->nSamplesPerSec;
468 me->channels = lpfxFormat->nChannels;
469
470 dprintf(("DSOUND-PrimBuff: BPS = %d, Rate = %d, Ch = %d", me->bps, me->rate, me->channels));
471
472 Dart_SetFormat(&me->usDeviceID, me->vpMixSetup, me->vpBuffParms, &me->vpMixBuffer, me->bps, me->rate, me->channels);
473
474 return DS_OK;
475}
476
477//******************************************************************************
478//******************************************************************************
479HRESULT __stdcall PrimBufSetVolume(THIS_ LONG )
480{
481 dprintf(("DSOUND-PrimBuff: SetVolume"));
482
483 return DSERR_CONTROLUNAVAIL;
484}
485
486//******************************************************************************
487//******************************************************************************
488HRESULT __stdcall PrimBufSetPan(THIS_ LONG )
489{
490 dprintf(("DSOUND-PrimBuff: SetPan"));
491
492 return DSERR_CONTROLUNAVAIL;
493}
494
495//******************************************************************************
496//******************************************************************************
497HRESULT __stdcall PrimBufSetFrequency(THIS_ DWORD )
498{
499 dprintf(("DSOUND-PrimBuff: SetFrequency"));
500
501 return DSERR_CONTROLUNAVAIL;
502}
503
504//******************************************************************************
505//******************************************************************************
506HRESULT __stdcall PrimBufStop(THIS )
507{
508 OS2PrimBuff *me = (OS2PrimBuff *)This;
509 dprintf(("DSOUND-PrimBuff: Stop"));
510
511 if (me == NULL) {
512 return DSERR_INVALIDPARAM;
513 }
514
515 if (!me->fPlaying)
516 return DS_OK;
517
518 me->fPlaying = FALSE;
519
520 return Dart_Stop(me->usDeviceID);
521}
522
523//******************************************************************************
524//******************************************************************************
525HRESULT __stdcall PrimBufUnlock(THIS_ LPVOID,DWORD,LPVOID,DWORD )
526{
527 // I don't think we really need any code here..
528
529 dprintf(("DSOUND-PrimBuff: Unlock"));
530
531 return DS_OK;
532}
533
534//******************************************************************************
535//******************************************************************************
536HRESULT __stdcall PrimBufRestore(THIS )
537{
538 // This maybe a good place to re-aquire the device if some other process
539 // has taken the audio focus, but before we do that we need to determine
540 // if we have lost the device and set the falg in the GetStatus method!
541
542 dprintf(("DSOUND-PrimBuff: Restore"));
543
544 return DS_OK;
545}
546
547
Note: See TracBrowser for help on using the repository browser.