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