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

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

Added code to dump played wave data to disk (disabled by default)

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