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