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