source: trunk/src/winmm/waveoutdart.cpp

Last change on this file was 21916, checked in by dmik, 14 years ago

Merge branch gcc-kmk to trunk.

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