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