1 /* fhandler_dev_dsp: code to emulate OSS sound model /dev/dsp
3 Copyright 2001, 2002, 2003 Red Hat, Inc
5 Written by Andy Younger (andy@snoogie.demon.co.uk)
7 This file is part of Cygwin.
9 This software is a copyrighted work licensed under the terms of the
10 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
16 #include <sys/soundcard.h>
23 //------------------------------------------------------------------------
24 // Simple encapsulation of the win32 audio device.
26 static void CALLBACK wave_callback (HWAVE hWave, UINT msg, DWORD instance,
27 DWORD param1, DWORD param2);
35 TOT_BLOCK_SIZE = BLOCK_SIZE + sizeof (WAVEHDR)
41 bool open (int rate, int bits, int channels, bool bCallback = false);
44 void setvolume (int newVolume);
45 bool write (const void *pSampleData, int nBytes);
47 void callback_sampledone (void *pData);
48 void setformat (int format) {formattype_ = format;}
49 int numbytesoutput ();
51 void *operator new (size_t, void *p) {return p;}
54 char *initialisebuffer ();
55 void waitforcallback ();
59 volatile int nBlocksInQue_;
63 CRITICAL_SECTION lock_;
64 char *freeblocks_[MAX_BLOCKS];
67 char bigwavebuffer_[MAX_BLOCKS * TOT_BLOCK_SIZE];
70 static char audio_buf[sizeof (class Audio)];
74 InitializeCriticalSection (&lock_);
75 memset (bigwavebuffer_, 0, sizeof (bigwavebuffer_));
76 for (int i = 0; i < MAX_BLOCKS; i++)
77 freeblocks_[i] = &bigwavebuffer_[i * TOT_BLOCK_SIZE];
84 DeleteCriticalSection (&lock_);
88 Audio::open (int rate, int bits, int channels, bool bCallback)
91 int nDevices = waveOutGetNumDevs ();
96 debug_printf ("number devices %d", nDevices);
100 debug_printf ("trying to map device freq %d, bits %d, "
101 "channels %d, callback %d", rate, bits, channels,
104 int bytesperSample = bits / 8;
106 memset (&format, 0, sizeof (format));
107 format.wFormatTag = WAVE_FORMAT_PCM;
108 format.wBitsPerSample = bits;
109 format.nChannels = channels;
110 format.nSamplesPerSec = rate;
111 format.nAvgBytesPerSec = format.nSamplesPerSec * format.nChannels *
113 format.nBlockAlign = format.nChannels * bytesperSample;
116 HRESULT res = waveOutOpen (&dev_, WAVE_MAPPER, &format, (DWORD) wave_callback,
117 (DWORD) this, bCallback ? CALLBACK_FUNCTION : 0);
120 debug_printf ("Sucessfully opened!");
125 debug_printf ("failed to open");
135 flush (); // force out last block whatever size..
137 while (blocks ()) // block till finished..
148 Audio::numbytesoutput ()
150 return nBytesWritten_;
158 waveOutGetVolume (dev_, &volume);
159 return ((volume >> 16) + (volume & 0xffff)) >> 1;
163 Audio::setvolume (int newVolume)
165 waveOutSetVolume (dev_, (newVolume << 16) | newVolume);
169 Audio::initialisebuffer ()
171 EnterCriticalSection (&lock_);
172 WAVEHDR *pHeader = 0L;
173 for (int i = 0; i < MAX_BLOCKS; i++)
175 char *pData = freeblocks_[i];
178 pHeader = (WAVEHDR *) pData;
179 if (pHeader->dwFlags & WHDR_DONE)
181 waveOutUnprepareHeader (dev_, pHeader, sizeof (WAVEHDR));
187 LeaveCriticalSection (&lock_);
191 memset (pHeader, 0, sizeof (WAVEHDR));
192 pHeader->dwBufferLength = BLOCK_SIZE;
193 pHeader->lpData = (LPSTR) (&pHeader[1]);
194 return (char *) pHeader->lpData;
200 Audio::write (const void *pSampleData, int nBytes)
202 // split up big blocks into smaller BLOCK_SIZE chunks
203 while (nBytes > BLOCK_SIZE)
205 write (pSampleData, BLOCK_SIZE);
206 nBytes -= BLOCK_SIZE;
207 pSampleData = (void *) ((char *) pSampleData + BLOCK_SIZE);
210 // Block till next sound is flushed
211 if (blocks () == MAX_BLOCKS)
214 // Allocate new wave buffer if necessary
217 buffer_ = initialisebuffer ();
223 // Handle gathering blocks into larger buffer
224 int sizeleft = BLOCK_SIZE - bufferIndex_;
225 if (nBytes < sizeleft)
227 memcpy (&buffer_[bufferIndex_], pSampleData, nBytes);
228 bufferIndex_ += nBytes;
229 nBytesWritten_ += nBytes;
233 // flushing when we reach our limit of BLOCK_SIZE
234 memcpy (&buffer_[bufferIndex_], pSampleData, sizeleft);
235 bufferIndex_ += sizeleft;
236 nBytesWritten_ += sizeleft;
239 // change pointer to rest of sample, and size accordingly
240 pSampleData = (void *) ((char *) pSampleData + sizeleft);
243 // if we still have some sample left over write it out
245 return write (pSampleData, nBytes);
250 // return number of blocks back.
254 EnterCriticalSection (&lock_);
255 int ret = nBlocksInQue_;
256 LeaveCriticalSection (&lock_);
260 // This is called on an interupt so use locking.. Note nBlocksInQue_ is
261 // modified by it so we should wrap all references to it in locks.
263 Audio::callback_sampledone (void *pData)
265 EnterCriticalSection (&lock_);
268 for (int i = 0; i < MAX_BLOCKS; i++)
271 freeblocks_[i] = (char *) pData;
275 LeaveCriticalSection (&lock_);
279 Audio::waitforcallback ()
288 while (n == blocks ());
297 // Send internal buffer out to the soundcard
298 WAVEHDR *pHeader = ((WAVEHDR *) buffer_) - 1;
299 pHeader->dwBufferLength = bufferIndex_;
301 // Quick bit of sample buffer conversion
302 if (formattype_ == AFMT_S8)
304 unsigned char *p = ((unsigned char *) buffer_);
305 for (int i = 0; i < bufferIndex_; i++)
311 if (waveOutPrepareHeader (dev_, pHeader, sizeof (WAVEHDR)) == S_OK &&
312 waveOutWrite (dev_, pHeader, sizeof (WAVEHDR)) == S_OK)
314 EnterCriticalSection (&lock_);
316 LeaveCriticalSection (&lock_);
323 EnterCriticalSection (&lock_);
324 for (int i = 0; i < MAX_BLOCKS; i++)
327 freeblocks_[i] = (char *) pHeader;
330 LeaveCriticalSection (&lock_);
335 //------------------------------------------------------------------------
338 wave_callback (HWAVE hWave, UINT msg, DWORD instance, DWORD param1,
343 Audio *ptr = (Audio *) instance;
344 ptr->callback_sampledone ((void *) param1);
348 //------------------------------------------------------------------------
350 static Audio *s_audio; // static instance of the Audio handler
352 //------------------------------------------------------------------------
353 // wav file detection..
362 unsigned short wFormatTag;
363 unsigned short wChannels;
364 unsigned int dwSamplesPerSec;
365 unsigned int dwAvgBytesPerSec;
366 unsigned short wBlockAlign;
367 unsigned short wBitsPerSample;
372 fhandler_dev_dsp::setupwav (const char *pData, int nBytes)
375 const char *end = pData + nBytes;
377 if (!(pData[0] == 'R' && pData[1] == 'I' &&
378 pData[2] == 'F' && pData[3] == 'F'))
380 if (!(pData[8] == 'W' && pData[9] == 'A' &&
381 pData[10] == 'V' && pData[11] == 'E'))
384 len = *(int *) &pData[4];
386 while (len && pData < end)
388 wavchunk * pChunk = (wavchunk *) pData;
389 int blklen = pChunk-> len;
390 if (pChunk->id[0] == 'f' && pChunk->id[1] == 'm' &&
391 pChunk->id[2] == 't' && pChunk->id[3] == ' ')
393 wavformat *format = (wavformat *) (pChunk + 1);
394 if ((char *) (format + 1) > end)
397 // Open up audio device with correct frequency for wav file
399 // FIXME: should through away all the header & not output
400 // it to the soundcard.
402 if (s_audio->open (format->dwSamplesPerSec, format->wBitsPerSample,
403 format->wChannels) == false)
405 s_audio->open (audiofreq_, audiobits_, audiochannels_);
409 audiofreq_ = format->dwSamplesPerSec;
410 audiobits_ = format->wBitsPerSample;
411 audiochannels_ = format->wChannels;
416 pData += blklen + sizeof (wavchunk);
421 //------------------------------------------------------------------------
422 fhandler_dev_dsp::fhandler_dev_dsp ():
427 fhandler_dev_dsp::~fhandler_dev_dsp ()
432 fhandler_dev_dsp::open (int flags, mode_t mode)
434 // currently we only support writing
435 if ((flags & (O_WRONLY | O_RDONLY | O_RDWR)) != O_WRONLY)
441 set_flags ((flags & ~O_TEXT) | O_BINARY);
444 s_audio = new (audio_buf) Audio;
446 // Work out initial sample format & frequency
448 audioformat_ = AFMT_S8;
454 if (!s_audio->open (audiofreq_, audiobits_, audiochannels_))
462 debug_printf ("returns %d", res);
467 fhandler_dev_dsp::write (const void *ptr, size_t len)
469 if (s_audio->numbytesoutput () == 0)
471 // check for wave file & setup frequencys properly if possible.
472 setupwav ((const char *) ptr, len);
474 // Open audio device properly with callbacks.
476 if (!s_audio->open (audiofreq_, audiobits_, audiochannels_, true))
480 s_audio->write (ptr, len);
485 fhandler_dev_dsp::read (void *ptr, size_t& len)
491 fhandler_dev_dsp::lseek (_off64_t offset, int whence)
497 fhandler_dev_dsp::close (void)
504 fhandler_dev_dsp::dup (fhandler_base * child)
506 fhandler_dev_dsp *fhc = (fhandler_dev_dsp *) child;
508 fhc->set_flags (get_flags ());
509 fhc->audiochannels_ = audiochannels_;
510 fhc->audiobits_ = audiobits_;
511 fhc->audiofreq_ = audiofreq_;
512 fhc->audioformat_ = audioformat_;
517 fhandler_dev_dsp::ioctl (unsigned int cmd, void *ptr)
519 int *intptr = (int *) ptr;
522 #define CASE(a) case a : debug_printf("/dev/dsp: ioctl %s", #a);
524 CASE (SNDCTL_DSP_RESET)
525 audioformat_ = AFMT_S8;
531 CASE (SNDCTL_DSP_GETBLKSIZE)
532 *intptr = Audio::BLOCK_SIZE;
535 CASE (SNDCTL_DSP_SETFMT)
538 if (*intptr == AFMT_S16_LE)
540 else if (*intptr == AFMT_U8)
542 else if (*intptr == AFMT_S8)
546 s_audio->setformat (*intptr);
548 if (s_audio->open (audiofreq_, nBits, audiochannels_) == true)
555 s_audio->open (audiofreq_, audiobits_, audiochannels_);
562 CASE (SNDCTL_DSP_SPEED)
564 if (s_audio->open (*intptr, audiobits_, audiochannels_) == true)
566 audiofreq_ = *intptr;
571 s_audio->open (audiofreq_, audiobits_, audiochannels_);
576 CASE (SNDCTL_DSP_STEREO)
578 int nChannels = *intptr + 1;
581 if (s_audio->open (audiofreq_, audiobits_, nChannels) == true)
583 audiochannels_ = nChannels;
588 s_audio->open (audiofreq_, audiobits_, audiochannels_);
594 CASE (SNDCTL_DSP_GETOSPACE)
596 audio_buf_info *p = (audio_buf_info *) ptr;
598 int nBlocks = s_audio->blocks ();
599 int leftblocks = ((Audio::MAX_BLOCKS - nBlocks) - 1);
604 int left = leftblocks * Audio::BLOCK_SIZE;
606 p->fragments = leftblocks;
607 p->fragstotal = Audio::MAX_BLOCKS;
608 p->fragsize = Audio::BLOCK_SIZE;
611 debug_printf ("ptr %p nblocks %d leftblocks %d left bytes %d ",
612 ptr, nBlocks, leftblocks, left);
618 CASE (SNDCTL_DSP_SETFRAGMENT)
620 // Fake!! esound & mikmod require this on non PowerPC platforms.
626 CASE (SNDCTL_DSP_GETFMTS)
628 *intptr = AFMT_S16_LE | AFMT_U8 | AFMT_S8; // more?
634 debug_printf ("/dev/dsp: ioctl not handled yet! FIXME:");
643 fhandler_dev_dsp::dump ()
645 paranoid_printf ("here, fhandler_dev_dsp");
649 fhandler_dev_dsp::fixup_after_exec (HANDLE)
651 /* FIXME: Is there a better way to do this? */
652 s_audio = new (audio_buf) Audio;