⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fhandler_dsp.cc

📁 cygwin, 著名的在win32下模拟unix操作系统的东东
💻 CC
字号:
/* 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 theCygwin license.  Please consult the file "CYGWIN_LICENSE" fordetails. */#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_);}boolAudio::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", nDevices);  if (nDevices <= 0)    return false;  debug_printf ("trying to map device freq %d, bits %d, "		"channels %d, callback %d", 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;    }}voidAudio::close (){  if (dev_)    {      flush ();			// force out last block whatever size..      while (blocks ())		// block till finished..	waitforcallback ();      waveOutReset (dev_);      waveOutClose (dev_);      dev_ = 0L;    }  nBytesWritten_ = 0L;}intAudio::numbytesoutput (){  return nBytesWritten_;}intAudio::getvolume (){  DWORD volume;  waveOutGetVolume (dev_, &volume);  return ((volume >> 16) + (volume & 0xffff)) >> 1;}voidAudio::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;}boolAudio::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.intAudio::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.voidAudio::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_);}voidAudio::waitforcallback (){  int n = blocks ();  if (!n)    return;  do    {      Sleep (250);    }  while (n == blocks ());}boolAudio::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 routinestatic void CALLBACKwave_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 handlerstatic 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()boolfhandler_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 (){}intfhandler_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;}intfhandler_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 __stdcallfhandler_dev_dsp::read (void *ptr, size_t len){  return len;}__off64_tfhandler_dev_dsp::lseek (__off64_t offset, int whence){  return 0;}intfhandler_dev_dsp::close (void){  s_audio->close ();  return 0;}intfhandler_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;}intfhandler_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", #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:");      break;#undef CASE    };  return -1;}voidfhandler_dev_dsp::dump (){  paranoid_printf ("here, fhandler_dev_dsp");}voidfhandler_dev_dsp::fixup_after_exec (HANDLE){  /* FIXME:  Is there a better way to do this? */  s_audio = new (audio_buf) Audio;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -