2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 #include <sys/param.h>
22 #include <sys/audioio.h>
24 #include <sys/endian.h>
26 #include <sys/ioctl.h>
38 static const int tryrates[] = {44100, 22050, 11025, 8000};
40 static int audio_fd = -1;
41 static qboolean snd_inited = false;
43 // TODO: allocate them in SNDDMA_Init, with a size depending on
44 // the sound format (enough for 0.5 sec of sound for instance)
45 #define SND_BUFF_SIZE 65536
46 static unsigned char dma_buffer [SND_BUFF_SIZE];
47 static unsigned char writebuf [SND_BUFF_SIZE];
50 qboolean SNDDMA_Init (void)
56 memset ((void*)shm, 0, sizeof (*shm));
58 // Open the audio device
63 snddev = "/dev/sound";
65 snddev = "/dev/audio";
68 audio_fd = open (snddev, O_WRONLY | O_NDELAY | O_NONBLOCK);
71 Con_Printf("Can't open the sound device (%s)\n", snddev);
75 // Look for an appropriate sound format
76 // TODO: we should also test mono/stereo and bits
77 // TODO: support "-sndspeed", "-sndbits", "-sndmono" and "-sndstereo"
78 shm->format.channels = 2;
79 shm->format.width = 2;
80 for (i = 0; i < sizeof (tryrates) / sizeof (tryrates[0]); i++)
82 shm->format.speed = tryrates[i];
84 AUDIO_INITINFO (&info);
85 info.play.sample_rate = shm->format.speed;
86 info.play.channels = shm->format.channels;
87 info.play.precision = shm->format.width * 8;
88 // We only handle sound cards of the same endianess than the CPU
89 #if BYTE_ORDER == BIG_ENDIAN
90 info.play.encoding = AUDIO_ENCODING_SLINEAR_BE;
93 info.play.encoding = AUDIO_ENCODING_SLINEAR_LE;
95 info.play.encoding = AUDIO_ENCODING_LINEAR;
98 if (ioctl (audio_fd, AUDIO_SETINFO, &info) == 0)
101 if (i == sizeof (tryrates) / sizeof (tryrates[0]))
103 Con_Print("Can't select an appropriate sound output format\n");
108 // Print some information
109 Con_Printf("%d bit %s sound initialized (rate: %dHz)\n",
111 (info.play.channels == 2) ? "stereo" : "mono",
112 info.play.sample_rate);
114 shm->samples = sizeof (dma_buffer) / shm->format.width;
116 shm->buffer = dma_buffer;
122 int SNDDMA_GetDMAPos (void)
129 if (ioctl (audio_fd, AUDIO_GETINFO, &info) < 0)
131 Con_Print("Error: can't get audio info\n");
136 return ((info.play.samples * shm->format.channels) % shm->samples);
139 void SNDDMA_Shutdown (void)
153 Send sound to device if buffer isn't really the dma buffer
156 void SNDDMA_Submit (void)
160 static int wbufp = 0;
163 int stop = paintedtime;
168 if (paintedtime < wbufp)
171 bsize = shm->format.channels * shm->format.width;
172 bytes = (paintedtime - wbufp) * bsize;
177 if (bytes > sizeof (writebuf))
179 bytes = sizeof (writebuf);
180 stop = wbufp + bytes / bsize;
183 // Transfert the sound data from the circular dma_buffer to writebuf
184 // TODO: using 2 memcpys instead of this loop should be faster
186 idx = (wbufp*bsize) & (sizeof (dma_buffer) - 1);
187 for (b = bytes; b; b--)
189 *p++ = dma_buffer[idx];
190 idx = (idx + 1) & (sizeof (dma_buffer) - 1);
193 if (write (audio_fd, writebuf, bytes) < bytes)
194 Con_Print("audio can't keep up!\n");
199 void *S_LockBuffer (void)
204 void S_UnlockBuffer (void)