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

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

Implemented waveOutGetPosition

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