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

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

Added new logging feature + fixed waveout query format bug

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