1 /*
2 * dtmf-dial 0.1
3 * (C) 1998 Itai Nahshon (nahshon@actcom.co.il)
4 *
5 * Use and redistribution are subject to the GNU GENERAL PUBLIC LICENSE.
6 */
7 #include <math.h>
8 #include <stdio.h>
9 #include <fcntl.h>
10 #include <stdlib.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <sys/soundcard.h>
14
15 #define DEBUG(x)
16
17 void gen_costab(void);
18 void dial_digit(int c);
19 void silent(int msec);
20 void dial(int f1, int f2, int msec);
21
22 char *output = "/dev/dsp";
23 int bits = 8;
24 int speed = 8000;
25 int tone_time = 100;
26 int silent_time = 50;
27 int sleep_time = 500;
28 int volume = 100;
29 int format = AFMT_U8;
30 int use_audio = 1;
31
32 #define BSIZE 4096
33
34 unsigned char *buf;
35 int bufsize = BSIZE;
36 int bufidx;
37
38 #define MINTABSIZE 2
39 #define MAXTABSIZE 65536
40 signed short *costab;
41 int tabsize = 256;
42
43 int dialed = 0;
44
45 int right = 0;
46 int left = 0;
47
48 int fd;
49
50 void
Usage(void)51 Usage(void) {
52 fprintf(stderr, "usage: dial [options] number ...\n"
53 " Valid options with their default values are:\n"
54 " Duration options:\n"
55 " --tone-time 100\n"
56 " --silent-time 50\n"
57 " --sleep-time 500\n"
58 " Audio output options:\n"
59 " --output-dev /dev/dsp\n"
60 " --use-audio 1\n"
61 " --bufsize 4096\n"
62 " --speed 8000\n"
63 " --bits 8\n"
64 " Audio generation options:\n"
65 " --table-size 256\n"
66 " --volume 100\n"
67 " --left 0\n"
68 " --right 0\n"
69 );
70
71 exit(1);
72 }
73
74 void
initialize_audiodev(void)75 initialize_audiodev(void) {
76 int speed_local = speed;
77 int channels = 1;
78 int diff;
79
80 if(!use_audio)
81 return;
82
83 if(right || left)
84 channels = 2;
85
86 if(ioctl(fd, SNDCTL_DSP_CHANNELS, &channels)) {
87 perror("ioctl(SNDCTL_DSP_CHANNELS)");
88 exit(1);
89 }
90
91 if(ioctl(fd, SNDCTL_DSP_SETFMT, &format)) {
92 perror("ioctl(SNDCTL_DSP_SPEED)");
93 exit(1);
94 }
95
96 if(ioctl(fd, SNDCTL_DSP_SPEED, &speed_local)) {
97 perror("ioctl(SNDCTL_DSP_SPEED)");
98 exit(1);
99 }
100
101 diff = speed_local - speed;
102 if(diff < 0)
103 diff = -diff;
104 if(diff > 500) {
105 fprintf(stderr,
106 "Your sound card does not support the requested speed\n");
107 exit(1);
108 }
109 if(diff != 0) {
110 fprintf(stderr,
111 "Setting speed to %d\n", speed_local);
112 }
113 speed = speed_local;
114 }
115
116 void
getvalue(int * arg,int * index,int argc,char ** argv,int min,int max)117 getvalue(int *arg, int *index, int argc,
118 char **argv, int min, int max) {
119
120 if (*index >= argc-1)
121 Usage();
122
123 *arg = atoi(argv[1+*index]);
124
125 if(*arg < min || *arg > max) {
126 fprintf(stderr, "Value for %s should be in the range %d..%d\n",
127 argv[*index]+2, min, max);
128 exit(1);
129 }
130 ++*index;
131 }
132
133 int
main(int argc,char ** argv)134 main(int argc, char **argv)
135 {
136 char *cp;
137 int i;
138
139 for(i = 1; i < argc; i++) {
140 if(argv[i][0] != '-' ||
141 argv[i][1] != '-')
142 break;
143
144 if(!strcmp(argv[i], "--table-size")) {
145 getvalue(&tabsize, &i, argc, argv,
146 MINTABSIZE, MAXTABSIZE);
147 }
148 else if(!strcmp(argv[i], "--tone-time")) {
149 getvalue(&tone_time, &i, argc, argv,
150 10, 10000);
151 }
152 else if(!strcmp(argv[i], "--sleep-time")) {
153 getvalue(&sleep_time, &i, argc, argv,
154 10, 10000);
155 }
156 else if(!strcmp(argv[i], "--silent-time")) {
157 getvalue(&silent_time, &i, argc, argv,
158 10, 10000);
159 }
160 else if(!strcmp(argv[i], "--sleep-time")) {
161 getvalue(&sleep_time, &i, argc, argv,
162 10, 100000);
163 }
164 else if(!strcmp(argv[i], "--volume")) {
165 getvalue(&volume, &i, argc, argv,
166 0, 100);
167 }
168 else if(!strcmp(argv[i], "--speed")) {
169 getvalue(&speed, &i, argc, argv,
170 5000, 48000);
171 }
172 else if(!strcmp(argv[i], "--bits")) {
173 getvalue(&bits, &i, argc, argv,
174 8, 16);
175 }
176 else if(!strcmp(argv[i], "--bufsize")) {
177 getvalue(&bufsize, &i, argc, argv,
178 4, 65536);
179 }
180 else if(!strcmp(argv[i], "--use-audio")) {
181 getvalue(&use_audio, &i, argc, argv,
182 0, 1);
183 }
184 else if(!strcmp(argv[i], "--right")) {
185 getvalue(&right, &i, argc, argv,
186 0, 1);
187 }
188 else if(!strcmp(argv[i], "--left")) {
189 getvalue(&left, &i, argc, argv,
190 0, 1);
191 }
192 else if(!strcmp(argv[i], "--output-dev")) {
193 i++;
194 if(i >= argc)
195 Usage();
196 output = argv[i];
197 }
198 else
199 Usage();
200 }
201
202 if(i >= argc)
203 Usage();
204
205 if(!strcmp(output, "-"))
206 fd = 1; /* stdout */
207 else {
208 fd = open(output, O_CREAT|O_TRUNC|O_WRONLY, 0644);
209 if(fd < 0) {
210 perror(output);
211 exit(1);
212 }
213 }
214
215 switch(bits) {
216 case 8:
217 format = AFMT_U8;
218 break;
219 case 16:
220 format = AFMT_S16_LE;
221 break;
222 default:
223 fprintf(stderr, "Value for bits should be 8 or 16\n");
224 exit(1);
225 }
226
227 initialize_audiodev();
228
229 gen_costab();
230 buf = malloc(bufsize);
231 if(buf == NULL) {
232 perror("malloc buf");
233 exit(1);
234 }
235
236 bufidx = 0;
237 for(; i < argc; i++) {
238 cp = argv[i];
239 if(dialed)
240 silent(sleep_time);
241 while(cp && *cp) {
242 if(*cp == ',' || *cp == ' ')
243 silent(sleep_time);
244 else {
245 if(dialed)
246 silent(silent_time);
247 dial_digit(*cp);
248 }
249 cp++;
250 }
251 }
252 if(bufidx > 0) {
253 #if 0
254 while(bufidx < bufsize) {
255 if(format == AFMT_U8) {
256 buf[bufidx++] = 128;
257 }
258 else { /* AFMT_S16_LE */
259 buf[bufidx++] = 0;
260 buf[bufidx++] = 0;
261 }
262 }
263 #endif
264 write(fd, buf, bufidx);
265 }
266 exit(0);
267 }
268
269 void
dial_digit(int c)270 dial_digit(int c) {
271 DEBUG(fprintf(stderr, "dial_digit %#c\n", c));
272 switch(c) {
273 case '0':
274 dial(941, 1336, tone_time);
275 break;
276 case '1':
277 dial(697, 1209, tone_time);
278 break;
279 case '2':
280 dial(697, 1336, tone_time);
281 break;
282 case '3':
283 dial(697, 1477, tone_time);
284 break;
285 case '4':
286 dial(770, 1209, tone_time);
287 break;
288 case '5':
289 dial(770, 1336, tone_time);
290 break;
291 case '6':
292 dial(770, 1477, tone_time);
293 break;
294 case '7':
295 dial(852, 1209, tone_time);
296 break;
297 case '8':
298 dial(852, 1336, tone_time);
299 break;
300 case '9':
301 dial(852, 1477, tone_time);
302 break;
303 case '*':
304 dial(941, 1209, tone_time);
305 break;
306 case '#':
307 dial(941, 1477, tone_time);
308 break;
309 case 'A':
310 dial(697, 1633, tone_time);
311 break;
312 case 'B':
313 dial(770, 1633, tone_time);
314 break;
315 case 'C':
316 dial(852, 1633, tone_time);
317 break;
318 case 'D':
319 dial(941, 1633, tone_time);
320 break;
321 }
322 }
323
324 void
silent(int msec)325 silent(int msec) {
326 int time;
327 if(msec <= 0)
328 return;
329
330 DEBUG(fprintf(stderr, "silent %d\n", msec));
331
332 time = (msec * speed) / 1000;
333 while(--time >= 0) {
334 if(format == AFMT_U8) {
335 buf[bufidx++] = 128;
336 }
337 else { /* AFMT_S16_LE */
338 buf[bufidx++] = 0;
339 buf[bufidx++] = 0;
340 }
341 if(right || left) {
342 if(format == AFMT_U8) {
343 buf[bufidx++] = 128;
344 }
345 else { /* AFMT_S16_LE */
346 buf[bufidx++] = 0;
347 buf[bufidx++] = 0;
348 }
349 }
350 if(bufidx >= bufsize) {
351 write(fd, buf, bufsize);
352 bufidx = 0;
353 }
354 }
355 dialed = 0;
356 }
357
358 void
dial(int f1,int f2,int msec)359 dial(int f1, int f2, int msec) {
360 int i1, i2, d1, d2, e1, e2, g1, g2;
361 int time;
362 int val;
363
364 if(msec <= 0)
365 return;
366
367 DEBUG(fprintf(stderr, "dial %d %d %d\n", f1, f2, msec));
368
369 f1 *= tabsize;
370 f2 *= tabsize;
371 d1 = f1 / speed;
372 d2 = f2 / speed;
373 g1 = f1 - d1 * speed;
374 g2 = f2 - d2 * speed;
375 e1 = speed/2;
376 e2 = speed/2;
377
378 i1 = i2 = 0;
379
380 time = (msec * speed) / 1000;
381 while(--time >= 0) {
382 val = costab[i1] + costab[i2];
383
384 if(left || !right) {
385 if(format == AFMT_U8) {
386 buf[bufidx++] = 128 + (val >> 8);
387 }
388 else { /* AFMT_S16_LE */
389 buf[bufidx++] = val & 0xff;
390 buf[bufidx++] = (val >> 8) & 0xff;
391 }
392 }
393 if (left != right) {
394 if(format == AFMT_U8) {
395 buf[bufidx++] = 128;
396 }
397 else { /* AFMT_S16_LE */
398 buf[bufidx++] = 0;
399 buf[bufidx++] = 0;
400 }
401 }
402 if(right) {
403 if(format == AFMT_U8) {
404 buf[bufidx++] = 128 + (val >> 8);
405 }
406 else { /* AFMT_S16_LE */
407 buf[bufidx++] = val & 0xff;
408 buf[bufidx++] = (val >> 8) & 0xff;
409 }
410 }
411
412 i1 += d1;
413 if (e1 < 0) {
414 e1 += speed;
415 i1 += 1;
416 }
417 if (i1 >= tabsize)
418 i1 -= tabsize;
419
420 i2 += d2;
421 if (e2 < 0) {
422 e2 += speed;
423 i2 += 1;
424 }
425 if (i2 >= tabsize)
426 i2 -= tabsize;
427
428 if(bufidx >= bufsize) {
429 write(fd, buf, bufsize);
430 bufidx = 0;
431 }
432 e1 -= g1;
433 e2 -= g2;
434 }
435 dialed = 1;
436 }
437
438 void
gen_costab(void)439 gen_costab(void) {
440 int i;
441 double d;
442
443 costab = (signed short *)malloc(tabsize * sizeof(signed short));
444 if(costab == NULL) {
445 perror("malloc costab");
446 exit(1);
447 }
448
449 for (i = 0; i < tabsize; i++) {
450 d = 2*M_PI*i;
451 costab[i] = (int)((volume/100.)*16383.*cos(d/tabsize));
452 }
453 }
454