comparison src/libsst.c @ 428:3ecd8885ac67 r21-2-22

Import from CVS: tag r21-2-22
author cvs
date Mon, 13 Aug 2007 11:28:15 +0200
parents
children 84b14dcb0985
comparison
equal deleted inserted replaced
427:0a0253eac470 428:3ecd8885ac67
1 /* libsst.c - SPARC sound tools library
2 **
3 ** Copyright (C) 1989 by Jef Poskanzer.
4 **
5 ** Permission to use, copy, modify, and distribute this software and its
6 ** documentation for any purpose and without fee is hereby granted, provided
7 ** that the above copyright notice appear in all copies and that both that
8 ** copyright notice and this permission notice appear in supporting
9 ** documentation. This software is provided "as is" without express or
10 ** implied warranty.
11
12 ** Hacked on by jwz for emacs.
13
14 */
15
16 /* Synched up with: Not in FSF. */
17
18 #ifdef emacs
19 #include <config.h>
20 #include "lisp.h"
21 #endif
22
23 #ifdef STDC_HEADERS
24 #include <stdlib.h>
25 #endif
26
27 #ifdef HAVE_UNISTD_H
28 #include <unistd.h>
29 #endif
30
31 #include <stdio.h>
32 #include <fcntl.h>
33 #include "libsst.h"
34
35 #define AUDBUF 1024
36
37 extern void usleep();
38
39 int
40 sst_open(play_level, record_level)
41 int play_level, record_level;
42 {
43 int fd, i, gr, ger, gx;
44 struct audio_ioctl ai;
45 char *getenv(), *ep;
46
47 fd = open( "/dev/audio", O_RDWR );
48 if ( fd < 0 )
49 {
50 perror( "sst_open: open /dev/audio" );
51 return( fd );
52 }
53
54 #ifdef AUDIOSETQSIZE /* This no longer exists as of 4.1.2. */
55
56 /* Shrink audio device's queue size, to cut down time delay. */
57 i = AUDBUF;
58 if ( ioctl( fd, AUDIOSETQSIZE, &i ) < 0 )
59 {
60 perror( "sst_open: SETQSIZE" );
61 return( fd );
62 }
63 #endif /* AUDIOSETQSIZE */
64
65 /* Set gains. -10 <= ger <= 18, -18 <= gr <= 12, -18 <= gx <= 12. */
66 if (!play_level)
67 {
68 play_level = 75;
69 if ( (ep = getenv( "SST_PLAY" )) != NULL )
70 {
71 play_level = atoi( ep );
72 if ( play_level < 0 || play_level > 99 )
73 {
74 warn( "sst_open: SST_PLAY must be between 0 and 99" );
75 return( -1 );
76 }
77 }
78 }
79 if (!record_level)
80 {
81 record_level = 75;
82 if ( (ep = getenv( "SST_RECORD" )) != NULL )
83 {
84 record_level = atoi( ep );
85 if ( record_level < 0 || record_level > 99 )
86 {
87 warn( "sst_open: SST_RECORD must be between 0 and 99" );
88 return( -1 );
89 }
90 }
91 }
92
93 play_level = play_level * 59 / 100 - 28;
94 ger = play_level / 2;
95 gr = play_level - ger;
96 if ( ger < -10 )
97 {
98 ger = -10;
99 gr = play_level - ger;
100 }
101 if ( gr > 12 )
102 {
103 gr = 12;
104 ger = play_level - gr;
105 }
106 gx = record_level * 31 / 100 - 18;
107 sst_set_gr( fd, gr );
108 sst_set_ger( fd, ger );
109 sst_set_gx( fd, gx );
110
111 /* Initialize the MMR2 register to send the output to either
112 ** the speaker or the earphone jack, depending on SST_EARPHONES.
113 */
114 ai.control = AUDIO_MAP_MMR2;
115 if ( ioctl( fd, AUDIOGETREG, &ai ) < 0 )
116 {
117 perror( "sst_open: GETREG MMR2" );
118 return( -1 );
119 }
120 if ( (ep = getenv( "SST_EARPHONES" )) != NULL )
121 ai.data[0] &= ~AUDIO_MMR2_BITS_LS;
122 else
123 ai.data[0] |= AUDIO_MMR2_BITS_LS;
124 if ( ioctl( fd, AUDIOSETREG, &ai ) < 0 )
125 {
126 perror( "sst_open: SETREG MMR2" );
127 return( fd );
128 }
129
130 return fd;
131 }
132
133 void
134 sst_close( fd )
135 int fd;
136 {
137 struct audio_ioctl ai;
138
139 ai.control = AUDIO_MAP_MMR1;
140 ai.data[0] = 0;
141 if ( ioctl( fd, AUDIOSETREG, &ai ) < 0 )
142 {
143 perror( "sst_close: SETREG MMR1" );
144 }
145 ai.control = AUDIO_MAP_MMR2;
146 ai.data[0] = 0;
147 if ( ioctl( fd, AUDIOSETREG, &ai ) < 0 )
148 {
149 perror( "sst_close: SETREG MMR2" );
150 }
151 close( fd );
152 }
153
154 /* These are tables of values to be loaded into various gain registers.
155 */
156
157 static unsigned char ger_table[][2] = {
158 0xaa, 0xaa, /* -10db */
159 0x79, 0xac,
160 0x41, 0x99,
161 0x9c, 0xde,
162 0x74, 0x9c, /* -6db */
163 0x6a, 0xae,
164 0xab, 0xdf,
165 0x64, 0xab,
166 0x2a, 0xbd,
167 0x5c, 0xce,
168 0x00, 0x99, /* 0db */
169 0x43, 0xdd,
170 0x52, 0xef,
171 0x55, 0x42,
172 0x31, 0xdd,
173 0x43, 0x1f,
174 0x40, 0xdd, /* 6db */
175 0x44, 0x0f,
176 0x31, 0x1f,
177 0x10, 0xdd,
178 0x41, 0x0f,
179 0x60, 0x0b,
180 0x42, 0x10, /* 12db */
181 0x11, 0x0f,
182 0x72, 0x00,
183 0x21, 0x10,
184 0x22, 0x00,
185 0x00, 0x0b,
186 0x00, 0x0f, /* 18db */
187 };
188
189
190 static unsigned char gr_gx_table[][2] = {
191 0x8b, 0x7c, /* -18db */
192 0x8b, 0x35,
193 0x8b, 0x24,
194 0x91, 0x23,
195 0x91, 0x2a,
196 0x91, 0x3b,
197 0x91, 0xf9, /* -12db */
198 0x91, 0xb6,
199 0x91, 0xa4,
200 0x92, 0x32,
201 0x92, 0xaa,
202 0x93, 0xb3,
203 0x9f, 0x91, /* -6db */
204 0x9b, 0xf9,
205 0x9a, 0x4a,
206 0xa2, 0xa2,
207 0xaa, 0xa3,
208 0xbb, 0x52,
209 0x08, 0x08, /* 0db */
210 0x3d, 0xac,
211 0x25, 0x33,
212 0x21, 0x22,
213 0x12, 0xa2,
214 0x11, 0x3b,
215 0x10, 0xf2, /* 6db */
216 0x02, 0xca,
217 0x01, 0x5a,
218 0x01, 0x12,
219 0x00, 0x32,
220 0x00, 0x13,
221 0x00, 0x0e, /* 12db */
222 };
223
224 void
225 sst_set_ger( fd, value )
226 int fd, value;
227 {
228 struct audio_ioctl ai;
229
230 if ( ( value < -10 ) || ( value > 18 ) )
231 {
232 char buf [255];
233 sprintf (buf, "sst_set_ger: GER %d out of range", value);
234 warn(buf);
235 return;
236 }
237
238 /* Add 10 to the value to get the index into the table. */
239 ai.control = AUDIO_MAP_GER;
240 ai.data[0] = ger_table[value + 10][1];
241 ai.data[1] = ger_table[value + 10][0];
242
243 if ( ioctl( fd, AUDIOSETREG, &ai ) < 0 )
244 {
245 perror( "sst_set_ger: SETREG GER" );
246 }
247
248 ai.control = AUDIO_MAP_MMR1;
249 if ( ioctl( fd, AUDIOGETREG, &ai ) < 0 )
250 {
251 perror( "sst_set_ger: GETREG MMR1" );
252 }
253 ai.data[0] |= AUDIO_MMR1_BITS_LOAD_GER;
254 if ( ioctl( fd, AUDIOSETREG, &ai ) < 0 )
255 {
256 perror( "sst_set_ger: SETREG MMR1" );
257 }
258 }
259
260 void
261 sst_set_gr( fd, value )
262 int fd, value;
263 {
264 struct audio_ioctl ai;
265
266 if ( ( value < -18 ) || ( value > 12 ) )
267 {
268 char buf [255];
269 sprintf (buf, "sst_set_gr: GR %d out of range", value);
270 warn (buf);
271 return;
272 }
273
274 ai.control = AUDIO_MAP_GR;
275 ai.data[0] = gr_gx_table[value + 18][1];
276 ai.data[1] = gr_gx_table[value + 18][0];
277
278 if ( ioctl( fd, AUDIOSETREG, &ai ) < 0 )
279 {
280 perror( "sst_set_gr: SETREG GR" );
281 }
282
283 ai.control = AUDIO_MAP_MMR1;
284 if ( ioctl( fd, AUDIOGETREG, &ai ) < 0 )
285 {
286 perror( "sst_set_gr: GETREG MMR1" );
287 }
288 ai.data[0] |= AUDIO_MMR1_BITS_LOAD_GR;
289 if ( ioctl( fd, AUDIOSETREG, &ai ) < 0 )
290 {
291 perror( "sst_set_gr: SETREG MMR1" );
292 }
293 }
294
295 void
296 sst_set_gx( fd, value )
297 int fd, value;
298 {
299 struct audio_ioctl ai;
300 char buf [255];
301
302 if ( ( value < -18 ) || ( value > 12 ) )
303 {
304 sprintf (buf, "sst_set_gx: GX %d out of range", value);
305 warn (buf);
306 return;
307 }
308
309 /* We add 18 to get the index into the table, since entry 0 represents
310 * -18db.
311 */
312 ai.control = AUDIO_MAP_GX;
313 ai.data[0] = gr_gx_table[value + 18][1];
314 ai.data[1] = gr_gx_table[value + 18][0];
315
316 if ( ioctl( fd, AUDIOSETREG, &ai ) < 0 )
317 {
318 perror( "sst_set_gx: SETREG GX" );
319 }
320
321 ai.control = AUDIO_MAP_MMR1;
322 if ( ioctl( fd, AUDIOGETREG, &ai ) < 0 )
323 {
324 perror( "sst_set_gx: GETREG MMR1" );
325 }
326 ai.data[0] |= AUDIO_MMR1_BITS_LOAD_GX;
327 if ( ioctl( fd, AUDIOSETREG, &ai ) < 0 )
328 {
329 perror( "sst_set_gx: SETREG MMR1" );
330 }
331 }
332
333 void
334 sst_tones( fd, dhz1, dhz2, thz, rhz, usec )
335 int fd, dhz1, dhz2, thz, rhz, usec;
336 {
337 char buf [255];
338 struct audio_ioctl ai;
339 int dval1, dval2, tval, rval;
340 unsigned char oldmmr2, newmmr2;
341
342 if ( dhz1 == 0 )
343 dval1 = 0;
344 else
345 {
346 dval1 = ( dhz1 * 128 + 63 ) / 1000;
347 if ( ( dval1 < 1 ) || ( dval1 > 255 ) )
348 {
349 sprintf(buf, "sst_tones: dhz1 %d out of range", dhz1 );
350 warn (buf);
351 return;
352 }
353 }
354
355 if ( dhz2 == 0 )
356 dval2 = 0;
357 else
358 {
359 dval2 = ( dhz2 * 128 + 63 ) / 1000;
360 if ( ( dval2 < 1 ) || ( dval2 > 255 ) )
361 {
362 sprintf(buf, "sst_tones: dhz2 %d out of range", dhz2 );
363 warn (buf);
364 return;
365 }
366 }
367
368 if ( thz == 0 )
369 tval = 0;
370 else
371 {
372 tval = ( thz * 128 + 63 ) / 2000;
373 if ( ( tval < 1 ) || ( tval > 255 ) )
374 {
375 sprintf(buf, "sst_tones: thz %d out of range", thz );
376 warn (buf);
377 return;
378 }
379 }
380
381 if ( rhz == 0 )
382 rval = 0;
383 else
384 {
385 rval = ( rhz * 128 + 63 ) / 2000;
386 if ( ( rval < 1 ) || ( rval > 255 ) )
387 {
388 sprintf(buf, "sst_tones: rhz %d out of range", dhz2 );
389 warn (buf);
390 return;
391 }
392 }
393
394 if ( ( dval1 != 0 || dval2 != 0 ) && ( tval != 0 || rval != 0 ) )
395 {
396 sprintf(buf, "sst_tones: cannot use DTMF and TONE or RINGER at the same time", dhz2 );
397 warn (buf);
398 return;
399 }
400
401 if ( tval != 0 && rval != 0 )
402 {
403 sprintf(buf, "sst_tones: cannot use TONE and RINGER at the same time", dhz2 );
404 warn (buf);
405 return;
406 }
407
408 ai.control = AUDIO_MAP_MMR2;
409 if ( ioctl( fd, AUDIOGETREG, &ai ) < 0 )
410 {
411 perror( "sst_tones: GETREG MMR2" );
412 }
413 oldmmr2 = newmmr2 = ai.data[0];
414
415 if ( dval1 != 0 || dval2 != 0 )
416 {
417 newmmr2 |= AUDIO_MMR2_BITS_DTMF;
418 ai.control = AUDIO_MAP_FTGR;
419 ai.data[0] = dval1;
420 ai.data[1] = dval2;
421 if ( ioctl( fd, AUDIOSETREG, &ai ) < 0 )
422 {
423 perror( "sst_tones: SETREG FTGR" );
424 }
425 }
426
427 if ( tval != 0 )
428 {
429 newmmr2 |= AUDIO_MMR2_BITS_TONE;
430 ai.control = AUDIO_MAP_FTGR;
431 ai.data[0] = tval;
432 ai.data[1] = 0;
433 if ( ioctl( fd, AUDIOSETREG, &ai ) < 0 )
434 {
435 perror( "sst_tones: SETREG FTGR" );
436 }
437 }
438
439 if ( rval != 0 )
440 {
441 newmmr2 |= AUDIO_MMR2_BITS_RINGER;
442 ai.control = AUDIO_MAP_FTGR;
443 ai.data[0] = rval;
444 ai.data[1] = 0;
445 if ( ioctl( fd, AUDIOSETREG, &ai ) < 0 )
446 {
447 perror( "sst_tones: SETREG FTGR" );
448 }
449 }
450
451 ai.control = AUDIO_MAP_MMR2;
452 ai.data[0] = newmmr2;
453 if ( ioctl( fd, AUDIOSETREG, &ai ) < 0 )
454 {
455 perror( "sst_tones: SETREG MMR2" );
456 }
457
458 usleep( usec );
459
460 ai.data[0] = oldmmr2;
461 if ( ioctl( fd, AUDIOSETREG, &ai ) < 0 )
462 {
463 perror( "sst_tones: SETREG MMR2" );
464 }
465 }
466
467 void
468 sst_dtmf( fd, dial, usecper, usecpause )
469 int fd, usecper, usecpause;
470 char *dial;
471 {
472 char *cp;
473
474 for ( cp = dial; *cp != '\0'; cp++ )
475 {
476 switch ( *cp )
477 {
478 case '1': sst_tones( fd, 703, 1211, 0, 0, usecper ); break;
479 case '2': sst_tones( fd, 703, 1336, 0, 0, usecper ); break;
480 case '3': sst_tones( fd, 703, 1492, 0, 0, usecper ); break;
481 case 'A': sst_tones( fd, 703, 1648, 0, 0, usecper ); break;
482 case '4': sst_tones( fd, 773, 1211, 0, 0, usecper ); break;
483 case '5': sst_tones( fd, 773, 1336, 0, 0, usecper ); break;
484 case '6': sst_tones( fd, 773, 1492, 0, 0, usecper ); break;
485 case 'B': sst_tones( fd, 773, 1648, 0, 0, usecper ); break;
486 case '7': sst_tones( fd, 859, 1211, 0, 0, usecper ); break;
487 case '8': sst_tones( fd, 859, 1336, 0, 0, usecper ); break;
488 case '9': sst_tones( fd, 859, 1492, 0, 0, usecper ); break;
489 case 'C': sst_tones( fd, 859, 1648, 0, 0, usecper ); break;
490 case '*': sst_tones( fd, 945, 1211, 0, 0, usecper ); break;
491 case '0': sst_tones( fd, 945, 1336, 0, 0, usecper ); break;
492 case '#': sst_tones( fd, 945, 1492, 0, 0, usecper ); break;
493 case 'D': sst_tones( fd, 945, 1648, 0, 0, usecper ); break;
494
495 case ' ': case '-': case '(': case ')': case '+':
496 continue; /* ignore */
497
498 case ',': usleep( usecper ); break; /* big pause */
499
500 default:
501 {
502 char buf [255];
503 sprintf( buf, "sst_dtmf: unknown dialing code '%c'", *cp );
504 warn (buf);
505 }
506 }
507 usleep( usecpause );
508 }
509 }