This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#include "quakedef.h"
#include <sys/param.h>
#include <sys/audioio.h>
-#include <sys/endian.h>
+#ifndef SUNOS
+# include <sys/endian.h>
+#endif
#include <sys/ioctl.h>
#include <fcntl.h>
-#include <paths.h>
+#ifndef SUNOS
+# include <paths.h>
+#endif
#include <unistd.h>
-#include "quakedef.h"
-
+#include "snd_main.h"
-static const int tryrates[] = {44100, 22051, 11025, 8000};
static int audio_fd = -1;
-static qboolean snd_inited = false;
-// TODO: allocate them in SNDDMA_Init, with a size depending on
-// the sound format (enough for 0.5 sec of sound for instance)
-#define SND_BUFF_SIZE 65536
-static qbyte dma_buffer [SND_BUFF_SIZE];
-static qbyte writebuf [SND_BUFF_SIZE];
+/*
+====================
+SndSys_Init
-qboolean SNDDMA_Init (void)
+Create "snd_renderbuffer" with the proper sound format if the call is successful
+May return a suggested format if the requested format isn't available
+====================
+*/
+qboolean SndSys_Init (const snd_format_t* requested, snd_format_t* suggested)
{
unsigned int i;
- const char *snddev = _PATH_SOUND;
+ const char *snddev;
audio_info_t info;
- memset ((void*)shm, 0, sizeof (*shm));
-
// Open the audio device
+#ifdef _PATH_SOUND
+ snddev = _PATH_SOUND;
+#elif defined(SUNOS)
+ snddev = "/dev/audio";
+#else
+ snddev = "/dev/sound";
+#endif
audio_fd = open (snddev, O_WRONLY | O_NDELAY | O_NONBLOCK);
if (audio_fd < 0)
{
- Con_Printf ("Can't open the sound device (%s)\n", snddev);
+ Con_Printf("Can't open the sound device (%s)\n", snddev);
return false;
}
- // Look for an appropriate sound format
- // TODO: we should also test mono/stereo and bits
- // TODO: support "-sndspeed", "-sndbits", "-sndmono" and "-sndstereo"
- shm->channels = 2;
- shm->samplebits = 16;
- for (i = 0; i < sizeof (tryrates) / sizeof (tryrates[0]); i++)
- {
- shm->speed = tryrates[i];
-
- AUDIO_INITINFO (&info);
- info.play.sample_rate = shm->speed;
- info.play.channels = shm->channels;
- info.play.precision = shm->samplebits;
-// We only handle sound cards of the same endianess than the CPU
-#if BYTE_ORDER == BIG_ENDIAN
- info.play.encoding = AUDIO_ENCODING_SLINEAR_BE;
+ AUDIO_INITINFO (&info);
+#ifdef AUMODE_PLAY // NetBSD / OpenBSD
+ info.mode = AUMODE_PLAY;
+#endif
+ info.play.sample_rate = requested->speed;
+ info.play.channels = requested->channels;
+ info.play.precision = requested->width * 8;
+ if (requested->width == 1)
+#ifdef SUNOS
+ info.play.encoding = AUDIO_ENCODING_LINEAR8;
+#else
+ info.play.encoding = AUDIO_ENCODING_ULINEAR;
+#endif
+ else
+#ifdef SUNOS
+ info.play.encoding = AUDIO_ENCODING_LINEAR;
#else
+ if (mem_bigendian)
+ info.play.encoding = AUDIO_ENCODING_SLINEAR_BE;
+ else
info.play.encoding = AUDIO_ENCODING_SLINEAR_LE;
#endif
- if (ioctl (audio_fd, AUDIO_SETINFO, &info) == 0)
- break;
- }
- if (i == sizeof (tryrates) / sizeof (tryrates[0]))
+
+ if (ioctl (audio_fd, AUDIO_SETINFO, &info) != 0)
{
- Con_Printf ("Can't select an appropriate sound output format\n");
- close (audio_fd);
+ Con_Printf("Can't set up the sound device (%s)\n", snddev);
return false;
}
- // Print some information
- Con_Printf ("%d bit %s sound initialized (rate: %dHz)\n",
- info.play.precision,
- (info.play.channels == 2) ? "stereo" : "mono",
- info.play.sample_rate);
+ // TODO: check the parameters with AUDIO_GETINFO
+ // TODO: check AUDIO_ENCODINGFLAG_EMULATED with AUDIO_GETENC
- shm->samples = sizeof (dma_buffer) / (shm->samplebits / 8);
- shm->samplepos = 0;
- shm->buffer = dma_buffer;
-
- snd_inited = true;
+ snd_renderbuffer = Snd_CreateRingBuffer(requested, 0, NULL);
return true;
}
-int SNDDMA_GetDMAPos (void)
-{
- audio_info_t info;
- if (!snd_inited)
- return 0;
+/*
+====================
+SndSys_Shutdown
- if (ioctl (audio_fd, AUDIO_GETINFO, &info) < 0)
+Stop the sound card, delete "snd_renderbuffer" and free its other resources
+====================
+*/
+void SndSys_Shutdown (void)
+{
+ if (audio_fd >= 0)
{
- Con_Printf ("Error: can't get audio info\n");
- SNDDMA_Shutdown ();
- return 0;
+ close(audio_fd);
+ audio_fd = -1;
}
- return ((info.play.samples * shm->channels) % shm->samples);
-}
-
-void SNDDMA_Shutdown (void)
-{
- if (snd_inited)
+ if (snd_renderbuffer != NULL)
{
- close (audio_fd);
- audio_fd = -1;
- snd_inited = false;
+ Mem_Free(snd_renderbuffer->ring);
+ Mem_Free(snd_renderbuffer);
+ snd_renderbuffer = NULL;
}
}
+
/*
-==============
-SNDDMA_Submit
+====================
+SndSys_Submit
-Send sound to device if buffer isn't really the dma buffer
-===============
+Submit the contents of "snd_renderbuffer" to the sound card
+====================
*/
-void SNDDMA_Submit (void)
+void SndSys_Submit (void)
{
- int bsize;
- int bytes, b;
- static int wbufp = 0;
- unsigned char *p;
- int idx;
- int stop = paintedtime;
-
- if (!snd_inited)
- return;
-
- if (paintedtime < wbufp)
- wbufp = 0; // reset
-
- bsize = shm->channels * (shm->samplebits / 8);
- bytes = (paintedtime - wbufp) * bsize;
+ unsigned int startoffset, factor, limit, nbframes;
+ int written;
- if (!bytes)
+ if (audio_fd < 0 ||
+ snd_renderbuffer->startframe == snd_renderbuffer->endframe)
return;
- if (bytes > sizeof (writebuf))
+ startoffset = snd_renderbuffer->startframe % snd_renderbuffer->maxframes;
+ factor = snd_renderbuffer->format.width * snd_renderbuffer->format.channels;
+ limit = snd_renderbuffer->maxframes - startoffset;
+ nbframes = snd_renderbuffer->endframe - snd_renderbuffer->startframe;
+ if (nbframes > limit)
{
- bytes = sizeof (writebuf);
- stop = wbufp + bytes / bsize;
+ written = write (audio_fd, &snd_renderbuffer->ring[startoffset * factor], limit * factor);
+ if (written < 0)
+ {
+ Con_Printf("SndSys_Submit: audio write returned %d!\n", written);
+ return;
+ }
+
+ if (written % factor != 0)
+ Sys_Error("SndSys_Submit: nb of bytes written (%d) isn't aligned to a frame sample!\n", written);
+
+ snd_renderbuffer->startframe += written / factor;
+
+ if ((unsigned int)written < limit * factor)
+ {
+ Con_Printf("SndSys_Submit: audio can't keep up! (%u < %u)\n", written, limit * factor);
+ return;
+ }
+
+ nbframes -= limit;
+ startoffset = 0;
+ }
+
+ written = write (audio_fd, &snd_renderbuffer->ring[startoffset * factor], nbframes * factor);
+ if (written < 0)
+ {
+ Con_Printf("SndSys_Submit: audio write returned %d!\n", written);
+ return;
}
+ snd_renderbuffer->startframe += written / factor;
+}
+
+
+/*
+====================
+SndSys_GetSoundTime
+
+Returns the number of sample frames consumed since the sound started
+====================
+*/
+unsigned int SndSys_GetSoundTime (void)
+{
+ audio_info_t info;
- // Transfert the sound data from the circular dma_buffer to writebuf
- // TODO: using 2 memcpys instead of this loop should be faster
- p = writebuf;
- idx = (wbufp*bsize) & (sizeof (dma_buffer) - 1);
- for (b = bytes; b; b--)
+ if (ioctl (audio_fd, AUDIO_GETINFO, &info) < 0)
{
- *p++ = dma_buffer[idx];
- idx = (idx + 1) & (sizeof (dma_buffer) - 1);
+ Con_Print("Error: can't get audio info\n");
+ SndSys_Shutdown ();
+ return 0;
}
- if (write (audio_fd, writebuf, bytes) < bytes)
- Con_Printf ("audio can't keep up!\n");
+ return info.play.samples;
+}
+
- wbufp = stop;
+/*
+====================
+SndSys_LockRenderBuffer
+
+Get the exclusive lock on "snd_renderbuffer"
+====================
+*/
+qboolean SndSys_LockRenderBuffer (void)
+{
+ // Nothing to do
+ return true;
}
-void *S_LockBuffer (void)
+
+/*
+====================
+SndSys_UnlockRenderBuffer
+
+Release the exclusive lock on "snd_renderbuffer"
+====================
+*/
+void SndSys_UnlockRenderBuffer (void)
{
- return shm->buffer;
+ // Nothing to do
}
-void S_UnlockBuffer (void)
+/*
+====================
+SndSys_SendKeyEvents
+
+Send keyboard events originating from the sound system (e.g. MIDI)
+====================
+*/
+void SndSys_SendKeyEvents(void)
{
+ // not supported
}