source: trunk/src/winmm/waveoutdart.cpp@ 9907

Last change on this file since 9907 was 9907, checked in by sandervl, 22 years ago

Don't pause the wave stream if no buffers left to add. Let DART detect the underrun condition.

File size: 24.6 KB
Line 
1/* $Id: waveoutdart.cpp,v 1.18 2003-03-05 16:45:10 sandervl Exp $ */
2
3/*
4 * Wave playback class (DART)
5 *
6 * Copyright 1998-2001 Sander van Leeuwen (sandervl@xs4all.nl)
7 *
8 *
9 * Project Odin Software License can be found in LICENSE.TXT
10 *
11 * Note:
12 * 2000/11/24 PH MCI_MIXSETUP_PARMS->pMixWrite does alter FS: selector!
13 * TODO: mulaw, alaw & adpcm
14 *
15 */
16
17
18/****************************************************************************
19 * Includes *
20 ****************************************************************************/
21
22
23
24#define INCL_BASE
25#define INCL_OS2MM
26#define INCL_DOSPROCESS
27#include <os2wrap.h> //Odin32 OS/2 api wrappers
28#include <os2mewrap.h> //Odin32 OS/2 MMPM/2 api wrappers
29#include <stdlib.h>
30#include <stddef.h>
31#include <string.h>
32#define OS2_ONLY
33#include <win32api.h>
34#include <wprocess.h>
35
36#include "misc.h"
37#include "waveoutdart.h"
38#include "initwinmm.h"
39
40#define DBG_LOCALLOG DBG_waveoutdart
41#include "dbglocal.h"
42
43#ifndef min
44#define min(a, b) ((a > b) ? b : a)
45#endif
46
47#ifndef max
48#define max(a, b) ((a > b) ? a : b)
49#endif
50
51LONG APIENTRY WaveOutHandler(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags);
52
53static BOOL fFixedWaveBufferSize = FALSE;
54
55//******************************************************************************
56// ODIN_waveOutSetFixedBuffers
57//
58// Tell WINMM to use DART buffers of the same size as the first buffer delivered
59// by waveOutWrite
60//
61// NOTE: This will only work in very specific cases; it is not a good general
62// purpose solution.
63//
64//******************************************************************************
65void WIN32API ODIN_waveOutSetFixedBuffers()
66{
67 fFixedWaveBufferSize = TRUE;
68}
69/******************************************************************************/
70/******************************************************************************/
71DartWaveOut::DartWaveOut(LPWAVEFORMATEX pwfx, ULONG fdwOpen, ULONG nCallback, ULONG dwInstance)
72 : WaveOut(pwfx, fdwOpen, nCallback, dwInstance)
73{
74 MCI_GENERIC_PARMS GenericParms;
75 MCI_AMP_OPEN_PARMS AmpOpenParms;
76 APIRET rc;
77
78 curPlayBuf = curFillBuf = curFillPos = curPlayPos = 0;
79 fMixerSetup = FALSE;
80 fUnderrun = FALSE;
81
82 ulBufSize = DART_BUFSIZE;
83
84 MixBuffer = (MCI_MIX_BUFFER *)malloc(PREFILLBUF_DART*sizeof(MCI_MIX_BUFFER));
85 MixSetupParms = (MCI_MIXSETUP_PARMS *)malloc(sizeof(MCI_MIXSETUP_PARMS));
86 BufferParms = (MCI_BUFFER_PARMS *)malloc(sizeof(MCI_BUFFER_PARMS));
87 if(!MixBuffer || !MixSetupParms || !BufferParms) {
88 dprintf(("ERROR: malloc failed!!"));
89 ulError = MMSYSERR_NOMEM;
90 return;
91 }
92
93 // Setup the open structure, pass the playlist and tell MCI_OPEN to use it
94 memset(&AmpOpenParms,0,sizeof(AmpOpenParms));
95
96 AmpOpenParms.usDeviceID = ( USHORT ) 0;
97 AmpOpenParms.pszDeviceType = ( PSZ ) MCI_DEVTYPE_AUDIO_AMPMIX;
98
99 rc = mymciSendCommand(0, MCI_OPEN, MCI_WAIT | MCI_OPEN_TYPE_ID | MCI_OPEN_SHAREABLE,
100 (PVOID) &AmpOpenParms, 0);
101
102 DeviceId = AmpOpenParms.usDeviceID;
103 if(rc) {
104 dprintf(("MCI_OPEN failed\n"));
105 mciError(rc);
106 ulError = MMSYSERR_NODRIVER;
107 }
108 if(rc == 0) {
109 //Grab exclusive rights to device instance (NOT entire device)
110 GenericParms.hwndCallback = 0; //Not needed, so set to 0
111 rc = mymciSendCommand(DeviceId, MCI_ACQUIREDEVICE, MCI_EXCLUSIVE_INSTANCE,
112 (PVOID)&GenericParms, 0);
113 if(rc) {
114 dprintf(("MCI_ACQUIREDEVICE failed\n"));
115 mciError(rc);
116 ulError = MMSYSERR_NOTENABLED;
117 }
118 }
119 setVolume(volume);
120
121 if(!ulError)
122 callback(WOM_OPEN, 0, 0);
123}
124/******************************************************************************/
125/******************************************************************************/
126DartWaveOut::~DartWaveOut()
127{
128 MCI_GENERIC_PARMS GenericParms;
129
130 State = STATE_STOPPED;
131
132 if(!ulError) {
133 // Generic parameters
134 GenericParms.hwndCallback = 0; //hwndFrame
135
136 // Stop the playback.
137 mymciSendCommand(DeviceId, MCI_STOP,MCI_WAIT, (PVOID)&GenericParms,0);
138
139 mymciSendCommand(DeviceId, MCI_BUFFER,
140 MCI_WAIT | MCI_DEALLOCATE_MEMORY,
141 (PVOID)&BufferParms, 0);
142
143 // Generic parameters
144 GenericParms.hwndCallback = 0; //hwndFrame
145
146 // Close the device
147 mymciSendCommand(DeviceId, MCI_CLOSE, MCI_WAIT, (PVOID)&GenericParms, 0);
148 }
149
150 if(!ulError)
151 {
152 callback(WOM_CLOSE, 0, 0);
153 }
154
155 if(MixBuffer)
156 free(MixBuffer);
157 if(MixSetupParms)
158 free(MixSetupParms);
159 if(BufferParms)
160 free(BufferParms);
161}
162/******************************************************************************/
163/******************************************************************************/
164MMRESULT DartWaveOut::write(LPWAVEHDR pwh, UINT cbwh)
165{
166 MCI_GENERIC_PARMS GenericParms = {0};
167 APIRET rc;
168 int i, buflength;
169
170 queuedbuffers++;
171 if(fMixerSetup == FALSE)
172 {
173 dprintf(("device acquired\n"));
174 /* Set the MixSetupParms data structure to match the loaded file.
175 * This is a global that is used to setup the mixer.
176 */
177 memset(MixSetupParms, 0, sizeof( MCI_MIXSETUP_PARMS ) );
178
179 MixSetupParms->ulBitsPerSample = BitsPerSample;
180 MixSetupParms->ulSamplesPerSec = SampleRate;
181 MixSetupParms->ulFormatTag = MCI_WAVE_FORMAT_PCM;
182 MixSetupParms->ulChannels = nChannels;
183
184 dprintf(("bps %d, sps %d chan %d\n", BitsPerSample, SampleRate, nChannels));
185
186 /* Setup the mixer for playback of wave data
187 */
188 MixSetupParms->ulFormatMode = MCI_PLAY;
189 MixSetupParms->ulDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO;
190 MixSetupParms->pmixEvent = WaveOutHandler;
191
192 rc = mymciSendCommand(DeviceId,
193 MCI_MIXSETUP,
194 MCI_WAIT | MCI_MIXSETUP_INIT,
195 (PVOID)MixSetupParms,
196 0);
197
198 if ( rc != MCIERR_SUCCESS ) {
199 mciError(rc);
200 mymciSendCommand(DeviceId, MCI_RELEASEDEVICE, MCI_WAIT,
201 (PVOID)&GenericParms, 0);
202 return(MMSYSERR_NOTSUPPORTED);
203 }
204
205 /*
206 * Set up the BufferParms data structure and allocate
207 * device buffers from the Amp-Mixer
208 */
209 dprintf(("mix setup %d, %d\n", pwh->dwBufferLength, pwh->dwBufferLength));
210
211#if 1
212 if(fFixedWaveBufferSize == FALSE)
213 {//by default we need to select a small enough buffer to be able to
214 //signal buffer completion in time
215 int consumerate = getAvgBytesPerSecond();
216 int minbufsize = consumerate/32;
217
218 ulBufSize = pwh->dwBufferLength/2;
219 if(ulBufSize > minbufsize) {
220 dprintf(("set buffer size to %d bytes (org size = %d)", minbufsize, pwh->dwBufferLength));
221 ulBufSize = minbufsize;
222 }
223 }
224 else ulBufSize = pwh->dwBufferLength;
225#else
226 if(pwh->dwBufferLength >= 512 && pwh->dwBufferLength <= 1024)
227 ulBufSize = pwh->dwBufferLength;
228 else ulBufSize = 1024;
229#endif
230 MixSetupParms->ulBufferSize = ulBufSize;
231
232 BufferParms->ulNumBuffers = PREFILLBUF_DART;
233 BufferParms->ulBufferSize = MixSetupParms->ulBufferSize;
234 BufferParms->pBufList = MixBuffer;
235
236 for(i=0;i<PREFILLBUF_DART;i++) {
237 MixBuffer[i].ulUserParm = (ULONG)this;
238 }
239
240 rc = mymciSendCommand(DeviceId,
241 MCI_BUFFER,
242 MCI_WAIT | MCI_ALLOCATE_MEMORY,
243 (PVOID)BufferParms,
244 0);
245
246 if(ULONG_LOWD(rc) != MCIERR_SUCCESS) {
247 mciError(rc);
248 mymciSendCommand(DeviceId, MCI_RELEASEDEVICE, MCI_WAIT,
249 (PVOID)&GenericParms, 0);
250 return(MMSYSERR_NOTSUPPORTED);
251 }
252
253 wmutex.enter();
254 fMixerSetup = TRUE;
255
256 curPlayBuf = curFillBuf = curFillPos = curPlayPos = 0;
257 bytesPlayed = bytesCopied = bytesReturned = 0;
258
259 for(i=0;i<PREFILLBUF_DART;i++) {
260 memset(MixBuffer[i].pBuffer, 0, MixBuffer[i].ulBufferLength);
261 }
262 dprintf(("Dart opened, bufsize = %d\n", MixBuffer[0].ulBufferLength));
263
264 wavehdr = pwh;
265 curhdr = pwh;
266 pwh->lpNext = NULL;
267 pwh->reserved = 0;
268
269 if(State != STATE_STOPPED) {//don't start playback if paused
270 wmutex.leave();
271 return(MMSYSERR_NOERROR);
272 }
273
274 writeBuffer(); //must be called before (re)starting playback
275
276 dprintf(("MixSetupParms = %X\n", MixSetupParms));
277 State = STATE_PLAYING;
278 fUnderrun = FALSE;
279 wmutex.leave();
280
281 //write buffers to DART; starts playback
282 dprintf(("WINMM: transfer all buffers to DART"));
283 USHORT selTIB = RestoreOS2FS(); // save current FS selector
284
285 MixSetupParms->pmixWrite(MixSetupParms->ulMixHandle,
286 MixBuffer,
287 PREFILLBUF_DART);
288 SetFS(selTIB); // switch back to the saved FS selector
289 dprintf(("Dart playing\n"));
290 }
291 else
292 {
293 pwh->lpNext = NULL;
294 pwh->reserved = 0;
295 wmutex.enter();
296 if(wavehdr) {
297 WAVEHDR *chdr = wavehdr;
298 while(chdr->lpNext) {
299 chdr = chdr->lpNext;
300 }
301 chdr->lpNext = pwh;
302 }
303 else wavehdr = pwh;
304
305 if(!fUnderrun && State != STATE_STOPPED) {//don't start playback if paused
306 //write new data to the DART buffers (if there's any room left)
307 if(State == STATE_PLAYING) {
308 writeBuffer(); //must be called before (re)starting playback
309 }
310 wmutex.leave();
311 return(MMSYSERR_NOERROR);
312 }
313 writeBuffer(); //must be called before (re)starting playback
314 State = STATE_PLAYING;
315 fUnderrun = FALSE;
316 wmutex.leave();
317
318 //write buffers to DART; starts playback
319 dprintf(("WINMM: transfer all buffers to DART"));
320 USHORT selTIB = RestoreOS2FS(); // save current FS selector
321
322 MixSetupParms->pmixWrite(MixSetupParms->ulMixHandle,
323 MixBuffer,
324 PREFILLBUF_DART);
325 SetFS(selTIB); // switch back to the saved FS selector
326
327 dprintf(("Dart playing\n"));
328 }
329 return(MMSYSERR_NOERROR);
330}
331/******************************************************************************/
332/******************************************************************************/
333MMRESULT DartWaveOut::pause()
334{
335 MCI_GENERIC_PARMS Params;
336
337 dprintf(("WINMM: DartWaveOut::pause"));
338
339 wmutex.enter();
340 if(State != STATE_PLAYING) {
341 State = STATE_PAUSED;
342 wmutex.leave();
343 return(MMSYSERR_NOERROR);
344 }
345
346 State = STATE_PAUSED;
347 wmutex.leave();
348
349 memset(&Params, 0, sizeof(Params));
350
351 // Pause playback.
352 mymciSendCommand(DeviceId, MCI_PAUSE, MCI_WAIT, (PVOID)&Params, 0);
353
354 return(MMSYSERR_NOERROR);
355}
356/******************************************************************************/
357/******************************************************************************/
358MMRESULT DartWaveOut::resume()
359{
360 MCI_GENERIC_PARMS Params;
361 int i, curbuf;
362
363 dprintf(("DartWaveOut::resume"));
364
365 wmutex.enter();
366 if(State != STATE_PAUSED) {
367 wmutex.leave();
368 return(MMSYSERR_NOERROR);
369 }
370 State = STATE_PLAYING;
371 wmutex.leave();
372
373 //Only write buffers to dart if mixer has been initialized; if not, then
374 //the first buffer write will do this for us.
375 if(fMixerSetup == TRUE)
376 {
377 wmutex.enter();
378 State = STATE_PLAYING;
379 fUnderrun = FALSE;
380 curbuf = curPlayBuf;
381 writeBuffer(); //must be called before (re)starting playback
382 wmutex.leave();
383
384 // MCI_MIXSETUP_PARMS->pMixWrite does alter FS: selector!
385 USHORT selTIB = GetFS(); // save current FS selector
386
387 for(i=0;i<PREFILLBUF_DART;i++)
388 {
389 dprintf(("restart: write buffer at %x size %d", MixBuffer[curbuf].pBuffer, MixBuffer[curbuf].ulBufferLength));
390 MixSetupParms->pmixWrite(MixSetupParms->ulMixHandle, &MixBuffer[curbuf], 1);
391 if(++curbuf == PREFILLBUF_DART)
392 curbuf = 0;
393 }
394 SetFS(selTIB); // switch back to the saved FS selector
395 }
396 return(MMSYSERR_NOERROR);
397}
398/******************************************************************************/
399/******************************************************************************/
400MMRESULT DartWaveOut::stop()
401{
402 MCI_GENERIC_PARMS Params;
403
404 dprintf(("DartWaveOut::stop %s", (State == STATE_PLAYING) ? "playing" : "stopped"));
405 if(State != STATE_PLAYING)
406 return(MMSYSERR_HANDLEBUSY);
407
408 memset(&Params, 0, sizeof(Params));
409
410 // Stop the playback.
411 mymciSendCommand(DeviceId, MCI_STOP, MCI_WAIT, (PVOID)&Params, 0);
412
413 State = STATE_STOPPED;
414 fUnderrun = FALSE;
415
416 curPlayBuf = curFillBuf = curFillPos = curPlayPos = 0;
417 bytesPlayed = bytesCopied = bytesReturned = 0;
418
419 return(MMSYSERR_NOERROR);
420}
421/******************************************************************************/
422/******************************************************************************/
423MMRESULT DartWaveOut::reset()
424{
425 MCI_GENERIC_PARMS Params;
426 LPWAVEHDR tmpwavehdr;
427
428 dprintf(("DartWaveOut::reset %s", (State == STATE_PLAYING) ? "playing" : "stopped"));
429 if(State != STATE_PLAYING)
430 return(MMSYSERR_HANDLEBUSY);
431
432 memset(&Params, 0, sizeof(Params));
433
434 wmutex.enter();
435 State = STATE_STOPPED;
436 wmutex.leave();
437
438 // Stop the playback.
439 mymciSendCommand(DeviceId, MCI_STOP, MCI_WAIT, (PVOID)&Params, 0);
440
441 wmutex.enter();
442 while(wavehdr)
443 {
444 wavehdr->dwFlags |= WHDR_DONE;
445 wavehdr->dwFlags &= ~WHDR_INQUEUE;
446 wavehdr->reserved = 0;
447 tmpwavehdr = wavehdr;
448 wavehdr = wavehdr->lpNext;
449 tmpwavehdr->lpNext = NULL;
450 wmutex.leave();
451
452 callback(WOM_DONE, (ULONG)tmpwavehdr, 0);
453 wmutex.enter();
454 }
455 wavehdr = NULL;
456 fUnderrun = FALSE;
457
458 curPlayBuf = curFillBuf = curFillPos = curPlayPos = 0;
459 bytesPlayed = bytesCopied = bytesReturned = 0;
460 queuedbuffers = 0;
461
462 wmutex.leave();
463 return(MMSYSERR_NOERROR);
464}
465/******************************************************************************/
466/******************************************************************************/
467ULONG DartWaveOut::getPosition()
468{
469 MCI_STATUS_PARMS mciStatus = {0};
470 ULONG rc, nrbytes;
471
472 if(State == STATE_STOPPED) {
473 dprintf(("Not playing; return 0 position"));
474 return 0;
475 }
476
477 mciStatus.ulItem = MCI_STATUS_POSITION;
478 rc = mymciSendCommand(DeviceId, MCI_STATUS, MCI_STATUS_ITEM|MCI_WAIT, (PVOID)&mciStatus, 0);
479 if((rc & 0xFFFF) == MCIERR_SUCCESS) {
480 nrbytes = (mciStatus.ulReturn * (getAvgBytesPerSecond()/1000));
481 return nrbytes;;
482 }
483 mciError(rc);
484 return 0xFFFFFFFF;
485}
486/******************************************************************************/
487/******************************************************************************/
488BOOL DartWaveOut::queryFormat(ULONG formatTag, ULONG nChannels,
489 ULONG nSamplesPerSec, ULONG wBitsPerSample)
490{
491 MCI_WAVE_GETDEVCAPS_PARMS mciAudioCaps;
492 MCI_GENERIC_PARMS GenericParms;
493 MCI_OPEN_PARMS mciOpenParms; /* open parms for MCI_OPEN */
494 int i, freqbits = 0;
495 ULONG rc, DeviceId;
496 BOOL winrc;
497
498 dprintf(("DartWaveOut::queryFormat %x srate=%d, nchan=%d, bps=%d", formatTag, nSamplesPerSec, nChannels, wBitsPerSample));
499
500 memset(&mciOpenParms, /* Object to fill with zeros. */
501 0, /* Value to place into the object. */
502 sizeof( mciOpenParms ) ); /* How many zero's to use. */
503
504 mciOpenParms.pszDeviceType = (PSZ)MCI_DEVTYPE_WAVEFORM_AUDIO;
505
506 rc = mymciSendCommand( (USHORT) 0,
507 MCI_OPEN,
508 MCI_WAIT | MCI_OPEN_TYPE_ID,
509 (PVOID) &mciOpenParms,
510 0);
511 if((rc & 0xFFFF) != MCIERR_SUCCESS) {
512 mciError(rc);
513 return(FALSE);
514 }
515 DeviceId = mciOpenParms.usDeviceID;
516
517 memset( &mciAudioCaps , 0, sizeof(MCI_WAVE_GETDEVCAPS_PARMS));
518
519 mciAudioCaps.ulBitsPerSample = wBitsPerSample;
520 mciAudioCaps.ulFormatTag = DATATYPE_WAVEFORM;
521 mciAudioCaps.ulSamplesPerSec = nSamplesPerSec;
522 mciAudioCaps.ulChannels = nChannels;
523 mciAudioCaps.ulFormatMode = MCI_PLAY;
524 mciAudioCaps.ulItem = MCI_GETDEVCAPS_WAVE_FORMAT;
525
526 rc = mymciSendCommand(DeviceId, /* Device ID */
527 MCI_GETDEVCAPS,
528 MCI_WAIT | MCI_GETDEVCAPS_EXTENDED | MCI_GETDEVCAPS_ITEM,
529 (PVOID) &mciAudioCaps,
530 0);
531 if((rc & 0xFFFF) != MCIERR_SUCCESS) {
532 mciError(rc);
533 winrc = FALSE;
534 }
535 else winrc = TRUE;
536
537 // Close the device
538 mymciSendCommand(DeviceId,MCI_CLOSE,MCI_WAIT,(PVOID)&GenericParms,0);
539 return(winrc);
540}
541/******************************************************************************/
542/******************************************************************************/
543void DartWaveOut::mciError(ULONG ulError)
544{
545#ifdef DEBUG
546 char szError[256] = "";
547
548 mymciGetErrorString(ulError, szError, sizeof(szError));
549 dprintf(("WINMM: DartWaveOut: %s\n", szError));
550#endif
551}
552//******************************************************************************
553//******************************************************************************
554void DartWaveOut::handler(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags)
555{
556 ULONG buflength;
557 WAVEHDR *whdr, *prevhdr = NULL;
558
559 dprintf2(("WINMM: handler %d; buffers left %d", curPlayBuf, queuedbuffers));
560 if(ulFlags == MIX_STREAM_ERROR) {
561 if(ulStatus == ERROR_DEVICE_UNDERRUN) {
562 dprintf(("WINMM: WaveOut handler UNDERRUN! state %s", (State == STATE_PLAYING) ? "playing" : "stopped"));
563 if(State == STATE_PLAYING) {
564 fUnderrun = TRUE;
565 stop(); //out of buffers, so stop playback
566 }
567 return;
568 }
569 dprintf(("WINMM: WaveOut handler, Unknown error %X\n", ulStatus));
570 return;
571 }
572 if(State != STATE_PLAYING) {
573 return;
574 }
575
576 wmutex.enter();
577
578 bytesPlayed += MixBuffer[curPlayBuf].ulBufferLength;
579
580 //update our buffer index
581 if(curPlayBuf == PREFILLBUF_DART-1)
582 curPlayBuf = 0;
583 else curPlayBuf++;
584
585 fUnderrun = FALSE;
586
587 whdr = wavehdr;
588 while(whdr) {
589 if(whdr->reserved == WHDR_DONE)
590 {
591 if(bytesPlayed < bytesReturned + whdr->dwBufferLength) {
592 dprintf2(("Buffer marked done, but not yet played completely (play %d/%d, cop %d, ret %d)", bytesPlayed, getPosition(), bytesCopied, bytesReturned));
593 break; //not yet done
594 }
595
596 dprintf2(("WINMM: handler buf %X done (play %d/%d, cop %d, ret %d)", whdr, bytesPlayed, getPosition(), bytesCopied, bytesReturned));
597 queuedbuffers--;
598
599 whdr->dwFlags &= ~WHDR_INQUEUE;
600 whdr->dwFlags |= WHDR_DONE;
601 whdr->reserved = 0;
602
603 if(prevhdr == NULL)
604 wavehdr = whdr->lpNext;
605 else prevhdr->lpNext = whdr->lpNext;
606
607 whdr->lpNext = NULL;
608
609 bytesReturned += whdr->dwBufferLength;
610 wmutex.leave();
611
612 callback(WOM_DONE, (ULONG)whdr, 0);
613
614 wmutex.enter();
615 }
616 else break;
617
618 prevhdr = whdr;
619 whdr = whdr->lpNext;
620 }
621
622 if(wavehdr == NULL) {
623 //last buffer played -> no new ones -> return now
624 dprintf(("WINMM: WaveOut handler LAST BUFFER PLAYED! state %s (play %d (%d), cop %d, ret %d)", (State == STATE_PLAYING) ? "playing" : "stopped", bytesPlayed, getPosition(), bytesCopied, bytesReturned));
625 wmutex.leave();
626 return;
627 }
628
629 writeBuffer();
630
631sendbuffer:
632 wmutex.leave();
633
634 //Transfer the buffer we just finished playing to DART
635 dprintf2(("WINMM: handler transfer buffer %d", pBuffer - MixBuffer));
636 USHORT selTIB = RestoreOS2FS(); // save current FS selector
637 MixSetupParms->pmixWrite(MixSetupParms->ulMixHandle, pBuffer, 1);
638 SetFS(selTIB); // switch back to the saved FS selector
639
640 dprintf2(("WINMM: handler DONE"));
641}
642/******************************************************************************/
643/******************************************************************************/
644void DartWaveOut::writeBuffer()
645{
646 ULONG buflength;
647
648 if(!fUnderrun && State == STATE_PLAYING && curFillBuf == curPlayBuf) {
649 dprintf2(("writeBuffer: no more room for more audio data"));
650 return; //no room left
651 }
652
653 if(curhdr == NULL)
654 curhdr = wavehdr;
655
656 while(curhdr && (curhdr->reserved == WHDR_DONE)) {
657 curhdr = curhdr->lpNext;
658 }
659
660 if(curhdr == NULL) {
661 return; //no unprocessed buffers left
662 }
663
664 dprintf2(("WINMM: handler cur (%d,%d), fill (%d,%d)\n", curPlayBuf, curPlayPos, curFillBuf, curFillPos));
665
666 while(curhdr) {
667 buflength = min((ULONG)MixBuffer[curFillBuf].ulBufferLength - curPlayPos,
668 (ULONG)curhdr->dwBufferLength - curFillPos);
669 dprintf2(("WINMM: copied %d bytes, cufFillPos = %d, curPlayPos = %d, dwBufferLength = %d\n", buflength, curFillPos, curPlayPos, curhdr->dwBufferLength));
670
671 memcpy((char *)MixBuffer[curFillBuf].pBuffer + curPlayPos,
672 curhdr->lpData + curFillPos, buflength);
673 curPlayPos += buflength;
674 curFillPos += buflength;
675 bytesCopied += buflength;
676
677 if(curFillPos == curhdr->dwBufferLength) {
678 dprintf2(("Buffer %d done ptr %x size %d %x %x %x %x %x %x", curFillBuf, curhdr->lpData, curhdr->dwBufferLength, curhdr->dwBytesRecorded, curhdr->dwUser, curhdr->dwFlags, curhdr->dwLoops, curhdr->lpNext, curhdr->reserved));
679
680 curFillPos = 0;
681 curhdr->reserved = WHDR_DONE;
682 //search for next unprocessed buffer
683 while(curhdr && (curhdr->reserved == WHDR_DONE))
684 curhdr = curhdr->lpNext;
685 }
686 if(curPlayPos == MixBuffer[curFillBuf].ulBufferLength) {
687 curPlayPos = 0;
688
689 if(++curFillBuf == PREFILLBUF_DART) {
690 curFillBuf = 0;
691 }
692 if(curFillBuf == curPlayBuf)
693 break; //no more room left
694 }
695 }
696}
697/******************************************************************************/
698/******************************************************************************/
699LONG APIENTRY WaveOutHandler(ULONG ulStatus,
700 PMCI_MIX_BUFFER pBuffer,
701 ULONG ulFlags)
702{
703 PTIB2 ptib2;
704 DartWaveOut *dwave;
705
706 dprintf2(("WaveOutHandler %x %x %x", ulStatus, pBuffer, ulFlags));
707
708 ptib2 = (PTIB2)_getTIBvalue(offsetof(TIB, tib_ptib2));
709 if(ptib2 && HIBYTE(ptib2->tib2_ulpri) != PRTYC_TIMECRITICAL) {
710 dprintf(("Setting priority of DART thread to PRTYC_TIMECRITICAL"));
711 DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
712 }
713 if(pBuffer && pBuffer->ulUserParm)
714 {
715 dwave = (DartWaveOut *)pBuffer->ulUserParm;
716 dwave->handler(ulStatus, pBuffer, ulFlags);
717 }
718 return(TRUE);
719}
720
721/******************************************************************************/
722/******************************************************************************/
723MMRESULT DartWaveOut::setVolume(ULONG ulVol)
724{
725 ULONG ulVolR = (((ulVol & 0xffff0000) >> 16 )*100)/0xFFFF; // Right Volume
726 ULONG ulVolL = ((ulVol& 0x0000ffff)*100)/0xFFFF; // Left Volume
727 MCI_SET_PARMS msp = {0};
728
729 dprintf(("DartWaveOut::setVolume %d %d", ulVolL, ulVolR));
730 volume = ulVol;
731
732// PD: My card (ESS 1868 PnP) driver can't change only
733// one channel Left or Right :-(
734//
735#ifdef GOOD_AUDIO_CARD_DRIVER
736
737 msp.ulAudio = MCI_SET_AUDIO_LEFT;
738 msp.ulLevel = ulVolL;
739
740 mymciSendCommand(DeviceId, MCI_SET,
741 MCI_WAIT | MCI_SET_AUDIO | MCI_SET_VOLUME,
742 &msp, 0);
743
744 msp.ulAudio = MCI_SET_AUDIO_RIGHT;
745 msp.ulLevel = ulVolR;
746
747#else
748 msp.ulAudio = MCI_SET_AUDIO_ALL;
749 msp.ulLevel = max(ulVolR,ulVolL);
750#endif
751
752 mymciSendCommand(DeviceId, MCI_SET,
753 MCI_WAIT | MCI_SET_AUDIO | MCI_SET_VOLUME,
754 &msp, 0);
755 return 0;
756}
757/******************************************************************************/
758/******************************************************************************/
759
Note: See TracBrowser for help on using the repository browser.