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