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

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

fixed restart

File size: 23.6 KB
Line 
1/* $Id: dwaveout.cpp,v 1.21 2000-04-06 21:11:10 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 wmutex->enter(VMUTEX_WAIT_FOREVER);
506 State = STATE_PLAYING;
507 wmutex->leave();
508 curbuf = curPlayBuf;
509 for(i=0;i<PREFILLBUF_DART;i++) {
510 MixSetupParms->pmixWrite(MixSetupParms->ulMixHandle, &MixBuffer[curbuf], 1);
511 if(++curbuf == PREFILLBUF_DART) {
512 curbuf = 0;
513 }
514 }
515 return(MMSYSERR_NOERROR);
516}
517/******************************************************************************/
518/******************************************************************************/
519ULONG DartWaveOut::getPosition()
520{
521 MCI_STATUS_PARMS mciStatus = {0};
522 ULONG rc, nrbytes;
523
524 if(State != STATE_PLAYING)
525 return 0;
526
527 mciStatus.ulItem = MCI_STATUS_POSITION;
528 rc = mciSendCommand(DeviceId, MCI_STATUS, MCI_STATUS_ITEM|MCI_WAIT, (PVOID)&mciStatus, 0);
529 if((rc & 0xFFFF) == MCIERR_SUCCESS) {
530 nrbytes = (mciStatus.ulReturn * (getAvgBytesPerSecond()/1000));
531 return nrbytes;;
532 }
533 mciError(rc);
534 return 0xFFFFFFFF;
535}
536/******************************************************************************/
537/******************************************************************************/
538BOOL DartWaveOut::queryFormat(ULONG formatTag, ULONG nChannels,
539 ULONG nSamplesPerSec, ULONG wBitsPerSample)
540{
541 MCI_WAVE_GETDEVCAPS_PARMS mciAudioCaps;
542 MCI_GENERIC_PARMS GenericParms;
543 MCI_OPEN_PARMS mciOpenParms; /* open parms for MCI_OPEN */
544 int i, freqbits = 0;
545 ULONG rc, DeviceId;
546 BOOL winrc;
547
548 dprintf(("DartWaveOut::queryFormat %x srate=%d, nchan=%d, bps=%d", formatTag, nSamplesPerSec, nChannels, wBitsPerSample));
549
550 memset(&mciOpenParms, /* Object to fill with zeros. */
551 0, /* Value to place into the object. */
552 sizeof( mciOpenParms ) ); /* How many zero's to use. */
553
554 mciOpenParms.pszDeviceType = (PSZ)MCI_DEVTYPE_WAVEFORM_AUDIO;
555
556 rc = mciSendCommand( (USHORT) 0,
557 MCI_OPEN,
558 MCI_WAIT | MCI_OPEN_TYPE_ID,
559 (PVOID) &mciOpenParms,
560 0);
561 if (rc != 0) {
562 return(FALSE);
563 }
564 DeviceId = mciOpenParms.usDeviceID;
565
566 memset( &mciAudioCaps , 0, sizeof(MCI_WAVE_GETDEVCAPS_PARMS));
567
568 mciAudioCaps.ulBitsPerSample = wBitsPerSample;
569 mciAudioCaps.ulFormatTag = DATATYPE_WAVEFORM;
570 mciAudioCaps.ulSamplesPerSec = nSamplesPerSec;
571 mciAudioCaps.ulChannels = nChannels;
572 mciAudioCaps.ulFormatMode = MCI_PLAY;
573 mciAudioCaps.ulItem = MCI_GETDEVCAPS_WAVE_FORMAT;
574
575 rc = mciSendCommand(DeviceId, /* Device ID */
576 MCI_GETDEVCAPS,
577 MCI_WAIT | MCI_GETDEVCAPS_EXTENDED | MCI_GETDEVCAPS_ITEM,
578 (PVOID) &mciAudioCaps,
579 0);
580 if((rc & 0xFFFF) != MCIERR_SUCCESS) {
581 mciError(rc);
582 winrc = FALSE;
583 }
584 else winrc = TRUE;
585
586 // Close the device
587 mciSendCommand(DeviceId,MCI_CLOSE,MCI_WAIT,(PVOID)&GenericParms,0);
588 return(winrc);
589}
590/******************************************************************************/
591/******************************************************************************/
592void DartWaveOut::mciError(ULONG ulError)
593{
594#ifdef DEBUG
595 char szError[256] = "";
596
597 mciGetErrorString(ulError, szError, sizeof(szError));
598 dprintf(("WINMM: DartWaveOut: %s\n", szError));
599#endif
600}
601//******************************************************************************
602//******************************************************************************
603BOOL DartWaveOut::find(DartWaveOut *dwave)
604{
605 DartWaveOut *curwave = waveout;
606
607 while(curwave) {
608 if(dwave == curwave) {
609 return(TRUE);
610 }
611 curwave = curwave->next;
612 }
613
614#ifdef DEBUG
615// WriteLog("WINMM:DartWaveOut not found!\n");
616#endif
617 return(FALSE);
618}
619/******************************************************************************/
620/******************************************************************************/
621void DartWaveOut::handler(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags)
622{
623 ULONG buflength;
624 WAVEHDR *whdr = wavehdr, *prevhdr = NULL;
625
626#ifdef DEBUG1
627 dprintf(("WINMM: handler %d\n", curPlayBuf));
628#endif
629 if(ulFlags == MIX_STREAM_ERROR) {
630 if(ulStatus == ERROR_DEVICE_UNDERRUN) {
631 dprintf(("WINMM: WaveOut handler UNDERRUN!\n"));
632 pause(); //out of buffers, so pause playback
633 return;
634 }
635 dprintf(("WINMM: WaveOut handler, Unknown error %X\n", ulStatus));
636 return;
637 }
638 wmutex->enter(VMUTEX_WAIT_FOREVER);
639
640 while(whdr) {
641 if(whdr->dwFlags & WHDR_DONE) {
642#ifdef DEBUG1
643 dprintf(("WINMM: handler buf %X done\n", whdr));
644#endif
645 whdr->dwFlags &= ~WHDR_INQUEUE;
646
647 if(prevhdr == NULL)
648 wavehdr = whdr->lpNext;
649 else prevhdr->lpNext = whdr->lpNext;
650
651 whdr->lpNext = NULL;
652 wmutex->leave();
653
654 if(mthdCallback) {
655 callback((ULONG)this, WOM_DONE, dwInstance, (ULONG)whdr, 0);
656 }
657 else
658 if(hwndCallback) {
659 dprintf(("Callback (msg) for buffer %x", whdr));
660 PostMessageA(hwndCallback, WOM_DONE, (WPARAM)this, (ULONG)whdr);
661 }
662
663 wmutex->enter(VMUTEX_WAIT_FOREVER);
664 }
665 prevhdr = whdr;
666 whdr = whdr->lpNext;
667 }
668
669 if(curhdr == NULL)
670 curhdr = wavehdr;
671
672#ifdef DEBUG1
673 dprintf(("WINMM: handler cur (%d,%d), fill (%d,%d)\n", curPlayBuf, curPlayPos, curFillBuf, curFillPos));
674#endif
675
676 while(curhdr) {
677 buflength = min((ULONG)MixBuffer[curFillBuf].ulBufferLength - curPlayPos,
678 (ULONG)curhdr->dwBufferLength - curFillPos);
679 memcpy((char *)MixBuffer[curFillBuf].pBuffer + curPlayPos,
680 curhdr->lpData + curFillPos,
681 buflength);
682 curPlayPos += buflength;
683 curFillPos += buflength;
684#ifdef DEBUG1
685 dprintf(("WINMM: copied %d bytes, cufFillPos = %d, dwBufferLength = %d\n", buflength, curFillPos, curhdr->dwBufferLength));
686#endif
687 if(curFillPos == curhdr->dwBufferLength) {
688#ifdef DEBUG1
689 dprintf(("Buffer %d done\n", curFillBuf));
690#endif
691 curFillPos = 0;
692 curhdr->dwFlags |= WHDR_DONE;
693 //search for next unprocessed buffer
694 while(curhdr && curhdr->dwFlags & WHDR_DONE)
695 curhdr = curhdr->lpNext;
696 }
697 if(curPlayPos == MixBuffer[curFillBuf].ulBufferLength) {
698 curPlayPos = 0;
699 if(++curFillBuf == PREFILLBUF_DART) {
700 curFillBuf = 0;
701 }
702 if(curFillBuf == curPlayBuf)
703 break; //no more room left
704 }
705 }
706
707 if(curPlayBuf == PREFILLBUF_DART-1)
708 curPlayBuf = 0;
709 else curPlayBuf++;
710
711 wmutex->leave();
712 //Transfer buffer to DART
713 MixSetupParms->pmixWrite(MixSetupParms->ulMixHandle, &MixBuffer[curPlayBuf], 1);
714}
715/******************************************************************************/
716/******************************************************************************/
717LONG APIENTRY WaveOutHandler(ULONG ulStatus,
718 PMCI_MIX_BUFFER pBuffer,
719 ULONG ulFlags)
720{
721 // PTIB ptib;
722 // PPIB ppib;
723 // DosGetInfoBlocks(&ptib, &ppib);
724 // dprintf(("WaveOutHandler: thread %d prio %X", ptib->tib_ptib2->tib2_ultid, ptib->tib_ptib2->tib2_ulpri));
725
726 DartWaveOut *dwave;
727
728 if(pBuffer && pBuffer->ulUserParm)
729 {
730 dwave = (DartWaveOut *)pBuffer->ulUserParm;
731 dwave->handler(ulStatus, pBuffer, ulFlags);
732 }
733 return(TRUE);
734}
735
736/******************************************************************************/
737/******************************************************************************/
738MMRESULT DartWaveOut::setVolume(ULONG ulVol)
739{
740 ULONG ulVolR = (((ulVol & 0xffff0000) >> 16 )*100)/0xFFFF; // Right Volume
741 ULONG ulVolL = ((ulVol& 0x0000ffff)*100)/0xFFFF; // Left Volume
742 MCI_SET_PARMS msp = {0};
743
744 volume = ulVol;
745
746// PD: My card (ESS 1868 PnP) driver can't change only
747// one channel Left or Right :-(
748//
749#ifdef GOOD_AUDIO_CARD_DRIVER
750
751 msp.ulAudio = MCI_SET_AUDIO_LEFT;
752 msp.ulLevel = ulVolL;
753
754 mciSendCommand(DeviceId, MCI_SET,
755 MCI_WAIT | MCI_SET_AUDIO | MCI_SET_VOLUME,
756 &msp, 0);
757
758 msp.ulAudio = MCI_SET_AUDIO_RIGHT;
759 msp.ulLevel = ulVolR;
760
761#else
762 msp.ulAudio = MCI_SET_AUDIO_ALL;
763 msp.ulLevel = max(ulVolR,ulVolL);
764#endif
765
766 mciSendCommand(DeviceId, MCI_SET,
767 MCI_WAIT | MCI_SET_AUDIO | MCI_SET_VOLUME,
768 &msp, 0);
769 return 0;
770}
771/******************************************************************************/
772/******************************************************************************/
773DartWaveOut *DartWaveOut::waveout = NULL;
774
Note: See TracBrowser for help on using the repository browser.