added ogg.o to WGL exe build
[divverent/darkplaces.git] / snd_oss.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 #include <unistd.h>
21 #include <fcntl.h>
22 #include <stdlib.h>
23 #include <sys/types.h>
24 #include <sys/ioctl.h>
25 #include <sys/mman.h>
26 #include <sys/shm.h>
27 #include <sys/wait.h>
28 #include <sys/soundcard.h>
29 #include <stdio.h>
30 #include "quakedef.h"
31
32 int audio_fd;
33 int snd_inited;
34
35 static int tryrates[] = {44100, 22051, 11025, 8000};
36
37 qboolean SNDDMA_Init(void)
38 {
39         int rc;
40         int fmt;
41         int tmp;
42         int i;
43         char *s;
44         struct audio_buf_info info;
45         int caps;
46         int format16bit;
47         // LordHavoc: a quick patch to support big endian cpu, I hope
48         union
49         {
50                 unsigned char c[2];
51                 unsigned short s;
52         }
53         endiantest;
54         endiantest.s = 1;
55         if (endiantest.c[1])
56                 format16bit = AFMT_S16_BE;
57         else
58                 format16bit = AFMT_S16_LE;
59
60         snd_inited = 0;
61
62         // open /dev/dsp, confirm capability to mmap, and get size of dma buffer
63     audio_fd = open("/dev/dsp", O_RDWR);
64         if (audio_fd < 0)
65         {
66                 perror("/dev/dsp");
67                 Con_Printf("Could not open /dev/dsp\n");
68                 return 0;
69         }
70
71         if (ioctl(audio_fd, SNDCTL_DSP_RESET, 0) < 0)
72         {
73                 perror("/dev/dsp");
74                 Con_Printf("Could not reset /dev/dsp\n");
75                 close(audio_fd);
76                 return 0;
77         }
78
79         if (ioctl(audio_fd, SNDCTL_DSP_GETCAPS, &caps)==-1)
80         {
81                 perror("/dev/dsp");
82                 Con_Printf("Sound driver too old\n");
83                 close(audio_fd);
84                 return 0;
85         }
86
87         if (!(caps & DSP_CAP_TRIGGER) || !(caps & DSP_CAP_MMAP))
88         {
89                 Con_Printf("Sorry but your soundcard can't do this\n");
90                 close(audio_fd);
91                 return 0;
92         }
93
94         if (ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info)==-1)
95         {
96                 perror("GETOSPACE");
97                 Con_Printf("Um, can't do GETOSPACE?\n");
98                 close(audio_fd);
99                 return 0;
100         }
101
102         // set sample bits & speed
103         s = getenv("QUAKE_SOUND_SAMPLEBITS");
104         if (s)
105                 shm->samplebits = atoi(s);
106         else if ((i = COM_CheckParm("-sndbits")) != 0)
107                 shm->samplebits = atoi(com_argv[i+1]);
108
109         if (shm->samplebits != 16 && shm->samplebits != 8)
110         {
111                 ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &fmt);
112                 if (fmt & format16bit)
113                         shm->samplebits = 16;
114                 else if (fmt & AFMT_U8)
115                         shm->samplebits = 8;
116     }
117
118         s = getenv("QUAKE_SOUND_SPEED");
119         if (s)
120                 shm->speed = atoi(s);
121         else if ((i = COM_CheckParm("-sndspeed")) != 0)
122                 shm->speed = atoi(com_argv[i+1]);
123         else
124         {
125                 for (i = 0;i < (int) sizeof(tryrates) / 4;i++)
126                         if (!ioctl(audio_fd, SNDCTL_DSP_SPEED, &tryrates[i]))
127                                 break;
128
129                 shm->speed = tryrates[i];
130     }
131
132         s = getenv("QUAKE_SOUND_CHANNELS");
133         if (s)
134                 shm->channels = atoi(s);
135         else if ((i = COM_CheckParm("-sndmono")) != 0)
136                 shm->channels = 1;
137         else if ((i = COM_CheckParm("-sndstereo")) != 0)
138                 shm->channels = 2;
139         else
140                 shm->channels = 2;
141
142         shm->samples = info.fragstotal * info.fragsize / (shm->samplebits/8);
143
144         // memory map the dma buffer
145         shm->bufferlength = info.fragstotal * info.fragsize;
146         shm->buffer = (unsigned char *) mmap(NULL, shm->bufferlength, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, audio_fd, 0);
147         if (!shm->buffer || shm->buffer == (unsigned char *)-1)
148         {
149                 perror("/dev/dsp");
150                 Con_Printf("Could not mmap /dev/dsp\n");
151                 close(audio_fd);
152                 return 0;
153         }
154
155         tmp = 0;
156         if (shm->channels == 2)
157                 tmp = 1;
158
159         rc = ioctl(audio_fd, SNDCTL_DSP_STEREO, &tmp);
160         if (rc < 0)
161         {
162                 perror("/dev/dsp");
163                 Con_Printf("Could not set /dev/dsp to stereo=%d", shm->channels);
164                 close(audio_fd);
165                 return 0;
166         }
167         if (tmp)
168                 shm->channels = 2;
169         else
170                 shm->channels = 1;
171
172         rc = ioctl(audio_fd, SNDCTL_DSP_SPEED, &shm->speed);
173         if (rc < 0)
174         {
175                 perror("/dev/dsp");
176                 Con_Printf("Could not set /dev/dsp speed to %d", shm->speed);
177                 close(audio_fd);
178                 return 0;
179         }
180
181         if (shm->samplebits == 16)
182         {
183                 rc = format16bit;
184                 rc = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &rc);
185                 if (rc < 0)
186                 {
187                         perror("/dev/dsp");
188                         Con_Printf("Could not support 16-bit data.  Try 8-bit.\n");
189                         close(audio_fd);
190                         return 0;
191                 }
192         }
193         else if (shm->samplebits == 8)
194         {
195                 rc = AFMT_U8;
196                 rc = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &rc);
197                 if (rc < 0)
198                 {
199                         perror("/dev/dsp");
200                         Con_Printf("Could not support 8-bit data.\n");
201                         close(audio_fd);
202                         return 0;
203                 }
204         }
205         else
206         {
207                 perror("/dev/dsp");
208                 Con_Printf("%d-bit sound not supported.", shm->samplebits);
209                 close(audio_fd);
210                 return 0;
211         }
212
213         // toggle the trigger & start her up
214         tmp = 0;
215         rc  = ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp);
216         if (rc < 0)
217         {
218                 perror("/dev/dsp");
219                 Con_Printf("Could not toggle.\n");
220                 close(audio_fd);
221                 return 0;
222         }
223         tmp = PCM_ENABLE_OUTPUT;
224         rc = ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp);
225         if (rc < 0)
226         {
227                 perror("/dev/dsp");
228                 Con_Printf("Could not toggle.\n");
229                 close(audio_fd);
230                 return 0;
231         }
232
233         shm->samplepos = 0;
234
235         snd_inited = 1;
236         return 1;
237 }
238
239 int SNDDMA_GetDMAPos(void)
240 {
241
242         struct count_info count;
243
244         if (!snd_inited) return 0;
245
246         if (ioctl(audio_fd, SNDCTL_DSP_GETOPTR, &count)==-1)
247         {
248                 perror("/dev/dsp");
249                 Con_Printf("Uh, sound dead.\n");
250                 close(audio_fd);
251                 snd_inited = 0;
252                 return 0;
253         }
254         shm->samplepos = count.ptr / (shm->samplebits / 8);
255
256         return shm->samplepos;
257 }
258
259 void SNDDMA_Shutdown(void)
260 {
261         int tmp;
262         if (snd_inited)
263         {
264                 // unmap the memory
265                 munmap(shm->buffer, shm->bufferlength);
266                 // stop the sound
267                 tmp = 0;
268                 ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp);
269                 ioctl(audio_fd, SNDCTL_DSP_RESET, 0);
270                 // close the device
271                 close(audio_fd);
272                 audio_fd = -1;
273                 snd_inited = 0;
274         }
275 }
276
277 /*
278 ==============
279 SNDDMA_Submit
280
281 Send sound to device if buffer isn't really the dma buffer
282 ===============
283 */
284 void SNDDMA_Submit(void)
285 {
286 }
287
288 void *S_LockBuffer(void)
289 {
290         return shm->buffer;
291 }
292
293 void S_UnlockBuffer(void)
294 {
295 }
296