Valdis Vitolins 9 years ago
parent
commit
a028a4ff95
44 changed files with 9057 additions and 12783 deletions
  1. 2
    1
      .gitignore
  2. 10
    3
      Makefile.am
  3. 37
    16
      README.md
  4. 54
    0
      _layouts/webpage.html
  5. 183
    254
      src/espeak-ng.c
  6. 959
    1269
      src/libespeak-ng/compiledata.c
  7. 515
    717
      src/libespeak-ng/compiledict.c
  8. 20
    28
      src/libespeak-ng/compilembrola.c
  9. 13
    19
      src/libespeak-ng/debug.c
  10. 5
    5
      src/libespeak-ng/debug.h
  11. 804
    1296
      src/libespeak-ng/dictionary.c
  12. 155
    203
      src/libespeak-ng/espeak_command.c
  13. 36
    46
      src/libespeak-ng/espeak_command.h
  14. 139
    197
      src/libespeak-ng/event.c
  15. 3
    3
      src/libespeak-ng/event.h
  16. 96
    145
      src/libespeak-ng/fifo.c
  17. 4
    4
      src/libespeak-ng/fifo.h
  18. 241
    375
      src/libespeak-ng/intonation.c
  19. 176
    265
      src/libespeak-ng/klatt.c
  20. 4
    7
      src/libespeak-ng/klatt.h
  21. 3
    3
      src/libespeak-ng/mbrowrap.c
  22. 679
    973
      src/libespeak-ng/numbers.c
  23. 3
    3
      src/libespeak-ng/phoneme.h
  24. 123
    224
      src/libespeak-ng/phonemelist.c
  25. 878
    1190
      src/libespeak-ng/readclause.c
  26. 165
    284
      src/libespeak-ng/setlengths.c
  27. 221
    308
      src/libespeak-ng/speak_lib.c
  28. 106
    139
      src/libespeak-ng/spect.c
  29. 2
    4
      src/libespeak-ng/spect.h
  30. 1
    1
      src/libespeak-ng/speech.h
  31. 148
    204
      src/libespeak-ng/synth_mbrola.c
  32. 270
    403
      src/libespeak-ng/synthdata.c
  33. 399
    625
      src/libespeak-ng/synthesize.c
  34. 3
    3
      src/libespeak-ng/synthesize.h
  35. 466
    516
      src/libespeak-ng/tr_languages.c
  36. 775
    1221
      src/libespeak-ng/translate.c
  37. 7
    8
      src/libespeak-ng/translate.h
  38. 466
    626
      src/libespeak-ng/voices.c
  39. 238
    327
      src/libespeak-ng/wave.c
  40. 9
    9
      src/libespeak-ng/wave.h
  41. 64
    79
      src/libespeak-ng/wave_pulse.c
  42. 40
    44
      src/libespeak-ng/wave_sada.c
  43. 336
    469
      src/libespeak-ng/wavegen.c
  44. 199
    267
      src/speak-ng.c

+ 2
- 1
.gitignore View File

libespeak-ng.la libespeak-ng.la
libespeak-ng.so* libespeak-ng.so*


# programs
# build output


*.html
*.exe *.exe


src/espeak-ng src/espeak-ng

+ 10
- 3
Makefile.am View File

rm -rf espeak-data/phondata-manifest rm -rf espeak-data/phondata-manifest
rm -f espeak-data/*_dict rm -f espeak-data/*_dict


##### documentation:

%.html: %.md _layouts/webpage.html
cat $< | sed -e 's/\.md)/.html)/g' | kramdown --template _layouts/webpage.html > $@

docs: README.html

docs/speak_lib.h: src/include/espeak-ng/speak_lib.h
cp $< $@

##### build targets: ##### build targets:


libespeak_ng_includedir = $(includedir)/espeak-ng libespeak_ng_includedir = $(includedir)/espeak-ng
libespeak_ng_include_HEADERS = \ libespeak_ng_include_HEADERS = \
src/include/espeak-ng/speak_lib.h src/include/espeak-ng/speak_lib.h


docs/speak_lib.h: src/include/espeak-ng/speak_lib.h
cp $< $@

lib_LTLIBRARIES += src/libespeak-ng.la lib_LTLIBRARIES += src/libespeak-ng.la


src_libespeak_ng_la_LDFLAGS = -version-info $(SHARED_VERSION) -lpthread -lm src_libespeak_ng_la_LDFLAGS = -version-info $(SHARED_VERSION) -lpthread -lm

+ 37
- 16
README.md View File

2. the portaudio development library to enable portaudio output; 2. the portaudio development library to enable portaudio output;
3. the sonic development library to enable sonic audio speed up support. 3. the sonic development library to enable sonic audio speed up support.


To build the documentation, you need:

1. the `kramdown` markdown processor.

### Debian ### Debian


Core dependencies:

| Dependency | Install | | Dependency | Install |
|---------------|------------------------------------------------------------------| |---------------|------------------------------------------------------------------|
| autotools | `sudo apt-get install make autoconf automake libtool pkg-config` | | autotools | `sudo apt-get install make autoconf automake libtool pkg-config` |
| c11 compiler | `sudo apt-get install gcc` | | c11 compiler | `sudo apt-get install gcc` |
| pulseaudio | `sudo apt-get install libpulse-dev` |
| portaudio | `sudo apt-get install libportaudio-dev` |
| sonic | `sudo apt-get install libsonic-dev` |

Optional dependencies:

| Dependency | Install |
|------------|-----------------------------------------|
| pulseaudio | `sudo apt-get install libpulse-dev` |
| portaudio | `sudo apt-get install libportaudio-dev` |
| sonic | `sudo apt-get install libsonic-dev` |

Documentation dependencies:

| Dependency | Install |
|---------------|--------------------------------------|
| kramdown | `sudo apt-get install ruby-kramdown` |


Cross-compiling for windows: Cross-compiling for windows:


| Dependency | Install |
|-------------------------|--------------------------------------------------------|
| 32-bit Windows compiler | `sudo apt-get install mingw-w64-i686-dev` |
| 64-bit Windows compiler | `sudo apt-get install mingw-w64-x86-64-dev` |
| Dependency | Install |
|-------------------------|---------------------------------------------|
| 32-bit Windows compiler | `sudo apt-get install mingw-w64-i686-dev` |
| 64-bit Windows compiler | `sudo apt-get install mingw-w64-x86-64-dev` |


## Building ## Building


The `espeak-ng` and `speak-ng` programs, along with the espeak-ng voices, can The `espeak-ng` and `speak-ng` programs, along with the espeak-ng voices, can
be built via the standard autotools commands: be built via the standard autotools commands:


$ ./autogen.sh
$ ./configure --prefix=/usr
$ make
./autogen.sh
./configure --prefix=/usr
make

The documentation can be built by running:

make doc


### Audio Output Configuration ### Audio Output Configuration




Before installing, you can test the built espeak-ng using the following command: Before installing, you can test the built espeak-ng using the following command:


$ ESPEAK_DATA_PATH=`pwd` LD_LIBRARY_PATH=src:${LD_LIBRARY_PATH} src/espeak-ng ...
ESPEAK_DATA_PATH=`pwd` LD_LIBRARY_PATH=src:${LD_LIBRARY_PATH} src/espeak-ng ...


The `ESPEAK_DATA_PATH` variable needs to be set to use the espeak-ng data from The `ESPEAK_DATA_PATH` variable needs to be set to use the espeak-ng data from
the source tree. Otherwise, espeak-ng will look in `$(HOME)` or the source tree. Otherwise, espeak-ng will look in `$(HOME)` or


You can install eSpeak NG by running the following command: You can install eSpeak NG by running the following command:


$ sudo make LIBDIR=/usr/lib/x86_64-linux-gnu install
sudo make LIBDIR=/usr/lib/x86_64-linux-gnu install


The `LIBDIR` path may be different to the one on your system (the above The `LIBDIR` path may be different to the one on your system (the above
is for 64-bit Debian/Ubuntu releases that use the multi-arch package is for 64-bit Debian/Ubuntu releases that use the multi-arch package
You can find out where espeak-ng is installed to on your system if you You can find out where espeak-ng is installed to on your system if you
already have an espeak-ng install by running: already have an espeak-ng install by running:


$ find /usr/lib | grep libespeak-ng
find /usr/lib | grep libespeak-ng


## Building Voices ## Building Voices


If you are modifying a language's phoneme, voice or dictionary files, you If you are modifying a language's phoneme, voice or dictionary files, you
can just build that voice by running: can just build that voice by running:


$ make <lang-code>
make <lang-code>


For example, if you add entries in the `dictsource/en_extra` file, you can For example, if you add entries in the `dictsource/en_extra` file, you can
run: run:


$ make en
make en


to build an English voice file with those changes in without rebuilding to build an English voice file with those changes in without rebuilding
all the voices. This will make it easier to spot errors. all the voices. This will make it easier to spot errors.
with the 1.24.02 release as the last entry. This makes it possible with the 1.24.02 release as the last entry. This makes it possible
to use the replace functionality of git to see the earlier history: to use the replace functionality of git to see the earlier history:


$ git replace 8d59235f 63c1c019
git replace 8d59235f 63c1c019


__NOTE:__ The source releases contain the `big_endian`, `espeak-edit`, __NOTE:__ The source releases contain the `big_endian`, `espeak-edit`,
`praat-mod`, `riskos`, `windows_dll` and `windows_sapi` folders. These `praat-mod`, `riskos`, `windows_dll` and `windows_sapi` folders. These

+ 54
- 0
_layouts/webpage.html View File

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width; initial-scale=1"/>
<meta name="robots" content="all"/>
<style type="text/css">
body
{
font-family: sans-serif;
font-size: 14px;
margin: 1em;
}

*:first-child
{
margin-top: 0;
}

code, pre
{
font-family: monospace;
background: #F7F7F7;
color: navy;
}

code
{
font-size: 85%;
padding: 0.2em;
}

pre
{
margin-left: 3em;
padding: 1em;
}

th
{
text-align: left;
}

hr
{
border: 0;
border-bottom: 1px solid #BBB;
}
</style>
</head>
<body>
<%= @body %>
</body>
</html>

+ 183
- 254
src/espeak-ng.c View File

#include "speak_lib.h" #include "speak_lib.h"
#include "espeak_ng.h" #include "espeak_ng.h"


extern void strncpy0(char *to,const char *from, int size);
extern void strncpy0(char *to, const char *from, int size);
extern int utf8_in(int *c, const char *buf); extern int utf8_in(int *c, const char *buf);
extern int GetFileLength(const char *filename); extern int GetFileLength(const char *filename);


const espeak_VOICE **voices; const espeak_VOICE **voices;
espeak_VOICE voice_select; espeak_VOICE voice_select;


static char genders[4] = {'-','M','F','-'};
static char genders[4] = { '-', 'M', 'F', '-' };


if((language != NULL) && (language[0] != 0))
{
if ((language != NULL) && (language[0] != 0)) {
// display only voices for the specified language, in order of priority // display only voices for the specified language, in order of priority
voice_select.languages = language; voice_select.languages = language;
voice_select.age = 0; voice_select.age = 0;
voice_select.gender = 0; voice_select.gender = 0;
voice_select.name = NULL; voice_select.name = NULL;
voices = espeak_ListVoices(&voice_select); voices = espeak_ListVoices(&voice_select);
}
else
{
} else {
voices = espeak_ListVoices(NULL); voices = espeak_ListVoices(NULL);
} }


fprintf(f_out,"Pty Language Age/Gender VoiceName File Other Languages\n");
fprintf(f_out, "Pty Language Age/Gender VoiceName File Other Languages\n");


for(ix=0; (v = voices[ix]) != NULL; ix++)
{
for (ix = 0; (v = voices[ix]) != NULL; ix++) {
count = 0; count = 0;
p = v->languages; p = v->languages;
while(*p != 0)
{
while (*p != 0) {
len = strlen(p+1); len = strlen(p+1);
lang_name = p+1; lang_name = p+1;


if(v->age == 0)
strcpy(age_buf," ");
if (v->age == 0)
strcpy(age_buf, " ");
else else
sprintf(age_buf,"%3d",v->age);
sprintf(age_buf, "%3d", v->age);


if(count==0)
{
for(j=0; j < sizeof(buf); j++)
{
if (count == 0) {
for (j = 0; j < sizeof(buf); j++) {
// replace spaces in the name // replace spaces in the name
if((c = v->name[j]) == ' ')
if ((c = v->name[j]) == ' ')
c = '_'; c = '_';
if((buf[j] = c) == 0)
if ((buf[j] = c) == 0)
break; break;
} }
fprintf(f_out,"%2d %-12s%s%c %-20s %-13s ",
p[0],lang_name,age_buf,genders[v->gender],buf,v->identifier);
}
else
{
fprintf(f_out,"(%s %d)",lang_name,p[0]);
fprintf(f_out, "%2d %-12s%s%c %-20s %-13s ",
p[0], lang_name, age_buf, genders[v->gender], buf, v->identifier);
} else {
fprintf(f_out, "(%s %d)", lang_name, p[0]);
} }
count++; count++;
p += len+2; p += len+2;
} }
fputc('\n',f_out);
fputc('\n', f_out);
} }
} }


// Write 4 bytes to a file, least significant first // Write 4 bytes to a file, least significant first
int ix; int ix;


for(ix=0; ix<4; ix++)
{
fputc(value & 0xff,f);
for (ix = 0; ix < 4; ix++) {
fputc(value & 0xff, f);
value = value >> 8; value = value >> 8;
} }
} }
int OpenWavFile(char *path, int rate) int OpenWavFile(char *path, int rate)
{ {
static unsigned char wave_hdr[44] = { static unsigned char wave_hdr[44] = {
'R','I','F','F',0x24,0xf0,0xff,0x7f,'W','A','V','E','f','m','t',' ',
0x10,0,0,0,1,0,1,0, 9,0x3d,0,0,0x12,0x7a,0,0,
2,0,0x10,0,'d','a','t','a', 0x00,0xf0,0xff,0x7f
'R', 'I', 'F', 'F', 0x24, 0xf0, 0xff, 0x7f, 'W', 'A', 'V', 'E', 'f', 'm', 't', ' ',
0x10, 0, 0, 0, 1, 0, 1, 0, 9, 0x3d, 0, 0, 0x12, 0x7a, 0, 0,
2, 0, 0x10, 0, 'd', 'a', 't', 'a', 0x00, 0xf0, 0xff, 0x7f
}; };


if(path == NULL)
return(2);
if (path == NULL)
return 2;


while(isspace(*path)) path++;
while (isspace(*path)) path++;


f_wavfile = NULL; f_wavfile = NULL;
if(path[0] != 0)
{
if(strcmp(path,"stdout")==0)
if (path[0] != 0) {
if (strcmp(path, "stdout") == 0)
f_wavfile = stdout; f_wavfile = stdout;
else else
f_wavfile = fopen(path,"wb");
f_wavfile = fopen(path, "wb");
} }


if(f_wavfile == NULL)
{
fprintf(stderr,"Can't write to: '%s'\n",path);
return(1);
if (f_wavfile == NULL) {
fprintf(stderr, "Can't write to: '%s'\n", path);
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);
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;
} }




{ {
unsigned int pos; unsigned int pos;


if((f_wavfile==NULL) || (f_wavfile == stdout))
if ((f_wavfile == NULL) || (f_wavfile == stdout))
return; return;


fflush(f_wavfile); fflush(f_wavfile);
pos = ftell(f_wavfile); pos = ftell(f_wavfile);


fseek(f_wavfile,4,SEEK_SET);
Write4Bytes(f_wavfile,pos - 8);
fseek(f_wavfile, 4, SEEK_SET);
Write4Bytes(f_wavfile, pos - 8);


fseek(f_wavfile,40,SEEK_SET);
Write4Bytes(f_wavfile,pos - 44);
fseek(f_wavfile, 40, SEEK_SET);
Write4Bytes(f_wavfile, pos - 44);


fclose(f_wavfile); fclose(f_wavfile);
f_wavfile = NULL; f_wavfile = NULL;
{ {
char fname[210]; char fname[210];


if(quiet) return(0); // -q quiet mode
if (quiet) return 0; // -q quiet mode


if(wav == NULL)
{
if (wav == NULL) {
CloseWavFile(); CloseWavFile();
return(0);
return 0;
} }


while(events->type != 0)
{
if(events->type == espeakEVENT_SAMPLERATE)
{
while (events->type != 0) {
if (events->type == espeakEVENT_SAMPLERATE) {
samplerate = events->id.number; samplerate = events->id.number;
samples_split = samples_split_seconds * samplerate; samples_split = samples_split_seconds * samplerate;
}
else
if(events->type == espeakEVENT_SENTENCE)
{
} else if (events->type == espeakEVENT_SENTENCE) {
// start a new WAV file when the limit is reached, at this sentence boundary // start a new WAV file when the limit is reached, at this sentence boundary
if((samples_split > 0) && (samples_total > samples_split))
{
if ((samples_split > 0) && (samples_total > samples_split)) {
CloseWavFile(); CloseWavFile();
samples_total = 0; samples_total = 0;
wavefile_count++; wavefile_count++;
events++; events++;
} }


if(f_wavfile == NULL)
{
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 (f_wavfile == NULL) {
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)
{
if (numsamples > 0) {
samples_total += numsamples; samples_total += numsamples;
fwrite(wav,numsamples*2,1,f_wavfile);
fwrite(wav, numsamples*2, 1, f_wavfile);
} }
return(0);
return 0;
} }




int optind; int optind;
static int optional_argument; static int optional_argument;
static const char *arg_opts = "abfgklpsvw"; // which options have arguments static const char *arg_opts = "abfgklpsvw"; // which options have arguments
static char *opt_string="";
static char *opt_string = "";
#define no_argument 0 #define no_argument 0
#define required_argument 1 #define required_argument 1
#define optional_argument 2 #define optional_argument 2
#endif #endif


int main (int argc, char **argv)
int main(int argc, char **argv)
{ {
static struct option long_options[] =
{
{"help", no_argument, 0, 'h'},
{"stdin", no_argument, 0, 0x100},
{"compile-debug", optional_argument, 0, 0x101},
{"compile", optional_argument, 0, 0x102},
{"punct", optional_argument, 0, 0x103},
{"voices", optional_argument, 0, 0x104},
{"stdout", no_argument, 0, 0x105},
{"split", optional_argument, 0, 0x106},
{"path", required_argument, 0, 0x107},
{"phonout", required_argument, 0, 0x108},
{"pho", no_argument, 0, 0x109},
{"ipa", optional_argument, 0, 0x10a},
{"version", no_argument, 0, 0x10b},
{"sep", optional_argument, 0, 0x10c},
{"tie", optional_argument, 0, 0x10d},
{"compile-mbrola", optional_argument, 0, 0x10e},
{"compile-intonations", no_argument, 0, 0x10f},
{"compile-phonemes", no_argument, 0, 0x110},
{0, 0, 0, 0}
static struct option long_options[] = {
{ "help", no_argument, 0, 'h' },
{ "stdin", no_argument, 0, 0x100 },
{ "compile-debug", optional_argument, 0, 0x101 },
{ "compile", optional_argument, 0, 0x102 },
{ "punct", optional_argument, 0, 0x103 },
{ "voices", optional_argument, 0, 0x104 },
{ "stdout", no_argument, 0, 0x105 },
{ "split", optional_argument, 0, 0x106 },
{ "path", required_argument, 0, 0x107 },
{ "phonout", required_argument, 0, 0x108 },
{ "pho", no_argument, 0, 0x109 },
{ "ipa", optional_argument, 0, 0x10a },
{ "version", no_argument, 0, 0x10b },
{ "sep", optional_argument, 0, 0x10c },
{ "tie", optional_argument, 0, 0x10d },
{ "compile-mbrola", optional_argument, 0, 0x10e },
{ "compile-intonations", no_argument, 0, 0x10f },
{ "compile-phonemes", no_argument, 0, 0x110 },
{ 0, 0, 0, 0 }
}; };


static const char* err_load = "Failed to read ";
static const char *err_load = "Failed to read ";




FILE *f_text=NULL;
char *p_text=NULL;
FILE *f_text = NULL;
char *p_text = NULL;
FILE *f_phonemes_out = stdout; FILE *f_phonemes_out = stdout;
char *data_path = NULL; // use default path for espeak-data char *data_path = NULL; // use default path for espeak-data


#ifdef NEED_GETOPT #ifdef NEED_GETOPT
optind = 1; optind = 1;
opt_string = ""; opt_string = "";
while(optind < argc)
{
while (optind < argc) {
int len; int len;
char *p; char *p;


if((c = *opt_string) == 0)
{
if ((c = *opt_string) == 0) {
opt_string = argv[optind]; opt_string = argv[optind];
if(opt_string[0] != '-')
if (opt_string[0] != '-')
break; break;


optind++; optind++;
opt_string++; opt_string++;
p = optarg2 = opt_string; p = optarg2 = opt_string;


if(c == '-')
{
if(p[0] == 0)
if (c == '-') {
if (p[0] == 0)
break; // -- means don't interpret further - as commands break; // -- means don't interpret further - as commands


opt_string="";
for(ix=0;; ix++)
{
if(long_options[ix].name == 0)
opt_string = "";
for (ix = 0;; ix++) {
if (long_options[ix].name == 0)
break; break;
len = strlen(long_options[ix].name); len = strlen(long_options[ix].name);
if(memcmp(long_options[ix].name,p,len)==0)
{
if (memcmp(long_options[ix].name, p, len) == 0) {
c = long_options[ix].val; c = long_options[ix].val;
optarg2 = NULL; optarg2 = NULL;


if((long_options[ix].has_arg != 0) && (p[len]=='='))
{
if ((long_options[ix].has_arg != 0) && (p[len] == '=')) {
optarg2 = &p[len+1]; optarg2 = &p[len+1];
} }
break; break;
} }
} }
}
else
if(strchr(arg_opts,c) != NULL)
{
opt_string="";
if(optarg2[0]==0)
{
} else if (strchr(arg_opts, c) != NULL) {
opt_string = "";
if (optarg2[0] == 0) {
// the option's value is in the next argument // the option's value is in the next argument
optarg2 = argv[optind++]; optarg2 = argv[optind++];
} }
} }
#else #else
while(true)
{
c = getopt_long (argc, argv, "a:b:f:g:hk:l:mp:qs:v:w:xXz",
long_options, &option_index);
while (true) {
c = getopt_long(argc, argv, "a:b:f:g:hk:l:mp:qs:v:w:xXz",
long_options, &option_index);


/* Detect the end of the options. */ /* Detect the end of the options. */
if (c == -1) if (c == -1)
{ {
case 'b': case 'b':
// input character encoding, 8bit, 16bit, UTF8 // input character encoding, 8bit, 16bit, UTF8
if((sscanf(optarg2,"%d",&value) == 1) && (value <= 4))
if ((sscanf(optarg2, "%d", &value) == 1) && (value <= 4))
synth_flags |= value; synth_flags |= value;
else else
synth_flags |= espeakCHARS_8BIT; synth_flags |= espeakCHARS_8BIT;
break; break;


case 'f': case 'f':
strncpy0(filename,optarg2,sizeof(filename));
strncpy0(filename, optarg2, sizeof(filename));
break; break;


case 'l': case 'l':
break; break;


case 'v': case 'v':
strncpy0(voicename,optarg2,sizeof(voicename));
strncpy0(voicename, optarg2, sizeof(voicename));
break; break;


case 'w': case 'w':
option_waveout = 1; option_waveout = 1;
strncpy0(wavefile,optarg2,sizeof(filename));
strncpy0(wavefile, optarg2, sizeof(filename));
break; break;


case 'z': // remove pause from the end of a sentence case 'z': // remove pause from the end of a sentence


case 0x105: // --stdout case 0x105: // --stdout
option_waveout = 1; option_waveout = 1;
strcpy(wavefile,"stdout");
strcpy(wavefile, "stdout");
break; break;


case 0x101: // --compile-debug case 0x101: // --compile-debug
case 0x102: // --compile case 0x102: // --compile
strncpy0(voicename,optarg2,sizeof(voicename));
strncpy0(voicename, optarg2, sizeof(voicename));
flag_compile = c; flag_compile = c;
quiet = 1; quiet = 1;
break; break;


case 0x103: // --punct case 0x103: // --punct
option_punctuation = 1; option_punctuation = 1;
if(optarg2 != NULL)
{
if (optarg2 != NULL) {
ix = 0; ix = 0;
while((ix < N_PUNCTLIST) && ((option_punctlist[ix] = optarg2[ix]) != 0)) ix++;
while ((ix < N_PUNCTLIST) && ((option_punctlist[ix] = optarg2[ix]) != 0)) ix++;
option_punctlist[N_PUNCTLIST-1] = 0; option_punctlist[N_PUNCTLIST-1] = 0;
option_punctuation = 2; option_punctuation = 2;
} }
break; break;


case 0x104: // --voices case 0x104: // --voices
espeak_Initialize(AUDIO_OUTPUT_SYNCHRONOUS,0,data_path,0);
DisplayVoices(stdout,optarg2);
espeak_Initialize(AUDIO_OUTPUT_SYNCHRONOUS, 0, data_path, 0);
DisplayVoices(stdout, optarg2);
exit(0); exit(0);


case 0x106: // -- split case 0x106: // -- split
if(optarg2 == NULL)
if (optarg2 == NULL)
samples_split_seconds = 30 * 60; // default 30 minutes samples_split_seconds = 30 * 60; // default 30 minutes
else else
samples_split_seconds = atoi(optarg2) * 60; samples_split_seconds = atoi(optarg2) * 60;
break; break;


case 0x108: // --phonout case 0x108: // --phonout
if((f_phonemes_out = fopen(optarg2,"w")) == NULL)
{
fprintf(stderr,"Can't write to: %s\n",optarg2);
if ((f_phonemes_out = fopen(optarg2, "w")) == NULL) {
fprintf(stderr, "Can't write to: %s\n", optarg2);
} }
break; break;




case 0x10a: // --ipa case 0x10a: // --ipa
phoneme_options |= espeakPHONEMES_IPA; phoneme_options |= espeakPHONEMES_IPA;
if(optarg2 != NULL)
{
if (optarg2 != NULL) {
// deprecated and obsolete // deprecated and obsolete
switch(atoi(optarg2))
switch (atoi(optarg2))
{ {
case 1: case 1:
phonemes_separator = '_'; phonemes_separator = '_';


case 0x10c: // --sep case 0x10c: // --sep
phoneme_options |= espeakPHONEMES_SHOW; phoneme_options |= espeakPHONEMES_SHOW;
if(optarg2 == 0)
if (optarg2 == 0)
phonemes_separator = ' '; phonemes_separator = ' ';
else else
utf8_in(&phonemes_separator, optarg2); utf8_in(&phonemes_separator, optarg2);
if(phonemes_separator == 'z')
if (phonemes_separator == 'z')
phonemes_separator = 0x200c; // ZWNJ phonemes_separator = 0x200c; // ZWNJ
break; break;


case 0x10d: // --tie case 0x10d: // --tie
phoneme_options |= (espeakPHONEMES_SHOW | espeakPHONEMES_TIE); phoneme_options |= (espeakPHONEMES_SHOW | espeakPHONEMES_TIE);
if(optarg2 == 0)
if (optarg2 == 0)
phonemes_separator = 0x0361; // default: combining-double-inverted-breve phonemes_separator = 0x0361; // default: combining-double-inverted-breve
else else
utf8_in(&phonemes_separator, optarg2); utf8_in(&phonemes_separator, optarg2);
if(phonemes_separator == 'z')
if (phonemes_separator == 'z')
phonemes_separator = 0x200d; // ZWJ phonemes_separator = 0x200d; // ZWJ
break; break;


case 0x10e: // --compile-mbrola case 0x10e: // --compile-mbrola
samplerate = espeak_Initialize(AUDIO_OUTPUT_PLAYBACK,0,data_path,0);
samplerate = espeak_Initialize(AUDIO_OUTPUT_PLAYBACK, 0, data_path, 0);
espeak_ng_CompileMbrolaVoice(optarg2, stdout); espeak_ng_CompileMbrolaVoice(optarg2, stdout);
exit(0); exit(0);


case 0x10f: // --compile-intonations case 0x10f: // --compile-intonations
samplerate = espeak_Initialize(AUDIO_OUTPUT_PLAYBACK,0,data_path,espeakINITIALIZE_PATH_ONLY);
samplerate = espeak_Initialize(AUDIO_OUTPUT_PLAYBACK, 0, data_path, espeakINITIALIZE_PATH_ONLY);
espeak_ng_CompileIntonation(stdout); espeak_ng_CompileIntonation(stdout);
exit(0); exit(0);


case 0x110: // --compile-phonemes case 0x110: // --compile-phonemes
samplerate = espeak_Initialize(AUDIO_OUTPUT_PLAYBACK,0,data_path,espeakINITIALIZE_PATH_ONLY);
samplerate = espeak_Initialize(AUDIO_OUTPUT_PLAYBACK, 0, data_path, espeakINITIALIZE_PATH_ONLY);
espeak_ng_CompilePhonemeData(22050, stdout); espeak_ng_CompilePhonemeData(22050, stdout);
exit(0); exit(0);


} }




if(option_waveout || quiet)
{
if (option_waveout || quiet) {
// writing to a file (or no output), we can use synchronous mode // writing to a file (or no output), we can use synchronous mode
samplerate = espeak_Initialize(AUDIO_OUTPUT_SYNCHRONOUS,0,data_path,0);
samplerate = espeak_Initialize(AUDIO_OUTPUT_SYNCHRONOUS, 0, data_path, 0);
samples_split = samplerate * samples_split_seconds; samples_split = samplerate * samples_split_seconds;


espeak_SetSynthCallback(SynthCallback); espeak_SetSynthCallback(SynthCallback);
if(samples_split)
{
if (samples_split) {
char *extn; char *extn;
extn = strrchr(wavefile,'.');
if((extn != NULL) && ((wavefile + strlen(wavefile) - extn) <= 4))
{
strcpy(filetype,extn);
extn = strrchr(wavefile, '.');
if ((extn != NULL) && ((wavefile + strlen(wavefile) - extn) <= 4)) {
strcpy(filetype, extn);
*extn = 0; *extn = 0;
} }
} }
}
else
{
} else {
// play the sound output // play the sound output
samplerate = espeak_Initialize(AUDIO_OUTPUT_PLAYBACK,0,data_path,0);
samplerate = espeak_Initialize(AUDIO_OUTPUT_PLAYBACK, 0, data_path, 0);
} }




if(voicename[0] == 0)
strcpy(voicename,"default");
if (voicename[0] == 0)
strcpy(voicename, "default");


if(espeak_SetVoiceByName(voicename) != EE_OK)
{
memset(&voice_select,0,sizeof(voice_select));
if (espeak_SetVoiceByName(voicename) != EE_OK) {
memset(&voice_select, 0, sizeof(voice_select));
voice_select.languages = voicename; voice_select.languages = voicename;
if(espeak_SetVoiceByProperties(&voice_select) != EE_OK)
{
fprintf(stderr,"%svoice '%s'\n",err_load,voicename);
if (espeak_SetVoiceByProperties(&voice_select) != EE_OK) {
fprintf(stderr, "%svoice '%s'\n", err_load, voicename);
exit(2); exit(2);
} }
} }


if(flag_compile)
{
if (flag_compile) {
// This must be done after the voice is set // This must be done after the voice is set
espeak_CompileDictionary("", stderr, flag_compile & 0x1); espeak_CompileDictionary("", stderr, flag_compile & 0x1);
exit(0); exit(0);
} }


// set any non-default values of parameters. This must be done after espeak_Initialize() // set any non-default values of parameters. This must be done after espeak_Initialize()
if(speed > 0)
espeak_SetParameter(espeakRATE,speed,0);
if(volume >= 0)
espeak_SetParameter(espeakVOLUME,volume,0);
if(pitch >= 0)
espeak_SetParameter(espeakPITCH,pitch,0);
if(option_capitals >= 0)
espeak_SetParameter(espeakCAPITALS,option_capitals,0);
if(option_punctuation >= 0)
espeak_SetParameter(espeakPUNCTUATION,option_punctuation,0);
if(wordgap >= 0)
espeak_SetParameter(espeakWORDGAP,wordgap,0);
if(option_linelength > 0)
espeak_SetParameter(espeakLINELENGTH,option_linelength,0);
if(option_punctuation == 2)
if (speed > 0)
espeak_SetParameter(espeakRATE, speed, 0);
if (volume >= 0)
espeak_SetParameter(espeakVOLUME, volume, 0);
if (pitch >= 0)
espeak_SetParameter(espeakPITCH, pitch, 0);
if (option_capitals >= 0)
espeak_SetParameter(espeakCAPITALS, option_capitals, 0);
if (option_punctuation >= 0)
espeak_SetParameter(espeakPUNCTUATION, option_punctuation, 0);
if (wordgap >= 0)
espeak_SetParameter(espeakWORDGAP, wordgap, 0);
if (option_linelength > 0)
espeak_SetParameter(espeakLINELENGTH, option_linelength, 0);
if (option_punctuation == 2)
espeak_SetPunctuationList(option_punctlist); espeak_SetPunctuationList(option_punctlist);




espeak_SetPhonemeTrace(phoneme_options | (phonemes_separator << 8), f_phonemes_out); espeak_SetPhonemeTrace(phoneme_options | (phonemes_separator << 8), f_phonemes_out);


if(filename[0]==0)
{
if((optind < argc) && (flag_stdin == 0))
{
if (filename[0] == 0) {
if ((optind < argc) && (flag_stdin == 0)) {
// there's a non-option parameter, and no -f or --stdin // there's a non-option parameter, and no -f or --stdin
// use it as text // use it as text
p_text = argv[optind]; p_text = argv[optind];
}
else
{
} else {
f_text = stdin; f_text = stdin;
if(flag_stdin == 0)
{
if (flag_stdin == 0) {
flag_stdin = 2; flag_stdin = 2;
} }
} }
}
else
{
} else {
filesize = GetFileLength(filename); filesize = GetFileLength(filename);
f_text = fopen(filename,"r");
f_text = fopen(filename, "r");
} }


if((f_text == NULL) && (p_text == NULL))
{
fprintf(stderr,"%sfile '%s'\n",err_load,filename);
if ((f_text == NULL) && (p_text == NULL)) {
fprintf(stderr, "%sfile '%s'\n", err_load, filename);
exit(1); exit(1);
} }




if(p_text != NULL)
{
if (p_text != NULL) {
int size; int size;
size = strlen(p_text); size = strlen(p_text);
espeak_Synth(p_text,size+1,0,POS_CHARACTER,0,synth_flags,NULL,NULL);
}
else
if(flag_stdin)
{
espeak_Synth(p_text, size+1, 0, POS_CHARACTER, 0, synth_flags, NULL, NULL);
} else if (flag_stdin) {
int max = 1000; int max = 1000;
p_text = (char *)malloc(max); p_text = (char *)malloc(max);


if(flag_stdin == 2)
{
if (flag_stdin == 2) {
// line by line input on stdin // line by line input on stdin
while(fgets(p_text,max,stdin) != NULL)
{
while (fgets(p_text, max, stdin) != NULL) {
p_text[max-1] = 0; p_text[max-1] = 0;
espeak_Synth(p_text,max,0,POS_CHARACTER,0,synth_flags,NULL,NULL);
espeak_Synth(p_text, max, 0, POS_CHARACTER, 0, synth_flags, NULL, NULL);


} }
}
else
{
} else {
// bulk input on stdin // bulk input on stdin
ix = 0; ix = 0;
while(!feof(stdin))
{
while (!feof(stdin)) {
p_text[ix++] = fgetc(stdin); p_text[ix++] = fgetc(stdin);
if(ix >= (max-1))
{
if (ix >= (max-1)) {
max += 1000; max += 1000;
p_text = (char *)realloc(p_text,max);
p_text = (char *)realloc(p_text, max);
} }
} }
if(ix > 0)
{
if (ix > 0) {
p_text[ix-1] = 0; p_text[ix-1] = 0;
espeak_Synth(p_text,ix+1,0,POS_CHARACTER,0,synth_flags,NULL,NULL);
espeak_Synth(p_text, ix+1, 0, POS_CHARACTER, 0, synth_flags, NULL, NULL);
} }
} }
}
else
if(f_text != NULL)
{
if((p_text = (char *)malloc(filesize+1)) == NULL)
{
fprintf(stderr,"Failed to allocate memory %d bytes",filesize);
} else if (f_text != NULL) {
if ((p_text = (char *)malloc(filesize+1)) == NULL) {
fprintf(stderr, "Failed to allocate memory %d bytes", filesize);
exit(3); exit(3);
} }


fread(p_text,1,filesize,f_text);
p_text[filesize]=0;
espeak_Synth(p_text,filesize+1,0,POS_CHARACTER,0,synth_flags,NULL,NULL);
fread(p_text, 1, filesize, f_text);
p_text[filesize] = 0;
espeak_Synth(p_text, filesize+1, 0, POS_CHARACTER, 0, synth_flags, NULL, NULL);
fclose(f_text); fclose(f_text);
} }


if(espeak_Synchronize() != EE_OK)
{
if (espeak_Synchronize() != EE_OK) {
fprintf(stderr, "espeak_Synchronize() failed, maybe error when opening output device\n"); fprintf(stderr, "espeak_Synchronize() failed, maybe error when opening output device\n");
exit(4); exit(4);
} }


if(f_phonemes_out != stdout)
if (f_phonemes_out != stdout)
fclose(f_phonemes_out); // needed for WinCE fclose(f_phonemes_out); // needed for WinCE
return(0);
return 0;
} }

+ 959
- 1269
src/libespeak-ng/compiledata.c
File diff suppressed because it is too large
View File


+ 515
- 717
src/libespeak-ng/compiledict.c
File diff suppressed because it is too large
View File


+ 20
- 28
src/libespeak-ng/compilembrola.c View File

unsigned char c; unsigned char c;
unsigned int word; unsigned int word;


if(string==NULL)
return(0);
if (string == NULL)
return 0;


word = 0; word = 0;
for(ix=0; ix<4; ix++)
{
if(string[ix]==0) break;
for (ix = 0; ix < 4; ix++) {
if (string[ix] == 0) break;
c = string[ix]; c = string[ix];
word |= (c << (ix*8)); word |= (c << (ix*8));
} }
return(word);
return word;
} }


