This is the mail archive of the
cygwin-patches@cygwin.com
mailing list for the Cygwin project.
setfragment patch for sound device
- From: "peter garrone" <pgarrone at linuxmail dot org>
- To: cygwin-patches at cygwin dot com
- Date: Thu, 11 Sep 2003 12:29:12 +0800
- Subject: setfragment patch for sound device
The following patch to the /dev/dsp sound device does the following:
- implements SNDCTL_DSP_SETFRAGMENT, allowing smaller sound buffers to be used.
- trivially implements SNDCTL_DSP_CHANNELS.
- opens and closes the class device upon SNDCTL_DSP_RESET.
- Uses win32 event to signal buffer output completion, instead of only a delay
I have only tested my own proprietary application. It compiled and ran without change, so,
of course, has to be buggy.
--- tmp/fhandler_dsp.cc 2003-09-11 08:32:15.796875000 +1000
+++ src/winsup/cygwin/fhandler_dsp.cc 2003-09-11 12:43:23.437500000 +1000
@@ -44,10 +44,13 @@
bool write (const void *pSampleData, int nBytes);
int blocks ();
void callback_sampledone (void *pData);
void setformat (int format) {formattype_ = format;}
int numbytesoutput ();
+ void setfragment(int arg);
+ inline int get_fragment_size(void){ return fragment_size;}
+ inline int get_fragment_count(void){ return fragment_count;}
void *operator new (size_t, void *p) {return p;}
private:
char *initialisebuffer ();
@@ -61,10 +64,14 @@
int bufferIndex_;
CRITICAL_SECTION lock_;
char *freeblocks_[MAX_BLOCKS];
int formattype_;
+ int fragment_size;
+ int fragment_count;
+ HANDLE callback_sync;
+
char bigwavebuffer_[MAX_BLOCKS * TOT_BLOCK_SIZE];
};
static char audio_buf[sizeof (class Audio)];
@@ -72,17 +79,21 @@
{
InitializeCriticalSection (&lock_);
memset (bigwavebuffer_, 0, sizeof (bigwavebuffer_));
for (int i = 0; i < MAX_BLOCKS; i++)
freeblocks_[i] = &bigwavebuffer_[i * TOT_BLOCK_SIZE];
+ fragment_size = BLOCK_SIZE;
+ fragment_count = MAX_BLOCKS;
+ callback_sync = CreateEvent(NULL, FALSE, FALSE, NULL);
}
Audio::~Audio ()
{
if (dev_)
close ();
DeleteCriticalSection (&lock_);
+ CloseHandle(callback_sync);
}
bool
Audio::open (int rate, int bits, int channels, bool bCallback)
{
@@ -186,30 +197,30 @@
LeaveCriticalSection (&lock_);
if (pHeader)
{
memset (pHeader, 0, sizeof (WAVEHDR));
- pHeader->dwBufferLength = BLOCK_SIZE;
+ pHeader->dwBufferLength = fragment_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)
+ while (nBytes > fragment_size)
{
- write (pSampleData, BLOCK_SIZE);
- nBytes -= BLOCK_SIZE;
- pSampleData = (void *) ((char *) pSampleData + BLOCK_SIZE);
+ write (pSampleData, fragment_size);
+ nBytes -= fragment_size;
+ pSampleData = (void *) ((char *) pSampleData + fragment_size);
}
// Block till next sound is flushed
- if (blocks () == MAX_BLOCKS)
+ if (blocks () == fragment_count)
waitforcallback ();
// Allocate new wave buffer if necessary
if (buffer_ == 0L)
{
@@ -218,20 +229,21 @@
return false;
}
// Handle gathering blocks into larger buffer
- int sizeleft = BLOCK_SIZE - bufferIndex_;
+ int sizeleft = fragment_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
+ // (now fragment_size not BLOCK_SIZE)
memcpy (&buffer_[bufferIndex_], pSampleData, sizeleft);
bufferIndex_ += sizeleft;
nBytesWritten_ += sizeleft;
flush ();
@@ -270,21 +282,22 @@
freeblocks_[i] = (char *) pData;
break;
}
LeaveCriticalSection (&lock_);
+ SetEvent(callback_sync);
}
void
Audio::waitforcallback ()
{
int n = blocks ();
if (!n)
return;
do
{
- Sleep (250);
+ WaitForSingleObject(callback_sync, 250);
}
while (n == blocks ());
}
bool
@@ -329,10 +342,41 @@
LeaveCriticalSection (&lock_);
}
return false;
}
+void
+Audio::setfragment(int arg)
+{
+ /*
+ * Information here is derived from 4front technologies
+ * Open Sound System Programming Guide version 1.11
+ */
+ int max_log_size = 0;
+ int count = (arg>>16)&0x0ffff;
+ int log_size = (arg)&0x0ffff;
+
+ int n = BLOCK_SIZE;
+ while((n&1)==0)
+ {
+ n >>= 1;
+ max_log_size++;
+ }
+
+ if(log_size == 0)log_size = max_log_size;
+ else if(log_size < 8)log_size = 8;
+ else if(log_size > max_log_size)log_size = max_log_size;
+
+ fragment_size = 1 << log_size;
+
+ if(count == 0)count = MAX_BLOCKS;
+ else if(count < 2)count = 2;
+ else if(count > MAX_BLOCKS)count = MAX_BLOCKS;
+
+ fragment_count = count;
+}
+
//------------------------------------------------------------------------
// Call back routine
static void CALLBACK
wave_callback (HWAVE hWave, UINT msg, DWORD instance, DWORD param1,
DWORD param2)
@@ -519,18 +563,21 @@
switch (cmd)
{
#define CASE(a) case a : debug_printf("/dev/dsp: ioctl %s", #a);
CASE (SNDCTL_DSP_RESET)
+ s_audio->close ();
audioformat_ = AFMT_S8;
audiofreq_ = 8000;
audiobits_ = 8;
audiochannels_ = 1;
+ s_audio->setfragment(0xffffffff);
+ s_audio->open (audiofreq_, audiobits_, audiochannels_);
return 0;
CASE (SNDCTL_DSP_GETBLKSIZE)
- *intptr = Audio::BLOCK_SIZE;
+ *intptr = s_audio->get_fragment_size();
return 0;
CASE (SNDCTL_DSP_SETFMT)
{
int nBits = 0;
@@ -571,12 +618,14 @@
return -1;
}
break;
CASE (SNDCTL_DSP_STEREO)
+ CASE (SNDCTL_DSP_CHANNELS)
{
- int nChannels = *intptr + 1;
+ int nChannels = *intptr;
+ if(cmd == SNDCTL_DSP_STEREO)nChannels++;
s_audio->close ();
if (s_audio->open (audiofreq_, audiobits_, nChannels) == true)
{
audiochannels_ = nChannels;
@@ -593,20 +642,20 @@
CASE (SNDCTL_DSP_GETOSPACE)
{
audio_buf_info *p = (audio_buf_info *) ptr;
int nBlocks = s_audio->blocks ();
- int leftblocks = ((Audio::MAX_BLOCKS - nBlocks) - 1);
+ int leftblocks = ((s_audio->get_fragment_count() - nBlocks) - 1);
if (leftblocks < 0)
leftblocks = 0;
if (leftblocks > 1)
leftblocks = 1;
- int left = leftblocks * Audio::BLOCK_SIZE;
+ int left = leftblocks * s_audio->get_fragment_size();
p->fragments = leftblocks;
- p->fragstotal = Audio::MAX_BLOCKS;
- p->fragsize = Audio::BLOCK_SIZE;
+ p->fragstotal = s_audio->get_fragment_count();
+ p->fragsize = s_audio->get_fragment_size();
p->bytes = left;
debug_printf ("ptr %p nblocks %d leftblocks %d left bytes %d ",
ptr, nBlocks, leftblocks, left);
@@ -614,12 +663,13 @@
}
break;
CASE (SNDCTL_DSP_SETFRAGMENT)
{
- // Fake!! esound & mikmod require this on non PowerPC platforms.
- //
+ s_audio->close ();
+ s_audio->setfragment(*intptr);
+ s_audio->open (audiofreq_, audiobits_, audiochannels_);
return 0;
}
break;
CASE (SNDCTL_DSP_GETFMTS)
--
______________________________________________
http://www.linuxmail.org/
Now with e-mail forwarding for only US$5.95/yr
Powered by Outblaze