source: trunk/src/winmm/dwaveout.cpp@ 5272

Last change on this file since 5272 was 5272, checked in by sandervl, 24 years ago

Added preliminary wavein support

File size: 25.9 KB
Line 
1/* $Id: dwaveout.cpp,v 1.31 2001-02-27 21:13:59 sandervl Exp $ */
2
3/*
4 * Wave playback class
5 *
6 * Copyright 1998 Sander van Leeuwen (sandervl@xs4all.nl)
7 *
8 *
9 * Project Odin Software License can be found in LICENSE.TXT
10 *
11 * Note:
12 * 2000/11/24 PH MCI_MIXSETUP_PARMS->pMixWrite does alter FS: selector!
13 *
14 */
15
16
17/****************************************************************************
18 * Includes *
19 ****************************************************************************/
20
21
22
23#define INCL_BASE
24#define INCL_OS2MM
25#include <os2wrap.h> //Odin32 OS/2 api wrappers
26#include <os2mewrap.h> //Odin32 OS/2 MMPM/2 api wrappers
27#include <stdlib.h>
28#include <string.h>
29#define OS2_ONLY
30#include <win32api.h>
31#include <wprocess.h>
32
33#include "misc.h"
34#include "dwaveout.h"
35
36#define DBG_LOCALLOG DBG_dwaveout
37#include "dbglocal.h"
38
39#ifndef min
40#define min(a, b) ((a > b) ? b : a)
41#endif
42
43#ifndef max
44#define max(a, b) ((a > b) ? a : b)
45#endif
46
47LONG APIENTRY WaveOutHandler(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags);
48
49//TODO: mulaw, alaw & adpcm
50/******************************************************************************/
51/******************************************************************************/
52DartWaveOut::DartWaveOut(LPWAVEFORMATEX pwfx)
53{
54 Init(pwfx);
55}
56/******************************************************************************/
57/******************************************************************************/
58DartWaveOut::DartWaveOut(LPWAVEFORMATEX pwfx, ULONG nCallback, ULONG dwInstance, USHORT usSel)
59{
60 Init(pwfx);
61
62 mthdCallback = (LPDRVCALLBACK)nCallback; // callback function
63 selCallback = usSel; // callback win32 tib selector
64 this->dwInstance = dwInstance;
65 fUnderrun = FALSE;
66
67 if(!ulError)
68 callback((ULONG)this, WOM_OPEN, dwInstance, 0, 0);
69}
70/******************************************************************************/
71/******************************************************************************/
72DartWaveOut::DartWaveOut(LPWAVEFORMATEX pwfx, HWND hwndCallback)
73{
74 Init(pwfx);
75
76 this->hwndCallback = hwndCallback;
77
78 if(!ulError)
79 PostMessageA(hwndCallback, WOM_OPEN, 0, 0);
80}
81/******************************************************************************/
82/******************************************************************************/
83void DartWaveOut::callback(HDRVR h, UINT uMessage, DWORD dwUser, DWORD dw1, DWORD dw2)
84{
85 USHORT selTIB = GetFS(); // save current FS selector
86
87 dprintf(("WINMM:DartWaveOut::callback(HDRVR h=%08xh, UINT uMessage=%08xh, DWORD dwUser=%08xh, DWORD dw1=%08xh, DWORD dw2=%08xh)\n",
88 h,
89 uMessage,
90 dwUser,
91 dw1,
92 dw2));
93
94 if (selCallback != 0)
95 SetFS(selCallback); // switch to callback win32 tib selector (stored in waveOutOpen)
96 else
97 dprintf(("WINMM:DartWaveOut::callback - selCallback is invalid"));
98
99 //@@@PH 1999/12/28 Shockwave Flashes seem to make assumptions on a
100 // specific stack layout. Do we have the correct calling convention here?
101 mthdCallback(h,uMessage,dwUser,dw1,dw2);
102 SetFS(selTIB); // switch back to the saved FS selector
103}
104/******************************************************************************/
105/******************************************************************************/
106void DartWaveOut::Init(LPWAVEFORMATEX pwfx)
107{
108 MCI_GENERIC_PARMS GenericParms;
109 MCI_AMP_OPEN_PARMS AmpOpenParms;
110 APIRET rc;
111
112 curPlayBuf = curFillBuf = curFillPos = curPlayPos = 0;
113
114 fMixerSetup = FALSE;
115 next = NULL;
116 wavehdr = NULL;
117 curhdr = NULL;
118 mthdCallback = NULL;
119 hwndCallback = 0;
120 selCallback = 0;
121 dwInstance = 0;
122 ulError = 0;
123 selCallback = 0;
124 volume = defvolume;
125 State = STATE_STOPPED;
126
127 MixBuffer = (MCI_MIX_BUFFER *)malloc(PREFILLBUF_DART*sizeof(MCI_MIX_BUFFER));
128 MixSetupParms = (MCI_MIXSETUP_PARMS *)malloc(sizeof(MCI_MIXSETUP_PARMS));
129 BufferParms = (MCI_BUFFER_PARMS *)malloc(sizeof(MCI_BUFFER_PARMS));
130
131 BitsPerSample = pwfx->wBitsPerSample;
132 SampleRate = pwfx->nSamplesPerSec;
133 this->nChannels = pwfx->nChannels;
134 ulBufSize = DART_BUFSIZE;
135
136 dprintf(("waveOutOpen: samplerate %d, numChan %d bps %d (%d), format %x", SampleRate, nChannels, BitsPerSample, pwfx->nBlockAlign, pwfx->wFormatTag));
137 // Setup the open structure, pass the playlist and tell MCI_OPEN to use it
138 memset(&AmpOpenParms,0,sizeof(AmpOpenParms));
139
140 AmpOpenParms.usDeviceID = ( USHORT ) 0;
141 AmpOpenParms.pszDeviceType = ( PSZ ) MCI_DEVTYPE_AUDIO_AMPMIX;
142
143 rc = mciSendCommand(0, MCI_OPEN,
144 MCI_WAIT | MCI_OPEN_TYPE_ID | MCI_OPEN_SHAREABLE,
145 (PVOID) &AmpOpenParms,
146 0);
147 DeviceId = AmpOpenParms.usDeviceID;
148 if(rc) {
149 dprintf(("MCI_OPEN failed\n"));
150 mciError(rc);
151 ulError = MMSYSERR_NODRIVER;
152 }
153 if(rc == 0) {
154 //Grab exclusive rights to device instance (NOT entire device)
155 GenericParms.hwndCallback = 0; //Not needed, so set to 0
156 rc = mciSendCommand(DeviceId, MCI_ACQUIREDEVICE, MCI_EXCLUSIVE_INSTANCE,
157 (PVOID)&GenericParms, 0);
158 if(rc) {
159 dprintf(("MCI_ACQUIREDEVICE failed\n"));
160 mciError(rc);
161 ulError = MMSYSERR_NOTENABLED;
162 }
163 }
164 State = STATE_STOPPED;
165
166 setVolume(volume);
167
168 wmutex = new VMutex();
169 if(wmutex == NULL) {
170 DebugInt3();
171 ulError = MMSYSERR_NOTSUPPORTED;
172 }
173 if(wmutex)
174 wmutex->enter(VMUTEX_WAIT_FOREVER);
175
176 if(waveout == NULL) {
177 waveout = this;
178 }
179 else {
180 DartWaveOut *dwave = waveout;
181
182 while(dwave->next) {
183 dwave = dwave->next;
184 }
185 dwave->next = this;
186 }
187
188 if(wmutex)
189 wmutex->leave();
190}
191/******************************************************************************/
192/******************************************************************************/
193DartWaveOut::~DartWaveOut()
194{
195 MCI_GENERIC_PARMS GenericParms;
196
197 if(!ulError) {
198 // Generic parameters
199 GenericParms.hwndCallback = 0; //hwndFrame
200
201 // Stop the playback.
202 mciSendCommand(DeviceId, MCI_STOP,MCI_WAIT, (PVOID)&GenericParms,0);
203
204 mciSendCommand(DeviceId,
205 MCI_BUFFER,
206 MCI_WAIT | MCI_DEALLOCATE_MEMORY,
207 (PVOID)&BufferParms,
208 0);
209
210 // Generic parameters
211 GenericParms.hwndCallback = 0; //hwndFrame
212
213 // Close the device
214 mciSendCommand(DeviceId, MCI_CLOSE, MCI_WAIT, (PVOID)&GenericParms, 0);
215 }
216
217 if(wmutex)
218 wmutex->enter(VMUTEX_WAIT_FOREVER);
219
220 State = STATE_STOPPED;
221
222 if(waveout == this) {
223 waveout = this->next;
224 }
225 else {
226 DartWaveOut *dwave = waveout;
227
228 while(dwave->next != this) {
229 dwave = dwave->next;
230 }
231 dwave->next = this->next;
232 }
233 if(wmutex)
234 wmutex->leave();
235
236 if(!ulError) {
237 if(mthdCallback) {
238 callback((ULONG)this, WOM_CLOSE, dwInstance, 0, 0);
239 }
240 else
241 if(hwndCallback)
242 PostMessageA(hwndCallback, WOM_CLOSE, 0, 0);
243 }
244
245 if(wmutex)
246 delete wmutex;
247
248 if(MixBuffer)
249 free(MixBuffer);
250 if(MixSetupParms)
251 free(MixSetupParms);
252 if(BufferParms)
253 free(BufferParms);
254}
255/******************************************************************************/
256/******************************************************************************/
257MMRESULT DartWaveOut::getError()
258{
259 return(ulError);
260}
261/******************************************************************************/
262/******************************************************************************/
263int DartWaveOut::getNumDevices()
264{
265 MCI_GENERIC_PARMS GenericParms;
266 MCI_AMP_OPEN_PARMS AmpOpenParms;
267 APIRET rc;
268
269 // Setup the open structure, pass the playlist and tell MCI_OPEN to use it
270 memset(&AmpOpenParms,0,sizeof(AmpOpenParms));
271
272 AmpOpenParms.usDeviceID = ( USHORT ) 0;
273 AmpOpenParms.pszDeviceType = ( PSZ ) MCI_DEVTYPE_AUDIO_AMPMIX;
274
275 rc = mciSendCommand(0, MCI_OPEN,
276 MCI_WAIT | MCI_OPEN_TYPE_ID | MCI_OPEN_SHAREABLE,
277 (PVOID) &AmpOpenParms,
278 0);
279
280 if(rc) {
281 return 0; //no devices present
282 }
283
284 // Generic parameters
285 GenericParms.hwndCallback = 0; //hwndFrame
286
287 // Close the device
288 mciSendCommand(AmpOpenParms.usDeviceID, MCI_CLOSE, MCI_WAIT, (PVOID)&GenericParms, 0);
289
290 return 1;
291}
292/******************************************************************************/
293/******************************************************************************/
294MMRESULT DartWaveOut::write(LPWAVEHDR pwh, UINT cbwh)
295{
296 MCI_GENERIC_PARMS GenericParms = {0};
297 APIRET rc;
298 int i, buflength;
299
300 if(fMixerSetup == FALSE)
301 {
302 dprintf(("device acquired\n"));
303 /* Set the MixSetupParms data structure to match the loaded file.
304 * This is a global that is used to setup the mixer.
305 */
306 memset(MixSetupParms, 0, sizeof( MCI_MIXSETUP_PARMS ) );
307
308 MixSetupParms->ulBitsPerSample = BitsPerSample;
309 MixSetupParms->ulSamplesPerSec = SampleRate;
310 MixSetupParms->ulFormatTag = MCI_WAVE_FORMAT_PCM;
311 MixSetupParms->ulChannels = nChannels;
312
313 dprintf(("bps %d, sps %d chan %d\n", BitsPerSample, SampleRate, nChannels));
314
315 /* Setup the mixer for playback of wave data
316 */
317 MixSetupParms->ulFormatMode = MCI_PLAY;
318 MixSetupParms->ulDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO;
319 MixSetupParms->pmixEvent = WaveOutHandler;
320
321 rc = mciSendCommand(DeviceId,
322 MCI_MIXSETUP,
323 MCI_WAIT | MCI_MIXSETUP_INIT,
324 (PVOID)MixSetupParms,
325 0);
326
327 if ( rc != MCIERR_SUCCESS ) {
328 mciError(rc);
329 mciSendCommand(DeviceId, MCI_RELEASEDEVICE, MCI_WAIT,
330 (PVOID)&GenericParms, 0);
331 return(MMSYSERR_NOTSUPPORTED);
332 }
333
334 /*
335 * Set up the BufferParms data structure and allocate
336 * device buffers from the Amp-Mixer
337 */
338 dprintf(("mix setup %d, %d\n", pwh->dwBufferLength, pwh->dwBufferLength));
339
340#if 1
341 int consumerate = getAvgBytesPerSecond();
342 int minbufsize = consumerate/32;
343
344 ulBufSize = pwh->dwBufferLength/2;
345 if(ulBufSize < minbufsize) {
346 dprintf(("set buffer size to %d bytes (org size = %d)", minbufsize, pwh->dwBufferLength));
347 ulBufSize = minbufsize;
348 }
349#else
350 if(pwh->dwBufferLength >= 512 && pwh->dwBufferLength <= 1024)
351 ulBufSize = pwh->dwBufferLength;
352 else ulBufSize = 1024;
353#endif
354
355 MixSetupParms->ulBufferSize = ulBufSize;
356
357 BufferParms->ulNumBuffers = PREFILLBUF_DART;
358 BufferParms->ulBufferSize = MixSetupParms->ulBufferSize;
359 BufferParms->pBufList = MixBuffer;
360
361 for(i=0;i<PREFILLBUF_DART;i++) {
362 MixBuffer[i].ulUserParm = (ULONG)this;
363 }
364
365 rc = mciSendCommand(DeviceId,
366 MCI_BUFFER,
367 MCI_WAIT | MCI_ALLOCATE_MEMORY,
368 (PVOID)BufferParms,
369 0);
370
371 if(ULONG_LOWD(rc) != MCIERR_SUCCESS) {
372 mciError(rc);
373 mciSendCommand(DeviceId, MCI_RELEASEDEVICE, MCI_WAIT,
374 (PVOID)&GenericParms, 0);
375 return(MMSYSERR_NOTSUPPORTED);
376 }
377
378 wmutex->enter(VMUTEX_WAIT_FOREVER);
379 fMixerSetup = TRUE;
380
381 curPlayBuf = curFillBuf = curFillPos = curPlayPos = 0;
382
383 for(i=0;i<PREFILLBUF_DART;i++) {
384 memset(MixBuffer[i].pBuffer, 0, MixBuffer[i].ulBufferLength);
385 }
386 dprintf(("Dart opened, bufsize = %d\n", MixBuffer[0].ulBufferLength));
387
388 wavehdr = pwh;
389 curhdr = pwh;
390 pwh->lpNext = NULL;
391
392 if(State != STATE_STOPPED) {//don't start playback if paused
393 wmutex->leave();
394 return(MMSYSERR_NOERROR);
395 }
396
397 while(TRUE) {
398 buflength = min((ULONG)MixBuffer[curFillBuf].ulBufferLength - curPlayPos,
399 (ULONG)wavehdr->dwBufferLength - curFillPos);
400 dprintf(("Copying %d data; curPlayPos = %d curFillPos = %d\n", buflength, curPlayPos, curFillPos));
401
402 memcpy((char *)MixBuffer[curFillBuf].pBuffer + curPlayPos,
403 wavehdr->lpData + curFillPos,
404 buflength);
405
406 curPlayPos += buflength;
407 curFillPos += buflength;
408 if(curFillPos == wavehdr->dwBufferLength) {
409 dprintf(("Processed first win32 buffer\n"));
410 curFillPos = 0;
411 wavehdr->dwFlags |= WHDR_DONE;
412 curhdr = NULL;
413 }
414 if(curPlayPos == MixBuffer[curPlayBuf].ulBufferLength) {
415 if(++curPlayBuf == PREFILLBUF_DART) {
416 curPlayBuf = 0;
417 break;
418 }
419 curPlayPos = 0;
420 }
421 if(curFillPos == 0)
422 break;
423 }
424 dprintf(("MixSetupParms = %X\n", MixSetupParms));
425 State = STATE_PLAYING;
426 fUnderrun = FALSE;
427 wmutex->leave();
428
429 //write buffers to DART; starts playback
430 {
431 // MCI_MIXSETUP_PARMS->pMixWrite does alter FS: selector!
432 USHORT selTIB = GetFS(); // save current FS selector
433
434 MixSetupParms->pmixWrite(MixSetupParms->ulMixHandle,
435 MixBuffer,
436 PREFILLBUF_DART);
437 SetFS(selTIB); // switch back to the saved FS selector
438 }
439 dprintf(("Dart playing\n"));
440 }
441 else
442 {
443 wmutex->enter(VMUTEX_WAIT_FOREVER);
444 pwh->lpNext = NULL;
445 if(wavehdr) {
446 WAVEHDR *chdr = wavehdr;
447 while(chdr->lpNext) {
448 chdr = chdr->lpNext;
449 }
450 chdr->lpNext = pwh;
451 }
452 else wavehdr = pwh;
453 wmutex->leave();
454 if(State == STATE_STOPPED || fUnderrun) {//continue playback
455 restart();
456 }
457 }
458
459 return(MMSYSERR_NOERROR);
460}
461/******************************************************************************/
462/******************************************************************************/
463MMRESULT DartWaveOut::pause()
464{
465 MCI_GENERIC_PARMS Params;
466
467 wmutex->enter(VMUTEX_WAIT_FOREVER);
468 if(State != STATE_PLAYING) {
469 State = STATE_PAUSED;
470 wmutex->leave();
471 return(MMSYSERR_NOERROR);
472 }
473
474 State = STATE_PAUSED;
475 wmutex->leave();
476
477 memset(&Params, 0, sizeof(Params));
478
479 // Stop the playback.
480 mciSendCommand(DeviceId, MCI_PAUSE, MCI_WAIT, (PVOID)&Params, 0);
481
482 return(MMSYSERR_NOERROR);
483}
484/******************************************************************************/
485/******************************************************************************/
486MMRESULT DartWaveOut::reset()
487{
488 MCI_GENERIC_PARMS Params;
489
490 dprintf(("DartWaveOut::reset %s", (State == STATE_PLAYING) ? "playing" : "stopped"));
491 if(State != STATE_PLAYING)
492 return(MMSYSERR_HANDLEBUSY);
493
494 memset(&Params, 0, sizeof(Params));
495
496 // Stop the playback.
497 mciSendCommand(DeviceId, MCI_STOP, MCI_WAIT, (PVOID)&Params, 0);
498
499 dprintf(("Nr of threads blocked on mutex = %d\n", wmutex->getNrBlocked()));
500
501 wmutex->enter(VMUTEX_WAIT_FOREVER);
502 while(wavehdr) {
503 wavehdr->dwFlags |= WHDR_DONE;
504 wavehdr->dwFlags &= ~WHDR_INQUEUE;
505 wavehdr = wavehdr->lpNext;
506 wavehdr->lpNext = NULL;
507 wmutex->leave();
508 if(mthdCallback) {
509 callback((ULONG)this, WOM_DONE, dwInstance, (ULONG)wavehdr, 0);
510 }
511 else
512 if(hwndCallback) {
513 dprintf(("Callback (msg) for buffer %x", wavehdr));
514 PostMessageA(hwndCallback, WOM_DONE, (WPARAM)this, (ULONG)wavehdr);
515 }
516 wmutex->enter(VMUTEX_WAIT_FOREVER);
517 }
518 wavehdr = NULL;
519 State = STATE_STOPPED;
520 fUnderrun = FALSE;
521
522 wmutex->leave();
523 return(MMSYSERR_NOERROR);
524}
525/******************************************************************************/
526/******************************************************************************/
527MMRESULT DartWaveOut::restart()
528{
529 int i, curbuf;
530
531 dprintf(("DartWaveOut::restart"));
532 if(State == STATE_PLAYING)
533 return(MMSYSERR_NOERROR);
534
535 //Only write buffers to dart if mixer has been initialized; if not, then
536 //the first buffer write will do this for us.
537 if(fMixerSetup == TRUE)
538 {
539 wmutex->enter(VMUTEX_WAIT_FOREVER);
540 State = STATE_PLAYING;
541 fUnderrun = FALSE;
542 wmutex->leave();
543 curbuf = curPlayBuf;
544
545 // MCI_MIXSETUP_PARMS->pMixWrite does alter FS: selector!
546 USHORT selTIB = GetFS(); // save current FS selector
547
548 for(i=0;i<PREFILLBUF_DART;i++)
549 {
550 MixSetupParms->pmixWrite(MixSetupParms->ulMixHandle, &MixBuffer[curbuf], 1);
551 if(++curbuf == PREFILLBUF_DART)
552 curbuf = 0;
553 }
554
555 SetFS(selTIB); // switch back to the saved FS selector
556 }
557 return(MMSYSERR_NOERROR);
558}
559/******************************************************************************/
560/******************************************************************************/
561ULONG DartWaveOut::getPosition()
562{
563 MCI_STATUS_PARMS mciStatus = {0};
564 ULONG rc, nrbytes;
565
566 mciStatus.ulItem = MCI_STATUS_POSITION;
567 rc = mciSendCommand(DeviceId, MCI_STATUS, MCI_STATUS_ITEM|MCI_WAIT, (PVOID)&mciStatus, 0);
568 if((rc & 0xFFFF) == MCIERR_SUCCESS) {
569 nrbytes = (mciStatus.ulReturn * (getAvgBytesPerSecond()/1000));
570 return nrbytes;;
571 }
572 mciError(rc);
573 return 0xFFFFFFFF;
574}
575/******************************************************************************/
576/******************************************************************************/
577BOOL DartWaveOut::queryFormat(ULONG formatTag, ULONG nChannels,
578 ULONG nSamplesPerSec, ULONG wBitsPerSample)
579{
580 MCI_WAVE_GETDEVCAPS_PARMS mciAudioCaps;
581 MCI_GENERIC_PARMS GenericParms;
582 MCI_OPEN_PARMS mciOpenParms; /* open parms for MCI_OPEN */
583 int i, freqbits = 0;
584 ULONG rc, DeviceId;
585 BOOL winrc;
586
587 dprintf(("DartWaveOut::queryFormat %x srate=%d, nchan=%d, bps=%d", formatTag, nSamplesPerSec, nChannels, wBitsPerSample));
588
589 memset(&mciOpenParms, /* Object to fill with zeros. */
590 0, /* Value to place into the object. */
591 sizeof( mciOpenParms ) ); /* How many zero's to use. */
592
593 mciOpenParms.pszDeviceType = (PSZ)MCI_DEVTYPE_WAVEFORM_AUDIO;
594
595 rc = mciSendCommand( (USHORT) 0,
596 MCI_OPEN,
597 MCI_WAIT | MCI_OPEN_TYPE_ID,
598 (PVOID) &mciOpenParms,
599 0);
600 if((rc & 0xFFFF) != MCIERR_SUCCESS) {
601 mciError(rc);
602 return(FALSE);
603 }
604 DeviceId = mciOpenParms.usDeviceID;
605
606 memset( &mciAudioCaps , 0, sizeof(MCI_WAVE_GETDEVCAPS_PARMS));
607
608 mciAudioCaps.ulBitsPerSample = wBitsPerSample;
609 mciAudioCaps.ulFormatTag = DATATYPE_WAVEFORM;
610 mciAudioCaps.ulSamplesPerSec = nSamplesPerSec;
611 mciAudioCaps.ulChannels = nChannels;
612 mciAudioCaps.ulFormatMode = MCI_PLAY;
613 mciAudioCaps.ulItem = MCI_GETDEVCAPS_WAVE_FORMAT;
614
615 rc = mciSendCommand(DeviceId, /* Device ID */
616 MCI_GETDEVCAPS,
617 MCI_WAIT | MCI_GETDEVCAPS_EXTENDED | MCI_GETDEVCAPS_ITEM,
618 (PVOID) &mciAudioCaps,
619 0);
620 if((rc & 0xFFFF) != MCIERR_SUCCESS) {
621 mciError(rc);
622 winrc = FALSE;
623 }
624 else winrc = TRUE;
625
626 // Close the device
627 mciSendCommand(DeviceId,MCI_CLOSE,MCI_WAIT,(PVOID)&GenericParms,0);
628 return(winrc);
629}
630/******************************************************************************/
631/******************************************************************************/
632void DartWaveOut::mciError(ULONG ulError)
633{
634#ifdef DEBUG
635 char szError[256] = "";
636
637 mciGetErrorString(ulError, szError, sizeof(szError));
638 dprintf(("WINMM: DartWaveOut: %s\n", szError));
639#endif
640}
641//******************************************************************************
642//******************************************************************************
643BOOL DartWaveOut::find(DartWaveOut *dwave)
644{
645 DartWaveOut *curwave = waveout;
646
647 while(curwave) {
648 if(dwave == curwave) {
649 return(TRUE);
650 }
651 curwave = curwave->next;
652 }
653
654#ifdef DEBUG
655// WriteLog("WINMM:DartWaveOut not found!\n");
656#endif
657 return(FALSE);
658}
659/******************************************************************************/
660/******************************************************************************/
661void DartWaveOut::handler(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags)
662{
663 ULONG buflength;
664 WAVEHDR *whdr, *prevhdr = NULL;
665
666#ifdef DEBUG1
667 dprintf(("WINMM: handler %d\n", curPlayBuf));
668#endif
669 if(ulFlags == MIX_STREAM_ERROR) {
670 if(ulStatus == ERROR_DEVICE_UNDERRUN) {
671 dprintf(("WINMM: WaveOut handler UNDERRUN!\n"));
672 if(State == STATE_PLAYING) {
673 fUnderrun = TRUE;
674 pause(); //out of buffers, so pause playback
675 }
676 return;
677 }
678 dprintf(("WINMM: WaveOut handler, Unknown error %X\n", ulStatus));
679 return;
680 }
681 wmutex->enter(VMUTEX_WAIT_FOREVER);
682
683 whdr = wavehdr;
684 if(whdr == NULL) {
685 wmutex->leave();
686 //last buffer played -> no new ones -> underrun; pause playback
687 dprintf(("WINMM: WaveOut handler UNDERRUN!\n"));
688 if(State == STATE_PLAYING) {
689 fUnderrun = TRUE;
690 pause(); //out of buffers, so pause playback
691 }
692 return;
693 }
694 while(whdr) {
695 if(whdr->dwFlags & WHDR_DONE) {
696#ifdef DEBUG1
697 dprintf(("WINMM: handler buf %X done\n", whdr));
698#endif
699 whdr->dwFlags &= ~WHDR_INQUEUE;
700
701 if(prevhdr == NULL)
702 wavehdr = whdr->lpNext;
703 else prevhdr->lpNext = whdr->lpNext;
704
705 whdr->lpNext = NULL;
706 wmutex->leave();
707
708 if(mthdCallback) {
709 callback((ULONG)this, WOM_DONE, dwInstance, (ULONG)whdr, 0);
710 }
711 else
712 if(hwndCallback) {
713 dprintf(("Callback (msg) for buffer %x", whdr));
714 PostMessageA(hwndCallback, WOM_DONE, (WPARAM)this, (ULONG)whdr);
715 }
716
717 wmutex->enter(VMUTEX_WAIT_FOREVER);
718 }
719 prevhdr = whdr;
720 whdr = whdr->lpNext;
721 }
722
723 if(curhdr == NULL)
724 curhdr = wavehdr;
725
726#ifdef DEBUG1
727 dprintf(("WINMM: handler cur (%d,%d), fill (%d,%d)\n", curPlayBuf, curPlayPos, curFillBuf, curFillPos));
728#endif
729
730 while(curhdr) {
731 buflength = min((ULONG)MixBuffer[curFillBuf].ulBufferLength - curPlayPos,
732 (ULONG)curhdr->dwBufferLength - curFillPos);
733 memcpy((char *)MixBuffer[curFillBuf].pBuffer + curPlayPos,
734 curhdr->lpData + curFillPos,
735 buflength);
736 curPlayPos += buflength;
737 curFillPos += buflength;
738#ifdef DEBUG1
739 dprintf(("WINMM: copied %d bytes, cufFillPos = %d, dwBufferLength = %d\n", buflength, curFillPos, curhdr->dwBufferLength));
740#endif
741 if(curFillPos == curhdr->dwBufferLength) {
742#ifdef DEBUG1
743 dprintf(("Buffer %d done\n", curFillBuf));
744#endif
745 curFillPos = 0;
746 curhdr->dwFlags |= WHDR_DONE;
747 //search for next unprocessed buffer
748 while(curhdr && curhdr->dwFlags & WHDR_DONE)
749 curhdr = curhdr->lpNext;
750 }
751 if(curPlayPos == MixBuffer[curFillBuf].ulBufferLength) {
752 curPlayPos = 0;
753 if(++curFillBuf == PREFILLBUF_DART) {
754 curFillBuf = 0;
755 }
756 if(curFillBuf == curPlayBuf)
757 break; //no more room left
758 }
759 }
760
761 if(curPlayBuf == PREFILLBUF_DART-1)
762 curPlayBuf = 0;
763 else curPlayBuf++;
764
765 wmutex->leave();
766
767 //Transfer buffer to DART
768 // MCI_MIXSETUP_PARMS->pMixWrite does alter FS: selector!
769 USHORT selTIB = GetFS(); // save current FS selector
770 MixSetupParms->pmixWrite(MixSetupParms->ulMixHandle, &MixBuffer[curPlayBuf], 1);
771 SetFS(selTIB); // switch back to the saved FS selector
772}
773/******************************************************************************/
774/******************************************************************************/
775LONG APIENTRY WaveOutHandler(ULONG ulStatus,
776 PMCI_MIX_BUFFER pBuffer,
777 ULONG ulFlags)
778{
779 // PTIB ptib;
780 // PPIB ppib;
781 // DosGetInfoBlocks(&ptib, &ppib);
782 // dprintf(("WaveOutHandler: thread %d prio %X", ptib->tib_ptib2->tib2_ultid, ptib->tib_ptib2->tib2_ulpri));
783
784 DartWaveOut *dwave;
785
786 if(pBuffer && pBuffer->ulUserParm)
787 {
788 dwave = (DartWaveOut *)pBuffer->ulUserParm;
789 dwave->handler(ulStatus, pBuffer, ulFlags);
790 }
791 return(TRUE);
792}
793
794/******************************************************************************/
795/******************************************************************************/
796MMRESULT DartWaveOut::setVolume(ULONG ulVol)
797{
798 ULONG ulVolR = (((ulVol & 0xffff0000) >> 16 )*100)/0xFFFF; // Right Volume
799 ULONG ulVolL = ((ulVol& 0x0000ffff)*100)/0xFFFF; // Left Volume
800 MCI_SET_PARMS msp = {0};
801
802 dprintf(("DartWaveOut::setVolume %x %x", ulVolL, ulVolR));
803 volume = ulVol;
804
805// PD: My card (ESS 1868 PnP) driver can't change only
806// one channel Left or Right :-(
807//
808#ifdef GOOD_AUDIO_CARD_DRIVER
809
810 msp.ulAudio = MCI_SET_AUDIO_LEFT;
811 msp.ulLevel = ulVolL;
812
813 mciSendCommand(DeviceId, MCI_SET,
814 MCI_WAIT | MCI_SET_AUDIO | MCI_SET_VOLUME,
815 &msp, 0);
816
817 msp.ulAudio = MCI_SET_AUDIO_RIGHT;
818 msp.ulLevel = ulVolR;
819
820#else
821 msp.ulAudio = MCI_SET_AUDIO_ALL;
822 msp.ulLevel = max(ulVolR,ulVolL);
823#endif
824
825 mciSendCommand(DeviceId, MCI_SET,
826 MCI_WAIT | MCI_SET_AUDIO | MCI_SET_VOLUME,
827 &msp, 0);
828 return 0;
829}
830/******************************************************************************/
831//Called if waveOutSetVolume is called by the application with waveout handle NULL
832//Sets the default volume of each waveout stream (until it's volume is changed
833//with an appropriate waveOutSetVolume call)
834/******************************************************************************/
835void DartWaveOut::setDefaultVolume(ULONG volume)
836{
837 defvolume = volume;
838}
839/******************************************************************************/
840/******************************************************************************/
841DartWaveOut *DartWaveOut::waveout = NULL;
842ULONG DartWaveOut::defvolume = 0xFFFFFFFF;
843
Note: See TracBrowser for help on using the repository browser.