diff options
Diffstat (limited to 'winsup/cygwin/fhandler_dsp.cc')
-rw-r--r-- | winsup/cygwin/fhandler_dsp.cc | 646 |
1 files changed, 0 insertions, 646 deletions
diff --git a/winsup/cygwin/fhandler_dsp.cc b/winsup/cygwin/fhandler_dsp.cc deleted file mode 100644 index fad4319..0000000 --- a/winsup/cygwin/fhandler_dsp.cc +++ /dev/null @@ -1,646 +0,0 @@ -/* fhandler_dev_dsp: code to emulate OSS sound model /dev/dsp - - Copyright 2001, 2002 Red Hat, Inc - - Written by Andy Younger (andy@snoogie.demon.co.uk) - -This file is part of Cygwin. - -This software is a copyrighted work licensed under the terms of the -Cygwin license. Please consult the file "CYGWIN_LICENSE" for -details. */ - -#include "winsup.h" -#include <stdio.h> -#include <errno.h> -#include <windows.h> -#include <sys/soundcard.h> -#include <mmsystem.h> -#include "cygerrno.h" -#include "security.h" -#include "fhandler.h" - -//------------------------------------------------------------------------ -// Simple encapsulation of the win32 audio device. -// -static void CALLBACK wave_callback (HWAVE hWave, UINT msg, DWORD instance, - DWORD param1, DWORD param2); -class Audio -{ -public: - enum - { - MAX_BLOCKS = 12, - BLOCK_SIZE = 16384, - TOT_BLOCK_SIZE = BLOCK_SIZE + sizeof (WAVEHDR) - }; - - Audio (); - ~Audio (); - - bool open (int rate, int bits, int channels, bool bCallback = false); - void close (); - int getvolume (); - void setvolume (int newVolume); - bool write (const void *pSampleData, int nBytes); - int blocks (); - void callback_sampledone (void *pData); - void setformat (int format) {formattype_ = format;} - int numbytesoutput (); - - void *operator new (size_t, void *p) {return p;} - -private: - char *initialisebuffer (); - void waitforcallback (); - bool flush (); - - HWAVEOUT dev_; - volatile int nBlocksInQue_; - int nBytesWritten_; - char *buffer_; - int bufferIndex_; - CRITICAL_SECTION lock_; - char *freeblocks_[MAX_BLOCKS]; - int formattype_; - - char bigwavebuffer_[MAX_BLOCKS * TOT_BLOCK_SIZE]; -}; - -static char audio_buf[sizeof (class Audio)]; - -Audio::Audio () -{ - InitializeCriticalSection (&lock_); - memset (bigwavebuffer_, 0, sizeof (bigwavebuffer_)); - for (int i = 0; i < MAX_BLOCKS; i++) - freeblocks_[i] = &bigwavebuffer_[i * TOT_BLOCK_SIZE]; -} - -Audio::~Audio () -{ - if (dev_) - close (); - DeleteCriticalSection (&lock_); -} - -bool -Audio::open (int rate, int bits, int channels, bool bCallback) -{ - WAVEFORMATEX format; - int nDevices = waveOutGetNumDevs (); - - nBytesWritten_ = 0L; - bufferIndex_ = 0; - buffer_ = 0L; - debug_printf ("number devices %d\n", nDevices); - if (nDevices <= 0) - return false; - - debug_printf ("trying to map device freq %d, bits %d, " - "channels %d, callback %d\n", rate, bits, channels, - bCallback); - - int bytesperSample = bits / 8; - - memset (&format, 0, sizeof (format)); - format.wFormatTag = WAVE_FORMAT_PCM; - format.wBitsPerSample = bits; - format.nChannels = channels; - format.nSamplesPerSec = rate; - format.nAvgBytesPerSec = format.nSamplesPerSec * format.nChannels * - bytesperSample; - format.nBlockAlign = format.nChannels * bytesperSample; - - nBlocksInQue_ = 0; - HRESULT res = waveOutOpen (&dev_, WAVE_MAPPER, &format, (DWORD) wave_callback, - (DWORD) this, bCallback ? CALLBACK_FUNCTION : 0); - if (res == S_OK) - { - debug_printf ("Sucessfully opened!"); - return true; - } - else - { - debug_printf ("failed to open"); - return false; - } -} - -void -Audio::close () -{ - if (dev_) - { - flush (); // force out last block whatever size.. - - while (blocks ()) // block till finished.. - waitforcallback (); - - waveOutReset (dev_); - waveOutClose (dev_); - dev_ = 0L; - } - nBytesWritten_ = 0L; -} - -int -Audio::numbytesoutput () -{ - return nBytesWritten_; -} - -int -Audio::getvolume () -{ - DWORD volume; - - waveOutGetVolume (dev_, &volume); - return ((volume >> 16) + (volume & 0xffff)) >> 1; -} - -void -Audio::setvolume (int newVolume) -{ - waveOutSetVolume (dev_, (newVolume << 16) | newVolume); -} - -char * -Audio::initialisebuffer () -{ - EnterCriticalSection (&lock_); - WAVEHDR *pHeader = 0L; - for (int i = 0; i < MAX_BLOCKS; i++) - { - char *pData = freeblocks_[i]; - if (pData) - { - pHeader = (WAVEHDR *) pData; - if (pHeader->dwFlags & WHDR_DONE) - { - waveOutUnprepareHeader (dev_, pHeader, sizeof (WAVEHDR)); - } - freeblocks_[i] = 0L; - break; - } - } - LeaveCriticalSection (&lock_); - - if (pHeader) - { - memset (pHeader, 0, sizeof (WAVEHDR)); - pHeader->dwBufferLength = BLOCK_SIZE; - pHeader->lpData = (LPSTR) (&pHeader[1]); - return (char *) pHeader->lpData; - } - return 0L; -} - -bool -Audio::write (const void *pSampleData, int nBytes) -{ - // split up big blocks into smaller BLOCK_SIZE chunks - while (nBytes > BLOCK_SIZE) - { - write (pSampleData, BLOCK_SIZE); - nBytes -= BLOCK_SIZE; - pSampleData = (void *) ((char *) pSampleData + BLOCK_SIZE); - } - - // Block till next sound is flushed - if (blocks () == MAX_BLOCKS) - waitforcallback (); - - // Allocate new wave buffer if necessary - if (buffer_ == 0L) - { - buffer_ = initialisebuffer (); - if (buffer_ == 0L) - return false; - } - - - // Handle gathering blocks into larger buffer - int sizeleft = BLOCK_SIZE - bufferIndex_; - if (nBytes < sizeleft) - { - memcpy (&buffer_[bufferIndex_], pSampleData, nBytes); - bufferIndex_ += nBytes; - nBytesWritten_ += nBytes; - return true; - } - - // flushing when we reach our limit of BLOCK_SIZE - memcpy (&buffer_[bufferIndex_], pSampleData, sizeleft); - bufferIndex_ += sizeleft; - nBytesWritten_ += sizeleft; - flush (); - - // change pointer to rest of sample, and size accordingly - pSampleData = (void *) ((char *) pSampleData + sizeleft); - nBytes -= sizeleft; - - // if we still have some sample left over write it out - if (nBytes) - return write (pSampleData, nBytes); - - return true; -} - -// return number of blocks back. -int -Audio::blocks () -{ - EnterCriticalSection (&lock_); - int ret = nBlocksInQue_; - LeaveCriticalSection (&lock_); - return ret; -} - -// This is called on an interupt so use locking.. Note nBlocksInQue_ is -// modified by it so we should wrap all references to it in locks. -void -Audio::callback_sampledone (void *pData) -{ - EnterCriticalSection (&lock_); - - nBlocksInQue_--; - for (int i = 0; i < MAX_BLOCKS; i++) - if (!freeblocks_[i]) - { - freeblocks_[i] = (char *) pData; - break; - } - - LeaveCriticalSection (&lock_); -} - -void -Audio::waitforcallback () -{ - int n = blocks (); - if (!n) - return; - do - { - Sleep (250); - } - while (n == blocks ()); -} - -bool -Audio::flush () -{ - if (!buffer_) - return false; - - // Send internal buffer out to the soundcard - WAVEHDR *pHeader = ((WAVEHDR *) buffer_) - 1; - pHeader->dwBufferLength = bufferIndex_; - - // Quick bit of sample buffer conversion - if (formattype_ == AFMT_S8) - { - unsigned char *p = ((unsigned char *) buffer_); - for (int i = 0; i < bufferIndex_; i++) - { - p[i] -= 0x7f; - } - } - - if (waveOutPrepareHeader (dev_, pHeader, sizeof (WAVEHDR)) == S_OK && - waveOutWrite (dev_, pHeader, sizeof (WAVEHDR)) == S_OK) - { - EnterCriticalSection (&lock_); - nBlocksInQue_++; - LeaveCriticalSection (&lock_); - bufferIndex_ = 0; - buffer_ = 0L; - return true; - } - else - { - EnterCriticalSection (&lock_); - for (int i = 0; i < MAX_BLOCKS; i++) - if (!freeblocks_[i]) - { - freeblocks_[i] = (char *) pHeader; - break; - } - LeaveCriticalSection (&lock_); - } - return false; -} - -//------------------------------------------------------------------------ -// Call back routine -static void CALLBACK -wave_callback (HWAVE hWave, UINT msg, DWORD instance, DWORD param1, - DWORD param2) -{ - if (msg == WOM_DONE) - { - Audio *ptr = (Audio *) instance; - ptr->callback_sampledone ((void *) param1); - } -} - -//------------------------------------------------------------------------ -// /dev/dsp handler -static Audio *s_audio; // static instance of the Audio handler - -//------------------------------------------------------------------------ -// wav file detection.. -#pragma pack(1) -struct wavchunk -{ - char id[4]; - unsigned int len; -}; -struct wavformat -{ - unsigned short wFormatTag; - unsigned short wChannels; - unsigned int dwSamplesPerSec; - unsigned int dwAvgBytesPerSec; - unsigned short wBlockAlign; - unsigned short wBitsPerSample; -}; -#pragma pack() - -bool -fhandler_dev_dsp::setupwav (const char *pData, int nBytes) -{ - int len; - const char *end = pData + nBytes; - - if (!(pData[0] == 'R' && pData[1] == 'I' && - pData[2] == 'F' && pData[3] == 'F')) - return false; - if (!(pData[8] == 'W' && pData[9] == 'A' && - pData[10] == 'V' && pData[11] == 'E')) - return false; - - len = *(int *) &pData[4]; - pData += 12; - while (len && pData < end) - { - wavchunk * pChunk = (wavchunk *) pData; - int blklen = pChunk-> len; - if (pChunk->id[0] == 'f' && pChunk->id[1] == 'm' && - pChunk->id[2] == 't' && pChunk->id[3] == ' ') - { - wavformat *format = (wavformat *) (pChunk + 1); - if ((char *) (format + 1) > end) - return false; - - // Open up audio device with correct frequency for wav file - // - // FIXME: should through away all the header & not output - // it to the soundcard. - s_audio->close (); - if (s_audio->open (format->dwSamplesPerSec, format->wBitsPerSample, - format->wChannels) == false) - { - s_audio->open (audiofreq_, audiobits_, audiochannels_); - } - else - { - audiofreq_ = format->dwSamplesPerSec; - audiobits_ = format->wBitsPerSample; - audiochannels_ = format->wChannels; - } - return true; - } - - pData += blklen + sizeof (wavchunk); - } - return false; -} - -//------------------------------------------------------------------------ -fhandler_dev_dsp::fhandler_dev_dsp (): - fhandler_base (FH_OSS_DSP) -{ -} - -fhandler_dev_dsp::~fhandler_dev_dsp () -{ -} - -int -fhandler_dev_dsp::open (path_conv *, int flags, mode_t mode) -{ - // currently we only support writing - if ((flags & (O_WRONLY | O_RDONLY | O_RDWR)) != O_WRONLY) - { - set_errno (EACCES); - return 0; - } - - set_flags ((flags & ~O_TEXT) | O_BINARY); - - if (!s_audio) - s_audio = new (audio_buf) Audio; - - // Work out initial sample format & frequency - // dev/dsp defaults - audioformat_ = AFMT_S8; - audiofreq_ = 8000; - audiobits_ = 8; - audiochannels_ = 1; - - int res; - if (!s_audio->open (audiofreq_, audiobits_, audiochannels_)) - res = 0; - else - { - set_open_status (); - res = 1; - } - - debug_printf ("returns %d", res); - return res; -} - -int -fhandler_dev_dsp::write (const void *ptr, size_t len) -{ - if (s_audio->numbytesoutput () == 0) - { - // check for wave file & setup frequencys properly if possible. - setupwav ((const char *) ptr, len); - - // Open audio device properly with callbacks. - s_audio->close (); - if (!s_audio->open (audiofreq_, audiobits_, audiochannels_, true)) - return 0; - } - - s_audio->write (ptr, len); - return len; -} - -int __stdcall -fhandler_dev_dsp::read (void *ptr, size_t len) -{ - return len; -} - -__off64_t -fhandler_dev_dsp::lseek (__off64_t offset, int whence) -{ - return 0; -} - -int -fhandler_dev_dsp::close (void) -{ - s_audio->close (); - return 0; -} - -int -fhandler_dev_dsp::dup (fhandler_base * child) -{ - fhandler_dev_dsp *fhc = (fhandler_dev_dsp *) child; - - fhc->set_flags (get_flags ()); - fhc->audiochannels_ = audiochannels_; - fhc->audiobits_ = audiobits_; - fhc->audiofreq_ = audiofreq_; - fhc->audioformat_ = audioformat_; - return 0; -} - -int -fhandler_dev_dsp::ioctl (unsigned int cmd, void *ptr) -{ - int *intptr = (int *) ptr; - switch (cmd) - { -#define CASE(a) case a : debug_printf("/dev/dsp: ioctl %s\n", #a); - - CASE (SNDCTL_DSP_RESET) - audioformat_ = AFMT_S8; - audiofreq_ = 8000; - audiobits_ = 8; - audiochannels_ = 1; - return 0; - - CASE (SNDCTL_DSP_GETBLKSIZE) - *intptr = Audio::BLOCK_SIZE; - return 0; - - CASE (SNDCTL_DSP_SETFMT) - { - int nBits = 0; - if (*intptr == AFMT_S16_LE) - nBits = 16; - else if (*intptr == AFMT_U8) - nBits = 8; - else if (*intptr == AFMT_S8) - nBits = 8; - if (nBits) - { - s_audio->setformat (*intptr); - s_audio->close (); - if (s_audio->open (audiofreq_, nBits, audiochannels_) == true) - { - audiobits_ = nBits; - return 0; - } - else - { - s_audio->open (audiofreq_, audiobits_, audiochannels_); - return -1; - } - } - } - break; - - CASE (SNDCTL_DSP_SPEED) - s_audio->close (); - if (s_audio->open (*intptr, audiobits_, audiochannels_) == true) - { - audiofreq_ = *intptr; - return 0; - } - else - { - s_audio->open (audiofreq_, audiobits_, audiochannels_); - return -1; - } - break; - - CASE (SNDCTL_DSP_STEREO) - { - int nChannels = *intptr + 1; - - s_audio->close (); - if (s_audio->open (audiofreq_, audiobits_, nChannels) == true) - { - audiochannels_ = nChannels; - return 0; - } - else - { - s_audio->open (audiofreq_, audiobits_, audiochannels_); - return -1; - } - } - break; - - CASE (SNDCTL_DSP_GETOSPACE) - { - audio_buf_info *p = (audio_buf_info *) ptr; - - int nBlocks = s_audio->blocks (); - int leftblocks = ((Audio::MAX_BLOCKS - nBlocks) - 1); - if (leftblocks < 0) - leftblocks = 0; - if (leftblocks > 1) - leftblocks = 1; - int left = leftblocks * Audio::BLOCK_SIZE; - - p->fragments = leftblocks; - p->fragstotal = Audio::MAX_BLOCKS; - p->fragsize = Audio::BLOCK_SIZE; - p->bytes = left; - - debug_printf ("ptr %p nblocks %d leftblocks %d left bytes %d ", - ptr, nBlocks, leftblocks, left); - - return 0; - } - break; - - CASE (SNDCTL_DSP_SETFRAGMENT) - { - // Fake!! esound & mikmod require this on non PowerPC platforms. - // - return 0; - } - break; - - default: - debug_printf ("/dev/dsp: ioctl not handled yet! FIXME:\n"); - break; - -#undef CASE - }; - return -1; -} - -void -fhandler_dev_dsp::dump () -{ - paranoid_printf ("here, fhandler_dev_dsp"); -} - -void -fhandler_dev_dsp::fixup_after_exec (HANDLE) -{ - /* FIXME: Is there a better way to do this? */ - s_audio = new (audio_buf) Audio; -} |