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

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

Merge branch gcc-kmk to trunk.

File size: 23.6 KB
Line 
1/* $Id: waveoutdart.cpp,v 1.24 2004-03-16 11:20:40 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// Includes
19/******************************************************************************/
20
21#define INCL_BASE
22#define INCL_OS2MM
23#define INCL_DOSPROCESS
24#include <os2wrap.h> //Odin32 OS/2 api wrappers
25#include <os2mewrap.h> //Odin32 OS/2 MMPM/2 api wrappers
26#include <stdlib.h>
27#include <stddef.h>
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"
35#include "initterm.h"
36
37#define DBG_LOCALLOG DBG_waveoutdart
38#include "dbglocal.h"
39
40/******************************************************************************/
41
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
52#define DART_BUFCNT 64
53#define DART_BUFSIZE 4096
54
55/******************************************************************************/
56
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
71/******************************************************************************/
72
73static BOOL fFixedWaveBufferSize = FALSE;
74
75/******************************************************************************/
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//
84/******************************************************************************/
85
86void WIN32API ODIN_waveOutSetFixedBuffers()
87{
88 fFixedWaveBufferSize = TRUE;
89}
90
91/******************************************************************************/
92/******************************************************************************/
93
94DartWaveOut::DartWaveOut(LPWAVEFORMATEX pwfx, ULONG fdwOpen, ULONG nCallback, ULONG dwInstance)
95 : WaveOut(pwfx, fdwOpen, nCallback, dwInstance)
96{
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}
116
117/******************************************************************************/
118/******************************************************************************/
119
120DartWaveOut::~DartWaveOut()
121{
122 MCI_GENERIC_PARMS GenericParms = {0};
123
124 State = STATE_STOPPED;
125
126#ifdef DEBUG_DUMP_PCM
127 if (pcmfile) fclose(pcmfile);
128#endif
129
130 if (DeviceId) {
131 // Stop the playback.
132 mymciSendCommand(DeviceId, MCI_STOP,
133 MCI_WAIT,
134 (PVOID)&GenericParms,0);
135
136 if (fMixerSetup)
137 mymciSendCommand(DeviceId, MCI_BUFFER,
138 MCI_WAIT | MCI_DEALLOCATE_MEMORY,
139 (PVOID)&BufferParms, 0);
140
141 // Close the device
142 mymciSendCommand(DeviceId, MCI_CLOSE,
143 MCI_WAIT,
144 (PVOID)&GenericParms, 0);
145
146 callback(WOM_CLOSE, 0, 0);
147 }
148
149 if (MixBuffer)
150 free(MixBuffer);
151 if (BufferParms)
152 free(BufferParms);
153}
154
155/******************************************************************************/
156/******************************************************************************/
157
158MMRESULT DartWaveOut::open()
159{
160 MCI_AMP_OPEN_PARMS AmpOpenParms;
161 MCI_GENERIC_PARMS GenericParms = {0};
162 MCI_MIXSETUP_PARMS MixSetupParms;
163 APIRET rc;
164
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 }
171
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;
176
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;
186
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));
198
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;
208
209 rc = mymciSendCommand(DeviceId, MCI_MIXSETUP,
210 MCI_WAIT | MCI_MIXSETUP_INIT,
211 (PVOID)&MixSetupParms, 0);
212
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 }
220
221 // Save the mixer handle & the ptr to the write proc.
222 mixHandle = MixSetupParms.ulMixHandle;
223 pmixWriteProc = MixSetupParms.pmixWrite;
224
225#ifdef DEBUG_DUMP_PCM
226 REC_STRUCT recinfo;
227
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);
234#endif
235
236 setVolume(volume);
237 callback(WOM_OPEN, 0, 0);
238
239 return MMSYSERR_NOERROR;
240}
241
242/******************************************************************************/
243/******************************************************************************/
244
245MMRESULT DartWaveOut::write(LPWAVEHDR pwh, UINT cbwh)
246{
247 APIRET rc;
248
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;
266 fMixerSetup = TRUE;
267 }
268
269 wmutex.enter();
270
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;
278 }
279 chdr->lpNext = pwh;
280 }
281 else wavehdr = pwh;
282
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 }
291
292 writeBuffer(); //must be called before (re)starting playback
293 State = STATE_PLAYING;
294 fUnderrun = FALSE;
295 wmutex.leave();
296
297 //write buffers to DART; starts playback
298 dprintf(("WINMM: transfer all buffers to DART"));
299
300 USHORT selTIB = RestoreOS2FS(); // save current FS selector
301 pmixWriteProc(mixHandle, MixBuffer, ulBufCount);
302 SetFS(selTIB); // switch back to the saved FS selector
303
304 dprintf(("Dart playing\n"));
305
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)
322 {
323 int consumerate = getAvgBytesPerSecond();
324 int minbufsize = consumerate/32;
325
326 ulBufSize /= 2;
327 if (ulBufSize > minbufsize) {
328 dprintf(("set buffer size to %d bytes (org size = %d)", minbufsize, orgbufsize));
329 ulBufSize = minbufsize;
330 }
331 }
332#else
333 if (ulBufSize < 512 || ulBufSize > 1024)
334 ulBufSize = 1024;
335#endif
336
337 dprintf(("buffer setup - WAVE size = %d, DART size = %d\n",
338 orgbufsize, ulBufSize));
339
340 BufferParms->ulNumBuffers = ulBufCount;
341 BufferParms->ulBufferSize = ulBufSize;
342 BufferParms->pBufList = MixBuffer;
343
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;
354 }
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;
366}
367
368/******************************************************************************/
369/******************************************************************************/
370
371MMRESULT DartWaveOut::pause()
372{
373 MCI_GENERIC_PARMS GenericParms = {0};
374
375 dprintf(("WINMM: DartWaveOut::pause"));
376
377 wmutex.enter();
378 if (State != STATE_PLAYING) {
379 State = STATE_PAUSED;
380 wmutex.leave();
381 return MMSYSERR_NOERROR;
382 }
383
384 State = STATE_PAUSED;
385 wmutex.leave();
386
387 // Pause playback.
388 mymciSendCommand(DeviceId, MCI_PAUSE,
389 MCI_WAIT,
390 (PVOID)&GenericParms, 0);
391
392 return MMSYSERR_NOERROR;
393}
394
395/******************************************************************************/
396/******************************************************************************/
397
398MMRESULT DartWaveOut::resume()
399{
400 int i, curbuf;
401
402 dprintf(("DartWaveOut::resume"));
403
404 wmutex.enter();
405 if (State != STATE_PAUSED) {
406 wmutex.leave();
407 return MMSYSERR_NOERROR;
408 }
409 State = STATE_PLAYING;
410 wmutex.leave();
411
412 //Only write buffers to dart if mixer has been initialized; if not, then
413 //the first buffer write will do this for us.
414 if (fMixerSetup == TRUE)
415 {
416 wmutex.enter();
417 State = STATE_PLAYING;
418 fUnderrun = FALSE;
419 curbuf = curPlayBuf;
420 writeBuffer(); //must be called before (re)starting playback
421 wmutex.leave();
422
423 USHORT selTIB = GetFS(); // save current FS selector
424 for (i = 0; i < ulBufCount; i++)
425 {
426 dprintf(("restart: write buffer at %x size %d", MixBuffer[curbuf].pBuffer, MixBuffer[curbuf].ulBufferLength));
427 pmixWriteProc(mixHandle, &MixBuffer[curbuf], 1);
428 if (++curbuf == ulBufCount)
429 curbuf = 0;
430 }
431 SetFS(selTIB); // switch back to the saved FS selector
432 }
433 return MMSYSERR_NOERROR;
434}
435
436/******************************************************************************/
437/******************************************************************************/
438
439MMRESULT DartWaveOut::stop()
440{
441 MCI_GENERIC_PARMS GenericParms = {0};
442
443 dprintf(("DartWaveOut::stop %s", (State == STATE_PLAYING) ? "playing" : "stopped"));
444 if (State != STATE_PLAYING)
445 return MMSYSERR_HANDLEBUSY;
446
447 // Stop the playback.
448 mymciSendCommand(DeviceId, MCI_STOP,
449 MCI_WAIT,
450 (PVOID)&GenericParms, 0);
451
452 State = STATE_STOPPED;
453 fUnderrun = FALSE;
454
455 curPlayBuf = curFillBuf = curFillPos = curPlayPos = 0;
456 bytesPlayed = bytesCopied = bytesReturned = 0;
457
458 return MMSYSERR_NOERROR;
459}
460
461/******************************************************************************/
462/******************************************************************************/
463
464MMRESULT DartWaveOut::reset()
465{
466 MCI_GENERIC_PARMS GenericParms = {0};
467 LPWAVEHDR tmpwavehdr;
468
469 dprintf(("DartWaveOut::reset %s", (State == STATE_PLAYING) ? "playing" : "stopped"));
470 if (State != STATE_PLAYING)
471 return MMSYSERR_HANDLEBUSY;
472
473 wmutex.enter();
474 State = STATE_STOPPED;
475 wmutex.leave();
476
477 // Stop the playback.
478 mymciSendCommand(DeviceId, MCI_STOP,
479 MCI_WAIT,
480 (PVOID)&GenericParms, 0);
481
482 wmutex.enter();
483 while (wavehdr)
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);
494 wmutex.enter();
495 }
496 wavehdr = NULL;
497 fUnderrun = FALSE;
498 ulUnderrunBase = 0;
499
500 curPlayBuf = curFillBuf = curFillPos = curPlayPos = 0;
501 bytesPlayed = bytesCopied = bytesReturned = 0;
502 queuedbuffers = 0;
503
504 wmutex.leave();
505 return MMSYSERR_NOERROR;
506}
507
508/******************************************************************************/
509/******************************************************************************/
510
511ULONG DartWaveOut::getPosition()
512{
513 MCI_STATUS_PARMS StatusParms = {0};
514 ULONG rc, nrbytes;
515
516 if (State == STATE_STOPPED) {
517 dprintf(("Not playing; return 0 position"));
518 return ulUnderrunBase;
519 }
520
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;
528 }
529
530 nrbytes = (ULONG)(((double)StatusParms.ulReturn * (double)getAvgBytesPerSecond())/1000.0);
531 return (ulUnderrunBase + nrbytes);
532}
533
534/******************************************************************************/
535/******************************************************************************/
536
537MMRESULT DartWaveOut::setVolume(ULONG ulVol)
538{
539 APIRET rc;
540 ULONG ulVolR = ((ulVol >> 16) * 100) / 0xFFFF;
541 ULONG ulVolL = ((ulVol & 0xffff) * 100) / 0xFFFF;
542 MCI_SET_PARMS SetParms = {0};
543
544 dprintf(("DartWaveOut::setVolume %d %d", ulVolL, ulVolR));
545 volume = ulVol;
546
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;
551
552 rc = mymciSendCommand(DeviceId, MCI_SET,
553 MCI_WAIT | MCI_SET_AUDIO | MCI_SET_VOLUME,
554 &SetParms, 0);
555 if (LOUSHORT(rc) != MCIERR_SUCCESS)
556 mciError(rc);
557
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
564
565 rc = mymciSendCommand(DeviceId, MCI_SET,
566 MCI_WAIT | MCI_SET_AUDIO | MCI_SET_VOLUME,
567 &SetParms, 0);
568 if (LOUSHORT(rc) != MCIERR_SUCCESS)
569 mciError(rc);
570
571 return MMSYSERR_NOERROR;
572}
573
574/******************************************************************************/
575/******************************************************************************/
576
577void DartWaveOut::mciError(ULONG rc)
578{
579#ifdef DEBUG
580 char szError[256] = "";
581
582 mymciGetErrorString(rc, szError, sizeof(szError));
583 dprintf(("WINMM: DartWaveOut: %s\n", szError));
584#endif
585}
586
587//******************************************************************************
588//******************************************************************************
589
590void DartWaveOut::handler(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags)
591{
592 ULONG buflength;
593 WAVEHDR *whdr, *prevhdr = NULL;
594
595 dprintf2(("WINMM: handler %d; buffers left %d", curPlayBuf, queuedbuffers));
596 if (ulFlags == MIX_STREAM_ERROR) {
597 if (ulStatus == ERROR_DEVICE_UNDERRUN) {
598 dprintf(("WINMM: WaveOut handler UNDERRUN! state %s", (State == STATE_PLAYING) ? "playing" : "stopped"));
599 if (State == STATE_PLAYING) {
600 fUnderrun = TRUE;
601 //save current position for when we continue later
602 ulUnderrunBase = bytesPlayed;
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 }
610 if (State != STATE_PLAYING)
611 return;
612
613 wmutex.enter();
614
615 bytesPlayed += MixBuffer[curPlayBuf].ulBufferLength;
616
617 // update our buffer index
618 if (++curPlayBuf >= ulBufCount)
619 curPlayBuf = 0;
620
621 fUnderrun = FALSE;
622
623 whdr = wavehdr;
624 while (whdr) {
625 if (whdr->reserved != WHDR_DONE)
626 break;
627
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 }
632
633 dprintf2(("WINMM: handler buf %X done (play %d/%d, cop %d, ret %d)", whdr, bytesPlayed, getPosition(), bytesCopied, bytesReturned));
634 queuedbuffers--;
635
636 whdr->dwFlags &= ~WHDR_INQUEUE;
637 whdr->dwFlags |= WHDR_DONE;
638 whdr->reserved = 0;
639
640 if (prevhdr == NULL)
641 wavehdr = whdr->lpNext;
642 else prevhdr->lpNext = whdr->lpNext;
643
644 whdr->lpNext = NULL;
645
646 bytesReturned += whdr->dwBufferLength;
647
648 wmutex.leave();
649 callback(WOM_DONE, (ULONG)whdr, 0);
650 wmutex.enter();
651
652 prevhdr = whdr;
653 whdr = whdr->lpNext;
654 }
655
656 if (wavehdr == NULL) {
657 // last buffer played -> no new ones -> return now
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));
659 if (getPosition() > bytesPlayed) {
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 }
666 wmutex.leave();
667 return;
668 }
669
670 writeBuffer();
671
672 wmutex.leave();
673
674 //Transfer the buffer we just finished playing to DART
675 dprintf2(("WINMM: handler transfer buffer %d", pBuffer - MixBuffer));
676 USHORT selTIB = RestoreOS2FS(); // save current FS selector
677 pmixWriteProc(mixHandle, pBuffer, 1);
678 SetFS(selTIB); // switch back to the saved FS selector
679
680 dprintf2(("WINMM: handler DONE"));
681}
682
683/******************************************************************************/
684/******************************************************************************/
685
686void DartWaveOut::writeBuffer()
687{
688 ULONG buflength;
689
690 if (!fUnderrun && State == STATE_PLAYING && wavehdr == NULL && curFillBuf == curPlayBuf) {
691 dprintf2(("writeBuffer: no more room for more audio data"));
692 return; //no room left
693 }
694
695 if (curhdr == NULL)
696 curhdr = wavehdr;
697
698 while (curhdr && (curhdr->reserved == WHDR_DONE)) {
699 curhdr = curhdr->lpNext;
700 }
701
702 if (curhdr == NULL)
703 return; //no unprocessed buffers left
704
705 if (State == STATE_PLAYING && curFillBuf == curPlayBuf)
706 {
707 dprintf(("curFillBuf == curPlayBuf; no more room (%d,%d)", curFillBuf, curPlayBuf));
708 return; //no more room left
709 }
710
711 dprintf2(("WINMM: handler cur (%d,%d), fill (%d,%d)\n", curPlayBuf, curPlayPos, curFillBuf, curFillPos));
712
713 while (curhdr) {
714 buflength = min((ULONG)MixBuffer[curFillBuf].ulBufferLength - curPlayPos,
715 (ULONG)curhdr->dwBufferLength - curFillPos);
716 dprintf2(("WINMM: copied %d bytes, cufFillPos = %d, curPlayPos = %d, dwBufferLength = %d\n", buflength, curFillPos, curPlayPos, curhdr->dwBufferLength));
717
718#ifdef DEBUG_DUMP_PCM
719 fwrite(curhdr->lpData + curFillPos, buflength, 1, pcmfile);
720#endif
721
722 memcpy((char *)MixBuffer[curFillBuf].pBuffer + curPlayPos,
723 curhdr->lpData + curFillPos, buflength);
724 curPlayPos += buflength;
725 curFillPos += buflength;
726 bytesCopied += buflength;
727
728 if (curFillPos == curhdr->dwBufferLength) {
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
734 while (curhdr && (curhdr->reserved == WHDR_DONE))
735 curhdr = curhdr->lpNext;
736 }
737 if (curPlayPos == MixBuffer[curFillBuf].ulBufferLength) {
738 curPlayPos = 0;
739
740 if (++curFillBuf >= ulBufCount)
741 curFillBuf = 0;
742
743 if (curFillBuf == curPlayBuf)
744 break; //no more room left
745 }
746 }
747}
748
749/******************************************************************************/
750/******************************************************************************/
751
752LONG APIENTRY WaveOutHandler(ULONG ulStatus,
753 PMCI_MIX_BUFFER pBuffer,
754 ULONG ulFlags)
755{
756 PTIB2 ptib2;
757 DartWaveOut *dwave;
758
759 dprintf2(("WaveOutHandler %x %x %x", ulStatus, pBuffer, ulFlags));
760
761#ifdef __IBMC__
762 ptib2 = (PTIB2)_getTIBvalue(offsetof(TIB, tib_ptib2));
763#else
764 PTIB ptib;
765 DosGetInfoBlocks(&ptib, NULL);
766 ptib2 = ptib->tib_ptib2;
767#endif
768
769 if (ptib2 && HIBYTE(ptib2->tib2_ulpri) != PRTYC_TIMECRITICAL &&
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);
774 }
775 if (pBuffer && pBuffer->ulUserParm)
776 {
777 dwave = (DartWaveOut *)pBuffer->ulUserParm;
778 dwave->handler(ulStatus, pBuffer, ulFlags);
779 }
780 return TRUE;
781}
782
783/******************************************************************************/
784/******************************************************************************/
785
Note: See TracBrowser for help on using the repository browser.