summaryrefslogtreecommitdiff
path: root/navit/support/espeak/espeak.c
diff options
context:
space:
mode:
Diffstat (limited to 'navit/support/espeak/espeak.c')
-rw-r--r--navit/support/espeak/espeak.c314
1 files changed, 230 insertions, 84 deletions
diff --git a/navit/support/espeak/espeak.c b/navit/support/espeak/espeak.c
index 7997d0673..028650272 100644
--- a/navit/support/espeak/espeak.c
+++ b/navit/support/espeak/espeak.c
@@ -1,5 +1,5 @@
/***************************************************************************
- * Copyright (C) 2006 to 2007 by Jonathan Duddington *
+ * Copyright (C) 2006 to 2013 by Jonathan Duddington *
* email: jonsd@users.sourceforge.net *
* *
* This program is free software; you can redistribute it and/or modify *
@@ -20,10 +20,15 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
+#ifndef NEED_GETOPT
#include <getopt.h>
+#include <stdbool.h> //for "true"
+#endif
#include <time.h>
#include <sys/stat.h>
+#include "speech.h"
#include "speak_lib.h"
// This version of the command-line speak program uses the
@@ -32,51 +37,55 @@
static const char *help_text =
-"\nspeak [options] [\"<words>\"]\n\n"
+"\nespeak [options] [\"<words>\"]\n\n"
"-f <text file> Text file to speak\n"
"--stdin Read text input from stdin instead of a file\n\n"
-"If neither -f nor --stdin, <words> are spoken, or if none then text is\n"
-"spoken from stdin, each line separately.\n\n"
+"If neither -f nor --stdin, then <words> are spoken, or if none then text\n"
+"is spoken from stdin, each line separately.\n\n"
"-a <integer>\n"
"\t Amplitude, 0 to 200, default is 100\n"
"-g <integer>\n"
"\t Word gap. Pause between words, units of 10mS at the default speed\n"
+"-k <integer>\n"
+"\t Indicate capital letters with: 1=sound, 2=the word \"capitals\",\n"
+"\t higher values indicate a pitch increase (try -k20).\n"
"-l <integer>\n"
"\t Line length. If not zero (which is the default), consider\n"
"\t lines less than this length as end-of-clause\n"
"-p <integer>\n"
"\t Pitch adjustment, 0 to 99, default is 50\n"
"-s <integer>\n"
-"\t Speed in words per minute, 80 to 390, default is 170\n"
+"\t Speed in words per minute, 80 to 450, default is 175\n"
"-v <voice name>\n"
"\t Use voice file of this name from espeak-data/voices\n"
"-w <wave file name>\n"
-"\t Write output to this WAV file, rather than speaking it directly\n"
+"\t Write speech to this WAV file, rather than speaking it directly\n"
"-b\t Input text encoding, 1=UTF8, 2=8 bit, 4=16 bit \n"
"-m\t Interpret SSML markup, and ignore other < > tags\n"
"-q\t Quiet, don't produce any speech (may be useful with -x)\n"
"-x\t Write phoneme mnemonics to stdout\n"
"-X\t Write phonemes mnemonics and translation trace to stdout\n"
"-z\t No final sentence pause at the end of the text\n"
-"--stdout Write speech output to stdout\n"
"--compile=<voice name>\n"
-"\t Compile the pronunciation rules and dictionary in the current\n"
-"\t directory. =<voice name> is optional and specifies which language\n"
+"\t Compile pronunciation rules and dictionary from the current\n"
+"\t directory. <voice name> specifies the language\n"
+"--ipa Write phonemes to stdout using International Phonetic Alphabet\n"
+"\t --ipa=1 Use ties, --ipa=2 Use ZWJ, --ipa=3 Separate with _\n"
"--path=\"<path>\"\n"
"\t Specifies the directory containing the espeak-data directory\n"
+"--pho Write mbrola phoneme data (.pho) to stdout or to the file in --phonout\n"
"--phonout=\"<filename>\"\n"
-"\t Write output from -x -X commands and mbrola phoneme data to this file\n"
+"\t Write phoneme output from -x -X --ipa and --pho to this file\n"
"--punct=\"<characters>\"\n"
"\t Speak the names of punctuation characters during speaking. If\n"
"\t =<characters> is omitted, all punctuation is spoken.\n"
"--split=\"<minutes>\"\n"
"\t Starts a new WAV file every <minutes>. Used with -w\n"
+"--stdout Write speech output to stdout\n"
+"--version Shows version number and date, and location of espeak-data\n"
"--voices=<language>\n"
"\t List the available voices for the specified language.\n"
-"\t If <language> is omitted, then list all voices.\n"
-"-k <integer>\n"
-"\t Indicate capital letters with: 1=sound, 2=the word \"capitals\",\n"
-"\t higher values = a pitch increase (try -k20).\n";
+"\t If <language> is omitted, then list all voices.\n";
@@ -85,6 +94,7 @@ int samplerate;
int quiet = 0;
unsigned int samples_total = 0;
unsigned int samples_split = 0;
+unsigned int samples_split_seconds = 0;
unsigned int wavefile_count = 0;
FILE *f_wavfile = NULL;
@@ -116,20 +126,22 @@ void strncpy0(char *dest, const char *source, int size)
}
-void DisplayVoices(FILE *f_out, char *language)
+static void DisplayVoices(FILE *f_out, char *language)
{//============================================
int ix;
const char *p;
int len;
int count;
- int scores = 0;
+ int c;
+ int j;
const espeak_VOICE *v;
const char *lang_name;
char age_buf[12];
+ char buf[80];
const espeak_VOICE **voices;
espeak_VOICE voice_select;
- static char genders[4] = {' ','M','F',' '};
+ static char genders[4] = {'-','M','F','-'};
if((language != NULL) && (language[0] != 0))
{
@@ -139,14 +151,13 @@ void DisplayVoices(FILE *f_out, char *language)
voice_select.gender = 0;
voice_select.name = NULL;
voices = espeak_ListVoices(&voice_select);
- scores = 1;
}
else
{
voices = espeak_ListVoices(NULL);
}
- fprintf(f_out,"Pty Language Age/Gender VoiceName File Other Langs\n");
+ fprintf(f_out,"Pty Language Age/Gender VoiceName File Other Languages\n");
for(ix=0; (v = voices[ix]) != NULL; ix++)
{
@@ -164,8 +175,16 @@ void DisplayVoices(FILE *f_out, char *language)
if(count==0)
{
- fprintf(f_out,"%2d %-12s%s%c %-17s %-11s ",
- p[0],lang_name,age_buf,genders[v->gender],v->name,v->identifier);
+ for(j=0; j < sizeof(buf); j++)
+ {
+ // replace spaces in the name
+ if((c = v->name[j]) == ' ')
+ c = '_';
+ if((buf[j] = c) == 0)
+ break;
+ }
+ fprintf(f_out,"%2d %-12s%s%c %-20s %-13s ",
+ p[0],lang_name,age_buf,genders[v->gender],buf,v->identifier);
}
else
{
@@ -174,8 +193,6 @@ void DisplayVoices(FILE *f_out, char *language)
count++;
p += len+2;
}
-// if(scores)
-// fprintf(f_out,"%3d ",v->score);
fputc('\n',f_out);
}
} // end of DisplayVoices
@@ -197,7 +214,7 @@ static void Write4Bytes(FILE *f, int value)
-int OpenWavFile(char *path, int rate)
+static int OpenWavFile(char *path, int rate)
//===================================
{
static unsigned char wave_hdr[44] = {
@@ -208,28 +225,34 @@ int OpenWavFile(char *path, int rate)
if(path == NULL)
return(2);
- if(path[0] == 0)
- return(0);
-
- if(strcmp(path,"stdout")==0)
- f_wavfile = stdout;
- else
- f_wavfile = fopen(path,"wb");
+ while(isspace(*path)) path++;
- if(f_wavfile != NULL)
+ f_wavfile = NULL;
+ if(path[0] != 0)
{
- fwrite(wave_hdr,1,24,f_wavfile);
- Write4Bytes(f_wavfile,rate);
- Write4Bytes(f_wavfile,rate * 2);
- fwrite(&wave_hdr[32],1,12,f_wavfile);
- return(0);
+ if(strcmp(path,"stdout")==0)
+ f_wavfile = stdout;
+ else
+ f_wavfile = fopen(path,"wb");
+ }
+
+ if(f_wavfile == NULL)
+ {
+ fprintf(stderr,"Can't write to: '%s'\n",path);
+ return(1);
}
- return(1);
+
+
+ fwrite(wave_hdr,1,24,f_wavfile);
+ Write4Bytes(f_wavfile,rate);
+ Write4Bytes(f_wavfile,rate * 2);
+ fwrite(&wave_hdr[32],1,12,f_wavfile);
+ return(0);
} // end of OpenWavFile
-static void CloseWavFile()
+static void CloseWavFile(void)
//========================
{
unsigned int pos;
@@ -264,25 +287,40 @@ static int SynthCallback(short *wav, int numsamples, espeak_EVENT *events)
return(0);
}
- if(samples_split > 0)
+ while(events->type != 0)
{
- // start a new WAV file when this limit is reached, at the next sentence boundary
- while(events->type != 0)
+ if(events->type == espeakEVENT_SAMPLERATE)
{
- if((events->type == espeakEVENT_SENTENCE) && (samples_total > samples_split))
+ samplerate = events->id.number;
+ samples_split = samples_split_seconds * samplerate;
+ }
+ else
+ if(events->type == espeakEVENT_SENTENCE)
+ {
+ // start a new WAV file when the limit is reached, at this sentence boundary
+ if((samples_split > 0) && (samples_total > samples_split))
{
CloseWavFile();
samples_total = 0;
+ wavefile_count++;
}
- events++;
}
+ events++;
}
if(f_wavfile == NULL)
{
- sprintf(fname,"%s_%.2d%s",wavefile,++wavefile_count,filetype);
- if(OpenWavFile(fname, samplerate) != 0)
- return(1);
+ if(samples_split > 0)
+ {
+ sprintf(fname,"%s_%.2d%s",wavefile,wavefile_count+1,filetype);
+ if(OpenWavFile(fname, samplerate) != 0)
+ return(1);
+ }
+ else
+ {
+ if(OpenWavFile(wavefile, samplerate) != 0)
+ return(1);
+ }
}
if(numsamples > 0)
@@ -294,6 +332,32 @@ static int SynthCallback(short *wav, int numsamples, espeak_EVENT *events)
}
+static void PrintVersion(void)
+{//=======================
+ const char *version;
+ const char *path_data;
+ espeak_Initialize(AUDIO_OUTPUT_SYNCHRONOUS, 0, NULL, espeakINITIALIZE_DONT_EXIT);
+ version = espeak_Info(&path_data);
+ printf("eSpeak text-to-speech: %s Data at: %s\n", version, path_data);
+}
+
+
+
+#ifdef NEED_GETOPT
+ struct option {
+ char *name;
+ int has_arg;
+ int *flag;
+ int val;
+ };
+ int optind;
+ static int optional_argument;
+ static const char *arg_opts = "abfgklpsvw"; // which options have arguments
+ static char *opt_string="";
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+#endif
int main (int argc, char **argv)
//==============================
@@ -315,7 +379,10 @@ int main (int argc, char **argv)
{"stdout", no_argument, 0, 0x105},
{"split", optional_argument, 0, 0x106},
{"path", required_argument, 0, 0x107},
- {"phonout", required_argument, 0, 0x108},
+ {"phonout", required_argument, 0, 0x108},
+ {"pho", no_argument, 0, 0x109},
+ {"ipa", optional_argument, 0, 0x10a},
+ {"version", no_argument, 0, 0x10b},
{0, 0, 0, 0}
};
@@ -330,6 +397,7 @@ int main (int argc, char **argv)
int option_index = 0;
int c;
int ix;
+ char *optarg2;
int value;
int flag_stdin = 0;
int flag_compile = 0;
@@ -342,25 +410,78 @@ int main (int argc, char **argv)
int wordgap = -1;
int option_capitals = -1;
int option_punctuation = -1;
- int option_phonemes = -1;
+ int option_phonemes = 0;
+ int option_mbrola_phonemes = 0;
int option_linelength = 0;
int option_waveout = 0;
espeak_VOICE voice_select;
char filename[200];
char voicename[40];
- char voice_mbrola[20];
- char dictname[40];
#define N_PUNCTLIST 100
wchar_t option_punctlist[N_PUNCTLIST];
voicename[0] = 0;
- voice_mbrola[0] = 0;
- dictname[0] = 0;
wavefile[0] = 0;
filename[0] = 0;
option_punctlist[0] = 0;
+#ifdef NEED_GETOPT
+ optind = 1;
+ opt_string = "";
+ while(optind < argc)
+ {
+ int len;
+ char *p;
+
+ if((c = *opt_string) == 0)
+ {
+ opt_string = argv[optind];
+ if(opt_string[0] != '-')
+ break;
+
+ optind++;
+ opt_string++;
+ c = *opt_string;
+ }
+ opt_string++;
+ p = optarg2 = opt_string;
+
+ if(c == '-')
+ {
+ if(p[0] == 0)
+ break; // -- means don't interpret further - as commands
+
+ opt_string="";
+ for(ix=0; ;ix++)
+ {
+ if(long_options[ix].name == 0)
+ break;
+ len = strlen(long_options[ix].name);
+ if(memcmp(long_options[ix].name,p,len)==0)
+ {
+ c = long_options[ix].val;
+ optarg2 = NULL;
+
+ if((long_options[ix].has_arg != 0) && (p[len]=='='))
+ {
+ optarg2 = &p[len+1];
+ }
+ break;
+ }
+ }
+ }
+ else
+ if(strchr(arg_opts,c) != NULL)
+ {
+ opt_string="";
+ if(optarg2[0]==0)
+ {
+ // the option's value is in the next argument
+ optarg2 = argv[optind++];
+ }
+ }
+#else
while(true)
{
c = getopt_long (argc, argv, "a:b:f:g:hk:l:mp:qs:v:w:xXz",
@@ -369,12 +490,14 @@ int main (int argc, char **argv)
/* Detect the end of the options. */
if (c == -1)
break;
+ optarg2 = optarg;
+#endif
switch (c)
{
case 'b':
// input character encoding, 8bit, 16bit, UTF8
- if((sscanf(optarg,"%d",&value) == 1) && (value <= 4))
+ if((sscanf(optarg2,"%d",&value) == 1) && (value <= 4))
synth_flags |= value;
else
synth_flags |= espeakCHARS_8BIT;
@@ -382,12 +505,13 @@ int main (int argc, char **argv)
case 'h':
printf("\n");
- printf("eSpeak text-to-speech: %s\n%s",espeak_Info(),help_text);
+ PrintVersion();
+ printf("%s", help_text);
exit(0);
break;
case 'k':
- option_capitals = atoi(optarg);
+ option_capitals = atoi(optarg2);
break;
case 'x':
@@ -403,7 +527,7 @@ int main (int argc, char **argv)
break;
case 'p':
- pitch = atoi(optarg);
+ pitch = atoi(optarg2);
break;
case 'q':
@@ -411,32 +535,32 @@ int main (int argc, char **argv)
break;
case 'f':
- strncpy0(filename,optarg,sizeof(filename));
+ strncpy0(filename,optarg2,sizeof(filename));
break;
case 'l':
- option_linelength = atoi(optarg);
+ option_linelength = atoi(optarg2);
break;
case 'a':
- volume = atoi(optarg);
+ volume = atoi(optarg2);
break;
case 's':
- speed = atoi(optarg);
+ speed = atoi(optarg2);
break;
case 'g':
- wordgap = atoi(optarg);
+ wordgap = atoi(optarg2);
break;
case 'v':
- strncpy0(voicename,optarg,sizeof(voicename));
+ strncpy0(voicename,optarg2,sizeof(voicename));
break;
case 'w':
option_waveout = 1;
- strncpy0(wavefile,optarg,sizeof(filename));
+ strncpy0(wavefile,optarg2,sizeof(filename));
break;
case 'z': // remove pause from the end of a sentence
@@ -454,17 +578,17 @@ int main (int argc, char **argv)
case 0x101: // --compile-debug
case 0x102: // --compile
- strncpy0(voicename,optarg,sizeof(voicename));
+ strncpy0(voicename,optarg2,sizeof(voicename));
flag_compile = c;
quiet = 1;
break;
case 0x103: // --punct
option_punctuation = 1;
- if(optarg != NULL)
+ if(optarg2 != NULL)
{
ix = 0;
- while((ix < N_PUNCTLIST) && ((option_punctlist[ix] = optarg[ix]) != 0)) ix++;
+ while((ix < N_PUNCTLIST) && ((option_punctlist[ix] = optarg2[ix]) != 0)) ix++;
option_punctlist[N_PUNCTLIST-1] = 0;
option_punctuation = 2;
}
@@ -472,27 +596,50 @@ int main (int argc, char **argv)
case 0x104: // --voices
espeak_Initialize(AUDIO_OUTPUT_SYNCHRONOUS,0,data_path,0);
- DisplayVoices(stdout,optarg);
+ DisplayVoices(stdout,optarg2);
exit(0);
case 0x106: // -- split
- if(optarg == NULL)
- samples_split = 30; // default 30 minutes
+ if(optarg2 == NULL)
+ samples_split_seconds = 30 * 60; // default 30 minutes
else
- samples_split = atoi(optarg);
+ samples_split_seconds = atoi(optarg2) * 60;
break;
case 0x107: // --path
- data_path = optarg;
+ data_path = optarg2;
break;
case 0x108: // --phonout
- if((f_phonemes_out = fopen(optarg,"w")) == NULL)
+ if((f_phonemes_out = fopen(optarg2,"w")) == NULL)
+ {
+ fprintf(stderr,"Can't write to: %s\n",optarg2);
+ }
+ break;
+
+ case 0x109: // --pho
+ option_mbrola_phonemes = 16;
+ break;
+
+ case 0x10a: // --ipa
+ option_phonemes = 3;
+ if(optarg2 != NULL)
{
- fprintf(stderr,"Can't write to: %s\n",optarg);
+ value = -1;
+ sscanf(optarg2,"%d",&value);
+ if((value<0) || (value>3))
+ {
+ fprintf(stderr,"Bad value for -ipa=\n");
+ value = 0;
+ }
+ option_phonemes += value;
}
break;
+ case 0x10b: // -version
+ PrintVersion();
+ exit(0);
+
default:
exit(0);
}
@@ -503,7 +650,7 @@ int main (int argc, char **argv)
{
// writing to a file (or no output), we can use synchronous mode
samplerate = espeak_Initialize(AUDIO_OUTPUT_SYNCHRONOUS,0,data_path,0);
- samples_split = (samplerate * samples_split) * 60;
+ samples_split = samplerate * samples_split_seconds;
espeak_SetSynthCallback(SynthCallback);
if(samples_split)
@@ -516,12 +663,6 @@ int main (int argc, char **argv)
*extn = 0;
}
}
- else
- if(option_waveout)
- {
- if(OpenWavFile(wavefile,samplerate) != 0)
- exit(4);
- }
}
else
{
@@ -568,7 +709,7 @@ int main (int argc, char **argv)
espeak_SetParameter(espeakLINELENGTH,option_linelength,0);
if(option_punctuation == 2)
espeak_SetPunctuationList(option_punctlist);
- espeak_SetPhonemeTrace(option_phonemes,f_phonemes_out);
+ espeak_SetPhonemeTrace(option_phonemes | option_mbrola_phonemes,f_phonemes_out);
if(filename[0]==0)
{
@@ -651,13 +792,18 @@ int main (int argc, char **argv)
exit(3);
}
- fread(p_text,1,filesize,f_text);
+ if(fread(p_text,1,filesize,f_text) <= 0)
+ fprintf(stderr, "unable to read from file\n");
p_text[filesize]=0;
espeak_Synth(p_text,filesize+1,0,POS_CHARACTER,0,synth_flags,NULL,NULL);
fclose(f_text);
}
- espeak_Synchronize();
+ if(espeak_Synchronize() != EE_OK)
+ {
+ fprintf(stderr, "espeak_Synchronize() failed, maybe error when opening output device\n");
+ exit(4);
+ }
if(f_phonemes_out != stdout)
fclose(f_phonemes_out); // needed for WinCE