1
2 /*
3 * Diverse Bristol audio routines.
4 * Copyright (c) by Nick Copeland <nickycopeland@hotmail.com> 1996,2012
5 *
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21 #define DUPLICATE
22
23 /*
24 * We need to declare a duplexDev from the SLab routines, initialise this for
25 * a set of audio parameters (sampleRate, driverType, resolution, etc), and
26 * then call our audio open library, also from SLab. The benefits of this are
27 * the need to only maintain one audio library for any new driver release
28 * across all the audio applications. It requires a bit of work here, but the
29 * benefits far outway the extra work. It does require that I import a lot of
30 * structures (ie, headers) from SLab.
31 */
32
33 #include "bristol.h"
34 #include "bristolmidi.h"
35 #include "engine.h"
36
37 #ifdef TEST
38 #include <unistd.h>
39 #endif
40
41 #ifdef DUPLICATE
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <fcntl.h>
45 #include <unistd.h>
46
47 int dupfd = -1;
48 #endif
49
50 static duplexDev audioDev;
51
52 extern int audioClose(duplexDev *);
53 extern int audioOpen(duplexDev *, int, int);
54 extern int audioWrite(duplexDev *, char *, int);
55 extern int audioRead(duplexDev *, char *, int);
56 extern int setAudioStart2(duplexDev *, int);
57
58 int
bristolAudioClose()59 bristolAudioClose()
60 {
61 return(audioClose(&audioDev));
62 }
63
64 int
bristolAudioOpen(char * device,int rate,int count,int flags)65 bristolAudioOpen(char *device, int rate, int count, int flags)
66 {
67 printf("bristolAudioOpen(%s, %i, %i, %x)\n", device, rate, count, flags);
68
69 /*
70 * Take the audioDev, configure a full set of reasonable parameters as
71 * required by the libslabaudio, and call audioOpen with this device.
72 */
73 audioDev.channels = 2;
74 audioDev.samplecount = count;
75
76 audioDev.writeSampleRate = rate;
77 audioDev.devID = 0;
78 if ((audioDev.preLoad = flags & 0x00ff) == 0)
79 audioDev.preLoad = 4;
80 audioDev.fd2 = -1;
81 /*
82 * need to keep the as well, and need to reference the format to make sure
83 * we get the correct buffer size. For now only shorts on output.
84 *
85 * Can this warning, multichannel will be handled with Jack
86 #warning Fix buf calc for formats and channels
87 */
88 audioDev.fragSize = count * sizeof(short) * audioDev.channels;
89 audioDev.fragBuf = 0;
90 audioDev.OSegmentSize = audioDev.fragSize;
91 #if (BRISTOL_HAS_ALSA == 1)
92 if (flags & BRISTOL_ALSA)
93 audioDev.siflags = AUDIO_ALSA;
94 #endif
95 #ifdef BRISTOL_PA
96 if (flags & BRISTOL_PULSE_S)
97 audioDev.siflags = AUDIO_PULSE;
98 #endif
99 audioDev.cflags |= SLAB_SUBFRAGMENT;
100 audioDev.cflags |= SLAB_AUDIODBG;
101
102 sprintf(audioDev.devName, "%s", device);
103 audioDev.mixerName[0] = '\0';
104
105 #ifdef TEST
106 audioDev.fragBuf = (char *) bristolmalloc(audioDev.fragSize);
107 return(audioDev.fragSize);
108 #endif
109
110 audioDev.flags = SLAB_FULL_DUPLEX;
111
112 if (flags & BRISTOL_DUMMY)
113 audioDev.flags |= AUDIO_DUMMY;
114
115 if (audioOpen(&audioDev, 0, SLAB_ORDWR) < 0)
116 return(-1);
117
118 printf(
119 "opened audio device with a fragment size of %i, buffer %p, fd %i/%i\n",
120 audioDev.fragSize, audioDev.fragBuf, audioDev.fd, audioDev.fd2);
121
122 return(audioDev.fragSize);
123 }
124
125 int
bristolAudioStart()126 bristolAudioStart()
127 {
128 return(setAudioStart2(&audioDev, 0));
129 }
130
131 static short accum = 0;
132
133 int
bristolAudioWrite(register float * buf,register int count)134 bristolAudioWrite(register float *buf, register int count)
135 {
136 register short *audioBuf;
137 register int clipped = 0, result, Count = count;
138
139 if (audioDev.flags & SLAB_AUDIODBG2)
140 printf("bristolAudioWrite(%p, %i), %i\n",
141 buf, count, audioDev.samplecount);
142
143 /*
144 * Based on the assumption that we are always going to be working with
145 * floats, and the output device has a given format (assume 16 bit for now)
146 * then convert the buffer of data.
147 */
148 audioBuf = (short *) audioDev.fragBuf;
149
150 /*
151 * sample count is actually frame count, ie, this is actually a sample from
152 * each channel. As such, it looks like count is wrong. It is correct.
153 */
154 for (; Count > 0; Count-=4)
155 {
156 /*
157 * This is a conversion routine from the floats used by bristol, and
158 * most of the code is for clipchecking.
159 */
160 *(audioBuf++) = (short) (*buf > 32767?32767:*buf < -32767?-32767:*buf);
161 if ((*buf > 32767) || (*buf < -32768)) clipped = 1;
162 buf++;
163 *(audioBuf++) = (short) (*buf > 32767?32767:*buf < -32767?-32767:*buf);
164 buf++;
165 *(audioBuf++) = (short) (*buf > 32767?32767:*buf < -32767?-32767:*buf);
166 buf++;
167 *(audioBuf++) = (short) (*buf > 32767?32767:*buf < -32767?-32767:*buf);
168 if ((*buf > 32767) || (*buf < -32768)) clipped = 1;
169 buf++;
170 *(audioBuf++) = (short) (*buf > 32767?32767:*buf < -32767?-32767:*buf);
171 buf++;
172 *(audioBuf++) = (short) (*buf > 32767?32767:*buf < -32767?-32767:*buf);
173 if ((*buf > 32767) || (*buf < -32768)) clipped = 1;
174 buf++;
175 *(audioBuf++) = (short) (*buf > 32767?32767:*buf < -32767?-32767:*buf);
176 if ((*buf > 32767) || (*buf < -32768)) clipped = 1;
177 buf++;
178 *(audioBuf++) = (short) (*buf > 32767?32767:*buf < -32767?-32767:*buf);
179 buf++;
180 }
181
182 #ifdef TEST
183 return(0);
184 #endif
185
186 if ((result = audioWrite(&audioDev, audioDev.fragBuf, audioDev.samplecount))
187 < 0)
188 {
189 printf("Write Failed: %i\n", result);
190 /*
191 * We could get into a panic here. The device originally opened
192 * correctly (otherwise we would assumably not be writing here. Lets
193 * just close and reopen the device, and see how things go.
194 *
195 * We should actually return a bad value, and continue, letting the
196 * calling party clear things up. This has been done.
197 */
198 return(result);
199 }
200 #ifdef DUPLICATE
201 if (dupfd > 0)
202 {
203 register short *sbuf = (short *) audioDev.fragBuf, d;
204
205 Count = count;
206
207 for (; Count > 0; Count--)
208 accum += *sbuf++ / 2;
209
210 if (accum != 0)
211 d = write(dupfd, audioDev.fragBuf, audioDev.fragSize);
212 }
213 #endif
214 if (clipped)
215 printf("Clipping output\n");
216
217 return(0);
218 }
219
220 int
bristolAudioRead(register float * buf,register int count)221 bristolAudioRead(register float *buf, register int count)
222 {
223 register short *audioBuf;
224 register int count2 = count;
225 register float norm = 12.0f/32768.0f;
226
227 if (audioDev.flags & SLAB_AUDIODBG2)
228 printf("bristolAudioRead(%i), %i\n", count, audioDev.samplecount);
229
230 /*
231 * Based on the assumption that we are always going to be working with
232 * floats, and the output device has a given format (assume 16 bit for now)
233 * then convert the buffer of data.
234 */
235 audioBuf = ((short *) audioDev.fragBuf) - 2;
236
237 #ifdef TEST
238 {
239 usleep(6000);
240 return(0);
241 }
242 #endif
243
244 if (audioRead(&audioDev, audioDev.fragBuf, audioDev.samplecount) < 0)
245 {
246 printf("Read Failed: fs %i, %p\n",
247 audioDev.fragSize, audioDev.fragBuf);
248 return(-6);
249 }
250
251 /*
252 * Demultiplex channels.
253 *
254 * The count is samples, but data is in frames, ie, two samples for the
255 * time being. I really want this data to be in a format that is +/-12,
256 * that means we have to normalise it and we should do it here.
257 */
258 for (; count > 0; count-=8)
259 {
260 *buf++ = ((float) *(audioBuf+=2)) * norm;
261 *buf++ = ((float) *(audioBuf+=2)) * norm;
262 *buf++ = ((float) *(audioBuf+=2)) * norm;
263 *buf++ = ((float) *(audioBuf+=2)) * norm;
264 *buf++ = ((float) *(audioBuf+=2)) * norm;
265 *buf++ = ((float) *(audioBuf+=2)) * norm;
266 *buf++ = ((float) *(audioBuf+=2)) * norm;
267 *buf++ = ((float) *(audioBuf+=2)) * norm;
268 }
269
270 audioBuf = ((short *) audioDev.fragBuf) - 1;
271
272 for (; count2 > 0; count2-=8)
273 {
274 *buf++ = ((float) *(audioBuf+=2)) * norm;
275 *buf++ = ((float) *(audioBuf+=2)) * norm;
276 *buf++ = ((float) *(audioBuf+=2)) * norm;
277 *buf++ = ((float) *(audioBuf+=2)) * norm;
278 *buf++ = ((float) *(audioBuf+=2)) * norm;
279 *buf++ = ((float) *(audioBuf+=2)) * norm;
280 *buf++ = ((float) *(audioBuf+=2)) * norm;
281 *buf++ = ((float) *(audioBuf+=2)) * norm;
282 }
283
284 return(0);
285 }
286
287 /*
288 * This was added for enabling audio debug
289 */
290 int
bristolAudioOption(int option,int value)291 bristolAudioOption(int option, int value)
292 {
293 switch (option) {
294 case BRISTOL_NRP_REQ_DEBUG:
295 if (value == 0)
296 audioDev.cflags &= ~SLAB_AUDIODBG;
297 else if (value == 1)
298 audioDev.cflags |= SLAB_AUDIODBG;
299 else
300 audioDev.cflags |= SLAB_AUDIODBG|SLAB_AUDIODBG2;
301 break;
302 }
303
304 return(0);
305 }
306
307