Mercurial > hg > xemacs-beta
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 } |