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

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

* empty log message *

File size: 23.3 KB
Line 
1/* $Id: dwaveout.cpp,v 1.18 2000-03-04 19:55:06 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#else
338 if(pwh->dwBufferLength >= 512 && pwh->dwBufferLength <= 1024)
339 ulBufSize = pwh->dwBufferLength;
340 else ulBufSize = 1024;
341#endif
342
343 MixSetupParms->ulBufferSize = ulBufSize;
344
345 BufferParms->ulNumBuffers = PREFILLBUF_DART;
346 BufferParms->ulBufferSize = MixSetupParms->ulBufferSize;
347 BufferParms->pBufList = MixBuffer;
348
349 for(i=0;i<PREFILLBUF_DART;i++) {
350 MixBuffer[i].ulUserParm = (ULONG)this;
351 }
352
353 rc = mciSendCommand(DeviceId,
354 MCI_BUFFER,
355 MCI_WAIT | MCI_ALLOCATE_MEMORY,
356 (PVOID)BufferParms,
357 0);
358
359 if(ULONG_LOWD(rc) != MCIERR_SUCCESS) {
360 mciError(rc);
361 mciSendCommand(DeviceId, MCI_RELEASEDEVICE, MCI_WAIT,
362 (PVOID)&GenericParms, 0);
363 return(MMSYSERR_NOTSUPPORTED);
364 }
365
366 wmutex->enter(VMUTEX_WAIT_FOREVER);
367 fMixerSetup = TRUE;
368
369 curPlayBuf = curFillBuf = curFillPos = curPlayPos = 0;
370
371 for(i=0;i<PREFILLBUF_DART;i++) {
372 memset(MixBuffer[i].pBuffer, 0, MixBuffer[i].ulBufferLength);
373 }
374 dprintf(("Dart opened, bufsize = %d\n", MixBuffer[i].ulBufferLength));
375
376 wavehdr = pwh;
377 curhdr = pwh;
378 pwh->lpNext = NULL;
379
380 while(TRUE) {
381 buflength = min((ULONG)MixBuffer[curFillBuf].ulBufferLength - curPlayPos,
382 (ULONG)wavehdr->dwBufferLength - curFillPos);
383 dprintf(("Copying %d data; curPlayPos = %d curFillPos = %d\n", buflength, curPlayPos, curFillPos));
384
385 memcpy((char *)MixBuffer[curFillBuf].pBuffer + curPlayPos,
386 wavehdr->lpData + curFillPos,
387 buflength);
388
389 curPlayPos += buflength;
390 curFillPos += buflength;
391 if(curFillPos == wavehdr->dwBufferLength) {
392 dprintf(("Processed first win32 buffer\n"));
393 curFillPos = 0;
394 wavehdr->dwFlags |= WHDR_DONE;
395 curhdr = NULL;
396 }
397 if(curPlayPos == MixBuffer[curPlayBuf].ulBufferLength) {
398 if(++curPlayBuf == PREFILLBUF_DART) {
399 curPlayBuf = 0;
400 break;
401 }
402 curPlayPos = 0;
403 }
404 if(curFillPos == 0)
405 break;
406 }
407 dprintf(("MixSetupParms = %X\n", MixSetupParms));
408 State = STATE_PLAYING;
409 wmutex->leave();
410
411 MixSetupParms->pmixWrite(MixSetupParms->ulMixHandle,
412 MixBuffer,
413 PREFILLBUF_DART);
414 dprintf(("Dart playing\n"));
415 }
416 else
417 {
418 wmutex->enter(VMUTEX_WAIT_FOREVER);
419 pwh->lpNext = NULL;
420 if(wavehdr) {
421 WAVEHDR *chdr = wavehdr;
422 while(chdr->lpNext) {
423 chdr = chdr->lpNext;
424 }
425 chdr->lpNext = pwh;
426 }
427 else wavehdr = pwh;
428 wmutex->leave();
429 if(State != STATE_PLAYING) {//continue playback
430 restart();
431 }
432 }
433
434 return(MMSYSERR_NOERROR);
435}
436/******************************************************************************/
437/******************************************************************************/
438MMRESULT DartWaveOut::pause()
439{
440 MCI_GENERIC_PARMS Params;
441
442 if(State != STATE_PLAYING)
443 return(MMSYSERR_NOERROR);
444
445 wmutex->enter(VMUTEX_WAIT_FOREVER);
446 State = STATE_PAUSED;
447 wmutex->leave();
448
449 memset(&Params, 0, sizeof(Params));
450
451 // Stop the playback.
452 mciSendCommand(DeviceId, MCI_PAUSE, MCI_WAIT, (PVOID)&Params, 0);
453
454 return(MMSYSERR_NOERROR);
455}
456/******************************************************************************/
457/******************************************************************************/
458MMRESULT DartWaveOut::reset()
459{
460 MCI_GENERIC_PARMS Params;
461
462 dprintf(("DartWaveOut::reset %s", (State == STATE_PLAYING) ? "playing" : "stopped"));
463 if(State != STATE_PLAYING)
464 return(MMSYSERR_HANDLEBUSY);
465
466 memset(&Params, 0, sizeof(Params));
467
468 // Stop the playback.
469 mciSendCommand(DeviceId, MCI_STOP, MCI_WAIT, (PVOID)&Params, 0);
470
471 dprintf(("Nr of threads blocked on mutex = %d\n", wmutex->getNrBlocked()));
472
473 wmutex->enter(VMUTEX_WAIT_FOREVER);
474 while(wavehdr) {
475 wavehdr->dwFlags |= WHDR_DONE;
476 wmutex->leave();
477 if(mthdCallback) {
478 callback((ULONG)this, WOM_DONE, dwInstance, wavehdr->dwUser, (ULONG)wavehdr);
479 }
480 else {
481 if(hwndCallback)
482 PostMessageA(hwndCallback, WOM_DONE, wavehdr->dwUser, (ULONG)wavehdr);
483 }
484 wmutex->enter(VMUTEX_WAIT_FOREVER);
485 wavehdr = wavehdr->lpNext;
486 }
487 wavehdr = NULL;
488 State = STATE_STOPPED;
489
490 wmutex->leave();
491 return(MMSYSERR_NOERROR);
492}
493/******************************************************************************/
494/******************************************************************************/
495MMRESULT DartWaveOut::restart()
496{
497 dprintf(("DartWaveOut::restart"));
498 wmutex->enter(VMUTEX_WAIT_FOREVER);
499 State = STATE_PLAYING;
500 wmutex->leave();
501 MixSetupParms->pmixWrite(MixSetupParms->ulMixHandle,
502 &MixBuffer[curPlayBuf],
503 PREFILLBUF_DART);
504 return(MMSYSERR_NOERROR);
505}
506/******************************************************************************/
507/******************************************************************************/
508ULONG DartWaveOut::getPosition()
509{
510 MCI_STATUS_PARMS mciStatus = {0};
511 ULONG rc, nrbytes;
512
513 if(State != STATE_PLAYING)
514 return 0;
515
516 mciStatus.ulItem = MCI_STATUS_POSITION;
517 rc = mciSendCommand(DeviceId, MCI_STATUS, MCI_STATUS_ITEM|MCI_WAIT, (PVOID)&mciStatus, 0);
518 if((rc & 0xFFFF) == MCIERR_SUCCESS) {
519 nrbytes = (mciStatus.ulReturn * (getAvgBytesPerSecond()/1000));
520 return nrbytes;;
521 }
522 mciError(rc);
523 return 0xFFFFFFFF;
524}
525/******************************************************************************/
526/******************************************************************************/
527BOOL DartWaveOut::queryFormat(ULONG formatTag, ULONG nChannels,
528 ULONG nSamplesPerSec, ULONG wBitsPerSample)
529{
530 MCI_WAVE_GETDEVCAPS_PARMS mciAudioCaps;
531 MCI_GENERIC_PARMS GenericParms;
532 MCI_OPEN_PARMS mciOpenParms; /* open parms for MCI_OPEN */
533 int i, freqbits = 0;
534 ULONG rc, DeviceId;
535 BOOL winrc;
536
537 dprintf(("DartWaveOut::queryFormat %x srate=%d, nchan=%d, bps=%d", formatTag, nSamplesPerSec, nChannels, wBitsPerSample));
538
539 memset(&mciOpenParms, /* Object to fill with zeros. */
540 0, /* Value to place into the object. */
541 sizeof( mciOpenParms ) ); /* How many zero's to use. */
542
543 mciOpenParms.pszDeviceType = (PSZ)MCI_DEVTYPE_WAVEFORM_AUDIO;
544
545 rc = mciSendCommand( (USHORT) 0,
546 MCI_OPEN,
547 MCI_WAIT | MCI_OPEN_TYPE_ID,
548 (PVOID) &mciOpenParms,
549 0);
550 if (rc != 0) {
551 return(FALSE);
552 }
553 DeviceId = mciOpenParms.usDeviceID;
554
555 memset( &mciAudioCaps , 0, sizeof(MCI_WAVE_GETDEVCAPS_PARMS));
556
557 mciAudioCaps.ulBitsPerSample = wBitsPerSample;
558 mciAudioCaps.ulFormatTag = DATATYPE_WAVEFORM;
559 mciAudioCaps.ulSamplesPerSec = nSamplesPerSec;
560 mciAudioCaps.ulChannels = nChannels;
561 mciAudioCaps.ulFormatMode = MCI_PLAY;
562 mciAudioCaps.ulItem = MCI_GETDEVCAPS_WAVE_FORMAT;
563
564 rc = mciSendCommand(DeviceId, /* Device ID */
565 MCI_GETDEVCAPS,
566 MCI_WAIT | MCI_GETDEVCAPS_EXTENDED | MCI_GETDEVCAPS_ITEM,
567 (PVOID) &mciAudioCaps,
568 0);
569 if((rc & 0xFFFF) != MCIERR_SUCCESS) {
570 mciError(rc);
571 winrc = FALSE;
572 }
573 else winrc = TRUE;
574
575 // Close the device
576 mciSendCommand(DeviceId,MCI_CLOSE,MCI_WAIT,(PVOID)&GenericParms,0);
577 return(winrc);
578}
579/******************************************************************************/
580/******************************************************************************/
581void DartWaveOut::mciError(ULONG ulError)
582{
583#ifdef DEBUG
584 char szError[256] = "";
585
586 mciGetErrorString(ulError, szError, sizeof(szError));
587 dprintf(("WINMM: DartWaveOut: %s\n", szError));
588#endif
589}
590//******************************************************************************
591//******************************************************************************
592BOOL DartWaveOut::find(DartWaveOut *dwave)
593{
594 DartWaveOut *curwave = waveout;
595
596 while(curwave) {
597 if(dwave == curwave) {
598 return(TRUE);
599 }
600 curwave = curwave->next;
601 }
602
603#ifdef DEBUG
604// WriteLog("WINMM:DartWaveOut not found!\n");
605#endif
606 return(FALSE);
607}
608/******************************************************************************/
609/******************************************************************************/
610void DartWaveOut::handler(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags)
611{
612 ULONG buflength;
613 WAVEHDR *whdr = wavehdr, *prevhdr = NULL;
614
615#ifdef DEBUG1
616 dprintf(("WINMM: handler %d\n", curPlayBuf));
617#endif
618 if(ulFlags == MIX_STREAM_ERROR) {
619 if(ulStatus == ERROR_DEVICE_UNDERRUN) {
620 dprintf(("WINMM: WaveOut handler UNDERRUN!\n"));
621 pause(); //out of buffers, so pause playback
622 return;
623 }
624 dprintf(("WINMM: WaveOut handler, Unknown error %X\n", ulStatus));
625 return;
626 }
627 wmutex->enter(VMUTEX_WAIT_FOREVER);
628
629 while(whdr) {
630 if(whdr->dwFlags & WHDR_DONE) {
631#ifdef DEBUG1
632 dprintf(("WINMM: handler buf %X done\n", whdr));
633#endif
634 whdr->dwFlags &= ~WHDR_INQUEUE;
635
636 if(prevhdr == NULL)
637 wavehdr = whdr->lpNext;
638 else prevhdr->lpNext = whdr->lpNext;
639
640 whdr->lpNext = NULL;
641 wmutex->leave();
642
643 if(mthdCallback) {
644 callback((ULONG)this, WOM_DONE, dwInstance, whdr->dwUser, (ULONG)whdr);
645 }
646 else
647 if(hwndCallback)
648 PostMessageA(hwndCallback, WOM_DONE, whdr->dwUser, (ULONG)whdr);
649
650 wmutex->enter(VMUTEX_WAIT_FOREVER);
651 }
652 prevhdr = whdr;
653 whdr = whdr->lpNext;
654 }
655
656 if(curhdr == NULL)
657 curhdr = wavehdr;
658
659#ifdef DEBUG1
660 dprintf(("WINMM: handler cur (%d,%d), fill (%d,%d)\n", curPlayBuf, curPlayPos, curFillBuf, curFillPos));
661#endif
662
663 while(curhdr) {
664 buflength = min((ULONG)MixBuffer[curFillBuf].ulBufferLength - curPlayPos,
665 (ULONG)curhdr->dwBufferLength - curFillPos);
666 memcpy((char *)MixBuffer[curFillBuf].pBuffer + curPlayPos,
667 curhdr->lpData + curFillPos,
668 buflength);
669 curPlayPos += buflength;
670 curFillPos += buflength;
671#ifdef DEBUG1
672 dprintf(("WINMM: copied %d bytes, cufFillPos = %d, dwBufferLength = %d\n", buflength, curFillPos, curhdr->dwBufferLength));
673#endif
674 if(curFillPos == curhdr->dwBufferLength) {
675#ifdef DEBUG1
676 dprintf(("Buffer %d done\n", curFillBuf));
677#endif
678 curFillPos = 0;
679 curhdr->dwFlags |= WHDR_DONE;
680 //search for next unprocessed buffer
681 while(curhdr && curhdr->dwFlags & WHDR_DONE)
682 curhdr = curhdr->lpNext;
683 }
684 if(curPlayPos == MixBuffer[curFillBuf].ulBufferLength) {
685 curPlayPos = 0;
686 if(++curFillBuf == PREFILLBUF_DART) {
687 curFillBuf = 0;
688 }
689 if(curFillBuf == curPlayBuf)
690 break; //no more room left
691 }
692 }
693
694 if(curPlayBuf == PREFILLBUF_DART-1)
695 curPlayBuf = 0;
696 else curPlayBuf++;
697
698 wmutex->leave();
699 //Transfer buffer to DART
700 MixSetupParms->pmixWrite(MixSetupParms->ulMixHandle, &MixBuffer[curPlayBuf], 1);
701}
702/******************************************************************************/
703/******************************************************************************/
704LONG APIENTRY WaveOutHandler(ULONG ulStatus,
705 PMCI_MIX_BUFFER pBuffer,
706 ULONG ulFlags)
707{
708 // PTIB ptib;
709 // PPIB ppib;
710 // DosGetInfoBlocks(&ptib, &ppib);
711 // dprintf(("WaveOutHandler: thread %d prio %X", ptib->tib_ptib2->tib2_ultid, ptib->tib_ptib2->tib2_ulpri));
712
713 DartWaveOut *dwave;
714
715 if(pBuffer && pBuffer->ulUserParm)
716 {
717 dwave = (DartWaveOut *)pBuffer->ulUserParm;
718 dwave->handler(ulStatus, pBuffer, ulFlags);
719 }
720 return(TRUE);
721}
722
723/******************************************************************************/
724/******************************************************************************/
725MMRESULT DartWaveOut::setVolume(ULONG ulVol)
726{
727 ULONG ulVolR = (((ulVol & 0xffff0000) >> 16 )*100)/0xFFFF; // Right Volume
728 ULONG ulVolL = ((ulVol& 0x0000ffff)*100)/0xFFFF; // Left Volume
729 MCI_SET_PARMS msp = {0};
730
731 volume = ulVol;
732
733// PD: My card (ESS 1868 PnP) driver can't change only
734// one channel Left or Right :-(
735//
736#ifdef GOOD_AUDIO_CARD_DRIVER
737
738 msp.ulAudio = MCI_SET_AUDIO_LEFT;
739 msp.ulLevel = ulVolL;
740
741 mciSendCommand(DeviceId, MCI_SET,
742 MCI_WAIT | MCI_SET_AUDIO | MCI_SET_VOLUME,
743 &msp, 0);
744
745 msp.ulAudio = MCI_SET_AUDIO_RIGHT;
746 msp.ulLevel = ulVolR;
747
748#else
749 msp.ulAudio = MCI_SET_AUDIO_ALL;
750 msp.ulLevel = max(ulVolR,ulVolL);
751#endif
752
753 mciSendCommand(DeviceId, MCI_SET,
754 MCI_WAIT | MCI_SET_AUDIO | MCI_SET_VOLUME,
755 &msp, 0);
756 return 0;
757}
758/******************************************************************************/
759/******************************************************************************/
760DartWaveOut *DartWaveOut::waveout = NULL;
761
Note: See TracBrowser for help on using the repository browser.