]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - snd_bsd.c
don't load images when running a dedicated server (they would only be discarded by...
[xonotic/darkplaces.git] / snd_bsd.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
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.
8
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.
12
13 See the GNU General Public License for more details.
14
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.
18
19 */
20
21 #include <sys/param.h>
22 #include <sys/audioio.h>
23 #ifndef SUNOS
24 #include <sys/endian.h>
25 #endif
26 #include <sys/ioctl.h>
27
28 #include <fcntl.h>
29 #ifndef SUNOS
30 #include <paths.h>
31 #endif
32 #include <unistd.h>
33
34 #include "quakedef.h"
35 #include "snd_main.h"
36
37
38 static const int tryrates[] = {44100, 22050, 11025, 8000};
39
40 static int audio_fd = -1;
41 static qboolean snd_inited = false;
42
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];
48
49
50 qboolean SNDDMA_Init (void)
51 {
52         unsigned int i;
53         const char *snddev;
54         audio_info_t info;
55
56         memset ((void*)shm, 0, sizeof (*shm));
57
58         // Open the audio device
59 #ifdef _PATH_SOUND
60         snddev = _PATH_SOUND;
61 #else
62 #ifndef SUNOS
63         snddev = "/dev/sound";
64 #else
65         snddev = "/dev/audio";
66 #endif
67 #endif
68         audio_fd = open (snddev, O_WRONLY | O_NDELAY | O_NONBLOCK);
69         if (audio_fd < 0)
70         {
71                 Con_Printf("Can't open the sound device (%s)\n", snddev);
72                 return false;
73         }
74
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++)
81         {
82                 shm->format.speed = tryrates[i];
83
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;
91 #else
92 #ifndef SUNOS
93                 info.play.encoding = AUDIO_ENCODING_SLINEAR_LE;
94 #else
95                 info.play.encoding = AUDIO_ENCODING_LINEAR;
96 #endif
97 #endif
98                 if (ioctl (audio_fd, AUDIO_SETINFO, &info) == 0)
99                         break;
100         }
101         if (i == sizeof (tryrates) / sizeof (tryrates[0]))
102         {
103                 Con_Print("Can't select an appropriate sound output format\n");
104                 close (audio_fd);
105                 return false;
106         }
107
108         // Print some information
109         Con_Printf("%d bit %s sound initialized (rate: %dHz)\n",
110                                 info.play.precision,
111                                 (info.play.channels == 2) ? "stereo" : "mono",
112                                 info.play.sample_rate);
113
114         shm->sampleframes = sizeof (dma_buffer) / shm->format.width / shm->format.channels;
115         shm->samples = shm->sampleframes * shm->format.channels;
116         shm->samplepos = 0;
117         shm->buffer = dma_buffer;
118
119         snd_inited = true;
120         return true;
121 }
122
123 int SNDDMA_GetDMAPos (void)
124 {
125         audio_info_t info;
126
127         if (!snd_inited)
128                 return 0;
129
130         if (ioctl (audio_fd, AUDIO_GETINFO, &info) < 0)
131         {
132                 Con_Print("Error: can't get audio info\n");
133                 SNDDMA_Shutdown ();
134                 return 0;
135         }
136
137         return ((info.play.samples * shm->format.channels) % shm->samples);
138 }
139
140 void SNDDMA_Shutdown (void)
141 {
142         if (snd_inited)
143         {
144                 close (audio_fd);
145                 audio_fd = -1;
146                 snd_inited = false;
147         }
148 }
149
150 /*
151 ==============
152 SNDDMA_Submit
153
154 Send sound to device if buffer isn't really the dma buffer
155 ===============
156 */
157 void SNDDMA_Submit (void)
158 {
159         int bsize;
160         int bytes, b;
161         static int wbufp = 0;
162         unsigned char *p;
163         int idx;
164         int stop = paintedtime;
165
166         if (!snd_inited)
167                 return;
168
169         if (paintedtime < wbufp)
170                 wbufp = 0; // reset
171
172         bsize = shm->format.channels * shm->format.width;
173         bytes = (paintedtime - wbufp) * bsize;
174
175         if (!bytes)
176                 return;
177
178         if (bytes > sizeof (writebuf))
179         {
180                 bytes = sizeof (writebuf);
181                 stop = wbufp + bytes / bsize;
182         }
183
184         // Transfert the sound data from the circular dma_buffer to writebuf
185         // TODO: using 2 memcpys instead of this loop should be faster
186         p = writebuf;
187         idx = (wbufp*bsize) & (sizeof (dma_buffer) - 1);
188         for (b = bytes; b; b--)
189         {
190                 *p++ = dma_buffer[idx];
191                 idx = (idx + 1) & (sizeof (dma_buffer) - 1);
192         }
193
194         if (write (audio_fd, writebuf, bytes) < bytes)
195                 Con_Print("audio can't keep up!\n");
196
197         wbufp = stop;
198 }
199
200 void *S_LockBuffer (void)
201 {
202         return shm->buffer;
203 }
204
205 void S_UnlockBuffer (void)
206 {
207 }