#pragma GCC visibility push(default) #pragma GCC visibility push(default)
int mbrola_ctrl = 20; // volume in 1/16 ths int mbrola_ctrl = 20; // volume in 1/16 ths
MBROLA_TAB data[N_PHONEME_TAB]; MBROLA_TAB data[N_PHONEME_TAB];


strcpy(buf,filepath);
if((f_in = fopen(buf,"r")) == NULL)
{
strcpy(buf, filepath);
if ((f_in = fopen(buf, "r")) == NULL) {
fprintf(log, "Can't read: %s\n", filepath); fprintf(log, "Can't read: %s\n", filepath);
return ENE_READ_ERROR; return ENE_READ_ERROR;
} }


while(fgets(buf,sizeof(phoneme),f_in) != NULL)
{
while (fgets(buf, sizeof(phoneme), f_in) != NULL) {
buf[sizeof(phoneme)-1] = 0; buf[sizeof(phoneme)-1] = 0;


if((p = strstr(buf,"//")) != NULL)
if ((p = strstr(buf, "//")) != NULL)
*p = 0; // truncate line at comment *p = 0; // truncate line at comment


if(memcmp(buf,"volume",6)==0)
{
if (memcmp(buf, "volume", 6) == 0) {
mbrola_ctrl = atoi(&buf[6]); mbrola_ctrl = atoi(&buf[6]);
continue; continue;
} }


n = sscanf(buf,"%d %s %s %d %s %s",&control,phoneme,phoneme2,&percent,name1,name2);
if(n >= 5)
{
n = sscanf(buf, "%d %s %s %d %s %s", &control, phoneme, phoneme2, &percent, name1, name2);
if (n >= 5) {
data[count].name = StringToWord(phoneme); data[count].name = StringToWord(phoneme);
if(strcmp(phoneme2,"NULL")==0)
if (strcmp(phoneme2, "NULL") == 0)
data[count].next_phoneme = 0; data[count].next_phoneme = 0;
else
if(strcmp(phoneme2,"VWL")==0)
else if (strcmp(phoneme2, "VWL") == 0)
data[count].next_phoneme = 2; data[count].next_phoneme = 2;
else else
data[count].next_phoneme = StringToWord(phoneme2); data[count].next_phoneme = StringToWord(phoneme2);
data[count].mbr_name2 = 0; data[count].mbr_name2 = 0;
data[count].percent = percent; data[count].percent = percent;
data[count].control = control; data[count].control = control;
if(strcmp(name1,"NULL")!=0)
if (strcmp(name1, "NULL") != 0)
data[count].mbr_name = StringToWord(name1); data[count].mbr_name = StringToWord(name1);
if(n == 6)
if (n == 6)
data[count].mbr_name2 = StringToWord(name2); data[count].mbr_name2 = StringToWord(name2);


count++; count++;
} }
fclose(f_in); fclose(f_in);


strcpy(mbrola_voice,basename(filepath));
sprintf(buf,"%s/mbrola_ph/%s_phtrans",path_home,mbrola_voice);
if((f_out = fopen(buf,"wb")) == NULL)
{
strcpy(mbrola_voice, basename(filepath));
sprintf(buf, "%s/mbrola_ph/%s_phtrans", path_home, mbrola_voice);
if ((f_out = fopen(buf, "wb")) == NULL) {
fprintf(log, "Can't write to: %s\n", buf); fprintf(log, "Can't write to: %s\n", buf);
return ENE_WRITE_ERROR; return ENE_WRITE_ERROR;
} }
Write4Bytes(f_out, mbrola_ctrl); Write4Bytes(f_out, mbrola_ctrl);


pw_end = (int *)(&data[count+1]); pw_end = (int *)(&data[count+1]);
for(pw = (int *)data; pw < pw_end; pw++)
{
for (pw = (int *)data; pw < pw_end; pw++) {
Write4Bytes(f_out, *pw); Write4Bytes(f_out, *pw);
} }
fclose(f_out); fclose(f_out);

+ 13
- 19
src/libespeak-ng/debug.c View File

#include <sys/time.h> #include <sys/time.h>
#include <unistd.h> #include <unistd.h>


static FILE* fd_log=NULL;
static const char* FILENAME="/tmp/espeak.log";
static FILE *fd_log = NULL;
static const char *FILENAME = "/tmp/espeak.log";


void debug_init() void debug_init()
{ {
if((fd_log = fopen(FILENAME,"a")) != NULL)
if ((fd_log = fopen(FILENAME, "a")) != NULL)
setvbuf(fd_log, NULL, _IONBF, 0); setvbuf(fd_log, NULL, _IONBF, 0);
} }


void debug_enter(const char* text)
void debug_enter(const char *text)
{ {
struct timeval tv; struct timeval tv;


gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);


if (!fd_log)
{
if (!fd_log) {
debug_init(); debug_init();
} }


if (fd_log)
{
fprintf(fd_log, "%03d.%03dms > ENTER %s\n",(int)(tv.tv_sec%1000), (int)(tv.tv_usec/1000), text);
if (fd_log) {
fprintf(fd_log, "%03d.%03dms > ENTER %s\n", (int)(tv.tv_sec%1000), (int)(tv.tv_usec/1000), text);
} }
} }


{ {
va_list args; va_list args;
va_start(args, format); va_start(args, format);
if (!fd_log)
{
if (!fd_log) {
debug_init(); debug_init();
} }
if (fd_log)
{
if (fd_log) {
vfprintf(fd_log, format, args); vfprintf(fd_log, format, args);
} }
va_end(args); va_end(args);
} }


void debug_time(const char* text)
void debug_time(const char *text)
{ {
struct timeval tv; struct timeval tv;


gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);


if (!fd_log)
{
if (!fd_log) {
debug_init(); debug_init();
} }
if (fd_log)
{
fprintf(fd_log, "%03d.%03dms > %s\n",(int)(tv.tv_sec%1000), (int)(tv.tv_usec/1000), text);
if (fd_log) {
fprintf(fd_log, "%03d.%03dms > %s\n", (int)(tv.tv_sec%1000), (int)(tv.tv_usec/1000), text);
} }
} }



+ 5
- 5
src/libespeak-ng/debug.h View File



#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
#define ENTER(text) debug_enter(text) #define ENTER(text) debug_enter(text)
#define SHOW(format,...) debug_show(format,__VA_ARGS__);
#define SHOW(format, ...) debug_show(format, __VA_ARGS__);
#define SHOW_TIME(text) debug_time(text); #define SHOW_TIME(text) debug_time(text);
extern void debug_enter(const char* text);
extern void debug_show(const char* format,...);
extern void debug_time(const char* text);
extern void debug_enter(const char *text);
extern void debug_show(const char *format, ...);
extern void debug_time(const char *text);


#else #else


#ifdef NO_VARIADIC_MACROS #ifdef NO_VARIADIC_MACROS
#define SHOW(format) // VC6 doesn't allow "..." #define SHOW(format) // VC6 doesn't allow "..."
#else #else
#define SHOW(format,...)
#define SHOW(format, ...)
#endif #endif
#define SHOW_TIME(text) #define SHOW_TIME(text)
#define ENTER(text) #define ENTER(text)

+ 804
- 1296
src/libespeak-ng/dictionary.c
File diff suppressed because it is too large
View File


+ 155
- 203
src/libespeak-ng/espeak_command.c View File



#include "debug.h" #include "debug.h"


static unsigned int my_current_text_id=0;
static unsigned int my_current_text_id = 0;


t_espeak_command* create_espeak_text(const void *text, size_t size, unsigned int position, espeak_POSITION_TYPE position_type, unsigned int end_position, unsigned int flags, void* user_data)
t_espeak_command *create_espeak_text(const void *text, size_t size, unsigned int position, espeak_POSITION_TYPE position_type, unsigned int end_position, unsigned int flags, void *user_data)
{ {
ENTER("create_espeak_text"); ENTER("create_espeak_text");
int a_error=1;
void* a_text = NULL;
t_espeak_text* data = NULL;
t_espeak_command* a_command = (t_espeak_command*)malloc(sizeof(t_espeak_command));
int a_error = 1;
void *a_text = NULL;
t_espeak_text *data = NULL;
t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command));


if (!text || !size || !a_command)
{
if (!text || !size || !a_command) {
goto text_error; goto text_error;
} }


a_text = malloc( size+1 );
if (!a_text)
{
a_text = malloc(size+1);
if (!a_text) {
goto text_error; goto text_error;
} }
memcpy(a_text, text, size); memcpy(a_text, text, size);
data->end_position = end_position; data->end_position = end_position;
data->flags = flags; data->flags = flags;
data->user_data = user_data; data->user_data = user_data;
a_error=0;
a_error = 0;


SHOW("ET_TEXT malloc text=%x, command=%x (uid=%d)\n", a_text, a_command, data->unique_identifier); SHOW("ET_TEXT malloc text=%x, command=%x (uid=%d)\n", a_text, a_command, data->unique_identifier);


text_error: text_error:
if (a_error)
{
if (a_text)
{
free (a_text);
if (a_error) {
if (a_text) {
free(a_text);
} }
if (a_command)
{
free (a_command);
if (a_command) {
free(a_command);
} }
a_command = NULL; a_command = NULL;
} }
return a_command; return a_command;
} }


t_espeak_command* create_espeak_terminated_msg(unsigned int unique_identifier, void* user_data)
t_espeak_command *create_espeak_terminated_msg(unsigned int unique_identifier, void *user_data)
{ {
ENTER("create_espeak_terminated_msg"); ENTER("create_espeak_terminated_msg");
int a_error=1;
t_espeak_terminated_msg* data = NULL;
t_espeak_command* a_command = (t_espeak_command*)malloc(sizeof(t_espeak_command));
int a_error = 1;
t_espeak_terminated_msg *data = NULL;
t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command));


if (!a_command)
{
if (!a_command) {
goto msg_error; goto msg_error;
} }


data = &(a_command->u.my_terminated_msg); data = &(a_command->u.my_terminated_msg);
data->unique_identifier = unique_identifier; data->unique_identifier = unique_identifier;
data->user_data = user_data; data->user_data = user_data;
a_error=0;
a_error = 0;


SHOW("ET_TERMINATED_MSG command=%x (uid=%d, user_data=0x%x)\n", a_command, unique_identifier, (int)user_data); SHOW("ET_TERMINATED_MSG command=%x (uid=%d, user_data=0x%x)\n", a_command, unique_identifier, (int)user_data);


msg_error: msg_error:
if (a_error)
{
if (a_command)
{
free (a_command);
if (a_error) {
if (a_command) {
free(a_command);
} }
a_command = NULL; a_command = NULL;
} }


} }


t_espeak_command* create_espeak_mark(const void *text, size_t size, const char *index_mark, unsigned int end_position, unsigned int flags, void* user_data)
t_espeak_command *create_espeak_mark(const void *text, size_t size, const char *index_mark, unsigned int end_position, unsigned int flags, void *user_data)
{ {
ENTER("create_espeak_mark"); ENTER("create_espeak_mark");
int a_error=1;
void* a_text = NULL;
int a_error = 1;
void *a_text = NULL;
char *a_index_mark = NULL; char *a_index_mark = NULL;
t_espeak_mark* data = NULL;
t_espeak_command* a_command = (t_espeak_command*)malloc(sizeof(t_espeak_command));
t_espeak_mark *data = NULL;
t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command));


if (!text || !size || !index_mark || !a_command)
{
if (!text || !size || !index_mark || !a_command) {
goto mark_error; goto mark_error;
} }


a_text = malloc( size );
if (!a_text)
{
a_text = malloc(size);
if (!a_text) {
goto mark_error; goto mark_error;
} }
memcpy(a_text, text, size); memcpy(a_text, text, size);


a_index_mark = strdup( index_mark);
a_index_mark = strdup(index_mark);


a_command->type = ET_MARK; a_command->type = ET_MARK;
a_command->state = CS_UNDEFINED; a_command->state = CS_UNDEFINED;
data->end_position = end_position; data->end_position = end_position;
data->flags = flags; data->flags = flags;
data->user_data = user_data; data->user_data = user_data;
a_error=0;
a_error = 0;


mark_error: mark_error:
if (a_error)
{
if (a_text)
{
free (a_text);
if (a_error) {
if (a_text) {
free(a_text);
} }
if (a_command)
{
free (a_command);
if (a_command) {
free(a_command);
} }
a_command = NULL; a_command = NULL;
if (a_index_mark)
{
free (a_index_mark);
if (a_index_mark) {
free(a_index_mark);
} }
} }


return a_command; return a_command;
} }


t_espeak_command* create_espeak_key(const char *key_name, void *user_data)
t_espeak_command *create_espeak_key(const char *key_name, void *user_data)
{ {
ENTER("create_espeak_key"); ENTER("create_espeak_key");
int a_error=1;
t_espeak_command* a_command = (t_espeak_command*)malloc(sizeof(t_espeak_command));
int a_error = 1;
t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command));


if (!key_name || !a_command)
{
if (!key_name || !a_command) {
goto key_error; goto key_error;
} }


a_command->state = CS_UNDEFINED; a_command->state = CS_UNDEFINED;
a_command->u.my_key.user_data = user_data; a_command->u.my_key.user_data = user_data;
a_command->u.my_key.unique_identifier = ++my_current_text_id; a_command->u.my_key.unique_identifier = ++my_current_text_id;
a_command->u.my_key.key_name = strdup( key_name);
a_error=0;
a_command->u.my_key.key_name = strdup(key_name);
a_error = 0;


key_error: key_error:
if (a_error)
{
if (a_command)
{
free (a_command);
if (a_error) {
if (a_command) {
free(a_command);
} }
a_command = NULL; a_command = NULL;
} }
return a_command; return a_command;
} }


t_espeak_command* create_espeak_char(wchar_t character, void* user_data)
t_espeak_command *create_espeak_char(wchar_t character, void *user_data)
{ {
ENTER("create_espeak_char"); ENTER("create_espeak_char");
int a_error=1;
t_espeak_command* a_command = (t_espeak_command*)malloc(sizeof(t_espeak_command));
if (!a_command)
{
int a_error = 1;
t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command));
if (!a_command) {
goto char_error; goto char_error;
} }


a_command->u.my_char.user_data = user_data; a_command->u.my_char.user_data = user_data;
a_command->u.my_char.unique_identifier = ++my_current_text_id; a_command->u.my_char.unique_identifier = ++my_current_text_id;
a_command->u.my_char.character = character; a_command->u.my_char.character = character;
a_error=0;
a_error = 0;


char_error: char_error:
if (a_error)
{
if (a_command)
{
free (a_command);
if (a_error) {
if (a_command) {
free(a_command);
} }
a_command = NULL; a_command = NULL;
} }
return a_command; return a_command;
} }


t_espeak_command* create_espeak_parameter(espeak_PARAMETER parameter, int value, int relative)
t_espeak_command *create_espeak_parameter(espeak_PARAMETER parameter, int value, int relative)
{ {
ENTER("create_espeak_parameter"); ENTER("create_espeak_parameter");
int a_error=1;
t_espeak_parameter* data = NULL;
t_espeak_command* a_command = (t_espeak_command*)malloc(sizeof(t_espeak_command));
if (!a_command)
{
int a_error = 1;
t_espeak_parameter *data = NULL;
t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command));
if (!a_command) {
goto param_error; goto param_error;
} }


data->parameter = parameter; data->parameter = parameter;
data->value = value; data->value = value;
data->relative = relative; data->relative = relative;
a_error=0;
a_error = 0;


param_error: param_error:
if (a_error)
{
if (a_command)
{
free (a_command);
if (a_error) {
if (a_command) {
free(a_command);
} }
a_command = NULL; a_command = NULL;
} }
return a_command; return a_command;
} }


t_espeak_command* create_espeak_punctuation_list(const wchar_t *punctlist)
t_espeak_command *create_espeak_punctuation_list(const wchar_t *punctlist)
{ {
ENTER("create_espeak_punctuation_list"); ENTER("create_espeak_punctuation_list");
int a_error=1;
t_espeak_command* a_command = (t_espeak_command*)malloc(sizeof(t_espeak_command));
int a_error = 1;
t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command));


if (!punctlist || !a_command)
{
if (!punctlist || !a_command) {
goto list_error; goto list_error;
} }




{ {
size_t len = (wcslen(punctlist) + 1)*sizeof(wchar_t); size_t len = (wcslen(punctlist) + 1)*sizeof(wchar_t);
wchar_t* a_list = (wchar_t*)malloc(len);
wchar_t *a_list = (wchar_t *)malloc(len);
memcpy(a_list, punctlist, len); memcpy(a_list, punctlist, len);
a_command->u.my_punctuation_list = a_list; a_command->u.my_punctuation_list = a_list;
} }


a_error=0;
a_error = 0;


list_error: list_error:
if (a_error)
{
if (a_command)
{
free (a_command);
if (a_error) {
if (a_command) {
free(a_command);
} }
a_command = NULL; a_command = NULL;
} }
return a_command; return a_command;
} }


t_espeak_command* create_espeak_voice_name(const char *name)
t_espeak_command *create_espeak_voice_name(const char *name)
{ {
ENTER("create_espeak_voice_name"); ENTER("create_espeak_voice_name");


int a_error=1;
t_espeak_command* a_command = (t_espeak_command*)malloc(sizeof(t_espeak_command));
int a_error = 1;
t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command));


if (!name || !a_command)
{
if (!name || !a_command) {
goto name_error; goto name_error;
} }


a_command->type = ET_VOICE_NAME; a_command->type = ET_VOICE_NAME;
a_command->state = CS_UNDEFINED; a_command->state = CS_UNDEFINED;
a_command->u.my_voice_name = strdup( name);
a_error=0;
a_command->u.my_voice_name = strdup(name);
a_error = 0;


name_error: name_error:
if (a_error)
{
if (a_command)
{
free (a_command);
if (a_error) {
if (a_command) {
free(a_command);
} }
a_command = NULL; a_command = NULL;
} }
return a_command; return a_command;
} }


t_espeak_command* create_espeak_voice_spec(espeak_VOICE *voice)
t_espeak_command *create_espeak_voice_spec(espeak_VOICE *voice)
{ {
ENTER("create_espeak_voice_spec"); ENTER("create_espeak_voice_spec");
int a_error=1;
t_espeak_command* a_command = (t_espeak_command*)malloc(sizeof(t_espeak_command));
int a_error = 1;
t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command));


if (!voice || !a_command)
{
if (!voice || !a_command) {
goto spec_error; goto spec_error;
} }


a_command->type = ET_VOICE_SPEC; a_command->type = ET_VOICE_SPEC;
a_command->state = CS_UNDEFINED; a_command->state = CS_UNDEFINED;
{ {
espeak_VOICE* data = &(a_command->u.my_voice_spec);
espeak_VOICE *data = &(a_command->u.my_voice_spec);
memcpy(data, voice, sizeof(espeak_VOICE)); memcpy(data, voice, sizeof(espeak_VOICE));


if (voice->name)
{
if (voice->name) {
data->name = strdup(voice->name); data->name = strdup(voice->name);
} }


if (voice->languages)
{
if (voice->languages) {
data->languages = strdup(voice->languages); data->languages = strdup(voice->languages);
} }


if (voice->identifier)
{
if (voice->identifier) {
data->identifier = strdup(voice->identifier); data->identifier = strdup(voice->identifier);
} }


a_error=0;
a_error = 0;
} }


spec_error: spec_error:
if (a_error)
{
if (a_command)
{
free (a_command);
if (a_error) {
if (a_command) {
free(a_command);
} }
a_command = NULL; a_command = NULL;
} }
return a_command; return a_command;
} }


