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

Last change on this file since 2286 was 2286, checked in by sandervl, 26 years ago

PD: implemented waveOutGet/SetVolume

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