1 /* fhandler_dev_dsp: code to emulate OSS sound model /dev/dsp
3 Copyright 2001, 2002 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
17 #include <sys/soundcard.h>
18 #include <sys/fcntl.h>
24 //------------------------------------------------------------------------
25 // Simple encapsulation of the win32 audio device.
27 static void CALLBACK wave_callback (HWAVE hWave, UINT msg, DWORD instance,
28 DWORD param1, DWORD param2);
36 TOT_BLOCK_SIZE = BLOCK_SIZE + sizeof (WAVEHDR)
42 bool open (int rate, int bits, int channels, bool bCallback = false);
45 void setvolume (int newVolume);
46 bool write (const void *pSampleData, int nBytes);
48 void callback_sampledone (void *pData);
49 void setformat (int format) {formattype_ = format;}
50 int numbytesoutput ();
52 void *operator new (size_t, void *p) {return p;}
55 char *initialisebuffer ();
56 void waitforcallback ();
60 volatile int nBlocksInQue_;
64 CRITICAL_SECTION lock_;
65 char *freeblocks_[MAX_BLOCKS];
68 char bigwavebuffer_[MAX_BLOCKS * TOT_BLOCK_SIZE];
71 static char audio_buf[sizeof (class Audio)];
75 InitializeCriticalSection (&lock_);
76 memset (bigwavebuffer_, 0, sizeof (bigwavebuffer_));
77 for (int i = 0; i < MAX_BLOCKS; i++)
78 freeblocks_[i] = &bigwavebuffer_[i * TOT_BLOCK_SIZE];
85 DeleteCriticalSection (&lock_);
89 Audio::open (int rate, int bits, int channels, bool bCallback)
92 int nDevices = waveOutGetNumDevs ();
97 debug_printf ("number devices %d\n", nDevices);
101 debug_printf ("trying to map device freq %d, bits %d, "
102 "channels %d, callback %d\n", rate, bits, channels,
105 int bytesperSample = bits / 8;
107 memset (&format, 0, sizeof (format));
108 format.wFormatTag = WAVE_FORMAT_PCM;
109 format.wBitsPerSample = bits;
110 format.nChannels = channels;
111 format.nSamplesPerSec = rate;
112 format.nAvgBytesPerSec = format.nSamplesPerSec * format.nChannels *
114 format.nBlockAlign = format.nChannels * bytesperSample;
117 HRESULT res = waveOutOpen (&dev_, WAVE_MAPPER, &format, (DWORD) wave_callback,
118 (DWORD) this, bCallback ? CALLBACK_FUNCTION : 0);
121 debug_printf ("Sucessfully opened!");
126 debug_printf ("failed to open");
136 flush (); // force out last block whatever size..
138 while (blocks ()) // block till finished..
149 Audio::numbytesoutput ()
151 return nBytesWritten_;
159 waveOutGetVolume (dev_, &volume);
160 return ((volume >> 16) + (volume & 0xffff)) >> 1;
164 Audio::setvolume (int newVolume)
166 waveOutSetVolume (dev_, (newVolume << 16) | newVolume);
170 Audio::initialisebuffer ()
172 EnterCriticalSection (&lock_);
173 WAVEHDR *pHeader = 0L;
174 for (int i = 0; i < MAX_BLOCKS; i++)
176 char *pData = freeblocks_[i];
179 pHeader = (WAVEHDR *) pData;
180 if (pHeader->dwFlags & WHDR_DONE)
182 waveOutUnprepareHeader (dev_, pHeader, sizeof (WAVEHDR));
188 LeaveCriticalSection (&lock_);
192 memset (pHeader, 0, sizeof (WAVEHDR));
193 pHeader->dwBufferLength = BLOCK_SIZE;
194 pHeader->lpData = (LPSTR) (&pHeader[1]);
195 return (char *) pHeader->lpData;
201 Audio::write (const void *pSampleData, int nBytes)
203 // split up big blocks into smaller BLOCK_SIZE chunks
204 while (nBytes > BLOCK_SIZE)
206 write (pSampleData, BLOCK_SIZE);
207 nBytes -= BLOCK_SIZE;
208 pSampleData = (void *) ((char *) pSampleData + BLOCK_SIZE);
211 // Block till next sound is flushed
212 if (blocks () == MAX_BLOCKS)
215 // Allocate new wave buffer if necessary
218 buffer_ = initialisebuffer ();
224 // Handle gathering blocks into larger buffer
225 int sizeleft = BLOCK_SIZE - bufferIndex_;
226 if (nBytes < sizeleft)
228 memcpy (&buffer_[bufferIndex_], pSampleData, nBytes);
229 bufferIndex_ += nBytes;
230 nBytesWritten_ += nBytes;
234 // flushing when we reach our limit of BLOCK_SIZE
235 memcpy (&buffer_[bufferIndex_], pSampleData, sizeleft);
236 bufferIndex_ += sizeleft;
237 nBytesWritten_ += sizeleft;
240 // change pointer to rest of sample, and size accordingly
241 pSampleData = (void *) ((char *) pSampleData + sizeleft);
244 // if we still have some sample left over write it out
246 return write (pSampleData, nBytes);
251 // return number of blocks back.
255 EnterCriticalSection (&lock_);
256 int ret = nBlocksInQue_;
257 LeaveCriticalSection (&lock_);
261 // This is called on an interupt so use locking.. Note nBlocksInQue_ is
262 // modified by it so we should wrap all references to it in locks.
264 Audio::callback_sampledone (void *pData)
266 EnterCriticalSection (&lock_);
269 for (int i = 0; i < MAX_BLOCKS; i++)
272 freeblocks_[i] = (char *) pData;
276 LeaveCriticalSection (&lock_);
280 Audio::waitforcallback ()
289 while (n == blocks ());
298 // Send internal buffer out to the soundcard
299 WAVEHDR *pHeader = ((WAVEHDR *) buffer_) - 1;
300 pHeader->dwBufferLength = bufferIndex_;
302 // Quick bit of sample buffer conversion
303 if (formattype_ == AFMT_S8)
305 unsigned char *p = ((unsigned char *) buffer_);
306 for (int i = 0; i < bufferIndex_; i++)
312 if (waveOutPrepareHeader (dev_, pHeader, sizeof (WAVEHDR)) == S_OK &&
313 waveOutWrite (dev_, pHeader, sizeof (WAVEHDR)) == S_OK)
315 EnterCriticalSection (&lock_);
317 LeaveCriticalSection (&lock_);
324 EnterCriticalSection (&lock_);
325 for (int i = 0; i < MAX_BLOCKS; i++)
328 freeblocks_[i] = (char *) pHeader;
331 LeaveCriticalSection (&lock_);
336 //------------------------------------------------------------------------
339 wave_callback (HWAVE hWave, UINT msg, DWORD instance, DWORD param1,
344 Audio *ptr = (Audio *) instance;
345 ptr->callback_sampledone ((void *) param1);
349 //------------------------------------------------------------------------
351 static Audio *s_audio; // static instance of the Audio handler
353 //------------------------------------------------------------------------
354 // wav file detection..
363 unsigned short wFormatTag;
364 unsigned short wChannels;
365 unsigned int dwSamplesPerSec;
366 unsigned int dwAvgBytesPerSec;
367 unsigned short wBlockAlign;
368 unsigned short wBitsPerSample;
373 fhandler_dev_dsp::setupwav (const char *pData, int nBytes)
376 const char *end = pData + nBytes;
378 if (!(pData[0] == 'R' && pData[1] == 'I' &&
379 pData[2] == 'F' && pData[3] == 'F'))
381 if (!(pData[8] == 'W' && pData[9] == 'A' &&
382 pData[10] == 'V' && pData[11] == 'E'))
385 len = *(int *) &pData[4];
387 while (len && pData < end)
389 wavchunk * pChunk = (wavchunk *) pData;
390 int blklen = pChunk-> len;
391 if (pChunk->id[0] == 'f' && pChunk->id[1] == 'm' &&
392 pChunk->id[2] == 't' && pChunk->id[3] == ' ')
394 wavformat *format = (wavformat *) (pChunk + 1);
395 if ((char *) (format + 1) > end)
398 // Open up audio device with correct frequency for wav file
400 // FIXME: should through away all the header & not output
401 // it to the soundcard.
403 if (s_audio->open (format->dwSamplesPerSec, format->wBitsPerSample,
404 format->wChannels) == false)
406 s_audio->open (audiofreq_, audiobits_, audiochannels_);
410 audiofreq_ = format->dwSamplesPerSec;
411 audiobits_ = format->wBitsPerSample;
412 audiochannels_ = format->wChannels;
417 pData += blklen + sizeof (wavchunk);
422 //------------------------------------------------------------------------
423 fhandler_dev_dsp::fhandler_dev_dsp ():
424 fhandler_base (FH_OSS_DSP)
428 fhandler_dev_dsp::~fhandler_dev_dsp ()
433 fhandler_dev_dsp::open (path_conv *, int flags, mode_t mode)
435 // currently we only support writing
436 if ((flags & (O_WRONLY | O_RDONLY | O_RDWR)) != O_WRONLY)
442 s_audio = new (audio_buf) Audio;
444 // Work out initial sample format & frequency
446 audioformat_ = AFMT_S8;
451 if (!s_audio->open (audiofreq_, audiobits_, audiochannels_))
452 debug_printf ("/dev/dsp: failed to open\n");
456 debug_printf ("/dev/dsp: successfully opened\n");
462 fhandler_dev_dsp::write (const void *ptr, size_t len)
464 if (s_audio->numbytesoutput () == 0)
466 // check for wave file & setup frequencys properly if possible.
467 setupwav ((const char *) ptr, len);
469 // Open audio device properly with callbacks.
471 if (!s_audio->open (audiofreq_, audiobits_, audiochannels_, true))
475 s_audio->write (ptr, len);
480 fhandler_dev_dsp::read (void *ptr, size_t len)
486 fhandler_dev_dsp::lseek (__off32_t offset, int whence)
492 fhandler_dev_dsp::close (void)
499 fhandler_dev_dsp::dup (fhandler_base * child)
501 fhandler_dev_dsp *fhc = (fhandler_dev_dsp *) child;
503 fhc->set_flags (get_flags ());
504 fhc->audiochannels_ = audiochannels_;
505 fhc->audiobits_ = audiobits_;
506 fhc->audiofreq_ = audiofreq_;
507 fhc->audioformat_ = audioformat_;
512 fhandler_dev_dsp::ioctl (unsigned int cmd, void *ptr)
514 int *intptr = (int *) ptr;
517 #define CASE(a) case a : debug_printf("/dev/dsp: ioctl %s\n", #a);
519 CASE (SNDCTL_DSP_RESET)
520 audioformat_ = AFMT_S8;
526 CASE (SNDCTL_DSP_GETBLKSIZE)
527 *intptr = Audio::BLOCK_SIZE;
530 CASE (SNDCTL_DSP_SETFMT)
533 if (*intptr == AFMT_S16_LE)
535 else if (*intptr == AFMT_U8)
537 else if (*intptr == AFMT_S8)
541 s_audio->setformat (*intptr);
543 if (s_audio->open (audiofreq_, nBits, audiochannels_) == true)
550 s_audio->open (audiofreq_, audiobits_, audiochannels_);
557 CASE (SNDCTL_DSP_SPEED)
559 if (s_audio->open (*intptr, audiobits_, audiochannels_) == true)
561 audiofreq_ = *intptr;
566 s_audio->open (audiofreq_, audiobits_, audiochannels_);
571 CASE (SNDCTL_DSP_STEREO)
573 int nChannels = *intptr + 1;
576 if (s_audio->open (audiofreq_, audiobits_, nChannels) == true)
578 audiochannels_ = nChannels;
583 s_audio->open (audiofreq_, audiobits_, audiochannels_);
589 CASE (SNDCTL_DSP_GETOSPACE)
591 audio_buf_info *p = (audio_buf_info *) ptr;
593 int nBlocks = s_audio->blocks ();
594 int leftblocks = ((Audio::MAX_BLOCKS - nBlocks) - 1);
599 int left = leftblocks * Audio::BLOCK_SIZE;
601 p->fragments = leftblocks;
602 p->fragstotal = Audio::MAX_BLOCKS;
603 p->fragsize = Audio::BLOCK_SIZE;
606 debug_printf ("ptr %p nblocks %d leftblocks %d left bytes %d ",
607 ptr, nBlocks, leftblocks, left);
613 CASE (SNDCTL_DSP_SETFRAGMENT)
615 // Fake!! esound & mikmod require this on non PowerPC platforms.
622 debug_printf ("/dev/dsp: ioctl not handled yet! FIXME:\n");
631 fhandler_dev_dsp::dump ()
633 paranoid_printf ("here, fhandler_dev_dsp");
637 fhandler_dev_dsp::fixup_after_exec (HANDLE)
639 /* FIXME: Is there a better way to do this? */
640 s_audio = new (audio_buf) Audio;