int delete_espeak_command( t_espeak_command* the_command)
int delete_espeak_command(t_espeak_command *the_command)
{ {
ENTER("delete_espeak_command"); ENTER("delete_espeak_command");
int a_status = 0; int a_status = 0;
if (the_command)
{
switch(the_command->type)
if (the_command) {
switch (the_command->type)
{ {
case ET_TEXT: case ET_TEXT:
if (the_command->u.my_text.text)
{
if (the_command->u.my_text.text) {
SHOW("delete_espeak_command > ET_TEXT free text=%x, command=%x, uid=%d\n", the_command->u.my_text.text, the_command, the_command->u.my_text.unique_identifier); SHOW("delete_espeak_command > ET_TEXT free text=%x, command=%x, uid=%d\n", the_command->u.my_text.text, the_command, the_command->u.my_text.unique_identifier);
free(the_command->u.my_text.text); free(the_command->u.my_text.text);
} }
break; break;


case ET_MARK: case ET_MARK:
if (the_command->u.my_mark.text)
{
if (the_command->u.my_mark.text) {
free(the_command->u.my_mark.text); free(the_command->u.my_mark.text);
} }
if (the_command->u.my_mark.index_mark)
{
free((void*)(the_command->u.my_mark.index_mark));
if (the_command->u.my_mark.index_mark) {
free((void *)(the_command->u.my_mark.index_mark));
} }
break; break;


// it must be processed here for informing the calling program // it must be processed here for informing the calling program
// that its message is finished. // that its message is finished.
// This can be important for cleaning the related user data. // This can be important for cleaning the related user data.
t_espeak_terminated_msg* data = &(the_command->u.my_terminated_msg);
if (the_command->state == CS_PENDING)
{
t_espeak_terminated_msg *data = &(the_command->u.my_terminated_msg);
if (the_command->state == CS_PENDING) {
the_command->state = CS_PROCESSED; the_command->state = CS_PROCESSED;
SHOW("delete_espeak_command > ET_TERMINATED_MSG callback (command=0x%x, uid=%d) \n", the_command, data->unique_identifier); SHOW("delete_espeak_command > ET_TERMINATED_MSG callback (command=0x%x, uid=%d) \n", the_command, data->unique_identifier);
sync_espeak_terminated_msg( data->unique_identifier, data->user_data);
sync_espeak_terminated_msg(data->unique_identifier, data->user_data);
} }
} }
break; break;


case ET_KEY: case ET_KEY:
if (the_command->u.my_key.key_name)
{
free((void*)(the_command->u.my_key.key_name));
if (the_command->u.my_key.key_name) {
free((void *)(the_command->u.my_key.key_name));
} }
break; break;


break; break;


case ET_PUNCTUATION_LIST: case ET_PUNCTUATION_LIST:
if (the_command->u.my_punctuation_list)
{
free((void*)(the_command->u.my_punctuation_list));
if (the_command->u.my_punctuation_list) {
free((void *)(the_command->u.my_punctuation_list));
} }
break; break;


case ET_VOICE_NAME: case ET_VOICE_NAME:
if (the_command->u.my_voice_name)
{
free((void*)(the_command->u.my_voice_name));
if (the_command->u.my_voice_name) {
free((void *)(the_command->u.my_voice_name));
} }
break; break;


case ET_VOICE_SPEC: case ET_VOICE_SPEC:
{ {
espeak_VOICE* data = &(the_command->u.my_voice_spec);
espeak_VOICE *data = &(the_command->u.my_voice_spec);


if (data->name)
{
if (data->name) {
free((void *)data->name); free((void *)data->name);
} }


if (data->languages)
{
if (data->languages) {
free((void *)data->languages); free((void *)data->languages);
} }


if (data->identifier)
{
if (data->identifier) {
free((void *)data->identifier); free((void *)data->identifier);
} }
} }
return a_status; return a_status;
} }


void process_espeak_command( t_espeak_command* the_command)
void process_espeak_command(t_espeak_command *the_command)
{ {
ENTER("process_espeak_command"); ENTER("process_espeak_command");


SHOW("command=0x%x\n", the_command); SHOW("command=0x%x\n", the_command);


if (the_command == NULL)
{
if (the_command == NULL) {
return; return;
} }


the_command->state = CS_PROCESSED; the_command->state = CS_PROCESSED;


switch(the_command->type)
switch (the_command->type)
{ {
case ET_TEXT: case ET_TEXT:
{ {
t_espeak_text* data = &(the_command->u.my_text);
sync_espeak_Synth( data->unique_identifier, data->text, data->size,
data->position, data->position_type,
data->end_position, data->flags, data->user_data);
t_espeak_text *data = &(the_command->u.my_text);
sync_espeak_Synth(data->unique_identifier, data->text, data->size,
data->position, data->position_type,
data->end_position, data->flags, data->user_data);
} }
break; break;


case ET_MARK: case ET_MARK:
{ {
t_espeak_mark* data = &(the_command->u.my_mark);
sync_espeak_Synth_Mark( data->unique_identifier, data->text, data->size,
data->index_mark, data->end_position, data->flags,
data->user_data);
t_espeak_mark *data = &(the_command->u.my_mark);
sync_espeak_Synth_Mark(data->unique_identifier, data->text, data->size,
data->index_mark, data->end_position, data->flags,
data->user_data);
} }
break; break;


case ET_TERMINATED_MSG: case ET_TERMINATED_MSG:
{ {
t_espeak_terminated_msg* data = &(the_command->u.my_terminated_msg);
sync_espeak_terminated_msg( data->unique_identifier, data->user_data);
t_espeak_terminated_msg *data = &(the_command->u.my_terminated_msg);
sync_espeak_terminated_msg(data->unique_identifier, data->user_data);
} }
break; break;


case ET_KEY: case ET_KEY:
{ {
const char* data = the_command->u.my_key.key_name;
const char *data = the_command->u.my_key.key_name;
sync_espeak_Key(data); sync_espeak_Key(data);
} }
break; break;
case ET_CHAR: case ET_CHAR:
{ {
const wchar_t data = the_command->u.my_char.character; const wchar_t data = the_command->u.my_char.character;
sync_espeak_Char( data);
sync_espeak_Char(data);
} }
break; break;


case ET_PARAMETER: case ET_PARAMETER:
{ {
t_espeak_parameter* data = &(the_command->u.my_param);
SetParameter( data->parameter, data->value, data->relative);
t_espeak_parameter *data = &(the_command->u.my_param);
SetParameter(data->parameter, data->value, data->relative);
} }
break; break;


case ET_PUNCTUATION_LIST: case ET_PUNCTUATION_LIST:
{ {
const wchar_t* data = the_command->u.my_punctuation_list;
sync_espeak_SetPunctuationList( data);
const wchar_t *data = the_command->u.my_punctuation_list;
sync_espeak_SetPunctuationList(data);
} }
break; break;


case ET_VOICE_NAME: case ET_VOICE_NAME:
{ {
const char* data = the_command->u.my_voice_name;
SetVoiceByName( data);
const char *data = the_command->u.my_voice_name;
SetVoiceByName(data);
} }
break; break;


case ET_VOICE_SPEC: case ET_VOICE_SPEC:
{ {
espeak_VOICE* data = &(the_command->u.my_voice_spec);
espeak_VOICE *data = &(the_command->u.my_voice_spec);
SetVoiceByProperties(data); SetVoiceByProperties(data);
} }
break; break;
} }
} }


void display_espeak_command( t_espeak_command* the_command)
void display_espeak_command(t_espeak_command *the_command)
{ {
ENTER("display_espeak_command"); ENTER("display_espeak_command");
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
if (the_command == NULL)
{
SHOW("display_espeak_command > command=%s\n","NULL");
if (the_command == NULL) {
SHOW("display_espeak_command > command=%s\n", "NULL");
return; return;
} }


SHOW("display_espeak_command > state=%d\n",the_command->state);
SHOW("display_espeak_command > state=%d\n", the_command->state);


switch(the_command->type)
switch (the_command->type)
{ {
case ET_TEXT: case ET_TEXT:
{ {
t_espeak_text* data = &(the_command->u.my_text);
SHOW("display_espeak_command > (0x%x) uid=%d, TEXT=%s, user_data=0x%x\n", the_command, data->unique_identifier, (char*)data->text, (int)(data->user_data));
t_espeak_text *data = &(the_command->u.my_text);
SHOW("display_espeak_command > (0x%x) uid=%d, TEXT=%s, user_data=0x%x\n", the_command, data->unique_identifier, (char *)data->text, (int)(data->user_data));
} }
break; break;


case ET_MARK: case ET_MARK:
{ {
t_espeak_mark* data = &(the_command->u.my_mark);
SHOW("display_espeak_command > (0x%x) uid=%d, MARK=%s, user_data=0x%x\n", the_command, data->unique_identifier, (char*)data->text, (int)(data->user_data));
t_espeak_mark *data = &(the_command->u.my_mark);
SHOW("display_espeak_command > (0x%x) uid=%d, MARK=%s, user_data=0x%x\n", the_command, data->unique_identifier, (char *)data->text, (int)(data->user_data));
} }
break; break;


case ET_KEY: case ET_KEY:
{ {
const char* data = the_command->u.my_key.key_name;
const char *data = the_command->u.my_key.key_name;
SHOW("display_espeak_command > (0x%x) KEY=%c\n", the_command, data); SHOW("display_espeak_command > (0x%x) KEY=%c\n", the_command, data);
} }
break; break;


case ET_TERMINATED_MSG: case ET_TERMINATED_MSG:
{ {
t_espeak_terminated_msg* data = &(the_command->u.my_terminated_msg);
t_espeak_terminated_msg *data = &(the_command->u.my_terminated_msg);


SHOW("display_espeak_command > (0x%x) TERMINATED_MSG uid=%d, user_data=0x%x, state=%d\n", SHOW("display_espeak_command > (0x%x) TERMINATED_MSG uid=%d, user_data=0x%x, state=%d\n",
the_command, data->unique_identifier, data->user_data, the_command, data->unique_identifier, data->user_data,


case ET_PARAMETER: case ET_PARAMETER:
{ {
t_espeak_parameter* data = &(the_command->u.my_param);
t_espeak_parameter *data = &(the_command->u.my_param);
SHOW("display_espeak_command > (0x%x) PARAMETER=%d, value=%d, relative=%d\n", SHOW("display_espeak_command > (0x%x) PARAMETER=%d, value=%d, relative=%d\n",
the_command, data->parameter, data->value, data->relative); the_command, data->parameter, data->value, data->relative);
} }


case ET_PUNCTUATION_LIST: case ET_PUNCTUATION_LIST:
{ {
const wchar_t* data = the_command->u.my_punctuation_list;
sync_espeak_SetPunctuationList( data);
SHOW("display_espeak_command > (0x%x) PUNCTLIST=%s\n", the_command, (char*)data);
const wchar_t *data = the_command->u.my_punctuation_list;
sync_espeak_SetPunctuationList(data);
SHOW("display_espeak_command > (0x%x) PUNCTLIST=%s\n", the_command, (char *)data);
} }
break; break;


case ET_VOICE_NAME: case ET_VOICE_NAME:
{ {
const char* data = the_command->u.my_voice_name;
const char *data = the_command->u.my_voice_name;
SHOW("display_espeak_command > (0x%x) VOICE_NAME=%s\n", the_command, data); SHOW("display_espeak_command > (0x%x) VOICE_NAME=%s\n", the_command, data);
} }
break; break;

+ 36
- 46
src/libespeak-ng/espeak_command.h View File

{ {
#endif #endif


typedef enum
{
typedef enum {
ET_TEXT, ET_TEXT,
ET_MARK, ET_MARK,
ET_KEY, ET_KEY,
ET_TERMINATED_MSG ET_TERMINATED_MSG
} t_espeak_type; } t_espeak_type;


typedef struct
{
typedef struct {
unsigned int unique_identifier; unsigned int unique_identifier;
void* text;
void *text;
size_t size; size_t size;
unsigned int position; unsigned int position;
espeak_POSITION_TYPE position_type; espeak_POSITION_TYPE position_type;
unsigned int end_position; unsigned int end_position;
unsigned int flags; unsigned int flags;
void* user_data;
void *user_data;
} t_espeak_text; } t_espeak_text;


typedef struct
{
typedef struct {
unsigned int unique_identifier; unsigned int unique_identifier;
void* text;
void *text;
size_t size; size_t size;
const char* index_mark;
const char *index_mark;
unsigned int end_position; unsigned int end_position;
unsigned int flags; unsigned int flags;
void* user_data;
void *user_data;
} t_espeak_mark; } t_espeak_mark;


typedef struct
{
typedef struct {
unsigned int unique_identifier; unsigned int unique_identifier;
void* user_data;
void *user_data;
wchar_t character; wchar_t character;
} t_espeak_character; } t_espeak_character;


typedef struct
{
typedef struct {
unsigned int unique_identifier; unsigned int unique_identifier;
void* user_data;
const char* key_name;
void *user_data;
const char *key_name;
} t_espeak_key; } t_espeak_key;




typedef struct
{
typedef struct {
unsigned int unique_identifier; unsigned int unique_identifier;
void* user_data;
void *user_data;
} t_espeak_terminated_msg; } t_espeak_terminated_msg;




typedef struct
{
typedef struct {
espeak_PARAMETER parameter; espeak_PARAMETER parameter;
int value; int value;
int relative; int relative;
} t_espeak_parameter; } t_espeak_parameter;


typedef enum
{
typedef enum {
CS_UNDEFINED, // The command has just been created CS_UNDEFINED, // The command has just been created
CS_PENDING, // stored in the fifo CS_PENDING, // stored in the fifo
CS_PROCESSED // processed CS_PROCESSED // processed
} t_command_state; } t_command_state;


typedef struct
{
typedef struct {
t_espeak_type type; t_espeak_type type;
t_command_state state; t_command_state state;


union command
{
union command {
t_espeak_text my_text; t_espeak_text my_text;
t_espeak_mark my_mark; t_espeak_mark my_mark;
t_espeak_key my_key; t_espeak_key my_key;
t_espeak_character my_char; t_espeak_character my_char;
t_espeak_parameter my_param; t_espeak_parameter my_param;
const wchar_t* my_punctuation_list;
const wchar_t *my_punctuation_list;
const char *my_voice_name; const char *my_voice_name;
espeak_VOICE my_voice_spec; espeak_VOICE my_voice_spec;
t_espeak_terminated_msg my_terminated_msg; t_espeak_terminated_msg my_terminated_msg;
} t_espeak_command; } t_espeak_command;




t_espeak_command* create_espeak_text(const void *text, size_t size, unsigned int position, espeak_POSITION_TYPE position_type, unsigned int end_position, unsigned int flags, void* user_data);
t_espeak_command *create_espeak_text(const void *text, size_t size, unsigned int position, espeak_POSITION_TYPE position_type, unsigned int end_position, unsigned int flags, void *user_data);


t_espeak_command* create_espeak_mark(const void *text, size_t size, const char *index_mark, unsigned int end_position, unsigned int flags, void* user_data);
t_espeak_command *create_espeak_mark(const void *text, size_t size, const char *index_mark, unsigned int end_position, unsigned int flags, void *user_data);


t_espeak_command* create_espeak_terminated_msg(unsigned int unique_identifier, void* user_data);
t_espeak_command *create_espeak_terminated_msg(unsigned int unique_identifier, void *user_data);


t_espeak_command* create_espeak_key(const char *key_name, void *user_data);
t_espeak_command *create_espeak_key(const char *key_name, void *user_data);


t_espeak_command* create_espeak_char(wchar_t character, void *user_data);
t_espeak_command *create_espeak_char(wchar_t character, void *user_data);


t_espeak_command* create_espeak_parameter(espeak_PARAMETER parameter, int value, int relative);
t_espeak_command *create_espeak_parameter(espeak_PARAMETER parameter, int value, int relative);


t_espeak_command* create_espeak_punctuation_list(const wchar_t *punctlist);
t_espeak_command *create_espeak_punctuation_list(const wchar_t *punctlist);


t_espeak_command* create_espeak_voice_name(const char *name);
t_espeak_command *create_espeak_voice_name(const char *name);


t_espeak_command* create_espeak_voice_spec(espeak_VOICE *voice_spec);
t_espeak_command *create_espeak_voice_spec(espeak_VOICE *voice_spec);


void process_espeak_command( t_espeak_command* the_command);
void process_espeak_command(t_espeak_command *the_command);


int delete_espeak_command( t_espeak_command* the_command);
int delete_espeak_command(t_espeak_command *the_command);


void display_espeak_command(t_espeak_command* the_command);
void display_espeak_command(t_espeak_command *the_command);




espeak_ERROR sync_espeak_Synth(unsigned int unique_identifier, const void *text, size_t size, espeak_ERROR sync_espeak_Synth(unsigned int unique_identifier, const void *text, size_t size,
unsigned int position, espeak_POSITION_TYPE position_type, unsigned int position, espeak_POSITION_TYPE position_type,
unsigned int end_position, unsigned int flags, void* user_data);
unsigned int end_position, unsigned int flags, void *user_data);
espeak_ERROR sync_espeak_Synth_Mark(unsigned int unique_identifier, const void *text, size_t size, espeak_ERROR sync_espeak_Synth_Mark(unsigned int unique_identifier, const void *text, size_t size,
const char *index_mark, unsigned int end_position, const char *index_mark, unsigned int end_position,
unsigned int flags, void* user_data);
unsigned int flags, void *user_data);
void sync_espeak_Key(const char *key); void sync_espeak_Key(const char *key);
void sync_espeak_Char(wchar_t character); void sync_espeak_Char(wchar_t character);
void sync_espeak_SetPunctuationList(const wchar_t *punctlist); void sync_espeak_SetPunctuationList(const wchar_t *punctlist);
espeak_ERROR SetVoiceByProperties(espeak_VOICE *voice_selector); espeak_ERROR SetVoiceByProperties(espeak_VOICE *voice_selector);
void SetParameter(int parameter, int value, int relative); void SetParameter(int parameter, int value, int relative);


int sync_espeak_terminated_msg(unsigned int unique_identifier, void* user_data);
int sync_espeak_terminated_msg(unsigned int unique_identifier, void *user_data);


#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif


//>
// >
#endif #endif

+ 139
- 197
src/libespeak-ng/event.c View File

static pthread_t my_thread; static pthread_t my_thread;
static bool thread_inited; static bool thread_inited;


static t_espeak_callback* my_callback = NULL;
static int my_event_is_running=0;
static t_espeak_callback *my_callback = NULL;
static int my_event_is_running = 0;


enum {MIN_TIMEOUT_IN_MS=10,
ACTIVITY_TIMEOUT=50, // in ms, check that the stream is active
MAX_ACTIVITY_CHECK=6};
enum { MIN_TIMEOUT_IN_MS = 10,
ACTIVITY_TIMEOUT = 50, // in ms, check that the stream is active
MAX_ACTIVITY_CHECK = 6 };




typedef struct t_node
{
void* data;
typedef struct t_node {
void *data;
struct t_node *next; struct t_node *next;
} node; } node;


static node* head=NULL;
static node* tail=NULL;
static int node_counter=0;
static espeak_ERROR push(void* data);
static void* pop();
static node *head = NULL;
static node *tail = NULL;
static int node_counter = 0;
static espeak_ERROR push(void *data);
static void *pop();
static void init(); static void init();
static void* polling_thread(void*);
static void *polling_thread(void *);


void event_set_callback(t_espeak_callback* SynthCallback)
void event_set_callback(t_espeak_callback *SynthCallback)
{ {
my_callback = SynthCallback; my_callback = SynthCallback;
} }
{ {
ENTER("event_init"); ENTER("event_init");


my_event_is_running=0;
my_event_is_running = 0;


// security // security
pthread_mutex_init( &my_mutex, (const pthread_mutexattr_t *)NULL);
pthread_mutex_init(&my_mutex, (const pthread_mutexattr_t *)NULL);
init(); init();


assert(-1 != sem_init(&my_sem_start_is_required, 0, 0)); assert(-1 != sem_init(&my_sem_start_is_required, 0, 0));


pthread_attr_t a_attrib; pthread_attr_t a_attrib;


if (pthread_attr_init (&a_attrib) == 0
&& pthread_attr_setdetachstate(&a_attrib, PTHREAD_CREATE_JOINABLE) == 0)
{
if (pthread_attr_init(&a_attrib) == 0
&& pthread_attr_setdetachstate(&a_attrib, PTHREAD_CREATE_JOINABLE) == 0) {
thread_inited = (0 == pthread_create(&my_thread, thread_inited = (0 == pthread_create(&my_thread,
&a_attrib, &a_attrib,
polling_thread, polling_thread,
(void*)NULL));
(void *)NULL));
} }
assert(thread_inited); assert(thread_inited);
pthread_attr_destroy(&a_attrib); pthread_attr_destroy(&a_attrib);
} }


static void event_display(espeak_EVENT* event)
static void event_display(espeak_EVENT *event)
{ {
ENTER("event_display"); ENTER("event_display");


#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
if (event==NULL)
{
SHOW("event_display > event=%s\n","NULL");
}
else
{
static const char* label[] = {
if (event == NULL) {
SHOW("event_display > event=%s\n", "NULL");
} else {
static const char *label[] = {
"LIST_TERMINATED", "LIST_TERMINATED",
"WORD", "WORD",
"SENTENCE", "SENTENCE",
"??" "??"
}; };


SHOW("event_display > event=0x%x\n",event);
SHOW("event_display > type=%s\n",label[event->type]);
SHOW("event_display > uid=%d\n",event->unique_identifier);
SHOW("event_display > text_position=%d\n",event->text_position);
SHOW("event_display > length=%d\n",event->length);
SHOW("event_display > audio_position=%d\n",event->audio_position);
SHOW("event_display > sample=%d\n",event->sample);
SHOW("event_display > user_data=0x%x\n",event->user_data);
SHOW("event_display > event=0x%x\n", event);
SHOW("event_display > type=%s\n", label[event->type]);
SHOW("event_display > uid=%d\n", event->unique_identifier);
SHOW("event_display > text_position=%d\n", event->text_position);
SHOW("event_display > length=%d\n", event->length);
SHOW("event_display > audio_position=%d\n", event->audio_position);
SHOW("event_display > sample=%d\n", event->sample);
SHOW("event_display > user_data=0x%x\n", event->user_data);
} }
#endif #endif
} }


static espeak_EVENT* event_copy (espeak_EVENT* event)
static espeak_EVENT *event_copy(espeak_EVENT *event)
{ {
ENTER("event_copy"); ENTER("event_copy");


if (event==NULL)
{
if (event == NULL) {
return NULL; return NULL;
} }


espeak_EVENT* a_event=(espeak_EVENT*)malloc(sizeof(espeak_EVENT));
if (a_event)
{
espeak_EVENT *a_event = (espeak_EVENT *)malloc(sizeof(espeak_EVENT));
if (a_event) {
memcpy(a_event, event, sizeof(espeak_EVENT)); memcpy(a_event, event, sizeof(espeak_EVENT));


switch(event->type)
switch (event->type)
{ {
case espeakEVENT_MARK: case espeakEVENT_MARK:
case espeakEVENT_PLAY: case espeakEVENT_PLAY:
if (event->id.name)
{
if (event->id.name) {
a_event->id.name = strdup(event->id.name); a_event->id.name = strdup(event->id.name);
} }
break; break;
// * Last call: event->type = espeakEVENT_MSG_TERMINATED // * Last call: event->type = espeakEVENT_MSG_TERMINATED
// //


static void event_notify(espeak_EVENT* event)
static void event_notify(espeak_EVENT *event)
{ {
ENTER("event_notify"); ENTER("event_notify");
static unsigned int a_old_uid = 0; static unsigned int a_old_uid = 0;


espeak_EVENT events[2]; espeak_EVENT events[2];
memcpy(&events[0],event,sizeof(espeak_EVENT)); // the event parameter in the callback function should be an array of eventd
memcpy(&events[1],event,sizeof(espeak_EVENT));
memcpy(&events[0], event, sizeof(espeak_EVENT)); // the event parameter in the callback function should be an array of eventd
memcpy(&events[1], event, sizeof(espeak_EVENT));
events[1].type = espeakEVENT_LIST_TERMINATED; // ... terminated by an event type=0 events[1].type = espeakEVENT_LIST_TERMINATED; // ... terminated by an event type=0


if (event && my_callback)
{
if (event && my_callback) {
event_display(event); event_display(event);


switch(event->type)
switch (event->type)
{ {
case espeakEVENT_SENTENCE: case espeakEVENT_SENTENCE:
my_callback(NULL, 0, events); my_callback(NULL, 0, events);
case espeakEVENT_END: case espeakEVENT_END:
case espeakEVENT_PHONEME: case espeakEVENT_PHONEME:
{ {
if (a_old_uid != event->unique_identifier)
{
if (a_old_uid != event->unique_identifier) {
espeak_EVENT_TYPE a_new_type = events[0].type; espeak_EVENT_TYPE a_new_type = events[0].type;
events[0].type = espeakEVENT_SENTENCE; events[0].type = espeakEVENT_SENTENCE;
my_callback(NULL, 0, events); my_callback(NULL, 0, events);
} }
} }


static int event_delete(espeak_EVENT* event)
static int event_delete(espeak_EVENT *event)
{ {
ENTER("event_delete"); ENTER("event_delete");


event_display(event); event_display(event);


if(event==NULL)
{
if (event == NULL) {
return 0; return 0;
} }


switch(event->type)
switch (event->type)
{ {
case espeakEVENT_MSG_TERMINATED: case espeakEVENT_MSG_TERMINATED:
event_notify(event); event_notify(event);


case espeakEVENT_MARK: case espeakEVENT_MARK:
case espeakEVENT_PLAY: case espeakEVENT_PLAY:
if(event->id.name)
{
free((void*)(event->id.name));
if (event->id.name) {
free((void *)(event->id.name));
} }
break; break;


return 1; return 1;
} }


espeak_ERROR event_declare (espeak_EVENT* event)
espeak_ERROR event_declare(espeak_EVENT *event)
{ {
ENTER("event_declare"); ENTER("event_declare");


event_display(event); event_display(event);


if (!event)
{
if (!event) {
return EE_INTERNAL_ERROR; return EE_INTERNAL_ERROR;
} }


int a_status = pthread_mutex_lock(&my_mutex); int a_status = pthread_mutex_lock(&my_mutex);
espeak_ERROR a_error = EE_OK; espeak_ERROR a_error = EE_OK;


if (!a_status)
{
if (!a_status) {
SHOW_TIME("event_declare > locked\n"); SHOW_TIME("event_declare > locked\n");
espeak_EVENT* a_event = event_copy(event);
espeak_EVENT *a_event = event_copy(event);
a_error = push(a_event); a_error = push(a_event);
if (a_error != EE_OK)
{
if (a_error != EE_OK) {
event_delete(a_event); event_delete(a_event);
} }
SHOW_TIME("event_declare > unlocking\n"); SHOW_TIME("event_declare > unlocking\n");
SHOW_TIME("event_declare > post my_sem_start_is_required\n"); SHOW_TIME("event_declare > post my_sem_start_is_required\n");
sem_post(&my_sem_start_is_required); sem_post(&my_sem_start_is_required);


if (a_status != 0)
{
if (a_status != 0) {
a_error = EE_INTERNAL_ERROR; a_error = EE_INTERNAL_ERROR;
} }


return a_error; return a_error;
} }


espeak_ERROR event_clear_all ()
espeak_ERROR event_clear_all()
{ {
ENTER("event_clear_all"); ENTER("event_clear_all");


int a_event_is_running = 0; int a_event_is_running = 0;


SHOW_TIME("event_stop > locked\n"); SHOW_TIME("event_stop > locked\n");
if (a_status != 0)
{
if (a_status != 0) {
return EE_INTERNAL_ERROR; return EE_INTERNAL_ERROR;
} }


if (my_event_is_running)
{
if (my_event_is_running) {
SHOW_TIME("event_stop > post my_sem_stop_is_required\n"); SHOW_TIME("event_stop > post my_sem_stop_is_required\n");
sem_post(&my_sem_stop_is_required); sem_post(&my_sem_stop_is_required);
a_event_is_running = 1; a_event_is_running = 1;
}
else
{
} else {
init(); // clear pending events init(); // clear pending events
} }
SHOW_TIME("event_stop > unlocking\n"); SHOW_TIME("event_stop > unlocking\n");
a_status = pthread_mutex_unlock(&my_mutex); a_status = pthread_mutex_unlock(&my_mutex);
if (a_status != 0)
{
if (a_status != 0) {
return EE_INTERNAL_ERROR; return EE_INTERNAL_ERROR;
} }


if (a_event_is_running)
{
if (a_event_is_running) {
SHOW_TIME("event_stop > wait for my_sem_stop_is_acknowledged\n"); SHOW_TIME("event_stop > wait for my_sem_stop_is_acknowledged\n");
while ((sem_wait(&my_sem_stop_is_acknowledged) == -1) && errno == EINTR)
{
while ((sem_wait(&my_sem_stop_is_acknowledged) == -1) && errno == EINTR) {
continue; // Restart when interrupted by handler continue; // Restart when interrupted by handler
} }
SHOW_TIME("event_stop > get my_sem_stop_is_acknowledged\n"); SHOW_TIME("event_stop > get my_sem_stop_is_acknowledged\n");
{ {
ENTER("sleep_until_timeout_or_stop_request"); ENTER("sleep_until_timeout_or_stop_request");


int a_stop_is_required=0;
int a_stop_is_required = 0;
struct timespec ts; struct timespec ts;
struct timeval tv; struct timeval tv;
int err=0;
int err = 0;


clock_gettime2( &ts);
clock_gettime2(&ts);


#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
struct timespec to; struct timespec to;
to.tv_nsec = ts.tv_nsec; to.tv_nsec = ts.tv_nsec;
#endif #endif


add_time_in_ms( &ts, time_in_ms);
add_time_in_ms(&ts, time_in_ms);


SHOW("polling_thread > sleep_until_timeout_or_stop_request > start sem_timedwait from %d.%09lu to %d.%09lu \n", SHOW("polling_thread > sleep_until_timeout_or_stop_request > start sem_timedwait from %d.%09lu to %d.%09lu \n",
to.tv_sec, to.tv_nsec, to.tv_sec, to.tv_nsec,
ts.tv_sec, ts.tv_nsec); ts.tv_sec, ts.tv_nsec);


while ((err = sem_timedwait(&my_sem_stop_is_required, &ts)) == -1 while ((err = sem_timedwait(&my_sem_stop_is_required, &ts)) == -1
&& errno == EINTR)
{
&& errno == EINTR) {
continue; // Restart when interrupted by handler continue; // Restart when interrupted by handler
} }


assert (gettimeofday(&tv, NULL) != -1);
assert(gettimeofday(&tv, NULL) != -1);
SHOW("polling_thread > sleep_until_timeout_or_stop_request > stop sem_timedwait %d.%09lu \n", SHOW("polling_thread > sleep_until_timeout_or_stop_request > stop sem_timedwait %d.%09lu \n",
tv.tv_sec, tv.tv_usec*1000); tv.tv_sec, tv.tv_usec*1000);


if (err == 0)
{
SHOW("polling_thread > sleep_until_timeout_or_stop_request > %s\n","stop required!");
a_stop_is_required=1; // stop required
if (err == 0) {
SHOW("polling_thread > sleep_until_timeout_or_stop_request > %s\n", "stop required!");
a_stop_is_required = 1; // stop required
} }
return a_stop_is_required; return a_stop_is_required;
} }
// If the stream is opened but the audio samples are not played, // If the stream is opened but the audio samples are not played,
// a timeout is started. // a timeout is started.


static int get_remaining_time(uint32_t sample, uint32_t* time_in_ms, int* stop_is_required)
static int get_remaining_time(uint32_t sample, uint32_t *time_in_ms, int *stop_is_required)
{ {
ENTER("get_remaining_time"); ENTER("get_remaining_time");


int err = 0; int err = 0;
*stop_is_required = 0; *stop_is_required = 0;
int i=0;
int i = 0;


for (i=0; i < MAX_ACTIVITY_CHECK && (*stop_is_required == 0); i++)
{
err = wave_get_remaining_time( sample, time_in_ms);
for (i = 0; i < MAX_ACTIVITY_CHECK && (*stop_is_required == 0); i++) {
err = wave_get_remaining_time(sample, time_in_ms);


if (err || wave_is_busy(NULL) || (*time_in_ms == 0))
{ // if err, stream not available: quit
// if wave is busy, time_in_ms is known: quit
// if wave is not busy but remaining time == 0, event is reached: quit
if (err || wave_is_busy(NULL) || (*time_in_ms == 0)) { // if err, stream not available: quit
// if wave is busy, time_in_ms is known: quit
// if wave is not busy but remaining time == 0, event is reached: quit
break; break;
} }


// //
// wait for the close of stream // wait for the close of stream


*stop_is_required = sleep_until_timeout_or_stop_request( ACTIVITY_TIMEOUT);
*stop_is_required = sleep_until_timeout_or_stop_request(ACTIVITY_TIMEOUT);
} }


return err; return err;
} }


static void* polling_thread(void*p)
static void *polling_thread(void *p)
{ {
ENTER("polling_thread"); ENTER("polling_thread");


while(1)
{
int a_stop_is_required=0;
while (1) {
int a_stop_is_required = 0;


SHOW_TIME("polling_thread > locking\n"); SHOW_TIME("polling_thread > locking\n");
int a_status = pthread_mutex_lock(&my_mutex); int a_status = pthread_mutex_lock(&my_mutex);


SHOW_TIME("polling_thread > wait for my_sem_start_is_required\n"); SHOW_TIME("polling_thread > wait for my_sem_start_is_required\n");


while ((sem_wait(&my_sem_start_is_required) == -1) && errno == EINTR)
{
while ((sem_wait(&my_sem_start_is_required) == -1) && errno == EINTR) {
continue; // Restart when interrupted by handler continue; // Restart when interrupted by handler
} }


pthread_mutex_unlock(&my_mutex); pthread_mutex_unlock(&my_mutex);
SHOW_TIME("polling_thread > unlocked\n"); SHOW_TIME("polling_thread > unlocked\n");


a_stop_is_required=0;
a_stop_is_required = 0;
a_status = sem_getvalue(&my_sem_stop_is_required, &a_stop_is_required); // NOTE: may set a_stop_is_required to -1 a_status = sem_getvalue(&my_sem_stop_is_required, &a_stop_is_required); // NOTE: may set a_stop_is_required to -1
if ((a_status==0) && (a_stop_is_required > 0))
{
if ((a_status == 0) && (a_stop_is_required > 0)) {
SHOW("polling_thread > stop required (%d)\n", __LINE__); SHOW("polling_thread > stop required (%d)\n", __LINE__);
while(0 == sem_trywait(&my_sem_stop_is_required))
{
};
}
else
{
a_stop_is_required=0;
while (0 == sem_trywait(&my_sem_stop_is_required)) {
}
;
} else {
a_stop_is_required = 0;
} }


// In this loop, my_event_is_running = 1 // In this loop, my_event_is_running = 1
while (head && (a_stop_is_required <= 0))
{
while (head && (a_stop_is_required <= 0)) {
SHOW_TIME("polling_thread > check head\n"); SHOW_TIME("polling_thread > check head\n");
while(0 == sem_trywait(&my_sem_start_is_required))
{
};
while (0 == sem_trywait(&my_sem_start_is_required)) {
}
;


espeak_EVENT* event = (espeak_EVENT*)(head->data);
espeak_EVENT *event = (espeak_EVENT *)(head->data);
assert(event); assert(event);


uint32_t time_in_ms = 0; uint32_t time_in_ms = 0;
int err = get_remaining_time((uint32_t)event->sample, int err = get_remaining_time((uint32_t)event->sample,
&time_in_ms, &time_in_ms,
&a_stop_is_required); &a_stop_is_required);
if (a_stop_is_required > 0)
{
if (a_stop_is_required > 0) {
break; break;
}
else if (err != 0)
{
} else if (err != 0) {
// No available time: the event is deleted. // No available time: the event is deleted.
SHOW("polling_thread > %s\n","audio device down");
SHOW("polling_thread > %s\n", "audio device down");
a_status = pthread_mutex_lock(&my_mutex); a_status = pthread_mutex_lock(&my_mutex);
SHOW_TIME("polling_thread > locked\n"); SHOW_TIME("polling_thread > locked\n");
event_delete( (espeak_EVENT*)pop());
event_delete((espeak_EVENT *)pop());
a_status = pthread_mutex_unlock(&my_mutex); a_status = pthread_mutex_unlock(&my_mutex);
SHOW_TIME("polling_thread > unlocked\n"); SHOW_TIME("polling_thread > unlocked\n");
}
else if (time_in_ms==0)
{ // the event is already reached.
if (my_callback)
{
} else if (time_in_ms == 0) { // the event is already reached.
if (my_callback) {
event_notify(event); event_notify(event);
// the user_data (and the type) are cleaned to be sure // the user_data (and the type) are cleaned to be sure
// that MSG_TERMINATED is called twice (at delete time too). // that MSG_TERMINATED is called twice (at delete time too).
event->type=espeakEVENT_LIST_TERMINATED;
event->user_data=NULL;
event->type = espeakEVENT_LIST_TERMINATED;
event->user_data = NULL;
} }


a_status = pthread_mutex_lock(&my_mutex); a_status = pthread_mutex_lock(&my_mutex);
SHOW_TIME("polling_thread > locked\n"); SHOW_TIME("polling_thread > locked\n");
event_delete( (espeak_EVENT*)pop());
event_delete((espeak_EVENT *)pop());
a_status = pthread_mutex_unlock(&my_mutex); a_status = pthread_mutex_unlock(&my_mutex);
SHOW_TIME("polling_thread > unlocked\n"); SHOW_TIME("polling_thread > unlocked\n");


a_stop_is_required=0;
a_stop_is_required = 0;
a_status = sem_getvalue(&my_sem_stop_is_required, &a_stop_is_required); a_status = sem_getvalue(&my_sem_stop_is_required, &a_stop_is_required);


if ((a_status==0) && (a_stop_is_required > 0))
{
if ((a_status == 0) && (a_stop_is_required > 0)) {
SHOW("polling_thread > stop required (%d)\n", __LINE__); SHOW("polling_thread > stop required (%d)\n", __LINE__);
while(0 == sem_trywait(&my_sem_stop_is_required))
{
};
}
else
{
a_stop_is_required=0;
while (0 == sem_trywait(&my_sem_stop_is_required)) {
}
;
} else {
a_stop_is_required = 0;
} }
}
else
{ // The event will be notified soon: sleep until timeout or stop request
} else { // The event will be notified soon: sleep until timeout or stop request
a_stop_is_required = sleep_until_timeout_or_stop_request(time_in_ms); a_stop_is_required = sleep_until_timeout_or_stop_request(time_in_ms);
} }
} }
SHOW_TIME("polling_thread > my_event_is_running = 0\n"); SHOW_TIME("polling_thread > my_event_is_running = 0\n");
my_event_is_running = 0; my_event_is_running = 0;


if(a_stop_is_required <= 0)
{
if (a_stop_is_required <= 0) {
a_status = sem_getvalue(&my_sem_stop_is_required, &a_stop_is_required); a_status = sem_getvalue(&my_sem_stop_is_required, &a_stop_is_required);
if ((a_status==0) && (a_stop_is_required > 0))
{
if ((a_status == 0) && (a_stop_is_required > 0)) {
SHOW("polling_thread > stop required (%d)\n", __LINE__); SHOW("polling_thread > stop required (%d)\n", __LINE__);
while(0 == sem_trywait(&my_sem_stop_is_required))
{
};
}
else
{
a_stop_is_required=0;
while (0 == sem_trywait(&my_sem_stop_is_required)) {
}
;
} else {
a_stop_is_required = 0;
} }
} }


a_status = pthread_mutex_unlock(&my_mutex); a_status = pthread_mutex_unlock(&my_mutex);
SHOW_TIME("polling_thread > unlocked\n"); SHOW_TIME("polling_thread > unlocked\n");


if (a_stop_is_required > 0)
{
SHOW("polling_thread > %s\n","stop required!");
if (a_stop_is_required > 0) {
SHOW("polling_thread > %s\n", "stop required!");
// no mutex required since the stop command is synchronous // no mutex required since the stop command is synchronous
// and waiting for my_sem_stop_is_acknowledged // and waiting for my_sem_stop_is_acknowledged
init(); init();
return NULL; return NULL;
} }


enum {MAX_NODE_COUNTER=1000};
enum { MAX_NODE_COUNTER = 1000 };


static espeak_ERROR push(void* the_data)
static espeak_ERROR push(void *the_data)
{ {
ENTER("event > push"); ENTER("event > push");


assert((!head && !tail) || (head && tail)); assert((!head && !tail) || (head && tail));


if (the_data == NULL)
{
if (the_data == NULL) {
SHOW("event > push > event=0x%x\n", NULL); SHOW("event > push > event=0x%x\n", NULL);
return EE_INTERNAL_ERROR; return EE_INTERNAL_ERROR;
} }


if (node_counter >= MAX_NODE_COUNTER)
{
if (node_counter >= MAX_NODE_COUNTER) {
SHOW("event > push > %s\n", "EE_BUFFER_FULL"); SHOW("event > push > %s\n", "EE_BUFFER_FULL");
return EE_BUFFER_FULL; return EE_BUFFER_FULL;
} }


node *n = (node *)malloc(sizeof(node)); node *n = (node *)malloc(sizeof(node));
if (n == NULL)
{
if (n == NULL) {
return EE_INTERNAL_ERROR; return EE_INTERNAL_ERROR;
} }


if (head == NULL)
{
if (head == NULL) {
head = n; head = n;
tail = n; tail = n;
}
else
{
} else {
tail->next = n; tail->next = n;
tail = n; tail = n;
} }
tail->data = the_data; tail->data = the_data;


node_counter++; node_counter++;
SHOW("event > push > counter=%d (uid=%d)\n",node_counter,((espeak_EVENT*)the_data)->unique_identifier);
SHOW("event > push > counter=%d (uid=%d)\n", node_counter, ((espeak_EVENT *)the_data)->unique_identifier);


return EE_OK; return EE_OK;
} }


static void* pop()
static void *pop()
{ {
ENTER("event > pop"); ENTER("event > pop");
void* the_data = NULL;
void *the_data = NULL;


assert((!head && !tail) || (head && tail)); assert((!head && !tail) || (head && tail));


if (head != NULL)
{
node* n = head;
if (head != NULL) {
node *n = head;
the_data = n->data; the_data = n->data;
head = n->next; head = n->next;
free(n); free(n);
node_counter--; node_counter--;
SHOW("event > pop > event=0x%x (counter=%d, uid=%d)\n",the_data, node_counter,((espeak_EVENT*)the_data)->unique_identifier);
SHOW("event > pop > event=0x%x (counter=%d, uid=%d)\n", the_data, node_counter, ((espeak_EVENT *)the_data)->unique_identifier);
} }


if(head == NULL)
{
if (head == NULL) {
tail = NULL; tail = NULL;
} }


{ {
ENTER("event > init"); ENTER("event > init");


while (event_delete( (espeak_EVENT*)pop() ))
{}
while (event_delete((espeak_EVENT *)pop())) {
}


node_counter = 0; node_counter = 0;
} }
{ {
ENTER("event_terminate"); ENTER("event_terminate");


if (thread_inited)
{
if (thread_inited) {
pthread_cancel(my_thread); pthread_cancel(my_thread);
pthread_join(my_thread,NULL);
pthread_join(my_thread, NULL);
pthread_mutex_destroy(&my_mutex); pthread_mutex_destroy(&my_mutex);
sem_destroy(&my_sem_start_is_required); sem_destroy(&my_sem_start_is_required);
sem_destroy(&my_sem_stop_is_required); sem_destroy(&my_sem_stop_is_required);

+ 3
- 3
src/libespeak-ng/event.h View File

// the callback will be called when the event actually occurs. // the callback will be called when the event actually occurs.
// The callback is detailled in speak_lib.h . // The callback is detailled in speak_lib.h .
void event_init(void); void event_init(void);
void event_set_callback(t_espeak_callback* cb);
void event_set_callback(t_espeak_callback *cb);


// Clear any pending event. // Clear any pending event.
// //
// Return: EE_OK: operation achieved // Return: EE_OK: operation achieved
// EE_INTERNAL_ERROR. // EE_INTERNAL_ERROR.
espeak_ERROR event_clear_all ();
espeak_ERROR event_clear_all();


// Declare a future event // Declare a future event
// //
// EE_BUFFER_FULL: the event can not be buffered; // EE_BUFFER_FULL: the event can not be buffered;
// you may try after a while to call the function again. // you may try after a while to call the function again.
// EE_INTERNAL_ERROR. // EE_INTERNAL_ERROR.
espeak_ERROR event_declare (espeak_EVENT* event);
espeak_ERROR event_declare(espeak_EVENT *event);


// Terminate the event component. // Terminate the event component.
// Last function to be called. // Last function to be called.

+ 96
- 145
src/libespeak-ng/fifo.c View File

static sem_t my_sem_start_is_required; static sem_t my_sem_start_is_required;
static sem_t my_sem_stop_is_acknowledged; static sem_t my_sem_stop_is_acknowledged;


static void* say_thread(void*);
static void *say_thread(void *);


static espeak_ERROR push(t_espeak_command* the_command);
static t_espeak_command* pop();
static espeak_ERROR push(t_espeak_command *the_command);
static t_espeak_command *pop();
static void init(int process_parameters); static void init(int process_parameters);
static int node_counter=0;
enum {MAX_NODE_COUNTER=400,
INACTIVITY_TIMEOUT=50, // in ms, check that the stream is inactive
MAX_INACTIVITY_CHECK=2};
static int node_counter = 0;
enum { MAX_NODE_COUNTER = 400,
INACTIVITY_TIMEOUT = 50, // in ms, check that the stream is inactive
MAX_INACTIVITY_CHECK = 2 };


void fifo_init() void fifo_init()
{ {
ENTER("fifo_init"); ENTER("fifo_init");


// security // security
pthread_mutex_init( &my_mutex, (const pthread_mutexattr_t *)NULL);
pthread_mutex_init(&my_mutex, (const pthread_mutexattr_t *)NULL);
init(0); init(0);


assert(-1 != sem_init(&my_sem_start_is_required, 0, 0)); assert(-1 != sem_init(&my_sem_start_is_required, 0, 0));
assert(-1 != sem_init(&my_sem_stop_is_acknowledged, 0, 0)); assert(-1 != sem_init(&my_sem_stop_is_acknowledged, 0, 0));


pthread_attr_t a_attrib; pthread_attr_t a_attrib;
if (pthread_attr_init (&a_attrib)
if (pthread_attr_init(&a_attrib)
|| pthread_attr_setdetachstate(&a_attrib, PTHREAD_CREATE_JOINABLE) || pthread_attr_setdetachstate(&a_attrib, PTHREAD_CREATE_JOINABLE)
|| pthread_create( &my_thread,
&a_attrib,
say_thread,
(void*)NULL))
{
|| pthread_create(&my_thread,
&a_attrib,
say_thread,
(void *)NULL)) {
assert(0); assert(0);
} }




// leave once the thread is actually started // leave once the thread is actually started
SHOW_TIME("fifo > wait for my_sem_stop_is_acknowledged\n"); SHOW_TIME("fifo > wait for my_sem_stop_is_acknowledged\n");
while ((sem_wait(&my_sem_stop_is_acknowledged) == -1) && errno == EINTR)
{
while ((sem_wait(&my_sem_stop_is_acknowledged) == -1) && errno == EINTR) {
continue; // Restart when interrupted by handler continue; // Restart when interrupted by handler
} }
SHOW_TIME("fifo > get my_sem_stop_is_acknowledged\n"); SHOW_TIME("fifo > get my_sem_stop_is_acknowledged\n");
} }


espeak_ERROR fifo_add_command (t_espeak_command* the_command)
espeak_ERROR fifo_add_command(t_espeak_command *the_command)
{ {
ENTER("fifo_add_command"); ENTER("fifo_add_command");


int a_status = pthread_mutex_lock(&my_mutex); int a_status = pthread_mutex_lock(&my_mutex);
espeak_ERROR a_error = EE_OK; espeak_ERROR a_error = EE_OK;


if (!a_status)
{
if (!a_status) {
SHOW_TIME("fifo_add_command > locked\n"); SHOW_TIME("fifo_add_command > locked\n");
a_error = push(the_command); a_error = push(the_command);
SHOW_TIME("fifo_add_command > unlocking\n"); SHOW_TIME("fifo_add_command > unlocking\n");
a_status = pthread_mutex_unlock(&my_mutex); a_status = pthread_mutex_unlock(&my_mutex);
} }


if (!a_status && !my_command_is_running && (a_error == EE_OK))
{
if (!a_status && !my_command_is_running && (a_error == EE_OK)) {
// quit when command is actually started // quit when command is actually started
// (for possible forthcoming 'end of command' checks) // (for possible forthcoming 'end of command' checks)
SHOW_TIME("fifo_add_command > post my_sem_start_is_required\n"); SHOW_TIME("fifo_add_command > post my_sem_start_is_required\n");
sem_post(&my_sem_start_is_required); sem_post(&my_sem_start_is_required);
int val=1;
while (val > 0)
{
int val = 1;
while (val > 0) {
usleep(50000); // TBD: event? usleep(50000); // TBD: event?
sem_getvalue(&my_sem_start_is_required, &val); sem_getvalue(&my_sem_start_is_required, &val);
} }
} }


if (a_status != 0)
{
if (a_status != 0) {
a_error = EE_INTERNAL_ERROR; a_error = EE_INTERNAL_ERROR;
} }


return a_error; return a_error;
} }


espeak_ERROR fifo_add_commands (t_espeak_command* command1, t_espeak_command* command2)
espeak_ERROR fifo_add_commands(t_espeak_command *command1, t_espeak_command *command2)
{ {
ENTER("fifo_add_command"); ENTER("fifo_add_command");


int a_status = pthread_mutex_lock(&my_mutex); int a_status = pthread_mutex_lock(&my_mutex);
espeak_ERROR a_error = EE_OK; espeak_ERROR a_error = EE_OK;


if (!a_status)
{
if (!a_status) {
SHOW_TIME("fifo_add_commands > locked\n"); SHOW_TIME("fifo_add_commands > locked\n");


if (node_counter+1 >= MAX_NODE_COUNTER)
{
if (node_counter+1 >= MAX_NODE_COUNTER) {
SHOW("push > %s\n", "EE_BUFFER_FULL"); SHOW("push > %s\n", "EE_BUFFER_FULL");
a_error = EE_BUFFER_FULL; a_error = EE_BUFFER_FULL;
}
else
{
} else {
push(command1); push(command1);
push(command2); push(command2);
} }
a_status = pthread_mutex_unlock(&my_mutex); a_status = pthread_mutex_unlock(&my_mutex);
} }


if (!a_status && !my_command_is_running && (a_error == EE_OK))
{
if (!a_status && !my_command_is_running && (a_error == EE_OK)) {
// quit when one command is actually started // quit when one command is actually started
// (for possible forthcoming 'end of command' checks) // (for possible forthcoming 'end of command' checks)
SHOW_TIME("fifo_add_command > post my_sem_start_is_required\n"); SHOW_TIME("fifo_add_command > post my_sem_start_is_required\n");
sem_post(&my_sem_start_is_required); sem_post(&my_sem_start_is_required);
int val=1;
while (val > 0)
{
int val = 1;
while (val > 0) {
usleep(50000); // TBD: event? usleep(50000); // TBD: event?
sem_getvalue(&my_sem_start_is_required, &val); sem_getvalue(&my_sem_start_is_required, &val);
} }
} }


if (a_status != 0)
{
if (a_status != 0) {
a_error = EE_INTERNAL_ERROR; a_error = EE_INTERNAL_ERROR;
} }


return a_error; return a_error;
} }


espeak_ERROR fifo_stop ()
espeak_ERROR fifo_stop()
{ {
ENTER("fifo_stop"); ENTER("fifo_stop");


int a_command_is_running = 0; int a_command_is_running = 0;
int a_status = pthread_mutex_lock(&my_mutex); int a_status = pthread_mutex_lock(&my_mutex);
SHOW_TIME("fifo_stop > locked\n"); SHOW_TIME("fifo_stop > locked\n");
if (a_status != 0)
{
if (a_status != 0) {
return EE_INTERNAL_ERROR; return EE_INTERNAL_ERROR;
} }


if (my_command_is_running)
{
if (my_command_is_running) {
a_command_is_running = 1; a_command_is_running = 1;
my_stop_is_required = 1; my_stop_is_required = 1;
SHOW_TIME("fifo_stop > my_stop_is_required = 1\n"); SHOW_TIME("fifo_stop > my_stop_is_required = 1\n");
} }
SHOW_TIME("fifo_stop > unlocking\n"); SHOW_TIME("fifo_stop > unlocking\n");
a_status = pthread_mutex_unlock(&my_mutex); a_status = pthread_mutex_unlock(&my_mutex);
if (a_status != 0)
{
if (a_status != 0) {
return EE_INTERNAL_ERROR; return EE_INTERNAL_ERROR;
} }


if (a_command_is_running)
{
if (a_command_is_running) {
SHOW_TIME("fifo_stop > wait for my_sem_stop_is_acknowledged\n"); SHOW_TIME("fifo_stop > wait for my_sem_stop_is_acknowledged\n");
while ((sem_wait(&my_sem_stop_is_acknowledged) == -1) && errno == EINTR)
{
while ((sem_wait(&my_sem_stop_is_acknowledged) == -1) && errno == EINTR) {
continue; // Restart when interrupted by handler continue; // Restart when interrupted by handler
} }
SHOW_TIME("fifo_stop > get my_sem_stop_is_acknowledged\n"); SHOW_TIME("fifo_stop > get my_sem_stop_is_acknowledged\n");
return EE_OK; return EE_OK;
} }


int fifo_is_busy ()
int fifo_is_busy()
{ {
SHOW("fifo_is_busy > aResult = %d\n",my_command_is_running);
SHOW("fifo_is_busy > aResult = %d\n", my_command_is_running);
return my_command_is_running; return my_command_is_running;
} }


static int sleep_until_start_request_or_inactivity() static int sleep_until_start_request_or_inactivity()
{ {
SHOW_TIME("fifo > sleep_until_start_request_or_inactivity > ENTER"); SHOW_TIME("fifo > sleep_until_start_request_or_inactivity > ENTER");
int a_start_is_required=0;
int a_start_is_required = 0;


// Wait for the start request (my_sem_start_is_required). // Wait for the start request (my_sem_start_is_required).
// Besides this, if the audio stream is still busy, // Besides this, if the audio stream is still busy,
// The end of the stream is confirmed by several checks // The end of the stream is confirmed by several checks
// for filtering underflow. // for filtering underflow.
// //
int i=0;
while((i<= MAX_INACTIVITY_CHECK) && !a_start_is_required)
{
if (wave_is_busy( NULL) )
{
int i = 0;
while ((i <= MAX_INACTIVITY_CHECK) && !a_start_is_required) {
if (wave_is_busy(NULL)) {
i = 0; i = 0;
}
else
{
} else {
i++; i++;
} }


int err=0;
int err = 0;
struct timespec ts; struct timespec ts;
struct timeval tv; struct timeval tv;


clock_gettime2( &ts);
clock_gettime2(&ts);


#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
struct timespec to; struct timespec to;
to.tv_nsec = ts.tv_nsec; to.tv_nsec = ts.tv_nsec;
#endif #endif


add_time_in_ms( &ts, INACTIVITY_TIMEOUT);
add_time_in_ms(&ts, INACTIVITY_TIMEOUT);


SHOW("fifo > sleep_until_start_request_or_inactivity > start sem_timedwait (start_is_required) from %d.%09lu to %d.%09lu \n", SHOW("fifo > sleep_until_start_request_or_inactivity > start sem_timedwait (start_is_required) from %d.%09lu to %d.%09lu \n",
to.tv_sec, to.tv_nsec, to.tv_sec, to.tv_nsec,
ts.tv_sec, ts.tv_nsec); ts.tv_sec, ts.tv_nsec);


while ((err = sem_timedwait(&my_sem_start_is_required, &ts)) == -1 while ((err = sem_timedwait(&my_sem_start_is_required, &ts)) == -1
&& errno == EINTR)
{
&& errno == EINTR) {
continue; continue;
} }


assert (gettimeofday(&tv, NULL) != -1);
assert(gettimeofday(&tv, NULL) != -1);
SHOW("fifo > sleep_until_start_request_or_inactivity > stop sem_timedwait (start_is_required, err=%d) %d.%09lu \n", err, SHOW("fifo > sleep_until_start_request_or_inactivity > stop sem_timedwait (start_is_required, err=%d) %d.%09lu \n", err,
tv.tv_sec, tv.tv_usec*1000); tv.tv_sec, tv.tv_usec*1000);


if (err==0)
{
if (err == 0) {
a_start_is_required = 1; a_start_is_required = 1;
} }
} }
// my_stop_is_required = 1; // my_stop_is_required = 1;


int a_status = pthread_mutex_lock(&my_mutex); int a_status = pthread_mutex_lock(&my_mutex);
assert (!a_status);
assert(!a_status);
int a_stop_is_required = my_stop_is_required; int a_stop_is_required = my_stop_is_required;
if (!a_stop_is_required)
{
if (!a_stop_is_required) {
my_command_is_running = 1; my_command_is_running = 1;
} }
a_status = pthread_mutex_unlock(&my_mutex); a_status = pthread_mutex_unlock(&my_mutex);


if (!a_stop_is_required)
{
if (!a_stop_is_required) {
wave_close(NULL); wave_close(NULL);


int a_status = pthread_mutex_lock(&my_mutex); int a_status = pthread_mutex_lock(&my_mutex);
assert (!a_status);
assert(!a_status);
my_command_is_running = 0; my_command_is_running = 0;


a_stop_is_required = my_stop_is_required; a_stop_is_required = my_stop_is_required;
a_status = pthread_mutex_unlock(&my_mutex); a_status = pthread_mutex_unlock(&my_mutex);


if (a_stop_is_required)
{
if (a_stop_is_required) {
// acknowledge the stop request // acknowledge the stop request
SHOW_TIME("fifo > close_stream > post my_sem_stop_is_acknowledged\n"); SHOW_TIME("fifo > close_stream > post my_sem_stop_is_acknowledged\n");
int a_status = sem_post(&my_sem_stop_is_acknowledged); int a_status = sem_post(&my_sem_stop_is_acknowledged);
assert( a_status != -1);
assert(a_status != -1);
} }
} }


SHOW_TIME("fifo > close_stream > LEAVE\n"); SHOW_TIME("fifo > close_stream > LEAVE\n");
} }


static void* say_thread(void*p)
static void *say_thread(void *p)
{ {
ENTER("say_thread"); ENTER("say_thread");


// announce that thread is started // announce that thread is started
sem_post(&my_sem_stop_is_acknowledged); sem_post(&my_sem_stop_is_acknowledged);


int look_for_inactivity=0;
int look_for_inactivity = 0;


while(1)
{
while (1) {
SHOW_TIME("say_thread > wait for my_sem_start_is_required\n"); SHOW_TIME("say_thread > wait for my_sem_start_is_required\n");


int a_start_is_required = 0; int a_start_is_required = 0;
if (look_for_inactivity)
{
if (look_for_inactivity) {
a_start_is_required = sleep_until_start_request_or_inactivity(); a_start_is_required = sleep_until_start_request_or_inactivity();
if (!a_start_is_required)
{
if (!a_start_is_required) {
close_stream(); close_stream();
} }
} }
look_for_inactivity = 1; look_for_inactivity = 1;


if (!a_start_is_required)
{
while ((sem_wait(&my_sem_start_is_required) == -1) && errno == EINTR)
{
if (!a_start_is_required) {
while ((sem_wait(&my_sem_start_is_required) == -1) && errno == EINTR) {
continue; // Restart when interrupted by handler continue; // Restart when interrupted by handler
} }
} }
SHOW_TIME("say_thread > my_command_is_running = 1\n"); SHOW_TIME("say_thread > my_command_is_running = 1\n");
my_command_is_running = 1; my_command_is_running = 1;


while( my_command_is_running)
{
while (my_command_is_running) {
SHOW_TIME("say_thread > locking\n"); SHOW_TIME("say_thread > locking\n");
int a_status = pthread_mutex_lock(&my_mutex); int a_status = pthread_mutex_lock(&my_mutex);
assert (!a_status);
t_espeak_command* a_command = (t_espeak_command*)pop();
assert(!a_status);
t_espeak_command *a_command = (t_espeak_command *)pop();


if (a_command == NULL)
{
if (a_command == NULL) {
SHOW_TIME("say_thread > text empty (talking=0) \n"); SHOW_TIME("say_thread > text empty (talking=0) \n");
a_status = pthread_mutex_unlock(&my_mutex); a_status = pthread_mutex_unlock(&my_mutex);
SHOW_TIME("say_thread > unlocked\n"); SHOW_TIME("say_thread > unlocked\n");
SHOW_TIME("say_thread > my_command_is_running = 0\n"); SHOW_TIME("say_thread > my_command_is_running = 0\n");
my_command_is_running = 0; my_command_is_running = 0;
}
else
{
} else {
display_espeak_command(a_command); display_espeak_command(a_command);
// purge start semaphore // purge start semaphore
SHOW_TIME("say_thread > purge my_sem_start_is_required\n"); SHOW_TIME("say_thread > purge my_sem_start_is_required\n");
while(0 == sem_trywait(&my_sem_start_is_required))
{
};
while (0 == sem_trywait(&my_sem_start_is_required)) {
}
;


if (my_stop_is_required)
{
if (my_stop_is_required) {
SHOW_TIME("say_thread > my_command_is_running = 0\n"); SHOW_TIME("say_thread > my_command_is_running = 0\n");
my_command_is_running = 0; my_command_is_running = 0;
} }
SHOW_TIME("say_thread > unlocking\n"); SHOW_TIME("say_thread > unlocking\n");
a_status = pthread_mutex_unlock(&my_mutex); a_status = pthread_mutex_unlock(&my_mutex);


if (my_command_is_running)
{
if (my_command_is_running) {
process_espeak_command(a_command); process_espeak_command(a_command);
} }
delete_espeak_command(a_command); delete_espeak_command(a_command);
} }
} }


if (my_stop_is_required)
{
if (my_stop_is_required) {
// no mutex required since the stop command is synchronous // no mutex required since the stop command is synchronous
// and waiting for my_sem_stop_is_acknowledged // and waiting for my_sem_stop_is_acknowledged
init(1); init(1);


// purge start semaphore // purge start semaphore
SHOW_TIME("say_thread > purge my_sem_start_is_required\n"); SHOW_TIME("say_thread > purge my_sem_start_is_required\n");
while(0==sem_trywait(&my_sem_start_is_required))
{
};
while (0 == sem_trywait(&my_sem_start_is_required)) {
}
;


// acknowledge the stop request // acknowledge the stop request
SHOW_TIME("say_thread > post my_sem_stop_is_acknowledged\n"); SHOW_TIME("say_thread > post my_sem_stop_is_acknowledged\n");
int a_status = sem_post(&my_sem_stop_is_acknowledged); int a_status = sem_post(&my_sem_stop_is_acknowledged);
assert( a_status != -1);
assert(a_status != -1);
} }
// and wait for the next start // and wait for the next start
SHOW_TIME("say_thread > wait for my_sem_start_is_required\n"); SHOW_TIME("say_thread > wait for my_sem_start_is_required\n");


int fifo_is_command_enabled() int fifo_is_command_enabled()
{ {
SHOW("ENTER fifo_is_command_enabled=%d\n",(int)(0 == my_stop_is_required));
return (0 == my_stop_is_required);
SHOW("ENTER fifo_is_command_enabled=%d\n", (int)(0 == my_stop_is_required));
return 0 == my_stop_is_required;
} }


typedef struct t_node
{
t_espeak_command* data;
typedef struct t_node {
t_espeak_command *data;
struct t_node *next; struct t_node *next;
} node; } node;


static node* head=NULL;
static node* tail=NULL;
static node *head = NULL;
static node *tail = NULL;


static espeak_ERROR push(t_espeak_command* the_command)
static espeak_ERROR push(t_espeak_command *the_command)
{ {
ENTER("fifo > push"); ENTER("fifo > push");


assert((!head && !tail) || (head && tail)); assert((!head && !tail) || (head && tail));


if (the_command == NULL)
{
if (the_command == NULL) {
SHOW("push > command=0x%x\n", NULL); SHOW("push > command=0x%x\n", NULL);
return EE_INTERNAL_ERROR; return EE_INTERNAL_ERROR;
} }


if (node_counter >= MAX_NODE_COUNTER)
{
if (node_counter >= MAX_NODE_COUNTER) {
SHOW("push > %s\n", "EE_BUFFER_FULL"); SHOW("push > %s\n", "EE_BUFFER_FULL");
return EE_BUFFER_FULL; return EE_BUFFER_FULL;
} }


node *n = (node *)malloc(sizeof(node)); node *n = (node *)malloc(sizeof(node));
if (n == NULL)
{
if (n == NULL) {
return EE_INTERNAL_ERROR; return EE_INTERNAL_ERROR;
} }


if (head == NULL)
{
if (head == NULL) {
head = n; head = n;
tail = n; tail = n;
}
else
{
} else {
tail->next = n; tail->next = n;
tail = n; tail = n;
} }
tail->data = the_command; tail->data = the_command;


node_counter++; node_counter++;
SHOW("push > counter=%d\n",node_counter);
SHOW("push > counter=%d\n", node_counter);


the_command->state = CS_PENDING; the_command->state = CS_PENDING;
display_espeak_command(the_command); display_espeak_command(the_command);
return EE_OK; return EE_OK;
} }


static t_espeak_command* pop()
static t_espeak_command *pop()
{ {
ENTER("fifo > pop"); ENTER("fifo > pop");
t_espeak_command* the_command = NULL;
t_espeak_command *the_command = NULL;


assert((!head && !tail) || (head && tail)); assert((!head && !tail) || (head && tail));


if (head != NULL)
{
node* n = head;
if (head != NULL) {
node *n = head;
the_command = n->data; the_command = n->data;
head = n->next; head = n->next;
free(n); free(n);
node_counter--; node_counter--;
SHOW("pop > command=0x%x (counter=%d)\n",the_command, node_counter);
SHOW("pop > command=0x%x (counter=%d)\n", the_command, node_counter);
} }


if(head == NULL)
{
if (head == NULL) {
tail = NULL; tail = NULL;
} }


ENTER("fifo > init"); ENTER("fifo > init");
c = pop(); c = pop();
while (c != NULL) { while (c != NULL) {
if (process_parameters && (c->type == ET_PARAMETER || c->type == ET_VOICE_NAME || c->type == ET_VOICE_SPEC))
{
if (process_parameters && (c->type == ET_PARAMETER || c->type == ET_VOICE_NAME || c->type == ET_VOICE_SPEC)) {
process_espeak_command(c); process_espeak_command(c);
} }
delete_espeak_command(c); delete_espeak_command(c);
ENTER("fifo_terminate"); ENTER("fifo_terminate");


pthread_cancel(my_thread); pthread_cancel(my_thread);
pthread_join(my_thread,NULL);
pthread_join(my_thread, NULL);
pthread_mutex_destroy(&my_mutex); pthread_mutex_destroy(&my_mutex);
sem_destroy(&my_sem_start_is_required); sem_destroy(&my_sem_start_is_required);
sem_destroy(&my_sem_stop_is_acknowledged); sem_destroy(&my_sem_stop_is_acknowledged);

+ 4
- 4
src/libespeak-ng/fifo.h View File

// EE_BUFFER_FULL: the command can not be buffered; // EE_BUFFER_FULL: the command can not be buffered;
// you may try after a while to call the function again. // you may try after a while to call the function again.
// EE_INTERNAL_ERROR. // EE_INTERNAL_ERROR.
espeak_ERROR fifo_add_command (t_espeak_command* c);
espeak_ERROR fifo_add_command(t_espeak_command *c);


// Add two espeak commands in a single transaction. // Add two espeak commands in a single transaction.
// //
// EE_BUFFER_FULL: at least one command can not be buffered; // EE_BUFFER_FULL: at least one command can not be buffered;
// you may try after a while to call the function again. // you may try after a while to call the function again.
// EE_INTERNAL_ERROR. // EE_INTERNAL_ERROR.
espeak_ERROR fifo_add_commands (t_espeak_command* c1, t_espeak_command* c2);
espeak_ERROR fifo_add_commands(t_espeak_command *c1, t_espeak_command *c2);


// The current running command must be stopped and the awaiting commands are cleared. // The current running command must be stopped and the awaiting commands are cleared.
// Return: EE_OK: operation achieved // Return: EE_OK: operation achieved
// EE_INTERNAL_ERROR. // EE_INTERNAL_ERROR.
espeak_ERROR fifo_stop ();
espeak_ERROR fifo_stop();


// Is there a running command? // Is there a running command?
// Returns 1 if yes; 0 otherwise. // Returns 1 if yes; 0 otherwise.
int fifo_is_busy ();
int fifo_is_busy();


// Terminate the fifo component. // Terminate the fifo component.
// Last function to be called. // Last function to be called.

+ 241
- 375
src/libespeak-ng/intonation.c
File diff suppressed because it is too large
View File


+ 176
- 265
src/libespeak-ng/klatt.c
File diff suppressed because it is too large
View File


+ 4
- 7
src/libespeak-ng/klatt.h View File



/* Resonator Structure */ /* Resonator Structure */


typedef struct
{
typedef struct {
double a; double a;
double b; double b;
double c; double c;


/* Structure for Klatt Globals */ /* Structure for Klatt Globals */


typedef struct
{
typedef struct {
flag synthesis_model; /* cascade-parallel or all-parallel */ flag synthesis_model; /* cascade-parallel or all-parallel */
flag outsl; /* Output waveform selector */ flag outsl; /* Output waveform selector */
long samrate; /* Number of output samples per second */ long samrate; /* Number of output samples per second */
#define F_NP 9 // nasal pole formant #define F_NP 9 // nasal pole formant




typedef struct
{
typedef struct {
int F0hz10; /* Voicing fund freq in Hz */ int F0hz10; /* Voicing fund freq in Hz */
int AVdb; /* Amp of voicing in dB, 0 to 70 */ int AVdb; /* Amp of voicing in dB, 0 to 70 */
int Fhz[10]; // formant Hz, F_NZ to F6 to F_NP int Fhz[10]; // formant Hz, F_NZ to F6 to F_NP
int AVpdb; /* Amp of voicing, par in dB, 0 to 70 */ int AVpdb; /* Amp of voicing, par in dB, 0 to 70 */
int Gain0; /* Overall gain, 60 dB is unity, 0 to 60 */ int Gain0; /* Overall gain, 60 dB is unity, 0 to 60 */


int AVdb_tmp; //copy of AVdb, which is changed within parwave()
int AVdb_tmp; // copy of AVdb, which is changed within parwave()
int Fhz_next[10]; // Fhz for the next chunk, so we can do interpolation of resonator (a,b,c) parameters int Fhz_next[10]; // Fhz for the next chunk, so we can do interpolation of resonator (a,b,c) parameters
int Bhz_next[10]; int Bhz_next[10];
} klatt_frame_t, *klatt_frame_ptr; } klatt_frame_t, *klatt_frame_ptr;

+ 3
- 3
src/libespeak-ng/mbrowrap.c View File

char *buf_ptr, *lf; char *buf_ptr, *lf;


buf_ptr = buffer; buf_ptr = buffer;
for (;; ) {
for (;;) {
result = read(mbr_error_fd, buf_ptr, result = read(mbr_error_fd, buf_ptr,
sizeof(buffer) - (buf_ptr - buffer) - 1); sizeof(buffer) - (buf_ptr - buffer) - 1);
if (result == -1) { if (result == -1) {
p = (char *)memchr(buffer, ')', sizeof(buffer)); p = (char *)memchr(buffer, ')', sizeof(buffer));
if (!p || (unsigned)(p - buffer) >= sizeof(buffer) - 2) if (!p || (unsigned)(p - buffer) >= sizeof(buffer) - 2)
return 0; return 0;
return (p[1] == ' ' && p[2] == 'S');
return p[1] == ' ' && p[2] == 'S';
} }


static ssize_t receive_from_mbrola(void *buffer, size_t bufsize) static ssize_t receive_from_mbrola(void *buffer, size_t bufsize)
} }
mbr_samplerate = wavhdr[24] + (wavhdr[25]<<8) + mbr_samplerate = wavhdr[24] + (wavhdr[25]<<8) +
(wavhdr[26]<<16) + (wavhdr[27]<<24); (wavhdr[26]<<16) + (wavhdr[27]<<24);
//log("mbrowrap: voice samplerate = %d", mbr_samplerate);
// log("mbrowrap: voice samplerate = %d", mbr_samplerate);


/* remember the voice path for setVolumeRatio_MBR() */ /* remember the voice path for setVolumeRatio_MBR() */
if (mbr_voice_path != voice_path) { if (mbr_voice_path != voice_path) {

+ 679
- 973
src/libespeak-ng/numbers.c
File diff suppressed because it is too large
View File


+ 3
- 3
src/libespeak-ng/phoneme.h View File







#define PH(c1,c2) (c2<<8)+c1 // combine two characters into an integer for phoneme name
#define PH3(c1,c2,c3) (c3<<16)+(c2<<8)+c1
#define PhonemeCode2(c1,c2) PhonemeCode((c2<<8)+c1)
#define PH(c1, c2) (c2<<8)+c1 // combine two characters into an integer for phoneme name
#define PH3(c1, c2, c3) (c3<<16)+(c2<<8)+c1
#define PhonemeCode2(c1, c2) PhonemeCode((c2<<8)+c1)
int LookupPhonemeString(const char *string); int LookupPhonemeString(const char *string);
int PhonemeCode(unsigned int mnem); int PhonemeCode(unsigned int mnem);



+ 123
- 224
src/libespeak-ng/phonemelist.c View File

#include "translate.h" #include "translate.h"




const unsigned char pause_phonemes[8] = {0, phonPAUSE_VSHORT, phonPAUSE_SHORT, phonPAUSE, phonPAUSE_LONG, phonGLOTTALSTOP, phonPAUSE_LONG, phonPAUSE_LONG};
const unsigned char pause_phonemes[8] = { 0, phonPAUSE_VSHORT, phonPAUSE_SHORT, phonPAUSE, phonPAUSE_LONG, phonGLOTTALSTOP, phonPAUSE_LONG, phonPAUSE_LONG };




extern int n_ph_list2; extern int n_ph_list2;
int n_plist_out = 0; int n_plist_out = 0;
int word_end; int word_end;
PHONEME_LIST2 *plist2; PHONEME_LIST2 *plist2;
PHONEME_TAB *next=NULL;
PHONEME_TAB *next = NULL;


for(ix=0; (ix < n_ph_list2) && (n_plist_out < N_PHONEME_LIST); ix++)
{
for (ix = 0; (ix < n_ph_list2) && (n_plist_out < N_PHONEME_LIST); ix++) {
plist2 = &ph_list2[ix]; plist2 = &ph_list2[ix];


// don't do any substitution if the language has been temporarily changed // don't do any substitution if the language has been temporarily changed
if(!(plist2->synthflags & SFLAG_SWITCHED_LANG))
{
if(ix < (n_ph_list2 -1))
if (!(plist2->synthflags & SFLAG_SWITCHED_LANG)) {
if (ix < (n_ph_list2 -1))
next = phoneme_tab[ph_list2[ix+1].phcode]; next = phoneme_tab[ph_list2[ix+1].phcode];


word_end = 0; word_end = 0;
if((plist2+1)->sourceix || ((next != 0) && (next->type == phPAUSE)))
if ((plist2+1)->sourceix || ((next != 0) && (next->type == phPAUSE)))
word_end = 1; // this phoneme is the end of a word word_end = 1; // this phoneme is the end of a word


// check whether a Voice has specified that we should replace this phoneme // check whether a Voice has specified that we should replace this phoneme
for(k=0; k<n_replace_phonemes; k++)
{
if(plist2->phcode == replace_phonemes[k].old_ph)
{
for (k = 0; k < n_replace_phonemes; k++) {
if (plist2->phcode == replace_phonemes[k].old_ph) {
replace_flags = replace_phonemes[k].type; replace_flags = replace_phonemes[k].type;


if((replace_flags & 1) && (word_end == 0))
if ((replace_flags & 1) && (word_end == 0))
continue; // this replacement only occurs at the end of a word continue; // this replacement only occurs at the end of a word


if((replace_flags & 2) && ((plist2->stresslevel & 0x7) > 3))
if ((replace_flags & 2) && ((plist2->stresslevel & 0x7) > 3))
continue; // this replacement doesn't occur in stressed syllables continue; // this replacement doesn't occur in stressed syllables


if((replace_flags & 4) && (plist2->sourceix == 0))
if ((replace_flags & 4) && (plist2->sourceix == 0))
continue; // this replacement only occurs at the start of a word continue; // this replacement only occurs at the start of a word


// substitute the replacement phoneme // substitute the replacement phoneme
plist2->phcode = replace_phonemes[k].new_ph; plist2->phcode = replace_phonemes[k].new_ph;
if((plist2->stresslevel > 1) && (phoneme_tab[plist2->phcode]->phflags & phUNSTRESSED))
if ((plist2->stresslevel > 1) && (phoneme_tab[plist2->phcode]->phflags & phUNSTRESSED))
plist2->stresslevel = 0; // the replacement must be unstressed plist2->stresslevel = 0; // the replacement must be unstressed
break; break;
} }
} }


if(plist2->phcode == 0)
{
if (plist2->phcode == 0) {
continue; // phoneme has been replaced by NULL, so don't copy it continue; // phoneme has been replaced by NULL, so don't copy it
} }
} }


// copy phoneme into the output list // copy phoneme into the output list
memcpy(&plist_out[n_plist_out],plist2,sizeof(PHONEME_LIST2));
memcpy(&plist_out[n_plist_out], plist2, sizeof(PHONEME_LIST2));
plist_out[n_plist_out].ph = phoneme_tab[plist2->phcode]; plist_out[n_plist_out].ph = phoneme_tab[plist2->phcode];
plist_out[n_plist_out].type = plist_out[n_plist_out].ph->type; plist_out[n_plist_out].type = plist_out[n_plist_out].ph->type;
n_plist_out++; n_plist_out++;
} }
return(n_plist_out);
return n_plist_out;
} }




void MakePhonemeList(Translator *tr, int post_pause, int start_sentence) void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
{ {


int ix=0;
int ix = 0;
int j; int j;
int insert_ph = 0; int insert_ph = 0;
PHONEME_LIST *phlist; PHONEME_LIST *phlist;


// is the last word of the clause unstressed ? // is the last word of the clause unstressed ?
max_stress = 0; max_stress = 0;
for(j = n_ph_list2-3; j>=0; j--)
{
for (j = n_ph_list2-3; j >= 0; j--) {
// start with the last phoneme (before the terminating pauses) and move backwards // start with the last phoneme (before the terminating pauses) and move backwards
if((plist2[j].stresslevel & 0x7f) > max_stress)
if ((plist2[j].stresslevel & 0x7f) > max_stress)
max_stress = plist2[j].stresslevel & 0x7f; max_stress = plist2[j].stresslevel & 0x7f;
if(plist2[j].sourceix != 0)
if (plist2[j].sourceix != 0)
break; break;
} }
if(max_stress < 4)
{
if (max_stress < 4) {
// the last word is unstressed, look for a previous word that can be stressed // the last word is unstressed, look for a previous word that can be stressed
while(--j >= 0)
{
if(plist2[j].synthflags & SFLAG_PROMOTE_STRESS) // dictionary flags indicated that this stress can be promoted
{
while (--j >= 0) {
if (plist2[j].synthflags & SFLAG_PROMOTE_STRESS) { // dictionary flags indicated that this stress can be promoted
plist2[j].stresslevel = 4; // promote to stressed plist2[j].stresslevel = 4; // promote to stressed
break; break;
} }
if(plist2[j].stresslevel >= 4)
{
if (plist2[j].stresslevel >= 4) {
// found a stressed syllable, so stop looking // found a stressed syllable, so stop looking
break; break;
} }
// look for switch of phoneme tables // look for switch of phoneme tables
delete_count = 0; delete_count = 0;
current_phoneme_tab = tr->phoneme_tab_ix; current_phoneme_tab = tr->phoneme_tab_ix;
for(j = 0; j < n_ph_list2; j++)
{
if(current_phoneme_tab != tr->phoneme_tab_ix)
{
for (j = 0; j < n_ph_list2; j++) {
if (current_phoneme_tab != tr->phoneme_tab_ix) {
plist2[j].synthflags |= SFLAG_SWITCHED_LANG; plist2[j].synthflags |= SFLAG_SWITCHED_LANG;
} }


if(delete_count > 0)
{
if (delete_count > 0) {
memcpy(&plist2[j-delete_count], &plist2[j], sizeof(plist2[0])); memcpy(&plist2[j-delete_count], &plist2[j], sizeof(plist2[0]));
} }


if(plist2[j].phcode == phonSWITCH)
{
if((!(plist2[j].synthflags & SFLAG_EMBEDDED)) && (
(plist2[j].tone_ph == current_phoneme_tab) ||
(plist2[j+1].phcode == phonSWITCH) ||
((plist2[j+1].phcode == phonPAUSE) && (plist2[j+2].phcode == phonSWITCH))
))
{
if (plist2[j].phcode == phonSWITCH) {
if ((!(plist2[j].synthflags & SFLAG_EMBEDDED)) && (
(plist2[j].tone_ph == current_phoneme_tab) ||
(plist2[j+1].phcode == phonSWITCH) ||
((plist2[j+1].phcode == phonPAUSE) && (plist2[j+2].phcode == phonSWITCH))
)) {
// delete this phonSWITCH if it's switching to the current phoneme table, or // delete this phonSWITCH if it's switching to the current phoneme table, or
// delete this phonSWITCH if its followed by another phonSWITCH // delete this phonSWITCH if its followed by another phonSWITCH
delete_count++; delete_count++;
}
else
{
} else {
current_phoneme_tab = plist2[j].tone_ph; current_phoneme_tab = plist2[j].tone_ph;
} }
} }
} }
n_ph_list2 -= delete_count; n_ph_list2 -= delete_count;


if((regression = tr->langopts.param[LOPT_REGRESSIVE_VOICING]) != 0)
{
if ((regression = tr->langopts.param[LOPT_REGRESSIVE_VOICING]) != 0) {
// set consonant clusters to all voiced or all unvoiced // set consonant clusters to all voiced or all unvoiced
// Regressive // Regressive
int type; int type;
int stop_propagation = 0; int stop_propagation = 0;
voicing = 0; voicing = 0;


for(j=n_ph_list2-1; j>=0; j--)
{
for (j = n_ph_list2-1; j >= 0; j--) {
ph = phoneme_tab[plist2[j].phcode]; ph = phoneme_tab[plist2[j].phcode];
if(ph == NULL)
if (ph == NULL)
continue; continue;


if(plist2[j].synthflags & SFLAG_SWITCHED_LANG)
{
if (plist2[j].synthflags & SFLAG_SWITCHED_LANG) {
stop_propagation = 0; stop_propagation = 0;
voicing = 0; voicing = 0;
if(regression & 0x100)
if (regression & 0x100)
voicing = 1; // word-end devoicing voicing = 1; // word-end devoicing
continue; continue;
} }


type = ph->type; type = ph->type;


if(regression & 0x2)
{
if (regression & 0x2) {
// [v] amd [v;] don't cause regression, or [R^] // [v] amd [v;] don't cause regression, or [R^]
if(((ph->mnemonic & 0xff) == 'v') || ((ph->mnemonic & 0xff)== 'R'))
{
if (((ph->mnemonic & 0xff) == 'v') || ((ph->mnemonic & 0xff) == 'R')) {
stop_propagation = 1; stop_propagation = 1;
if(regression & 0x10)
if (regression & 0x10)
voicing = 0; voicing = 0;
} }
} }


if((type==phSTOP) || type==(phFRICATIVE))
{
if((voicing==0) && (regression & 0xf))
{
if ((type == phSTOP) || type == (phFRICATIVE)) {
if ((voicing == 0) && (regression & 0xf)) {
voicing = 1; voicing = 1;
}
else if((voicing==2) && (ph->end_type != 0)) // use end_type field for voicing_switch for consonants
{
} else if ((voicing == 2) && (ph->end_type != 0)) { // use end_type field for voicing_switch for consonants
plist2[j].phcode = ph->end_type; // change to voiced equivalent plist2[j].phcode = ph->end_type; // change to voiced equivalent
} }
}
else if((type==phVSTOP) || type==(phVFRICATIVE))
{
if((voicing==0) && (regression & 0xf))
{
} else if ((type == phVSTOP) || type == (phVFRICATIVE)) {
if ((voicing == 0) && (regression & 0xf)) {
voicing = 2; voicing = 2;
}
else if((voicing==1) && (ph->end_type != 0))
{
} else if ((voicing == 1) && (ph->end_type != 0)) {
plist2[j].phcode = ph->end_type; // change to unvoiced equivalent plist2[j].phcode = ph->end_type; // change to unvoiced equivalent
} }
}
else
{
if(regression & 0x8)
{
} else {
if (regression & 0x8) {
// LANG=Polish, propagate through liquids and nasals // LANG=Polish, propagate through liquids and nasals
if((type == phPAUSE) || (type == phVOWEL))
if ((type == phPAUSE) || (type == phVOWEL))
voicing = 0; voicing = 0;
}
else
{
} else {
voicing = 0; voicing = 0;
} }
} }
if(stop_propagation)
{
if (stop_propagation) {
voicing = 0; voicing = 0;
stop_propagation = 0; stop_propagation = 0;
} }


if(plist2[j].sourceix)
{
if(regression & 0x04)
{
if (plist2[j].sourceix) {
if (regression & 0x04) {
// stop propagation at a word boundary // stop propagation at a word boundary
voicing = 0; voicing = 0;
} }
if(regression & 0x100)
{
if (regression & 0x100) {
// devoice word-final consonants, unless propagating voiced // devoice word-final consonants, unless propagating voiced
if(voicing == 0)
{
if (voicing == 0) {
voicing = 1; voicing = 1;
} }
} }
} }
} }


n_ph_list3 = SubstitutePhonemes(tr,ph_list3) - 2;
n_ph_list3 = SubstitutePhonemes(tr, ph_list3) - 2;


for(j=0; (j < n_ph_list3) && (ix < N_PHONEME_LIST-3); )
{
if(ph_list3[j].sourceix)
{
for (j = 0; (j < n_ph_list3) && (ix < N_PHONEME_LIST-3);) {
if (ph_list3[j].sourceix) {
// start of a word // start of a word
int k; int k;
int nextw; int nextw;
word_stress = 0; word_stress = 0;


// find the highest stress level in this word // find the highest stress level in this word
for(nextw=j; nextw < n_ph_list3; )
{
if(ph_list3[nextw].stresslevel > word_stress)
for (nextw = j; nextw < n_ph_list3;) {
if (ph_list3[nextw].stresslevel > word_stress)
word_stress = ph_list3[nextw].stresslevel; word_stress = ph_list3[nextw].stresslevel;


nextw++; nextw++;
if(ph_list3[nextw].sourceix)
if (ph_list3[nextw].sourceix)
break; // start of the next word break; // start of the next word
} }
for(k=j; k<nextw; k++)
{
for (k = j; k < nextw; k++) {
ph_list3[k].wordstress = word_stress; ph_list3[k].wordstress = word_stress;
} }
j = nextw; j = nextw;
}
else
{
} else {
j++; j++;
} }
} }
ph_list3[0].ph = ph; ph_list3[0].ph = ph;
word_start = 1; word_start = 1;


for(j=0; insert_ph || ((j < n_ph_list3) && (ix < N_PHONEME_LIST-3)); j++)
{
for (j = 0; insert_ph || ((j < n_ph_list3) && (ix < N_PHONEME_LIST-3)); j++) {
plist3 = &ph_list3[j]; plist3 = &ph_list3[j];


inserted = 0; inserted = 0;
deleted = 0; deleted = 0;
if(insert_ph != 0)
{
if (insert_ph != 0) {
// we have a (linking) phoneme which we need to insert here // we have a (linking) phoneme which we need to insert here
next = phoneme_tab[plist3->phcode]; // this phoneme, i.e. after the insert next = phoneme_tab[plist3->phcode]; // this phoneme, i.e. after the insert


// That's OK because we don't look backwards from plist3 *** but CountVowelPosition() and isAfterStress does !!! // That's OK because we don't look backwards from plist3 *** but CountVowelPosition() and isAfterStress does !!!
j--; j--;
plist3 = plist3_inserted = &ph_list3[j]; plist3 = plist3_inserted = &ph_list3[j];
if(j > 0)
{
if (j > 0) {
// move all previous phonemes in the word back one place // move all previous phonemes in the word back one place
int k; int k;
if(word_start > 0)
{
if (word_start > 0) {
k = word_start; k = word_start;
word_start--; word_start--;
}
else
{
} else {
k = 2; // No more space, don't loose the start of word mark at ph_list2[word_start] k = 2; // No more space, don't loose the start of word mark at ph_list2[word_start]
} }
for(; k<=j; k++)
for (; k <= j; k++)
memcpy(&ph_list3[k-1], &ph_list3[k], sizeof(*plist3)); memcpy(&ph_list3[k-1], &ph_list3[k], sizeof(*plist3));
} }
memset(&plist3[0], 0, sizeof(*plist3)); memset(&plist3[0], 0, sizeof(*plist3));
plist3->ph = ph; plist3->ph = ph;
insert_ph = 0; insert_ph = 0;
inserted = 1; // don't insert the same phoneme repeatedly inserted = 1; // don't insert the same phoneme repeatedly
}
else
{
} else {
// otherwise get the next phoneme from the list // otherwise get the next phoneme from the list
if(plist3->sourceix != 0)
if (plist3->sourceix != 0)
word_start = j; word_start = j;


ph = phoneme_tab[plist3->phcode]; ph = phoneme_tab[plist3->phcode];
plist3[0].ph = ph; plist3[0].ph = ph;


if(plist3->phcode == phonSWITCH)
{
if (plist3->phcode == phonSWITCH) {
// change phoneme table // change phoneme table
SelectPhonemeTable(plist3->tone_ph); SelectPhonemeTable(plist3->tone_ph);
} }
plist3[1].ph = next; plist3[1].ph = next;
} }


if(ph == NULL) continue;
if (ph == NULL) continue;


InterpretPhoneme(tr, 0x100, plist3, &phdata, &worddata); InterpretPhoneme(tr, 0x100, plist3, &phdata, &worddata);


if((alternative = phdata.pd_param[pd_CHANGE_NEXTPHONEME]) > 0)
{
if ((alternative = phdata.pd_param[pd_CHANGE_NEXTPHONEME]) > 0) {
ph_list3[j+1].ph = phoneme_tab[alternative]; ph_list3[j+1].ph = phoneme_tab[alternative];
ph_list3[j+1].phcode = alternative; ph_list3[j+1].phcode = alternative;
ph_list3[j+1].type = phoneme_tab[alternative]->type; ph_list3[j+1].type = phoneme_tab[alternative]->type;
next = phoneme_tab[alternative]; next = phoneme_tab[alternative];
} }


if(((alternative = phdata.pd_param[pd_INSERTPHONEME]) > 0) && (inserted == 0))
{
if (((alternative = phdata.pd_param[pd_INSERTPHONEME]) > 0) && (inserted == 0)) {
// PROBLEM: if we insert a phoneme before a vowel then we loose the stress. // PROBLEM: if we insert a phoneme before a vowel then we loose the stress.
PHONEME_TAB *ph2; PHONEME_TAB *ph2;
ph2 = ph; ph2 = ph;
plist3->ph = ph; plist3->ph = ph;
plist3->phcode = alternative; plist3->phcode = alternative;


if(ph->type == phVOWEL)
{
if (ph->type == phVOWEL) {
plist3->synthflags |= SFLAG_SYLLABLE; plist3->synthflags |= SFLAG_SYLLABLE;
if(ph2->type != phVOWEL)
if (ph2->type != phVOWEL)
plist3->stresslevel = 0; // change from non-vowel to vowel, make sure it's unstressed plist3->stresslevel = 0; // change from non-vowel to vowel, make sure it's unstressed
}
else
} else
plist3->synthflags &= ~SFLAG_SYLLABLE; plist3->synthflags &= ~SFLAG_SYLLABLE;


// re-interpret the changed phoneme // re-interpret the changed phoneme
InterpretPhoneme(tr, 0x100, plist3, &phdata, &worddata); InterpretPhoneme(tr, 0x100, plist3, &phdata, &worddata);
} }


if((alternative = phdata.pd_param[pd_CHANGEPHONEME]) > 0)
{
if ((alternative = phdata.pd_param[pd_CHANGEPHONEME]) > 0) {
PHONEME_TAB *ph2; PHONEME_TAB *ph2;
ph2 = ph; ph2 = ph;
ph = phoneme_tab[alternative]; ph = phoneme_tab[alternative];
plist3->ph = ph; plist3->ph = ph;
plist3->phcode = alternative; plist3->phcode = alternative;


if(alternative == 1)
{
if (alternative == 1) {
deleted = 1; // NULL phoneme, discard deleted = 1; // NULL phoneme, discard
}
else
{
if(ph->type == phVOWEL)
{
} else {
if (ph->type == phVOWEL) {
plist3->synthflags |= SFLAG_SYLLABLE; plist3->synthflags |= SFLAG_SYLLABLE;
if(ph2->type != phVOWEL)
if (ph2->type != phVOWEL)
plist3->stresslevel = 0; // change from non-vowel to vowel, make sure it's unstressed plist3->stresslevel = 0; // change from non-vowel to vowel, make sure it's unstressed
}
else
} else
plist3->synthflags &= ~SFLAG_SYLLABLE; plist3->synthflags &= ~SFLAG_SYLLABLE;


// re-interpret the changed phoneme // re-interpret the changed phoneme
} }
} }


if((ph->type == phVOWEL) && (deleted == 0))
{
if ((ph->type == phVOWEL) && (deleted == 0)) {
PHONEME_LIST *p; PHONEME_LIST *p;


// Check for consecutive unstressed syllables, even across word boundaries. // Check for consecutive unstressed syllables, even across word boundaries.
// Do this after changing phonemes according to stress level. // Do this after changing phonemes according to stress level.
if(plist3->stresslevel <= 1)
{
if (plist3->stresslevel <= 1) {
// an unstressed vowel // an unstressed vowel
unstress_count++; unstress_count++;


if(tr->langopts.stress_flags & 0x08)
{
if (tr->langopts.stress_flags & 0x08) {
// change sequences of consecutive unstressed vowels in unstressed words to diminished stress (TEST) // change sequences of consecutive unstressed vowels in unstressed words to diminished stress (TEST)
for(p=plist3+1; p->type != phPAUSE; p++)
{
if(p->type == phVOWEL)
{
if(p->stresslevel <= 1)
{
if(plist3->wordstress < 4)
for (p = plist3+1; p->type != phPAUSE; p++) {
if (p->type == phVOWEL) {
if (p->stresslevel <= 1) {
if (plist3->wordstress < 4)
plist3->stresslevel = 0; plist3->stresslevel = 0;
if(p->wordstress < 4)
if (p->wordstress < 4)
p->stresslevel = 0; p->stresslevel = 0;
} }
break; break;
} }
} }
}
else
{
if((unstress_count > 1) && ((unstress_count & 1)==0))
{
} else {
if ((unstress_count > 1) && ((unstress_count & 1) == 0)) {
// in a sequence of unstressed syllables, reduce alternate syllables to 'diminished' // in a sequence of unstressed syllables, reduce alternate syllables to 'diminished'
// stress. But not for the last phoneme of a stressed word // stress. But not for the last phoneme of a stressed word
if((tr->langopts.stress_flags & S_NO_DIM) || ((word_stress > 3) && ((plist3+1)->sourceix!=0)))
{
if ((tr->langopts.stress_flags & S_NO_DIM) || ((word_stress > 3) && ((plist3+1)->sourceix != 0))) {
// An unstressed final vowel of a stressed word // An unstressed final vowel of a stressed word
unstress_count=1; // try again for next syllable
}
else
{
unstress_count = 1; // try again for next syllable
} else {
plist3->stresslevel = 0; // change stress to 'diminished' plist3->stresslevel = 0; // change stress to 'diminished'
} }
} }
} }
}
else
{
} else {
unstress_count = 0; unstress_count = 0;
} }
} }


if((plist3+1)->synthflags & SFLAG_LENGTHEN)
{
static char types_double[] = {phFRICATIVE,phVFRICATIVE,phNASAL,phLIQUID,0};
if((j > 0) && (strchr(types_double,next->type)))
{
if ((plist3+1)->synthflags & SFLAG_LENGTHEN) {
static char types_double[] = { phFRICATIVE, phVFRICATIVE, phNASAL, phLIQUID, 0 };
if ((j > 0) && (strchr(types_double, next->type))) {
// lengthen this consonant by doubling it // lengthen this consonant by doubling it
// BUT, can't insert a phoneme at position plist3[0] because it crashes PrevPh() // BUT, can't insert a phoneme at position plist3[0] because it crashes PrevPh()
insert_ph = next->code; insert_ph = next->code;
} }
} }


if((plist3+1)->sourceix != 0)
{
if ((plist3+1)->sourceix != 0) {
int x; int x;


if(tr->langopts.vowel_pause && (ph->type != phPAUSE))
{
if (tr->langopts.vowel_pause && (ph->type != phPAUSE)) {


if((ph->type != phVOWEL) && (tr->langopts.vowel_pause & 0x200))
{
if ((ph->type != phVOWEL) && (tr->langopts.vowel_pause & 0x200)) {
// add a pause after a word which ends in a consonant // add a pause after a word which ends in a consonant
insert_ph = phonPAUSE_NOLINK; insert_ph = phonPAUSE_NOLINK;
} }


if(next->type == phVOWEL)
{
if((x = tr->langopts.vowel_pause & 0x0c) != 0)
{
if (next->type == phVOWEL) {
if ((x = tr->langopts.vowel_pause & 0x0c) != 0) {
// break before a word which starts with a vowel // break before a word which starts with a vowel
if(x == 0xc)
if (x == 0xc)
insert_ph = phonPAUSE_NOLINK; insert_ph = phonPAUSE_NOLINK;
else else
insert_ph = phonPAUSE_VSHORT; insert_ph = phonPAUSE_VSHORT;
} }


if((ph->type == phVOWEL) && ((x = tr->langopts.vowel_pause & 0x03) != 0))
{
if ((ph->type == phVOWEL) && ((x = tr->langopts.vowel_pause & 0x03) != 0)) {
// adjacent vowels over a word boundary // adjacent vowels over a word boundary
if(x == 2)
if (x == 2)
insert_ph = phonPAUSE_SHORT; insert_ph = phonPAUSE_SHORT;
else else
insert_ph = phonPAUSE_VSHORT; insert_ph = phonPAUSE_VSHORT;
} }


if(((plist3+1)->stresslevel >= 4) && (tr->langopts.vowel_pause & 0x100))
{
if (((plist3+1)->stresslevel >= 4) && (tr->langopts.vowel_pause & 0x100)) {
// pause before a words which starts with a stressed vowel // pause before a words which starts with a stressed vowel
insert_ph = phonPAUSE_SHORT; insert_ph = phonPAUSE_SHORT;
} }
} }
} }


if((plist3 != plist3_inserted) && (ix > 0))
{
if((x = (tr->langopts.word_gap & 0x7)) != 0)
{
if((x > 1) || ((insert_ph != phonPAUSE_SHORT) && (insert_ph != phonPAUSE_NOLINK)))
{
if ((plist3 != plist3_inserted) && (ix > 0)) {
if ((x = (tr->langopts.word_gap & 0x7)) != 0) {
if ((x > 1) || ((insert_ph != phonPAUSE_SHORT) && (insert_ph != phonPAUSE_NOLINK))) {
// don't reduce the pause // don't reduce the pause
insert_ph = pause_phonemes[x]; insert_ph = pause_phonemes[x];
} }
} }
if(option_wordgap > 0)
{
if (option_wordgap > 0) {
insert_ph = phonPAUSE_LONG; insert_ph = phonPAUSE_LONG;
} }
} }
next2 = phoneme_tab[plist3[2].phcode]; next2 = phoneme_tab[plist3[2].phcode];
plist3[2].ph = next2; plist3[2].ph = next2;


if((insert_ph == 0) && (phdata.pd_param[pd_APPENDPHONEME] != 0))
{
if ((insert_ph == 0) && (phdata.pd_param[pd_APPENDPHONEME] != 0)) {
insert_ph = phdata.pd_param[pd_APPENDPHONEME]; insert_ph = phdata.pd_param[pd_APPENDPHONEME];
} }


if(deleted == 0)
{
if (deleted == 0) {
phlist[ix].ph = ph; phlist[ix].ph = ph;
phlist[ix].type = ph->type; phlist[ix].type = ph->type;
phlist[ix].env = PITCHfall; // default, can be changed in the "intonation" module phlist[ix].env = PITCHfall; // default, can be changed in the "intonation" module
phlist[ix].sourceix = 0; phlist[ix].sourceix = 0;
phlist[ix].phcode = ph->code; phlist[ix].phcode = ph->code;


if(plist3->sourceix != 0)
{
if (plist3->sourceix != 0) {
phlist[ix].sourceix = plist3->sourceix; phlist[ix].sourceix = plist3->sourceix;
phlist[ix].newword = 1; // this phoneme is the start of a word phlist[ix].newword = 1; // this phoneme is the start of a word


if(start_sentence)
{
if (start_sentence) {
phlist[ix].newword = 5; // start of sentence + start of word phlist[ix].newword = 5; // start of sentence + start of word
start_sentence = 0; start_sentence = 0;
} }
}
else
{
} else {
phlist[ix].newword = 0; phlist[ix].newword = 0;
} }


phlist[ix].length = phdata.pd_param[i_SET_LENGTH]*2; phlist[ix].length = phdata.pd_param[i_SET_LENGTH]*2;
if((ph->code == phonPAUSE_LONG) && (option_wordgap > 0) && (plist3[1].sourceix != 0))
{
if ((ph->code == phonPAUSE_LONG) && (option_wordgap > 0) && (plist3[1].sourceix != 0)) {
phlist[ix].ph = phoneme_tab[phonPAUSE_SHORT]; phlist[ix].ph = phoneme_tab[phonPAUSE_SHORT];
phlist[ix].length = option_wordgap*14; // 10mS per unit at the default speed phlist[ix].length = option_wordgap*14; // 10mS per unit at the default speed
} }


if(ph->type==phVOWEL || ph->type==phLIQUID || ph->type==phNASAL || ph->type==phVSTOP || ph->type==phVFRICATIVE || (ph->phflags & phPREVOICE))
{
if (ph->type == phVOWEL || ph->type == phLIQUID || ph->type == phNASAL || ph->type == phVSTOP || ph->type == phVFRICATIVE || (ph->phflags & phPREVOICE)) {
phlist[ix].length = 128; // length_mod phlist[ix].length = 128; // length_mod
phlist[ix].env = PITCHfall; phlist[ix].env = PITCHfall;
} }
phlist[ix].phcode = phonPAUSE; phlist[ix].phcode = phonPAUSE;
phlist[ix].type = phPAUSE; phlist[ix].type = phPAUSE;
phlist[ix].length = 0; phlist[ix].length = 0;
phlist[ix].sourceix=0;
phlist[ix].sourceix = 0;
phlist[ix].synthflags = 0; phlist[ix].synthflags = 0;
phlist[ix++].ph = phoneme_tab[phonPAUSE_SHORT]; phlist[ix++].ph = phoneme_tab[phonPAUSE_SHORT];



+ 878
- 1190
src/libespeak-ng/readclause.c
File diff suppressed because it is too large
View File


+ 165
- 284
src/libespeak-ng/setlengths.c View File



// speed_factor1 adjustments for speeds 350 to 374: pauses // speed_factor1 adjustments for speeds 350 to 374: pauses
static unsigned char pause_factor_350[] = { static unsigned char pause_factor_350[] = {
22,22,22,22,22,22,22,21,21,21, // 350
21,20,20,19,19,18,17,16,15,15, // 360
15,15,15,15,15
22, 22, 22, 22, 22, 22, 22, 21, 21, 21, // 350
21, 20, 20, 19, 19, 18, 17, 16, 15, 15, // 360
15, 15, 15, 15, 15
}; // 370 }; // 370


// wav_factor adjustments for speeds 350 to 450 // wav_factor adjustments for speeds 350 to 450
speed.min_pause = 5; speed.min_pause = 5;


wpm = embedded_value[EMBED_S]; wpm = embedded_value[EMBED_S];
if(control == 2)
if (control == 2)
wpm = embedded_value[EMBED_S2]; wpm = embedded_value[EMBED_S2];


wpm_value = wpm; wpm_value = wpm;


if(voice->speed_percent > 0)
{
if (voice->speed_percent > 0) {
wpm = (wpm * voice->speed_percent)/100; wpm = (wpm * voice->speed_percent)/100;
} }


if(control & 2)
{
if (control & 2) {
DoSonicSpeed(1 * 1024); DoSonicSpeed(1 * 1024);
} }
if((wpm_value >= 450) || ((wpm_value > speed.fast_settings[0]) && (wpm > 350)))
{
if ((wpm_value >= 450) || ((wpm_value > speed.fast_settings[0]) && (wpm > 350))) {
wpm2 = wpm; wpm2 = wpm;
wpm = 175; wpm = 175;


// set special eSpeak speed parameters for Sonic use // set special eSpeak speed parameters for Sonic use
// The eSpeak output will be speeded up by at least x2 // The eSpeak output will be speeded up by at least x2
x = 73; x = 73;
if(control & 1)
{
if (control & 1) {
speed1 = (x * voice->speedf1)/256; speed1 = (x * voice->speedf1)/256;
speed2 = (x * voice->speedf2)/256; speed2 = (x * voice->speedf2)/256;
speed3 = (x * voice->speedf3)/256; speed3 = (x * voice->speedf3)/256;
} }
if(control & 2)
{
if (control & 2) {
sonic = ((double)wpm2)/wpm; sonic = ((double)wpm2)/wpm;
DoSonicSpeed((int)(sonic * 1024)); DoSonicSpeed((int)(sonic * 1024));
speed.pause_factor = 85; speed.pause_factor = 85;
return; return;
} }


if(wpm > 450)
if (wpm > 450)
wpm = 450; wpm = 450;


if(wpm > 360)
{
if (wpm > 360) {
speed.loud_consonants = (wpm - 360) / 8; speed.loud_consonants = (wpm - 360) / 8;
} }


wpm2 = wpm; wpm2 = wpm;
if(wpm > 359) wpm2 = 359;
if(wpm < 80) wpm2 = 80;
if (wpm > 359) wpm2 = 359;
if (wpm < 80) wpm2 = 80;
x = speed_lookup[wpm2-80]; x = speed_lookup[wpm2-80];


if(wpm >= 380)
if (wpm >= 380)
x = 7; x = 7;
if(wpm >= 400)
if (wpm >= 400)
x = 6; x = 6;


if(control & 1)
{
if (control & 1) {
// set speed factors for different syllable positions within a word // set speed factors for different syllable positions within a word
// these are used in CalcLengths() // these are used in CalcLengths()
speed1 = (x * voice->speedf1)/256; speed1 = (x * voice->speedf1)/256;
speed2 = (x * voice->speedf2)/256; speed2 = (x * voice->speedf2)/256;
speed3 = (x * voice->speedf3)/256; speed3 = (x * voice->speedf3)/256;


if(x <= 7)
{
if (x <= 7) {
speed1 = x; speed1 = x;
speed2 = speed3 = x - 1; speed2 = speed3 = x - 1;
} }
} }


if(control & 2)
{
if (control & 2) {
// these are used in synthesis file // these are used in synthesis file


if(wpm > 350)
{
if (wpm > 350) {
speed.lenmod_factor = 85 - (wpm - 350) / 3; speed.lenmod_factor = 85 - (wpm - 350) / 3;
speed.lenmod2_factor = 60 - (wpm - 350) / 8; speed.lenmod2_factor = 60 - (wpm - 350) / 8;
}
else
if(wpm > 250)
{
} else if (wpm > 250) {
speed.lenmod_factor = 110 - (wpm - 250)/4; speed.lenmod_factor = 110 - (wpm - 250)/4;
speed.lenmod2_factor = 110 - (wpm - 250)/2; speed.lenmod2_factor = 110 - (wpm - 250)/2;
} }


s1 = (x * voice->speedf1)/256; s1 = (x * voice->speedf1)/256;


if(wpm >= 170)
if (wpm >= 170)
speed.wav_factor = 110 + (150*s1)/128; // reduced speed adjustment, used for playing recorded sounds speed.wav_factor = 110 + (150*s1)/128; // reduced speed adjustment, used for playing recorded sounds
else else
speed.wav_factor = 128 + (128*s1)/130; // = 215 at 170 wpm speed.wav_factor = 128 + (128*s1)/130; // = 215 at 170 wpm


if(wpm >= 350)
{
if (wpm >= 350) {
speed.wav_factor = wav_factor_350[wpm-350]; speed.wav_factor = wav_factor_350[wpm-350];
} }


if(wpm >= 390)
{
if (wpm >= 390) {
speed.min_sample_len = 450 - (wpm - 400)/2; speed.min_sample_len = 450 - (wpm - 400)/2;
if(wpm > 440)
if (wpm > 440)
speed.min_sample_len = 420 - (wpm - 440); speed.min_sample_len = 420 - (wpm - 440);
} }


speed.pause_factor = (256 * s1)/115; // full speed adjustment, used for pause length speed.pause_factor = (256 * s1)/115; // full speed adjustment, used for pause length
speed.clause_pause_factor = 0; speed.clause_pause_factor = 0;


if(wpm > 430)
{
if (wpm > 430) {
speed.pause_factor = 12; speed.pause_factor = 12;
}
else
if(wpm > 400)
{
} else if (wpm > 400) {
speed.pause_factor = 13; speed.pause_factor = 13;
}
else
if(wpm > 374)
{
} else if (wpm > 374) {
speed.pause_factor = 14; speed.pause_factor = 14;
}
else
if(wpm > 350)
{
} else if (wpm > 350) {
speed.pause_factor = pause_factor_350[wpm - 350]; speed.pause_factor = pause_factor_350[wpm - 350];
} }


if(speed.clause_pause_factor == 0)
{
if (speed.clause_pause_factor == 0) {
// restrict the reduction of pauses between clauses // restrict the reduction of pauses between clauses
if((speed.clause_pause_factor = speed.pause_factor) < 16)
if ((speed.clause_pause_factor = speed.pause_factor) < 16)
speed.clause_pause_factor = 16; speed.clause_pause_factor = 16;
} }
} }
speed.lenmod2_factor = 100; speed.lenmod2_factor = 100;


wpm = embedded_value[EMBED_S]; wpm = embedded_value[EMBED_S];
if(control == 2)
if (control == 2)
wpm = embedded_value[EMBED_S2]; wpm = embedded_value[EMBED_S2];


if(voice->speed_percent > 0)
{
if (voice->speed_percent > 0) {
wpm = (wpm * voice->speed_percent)/100; wpm = (wpm * voice->speed_percent)/100;
} }
if(wpm > 450)
if (wpm > 450)
wpm = 450; wpm = 450;


if(wpm > 360)
{
if (wpm > 360) {
speed.loud_consonants = (wpm - 360) / 8; speed.loud_consonants = (wpm - 360) / 8;
} }


wpm2 = wpm; wpm2 = wpm;
if(wpm > 359) wpm2 = 359;
if(wpm < 80) wpm2 = 80;
if (wpm > 359) wpm2 = 359;
if (wpm < 80) wpm2 = 80;
x = speed_lookup[wpm2-80]; x = speed_lookup[wpm2-80];


if(wpm >= 380)
if (wpm >= 380)
x = 7; x = 7;
if(wpm >= 400)
if (wpm >= 400)
x = 6; x = 6;


if(control & 1)
{
if (control & 1) {
// set speed factors for different syllable positions within a word // set speed factors for different syllable positions within a word
// these are used in CalcLengths() // these are used in CalcLengths()
speed1 = (x * voice->speedf1)/256; speed1 = (x * voice->speedf1)/256;
speed2 = (x * voice->speedf2)/256; speed2 = (x * voice->speedf2)/256;
speed3 = (x * voice->speedf3)/256; speed3 = (x * voice->speedf3)/256;


if(x <= 7)
{
if (x <= 7) {
speed1 = x; speed1 = x;
speed2 = speed3 = x - 1; speed2 = speed3 = x - 1;
} }
} }


if(control & 2)
{
if (control & 2) {
// these are used in synthesis file // these are used in synthesis file


if(wpm > 350)
{
if (wpm > 350) {
speed.lenmod_factor = 85 - (wpm - 350) / 3; speed.lenmod_factor = 85 - (wpm - 350) / 3;
speed.lenmod2_factor = 60 - (wpm - 350) / 8; speed.lenmod2_factor = 60 - (wpm - 350) / 8;
}
else
if(wpm > 250)
{
} else if (wpm > 250) {
speed.lenmod_factor = 110 - (wpm - 250)/4; speed.lenmod_factor = 110 - (wpm - 250)/4;
speed.lenmod2_factor = 110 - (wpm - 250)/2; speed.lenmod2_factor = 110 - (wpm - 250)/2;
} }


s1 = (x * voice->speedf1)/256; s1 = (x * voice->speedf1)/256;


if(wpm >= 170)
if (wpm >= 170)
speed.wav_factor = 110 + (150*s1)/128; // reduced speed adjustment, used for playing recorded sounds speed.wav_factor = 110 + (150*s1)/128; // reduced speed adjustment, used for playing recorded sounds
else else
speed.wav_factor = 128 + (128*s1)/130; // = 215 at 170 wpm speed.wav_factor = 128 + (128*s1)/130; // = 215 at 170 wpm


if(wpm >= 350)
{
if (wpm >= 350) {
speed.wav_factor = wav_factor_350[wpm-350]; speed.wav_factor = wav_factor_350[wpm-350];
} }


if(wpm >= 390)
{
if (wpm >= 390) {
speed.min_sample_len = 450 - (wpm - 400)/2; speed.min_sample_len = 450 - (wpm - 400)/2;
if(wpm > 440)
if (wpm > 440)
speed.min_sample_len = 420 - (wpm - 440); speed.min_sample_len = 420 - (wpm - 440);
} }


speed.pause_factor = (256 * s1)/115; // full speed adjustment, used for pause length speed.pause_factor = (256 * s1)/115; // full speed adjustment, used for pause length
speed.clause_pause_factor = 0; speed.clause_pause_factor = 0;


if(wpm > 430)
{
if (wpm > 430) {
speed.pause_factor = 12; speed.pause_factor = 12;
}
else
if(wpm > 400)
{
} else if (wpm > 400) {
speed.pause_factor = 13; speed.pause_factor = 13;
}
else
if(wpm > 374)
{
} else if (wpm > 374) {
speed.pause_factor = 14; speed.pause_factor = 14;
}
else
if(wpm > 350)
{
} else if (wpm > 350) {
speed.pause_factor = pause_factor_350[wpm - 350]; speed.pause_factor = pause_factor_350[wpm - 350];
} }


if(speed.clause_pause_factor == 0)
{
if (speed.clause_pause_factor == 0) {
// restrict the reduction of pauses between clauses // restrict the reduction of pauses between clauses
if((speed.clause_pause_factor = speed.pause_factor) < 16)
if ((speed.clause_pause_factor = speed.pause_factor) < 16)
speed.clause_pause_factor = 16; speed.clause_pause_factor = 16;
} }
} }
int new_value = value; int new_value = value;
int default_value; int default_value;


if(relative)
{
if(parameter < 5)
{
if (relative) {
if (parameter < 5) {
default_value = param_defaults[parameter]; default_value = param_defaults[parameter];
new_value = default_value + (default_value * value)/100; new_value = default_value + (default_value * value)/100;
} }
param_stack[0].parameter[parameter] = new_value; param_stack[0].parameter[parameter] = new_value;
saved_parameters[parameter] = new_value; saved_parameters[parameter] = new_value;


switch(parameter)
switch (parameter)
{ {
case espeakRATE: case espeakRATE:
embedded_value[EMBED_S] = new_value; embedded_value[EMBED_S] = new_value;
break; break;


case espeakPITCH: case espeakPITCH:
if(new_value > 99) new_value = 99;
if(new_value < 0) new_value = 0;
if (new_value > 99) new_value = 99;
if (new_value < 0) new_value = 0;
embedded_value[EMBED_P] = new_value; embedded_value[EMBED_P] = new_value;
break; break;


case espeakRANGE: case espeakRANGE:
if(new_value > 99) new_value = 99;
if (new_value > 99) new_value = 99;
embedded_value[EMBED_R] = new_value; embedded_value[EMBED_R] = new_value;
break; break;


break; break;


case espeakINTONATION: case espeakINTONATION:
if((new_value & 0xff) != 0)
if ((new_value & 0xff) != 0)
translator->langopts.intonation_group = new_value & 0xff; translator->langopts.intonation_group = new_value & 0xff;
option_tone_flags = new_value; option_tone_flags = new_value;
break; break;
do { do {
word = embedded_list[(*embix)++]; word = embedded_list[(*embix)++];


if((word & 0x1f) == EMBED_S)
{
if ((word & 0x1f) == EMBED_S) {
// speed // speed
SetEmbedded(word & 0x7f, word >> 8); // adjusts embedded_value[EMBED_S] SetEmbedded(word & 0x7f, word >> 8); // adjusts embedded_value[EMBED_S]
SetSpeed(1); SetSpeed(1);
} }
} while((word & 0x80) == 0);
} while ((word & 0x80) == 0);
} }






int stress; int stress;
int type; int type;
static int more_syllables=0;
int pre_sonorant=0;
int pre_voiced=0;
static int more_syllables = 0;
int pre_sonorant = 0;
int pre_voiced = 0;
int last_pitch = 0; int last_pitch = 0;
int pitch_start; int pitch_start;
int length_mod; int length_mod;
int pitch1; int pitch1;
int emphasized; int emphasized;
int tone_mod; int tone_mod;
unsigned char *pitch_env=NULL;
unsigned char *pitch_env = NULL;
PHONEME_DATA phdata_tone; PHONEME_DATA phdata_tone;


for(ix=1; ix<n_phoneme_list; ix++)
{
for (ix = 1; ix < n_phoneme_list; ix++) {
prev = &phoneme_list[ix-1]; prev = &phoneme_list[ix-1];
p = &phoneme_list[ix]; p = &phoneme_list[ix];
stress = p->stresslevel & 0x7; stress = p->stresslevel & 0x7;


next = &phoneme_list[ix+1]; next = &phoneme_list[ix+1];


if(p->synthflags & SFLAG_EMBEDDED)
{
if (p->synthflags & SFLAG_EMBEDDED) {
DoEmbedded2(&embedded_ix); DoEmbedded2(&embedded_ix);
} }


type = p->type; type = p->type;
if(p->synthflags & SFLAG_SYLLABLE)
if (p->synthflags & SFLAG_SYLLABLE)
type = phVOWEL; type = phVOWEL;


switch(type)
switch (type)
{ {
case phPAUSE: case phPAUSE:
last_pitch = 0; last_pitch = 0;


case phSTOP: case phSTOP:
last_pitch = 0; last_pitch = 0;
if(prev->type == phFRICATIVE)
if (prev->type == phFRICATIVE)
p->prepause = 25; p->prepause = 25;
else
if((more_syllables > 0) || (stress < 4))
else if ((more_syllables > 0) || (stress < 4))
p->prepause = 48; p->prepause = 48;
else else
p->prepause = 60; p->prepause = 60;


if(prev->type == phSTOP)
if (prev->type == phSTOP)
p->prepause = 60; p->prepause = 60;


if((tr->langopts.word_gap & 0x10) && (p->newword))
if ((tr->langopts.word_gap & 0x10) && (p->newword))
p->prepause = 60; p->prepause = 60;


if(p->ph->phflags & phLENGTHENSTOP)
if (p->ph->phflags & phLENGTHENSTOP)
p->prepause += 30; p->prepause += 30;


if(p->synthflags & SFLAG_LENGTHEN)
if (p->synthflags & SFLAG_LENGTHEN)
p->prepause += tr->langopts.long_stop; p->prepause += tr->langopts.long_stop;
break; break;


case phVFRICATIVE: case phVFRICATIVE:
case phFRICATIVE: case phFRICATIVE:
if(p->newword)
{
if((prev->type == phVOWEL) && (p->ph->phflags & phNOPAUSE))
{
}
else
{
if (p->newword) {
if ((prev->type == phVOWEL) && (p->ph->phflags & phNOPAUSE)) {
} else {
p->prepause = 15; p->prepause = 15;
} }
} }


if(next->type==phPAUSE && prev->type==phNASAL && !(p->ph->phflags&phFORTIS))
if (next->type == phPAUSE && prev->type == phNASAL && !(p->ph->phflags&phFORTIS))
p->prepause = 25; p->prepause = 25;


if(prev->ph->phflags & phBRKAFTER)
if (prev->ph->phflags & phBRKAFTER)
p->prepause = 30; p->prepause = 30;


if((tr->langopts.word_gap & 0x10) && (p->newword))
if ((tr->langopts.word_gap & 0x10) && (p->newword))
p->prepause = 30; p->prepause = 30;


if((p->ph->phflags & phSIBILANT) && next->type==phSTOP && !next->newword)
{
if(prev->type == phVOWEL)
if ((p->ph->phflags & phSIBILANT) && next->type == phSTOP && !next->newword) {
if (prev->type == phVOWEL)
p->length = 200; // ?? should do this if it's from a prefix p->length = 200; // ?? should do this if it's from a prefix
else else
p->length = 150; p->length = 150;
}
else
} else
p->length = 256; p->length = 256;


if(type == phVFRICATIVE)
{
if(next->type==phVOWEL)
{
if (type == phVFRICATIVE) {
if (next->type == phVOWEL) {
pre_voiced = 1; pre_voiced = 1;
} }
if((prev->type==phVOWEL) || (prev->type == phLIQUID))
{
if ((prev->type == phVOWEL) || (prev->type == phLIQUID)) {
p->length = (255 + prev->length)/2; p->length = (255 + prev->length)/2;
} }
} }
break; break;


case phVSTOP: case phVSTOP:
if(prev->type==phVFRICATIVE || prev->type==phFRICATIVE || (prev->ph->phflags & phSIBILANT) || (prev->type == phLIQUID))
if (prev->type == phVFRICATIVE || prev->type == phFRICATIVE || (prev->ph->phflags & phSIBILANT) || (prev->type == phLIQUID))
p->prepause = 30; p->prepause = 30;


if(next->type==phVOWEL || next->type==phLIQUID)
{
if((next->type==phVOWEL) || !next->newword)
if (next->type == phVOWEL || next->type == phLIQUID) {
if ((next->type == phVOWEL) || !next->newword)
pre_voiced = 1; pre_voiced = 1;


p->prepause = 40; p->prepause = 40;


if(prev->type == phVOWEL)
{
if (prev->type == phVOWEL) {
p->prepause = 0; // use murmur instead to link from the preceding vowel p->prepause = 0; // use murmur instead to link from the preceding vowel
}
else
if(prev->type == phPAUSE)
{
} else if (prev->type == phPAUSE) {
// reduce by the length of the preceding pause // reduce by the length of the preceding pause
if(prev->length < p->prepause)
if (prev->length < p->prepause)
p->prepause -= prev->length; p->prepause -= prev->length;
else else
p->prepause = 0; p->prepause = 0;
}
else
if(p->newword==0)
{
if(prev->type==phLIQUID)
} else if (p->newword == 0) {
if (prev->type == phLIQUID)
p->prepause = 20; p->prepause = 20;
if(prev->type==phNASAL)
if (prev->type == phNASAL)
p->prepause = 12; p->prepause = 12;


if(prev->type==phSTOP && !(prev->ph->phflags & phFORTIS))
if (prev->type == phSTOP && !(prev->ph->phflags & phFORTIS))
p->prepause = 0; p->prepause = 0;
} }
} }
if((tr->langopts.word_gap & 0x10) && (p->newword) && (p->prepause < 20))
if ((tr->langopts.word_gap & 0x10) && (p->newword) && (p->prepause < 20))
p->prepause = 20; p->prepause = 20;


break; break;
p->length = 256; // TEMPORARY p->length = 256; // TEMPORARY
min_drop = 0; min_drop = 0;


if(p->newword)
{
if(prev->type==phLIQUID)
if (p->newword) {
if (prev->type == phLIQUID)
p->prepause = 25; p->prepause = 25;
if(prev->type==phVOWEL)
{
if(!(p->ph->phflags & phNOPAUSE))
if (prev->type == phVOWEL) {
if (!(p->ph->phflags & phNOPAUSE))
p->prepause = 12; p->prepause = 12;
} }
} }


if(next->type==phVOWEL)
{
if (next->type == phVOWEL) {
pre_sonorant = 1; pre_sonorant = 1;
}
else
{
} else {
p->pitch2 = last_pitch; p->pitch2 = last_pitch;


if((prev->type==phVOWEL) || (prev->type == phLIQUID))
{
if ((prev->type == phVOWEL) || (prev->type == phLIQUID)) {
p->length = prev->length; p->length = prev->length;


if(p->type == phLIQUID)
{
if (p->type == phLIQUID) {
p->length = speed1; p->length = speed1;
} }


if(next->type == phVSTOP)
{
if (next->type == phVSTOP) {
p->length = (p->length * 160)/100; p->length = (p->length * 160)/100;
} }
if(next->type == phVFRICATIVE)
{
if (next->type == phVFRICATIVE) {
p->length = (p->length * 120)/100; p->length = (p->length * 120)/100;
} }
}
else
{
for(ix2=ix; ix2<n_phoneme_list; ix2++)
{
if(phoneme_list[ix2].type == phVOWEL)
{
} else {
for (ix2 = ix; ix2 < n_phoneme_list; ix2++) {
if (phoneme_list[ix2].type == phVOWEL) {
p->pitch2 = phoneme_list[ix2].pitch2; p->pitch2 = phoneme_list[ix2].pitch2;
break; break;
} }
} }


p->pitch1 = p->pitch2-16; p->pitch1 = p->pitch2-16;
if(p->pitch2 < 16)
{
if (p->pitch2 < 16) {
p->pitch1 = 0; p->pitch1 = 0;
} }
p->env = PITCHfall; p->env = PITCHfall;
next2 = &phoneme_list[ix+2]; next2 = &phoneme_list[ix+2];
next3 = &phoneme_list[ix+3]; next3 = &phoneme_list[ix+3];


if(stress > 7) stress = 7;
if (stress > 7) stress = 7;


if(stress <= 1)
{
if (stress <= 1) {
stress = stress ^ 1; // swap diminished and unstressed (until we swap stress_amps,stress_lengths in tr_languages) stress = stress ^ 1; // swap diminished and unstressed (until we swap stress_amps,stress_lengths in tr_languages)
} }
if(pre_sonorant)
if (pre_sonorant)
p->amp = tr->stress_amps[stress]-1; p->amp = tr->stress_amps[stress]-1;
else else
p->amp = tr->stress_amps[stress]; p->amp = tr->stress_amps[stress];


if(emphasized)
if (emphasized)
p->amp = 25; p->amp = 25;


if(ix >= (n_phoneme_list-3))
{
if (ix >= (n_phoneme_list-3)) {
// last phoneme of a clause, limit its amplitude // last phoneme of a clause, limit its amplitude
if(p->amp > tr->langopts.param[LOPT_MAXAMP_EOC])
if (p->amp > tr->langopts.param[LOPT_MAXAMP_EOC])
p->amp = tr->langopts.param[LOPT_MAXAMP_EOC]; p->amp = tr->langopts.param[LOPT_MAXAMP_EOC];
} }


// is the last syllable of a word ? // is the last syllable of a word ?
more_syllables=0;
more_syllables = 0;
end_of_clause = 0; end_of_clause = 0;
for(p2 = p+1; p2->newword== 0; p2++)
{
if((p2->type == phVOWEL) && !(p2->ph->phflags & phNONSYLLABIC))
for (p2 = p+1; p2->newword == 0; p2++) {
if ((p2->type == phVOWEL) && !(p2->ph->phflags & phNONSYLLABIC))
more_syllables++; more_syllables++;


if(p2->ph->code == phonPAUSE_CLAUSE)
if (p2->ph->code == phonPAUSE_CLAUSE)
end_of_clause = 2; end_of_clause = 2;
} }
if(p2->ph->code == phonPAUSE_CLAUSE)
if (p2->ph->code == phonPAUSE_CLAUSE)
end_of_clause = 2; end_of_clause = 2;


if((p2->newword & 2) && (more_syllables==0))
{
if ((p2->newword & 2) && (more_syllables == 0)) {
end_of_clause = 2; end_of_clause = 2;
} }


// calc length modifier // calc length modifier
if((next->ph->code == phonPAUSE_VSHORT) && (next2->type == phPAUSE))
{
if ((next->ph->code == phonPAUSE_VSHORT) && (next2->type == phPAUSE)) {
// if PAUSE_VSHORT is followed by a pause, then use that // if PAUSE_VSHORT is followed by a pause, then use that
next = next2; next = next2;
next2 = next3; next2 = next3;
} }


next2type = next2->ph->length_mod; next2type = next2->ph->length_mod;
if(more_syllables==0)
{
if(next->newword || next2->newword)
{
if (more_syllables == 0) {
if (next->newword || next2->newword) {
// don't use 2nd phoneme over a word boundary, unless it's a pause // don't use 2nd phoneme over a word boundary, unless it's a pause
if(next2type != 1)
if (next2type != 1)
next2type = 0; next2type = 0;
} }


len = tr->langopts.length_mods0[next2type *10+ next->ph->length_mod]; len = tr->langopts.length_mods0[next2type *10+ next->ph->length_mod];


if((next->newword) && (tr->langopts.word_gap & 0x20))
{
if ((next->newword) && (tr->langopts.word_gap & 0x20)) {
// consider as a pause + first phoneme of the next word // consider as a pause + first phoneme of the next word
length_mod = (len + tr->langopts.length_mods0[next->ph->length_mod *10+ 1])/2; length_mod = (len + tr->langopts.length_mods0[next->ph->length_mod *10+ 1])/2;
}
else
} else
length_mod = len; length_mod = len;
}
else
{
} else {
length_mod = tr->langopts.length_mods[next2type *10+ next->ph->length_mod]; length_mod = tr->langopts.length_mods[next2type *10+ next->ph->length_mod];


if((next->type == phNASAL) && (next2->type == phSTOP || next2->type == phVSTOP) && (next3->ph->phflags & phFORTIS))
if ((next->type == phNASAL) && (next2->type == phSTOP || next2->type == phVSTOP) && (next3->ph->phflags & phFORTIS))
length_mod -= 15; length_mod -= 15;
} }


if(more_syllables==0)
if (more_syllables == 0)
length_mod *= speed1; length_mod *= speed1;
else
if(more_syllables==1)
else if (more_syllables == 1)
length_mod *= speed2; length_mod *= speed2;
else else
length_mod *= speed3; length_mod *= speed3;


length_mod = length_mod / 128; length_mod = length_mod / 128;


if(length_mod < 8)
if (length_mod < 8)
length_mod = 8; // restrict how much lengths can be reduced length_mod = 8; // restrict how much lengths can be reduced


if(stress >= 7)
{
if (stress >= 7) {
// tonic syllable, include a constant component so it doesn't decrease directly with speed // tonic syllable, include a constant component so it doesn't decrease directly with speed
length_mod += tr->langopts.lengthen_tonic; length_mod += tr->langopts.lengthen_tonic;
if(emphasized)
if (emphasized)
length_mod += (tr->langopts.lengthen_tonic/2); length_mod += (tr->langopts.lengthen_tonic/2);
}
else
if(emphasized)
{
} else if (emphasized) {
length_mod += tr->langopts.lengthen_tonic; length_mod += tr->langopts.lengthen_tonic;
} }


if((len = tr->stress_lengths[stress]) == 0)
if ((len = tr->stress_lengths[stress]) == 0)
len = tr->stress_lengths[6]; len = tr->stress_lengths[6];


length_mod = length_mod * len; length_mod = length_mod * len;


if(p->tone_ph != 0)
{
if((tone_mod = phoneme_tab[p->tone_ph]->std_length) > 0)
{
if (p->tone_ph != 0) {
if ((tone_mod = phoneme_tab[p->tone_ph]->std_length) > 0) {
// a tone phoneme specifies a percentage change to the length // a tone phoneme specifies a percentage change to the length
length_mod = (length_mod * tone_mod) / 100; length_mod = (length_mod * tone_mod) / 100;
} }
} }




if((end_of_clause == 2) && !(tr->langopts.stress_flags & S_NO_EOC_LENGTHEN))
{
if ((end_of_clause == 2) && !(tr->langopts.stress_flags & S_NO_EOC_LENGTHEN)) {
// this is the last syllable in the clause, lengthen it - more for short vowels // this is the last syllable in the clause, lengthen it - more for short vowels
len = (p->ph->std_length * 2); len = (p->ph->std_length * 2);
if(tr->langopts.stress_flags & S_EO_CLAUSE1)
len=200; // don't lengthen short vowels more than long vowels at end-of-clause
if (tr->langopts.stress_flags & S_EO_CLAUSE1)
len = 200; // don't lengthen short vowels more than long vowels at end-of-clause
length_mod = length_mod * (256 + (280 - len)/3)/256; length_mod = length_mod * (256 + (280 - len)/3)/256;
} }


if(length_mod > tr->langopts.max_lengthmod*speed1)
{
//limit the vowel length adjustment for some languages
if (length_mod > tr->langopts.max_lengthmod*speed1) {
// limit the vowel length adjustment for some languages
length_mod = (tr->langopts.max_lengthmod*speed1); length_mod = (tr->langopts.max_lengthmod*speed1);
} }


length_mod = length_mod / 128; length_mod = length_mod / 128;


if(p->type != phVOWEL)
{
if (p->type != phVOWEL) {
length_mod = 256; // syllabic consonant length_mod = 256; // syllabic consonant
min_drop = 16; min_drop = 16;
} }
p->length = length_mod; p->length = length_mod;


if(p->env >= (N_ENVELOPE_DATA-1))
{
fprintf(stderr,"espeak: Bad intonation data\n");
if (p->env >= (N_ENVELOPE_DATA-1)) {
fprintf(stderr, "espeak: Bad intonation data\n");
p->env = 0; p->env = 0;
} }


// set last-pitch // set last-pitch
env2 = p->env + 1; // version for use with preceding semi-vowel env2 = p->env + 1; // version for use with preceding semi-vowel


if(p->tone_ph != 0)
{
if (p->tone_ph != 0) {
InterpretPhoneme2(p->tone_ph, &phdata_tone); InterpretPhoneme2(p->tone_ph, &phdata_tone);
pitch_env = GetEnvelope(phdata_tone.pitch_env); pitch_env = GetEnvelope(phdata_tone.pitch_env);
}
else
{
} else {
pitch_env = envelope_data[env2]; pitch_env = envelope_data[env2];
} }


pitch_start = p->pitch1 + ((p->pitch2-p->pitch1)*pitch_env[0])/256; pitch_start = p->pitch1 + ((p->pitch2-p->pitch1)*pitch_env[0])/256;


if(pre_sonorant || pre_voiced)
{
if (pre_sonorant || pre_voiced) {
// set pitch for pre-vocalic part // set pitch for pre-vocalic part
if(pitch_start == 255)
if (pitch_start == 255)
last_pitch = pitch_start; // pitch is not set last_pitch = pitch_start; // pitch is not set


if(pitch_start - last_pitch > 16)
if (pitch_start - last_pitch > 16)
last_pitch = pitch_start - 16; last_pitch = pitch_start - 16;


prev->pitch1 = last_pitch; prev->pitch1 = last_pitch;
prev->pitch2 = pitch_start; prev->pitch2 = pitch_start;
if(last_pitch < pitch_start)
{
if (last_pitch < pitch_start) {
prev->env = PITCHrise; prev->env = PITCHrise;
p->env = env2; p->env = env2;
}
else
{
} else {
prev->env = PITCHfall; prev->env = PITCHfall;
} }


prev->length = length_mod; prev->length = length_mod;


prev->amp = p->amp; prev->amp = p->amp;
if((prev->type != phLIQUID) && (prev->amp > 18))
if ((prev->type != phLIQUID) && (prev->amp > 18))
prev->amp = 18; prev->amp = 18;
} }


// vowel & post-vocalic part // vowel & post-vocalic part
next->synthflags &= ~SFLAG_SEQCONTINUE; next->synthflags &= ~SFLAG_SEQCONTINUE;
if(next->type == phNASAL && next2->type != phVOWEL)
if (next->type == phNASAL && next2->type != phVOWEL)
next->synthflags |= SFLAG_SEQCONTINUE; next->synthflags |= SFLAG_SEQCONTINUE;


if(next->type == phLIQUID)
{
if (next->type == phLIQUID) {
next->synthflags |= SFLAG_SEQCONTINUE; next->synthflags |= SFLAG_SEQCONTINUE;


if(next2->type == phVOWEL)
{
if (next2->type == phVOWEL) {
next->synthflags &= ~SFLAG_SEQCONTINUE; next->synthflags &= ~SFLAG_SEQCONTINUE;
} }


if(next2->type != phVOWEL)
{
if(next->ph->mnemonic == ('/'*256+'r'))
{
if (next2->type != phVOWEL) {
if (next->ph->mnemonic == ('/'*256+'r')) {
next->synthflags &= ~SFLAG_SEQCONTINUE; next->synthflags &= ~SFLAG_SEQCONTINUE;
} }
} }
} }


if((min_drop > 0) && ((p->pitch2 - p->pitch1) < min_drop))
{
if ((min_drop > 0) && ((p->pitch2 - p->pitch1) < min_drop)) {
pitch1 = p->pitch2 - min_drop; pitch1 = p->pitch2 - min_drop;
if(pitch1 < 0)
if (pitch1 < 0)
pitch1 = 0; pitch1 = 0;
p->pitch1 = pitch1; p->pitch1 = pitch1;
} }

+ 221
- 308
src/libespeak-ng/speak_lib.c
File diff suppressed because it is too large
View File


+ 106
- 139
src/libespeak-ng/spect.c View File

#define PEAKSHAPEW 256 #define PEAKSHAPEW 256


static int default_freq[N_PEAKS] = static int default_freq[N_PEAKS] =
{200,500,1200,3000,3500,4000,6900,7800,9000};
{ 200, 500, 1200, 3000, 3500, 4000, 6900, 7800, 9000 };
static int default_width[N_PEAKS] = static int default_width[N_PEAKS] =
{750,500,550,550,600,700,700,700,700};
{ 750, 500, 550, 550, 600, 700, 700, 700, 700 };
static int default_klt_bw[N_PEAKS] = static int default_klt_bw[N_PEAKS] =
{89,90,140,260,260,260,500,500,500};
{ 89, 90, 140, 260, 260, 260, 500, 500, 500 };


static double read_double(FILE *stream) static double read_double(FILE *stream)
{ {
unsigned char bytes[10]; unsigned char bytes[10];
fread(bytes,sizeof(char),10,stream);
fread(bytes, sizeof(char), 10, stream);
return ConvertFromIeeeExtended(bytes); return ConvertFromIeeeExtended(bytes);
} }


float polint(float xa[],float ya[],int n,float x)
float polint(float xa[], float ya[], int n, float x)
{ {
// General polinomial interpolation routine, xa[1...n] ya[1...n] // General polinomial interpolation routine, xa[1...n] ya[1...n]
int i,m,ns=1;
float den,dif,dift,ho,hp,w;
int i, m, ns = 1;
float den, dif, dift, ho, hp, w;
float y; // result float y; // result
float c[9],d[9];
float c[9], d[9];


dif=fabs(x-xa[1]);
dif = fabs(x-xa[1]);


for(i=1; i<=n; i++) {
if((dift=fabs(x-xa[i])) < dif) {
ns=i;
dif=dift;
for (i = 1; i <= n; i++) {
if ((dift = fabs(x-xa[i])) < dif) {
ns = i;
dif = dift;
} }
c[i]=ya[i];
d[i]=ya[i];
c[i] = ya[i];
d[i] = ya[i];
} }
y=ya[ns--];
for(m=1; m<n; m++) {
for(i=1; i<=n-m; i++) {
ho=xa[i]-x;
hp=xa[i+m]-x;
w=c[i+1]-d[i];
if((den=ho-hp) == 0.0)
{
return(ya[2]); // two input xa are identical
y = ya[ns--];
for (m = 1; m < n; m++) {
for (i = 1; i <= n-m; i++) {
ho = xa[i]-x;
hp = xa[i+m]-x;
w = c[i+1]-d[i];
if ((den = ho-hp) == 0.0) {
return ya[2]; // two input xa are identical
} }
den=w/den;
d[i]=hp*den;
c[i]=ho*den;
den = w/den;
d[i] = hp*den;
c[i] = ho*den;
} }
y += ((2*ns < (n-m) ? c[ns+1] : d[ns--])); y += ((2*ns < (n-m) ? c[ns+1] : d[ns--]));
} }
return(y);
return y;
} }




frame->amp_adjust = 100; frame->amp_adjust = 100;
frame->length_adjust = 0; frame->length_adjust = 0;


for(ix=0; ix<N_PEAKS; ix++)
{
for (ix = 0; ix < N_PEAKS; ix++) {
frame->formants[ix].freq = 0; frame->formants[ix].freq = 0;
frame->peaks[ix].pkfreq = default_freq[ix]; frame->peaks[ix].pkfreq = default_freq[ix];
frame->peaks[ix].pkheight = 0; frame->peaks[ix].pkheight = 0;


static void SpectFrameDestroy(SpectFrame *frame) static void SpectFrameDestroy(SpectFrame *frame)
{ {
if(frame->spect != NULL)
if (frame->spect != NULL)
free(frame->spect); free(frame->spect);
free(frame); free(frame);
} }
frame->pitch = read_double(stream); frame->pitch = read_double(stream);
frame->length = read_double(stream); frame->length = read_double(stream);
frame->dx = read_double(stream); frame->dx = read_double(stream);
fread(&frame->nx,sizeof(short),1,stream);
fread(&frame->markers,sizeof(short),1,stream);
fread(&frame->amp_adjust,sizeof(short),1,stream);

if(file_format_type == 2)
{
fread(&ix,sizeof(short),1,stream); // spare
fread(&ix,sizeof(short),1,stream); // spare
fread(&frame->nx, sizeof(short), 1, stream);
fread(&frame->markers, sizeof(short), 1, stream);
fread(&frame->amp_adjust, sizeof(short), 1, stream);

if (file_format_type == 2) {
fread(&ix, sizeof(short), 1, stream); // spare
fread(&ix, sizeof(short), 1, stream); // spare
} }


for(ix=0; ix<N_PEAKS; ix++)
{
fread(&frame->formants[ix].freq,sizeof(short),1,stream);
fread(&frame->formants[ix].bandw,sizeof(short),1,stream);
fread(&frame->peaks[ix].pkfreq,sizeof(short),1,stream);
fread(&frame->peaks[ix].pkheight,sizeof(short),1,stream);
fread(&frame->peaks[ix].pkwidth,sizeof(short),1,stream);
fread(&frame->peaks[ix].pkright,sizeof(short),1,stream);
if(frame->peaks[ix].pkheight > 0)
for (ix = 0; ix < N_PEAKS; ix++) {
fread(&frame->formants[ix].freq, sizeof(short), 1, stream);
fread(&frame->formants[ix].bandw, sizeof(short), 1, stream);
fread(&frame->peaks[ix].pkfreq, sizeof(short), 1, stream);
fread(&frame->peaks[ix].pkheight, sizeof(short), 1, stream);
fread(&frame->peaks[ix].pkwidth, sizeof(short), 1, stream);
fread(&frame->peaks[ix].pkright, sizeof(short), 1, stream);
if (frame->peaks[ix].pkheight > 0)
frame->keyframe = 1; frame->keyframe = 1;


if(file_format_type == 2)
{
fread(&frame->peaks[ix].klt_bw,sizeof(short),1,stream);
fread(&frame->peaks[ix].klt_ap,sizeof(short),1,stream);
fread(&frame->peaks[ix].klt_bp,sizeof(short),1,stream);
if (file_format_type == 2) {
fread(&frame->peaks[ix].klt_bw, sizeof(short), 1, stream);
fread(&frame->peaks[ix].klt_ap, sizeof(short), 1, stream);
fread(&frame->peaks[ix].klt_bp, sizeof(short), 1, stream);
} }
} }


if(file_format_type > 0)
{
for(ix=0; ix<N_KLATTP2; ix++)
{
fread(frame->klatt_param + ix,sizeof(short),1,stream);
if (file_format_type > 0) {
for (ix = 0; ix < N_KLATTP2; ix++) {
fread(frame->klatt_param + ix, sizeof(short), 1, stream);
} }
} }


spect_data = malloc(sizeof(USHORT) * frame->nx); spect_data = malloc(sizeof(USHORT) * frame->nx);


if(spect_data == NULL)
{
fprintf(stderr,"Failed to allocate memory\n");
return(1);
if (spect_data == NULL) {
fprintf(stderr, "Failed to allocate memory\n");
return 1;
} }


frame->max_y = 0; frame->max_y = 0;
for(ix=0; ix<frame->nx; ix++)
{
fread(&x,sizeof(short),1,stream);
for (ix = 0; ix < frame->nx; ix++) {
fread(&x, sizeof(short), 1, stream);
spect_data[ix] = x; spect_data[ix] = x;
if(x > frame->max_y) frame->max_y = x;
if (x > frame->max_y) frame->max_y = x;
} }
frame->spect = spect_data; frame->spect = spect_data;


return(0);
return 0;
} }




double GetFrameRms(SpectFrame *frame, int seq_amplitude) double GetFrameRms(SpectFrame *frame, int seq_amplitude)
{ {
int h; int h;
float total=0;
float total = 0;
int maxh; int maxh;
int height; int height;
int htab[400]; int htab[400];
wavegen_peaks_t wpeaks[9]; wavegen_peaks_t wpeaks[9];


for(h=0; h<9; h++)
{
for (h = 0; h < 9; h++) {
height = (frame->peaks[h].pkheight * seq_amplitude * frame->amp_adjust)/10000; height = (frame->peaks[h].pkheight * seq_amplitude * frame->amp_adjust)/10000;
wpeaks[h].height = height << 8; wpeaks[h].height = height << 8;


wpeaks[h].right = frame->peaks[h].pkright << 16; wpeaks[h].right = frame->peaks[h].pkright << 16;
} }


maxh = PeaksToHarmspect(wpeaks,90<<16,htab,0);
for(h=1; h<maxh; h++)
{
maxh = PeaksToHarmspect(wpeaks, 90<<16, htab, 0);
for (h = 1; h < maxh; h++) {
total += ((htab[h] * htab[h]) >> 10); total += ((htab[h] * htab[h]) >> 10);
} }
frame->rms = sqrt(total) / 7.25; frame->rms = sqrt(total) / 7.25;
return(frame->rms);
return frame->rms;
} }




void SpectSeqDestroy(SpectSeq *spect) void SpectSeqDestroy(SpectSeq *spect)
{ {
int ix; int ix;
if(spect->frames != NULL)
{
for(ix=0; ix<spect->numframes; ix++)
{
if(spect->frames[ix] != NULL)
if (spect->frames != NULL) {
for (ix = 0; ix < spect->numframes; ix++) {
if (spect->frames[ix] != NULL)
SpectFrameDestroy(spect->frames[ix]); SpectFrameDestroy(spect->frames[ix]);
} }
free(spect->frames); free(spect->frames);
static float GetFrameLength(SpectSeq *spect, int frame) static float GetFrameLength(SpectSeq *spect, int frame)
{ {
int ix; int ix;
float adjust=0;
float adjust = 0;


if(frame >= spect->numframes-1) return(0);
if (frame >= spect->numframes-1) return 0;


for(ix=frame+1; ix<spect->numframes-1; ix++)
{
if(spect->frames[ix]->keyframe) break; // reached next keyframe
for (ix = frame+1; ix < spect->numframes-1; ix++) {
if (spect->frames[ix]->keyframe) break; // reached next keyframe
adjust += spect->frames[ix]->length_adjust; adjust += spect->frames[ix]->length_adjust;
} }
return ((spect->frames[ix]->time - spect->frames[frame]->time) * 1000.0 + adjust);
return (spect->frames[ix]->time - spect->frames[frame]->time) * 1000.0 + adjust;
} }




short n, temp; short n, temp;
int ix; int ix;
uint32_t id1, id2, name_len; uint32_t id1, id2, name_len;
int set_max_y=0;
int set_max_y = 0;
float time_offset; float time_offset;


FILE *stream = fopen(filename, "rb"); FILE *stream = fopen(filename, "rb");
if(stream == NULL)
{
if (stream == NULL) {
fprintf(stderr, "Failed to open: '%s'", filename); fprintf(stderr, "Failed to open: '%s'", filename);
return(0);
return 0;
} }


fread(&id1,sizeof(uint32_t),1,stream);
fread(&id2,sizeof(uint32_t),1,stream);
fread(&id1, sizeof(uint32_t), 1, stream);
fread(&id2, sizeof(uint32_t), 1, stream);


if((id1 == FILEID1_SPECTSEQ) && (id2 == FILEID2_SPECTSEQ))
{
if ((id1 == FILEID1_SPECTSEQ) && (id2 == FILEID2_SPECTSEQ)) {
spect->file_format = 0; // eSpeak formants spect->file_format = 0; // eSpeak formants
}
else
if((id1 == FILEID1_SPECTSEQ) && (id2 == FILEID2_SPECTSEK))
{
} else if ((id1 == FILEID1_SPECTSEQ) && (id2 == FILEID2_SPECTSEK)) {
spect->file_format = 1; // formants for Klatt synthesizer spect->file_format = 1; // formants for Klatt synthesizer
}
else
if((id1 == FILEID1_SPECTSEQ) && (id2 == FILEID2_SPECTSQ2))
{
} else if ((id1 == FILEID1_SPECTSEQ) && (id2 == FILEID2_SPECTSQ2)) {
spect->file_format = 2; // formants for Klatt synthesizer spect->file_format = 2; // formants for Klatt synthesizer
}
else
{
} else {
fprintf(stderr, "Unsupported spectral file format.\n"); fprintf(stderr, "Unsupported spectral file format.\n");
fclose(stream); fclose(stream);
return(1);
return 1;
} }


fread(&name_len,sizeof(uint32_t),1,stream);
if (name_len > 0)
{
fread(&name_len, sizeof(uint32_t), 1, stream);
if (name_len > 0) {
spect->name = (char *)malloc(name_len); spect->name = (char *)malloc(name_len);
fread(spect->name,sizeof(char),name_len,stream);
}
else
fread(spect->name, sizeof(char), name_len, stream);
} else
spect->name = NULL; spect->name = NULL;


fread(&n,sizeof(short),1,stream);
fread(&spect->amplitude,sizeof(short),1,stream);
fread(&spect->max_y,sizeof(short),1,stream);
fread(&temp,sizeof(short),1,stream); // unused
fread(&n, sizeof(short), 1, stream);
fread(&spect->amplitude, sizeof(short), 1, stream);
fread(&spect->max_y, sizeof(short), 1, stream);
fread(&temp, sizeof(short), 1, stream); // unused


if(n==0)
{
if (n == 0) {
fclose(stream); fclose(stream);
return(0);
return 0;
} }


if(spect->frames != NULL)
{
for(ix=0; ix<spect->numframes; ix++)
{
if(spect->frames[ix] != NULL)
if (spect->frames != NULL) {
for (ix = 0; ix < spect->numframes; ix++) {
if (spect->frames[ix] != NULL)
SpectFrameDestroy(spect->frames[ix]); SpectFrameDestroy(spect->frames[ix]);
} }
free(spect->frames); free(spect->frames);


spect->numframes = 0; spect->numframes = 0;
spect->max_x = 3000; spect->max_x = 3000;
if(spect->max_y == 0)
{
if (spect->max_y == 0) {
set_max_y = 1; set_max_y = 1;
spect->max_y = 1; spect->max_y = 1;
} }
for(ix = 0; ix < n; ix++)
{
for (ix = 0; ix < n; ix++) {
SpectFrame *frame = SpectFrameCreate(); SpectFrame *frame = SpectFrameCreate();


if(LoadFrame(frame, stream, spect->file_format) != 0)
{
if (LoadFrame(frame, stream, spect->file_format) != 0) {
free(frame); free(frame);
break; break;
} }


spect->frames[spect->numframes++] = frame; spect->frames[spect->numframes++] = frame;


if(set_max_y && (frame->max_y > spect->max_y))
if (set_max_y && (frame->max_y > spect->max_y))
spect->max_y = frame->max_y; spect->max_y = frame->max_y;
if(frame->nx * frame->dx > spect->max_x) spect->max_x = (int)(frame->nx * frame->dx);
if (frame->nx * frame->dx > spect->max_x) spect->max_x = (int)(frame->nx * frame->dx);
} }
spect->max_x = 9000; // disable auto-xscaling spect->max_x = 9000; // disable auto-xscaling


frame_width = (int)((FRAME_WIDTH*spect->max_x)/MAX_DISPLAY_FREQ); frame_width = (int)((FRAME_WIDTH*spect->max_x)/MAX_DISPLAY_FREQ);
if(frame_width > FRAME_WIDTH) frame_width = FRAME_WIDTH;
if (frame_width > FRAME_WIDTH) frame_width = FRAME_WIDTH;




// start times from zero // start times from zero
time_offset = spect->frames[0]->time; time_offset = spect->frames[0]->time;
for(ix=0; ix<spect->numframes; ix++)
for (ix = 0; ix < spect->numframes; ix++)
spect->frames[ix]->time -= time_offset; spect->frames[ix]->time -= time_offset;


spect->pitch1 = spect->pitchenv.pitch1; spect->pitch1 = spect->pitchenv.pitch1;
spect->pitch2 = spect->pitchenv.pitch2; spect->pitch2 = spect->pitchenv.pitch2;
spect->duration = (int)(spect->frames[spect->numframes-1]->time * 1000); spect->duration = (int)(spect->frames[spect->numframes-1]->time * 1000);


if(spect->max_y < 400)
if (spect->max_y < 400)
spect->max_y = 200; spect->max_y = 200;
else else
spect->max_y = 29000; // disable auto height scaling spect->max_y = 29000; // disable auto height scaling


for(ix=0; ix<spect->numframes; ix++)
{
if(spect->frames[ix]->keyframe)
spect->frames[ix]->length_adjust = spect->frames[ix]->length - GetFrameLength(spect,ix);
for (ix = 0; ix < spect->numframes; ix++) {
if (spect->frames[ix]->keyframe)
spect->frames[ix]->length_adjust = spect->frames[ix]->length - GetFrameLength(spect, ix);
} }
fclose(stream); fclose(stream);
return(0);
return 0;
} }

+ 2
- 4
src/libespeak-ng/spect.h View File

} peak_t; } peak_t;




typedef struct
{
typedef struct {
int keyframe; int keyframe;
short amp_adjust; short amp_adjust;
float length_adjust; float length_adjust;


double GetFrameRms(SpectFrame *frame, int amp); double GetFrameRms(SpectFrame *frame, int amp);


typedef struct
{
typedef struct {
int numframes; int numframes;
short amplitude; short amplitude;
int spare; int spare;

+ 1
- 1
src/libespeak-ng/speech.h View File



extern char path_home[N_PATH_HOME]; // this is the espeak-data directory extern char path_home[N_PATH_HOME]; // this is the espeak-data directory


extern void strncpy0(char *to,const char *from, int size);
extern void strncpy0(char *to, const char *from, int size);
int GetFileLength(const char *filename); int GetFileLength(const char *filename);
char *Alloc(int size); char *Alloc(int size);
void Free(void *ptr); void Free(void *ptr);

+ 148
- 204
src/libespeak-ng/synth_mbrola.c View File

typedef void (WINAPI *PROCVF)(float); typedef void (WINAPI *PROCVF)(float);
typedef int (WINAPI *PROCIV)(); typedef int (WINAPI *PROCIV)();
typedef int (WINAPI *PROCIC)(char *); typedef int (WINAPI *PROCIC)(char *);
typedef int (WINAPI *PROCISI)(short *,int);
typedef char* (WINAPI *PROCVCI)(char *,int);
typedef int (WINAPI *PROCISI)(short *, int);
typedef char * (WINAPI *PROCVCI)(char *, int);


PROCIC init_MBR; PROCIC init_MBR;
PROCIC write_MBR; PROCIC write_MBR;


BOOL load_MBR() BOOL load_MBR()
{ {
if(hinstDllMBR != NULL)
if (hinstDllMBR != NULL)
return TRUE; // already loaded return TRUE; // already loaded


if ((hinstDllMBR=LoadLibraryA("mbrola.dll")) == 0)
if ((hinstDllMBR = LoadLibraryA("mbrola.dll")) == 0)
return FALSE; return FALSE;
init_MBR =(PROCIC) GetProcAddress(hinstDllMBR,"init_MBR");
write_MBR =(PROCIC) GetProcAddress(hinstDllMBR,"write_MBR");
flush_MBR =(PROCIV) GetProcAddress(hinstDllMBR,"flush_MBR");
read_MBR =(PROCISI) GetProcAddress(hinstDllMBR,"read_MBR");
close_MBR =(PROCVV) GetProcAddress(hinstDllMBR,"close_MBR");
reset_MBR =(PROCVV) GetProcAddress(hinstDllMBR,"reset_MBR");
lastError_MBR =(PROCIV) GetProcAddress(hinstDllMBR,"lastError_MBR");
lastErrorStr_MBR =(PROCVCI) GetProcAddress(hinstDllMBR,"lastErrorStr_MBR");
setNoError_MBR =(PROCVI) GetProcAddress(hinstDllMBR,"setNoError_MBR");
setVolumeRatio_MBR =(PROCVF) GetProcAddress(hinstDllMBR,"setVolumeRatio_MBR");
init_MBR = (PROCIC)GetProcAddress(hinstDllMBR, "init_MBR");
write_MBR = (PROCIC)GetProcAddress(hinstDllMBR, "write_MBR");
flush_MBR = (PROCIV)GetProcAddress(hinstDllMBR, "flush_MBR");
read_MBR = (PROCISI)GetProcAddress(hinstDllMBR, "read_MBR");
close_MBR = (PROCVV)GetProcAddress(hinstDllMBR, "close_MBR");
reset_MBR = (PROCVV)GetProcAddress(hinstDllMBR, "reset_MBR");
lastError_MBR = (PROCIV)GetProcAddress(hinstDllMBR, "lastError_MBR");
lastErrorStr_MBR = (PROCVCI)GetProcAddress(hinstDllMBR, "lastErrorStr_MBR");
setNoError_MBR = (PROCVI)GetProcAddress(hinstDllMBR, "setNoError_MBR");
setVolumeRatio_MBR = (PROCVF)GetProcAddress(hinstDllMBR, "setVolumeRatio_MBR");
return TRUE; return TRUE;
} }




void unload_MBR() void unload_MBR()
{ {
if (hinstDllMBR)
{
FreeLibrary (hinstDllMBR);
hinstDllMBR=NULL;
if (hinstDllMBR) {
FreeLibrary(hinstDllMBR);
hinstDllMBR = NULL;
} }
} }


mbrola_delay = 0; mbrola_delay = 0;
mbr_name_prefix = 0; mbr_name_prefix = 0;


if(mbrola_voice == NULL)
{
if (mbrola_voice == NULL) {
samplerate = samplerate_native; samplerate = samplerate_native;
SetParameter(espeakVOICETYPE,0,0);
return(EE_OK);
SetParameter(espeakVOICETYPE, 0, 0);
return EE_OK;
} }


sprintf(path,"%s/mbrola/%s",path_home,mbrola_voice);
sprintf(path, "%s/mbrola/%s", path_home, mbrola_voice);
#ifdef PLATFORM_POSIX #ifdef PLATFORM_POSIX
// if not found, then also look in // if not found, then also look in
// usr/share/mbrola/xx, /usr/share/mbrola/xx/xx, /usr/share/mbrola/voices/xx // usr/share/mbrola/xx, /usr/share/mbrola/xx/xx, /usr/share/mbrola/voices/xx
if(GetFileLength(path) <= 0)
{
sprintf(path,"/usr/share/mbrola/%s",mbrola_voice);
if (GetFileLength(path) <= 0) {
sprintf(path, "/usr/share/mbrola/%s", mbrola_voice);


if(GetFileLength(path) <= 0)
{
sprintf(path,"/usr/share/mbrola/%s/%s",mbrola_voice,mbrola_voice);
if (GetFileLength(path) <= 0) {
sprintf(path, "/usr/share/mbrola/%s/%s", mbrola_voice, mbrola_voice);


if(GetFileLength(path) <= 0)
{
sprintf(path,"/usr/share/mbrola/voices/%s",mbrola_voice);
if (GetFileLength(path) <= 0) {
sprintf(path, "/usr/share/mbrola/voices/%s", mbrola_voice);
} }
} }
} }
close_MBR(); close_MBR();
#endif #endif
#ifdef PLATFORM_WINDOWS #ifdef PLATFORM_WINDOWS
if(load_MBR() == FALSE) // load mbrola.dll
{
if (load_MBR() == FALSE) { // load mbrola.dll
fprintf(stderr, "Can't load mbrola.dll\n"); fprintf(stderr, "Can't load mbrola.dll\n");
return(EE_INTERNAL_ERROR);
return EE_INTERNAL_ERROR;
} }
#endif #endif


if(init_MBR(path) != 0) // initialise the required mbrola voice
return(EE_NOT_FOUND);
if (init_MBR(path) != 0) // initialise the required mbrola voice
return EE_NOT_FOUND;


setNoError_MBR(1); // don't stop on phoneme errors setNoError_MBR(1); // don't stop on phoneme errors


// read eSpeak's mbrola phoneme translation data, eg. en1_phtrans // read eSpeak's mbrola phoneme translation data, eg. en1_phtrans
sprintf(path,"%s/mbrola_ph/%s",path_home,phtrans);
sprintf(path, "%s/mbrola_ph/%s", path_home, phtrans);
size = GetFileLength(path); size = GetFileLength(path);
if((f_in = fopen(path,"rb")) == NULL) {
if ((f_in = fopen(path, "rb")) == NULL) {
close_MBR(); close_MBR();
return(EE_NOT_FOUND);
return EE_NOT_FOUND;
} }


if((mbrola_tab = (MBROLA_TAB *)realloc(mbrola_tab,size)) == NULL)
{
if ((mbrola_tab = (MBROLA_TAB *)realloc(mbrola_tab, size)) == NULL) {
fclose(f_in); fclose(f_in);
close_MBR(); close_MBR();
return(EE_INTERNAL_ERROR);
return EE_INTERNAL_ERROR;
} }


mbrola_control = Read4Bytes(f_in); mbrola_control = Read4Bytes(f_in);
pw = (int *)mbrola_tab; pw = (int *)mbrola_tab;
for(ix=4; ix<size; ix+=4)
{
for (ix = 4; ix < size; ix += 4) {
*pw++ = Read4Bytes(f_in); *pw++ = Read4Bytes(f_in);
} }
size = fread(mbrola_tab,1,size,f_in);
size = fread(mbrola_tab, 1, size, f_in);
fclose(f_in); fclose(f_in);


setVolumeRatio_MBR((float)(mbrola_control & 0xff) /16.0f); setVolumeRatio_MBR((float)(mbrola_control & 0xff) /16.0f);
samplerate = *srate = getFreq_MBR(); samplerate = *srate = getFreq_MBR();
if(*srate == 22050)
SetParameter(espeakVOICETYPE,0,0);
if (*srate == 22050)
SetParameter(espeakVOICETYPE, 0, 0);
else else
SetParameter(espeakVOICETYPE,1,0);
strcpy(mbrola_name,mbrola_voice);
SetParameter(espeakVOICETYPE, 1, 0);
strcpy(mbrola_name, mbrola_voice);
mbrola_delay = 1000; // improve synchronization of events mbrola_delay = 1000; // improve synchronization of events
return(EE_OK);
return EE_OK;
} }




// bit 5 only in stressed syllable // bit 5 only in stressed syllable
// bit 6 only at the end of a word // bit 6 only at the end of a word


*name2=0;
*split=0;
*control=0;
*name2 = 0;
*split = 0;
*control = 0;
mnem = ph->mnemonic; mnem = ph->mnemonic;


pr = mbrola_tab; pr = mbrola_tab;
while(pr->name != 0)
{
if(mnem == pr->name)
{
if(pr->next_phoneme == 0)
while (pr->name != 0) {
if (mnem == pr->name) {
if (pr->next_phoneme == 0)
found = 1; found = 1;
else
if((pr->next_phoneme == ':') && (plist->synthflags & SFLAG_LENGTHEN))
{
else if ((pr->next_phoneme == ':') && (plist->synthflags & SFLAG_LENGTHEN)) {
found = 1; found = 1;
}
else
{
if(pr->control & 2)
} else {
if (pr->control & 2)
other_ph = ph_prev; other_ph = ph_prev;
else
if((pr->control & 8) && ((plist+1)->newword))
else if ((pr->control & 8) && ((plist+1)->newword))
other_ph = phoneme_tab[phPAUSE]; // don't match the next phoneme over a word boundary other_ph = phoneme_tab[phPAUSE]; // don't match the next phoneme over a word boundary
else else
other_ph = ph_next; other_ph = ph_next;


if((pr->next_phoneme == other_ph->mnemonic) ||
((pr->next_phoneme == 2) && (other_ph->type == phVOWEL)) ||
((pr->next_phoneme == '_') && (other_ph->type == phPAUSE)))
{
if ((pr->next_phoneme == other_ph->mnemonic) ||
((pr->next_phoneme == 2) && (other_ph->type == phVOWEL)) ||
((pr->next_phoneme == '_') && (other_ph->type == phPAUSE))) {
found = 1; found = 1;
} }
} }


if((pr->control & 4) && (plist->newword == 0)) // only at start of word
if ((pr->control & 4) && (plist->newword == 0)) // only at start of word
found = 0; found = 0;


if((pr->control & 0x40) && (plist[1].newword == 0)) // only at the end of a word
if ((pr->control & 0x40) && (plist[1].newword == 0)) // only at the end of a word
found = 0; found = 0;


if((pr->control & 0x20) && (plist->stresslevel < plist->wordstress))
if ((pr->control & 0x20) && (plist->stresslevel < plist->wordstress))
found = 0; // only in stressed syllables found = 0; // only in stressed syllables


if(found)
{
if (found) {
*name2 = pr->mbr_name2; *name2 = pr->mbr_name2;
*split = pr->percent; *split = pr->percent;
*control = pr->control; *control = pr->control;


if(pr->control & 0x10)
{
if (pr->control & 0x10) {
mbr_name_prefix = pr->mbr_name; mbr_name_prefix = pr->mbr_name;
return(0);
return 0;
} }
mnem = pr->mbr_name; mnem = pr->mbr_name;
break; break;
pr++; pr++;
} }


if(mbr_name_prefix != 0)
{
if (mbr_name_prefix != 0) {
mnem = (mnem << 8) | (mbr_name_prefix & 0xff); mnem = (mnem << 8) | (mbr_name_prefix & 0xff);
} }
mbr_name_prefix = 0; mbr_name_prefix = 0;
return(mnem);
return mnem;
} }




int ix; int ix;
int pitch_base; int pitch_base;
int pitch_range; int pitch_range;
int p1,p2,p_end;
int p1, p2, p_end;
unsigned char *pitch_env; unsigned char *pitch_env;
int max = -1; int max = -1;
int min = 999; int min = 999;
int y_max=0;
int y_min=0;
int y_max = 0;
int y_min = 0;
int env100 = 80; // apply the pitch change only over this proportion of the mbrola phoneme(s) int env100 = 80; // apply the pitch change only over this proportion of the mbrola phoneme(s)
int y2; int y2;
int y[4]; int y[4];




env_split = (split * 128)/100; env_split = (split * 128)/100;
if(env_split < 0)
if (env_split < 0)
env_split = 0-env_split; env_split = 0-env_split;


// find max and min in the pitch envelope // find max and min in the pitch envelope
for(x=0; x<128; x++)
{
if(pitch_env[x] > max)
{
for (x = 0; x < 128; x++) {
if (pitch_env[x] > max) {
max = pitch_env[x]; max = pitch_env[x];
y_max = x; y_max = x;
} }
if(pitch_env[x] < min)
{
if (pitch_env[x] < min) {
min = pitch_env[x]; min = pitch_env[x];
y_min = x; y_min = x;
} }
// set an additional pitch point half way through the phoneme. // set an additional pitch point half way through the phoneme.
// but look for a maximum or a minimum and use that instead // but look for a maximum or a minimum and use that instead
y[2] = 64; y[2] = 64;
if((y_max > 0) && (y_max < 127))
{
if ((y_max > 0) && (y_max < 127)) {
y[2] = y_max; y[2] = y_max;
} }
if((y_min > 0) && (y_min < 127))
{
if ((y_min > 0) && (y_min < 127)) {
y[2] = y_min; y[2] = y_min;
} }
y[1] = y[2] / 2; y[1] = y[2] / 2;
p_end = ((pitch_env[127]*pitch_range)>>8) + pitch_base; p_end = ((pitch_env[127]*pitch_range)>>8) + pitch_base;




if(split >= 0)
{
sprintf(buf," 0 %d",p1/4096);
strcat(output,buf);
if (split >= 0) {
sprintf(buf, " 0 %d", p1/4096);
strcat(output, buf);
} }


// don't use intermediate pitch points for linear rise and fall // don't use intermediate pitch points for linear rise and fall
if(env > 1)
{
for(ix=1; ix<4; ix++)
{
if (env > 1) {
for (ix = 1; ix < 4; ix++) {
p2 = ((pitch_env[y[ix]]*pitch_range)>>8) + pitch_base; p2 = ((pitch_env[y[ix]]*pitch_range)>>8) + pitch_base;


if(split > 0)
{
if (split > 0) {
y2 = (y[ix] * env100)/env_split; y2 = (y[ix] * env100)/env_split;
}
else
if(split < 0)
{
} else if (split < 0) {
y2 = ((y[ix]-env_split) * env100)/env_split; y2 = ((y[ix]-env_split) * env100)/env_split;
}
else
{
} else {
y2 = (y[ix] * env100)/128; y2 = (y[ix] * env100)/128;
} }
if((y2 > 0) && (y2 <= env100))
{
sprintf(buf," %d %d",y2,p2/4096);
strcat(output,buf);
if ((y2 > 0) && (y2 <= env100)) {
sprintf(buf, " %d %d", y2, p2/4096);
strcat(output, buf);
} }
} }
} }


p_end = p_end/4096; p_end = p_end/4096;
if(split <= 0)
{
sprintf(buf," %d %d",env100,p_end);
strcat(output,buf);
if (split <= 0) {
sprintf(buf, " %d %d", env100, p_end);
strcat(output, buf);
} }
if(env100 < 100)
{
sprintf(buf," %d %d",100,p_end);
strcat(output,buf);
if (env100 < 100) {
sprintf(buf, " %d %d", 100, p_end);
strcat(output, buf);
} }
strcat(output,"\n");
strcat(output, "\n");


if(final)
sprintf(output,"\t100 %d\n",p_end);
return(output);
if (final)
sprintf(output, "\t100 %d\n", p_end);
return output;
} }




word_count = 0; word_count = 0;
} }


while (phix < n_phonemes)
{
while (phix < n_phonemes) {
if (WcmdqFree() < MIN_WCMDQ) if (WcmdqFree() < MIN_WCMDQ)
return 1; return 1;


ph_prev = plist[phix-1].ph; ph_prev = plist[phix-1].ph;
ph_next = plist[phix+1].ph; ph_next = plist[phix+1].ph;


if(p->synthflags & SFLAG_EMBEDDED)
{
if (p->synthflags & SFLAG_EMBEDDED) {
DoEmbedded(&embedded_ix, p->sourceix); DoEmbedded(&embedded_ix, p->sourceix);
} }


if(p->newword & 4)
if (p->newword & 4)
DoMarker(espeakEVENT_SENTENCE, (p->sourceix & 0x7ff) + clause_start_char, 0, count_sentences); DoMarker(espeakEVENT_SENTENCE, (p->sourceix & 0x7ff) + clause_start_char, 0, count_sentences);
if(p->newword & 1)
if (p->newword & 1)
DoMarker(espeakEVENT_WORD, (p->sourceix & 0x7ff) + clause_start_char, p->sourceix >> 11, clause_start_word + word_count++); DoMarker(espeakEVENT_WORD, (p->sourceix & 0x7ff) + clause_start_char, p->sourceix >> 11, clause_start_word + word_count++);


name = GetMbrName(p,ph,ph_prev,ph_next,&name2,&len_percent,&control);
if(control & 1)
name = GetMbrName(p, ph, ph_prev, ph_next, &name2, &len_percent, &control);
if (control & 1)
phix++; phix++;


if(name == 0) {
if (name == 0) {
phix++; phix++;
continue; // ignore this phoneme continue; // ignore this phoneme
} }


if((ph->type == phPAUSE) && (name == ph->mnemonic))
{
if ((ph->type == phPAUSE) && (name == ph->mnemonic)) {
// a pause phoneme, which has not been changed by the translation // a pause phoneme, which has not been changed by the translation
name = '_'; name = '_';
len = (p->length * speed.pause_factor)/256; len = (p->length * speed.pause_factor)/256;
if(len == 0)
if (len == 0)
len = 1; len = 1;
}
else
} else
len = (80 * speed.wav_factor)/256; len = (80 * speed.wav_factor)/256;


if(ph->code != phonEND_WORD)
{
if (ph->code != phonEND_WORD) {
char phoneme_name[16]; char phoneme_name[16];
WritePhMnemonic(phoneme_name, p->ph, p, option_phoneme_events & espeakINITIALIZE_PHONEME_IPA, NULL); WritePhMnemonic(phoneme_name, p->ph, p, option_phoneme_events & espeakINITIALIZE_PHONEME_IPA, NULL);
DoPhonemeMarker(espeakEVENT_PHONEME, (p->sourceix & 0x7ff) + clause_start_char, 0, phoneme_name); DoPhonemeMarker(espeakEVENT_PHONEME, (p->sourceix & 0x7ff) + clause_start_char, 0, phoneme_name);
} }


ptr += sprintf(ptr,"%s\t",WordToString(name));
ptr += sprintf(ptr, "%s\t", WordToString(name));


if(name2 == '_')
{
if (name2 == '_') {
// add a pause after this phoneme // add a pause after this phoneme
pause = len_percent; pause = len_percent;
name2 = 0; name2 = 0;
done = 0; done = 0;
final_pitch = ""; final_pitch = "";


switch(ph->type)
switch (ph->type)
{ {
case phVOWEL: case phVOWEL:
len = ph->std_length; len = ph->std_length;
if(p->synthflags & SFLAG_LENGTHEN)
if (p->synthflags & SFLAG_LENGTHEN)
len += phoneme_tab[phonLENGTHEN]->std_length; // phoneme was followed by an extra : symbol len += phoneme_tab[phonLENGTHEN]->std_length; // phoneme was followed by an extra : symbol


if(ph_next->type == phPAUSE)
if (ph_next->type == phPAUSE)
len += 50; // lengthen vowels before a pause len += 50; // lengthen vowels before a pause
len = (len * p->length)/256; len = (len * p->length)/256;


if(name2 == 0)
{
char *pitch = WritePitch(p->env,p->pitch1,p->pitch2,0,0);
ptr += sprintf(ptr,"%d\t%s", len, pitch);
}
else
{
if (name2 == 0) {
char *pitch = WritePitch(p->env, p->pitch1, p->pitch2, 0, 0);
ptr += sprintf(ptr, "%d\t%s", len, pitch);
} else {
char *pitch; char *pitch;


pitch = WritePitch(p->env,p->pitch1,p->pitch2,len_percent,0);
pitch = WritePitch(p->env, p->pitch1, p->pitch2, len_percent, 0);
len1 = (len * len_percent)/100; len1 = (len * len_percent)/100;
ptr += sprintf(ptr,"%d\t%s", len1, pitch);
ptr += sprintf(ptr, "%d\t%s", len1, pitch);


pitch = WritePitch(p->env,p->pitch1,p->pitch2,-len_percent,0);
ptr += sprintf(ptr,"%s\t%d\t%s", WordToString(name2), len-len1, pitch);
pitch = WritePitch(p->env, p->pitch1, p->pitch2, -len_percent, 0);
ptr += sprintf(ptr, "%s\t%d\t%s", WordToString(name2), len-len1, pitch);
} }
done = 1; done = 1;
break; break;


case phSTOP: case phSTOP:
released = 0; released = 0;
if(next->type==phVOWEL) released = 1;
if(next->type==phLIQUID && !next->newword) released = 1;
if (next->type == phVOWEL) released = 1;
if (next->type == phLIQUID && !next->newword) released = 1;


if(released == 0)
if (released == 0)
p->synthflags |= SFLAG_NEXT_PAUSE; p->synthflags |= SFLAG_NEXT_PAUSE;
InterpretPhoneme(NULL, 0, p, &phdata, NULL); InterpretPhoneme(NULL, 0, p, &phdata, NULL);
len = DoSample3(&phdata, 0, -1); len = DoSample3(&phdata, 0, -1);


len = (len * 1000)/samplerate; // convert to mS len = (len * 1000)/samplerate; // convert to mS
len += PauseLength(p->prepause,1);
len += PauseLength(p->prepause, 1);
break; break;


case phVSTOP: case phVSTOP:
case phFRICATIVE: case phFRICATIVE:
len = 0; len = 0;
InterpretPhoneme(NULL, 0, p, &phdata, NULL); InterpretPhoneme(NULL, 0, p, &phdata, NULL);
if(p->synthflags & SFLAG_LENGTHEN)
if (p->synthflags & SFLAG_LENGTHEN)
len = DoSample3(&phdata, p->length, -1); // play it twice for [s:] etc. len = DoSample3(&phdata, p->length, -1); // play it twice for [s:] etc.
len += DoSample3(&phdata, p->length, -1); len += DoSample3(&phdata, p->length, -1);


break; break;


case phNASAL: case phNASAL:
if(next->type != phVOWEL)
{
if (next->type != phVOWEL) {
memset(&fmtp, 0, sizeof(fmtp)); memset(&fmtp, 0, sizeof(fmtp));
InterpretPhoneme(NULL, 0, p, &phdata, NULL); InterpretPhoneme(NULL, 0, p, &phdata, NULL);
fmtp.fmt_addr = phdata.sound_addr[pd_FMT]; fmtp.fmt_addr = phdata.sound_addr[pd_FMT];
len = DoSpect2(p->ph, 0, &fmtp, p, -1); len = DoSpect2(p->ph, 0, &fmtp, p, -1);
len = (len * 1000)/samplerate; len = (len * 1000)/samplerate;
if(next->type == phPAUSE)
if (next->type == phPAUSE)
len += 50; len += 50;
final_pitch = WritePitch(p->env,p->pitch1,p->pitch2,0,1);
final_pitch = WritePitch(p->env, p->pitch1, p->pitch2, 0, 1);
} }
break; break;


case phLIQUID: case phLIQUID:
if(next->type == phPAUSE)
{
if (next->type == phPAUSE) {
len += 50; len += 50;
final_pitch = WritePitch(p->env,p->pitch1,p->pitch2,0,1);
final_pitch = WritePitch(p->env, p->pitch1, p->pitch2, 0, 1);
} }
break; break;
} }


if(!done)
{
if(name2 != 0)
{
if (!done) {
if (name2 != 0) {
len1 = (len * len_percent)/100; len1 = (len * len_percent)/100;
ptr += sprintf(ptr,"%d\n%s\t",len1,WordToString(name2));
ptr += sprintf(ptr, "%d\n%s\t", len1, WordToString(name2));
len -= len1; len -= len1;
} }
ptr += sprintf(ptr,"%d%s\n",len,final_pitch);
ptr += sprintf(ptr, "%d%s\n", len, final_pitch);
} }


if(pause)
{
len += PauseLength(pause,0);
ptr += sprintf(ptr,"_ \t%d\n",PauseLength(pause,0));
if (pause) {
len += PauseLength(pause, 0);
ptr += sprintf(ptr, "_ \t%d\n", PauseLength(pause, 0));
pause = 0; pause = 0;
} }


if(f_mbrola)
{
fwrite(mbr_buf,1,(ptr-mbr_buf),f_mbrola); // write .pho to a file
}
else
{
if (f_mbrola) {
fwrite(mbr_buf, 1, (ptr-mbr_buf), f_mbrola); // write .pho to a file
} else {
int res = write_MBR(mbr_buf); int res = write_MBR(mbr_buf);
if (res < 0) if (res < 0)
return 0; /* don't get stuck on error */ return 0; /* don't get stuck on error */
phix++; phix++;
} }


if(!f_mbrola)
{
if (!f_mbrola) {
flush_MBR(); flush_MBR();


// flush the mbrola output buffer // flush the mbrola output buffer
{ {
FILE *f_mbrola = NULL; FILE *f_mbrola = NULL;


if(*n_ph == 0)
return(0);
if (*n_ph == 0)
return 0;


if(option_phonemes & espeakPHONEMES_MBROLA)
{
if (option_phonemes & espeakPHONEMES_MBROLA) {
// send mbrola data to a file, not to the mbrola library // send mbrola data to a file, not to the mbrola library
f_mbrola = f_trans; f_mbrola = f_trans;
} }
if (result <= 0) if (result <= 0)
return 0; return 0;


for(ix=0; ix < result; ix++)
{
for (ix = 0; ix < result; ix++) {
value16 = out_ptr[0] + (out_ptr[1] << 8); value16 = out_ptr[0] + (out_ptr[1] << 8);
value = value16 * amplitude; value = value16 * amplitude;
value = value / 40; // adjust this constant to give a suitable amplitude for mbrola voices value = value / 40; // adjust this constant to give a suitable amplitude for mbrola voices
if(value > 0x7fff)
if (value > 0x7fff)
value = 0x7fff; value = 0x7fff;
if(value < -0x8000)
if (value < -0x8000)
value = 0x8000; value = 0x8000;
out_ptr[0] = value; out_ptr[0] = value;
out_ptr[1] = value >> 8; out_ptr[1] = value >> 8;


espeak_ERROR LoadMbrolaTable(const char *mbrola_voice, const char *phtrans, int *srate) espeak_ERROR LoadMbrolaTable(const char *mbrola_voice, const char *phtrans, int *srate)
{ {
return(EE_INTERNAL_ERROR);
return EE_INTERNAL_ERROR;
} }


int MbrolaGenerate(PHONEME_LIST *phoneme_list, int *n_ph, int resume) int MbrolaGenerate(PHONEME_LIST *phoneme_list, int *n_ph, int resume)
{ {
return(0);
return 0;
} }


int MbrolaFill(int length, int resume, int amplitude) int MbrolaFill(int length, int resume, int amplitude)
{ {
return(0);
return 0;
} }


void MbrolaReset(void) void MbrolaReset(void)

+ 270
- 403
src/libespeak-ng/synthdata.c
File diff suppressed because it is too large
View File


+ 399
- 625
src/libespeak-ng/synthesize.c
File diff suppressed because it is too large
View File


+ 3
- 3
src/libespeak-ng/synthesize.h View File

int WavegenCloseSound(); int WavegenCloseSound();
int WavegenInitSound(); int WavegenInitSound();
void WavegenInit(int rate, int wavemult_fact); void WavegenInit(int rate, int wavemult_fact);
float polint(float xa[],float ya[],int n,float x);
float polint(float xa[], float ya[], int n, float x);
int WavegenFill(int fill_zeros); int WavegenFill(int fill_zeros);
void MarkerEvent(int type, unsigned int char_position, int value, int value2, unsigned char *out_ptr); void MarkerEvent(int type, unsigned int char_position, int value, int value2, unsigned char *out_ptr);


void Write4Bytes(FILE *f, int value); void Write4Bytes(FILE *f, int value);
int Read4Bytes(FILE *f); int Read4Bytes(FILE *f);
int Reverse4Bytes(int word); int Reverse4Bytes(int word);
int CompileDictionary(const char *dsource, const char *dict_name, FILE *log, char *err_name,int flags);
int CompileDictionary(const char *dsource, const char *dict_name, FILE *log, char *err_name, int flags);




#define ENV_LEN 128 // length of pitch envelopes #define ENV_LEN 128 // length of pitch envelopes
extern unsigned char *out_end; extern unsigned char *out_end;
extern int event_list_ix; extern int event_list_ix;
extern espeak_EVENT *event_list; extern espeak_EVENT *event_list;
extern t_espeak_callback* synth_callback;
extern t_espeak_callback *synth_callback;
extern const char *version_string; extern const char *version_string;
extern const int version_phdata; extern const int version_phdata;
extern double sonicSpeed; extern double sonicSpeed;

+ 466
- 516
src/libespeak-ng/tr_languages.c
File diff suppressed because it is too large
View File


+ 775
- 1221
src/libespeak-ng/translate.c
File diff suppressed because it is too large
View File


+ 7
- 8
src/libespeak-ng/translate.h View File

{ {
#endif #endif


#define L(c1,c2) (c1<<8)+c2 // combine two characters into an integer for translator name
#define L(c1, c2) (c1<<8)+c2 // combine two characters into an integer for translator name


#define CTRL_EMBEDDED 0x01 // control character at the start of an embedded command #define CTRL_EMBEDDED 0x01 // control character at the start of an embedded command
#define REPLACED_E 'E' // 'e' replaced by silent e #define REPLACED_E 'E' // 'e' replaced by silent e
// match 1 pre 2 post 0 - use common phoneme string // match 1 pre 2 post 0 - use common phoneme string
// match 1 pre 2 post 3 0 - empty phoneme string // match 1 pre 2 post 3 0 - empty phoneme string


typedef const char * constcharptr;
typedef const char *constcharptr;


typedef struct { typedef struct {
int points; int points;






typedef struct
{
typedef struct {


LANGUAGE_OPTIONS langopts; LANGUAGE_OPTIONS langopts;
int translator_name; int translator_name;
extern wchar_t *p_wchar_input; extern wchar_t *p_wchar_input;
extern int dictionary_skipwords; extern int dictionary_skipwords;


extern int (* uri_callback)(int, const char *, const char *);
extern int (* phoneme_callback)(const char *);
extern int (*uri_callback)(int, const char *, const char *);
extern int (*phoneme_callback)(const char *);
extern void SetLengthMods(Translator *tr, int value); extern void SetLengthMods(Translator *tr, int value);


void LoadConfig(void); void LoadConfig(void);
int utf8_in2(int *c, const char *buf, int backwards); int utf8_in2(int *c, const char *buf, int backwards);
int utf8_out(unsigned int c, char *buf); int utf8_out(unsigned int c, char *buf);
int utf8_nbytes(const char *buf); int utf8_nbytes(const char *buf);
int lookupwchar(const unsigned short *list,int c);
int lookupwchar2(const unsigned short *list,int c);
int lookupwchar(const unsigned short *list, int c);
int lookupwchar2(const unsigned short *list, int c);
int Eof(void); int Eof(void);
char *strchr_w(const char *s, int c); char *strchr_w(const char *s, int c);
int IsBracket(int c); int IsBracket(int c);

+ 466
- 626
src/libespeak-ng/voices.c
File diff suppressed because it is too large
View File


+ 238
- 327
src/libespeak-ng/wave.c
File diff suppressed because it is too large
View File


+ 9
- 9
src/libespeak-ng/wave.h View File

extern int option_device_number; extern int option_device_number;


extern int wave_init(int samplerate); extern int wave_init(int samplerate);
extern void* wave_open(const char* the_api);
extern void *wave_open(const char *the_api);


extern size_t wave_write(void* theHandler, char* theMono16BitsWaveBuffer, size_t theSize);
extern int wave_close(void* theHandler);
extern void wave_flush(void* theHandler);
extern int wave_is_busy(void* theHandler);
extern size_t wave_write(void *theHandler, char *theMono16BitsWaveBuffer, size_t theSize);
extern int wave_close(void *theHandler);
extern void wave_flush(void *theHandler);
extern int wave_is_busy(void *theHandler);
extern void wave_terminate(); extern void wave_terminate();
extern uint32_t wave_get_read_position(void* theHandler);
extern uint32_t wave_get_write_position(void* theHandler);
extern uint32_t wave_get_read_position(void *theHandler);
extern uint32_t wave_get_write_position(void *theHandler);


// Supply the remaining time in ms before the sample is played // Supply the remaining time in ms before the sample is played
// (or 0 if the event has been already played). // (or 0 if the event has been already played).
// time: supplied value in ms // time: supplied value in ms
// //
// return 0 if ok or -1 otherwise (stream not opened). // return 0 if ok or -1 otherwise (stream not opened).
extern int wave_get_remaining_time(uint32_t sample, uint32_t* time);
extern int wave_get_remaining_time(uint32_t sample, uint32_t *time);


// set the callback which informs if the output is still enabled. // set the callback which informs if the output is still enabled.
// Helpful if a new sample is waiting for free space whereas sound must be stopped. // Helpful if a new sample is waiting for free space whereas sound must be stopped.
typedef int (t_wave_callback)(void); typedef int (t_wave_callback)(void);
extern void wave_set_callback_is_output_enabled(t_wave_callback* cb);
extern void wave_set_callback_is_output_enabled(t_wave_callback *cb);




// general functions // general functions

+ 64
- 79
src/libespeak-ng/wave_pulse.c View File

#include "wave.h" #include "wave.h"
#include "debug.h" #include "debug.h"


enum {ONE_BILLION=1000000000};
enum { ONE_BILLION = 1000000000 };


enum { enum {
/* return value */ /* return value */


#ifdef USE_PULSEAUDIO #ifdef USE_PULSEAUDIO


static t_wave_callback* my_callback_is_output_enabled=NULL;
static t_wave_callback *my_callback_is_output_enabled = NULL;


#define SAMPLE_RATE 22050 #define SAMPLE_RATE 22050
#define ESPEAK_FORMAT PA_SAMPLE_S16LE #define ESPEAK_FORMAT PA_SAMPLE_S16LE
SHOW("Connection died: %s\n", context ? pa_strerror(pa_context_errno(context)) : "NULL"); \ SHOW("Connection died: %s\n", context ? pa_strerror(pa_context_errno(context)) : "NULL"); \
goto label; \ goto label; \
} \ } \
} while(0);
} while (0);


#define CHECK_CONNECTED(retval) \ #define CHECK_CONNECTED(retval) \
do { \ do { \
ENTER(__FUNCTION__); ENTER(__FUNCTION__);
assert(c); assert(c);


switch (pa_context_get_state(c)) {
switch (pa_context_get_state(c))
{
case PA_CONTEXT_READY: case PA_CONTEXT_READY:
case PA_CONTEXT_TERMINATED: case PA_CONTEXT_TERMINATED:
case PA_CONTEXT_FAILED: case PA_CONTEXT_FAILED:
} }
} }


static void stream_state_cb(pa_stream *s, void * userdata) {
static void stream_state_cb(pa_stream *s, void *userdata) {
ENTER(__FUNCTION__); ENTER(__FUNCTION__);
assert(s); assert(s);


switch (pa_stream_get_state(s)) {
switch (pa_stream_get_state(s))
{


case PA_STREAM_READY: case PA_STREAM_READY:
case PA_STREAM_FAILED: case PA_STREAM_FAILED:
assert(s); assert(s);


if (userdata) if (userdata)
*(int*) userdata = success;
*(int *)userdata = success;


pa_threaded_mainloop_signal(mainloop, 0); pa_threaded_mainloop_signal(mainloop, 0);
} }
assert(c); assert(c);


if (userdata) if (userdata)
*(int*) userdata = success;
*(int *)userdata = success;


pa_threaded_mainloop_signal(mainloop, 0); pa_threaded_mainloop_signal(mainloop, 0);
} }
pa_threaded_mainloop_lock(mainloop); pa_threaded_mainloop_lock(mainloop);
CHECK_DEAD_GOTO(fail, 1); CHECK_DEAD_GOTO(fail, 1);


if ((l = pa_stream_writable_size(stream)) == (size_t) -1) {
if ((l = pa_stream_writable_size(stream)) == (size_t)-1) {
SHOW("pa_stream_writable_size() failed: %s", pa_strerror(pa_context_errno(context))); SHOW("pa_stream_writable_size() failed: %s", pa_strerror(pa_context_errno(context)));
l = 0; l = 0;
goto fail; goto fail;


do_trigger = !!l; do_trigger = !!l;
SHOW("pulse_free: %d (ret)\n", (int)l); SHOW("pulse_free: %d (ret)\n", (int)l);
return (int) l;
return (int)l;
} }


static int pulse_playing(const pa_timing_info *the_timing_info) { static int pulse_playing(const pa_timing_info *the_timing_info) {


pa_threaded_mainloop_lock(mainloop); pa_threaded_mainloop_lock(mainloop);


for (;; ) {
for (;;) {
CHECK_DEAD_GOTO(fail, 1); CHECK_DEAD_GOTO(fail, 1);


if ((i = pa_stream_get_timing_info(stream)))
{
if ((i = pa_stream_get_timing_info(stream))) {
break; break;
} }
if (pa_context_errno(context) != PA_ERR_NODATA) { if (pa_context_errno(context) != PA_ERR_NODATA) {
} }


r = i->playing; r = i->playing;
memcpy((void*)the_timing_info, (void*)i, sizeof(pa_timing_info));
memcpy((void *)the_timing_info, (void *)i, sizeof(pa_timing_info));


fail: fail:
pa_threaded_mainloop_unlock(mainloop); pa_threaded_mainloop_unlock(mainloop);
return r; return r;
} }


static void pulse_write(void* ptr, int length) {
static void pulse_write(void *ptr, int length) {
ENTER(__FUNCTION__); ENTER(__FUNCTION__);






if (!success) { if (!success) {
SHOW("pa_stream_drain() failed: %s\n", pa_strerror(pa_context_errno(context))); SHOW("pa_stream_drain() failed: %s\n", pa_strerror(pa_context_errno(context)));
}
else {
} else {
ret = PULSE_OK; ret = PULSE_OK;
} }


assert(!stream); assert(!stream);
assert(!connected); assert(!connected);


pthread_mutex_init( &pulse_mutex, (const pthread_mutexattr_t *)NULL);
pthread_mutex_init(&pulse_mutex, (const pthread_mutexattr_t *)NULL);


ss.format = ESPEAK_FORMAT; ss.format = ESPEAK_FORMAT;
ss.rate = wave_samplerate; ss.rate = wave_samplerate;


SHOW_TIME("pa_threaded_mainloop_new (call)"); SHOW_TIME("pa_threaded_mainloop_new (call)");
if (!(mainloop = pa_threaded_mainloop_new())) { if (!(mainloop = pa_threaded_mainloop_new())) {
SHOW("Failed to allocate main loop\n","");
SHOW("Failed to allocate main loop\n", "");
goto fail; goto fail;
} }




SHOW_TIME("pa_context_new (call)"); SHOW_TIME("pa_context_new (call)");
if (!(context = pa_context_new(pa_threaded_mainloop_get_api(mainloop), "eSpeak"))) { if (!(context = pa_context_new(pa_threaded_mainloop_get_api(mainloop), "eSpeak"))) {
SHOW("Failed to allocate context\n","");
SHOW("Failed to allocate context\n", "");
goto unlock_and_fail; goto unlock_and_fail;
} }




SHOW_TIME("pa_threaded_mainloop_start (call)"); SHOW_TIME("pa_threaded_mainloop_start (call)");
if (pa_threaded_mainloop_start(mainloop) < 0) { if (pa_threaded_mainloop_start(mainloop) < 0) {
SHOW("Failed to start main loop","");
SHOW("Failed to start main loop", "");
goto unlock_and_fail; goto unlock_and_fail;
} }


pa_threaded_mainloop_free(mainloop); pa_threaded_mainloop_free(mainloop);
mainloop = NULL; mainloop = NULL;
} }
}
else {
} else {
pulse_close(); pulse_close();
} }




} }


void wave_flush(void* theHandler)
void wave_flush(void *theHandler)
{ {
ENTER("wave_flush"); ENTER("wave_flush");
} }


void wave_set_callback_is_output_enabled(t_wave_callback* cb)
void wave_set_callback_is_output_enabled(t_wave_callback *cb)
{ {
my_callback_is_output_enabled = cb; my_callback_is_output_enabled = cb;
} }
return pulse_open() == PULSE_OK; return pulse_open() == PULSE_OK;
} }


void* wave_open(const char* the_api)
void *wave_open(const char *the_api)
{ {
ENTER("wave_open"); ENTER("wave_open");
return((void*)1);
return (void *)1;
} }


size_t wave_write(void* theHandler, char* theMono16BitsWaveBuffer, size_t theSize)
size_t wave_write(void *theHandler, char *theMono16BitsWaveBuffer, size_t theSize)
{ {
ENTER("wave_write"); ENTER("wave_write");
size_t bytes_to_write = theSize; size_t bytes_to_write = theSize;
char* aBuffer=theMono16BitsWaveBuffer;
char *aBuffer = theMono16BitsWaveBuffer;


assert(stream); assert(stream);


size_t aTotalFreeMem=0;
size_t aTotalFreeMem = 0;


pthread_mutex_lock(&pulse_mutex); pthread_mutex_lock(&pulse_mutex);


while (1)
{
while (1) {
if (my_callback_is_output_enabled if (my_callback_is_output_enabled
&& (0==my_callback_is_output_enabled()))
{
&& (0 == my_callback_is_output_enabled())) {
SHOW_TIME("wave_write > my_callback_is_output_enabled: no!"); SHOW_TIME("wave_write > my_callback_is_output_enabled: no!");
theSize=0;
theSize = 0;
goto terminate; goto terminate;
} }


aTotalFreeMem = pulse_free(); aTotalFreeMem = pulse_free();
if (aTotalFreeMem >= bytes_to_write)
{
if (aTotalFreeMem >= bytes_to_write) {
SHOW("wave_write > aTotalFreeMem(%d) >= bytes_to_write(%d)\n", aTotalFreeMem, bytes_to_write); SHOW("wave_write > aTotalFreeMem(%d) >= bytes_to_write(%d)\n", aTotalFreeMem, bytes_to_write);
break; break;
} }


// TBD: check if really helpful // TBD: check if really helpful
if (aTotalFreeMem >= MAXLENGTH*2)
{
if (aTotalFreeMem >= MAXLENGTH*2) {
aTotalFreeMem = MAXLENGTH*2; aTotalFreeMem = MAXLENGTH*2;
} }


SHOW("wave_write > wait: aTotalFreeMem(%d) < bytes_to_write(%d)\n", aTotalFreeMem, bytes_to_write); SHOW("wave_write > wait: aTotalFreeMem(%d) < bytes_to_write(%d)\n", aTotalFreeMem, bytes_to_write);


// 500: threshold for avoiding too many calls to pulse_write // 500: threshold for avoiding too many calls to pulse_write
if (aTotalFreeMem>500)
{
if (aTotalFreeMem > 500) {
pulse_write(aBuffer, aTotalFreeMem); pulse_write(aBuffer, aTotalFreeMem);
bytes_to_write -= aTotalFreeMem; bytes_to_write -= aTotalFreeMem;
aBuffer += aTotalFreeMem; aBuffer += aTotalFreeMem;
return theSize; return theSize;
} }


int wave_close(void* theHandler)
int wave_close(void *theHandler)
{ {
SHOW_TIME("wave_close > ENTER"); SHOW_TIME("wave_close > ENTER");
static int aStopStreamCount = 0; static int aStopStreamCount = 0;
// Avoid race condition by making sure this function only // Avoid race condition by making sure this function only
// gets called once at a time // gets called once at a time
aStopStreamCount++; aStopStreamCount++;
if (aStopStreamCount != 1)
{
if (aStopStreamCount != 1) {
SHOW_TIME("wave_close > LEAVE (stopStreamCount)"); SHOW_TIME("wave_close > LEAVE (stopStreamCount)");
return 0; return 0;
} }


int a_status = pthread_mutex_lock(&pulse_mutex); int a_status = pthread_mutex_lock(&pulse_mutex);
if (a_status)
{
if (a_status) {
SHOW("Error: pulse_mutex lock=%d (%s)\n", a_status, __FUNCTION__); SHOW("Error: pulse_mutex lock=%d (%s)\n", a_status, __FUNCTION__);
aStopStreamCount = 0; // last action aStopStreamCount = 0; // last action
return PULSE_ERROR; return PULSE_ERROR;
return PULSE_OK; return PULSE_OK;
} }


int wave_is_busy(void* theHandler)
int wave_is_busy(void *theHandler)
{ {
SHOW_TIME("wave_is_busy"); SHOW_TIME("wave_is_busy");


pa_timing_info a_timing_info; pa_timing_info a_timing_info;
int active = pulse_playing(&a_timing_info); int active = pulse_playing(&a_timing_info);
SHOW("wave_is_busy: %d\n",active);
SHOW("wave_is_busy: %d\n", active);
return active; return active;
} }


ENTER("wave_terminate"); ENTER("wave_terminate");


int a_status; int a_status;
pthread_mutex_t* a_mutex = NULL;
pthread_mutex_t *a_mutex = NULL;
a_mutex = &pulse_mutex; a_mutex = &pulse_mutex;
a_status = pthread_mutex_lock(a_mutex); a_status = pthread_mutex_lock(a_mutex);


pthread_mutex_destroy(a_mutex); pthread_mutex_destroy(a_mutex);
} }


uint32_t wave_get_read_position(void* theHandler)
uint32_t wave_get_read_position(void *theHandler)
{ {
pa_timing_info a_timing_info; pa_timing_info a_timing_info;
pulse_playing(&a_timing_info); pulse_playing(&a_timing_info);
return a_timing_info.read_index; return a_timing_info.read_index;
} }


uint32_t wave_get_write_position(void* theHandler)
uint32_t wave_get_write_position(void *theHandler)
{ {
pa_timing_info a_timing_info; pa_timing_info a_timing_info;
pulse_playing(&a_timing_info); pulse_playing(&a_timing_info);
return a_timing_info.write_index; return a_timing_info.write_index;
} }


int wave_get_remaining_time(uint32_t sample, uint32_t* time)
int wave_get_remaining_time(uint32_t sample, uint32_t *time)
{ {
double a_time=0;
double a_time = 0;


if (!time || !stream)
{
SHOW("event get_remaining_time> %s\n","audio device not available");
if (!time || !stream) {
SHOW("event get_remaining_time> %s\n", "audio device not available");
return -1; return -1;
} }


pa_timing_info a_timing_info; pa_timing_info a_timing_info;
pulse_playing(&a_timing_info); pulse_playing(&a_timing_info);


if (sample > a_timing_info.read_index)
{
if (sample > a_timing_info.read_index) {
// TBD: take in account time suplied by portaudio V18 API // TBD: take in account time suplied by portaudio V18 API
a_time = sample - a_timing_info.read_index; a_time = sample - a_timing_info.read_index;
a_time = 0.5 + (a_time * 1000.0) / wave_samplerate; a_time = 0.5 + (a_time * 1000.0) / wave_samplerate;
}
else
{
} else {
a_time = 0; a_time = 0;
} }




int wave_init(return 1; ) { int wave_init(return 1; ) {
} }
void* wave_open(const char* the_api) {
void *wave_open(const char *the_api) {
return (void *)1; return (void *)1;
} }
size_t wave_write(void* theHandler, char* theMono16BitsWaveBuffer, size_t theSize) {
size_t wave_write(void *theHandler, char *theMono16BitsWaveBuffer, size_t theSize) {
return theSize; return theSize;
} }
int wave_close(void* theHandler) {
int wave_close(void *theHandler) {
return 0; return 0;
} }
int wave_is_busy(void* theHandler) {
int wave_is_busy(void *theHandler) {
return 0; return 0;
} }
void wave_terminate() { void wave_terminate() {
} }
uint32_t wave_get_read_position(void* theHandler) {
uint32_t wave_get_read_position(void *theHandler) {
return 0; return 0;
} }
uint32_t wave_get_write_position(void* theHandler) {
uint32_t wave_get_write_position(void *theHandler) {
return 0; return 0;
} }
void wave_flush(void* theHandler) {
void wave_flush(void *theHandler) {
} }
typedef int (t_wave_callback)(void); typedef int (t_wave_callback)(void);
void wave_set_callback_is_output_enabled(t_wave_callback* cb) {
void wave_set_callback_is_output_enabled(t_wave_callback *cb) {
} }
extern void* wave_test_get_write_buffer() {
extern void *wave_test_get_write_buffer() {
return NULL; return NULL;
} }


int wave_get_remaining_time(uint32_t sample, uint32_t* time)
int wave_get_remaining_time(uint32_t sample, uint32_t *time)
{ {
if (!time) return(-1);
if (!time) return -1;
*time = (uint32_t)0; *time = (uint32_t)0;
return 0; return 0;
} }
{ {
struct timeval tv; struct timeval tv;


if (!ts)
{
if (!ts) {
return; return;
} }


assert (gettimeofday(&tv, NULL) != -1);
assert(gettimeofday(&tv, NULL) != -1);
ts->tv_sec = tv.tv_sec; ts->tv_sec = tv.tv_sec;
ts->tv_nsec = tv.tv_usec*1000; ts->tv_nsec = tv.tv_usec*1000;
} }


void add_time_in_ms(struct timespec *ts, int time_in_ms) void add_time_in_ms(struct timespec *ts, int time_in_ms)
{ {
if (!ts)
{
if (!ts) {
return; return;
} }


uint64_t t_ns = (uint64_t)ts->tv_nsec + 1000000 * (uint64_t)time_in_ms; uint64_t t_ns = (uint64_t)ts->tv_nsec + 1000000 * (uint64_t)time_in_ms;
while(t_ns >= ONE_BILLION)
{
while (t_ns >= ONE_BILLION) {
SHOW("event > add_time_in_ms ns: %d sec %Lu nsec \n", ts->tv_sec, t_ns); SHOW("event > add_time_in_ms ns: %d sec %Lu nsec \n", ts->tv_sec, t_ns);
ts->tv_sec += 1; ts->tv_sec += 1;
t_ns -= ONE_BILLION; t_ns -= ONE_BILLION;

+ 40
- 44
src/libespeak-ng/wave_sada.c View File

#include "wave.h" #include "wave.h"
#include "debug.h" #include "debug.h"


enum {ONE_BILLION=1000000000};
enum { ONE_BILLION = 1000000000 };
#define SAMPLE_RATE 22050 #define SAMPLE_RATE 22050
#define SAMPLE_SIZE 16 #define SAMPLE_SIZE 16


#ifdef USE_SADA #ifdef USE_SADA


static t_wave_callback* my_callback_is_output_enabled=NULL;
static t_wave_callback *my_callback_is_output_enabled = NULL;


static const char *sun_audio_device = "/dev/audio"; static const char *sun_audio_device = "/dev/audio";
static int sun_audio_fd = -1; static int sun_audio_fd = -1;


// The last known playing index after a call to wave_close. // The last known playing index after a call to wave_close.
// //
static uint32_t last_play_position=0;
static uint32_t last_play_position = 0;


static uint32_t wave_samplerate; static uint32_t wave_samplerate;


SHOW("wave_init() sun_audio_fd: %d\n", sun_audio_fd); SHOW("wave_init() sun_audio_fd: %d\n", sun_audio_fd);


if (sun_audio_fd < 0) { if (sun_audio_fd < 0) {
return(0);
return 0;
} }


ioctl(sun_audio_fd, AUDIO_GETINFO, &ainfo); ioctl(sun_audio_fd, AUDIO_GETINFO, &ainfo);
if (ioctl(sun_audio_fd, AUDIO_SETINFO, &ainfo) == -1) { if (ioctl(sun_audio_fd, AUDIO_SETINFO, &ainfo) == -1) {
SHOW("wave_init() failed to set audio params: %s\n", strerror(errno)); SHOW("wave_init() failed to set audio params: %s\n", strerror(errno));
close(sun_audio_fd); close(sun_audio_fd);
return(0);
return 0;
} }
return(1);
return 1;
} }


// wave_open // wave_open
// sun_audio_fd opened in wave_init, which is passed in as theHandler // sun_audio_fd opened in wave_init, which is passed in as theHandler
// parameter in all other methods // parameter in all other methods
// //
void* wave_open(const char* the_api)
void *wave_open(const char *the_api)
{ {
ENTER("wave_open"); ENTER("wave_open");
return((void*) sun_audio_fd);
return (void *)sun_audio_fd;
} }


// wave_write // wave_write
// //
// the number of bytes (not 16-bit samples) sent // the number of bytes (not 16-bit samples) sent
// //
size_t wave_write(void* theHandler,
char* theMono16BitsWaveBuffer,
size_t wave_write(void *theHandler,
char *theMono16BitsWaveBuffer,
size_t theSize) size_t theSize)
{ {
size_t num; size_t num;
ENTER("wave_write"); ENTER("wave_write");
if (my_callback_is_output_enabled && (0==my_callback_is_output_enabled())) {
if (my_callback_is_output_enabled && (0 == my_callback_is_output_enabled())) {
SHOW_TIME("wave_write > my_callback_is_output_enabled: no!"); SHOW_TIME("wave_write > my_callback_is_output_enabled: no!");
return 0; return 0;
} }
char *out_end; char *out_end;
out_ptr = (char *)theMono16BitsWaveBuffer; out_ptr = (char *)theMono16BitsWaveBuffer;
out_end = out_ptr + theSize; out_end = out_ptr + theSize;
while(out_ptr < out_end)
{
while (out_ptr < out_end) {
c = out_ptr[0]; c = out_ptr[0];
out_ptr[0] = out_ptr[1]; out_ptr[0] = out_ptr[1];
out_ptr[1] = c; out_ptr[1] = c;
} }
#endif #endif


num = write((int) theHandler, theMono16BitsWaveBuffer, theSize);
num = write((int)theHandler, theMono16BitsWaveBuffer, theSize);


// Keep track of the total number of samples sent -- we use this in // Keep track of the total number of samples sent -- we use this in
// wave_get_read_position and also use it to help calculate the // wave_get_read_position and also use it to help calculate the
// //
// The result of the ioctl call (non-0 means failure) // The result of the ioctl call (non-0 means failure)
// //
int wave_close(void* theHandler)
int wave_close(void *theHandler)
{ {
int ret; int ret;
audio_info_t ainfo; audio_info_t ainfo;
int audio_fd = (int) theHandler;
int audio_fd = (int)theHandler;
if (!audio_fd) { if (!audio_fd) {
audio_fd = sun_audio_fd; audio_fd = sun_audio_fd;
} }
// //
// A non-0 value if audio is being played // A non-0 value if audio is being played
// //
int wave_is_busy(void* theHandler)
int wave_is_busy(void *theHandler)
{ {
uint32_t time; uint32_t time;
if (total_samples_sent >= 1) { if (total_samples_sent >= 1) {
// //
// theHandler: the audio device file descriptor // theHandler: the audio device file descriptor
// //
void wave_flush(void* theHandler)
void wave_flush(void *theHandler)
{ {
ENTER("wave_flush"); ENTER("wave_flush");
SHOW_TIME("wave_flush > LEAVE"); SHOW_TIME("wave_flush > LEAVE");
// //
// cb: the callback to call from wave_write // cb: the callback to call from wave_write
// //
void wave_set_callback_is_output_enabled(t_wave_callback* cb)
void wave_set_callback_is_output_enabled(t_wave_callback *cb)
{ {
my_callback_is_output_enabled = cb; my_callback_is_output_enabled = cb;
} }
// The total number of 16-bit samples played by the audio system // The total number of 16-bit samples played by the audio system
// so far. // so far.
// //
uint32_t wave_get_read_position(void* theHandler)
uint32_t wave_get_read_position(void *theHandler)
{ {
audio_info_t ainfo; audio_info_t ainfo;
ENTER("wave_get_read_position"); ENTER("wave_get_read_position");
ioctl((int) theHandler, AUDIO_GETINFO, &ainfo);
ioctl((int)theHandler, AUDIO_GETINFO, &ainfo);
SHOW("wave_get_read_position: %d\n", ainfo.play.samples); SHOW("wave_get_read_position: %d\n", ainfo.play.samples);
SHOW_TIME("wave_get_read_position > LEAVE"); SHOW_TIME("wave_get_read_position > LEAVE");
return ainfo.play.samples; return ainfo.play.samples;
// the index wraps back to 0. We don't handle that wrapping, so // the index wraps back to 0. We don't handle that wrapping, so
// the behavior after 54 hours of play time is undefined.]]] // the behavior after 54 hours of play time is undefined.]]]
// //
uint32_t wave_get_write_position(void* theHandler)
uint32_t wave_get_write_position(void *theHandler)
{ {
ENTER("wave_get_write_position"); ENTER("wave_get_write_position");
SHOW("wave_get_write_position: %d\n", total_samples_sent); SHOW("wave_get_write_position: %d\n", total_samples_sent);
// Time in milliseconds before the sample is played or 0 if the sample // Time in milliseconds before the sample is played or 0 if the sample
// is currently playing or has already been played. // is currently playing or has already been played.
// //
int wave_get_remaining_time(uint32_t sample, uint32_t* time)
int wave_get_remaining_time(uint32_t sample, uint32_t *time)
{ {
uint32_t a_time=0;
uint32_t a_time = 0;
uint32_t actual_index; uint32_t actual_index;


audio_info_t ainfo; audio_info_t ainfo;
ENTER("wave_get_remaining_time"); ENTER("wave_get_remaining_time");
if (!time) { if (!time) {
return(-1);
return -1;
SHOW_TIME("wave_get_remaining_time > LEAVE"); SHOW_TIME("wave_get_remaining_time > LEAVE");
} }


*time = 0; *time = 0;
} else { } else {
a_time = ((actual_index - ainfo.play.samples) * 1000) / wave_samplerate; a_time = ((actual_index - ainfo.play.samples) * 1000) / wave_samplerate;
*time = (uint32_t) a_time;
*time = (uint32_t)a_time;
} }
SHOW("wave_get_remaining_time for %d: %d\n", sample, *time); SHOW("wave_get_remaining_time for %d: %d\n", sample, *time);
SHOW_TIME("wave_get_remaining_time > LEAVE"); SHOW_TIME("wave_get_remaining_time > LEAVE");
init wave_init() { init wave_init() {
return 1; return 1;
} }
void* wave_open(const char* the_api) {
void *wave_open(const char *the_api) {
return (void *)1; return (void *)1;
} }
size_t wave_write(void* theHandler, char* theMono16BitsWaveBuffer, size_t theSize) {
size_t wave_write(void *theHandler, char *theMono16BitsWaveBuffer, size_t theSize) {
return theSize; return theSize;
} }
int wave_close(void* theHandler) {
int wave_close(void *theHandler) {
return 0; return 0;
} }
int wave_is_busy(void* theHandler) {
int wave_is_busy(void *theHandler) {
return 0; return 0;
} }
void wave_terminate() { void wave_terminate() {
} }
uint32_t wave_get_read_position(void* theHandler) {
uint32_t wave_get_read_position(void *theHandler) {
return 0; return 0;
} }
uint32_t wave_get_write_position(void* theHandler) {
uint32_t wave_get_write_position(void *theHandler) {
return 0; return 0;
} }
void wave_flush(void* theHandler) {
void wave_flush(void *theHandler) {
} }
typedef int (t_wave_callback)(void); typedef int (t_wave_callback)(void);
void wave_set_callback_is_output_enabled(t_wave_callback* cb) {
void wave_set_callback_is_output_enabled(t_wave_callback *cb) {
} }
extern void* wave_test_get_write_buffer() {
extern void *wave_test_get_write_buffer() {
return NULL; return NULL;
} }


int wave_get_remaining_time(uint32_t sample, uint32_t* time)
int wave_get_remaining_time(uint32_t sample, uint32_t *time)
{ {
if (!time) return(-1);
if (!time) return -1;
*time = (uint32_t)0; *time = (uint32_t)0;
return 0; return 0;
} }
{ {
struct timeval tv; struct timeval tv;


if (!ts)
{
if (!ts) {
return; return;
} }


assert (gettimeofday(&tv, NULL) != -1);
assert(gettimeofday(&tv, NULL) != -1);
ts->tv_sec = tv.tv_sec; ts->tv_sec = tv.tv_sec;
ts->tv_nsec = tv.tv_usec*1000; ts->tv_nsec = tv.tv_usec*1000;
} }


void add_time_in_ms(struct timespec *ts, int time_in_ms) void add_time_in_ms(struct timespec *ts, int time_in_ms)
{ {
if (!ts)
{
if (!ts) {
return; return;
} }


uint64_t t_ns = (uint64_t)ts->tv_nsec + 1000000 * (uint64_t)time_in_ms; uint64_t t_ns = (uint64_t)ts->tv_nsec + 1000000 * (uint64_t)time_in_ms;
while(t_ns >= ONE_BILLION)
{
while (t_ns >= ONE_BILLION) {
SHOW("event > add_time_in_ms ns: %d sec %Lu nsec \n", ts->tv_sec, t_ns); SHOW("event > add_time_in_ms ns: %d sec %Lu nsec \n", ts->tv_sec, t_ns);
ts->tv_sec += 1; ts->tv_sec += 1;
t_ns -= ONE_BILLION; t_ns -= ONE_BILLION;

+ 336
- 469
src/libespeak-ng/wavegen.c
File diff suppressed because it is too large
View File


+ 199
- 267
src/speak-ng.c View File

const espeak_VOICE **voices; const espeak_VOICE **voices;
espeak_VOICE voice_select; espeak_VOICE voice_select;


static char genders[4] = {'-','M','F','-'};
static char genders[4] = { '-', 'M', 'F', '-' };


if((language != NULL) && (language[0] != 0))
{
if ((language != NULL) && (language[0] != 0)) {
// display only voices for the specified language, in order of priority // display only voices for the specified language, in order of priority
voice_select.languages = language; voice_select.languages = language;
voice_select.age = 0; voice_select.age = 0;
voice_select.gender = 0; voice_select.gender = 0;
voice_select.name = NULL; voice_select.name = NULL;
voices = espeak_ListVoices(&voice_select); voices = espeak_ListVoices(&voice_select);
}
else
{
} else {
voices = espeak_ListVoices(NULL); voices = espeak_ListVoices(NULL);
} }


fprintf(f_out,"Pty Language Age/Gender VoiceName File Other Languages\n");
fprintf(f_out, "Pty Language Age/Gender VoiceName File Other Languages\n");


for(ix=0; (v = voices[ix]) != NULL; ix++)
{
for (ix = 0; (v = voices[ix]) != NULL; ix++) {
count = 0; count = 0;
p = v->languages; p = v->languages;
while(*p != 0)
{
while (*p != 0) {
len = strlen(p+1); len = strlen(p+1);
lang_name = p+1; lang_name = p+1;


if(v->age == 0)
strcpy(age_buf," ");
if (v->age == 0)
strcpy(age_buf, " ");
else else
sprintf(age_buf,"%3d",v->age);
sprintf(age_buf, "%3d", v->age);


if(count==0)
{
for(j=0; j < sizeof(buf); j++)
{
if (count == 0) {
for (j = 0; j < sizeof(buf); j++) {
// replace spaces in the name // replace spaces in the name
if((c = v->name[j]) == ' ')
if ((c = v->name[j]) == ' ')
c = '_'; c = '_';
if((buf[j] = c) == 0)
if ((buf[j] = c) == 0)
break; break;
} }
fprintf(f_out,"%2d %-12s%s%c %-20s %-13s ",
p[0],lang_name,age_buf,genders[v->gender],buf,v->identifier);
}
else
{
fprintf(f_out,"(%s %d)",lang_name,p[0]);
fprintf(f_out, "%2d %-12s%s%c %-20s %-13s ",
p[0], lang_name, age_buf, genders[v->gender], buf, v->identifier);
} else {
fprintf(f_out, "(%s %d)", lang_name, p[0]);
} }
count++; count++;
p += len+2; p += len+2;
} }
fputc('\n',f_out);
fputc('\n', f_out);
} }
} }


// Set the length of 0x7ffff000 for --stdout // Set the length of 0x7ffff000 for --stdout
// This will be changed to the correct length for -w (write to file) // This will be changed to the correct length for -w (write to file)
static unsigned char wave_hdr[44] = { static unsigned char wave_hdr[44] = {
'R','I','F','F',0x24,0xf0,0xff,0x7f,'W','A','V','E','f','m','t',' ',
0x10,0,0,0,1,0,1,0, 9,0x3d,0,0,0x12,0x7a,0,0,
2,0,0x10,0,'d','a','t','a', 0x00,0xf0,0xff,0x7f
'R', 'I', 'F', 'F', 0x24, 0xf0, 0xff, 0x7f, 'W', 'A', 'V', 'E', 'f', 'm', 't', ' ',
0x10, 0, 0, 0, 1, 0, 1, 0, 9, 0x3d, 0, 0, 0x12, 0x7a, 0, 0,
2, 0, 0x10, 0, 'd', 'a', 't', 'a', 0x00, 0xf0, 0xff, 0x7f
}; };


if(path == NULL)
return(2);
if (path == NULL)
return 2;


while(isspace(*path)) path++;
while (isspace(*path)) path++;


f_wave = NULL; f_wave = NULL;
if(path[0] != 0)
{
if(strcmp(path,"stdout")==0)
{
if (path[0] != 0) {
if (strcmp(path, "stdout") == 0) {
#ifdef PLATFORM_WINDOWS #ifdef PLATFORM_WINDOWS
// prevent Windows adding 0x0d before 0x0a bytes // prevent Windows adding 0x0d before 0x0a bytes
_setmode(_fileno(stdout), _O_BINARY); _setmode(_fileno(stdout), _O_BINARY);
#endif #endif
f_wave = stdout; f_wave = stdout;
}
else
f_wave = fopen(path,"wb");
} else
f_wave = fopen(path, "wb");
} }


if(f_wave != NULL)
{
fwrite(wave_hdr,1,24,f_wave);
Write4Bytes(f_wave,rate);
Write4Bytes(f_wave,rate * 2);
fwrite(&wave_hdr[32],1,12,f_wave);
return(0);
if (f_wave != NULL) {
fwrite(wave_hdr, 1, 24, f_wave);
Write4Bytes(f_wave, rate);
Write4Bytes(f_wave, rate * 2);
fwrite(&wave_hdr[32], 1, 12, f_wave);
return 0;
} }
return(1);
return 1;
} }




{ {
unsigned int pos; unsigned int pos;


if((f_wave == NULL) || (f_wave == stdout))
if ((f_wave == NULL) || (f_wave == stdout))
return; return;


fflush(f_wave); fflush(f_wave);
pos = ftell(f_wave); pos = ftell(f_wave);


fseek(f_wave,4,SEEK_SET);
Write4Bytes(f_wave,pos - 8);
fseek(f_wave, 4, SEEK_SET);
Write4Bytes(f_wave, pos - 8);


fseek(f_wave,40,SEEK_SET);
Write4Bytes(f_wave,pos - 44);
fseek(f_wave, 40, SEEK_SET);
Write4Bytes(f_wave, pos - 44);




fclose(f_wave); fclose(f_wave);


finished = WavegenFill(0); finished = WavegenFill(0);


if(quiet)
return(finished);
if (quiet)
return finished;


if(f_wave == NULL)
{
sprintf(fname,"%s_%.2d%s",wavefile,++wavefile_count,filetype);
if(OpenWaveFile(fname, samplerate) != 0)
return(1);
if (f_wave == NULL) {
sprintf(fname, "%s_%.2d%s", wavefile, ++wavefile_count, filetype);
if (OpenWaveFile(fname, samplerate) != 0)
return 1;
} }


if(end_of_sentence)
{
if (end_of_sentence) {
end_of_sentence = 0; end_of_sentence = 0;
if((samples_split > 0 ) && (samples_total > samples_split))
{
if ((samples_split > 0 ) && (samples_total > samples_split)) {
CloseWaveFile(); CloseWaveFile();
samples_total = 0; samples_total = 0;
} }
} }


if(f_wave != NULL)
{
if (f_wave != NULL) {
samples_total += (out_ptr - wav_outbuf)/2; samples_total += (out_ptr - wav_outbuf)/2;
fwrite(wav_outbuf, 1, out_ptr - wav_outbuf, f_wave); fwrite(wav_outbuf, 1, out_ptr - wav_outbuf, f_wave);
} }
return(finished);
return finished;
} }




static void init_path(char *argv0, char *path_specified) static void init_path(char *argv0, char *path_specified)
{ {


if(path_specified)
{
sprintf(path_home,"%s/espeak-data",path_specified);
if (path_specified) {
sprintf(path_home, "%s/espeak-data", path_specified);
return; return;
} }


char *env; char *env;
unsigned char buf[sizeof(path_home)-12]; unsigned char buf[sizeof(path_home)-12];


if(((env = getenv("ESPEAK_DATA_PATH")) != NULL) && ((strlen(env)+12) < sizeof(path_home)))
{
sprintf(path_home,"%s\\espeak-data",env);
if(GetFileLength(path_home) == -2)
if (((env = getenv("ESPEAK_DATA_PATH")) != NULL) && ((strlen(env)+12) < sizeof(path_home))) {
sprintf(path_home, "%s\\espeak-data", env);
if (GetFileLength(path_home) == -2)
return; // an espeak-data directory exists in the directory specified by environment variable return; // an espeak-data directory exists in the directory specified by environment variable
} }


strcpy(path_home,argv0);
if((p = strrchr(path_home,'\\')) != NULL)
{
strcpy(&p[1],"espeak-data");
if(GetFileLength(path_home) == -2)
strcpy(path_home, argv0);
if ((p = strrchr(path_home, '\\')) != NULL) {
strcpy(&p[1], "espeak-data");
if (GetFileLength(path_home) == -2)
return; // an espeak-data directory exists in the same directory as the espeak program return; // an espeak-data directory exists in the same directory as the espeak program
} }


var_type = REG_SZ; var_type = REG_SZ;
RegQueryValueEx(RegKey, "path", 0, &var_type, buf, &size); RegQueryValueEx(RegKey, "path", 0, &var_type, buf, &size);


sprintf(path_home,"%s\\espeak-data",buf);
sprintf(path_home, "%s\\espeak-data", buf);
#else #else
#ifdef PLATFORM_DOS #ifdef PLATFORM_DOS
strcpy(path_home,PATH_ESPEAK_DATA);
strcpy(path_home, PATH_ESPEAK_DATA);
#else #else
char *env; char *env;
if((env = getenv("ESPEAK_DATA_PATH")) != NULL)
{
snprintf(path_home,sizeof(path_home),"%s/espeak-data",env);
if(GetFileLength(path_home) == -2)
if ((env = getenv("ESPEAK_DATA_PATH")) != NULL) {
snprintf(path_home, sizeof(path_home), "%s/espeak-data", env);
if (GetFileLength(path_home) == -2)
return; // an espeak-data directory exists return; // an espeak-data directory exists
} }


snprintf(path_home,sizeof(path_home),"%s/espeak-data",getenv("HOME"));
if(access(path_home,R_OK) != 0)
{
strcpy(path_home,PATH_ESPEAK_DATA);
snprintf(path_home, sizeof(path_home), "%s/espeak-data", getenv("HOME"));
if (access(path_home, R_OK) != 0) {
strcpy(path_home, PATH_ESPEAK_DATA);
} }
#endif #endif
#endif #endif
// to something other than the default "C". Then, not only Latin1 but also the // to something other than the default "C". Then, not only Latin1 but also the
// other characters give the correct results with iswalpha() etc. // other characters give the correct results with iswalpha() etc.
#ifdef PLATFORM_RISCOS #ifdef PLATFORM_RISCOS
setlocale(LC_CTYPE,"ISO8859-1");
setlocale(LC_CTYPE, "ISO8859-1");
#else #else
if(setlocale(LC_CTYPE,"en_US.UTF-8") == NULL)
{
if(setlocale(LC_CTYPE,"UTF-8") == NULL)
setlocale(LC_CTYPE,"");
if (setlocale(LC_CTYPE, "en_US.UTF-8") == NULL) {
if (setlocale(LC_CTYPE, "UTF-8") == NULL)
setlocale(LC_CTYPE, "");
} }
#endif #endif




if((result = LoadPhData(&srate)) != 1)
{
if(result == -1)
{
fprintf(stderr,"Failed to load espeak-data\n");
if ((result = LoadPhData(&srate)) != 1) {
if (result == -1) {
fprintf(stderr, "Failed to load espeak-data\n");
exit(1); exit(1);
}
else
fprintf(stderr,"Wrong version of espeak-data 0x%x (expects 0x%x) at %s\n",result,version_phdata,path_home);
} else
fprintf(stderr, "Wrong version of espeak-data 0x%x (expects 0x%x) at %s\n", result, version_phdata, path_home);
} }
WavegenInit(srate,0);
WavegenInit(srate, 0);
LoadConfig(); LoadConfig();
SetVoiceStack(NULL, ""); SetVoiceStack(NULL, "");
SynthesizeInit(); SynthesizeInit();


for(param=0; param<N_SPEECH_PARAM; param++)
for (param = 0; param < N_SPEECH_PARAM; param++)
param_stack[0].parameter[param] = param_defaults[param]; param_stack[0].parameter[param] = param_defaults[param];


return(0);
return 0;
} }




int optind; int optind;
static int optional_argument; static int optional_argument;
static const char *arg_opts = "abfgklpsvw"; // which options have arguments static const char *arg_opts = "abfgklpsvw"; // which options have arguments
static char *opt_string="";
static char *opt_string = "";
#define no_argument 0 #define no_argument 0
#define required_argument 1 #define required_argument 1
#define optional_argument 2 #define optional_argument 2
#endif #endif


int main (int argc, char **argv)
int main(int argc, char **argv)
{ {
static struct option long_options[] =
{
{"help", no_argument, 0, 'h'},
{"stdin", no_argument, 0, 0x100},
{"compile-debug", optional_argument, 0, 0x101},
{"compile", optional_argument, 0, 0x102},
{"punct", optional_argument, 0, 0x103},
{"voices", optional_argument, 0, 0x104},
{"stdout", no_argument, 0, 0x105},
{"split", optional_argument, 0, 0x106},
{"path", required_argument, 0, 0x107},
{"phonout", required_argument, 0, 0x108},
{"pho", no_argument, 0, 0x109},
{"ipa", optional_argument, 0, 0x10a},
{"version", no_argument, 0, 0x10b},
{"sep", optional_argument, 0, 0x10c},
{"tie", optional_argument, 0, 0x10d},
{0, 0, 0, 0}
static struct option long_options[] = {
{ "help", no_argument, 0, 'h' },
{ "stdin", no_argument, 0, 0x100 },
{ "compile-debug", optional_argument, 0, 0x101 },
{ "compile", optional_argument, 0, 0x102 },
{ "punct", optional_argument, 0, 0x103 },
{ "voices", optional_argument, 0, 0x104 },
{ "stdout", no_argument, 0, 0x105 },
{ "split", optional_argument, 0, 0x106 },
{ "path", required_argument, 0, 0x107 },
{ "phonout", required_argument, 0, 0x108 },
{ "pho", no_argument, 0, 0x109 },
{ "ipa", optional_argument, 0, 0x10a },
{ "version", no_argument, 0, 0x10b },
{ "sep", optional_argument, 0, 0x10c },
{ "tie", optional_argument, 0, 0x10d },
{ 0, 0, 0, 0 }
}; };


static const char *err_load = "Failed to read "; static const char *err_load = "Failed to read ";


FILE *f_text=NULL;
const char *p_text=NULL;
FILE *f_text = NULL;
const char *p_text = NULL;
char *data_path = NULL; // use default path for espeak-data char *data_path = NULL; // use default path for espeak-data


int option_index = 0; int option_index = 0;
int c; int c;
int value; int value;
int speed=175;
int speed = 175;
int ix; int ix;
char *optarg2; char *optarg2;
int amp = 100; // default int amp = 100; // default
#ifdef NEED_GETOPT #ifdef NEED_GETOPT
optind = 1; optind = 1;
opt_string = ""; opt_string = "";
while(optind < argc)
{
while (optind < argc) {
int len; int len;
char *p; char *p;


if((c = *opt_string) == 0)
{
if ((c = *opt_string) == 0) {
opt_string = argv[optind]; opt_string = argv[optind];
if(opt_string[0] != '-')
if (opt_string[0] != '-')
break; break;


optind++; optind++;
opt_string++; opt_string++;
p = optarg2 = opt_string; p = optarg2 = opt_string;


if(c == '-')
{
if(p[0] == 0)
if (c == '-') {
if (p[0] == 0)
break; // -- means don't interpret further - as commands break; // -- means don't interpret further - as commands


opt_string="";
for(ix=0;; ix++)
{
if(long_options[ix].name == 0)
opt_string = "";
for (ix = 0;; ix++) {
if (long_options[ix].name == 0)
break; break;
len = strlen(long_options[ix].name); len = strlen(long_options[ix].name);
if(memcmp(long_options[ix].name,p,len)==0)
{
if (memcmp(long_options[ix].name, p, len) == 0) {
c = long_options[ix].val; c = long_options[ix].val;
optarg2 = NULL; optarg2 = NULL;


if((long_options[ix].has_arg != 0) && (p[len]=='='))
{
if ((long_options[ix].has_arg != 0) && (p[len] == '=')) {
optarg2 = &p[len+1]; optarg2 = &p[len+1];
} }
break; break;
} }
} }
}
else
if(strchr(arg_opts,c) != NULL)
{
opt_string="";
if(optarg2[0]==0)
{
} else if (strchr(arg_opts, c) != NULL) {
opt_string = "";
if (optarg2[0] == 0) {
// the option's value is in the next argument // the option's value is in the next argument
optarg2 = argv[optind++]; optarg2 = argv[optind++];
} }
} }
#else #else
while(true)
{
c = getopt_long (argc, argv, "a:b:f:g:hk:l:p:qs:v:w:xXmz", // NOTE: also change arg_opts to indicate which commands have a numeric value
long_options, &option_index);
while (true) {
c = getopt_long(argc, argv, "a:b:f:g:hk:l:p:qs:v:w:xXmz", // NOTE: also change arg_opts to indicate which commands have a numeric value
long_options, &option_index);


/* Detect the end of the options. */ /* Detect the end of the options. */
if (c == -1) if (c == -1)
case 'b': case 'b':
// input character encoding, 8bit, 16bit, UTF8 // input character encoding, 8bit, 16bit, UTF8
option_multibyte = espeakCHARS_8BIT; option_multibyte = espeakCHARS_8BIT;
if((sscanf(optarg2,"%d",&value) == 1) && (value <= 4))
option_multibyte= value;
if ((sscanf(optarg2, "%d", &value) == 1) && (value <= 4))
option_multibyte = value;
break; break;


case 'h': case 'h':
init_path(argv[0],data_path);
printf("\nspeak text-to-speech: %s Data at: %s\n%s",version_string,path_home,help_text);
init_path(argv[0], data_path);
printf("\nspeak text-to-speech: %s Data at: %s\n%s", version_string, path_home, help_text);
exit(0); exit(0);


case 'k': case 'k':


case 'p': case 'p':
pitch_adjustment = atoi(optarg2); pitch_adjustment = atoi(optarg2);
if(pitch_adjustment > 99) pitch_adjustment = 99;
if (pitch_adjustment > 99) pitch_adjustment = 99;
break; break;


case 'q': case 'q':
break; break;


case 'f': case 'f':
strncpy0(filename,optarg2,sizeof(filename));
strncpy0(filename, optarg2, sizeof(filename));
break; break;


case 'l': case 'l':
break; break;


case 'v': case 'v':
strncpy0(voicename,optarg2,sizeof(voicename));
strncpy0(voicename, optarg2, sizeof(voicename));
break; break;


case 'w': case 'w':
option_waveout = 1; option_waveout = 1;
strncpy0(wavefile,optarg2,sizeof(wavefile));
strncpy0(wavefile, optarg2, sizeof(wavefile));
break; break;


case 'z': case 'z':


case 0x105: // --stdout case 0x105: // --stdout
option_waveout = 1; option_waveout = 1;
strcpy(wavefile,"stdout");
strcpy(wavefile, "stdout");
break; break;


case 0x101: // --compile-debug case 0x101: // --compile-debug
case 0x102: // --compile case 0x102: // --compile
if(optarg2 != NULL)
strncpy0(voicename,optarg2,sizeof(voicename));
if (optarg2 != NULL)
strncpy0(voicename, optarg2, sizeof(voicename));
flag_compile = c; flag_compile = c;
break; break;


case 0x103: // --punct case 0x103: // --punct
option_punctuation = 1; option_punctuation = 1;
if(optarg2 != NULL)
{
if (optarg2 != NULL) {
ix = 0; ix = 0;
while((ix < N_PUNCTLIST) && ((option_punctlist[ix] = optarg2[ix]) != 0)) ix++;
while ((ix < N_PUNCTLIST) && ((option_punctlist[ix] = optarg2[ix]) != 0)) ix++;
option_punctlist[N_PUNCTLIST-1] = 0; option_punctlist[N_PUNCTLIST-1] = 0;
option_punctuation = 2; option_punctuation = 2;
} }
break; break;


case 0x104: // --voices case 0x104: // --voices
init_path(argv[0],data_path);
DisplayVoices(stdout,optarg2);
init_path(argv[0], data_path);
DisplayVoices(stdout, optarg2);
exit(0); exit(0);


case 0x106: // -- split case 0x106: // -- split
if(optarg2 == NULL)
if (optarg2 == NULL)
samples_split = 30; // default 30 minutes samples_split = 30; // default 30 minutes
else else
samples_split = atoi(optarg2); samples_split = atoi(optarg2);
break; break;


case 0x108: // --phonout case 0x108: // --phonout
if((f_trans = fopen(optarg2,"w")) == NULL)
{
fprintf(stderr,"Can't write to: %s\n",optarg2);
if ((f_trans = fopen(optarg2, "w")) == NULL) {
fprintf(stderr, "Can't write to: %s\n", optarg2);
f_trans = stderr; f_trans = stderr;
} }
break; break;


case 0x10a: // --ipa case 0x10a: // --ipa
phoneme_options |= espeakPHONEMES_IPA; phoneme_options |= espeakPHONEMES_IPA;
if(optarg2 != NULL)
{
if (optarg2 != NULL) {
// deprecated and obsolete // deprecated and obsolete
switch(atoi(optarg2))
switch (atoi(optarg2))
{ {
case 1: case 1:
phonemes_separator = '_'; phonemes_separator = '_';
break; break;


case 0x10b: // --version case 0x10b: // --version
init_path(argv[0],data_path);
printf("speak text-to-speech: %s Data at: %s\n",version_string,path_home);
init_path(argv[0], data_path);
printf("speak text-to-speech: %s Data at: %s\n", version_string, path_home);
exit(0); exit(0);


case 0x10c: // --sep case 0x10c: // --sep
phoneme_options |= espeakPHONEMES_SHOW; phoneme_options |= espeakPHONEMES_SHOW;
if(optarg2 == 0)
if (optarg2 == 0)
phonemes_separator = ' '; phonemes_separator = ' ';
else else
utf8_in(&phonemes_separator, optarg2); utf8_in(&phonemes_separator, optarg2);
if(phonemes_separator == 'z')
if (phonemes_separator == 'z')
phonemes_separator = 0x200c; // ZWNJ phonemes_separator = 0x200c; // ZWNJ
break; break;


case 0x10d: // --tie case 0x10d: // --tie
phoneme_options |= (espeakPHONEMES_SHOW | espeakPHONEMES_TIE); phoneme_options |= (espeakPHONEMES_SHOW | espeakPHONEMES_TIE);
if(optarg2 == 0)
if (optarg2 == 0)
phonemes_separator = 0x0361; // default: combining-double-inverted-breve phonemes_separator = 0x0361; // default: combining-double-inverted-breve
else else
utf8_in(&phonemes_separator, optarg2); utf8_in(&phonemes_separator, optarg2);
if(phonemes_separator == 'z')
if (phonemes_separator == 'z')
phonemes_separator = 0x200d; // ZWJ phonemes_separator = 0x200d; // ZWJ
break; break;


} }
} }


init_path(argv[0],data_path);
init_path(argv[0], data_path);
initialise(); initialise();


if(voicename[0] == 0)
strcpy(voicename,"default");
if (voicename[0] == 0)
strcpy(voicename, "default");


if(SetVoiceByName(voicename) != EE_OK)
{
memset(&voice_select,0,sizeof(voice_select));
if (SetVoiceByName(voicename) != EE_OK) {
memset(&voice_select, 0, sizeof(voice_select));
voice_select.languages = voicename; voice_select.languages = voicename;
if(SetVoiceByProperties(&voice_select) != EE_OK)
{
fprintf(stderr,"%svoice '%s'\n",err_load,voicename);
if (SetVoiceByProperties(&voice_select) != EE_OK) {
fprintf(stderr, "%svoice '%s'\n", err_load, voicename);
exit(2); exit(2);
} }
} }


if(flag_compile)
{
if (flag_compile) {
#ifdef PLATFORM_DOS #ifdef PLATFORM_DOS
char path_dsource[sizeof(path_home)+20]; char path_dsource[sizeof(path_home)+20];
strcpy(path_dsource,path_home);
strcpy(path_dsource, path_home);
path_dsource[strlen(path_home)-11] = 0; // remove "espeak-data" from the end path_dsource[strlen(path_home)-11] = 0; // remove "espeak-data" from the end
strcat(path_dsource,"dictsource\\");
CompileDictionary(path_dsource,dictionary_name,NULL,NULL, flag_compile & 0x1);
strcat(path_dsource, "dictsource\\");
CompileDictionary(path_dsource, dictionary_name, NULL, NULL, flag_compile & 0x1);
#else #else
#ifdef PLATFORM_WINDOWS #ifdef PLATFORM_WINDOWS
char path_dsource[sizeof(path_home)+20]; char path_dsource[sizeof(path_home)+20];
strcpy(path_dsource,path_home);
strcpy(path_dsource, path_home);
path_dsource[strlen(path_home)-11] = 0; // remove "espeak-data" from the end path_dsource[strlen(path_home)-11] = 0; // remove "espeak-data" from the end
strcat(path_dsource,"dictsource\\");
CompileDictionary(path_dsource,dictionary_name,NULL,NULL, flag_compile & 0x1);
strcat(path_dsource, "dictsource\\");
CompileDictionary(path_dsource, dictionary_name, NULL, NULL, flag_compile & 0x1);
#else #else
CompileDictionary(NULL,dictionary_name,NULL,NULL, flag_compile & 0x1);
CompileDictionary(NULL, dictionary_name, NULL, NULL, flag_compile & 0x1);
#endif #endif
#endif #endif
exit(0); exit(0);
} }




SetParameter(espeakRATE,speed,0);
SetParameter(espeakVOLUME,amp,0);
SetParameter(espeakCAPITALS,option_capitals,0);
SetParameter(espeakPUNCTUATION,option_punctuation,0);
SetParameter(espeakWORDGAP,wordgap,0);
SetParameter(espeakRATE, speed, 0);
SetParameter(espeakVOLUME, amp, 0);
SetParameter(espeakCAPITALS, option_capitals, 0);
SetParameter(espeakPUNCTUATION, option_punctuation, 0);
SetParameter(espeakWORDGAP, wordgap, 0);


option_phonemes = phoneme_options | (phonemes_separator << 8); option_phonemes = phoneme_options | (phonemes_separator << 8);


if(pitch_adjustment != 50)
{
SetParameter(espeakPITCH,pitch_adjustment,0);
if (pitch_adjustment != 50) {
SetParameter(espeakPITCH, pitch_adjustment, 0);
} }
DoVoiceChange(voice); DoVoiceChange(voice);


if(filename[0]==0)
{
if((optind < argc) && (flag_stdin == 0))
{
if (filename[0] == 0) {
if ((optind < argc) && (flag_stdin == 0)) {
// there's a non-option parameter, and no -f or --stdin // there's a non-option parameter, and no -f or --stdin
// use it as text // use it as text
p_text = argv[optind]; p_text = argv[optind];
}
else
{
} else {
f_text = stdin; f_text = stdin;
if(flag_stdin == 0)
if (flag_stdin == 0)
option_linelength = -1; // single input lines on stdin option_linelength = -1; // single input lines on stdin
} }
}
else
{
f_text = fopen(filename,"r");
} else {
f_text = fopen(filename, "r");
} }


if((f_text == NULL) && (p_text == NULL))
{
fprintf(stderr,"%sfile '%s'\n",err_load,filename);
if ((f_text == NULL) && (p_text == NULL)) {
fprintf(stderr, "%sfile '%s'\n", err_load, filename);
exit(1); exit(1);
} }


if(option_waveout || quiet)
{
if(quiet)
{
if (option_waveout || quiet) {
if (quiet) {
// no sound output // no sound output
OpenWaveFile(NULL,samplerate);
OpenWaveFile(NULL, samplerate);
option_waveout = 1; option_waveout = 1;
}
else
{
} else {
// write sound output to a WAV file // write sound output to a WAV file
samples_split = (samplerate * samples_split) * 60; samples_split = (samplerate * samples_split) * 60;


if(samples_split)
{
if (samples_split) {
// don't open the wav file until we start generating speech // don't open the wav file until we start generating speech
char *extn; char *extn;
extn = strrchr(wavefile,'.');
if((extn != NULL) && ((wavefile + strlen(wavefile) - extn) <= 4))
{
strcpy(filetype,extn);
extn = strrchr(wavefile, '.');
if ((extn != NULL) && ((wavefile + strlen(wavefile) - extn) <= 4)) {
strcpy(filetype, extn);
*extn = 0; *extn = 0;
} }
}
else
if(OpenWaveFile(wavefile,samplerate) != 0)
{
fprintf(stderr,"Can't write to output file '%s'\n'",wavefile);
} else if (OpenWaveFile(wavefile, samplerate) != 0) {
fprintf(stderr, "Can't write to output file '%s'\n'", wavefile);
exit(3); exit(3);
} }
} }


InitText(0); InitText(0);
SpeakNextClause(f_text,p_text,0);
SpeakNextClause(f_text, p_text, 0);


ix = 1; ix = 1;
for(;; )
{
if(WavegenFile() != 0)
{
if(ix == 0)
for (;;) {
if (WavegenFile() != 0) {
if (ix == 0)
break; // finished, wavegen command queue is empty break; // finished, wavegen command queue is empty
} }


if(Generate(phoneme_list,&n_phoneme_list,1)==0)
{
ix = SpeakNextClause(NULL,NULL,1);
if (Generate(phoneme_list, &n_phoneme_list, 1) == 0) {
ix = SpeakNextClause(NULL, NULL, 1);
} }
} }


CloseWaveFile(); CloseWaveFile();
}
else
{
} else {
WavegenInitSound(); WavegenInitSound();


InitText(0); InitText(0);
SpeakNextClause(f_text,p_text,0);
SpeakNextClause(f_text, p_text, 0);


if(option_quiet)
{
while(SpeakNextClause(NULL,NULL,1) != 0);
return(0);
if (option_quiet) {
while (SpeakNextClause(NULL, NULL, 1) != 0) ;
return 0;
} }


speaking = 1; speaking = 1;
while(speaking)
{
while (speaking) {
// NOTE: if nanosleep() isn't recognised on your system, try replacing // NOTE: if nanosleep() isn't recognised on your system, try replacing
// this by sleep(1); // this by sleep(1);
#ifdef PLATFORM_WINDOWS #ifdef PLATFORM_WINDOWS
struct timespec remaining; struct timespec remaining;
period.tv_sec = 0; period.tv_sec = 0;
period.tv_nsec = 300000000; // 0.3 sec period.tv_nsec = 300000000; // 0.3 sec
nanosleep(&period,&remaining);
nanosleep(&period, &remaining);
#else #else
sleep(1); sleep(1);
#endif #endif
#endif #endif
if(SynthOnTimer() != 0)
if (SynthOnTimer() != 0)
speaking = 0; speaking = 0;
} }
} }


if((f_trans != stdout) && (f_trans != stderr))
if ((f_trans != stdout) && (f_trans != stderr))
fclose(f_trans); // needed for WinCe fclose(f_trans); // needed for WinCe
return(0);
return 0;
} }

Loading…
Cancel
Save