1 /*
2 * YASR ("Yet Another Screen Reader") is an attempt at a lightweight,
3 * portable screen reader.
4 *
5 * Copyright (C) 2001-2003 by Michael P. Gorse. All rights reserved.
6 *
7 * YASR comes with ABSOLUTELY NO WARRANTY.
8 *
9 * This is free software, placed under the terms of the
10 * GNU Lesser General Public License, as published by the Free Software
11 * Foundation. Please see the file COPYING for details.
12 *
13 * Web Page: http://yasr.sf.net
14 *
15 * This software is maintained by:
16 * Michael P. Gorse <mgorse@users.sourceforge.net>
17 */
18
19 #include "yasr.h"
20
21 /* Constants and flags for use in setting the type of an option */
22
23 typedef struct
24 {
25 int len;
26 int lastlen;
27 int opt[10];
28 int saychar;
29 union
30 {
31 int val;
32 double val_float;
33 } v[10];
34 } Optqueue;
35
36 static Optqueue opq;
37
38
options_are_equal(int i,int j)39 static int options_are_equal(int i, int j)
40 {
41 if (i == j)
42 {
43 return (1);
44 }
45
46 /* Speakout's punctuation options are set using the same setting */
47 if ((i >= 14 && i <= 17) && (j >= 14 && j <= 17))
48 {
49 return (1);
50 }
51
52 return (0);
53 }
54
opt_queue_add(int num,...)55 static void opt_queue_add(int num, ...)
56 {
57 int i;
58 va_list args;
59
60 va_start(args, num);
61 for (i = 0; i < opq.len; i++)
62 {
63 if (options_are_equal(i, num)) break;
64 }
65 if (i == 10)
66 {
67 /* tbc - give some kind of warning */
68 }
69 else
70 {
71 opq.opt[i] = num;
72 if ((opt[num].type & 0x3f) == OT_FLOAT)
73 {
74 opq.v[i].val_float = va_arg(args, double);
75 }
76 else opq.v[i].val = va_arg(args, int);
77 if (i == opq.len) opq.len++;
78 (void) alarm(1);
79 }
80 va_end(args);
81 }
82
83
84 Opt opt[NUMOPTS];
85 static int curopt;
86 int synthopt;
87
88
opt_add(void * ptr,int tree,char * name,int type,...)89 void opt_add(void *ptr, int tree, char *name, int type, ...)
90 {
91 Opt *optr;
92 va_list args;
93 int i;
94
95 if (!strcasecmp(name, "synthesizer"))
96 synthopt = curopt;
97 optr = &opt[curopt];
98 optr->ptr = ptr;
99 optr->tree = tree;
100 optr->internal_name = name;
101 optr->localized_name = _(name);
102 optr->type = type;
103 va_start(args, type);
104 switch (type & 0x3f)
105 {
106 case OT_INT: /* Numeric value. Expects a min and a max. */
107 optr->v.val_int.min = va_arg(args, int);
108 optr->v.val_int.max = va_arg(args, int);
109 break;
110 case OT_FLOAT: /* Numeric value. Expects a min and a max. */
111 optr->v.val_float.min = va_arg(args, double);
112 optr->v.val_float.max = va_arg(args, double);
113 break;
114
115 case OT_ENUM: /* Toggle between several values. Expects the
116 * number of values followed by a name for each.
117 */
118 optr->v.enum_max = va_arg(args, int) - 1;
119 optr->arg = malloc((optr->v.enum_max + 1) * sizeof(char *));
120 for (i = 0; i <= optr->v.enum_max; i++)
121 {
122 optr->arg[i] = strdup(va_arg(args, char *));
123 }
124 break;
125
126 case OT_TREE: /* Sub-menu -- Next option is id */
127 optr->v.submenu = va_arg(args, int);
128 break;
129 }
130 if (optr->type & OT_SYNTH)
131 {
132 optr->synth = va_arg(args, int);
133 if (optr->type != (OT_TREE | OT_SYNTH))
134 {
135 optr->setstr = va_arg(args, char *);
136 }
137 } else
138 {
139 optr->synth = 0;
140 }
141 if (optr->type & OT_BITSLICE)
142 {
143 optr->shift = va_arg(args, int);
144 }
145 curopt++;
146 va_end(args);
147 }
148
149
150 #define opt_ptr(x) (opt[x].type & OT_SYNTH ? \
151 (void *)(voices[opt[x].synth] + (long) opt[x].ptr) : \
152 opt[x].ptr)
153
154 #define data_size(x) (((x)->type & 0x3f) == OT_FLOAT? sizeof(double): sizeof(int))
155
156
opt_getval(int num,int flag)157 int opt_getval(int num, int flag)
158 {
159 char *p = opt_ptr(num);
160 int out = 0, count = 0;
161 int retval;
162
163 if ((opt[num].type & OT_BITSLICE) && !flag)
164 { /* bitslice */
165 int v = opt[num].v.enum_max; /* assuming OT_ENUM */
166 while (v)
167 {
168 /* hmm; will this code work for enum_max > 1? */
169 out += ((*p >> (opt[num].shift + count)) & 1) << count;
170 count++;
171 v >>= 1;
172 }
173 return (out);
174 } else
175 {
176 (void) memcpy(&retval, p, data_size(&opt[num]));
177 return retval;
178 }
179 }
180
opt_getval_float(int num,int flag)181 double opt_getval_float(int num, int flag)
182 {
183 char *p = opt_ptr(num);
184 double retval;
185
186 (void) memcpy(&retval, p, data_size(&opt[num]));
187 return retval;
188 }
189
opt_setval(int num,void * val)190 static void opt_setval(int num, void *val)
191 {
192 char *p = opt_ptr(num);
193 int count = 0;
194 int out = *p;
195
196 if (opt[num].type & OT_BITSLICE)
197 {
198 int v = opt[num].v.enum_max;
199 int val_int = *(int *)val;
200 while (v)
201 {
202 out &= ~(1 << (opt[num].shift + count));
203 v >>= 1;
204 }
205 out |= val_int << opt[num].shift;
206 *p = out;
207 }
208 else (void) memcpy(p, val, data_size(&opt[num]));
209 }
210
opt_preset(int num,char pre)211 void opt_preset(int num, char pre)
212 {
213 char *p;
214
215 (void) strcpy((char *) buf, opt[num].arg[(int) pre]);
216 strtok((char *) buf, ":");
217 while ((p = strtok(NULL, ":")))
218 {
219 opt_read(p, tts.synth);
220 }
221 }
222
opt_synth_update(int num,int optval)223 static void opt_synth_update(int num, int optval)
224 {
225 char *p1, *p2;
226
227 p1 = opt[num].setstr;
228 if (!p1 && (opt[num].type & 0x3f) == OT_ENUM)
229 {
230 p1 = strstr(opt[num].arg[optval], ":") + 1;
231 }
232
233 /* This assumes that no synth will need a \ code at the beginning of a
234 * setstr string. If one does, then this code will need to be changed.
235 */
236 if (!strchr(p1 + 1, '\\') && !strstr(p1, "%s"))
237 {
238 (void) sprintf(ttsbuf, p1, optval);
239 }
240 else
241 {
242 p2 = ttsbuf;
243 while (*p1)
244 {
245 switch (*p1)
246 {
247 case '\\':
248 p1++;
249 switch (*(p1++))
250 {
251 case 'l':
252 *(p2++) = *((char *) opt_ptr(num)) + 64;
253 break;
254 case 'p':
255 *(p2++) = opt[num].arg[(int) *((char *) opt_ptr(num))][0];
256 break;
257 case '?': /* hard-coded special handling */
258 switch (num)
259 {
260 case 32: /* bns punctuation: tbd - rework using : form */
261 switch (*(short *) opt_ptr(num))
262 {
263 case 0:
264 *(p2++) = 'Z';
265 break;
266 case 1:
267 *(p2++) = 'S';
268 break;
269 case 2:
270 *(p2++) = 'M';
271 break;
272 case 3:
273 *(p2++) = 'T';
274 break;
275 }
276 }
277 break;
278 }
279 break;
280 case '%':
281 p1++;
282 switch (*(p1++))
283 {
284 case 's': /* send string of numeric option */
285 strcpy(p2, opt[num].arg[optval]);
286 while (*p2) p2++;
287 break;
288 default:
289 /* tbd - error */
290 break;
291 }
292 break;
293 default:
294 *(p2++) = *(p1++);
295 }
296 }
297 *p2 = '\0';
298 }
299 tts_send(ttsbuf, strlen(ttsbuf));
300 }
301
opt_synth_update_float(int num,double optval)302 static void opt_synth_update_float(int num, double optval)
303 {
304 int i;
305
306 (void) sprintf(ttsbuf, opt[num].setstr, optval);
307 for (i=0; i<strlen(ttsbuf); i++)
308 {
309 if ((ttsbuf[i])==',')
310 ttsbuf[i]='.';
311 }
312
313 tts_send(ttsbuf, strlen(ttsbuf));
314 }
315
opt_queue_empty(int mode)316 void opt_queue_empty(int mode)
317 {
318 int i;
319 int max;
320
321 max = (mode == 1 ? opq.lastlen : opq.len);
322 if (!max) return;
323 if (opq.saychar)
324 {
325 if (mode == 3)
326 {
327 opq.len = 0;
328 return;
329 }
330 tts_charoff();
331 opq.saychar = 0;
332 }
333 for (i = 0; i < max; i++)
334 {
335 if ((opt[opq.opt[i]].type & 0x3f) == OT_FLOAT)
336 {
337 opt_synth_update_float(opq.opt[i], opq.v[i].val_float);
338 }
339 else
340 {
341 opt_synth_update(opq.opt[i], opq.v[i].val);
342 }
343 }
344 switch (mode)
345 {
346 case 3:
347 opq.saychar = 1;
348 tts_charon();
349 case 0:
350 opq.lastlen = opq.len;
351 opq.len = 0;
352 break;
353 case 2:
354 opq.len = 0;
355 case 1:
356 opq.lastlen = 0;
357 break;
358 }
359 }
360
opt_set(int num,void * val)361 void opt_set(int num, void *val)
362 {
363 void *p = opt_ptr(num);
364
365 switch (opt[num].type & 0x3f)
366 {
367 case OT_STR:
368 (void) strncpy((char *) p, val, OPT_STR_SIZE);
369 break;
370
371 case OT_PRESET:
372 opt_preset(num, 0);
373 if (*(char *) val)
374 {
375 opt_preset(num, *(char *) val);
376 }
377
378 case OT_INT:
379 case OT_ENUM:
380 case OT_FLOAT:
381 opt_setval(num, val);
382 break;
383 }
384 if (!(opt[num].type & OT_SYNTH) || opt[num].synth != tts.synth) return;
385 switch (opt[num].type & 0x3f)
386 {
387 case OT_INT:
388 case OT_ENUM:
389 opt_queue_add(num, opt_getval(num, 1));
390 break;
391 case OT_FLOAT:
392 opt_queue_add(num, opt_getval_float(num, 1));
393 break;
394 }
395 }
396
opt_say(int num,int flag)397 void opt_say(int num, int flag)
398 {
399 void *p = opt_ptr(num);
400
401 if (flag)
402 {
403 (void) sprintf((char *) buf, "%s... ", opt[num].localized_name);
404 tts_say((char *) buf);
405 }
406 switch (opt[num].type & 0x3f)
407 {
408 case OT_INT:
409 (void) sprintf((char *) buf, "%d", opt_getval(num, 0));
410 tts_say((char *) buf);
411 break;
412 case OT_FLOAT:
413 (void) sprintf((char *) buf, "%f", opt_getval_float(num, 0));
414 tts_say((char *) buf);
415 break;
416 case OT_ENUM:
417 (void) strcpy((char *) buf, opt[num].arg[opt_getval(num, 0)]);
418 strtok((char *) buf, ":");
419 tts_say(_((char *) buf));
420 break;
421 case OT_STR:
422 tts_say((char *) p);
423 break;
424 }
425 }
426
427 #define opt_usable(x) (opt[x].tree == opt[curopt].tree && \
428 (!(opt[x].type & OT_SYNTH) || \
429 opt[x].synth == tts.synth || \
430 opt[i].synth == -1))
431
optmenu(int ch)432 int optmenu(int ch)
433 {
434 int i;
435 static int state = 0;
436
437 switch (state)
438 {
439 case 1: /* User has just finished entering an integer */
440 if (!ui.abort)
441 {
442 int num = atoi(ui.str);
443 if (num >= opt[curopt].v.val_int.min && num <= opt[curopt].v.val_int.max)
444 {
445 opt_set(curopt, &num);
446 tts_say(_("Value accepted."));
447 } else
448 {
449 tts_say(_("Value out of range."));
450 }
451 }
452 state = 0;
453 return (1);
454
455 case 2: /* User has just finished entering a float */
456 if (!ui.abort)
457 {
458 double num = atof(ui.str);
459 if (num >= opt[curopt].v.val_float.min && num <= opt[curopt].v.val_float.max)
460 {
461 opt_set(curopt, &num);
462 tts_say(_("Value accepted."));
463 } else
464 {
465 tts_say(_("Value out of range."));
466 }
467 }
468 state = 0;
469 return (1);
470
471 case 3: /* User has just entered a string -- not yet implemented */
472 if (!ui.abort)
473 {
474 opt_set(curopt, &ui.buf);
475 tts_say(_("value accepted."));
476 }
477 return (1);
478 }
479
480 switch (ch)
481 {
482 case 0: /* initialize */
483 tts_say(_("Setting options..."));
484 opt_say(curopt = 0, 1);
485 break;
486
487 case 0x1b5b41: /* up arrow */
488 for (i = curopt - 1; i >= 0; i--)
489 {
490 if (opt_usable(i))
491 {
492 curopt = i;
493 break;
494 }
495 }
496 opt_say(curopt, 1);
497 break;
498
499 case 0x1b5b42: /* down arrow */
500 for (i = curopt + 1; i < NUMOPTS; i++)
501 {
502 if (opt_usable(i))
503 {
504 curopt = i;
505 break;
506 }
507 }
508 opt_say(curopt, 1);
509 break;
510
511 case 0x1b5b44: /* left arrow */
512 if (!opt[curopt].tree)
513 {
514 opt_say(curopt, 1);
515 break;
516 }
517 for (i = curopt - 1; i >= 0; i--)
518 {
519 if ((opt[i].type & 0x3f) == OT_TREE &&
520 opt[i].v.submenu == opt[curopt].tree &&
521 (!opt[i].type & OT_SYNTH ||
522 opt[i].synth == tts.synth || opt[i].synth == -1))
523 {
524 curopt = i;
525 break;
526 }
527 }
528 opt_say(curopt, 1);
529 break;
530
531 case 0x1b5b43: /* right arrow */
532 case 0x0d:
533 case 0x20:
534 switch (opt[curopt].type & 0x3f)
535 {
536 case OT_INT:
537 (void) sprintf((char *) buf, "%s %d %s %d.",_("Enter a number from"), opt[curopt].v.val_int.min, _("to"), opt[curopt].v.val_int.max);
538 tts_say((char *) buf);
539 ui_funcman(&ui_build_str);
540 state = 1;
541 break;
542 case OT_FLOAT:
543 (void) sprintf((char *) buf, "%s %lf %s %lf.",_("Enter a number from"), opt[curopt].v.val_float.min,_("to"), opt[curopt].v.val_float.max);
544 tts_say((char *) buf);
545 ui_funcman(&ui_build_str);
546 state = 2;
547 break;
548
549 case OT_ENUM:
550 i = (opt_getval(curopt, 0) + 1) % (opt[curopt].v.enum_max + 1);
551 opt_set(curopt, &i);
552 opt_say(curopt, 1);
553 break;
554
555 case OT_STR: /* tbd -- allow the user to enter a string here */
556 break;
557
558 case OT_TREE:
559 for (i = curopt + 1; i < NUMOPTS; i++)
560 {
561 if (opt[i].tree == opt[curopt].v.submenu &&
562 (!(opt[i].type & OT_SYNTH) ||
563 opt[i].synth == tts.synth || opt[i].synth == -1))
564 {
565 curopt = i;
566 break;
567 }
568 }
569 opt_say(curopt, 1);
570 }
571 break;
572
573 case 27:
574 tts_say(_("exiting options menu."));
575 ui_funcman(0);
576 break;
577
578 default:
579 if ((ch & 0xffffff00) || !isalpha(ch))
580 {
581 break;
582 }
583 ch |= 0x20;
584 for (i = (curopt + 1) % NUMOPTS; i != curopt; i = (i + 1) % NUMOPTS)
585 {
586 if ((opt[i].localized_name[0] | 0x20) == ch && opt_usable(i))
587 {
588 curopt = i;
589 break;
590 }
591 }
592 opt_say(curopt, 1);
593 }
594
595 return (1);
596 }
597
strro(char * s,char c,int j)598 static char *strro(char *s, char c, int j)
599 {
600 static char buf[500];
601 char *p = s, *q = buf;
602
603 if (j)
604 {
605 while (*p && *p != c)
606 {
607 p++;
608 }
609 if (!*p)
610 {
611 buf[0] = '\0';
612 return (buf);
613 }
614 p++;
615 }
616 while (*p && *p != c)
617 {
618 *(q++) = *(p++);
619 }
620 *q = '\0';
621
622 return (buf);
623 }
624
opt_read(char * buf,int synth)625 int opt_read(char *buf, int synth)
626 {
627 int i, j;
628 void *p;
629 float float_val;
630
631 strtok(buf, "=");
632 i = strlen(buf);
633 while (i && buf[i] == ' ')
634 buf[i--] = '\0';
635 if (!strcasecmp(buf, "synthesizer") && cl_synth)
636 {
637 cl_synth = 0;
638 return (0);
639 }
640 if (!strcasecmp(buf, "synthesizer port") && cl_synthport)
641 {
642 cl_synthport = 0;
643 return 0;
644 }
645 for (i = 0; i < NUMOPTS; i++)
646 {
647 if (!strcasecmp(buf, opt[i].internal_name) && opt[i].synth == synth)
648 {
649 break;
650 }
651 }
652 if (i == NUMOPTS)
653 {
654 return (-1);
655 }
656 if (!(p = strtok(NULL, "")))
657 {
658 return (-1);
659 }
660 switch (opt[i].type & 0x3f)
661 {
662 case OT_INT:
663 j = strtol(p, NULL, 0);
664 opt_set(i, &j);
665 break;
666
667 case OT_FLOAT:
668 sscanf(p, "%f", &float_val);
669 opt_set(i, &float_val);
670 break;
671
672 case OT_ENUM:
673 for (j = 0; j <= opt[i].v.enum_max; j++)
674 {
675 if (!strcasecmp(p, strro(opt[i].arg[j], ':', 0)))
676 {
677 break;
678 }
679 }
680 if (j > opt[i].v.enum_max)
681 {
682 return (-1);
683 }
684 opt_set(i, &j);
685 break;
686 case OT_STR:
687 opt_set(i, p);
688 break;
689 }
690
691 return (0);
692 }
693
opt_write_single(FILE * fp,int i)694 void opt_write_single(FILE * fp, int i)
695 {
696 switch (opt[i].type & 0x3f)
697 {
698 case OT_INT:
699 (void) fprintf(fp, "%s=%d\n", opt[i].internal_name, opt_getval(i, 0));
700 break;
701 case OT_FLOAT:
702 (void) fprintf(fp, "%s=%lf\n", opt[i].internal_name, opt_getval_float(i, 0));
703 break;
704 case OT_ENUM:
705 (void) fprintf(fp, "%s=%s\n",
706 opt[i].internal_name, strro(opt[i].arg[opt_getval(i, 0)], ':', 0));
707 break;
708 case OT_STR:
709 (void) fprintf(fp, "%s=%s\n", opt[i].internal_name, (char *) opt_ptr(i));
710 break;
711 }
712 }
713
opt_write(FILE * fp)714 void opt_write(FILE * fp)
715 {
716 int i, j;
717
718 for (i = 0; i < NUMOPTS; i++)
719 {
720 if (!(opt[i].type & OT_SYNTH))
721 {
722 opt_write_single(fp, i);
723 }
724 }
725 for (i = 0; i <= opt[synthopt].v.enum_max; i++)
726 {
727 (void) fprintf(fp, "[%s]\n", opt[synthopt].arg[i]);
728 for (j = 0; j < NUMOPTS; j++)
729 {
730 if ((opt[j].type & OT_SYNTH) && opt[j].synth == i)
731 {
732 opt_write_single(fp, j);
733 }
734 }
735 }
736 }
737
opt_init()738 void opt_init()
739 {
740 opq.len = opq.lastlen = 0;
741 opt_add(&ui.curtrack, 0, N_("cursor tracking"), OT_ENUM, 3, N_("off"), N_("arrow keys"), N_("full"));
742 opt_add(&tts.synth, 0, N_("synthesizer"), OT_ENUM, 9, N_("speakout"), N_("dectalk"), N_("Emacspeak server"), N_("doubletalk"), N_("bns"), N_("apollo"), N_("festival"), N_("Ciber232"), N_("speech dispatcher"));
743 opt_add(tts.port, 0, N_("synthesizer port"), OT_STR);
744 opt_add(&ui.kbsay, 0, N_("key echo"), OT_ENUM, 3, N_("off"), N_("keys"), N_("words"));
745 opt_add(usershell, 0, N_("shell"), OT_STR);
746
747 /* tbd - The following is a bad hack that I use to play Angband. It should
748 * be replaced with a more general facility for defining screen windows.
749 */
750 opt_add(&special, 255, "special", OT_ENUM, 2, "off", "on");
751
752 opt_add(&rev.udmode, 0, N_("up and down arrows"), OT_ENUM, 3, N_("speak line"), N_("speak character"), N_("speak word"));
753
754 /* tbd - allow the user to enter 0x to indicate a Hex number, somehow */
755 opt_add(&ui.disable, 255, N_("DisableKey"), OT_INT, 0, 0x7fffffff);
756
757 opt_add(&ui.split_caps, 0, "Split caps", OT_ENUM, 2, "off", "on");
758
759 opt_add(NULL, 0, N_("synthesizer options"), OT_TREE | OT_SYNTH, -1, -1);
760
761 /* Speakout settings (first index is 10) */
762 opt_add((void *) 4, -1,N_( "rate"), OT_INT | OT_SYNTH, 0, 9, 0, "\005r%d");
763 opt_add((void *) 8, -1, N_("pitch"), OT_INT | OT_SYNTH, 0, 9, 0, "\005p%d");
764 opt_add((void *) 12, -1, N_("volume"), OT_INT | OT_SYNTH, 0, 9, 0, "\005v%d");
765 opt_add((void *) 16, -1, N_("tone"), OT_INT | OT_SYNTH, 1, 26, 0, "\005t\\l");
766 opt_add(NULL, -1, N_("Punctuation"), OT_TREE | OT_SYNTH, -2, 0);
767 opt_add(NULL, -2, N_("textual"), OT_ENUM | OT_SYNTH | OT_BITSLICE, 2, N_("off"), N_("on")":!,.:;", 0, "\005y%x", 3);
768 opt_add(NULL, -2, N_("math"), OT_ENUM | OT_SYNTH | OT_BITSLICE, 2, N_("off"), N_("on")":%^*()/-<=>+", 0, "\005y%x", 2);
769 opt_add(NULL, -2, N_("miscelaneous"), OT_ENUM | OT_SYNTH | OT_BITSLICE, 2, N_("off"), N_("on")":[]{}\\|_\"'@#$&", 0, "\005y%x", 1);
770 opt_add(NULL, -2, N_("spaces"), OT_ENUM | OT_SYNTH | OT_BITSLICE, 2, N_("off"), N_("on")": ", 0, "\005y%x", 0);
771
772 /* DEC-Talk settings (first index is 19) */
773 opt_add((void *) 4, -1, N_("rate"), OT_INT | OT_SYNTH, 75, 650, 1, "[:ra%d]");
774 opt_add((void *) 8, -1, N_("volume"), OT_INT | OT_SYNTH, 0, 99, 1, "[:vol set %d]");
775 opt_add((void *) 12, -1, N_("voice"), OT_ENUM | OT_SYNTH, 10, N_("paul"), N_("harry"), N_("frank"), N_("dennis"), N_("betty"), N_("ursula"), N_("rita"), N_("wendy"), N_("kit"), N_("val"), 1, "[:n\\p]");
776 opt_add((void *) 0, -1, N_("punctuation"), OT_ENUM | OT_SYNTH, 3, N_("some"), N_("none"), N_("all"), 1, "[:pu \\p]");
777
778 /* Emacspeak settings (first index is 23) */
779 opt_add((void *) 4, -1, N_("rate"), OT_INT | OT_SYNTH, 0, 999, 2, "tts_set_speech_rate {%d}\r");
780 opt_add((void *) 0, -1, N_("punctuation"), OT_ENUM | OT_SYNTH, 3, N_("none"), N_("some"), N_("all"), 2, "tts_set_punctuations %s\r");
781
782 /* DoubleTalk settings (first index is 24) */
783 opt_add((void *) 4, -1, N_("rate"), OT_INT | OT_SYNTH, 0, 9, 3, "\001%ds");
784 opt_add((void *) 8, -1, N_("pitch"), OT_INT | OT_SYNTH, 0, 99, 3, "\001%dp");
785 opt_add((void *) 12, -1, N_("volume"), OT_INT | OT_SYNTH, 0, 9, 3, "\001%dv");
786 opt_add((void *) 16, -1, N_("tone"), OT_INT | OT_SYNTH, 0, 2, 3, "\001%dX");
787 opt_add((void *) 20, -1, N_("voice"), OT_ENUM | OT_SYNTH, 8, N_("paul"), N_("vader"), N_("bob"), N_("pete"), N_("randy"), N_("biff"), N_("skip"), N_("roborobert"), 3, "\001%dO");
788 opt_add((void *) 0, -1, N_("punctuation"), OT_ENUM | OT_SYNTH, 4, N_("none")":\0017b", N_("some")":\0016b", N_("most")":\0015b", N_("all")":\0014b", 3, NULL);
789
790 /* Braille 'n Speak settings (first index is 30) */
791 opt_add((void *) 4, -1, N_("rate"), OT_INT | OT_SYNTH, 1, 15, 4, "\005%dE");
792 opt_add((void *) 8, -1, N_("pitch"), OT_INT | OT_SYNTH, 1, 63, 4, "\005%dP");
793 opt_add((void *) 12, -1, N_("volume"), OT_INT | OT_SYNTH, 1, 15, 4, "\005%dV");
794 opt_add((void *) 0, -1, N_("punctuation"), OT_ENUM | OT_SYNTH, 4, N_("none"), N_("some"), N_("most"), N_("all"), 4, "\005\\?");
795
796 /* Apollo settings (first index is 34) */
797 opt_add((void *) 0, -1, N_("punctuation"), OT_ENUM | OT_SYNTH, 2, N_("off"), N_("on"), 5, "@P%d");
798 opt_add((void *) 4, -1, N_("rate"), OT_INT | OT_SYNTH, 1, 9, 5, "@W%d");
799 opt_add((void *) 8, -1, N_("pitch"), OT_INT | OT_SYNTH, 1, 15, 5, "@F%x");
800 opt_add((void *) 12, -1, N_("prosody"), OT_INT | OT_SYNTH, 1, 7, 5, "@R%d");
801 opt_add((void *) 16, -1, N_("word pause"), OT_INT | OT_SYNTH, 1, 9, 5, "@Q%d");
802 opt_add((void *) 20, -1, N_("sentence pause"), OT_INT | OT_SYNTH, 1, 15, 5, "@D%x");
803 opt_add((void *) 24, -1, N_("degree"), OT_INT | OT_SYNTH, 1, 8, 5, "@B%d");
804 opt_add((void *) 28, -1, N_("volume"), OT_INT | OT_SYNTH, 1, 15, 5, "@A%x");
805 opt_add((void *) 32, -1, N_("voice"), OT_INT | OT_SYNTH, 1, 6, 5, "@V%d");
806
807 /* festival settings (first index is 44) */
808 opt_add((void *)4, -1, N_("rate"), OT_FLOAT|OT_SYNTH, (double)0.4, (double)2.5, 6, "(Parameter.set 'Duration_Stretch %e)");
809
810 /* Ciber232 settings (first index 44)*/
811 opt_add((void *) 4, -1, N_("rate"), OT_INT | OT_SYNTH, 0, 9, 7, "@b%d");
812 opt_add((void *) 8, -1, N_("volume"), OT_INT | OT_SYNTH, 0, 9, 7, "@d%d");
813 opt_add((void *) 12, -1, N_("pitch"), OT_INT | OT_SYNTH, 0, 9, 7, "@a%d");
814 opt_add((void *) 16, -1, N_("sex"), OT_INT | OT_SYNTH, 0, 1, 7, "@c%d");
815 opt_add((void *) 20, -1, N_("Voice"), OT_INT | OT_SYNTH, 0, 1, 7, "@q%d");
816 opt_add((void *) 24, -1, N_("entonation"), OT_INT | OT_SYNTH, 0, 9, 7, "@r%d");
817 opt_add((void *) 28, -1, N_("caseonwarning"), OT_INT | OT_SYNTH, 0, 1, 7, "@n%d");
818 opt_add((void *) 32, -1, N_("deviceonwarning"), OT_INT | OT_SYNTH, 0, 1, 7, "@t%d");
819
820 /* Speech Dispatcher settings (first index ?52?)*/
821 opt_add((void *) 4, -1, N_("rate"), OT_INT | OT_SYNTH, -100, 100, 8, "SET SELF RATE %d\r\n");
822 opt_add((void *) 8, -1, N_("pitch"), OT_INT | OT_SYNTH, -100, 100, 8, "SET SELF PITCH %d\r\n");
823 opt_add((void *) 12, -1, N_("volume"), OT_INT | OT_SYNTH, -100, 100, 8, "SET SELF VOLUME %d\r\n");
824 /* Language shouldn't be an enumeration! Fix me! */
825 /* Available languages: English, Spanish, and Latin. */
826 opt_add((void *) 16, -1, N_("language"), OT_ENUM | OT_SYNTH, 3, N_("en"), N_("es"), N_("la"), 8, "SET SELF LANGUAGE %s\r\n");
827 /* Output module shouldn't be an enumeration, either. */
828 opt_add((void *) 20, -1, N_("output module"), OT_ENUM | OT_SYNTH, 3, N_("espeak"), N_("flite"), N_("ibmtts"), 8, "SET SELF OUTPUT_MODULE %s\r\n");
829 opt_add((void *) 0, -1, N_("punctuation"), OT_ENUM | OT_SYNTH, 3, N_("none"), N_("some"), N_("all"), 8, "SET SELF PUNCTUATION %s\r\n");
830 }
831