23
#ifndef WITHOUT_DICTIONARY
37
#ifndef WITHOUT_DICTIONARY
40
#define RULEXDB_MAX_KEY_SIZE 50
41
#define RULEXDB_BUFSIZE 256
42
#define RULEXDB_SEARCH 0
43
#define RULEXDB_SPECIAL 1
45
typedef RULEXDB *(*rulexdb_open_function)(const char *, int);
46
typedef void (*rulexdb_close_function)(RULEXDB *);
47
typedef int (*rulexdb_search_function)(RULEXDB *, const char *, char *, int);
49
static void *dll = NULL;
50
static rulexdb_search_function rulexdb_search;
51
static rulexdb_close_function rulexdb_close;
53
static RULEXDB *rulexdb_open(const char *path, int mode)
56
dll = dlopen(RULEX_DLL, RTLD_LAZY);
59
rulexdb_open_function do_open = (rulexdb_open_function) dlsym(dll, "rulexdb_open");
60
rulexdb_search = (rulexdb_search_function) dlsym(dll, "rulexdb_search");
61
rulexdb_close = (rulexdb_close_function) dlsym(dll, "rulexdb_close");
64
return do_open(path, mode);
67
fprintf(stderr, "%s\nDictionary will not be searched\n", err);
73
static const char symbols[] =
90
static const char *charset = "ru_RU.koi8r";
91
static const char *alphabet;
94
static const char *help_msg =
95
"Speech control options:\n"
96
"-r value -- Speech rate factor.\n"
97
"-p value -- Voice pitch factor.\n"
98
"-e value -- Generated speech emotionality factor.\n"
99
"-g value -- Interclause gaps duration factor.\n"
100
"-a -- Use alternative (female) voice.\n\n"
102
"Numbers treatment control options:\n"
103
"-d. -- Only point should be treated as decimal separator.\n"
104
"-d, -- Only comma should be treated as decimal separator.\n"
105
"-d- -- Disable decimal separators treating.\n\n"
108
#ifndef WITHOUT_DICTIONARY
109
"-s path -- Pronunciation dictionary location.\n"
110
"-l path -- Log unknown words in specified file\n"
111
" (does matter only in conjunction with pronunciation dictionary).\n"
113
"-v -- Print name and version on stderr and exit.\n"
114
"-h -- Get this help.\n\n"
116
"All numeric parameters must be positive numbers. Default value is 1.0.\n\n"
118
"A value for -g option may be prepended by one of the following\n"
119
"punctuations: ',', '.', ';', ':', '?', '!'. In this case the factor\n"
120
"will be applied only to the gaps implied by that punctuation.\n"
121
"If the value is prepended by symbol '-', it will be used for\n"
122
"intonational gaps not caused by any punctuation.\n"
123
"Otherwise all interclause gaps will be affected.\n"
124
"Use this option several times to adjust various gaps.\n";
126
static const char *clause_separators = ",.;:?!-";
128
static int wave_consumer(void *buffer, size_t size, void *user_data)
131
*rc = (write(1, buffer, size) == -1);
133
perror("Output error");
137
static void *xrealloc(void *p, unsigned int n)
139
void *u = realloc(p, n);
143
perror("Memory allocation error");
148
static void *xmalloc(unsigned int n)
151
return xrealloc(u, n);
154
static int getval(const char *s)
157
double value = strtod(s, &t);
158
if ((s == t) || (value < 0.0))
160
fprintf(stderr, "Illegal option value \"%s\"\n", s);
161
fprintf(stderr, "Must be a positive number\n");
164
return rint(value * 100.0);
167
static void usage(const char* name)
169
fprintf(stderr, "Usage:\n");
170
fprintf(stderr, "%s [options]\n\n", name);
171
fprintf(stderr, "%s\n", help_msg);
174
int main(int argc, char **argv)
178
char c, *s, *text, *input = NULL;
180
#ifndef WITHOUT_DICTIONARY
184
ru_tts_conf_t ru_tts_config;
186
ru_tts_config_init(&ru_tts_config);
187
while ((c = getopt(argc, argv, "s:l:r:p:g:e:d:ahv")) != -1)
192
#ifndef WITHOUT_DICTIONARY
193
db = rulexdb_open(optarg, RULEXDB_SEARCH);
197
if (!db) perror(optarg);
199
fprintf(stderr, "Unsupported option \"-s\" is ignored\n");
203
#ifndef WITHOUT_DICTIONARY
206
fprintf(stderr, "Unsupported option \"-l\" is ignored\n");
210
ru_tts_config.flags |= USE_ALTERNATIVE_VOICE;
213
ru_tts_config.speech_rate = getval(optarg);
216
ru_tts_config.voice_pitch = getval(optarg);
219
if (strchr(clause_separators, *optarg))
223
ru_tts_config.comma_gap_factor = getval(optarg + 1);
226
ru_tts_config.dot_gap_factor = getval(optarg + 1);
229
ru_tts_config.semicolon_gap_factor = getval(optarg + 1);
232
ru_tts_config.colon_gap_factor = getval(optarg + 1);
235
ru_tts_config.question_gap_factor = getval(optarg + 1);
238
ru_tts_config.exclamation_gap_factor = getval(optarg + 1);
241
ru_tts_config.intonational_gap_factor = getval(optarg + 1);
246
else ru_tts_config.general_gap_factor = getval(optarg);
249
ru_tts_config.intonation = getval(optarg);
252
ru_tts_config.flags &= ~(DEC_SEP_POINT | DEC_SEP_COMMA);
256
ru_tts_config.flags |= DEC_SEP_POINT;
259
ru_tts_config.flags |= DEC_SEP_COMMA;
263
fprintf(stderr, "Invalid option \"-d%s\"\n\n", optarg);
272
fprintf(stderr, "%s version %s\n\n", PACKAGE_NAME, PACKAGE_VERSION);
275
fprintf(stderr, "\n");
281
#ifndef WITHOUT_DICTIONARY
284
if (setlocale(LC_CTYPE, charset))
288
slog = fopen(input, "a");
289
if (!slog) perror(input);
291
alphabet = symbols + 2;
295
fprintf(stderr, "Cannot set \"%s\" locale.\n", charset);
296
fprintf(stderr, "Dictionary will not be searched\n");
311
wave = xmalloc(WAVE_SIZE);
312
text = xmalloc(size);
316
input = fgets(s, text + size - s, stdin);
319
s = text + strlen(text) - 1;
322
for (*s-- = 0; *text; s--)
324
if (*s == ' ') *s = 0;
327
#ifndef WITHOUT_DICTIONARY
330
char *stressed = xmalloc(strlen(text) << 1);
333
for (s = text; *s; s++)
340
if ((n = strcspn(s, symbols)))
346
if ((n = strspn(s, symbols)))
348
if ((n <= RULEXDB_MAX_KEY_SIZE) && (n <= strspn(s, alphabet)))
350
char *key = xmalloc(RULEXDB_BUFSIZE);
353
if (rulexdb_search(db, key, t, 0)
355
if (slog) (void)fprintf(slog, "%s\n", key);
368
ru_tts_transfer(&ru_tts_config, stressed, wave, WAVE_SIZE, wave_consumer, &write_error);
373
ru_tts_transfer(&ru_tts_config, text, wave, WAVE_SIZE, wave_consumer, &write_error);
380
text = xrealloc(text, size <<= 1);
381
s = text + strlen(text);
386
#ifndef WITHOUT_DICTIONARY
399
return write_error ? EXIT_FAILURE : EXIT_SUCCESS;