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

Last change on this file since 3338 was 3338, checked in by sandervl, 25 years ago

don't restart when already playing

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