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 <stdio.h>
29 #include <sys/audioio.h>
30 #include <errno.h>
31 #include "quakedef.h"
32
33 int audio_fd;
34 int snd_inited;
35
36 static int bufpos;
37 static int wbufp;
38 static audio_info_t info;
39
40 #define BUFFER_SIZE 8192
41
42 unsigned char dma_buffer[BUFFER_SIZE];
43 unsigned char pend_buffer[BUFFER_SIZE];
44 int pending;
45
46 static int lastwrite = 0;
47
SNDDMA_Init(void)48 qboolean SNDDMA_Init(void)
49 {
50 int rc;
51 int fmt;
52 int tmp;
53 int i;
54 char *s;
55 int caps;
56
57 if (snd_inited) {
58 printf("Sound already init'd\n");
59 return;
60 }
61
62 shm = &sn;
63 shm->splitbuffer = 0;
64
65 audio_fd = open("/dev/audio", O_WRONLY|O_NDELAY);
66
67 if (audio_fd < 0) {
68 if (errno == EBUSY) {
69 Con_Printf("Audio device is being used by another process\n");
70 }
71 perror("/dev/audio");
72 Con_Printf("Could not open /dev/audio\n");
73 return (0);
74 }
75
76 if (ioctl(audio_fd, AUDIO_GETINFO, &info) < 0) {
77 perror("/dev/audio");
78 Con_Printf("Could not communicate with audio device.\n");
79 close(audio_fd);
80 return 0;
81 }
82
83 //
84 // set to nonblock
85 //
86 if (fcntl(audio_fd, F_SETFL, O_NONBLOCK) < 0) {
87 perror("/dev/audio");
88 close(audio_fd);
89 return 0;
90 }
91
92 AUDIO_INITINFO(&info);
93
94 shm->speed = 11025;
95
96 // try 16 bit stereo
97 info.play.encoding = AUDIO_ENCODING_LINEAR;
98 info.play.sample_rate = 11025;
99 info.play.channels = 2;
100 info.play.precision = 16;
101
102 if (ioctl(audio_fd, AUDIO_SETINFO, &info) < 0) {
103 info.play.encoding = AUDIO_ENCODING_LINEAR;
104 info.play.sample_rate = 11025;
105 info.play.channels = 1;
106 info.play.precision = 16;
107 if (ioctl(audio_fd, AUDIO_SETINFO, &info) < 0) {
108 Con_Printf("Incapable sound hardware.\n");
109 close(audio_fd);
110 return 0;
111 }
112 Con_Printf("16 bit mono sound initialized\n");
113 shm->samplebits = 16;
114 shm->channels = 1;
115 } else { // 16 bit stereo
116 Con_Printf("16 bit stereo sound initialized\n");
117 shm->samplebits = 16;
118 shm->channels = 2;
119 }
120
121 shm->soundalive = true;
122 shm->samples = sizeof(dma_buffer) / (shm->samplebits/8);
123 shm->samplepos = 0;
124 shm->submission_chunk = 1;
125 shm->buffer = (unsigned char *)dma_buffer;
126
127 snd_inited = 1;
128
129 return 1;
130 }
131
SNDDMA_GetDMAPos(void)132 int SNDDMA_GetDMAPos(void)
133 {
134 if (!snd_inited)
135 return (0);
136
137 if (ioctl(audio_fd, AUDIO_GETINFO, &info) < 0) {
138 perror("/dev/audio");
139 Con_Printf("Could not communicate with audio device.\n");
140 close(audio_fd);
141 snd_inited = 0;
142 return (0);
143 }
144
145 return ((info.play.samples*shm->channels) % shm->samples);
146 }
147
SNDDMA_GetSamples(void)148 int SNDDMA_GetSamples(void)
149 {
150 if (!snd_inited)
151 return (0);
152
153 if (ioctl(audio_fd, AUDIO_GETINFO, &info) < 0) {
154 perror("/dev/audio");
155 Con_Printf("Could not communicate with audio device.\n");
156 close(audio_fd);
157 snd_inited = 0;
158 return (0);
159 }
160
161 return info.play.samples;
162 }
163
SNDDMA_Shutdown(void)164 void SNDDMA_Shutdown(void)
165 {
166 if (snd_inited) {
167 close(audio_fd);
168 snd_inited = 0;
169 }
170 }
171
172 /*
173 ==============
174 SNDDMA_Submit
175
176 Send sound to device if buffer isn't really the dma buffer
177 ===============
178 */
SNDDMA_Submit(void)179 void SNDDMA_Submit(void)
180 {
181 int samps;
182 int bsize;
183 int bytes, b;
184 static unsigned char writebuf[1024];
185 unsigned char *p;
186 int idx;
187 int stop = paintedtime;
188 extern int soundtime;
189
190 if (paintedtime < wbufp)
191 wbufp = 0; // reset
192
193 bsize = shm->channels * (shm->samplebits/8);
194 bytes = (paintedtime - wbufp) * bsize;
195
196 if (!bytes)
197 return;
198
199 if (bytes > sizeof(writebuf)) {
200 bytes = sizeof(writebuf);
201 stop = wbufp + bytes/bsize;
202 }
203
204 p = writebuf;
205 idx = (wbufp*bsize) & (BUFFER_SIZE - 1);
206
207 for (b = bytes; b; b--) {
208 *p++ = dma_buffer[idx];
209 idx = (idx + 1) & (BUFFER_SIZE - 1);
210 }
211
212 wbufp = stop;
213
214 if (write(audio_fd, writebuf, bytes) < bytes)
215 printf("audio can't keep up!\n");
216
217 }
218
219