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

@@ -41,8 +41,9 @@ libespeak-ng.a
libespeak-ng.la
libespeak-ng.so*

# programs
# build output

*.html
*.exe

src/espeak-ng

+ 10
- 3
Makefile.am View File

@@ -50,15 +50,22 @@ distclean-local:
rm -rf espeak-data/phondata-manifest
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:

libespeak_ng_includedir = $(includedir)/espeak-ng
libespeak_ng_include_HEADERS = \
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

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

+ 37
- 16
README.md View File

@@ -39,31 +39,52 @@ Optionally, you need:
2. the portaudio development library to enable portaudio output;
3. the sonic development library to enable sonic audio speed up support.

To build the documentation, you need:

1. the `kramdown` markdown processor.

### Debian

Core dependencies:

| Dependency | Install |
|---------------|------------------------------------------------------------------|
| autotools | `sudo apt-get install make autoconf automake libtool pkg-config` |
| 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:

| 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

The `espeak-ng` and `speak-ng` programs, along with the espeak-ng voices, can
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

@@ -134,7 +155,7 @@ __NOTE:__ This currently fails to build `espeak-ng.exe`, but does build

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 source tree. Otherwise, espeak-ng will look in `$(HOME)` or
@@ -149,7 +170,7 @@ version).

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
is for 64-bit Debian/Ubuntu releases that use the multi-arch package
@@ -158,19 +179,19 @@ structure -- that is, Debian Wheezy or later).
You can find out where espeak-ng is installed to on your system if you
already have an espeak-ng install by running:

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

## Building Voices

If you are modifying a language's phoneme, voice or dictionary files, you
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
run:

$ make en
make en

to build an English voice file with those changes in without rebuilding
all the voices. This will make it easier to spot errors.
@@ -206,7 +227,7 @@ These early releases have been checked into the historical branch,
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:

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

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

+ 54
- 0
_layouts/webpage.html View File

@@ -0,0 +1,54 @@
<!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

@@ -31,7 +31,7 @@
#include "speak_lib.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 GetFileLength(const char *filename);

@@ -132,59 +132,50 @@ void DisplayVoices(FILE *f_out, char *language)
const espeak_VOICE **voices;
espeak_VOICE voice_select;

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

if((language != NULL) && (language[0] != 0))
{
if ((language != NULL) && (language[0] != 0)) {
// display only voices for the specified language, in order of priority
voice_select.languages = language;
voice_select.age = 0;
voice_select.gender = 0;
voice_select.name = NULL;
voices = espeak_ListVoices(&voice_select);
}
else
{
} else {
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;
p = v->languages;
while(*p != 0)
{
while (*p != 0) {
len = strlen(p+1);
lang_name = p+1;

if(v->age == 0)
strcpy(age_buf," ");
if (v->age == 0)
strcpy(age_buf, " ");
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
if((c = v->name[j]) == ' ')
if ((c = v->name[j]) == ' ')
c = '_';
if((buf[j] = c) == 0)
if ((buf[j] = c) == 0)
break;
}
fprintf(f_out,"%2d %-12s%s%c %-20s %-13s ",
p[0],lang_name,age_buf,genders[v->gender],buf,v->identifier);
}
else
{
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++;
p += len+2;
}
fputc('\n',f_out);
fputc('\n', f_out);
}
}

@@ -196,9 +187,8 @@ static void Write4Bytes(FILE *f, int value)
// Write 4 bytes to a file, least significant first
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;
}
}
@@ -208,37 +198,35 @@ static void Write4Bytes(FILE *f, int value)
int OpenWavFile(char *path, int rate)
{
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;
if(path[0] != 0)
{
if(strcmp(path,"stdout")==0)
if (path[0] != 0) {
if (strcmp(path, "stdout") == 0)
f_wavfile = stdout;
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;
}


@@ -247,17 +235,17 @@ static void CloseWavFile()
{
unsigned int pos;

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

fflush(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);
f_wavfile = NULL;
@@ -269,27 +257,20 @@ static int SynthCallback(short *wav, int numsamples, espeak_EVENT *events)
{
char fname[210];

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

if(wav == NULL)
{
if (wav == NULL) {
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;
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
if((samples_split > 0) && (samples_total > samples_split))
{
if ((samples_split > 0) && (samples_total > samples_split)) {
CloseWavFile();
samples_total = 0;
wavefile_count++;
@@ -298,27 +279,22 @@ static int SynthCallback(short *wav, int numsamples, espeak_EVENT *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;
fwrite(wav,numsamples*2,1,f_wavfile);
fwrite(wav, numsamples*2, 1, f_wavfile);
}
return(0);
return 0;
}


@@ -343,42 +319,41 @@ struct option {
int optind;
static int optional_argument;
static const char *arg_opts = "abfgklpsvw"; // which options have arguments
static char *opt_string="";
static char *opt_string = "";
#define no_argument 0
#define required_argument 1
#define optional_argument 2
#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;
char *data_path = NULL; // use default path for espeak-data

@@ -417,15 +392,13 @@ int main (int argc, char **argv)
#ifdef NEED_GETOPT
optind = 1;
opt_string = "";
while(optind < argc)
{
while (optind < argc) {
int len;
char *p;

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

optind++;
@@ -435,45 +408,36 @@ int main (int argc, char **argv)
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

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;
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;
optarg2 = NULL;

if((long_options[ix].has_arg != 0) && (p[len]=='='))
{
if ((long_options[ix].has_arg != 0) && (p[len] == '=')) {
optarg2 = &p[len+1];
}
break;
}
}
}
else
if(strchr(arg_opts,c) != NULL)
{
opt_string="";
if(optarg2[0]==0)
{
} else if (strchr(arg_opts, c) != NULL) {
opt_string = "";
if (optarg2[0] == 0) {
// the option's value is in the next argument
optarg2 = argv[optind++];
}
}
#else
while(true)
{
c = getopt_long (argc, argv, "a:b:f:g:hk:l:mp:qs:v:w:xXz",
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. */
if (c == -1)
@@ -485,7 +449,7 @@ int main (int argc, char **argv)
{
case 'b':
// 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;
else
synth_flags |= espeakCHARS_8BIT;
@@ -523,7 +487,7 @@ int main (int argc, char **argv)
break;

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

case 'l':
@@ -543,12 +507,12 @@ int main (int argc, char **argv)
break;

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

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

case 'z': // remove pause from the end of a sentence
@@ -561,34 +525,33 @@ int main (int argc, char **argv)

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

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

case 0x103: // --punct
option_punctuation = 1;
if(optarg2 != NULL)
{
if (optarg2 != NULL) {
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_punctuation = 2;
}
break;

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);

case 0x106: // -- split
if(optarg2 == NULL)
if (optarg2 == NULL)
samples_split_seconds = 30 * 60; // default 30 minutes
else
samples_split_seconds = atoi(optarg2) * 60;
@@ -599,9 +562,8 @@ int main (int argc, char **argv)
break;

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;

@@ -611,10 +573,9 @@ int main (int argc, char **argv)

case 0x10a: // --ipa
phoneme_options |= espeakPHONEMES_IPA;
if(optarg2 != NULL)
{
if (optarg2 != NULL) {
// deprecated and obsolete
switch(atoi(optarg2))
switch (atoi(optarg2))
{
case 1:
phonemes_separator = '_';
@@ -638,36 +599,36 @@ int main (int argc, char **argv)

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

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

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);
exit(0);

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);
exit(0);

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);
exit(0);

@@ -677,167 +638,135 @@ int main (int argc, char **argv)
}


if(option_waveout || quiet)
{
if (option_waveout || quiet) {
// 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;

espeak_SetSynthCallback(SynthCallback);
if(samples_split)
{
if (samples_split) {
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;
}
}
}
else
{
} else {
// 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;
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);
}
}

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

// 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_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
// use it as text
p_text = argv[optind];
}
else
{
} else {
f_text = stdin;
if(flag_stdin == 0)
{
if (flag_stdin == 0) {
flag_stdin = 2;
}
}
}
else
{
} else {
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);
}


if(p_text != NULL)
{
if (p_text != NULL) {
int size;
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;
p_text = (char *)malloc(max);

if(flag_stdin == 2)
{
if (flag_stdin == 2) {
// 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;
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
ix = 0;
while(!feof(stdin))
{
while (!feof(stdin)) {
p_text[ix++] = fgetc(stdin);
if(ix >= (max-1))
{
if (ix >= (max-1)) {
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;
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);
}

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);
}

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

if(f_phonemes_out != stdout)
if (f_phonemes_out != stdout)
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

@@ -48,17 +48,16 @@ static unsigned int StringToWord(const char *string)
unsigned char c;
unsigned int word;

if(string==NULL)
return(0);
if (string == NULL)
return 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];
word |= (c << (ix*8));
}
return(word);
return word;
}

#pragma GCC visibility push(default)
@@ -82,34 +81,29 @@ espeak_ng_STATUS espeak_ng_CompileMbrolaVoice(const char *filepath, FILE *log)
int mbrola_ctrl = 20; // volume in 1/16 ths
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);
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;

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

if(memcmp(buf,"volume",6)==0)
{
if (memcmp(buf, "volume", 6) == 0) {
mbrola_ctrl = atoi(&buf[6]);
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);
if(strcmp(phoneme2,"NULL")==0)
if (strcmp(phoneme2, "NULL") == 0)
data[count].next_phoneme = 0;
else
if(strcmp(phoneme2,"VWL")==0)
else if (strcmp(phoneme2, "VWL") == 0)
data[count].next_phoneme = 2;
else
data[count].next_phoneme = StringToWord(phoneme2);
@@ -117,9 +111,9 @@ espeak_ng_STATUS espeak_ng_CompileMbrolaVoice(const char *filepath, FILE *log)
data[count].mbr_name2 = 0;
data[count].percent = percent;
data[count].control = control;
if(strcmp(name1,"NULL")!=0)
if (strcmp(name1, "NULL") != 0)
data[count].mbr_name = StringToWord(name1);
if(n == 6)
if (n == 6)
data[count].mbr_name2 = StringToWord(name2);

count++;
@@ -127,10 +121,9 @@ espeak_ng_STATUS espeak_ng_CompileMbrolaVoice(const char *filepath, FILE *log)
}
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);
return ENE_WRITE_ERROR;
}
@@ -139,8 +132,7 @@ espeak_ng_STATUS espeak_ng_CompileMbrolaVoice(const char *filepath, FILE *log)
Write4Bytes(f_out, mbrola_ctrl);

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);
}
fclose(f_out);

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

@@ -27,29 +27,27 @@
#include <sys/time.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()
{
if((fd_log = fopen(FILENAME,"a")) != NULL)
if ((fd_log = fopen(FILENAME, "a")) != NULL)
setvbuf(fd_log, NULL, _IONBF, 0);
}

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

gettimeofday(&tv, NULL);

if (!fd_log)
{
if (!fd_log) {
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);
}
}

@@ -58,30 +56,26 @@ void debug_show(const char *format, ...)
{
va_list args;
va_start(args, format);
if (!fd_log)
{
if (!fd_log) {
debug_init();
}
if (fd_log)
{
if (fd_log) {
vfprintf(fd_log, format, args);
}
va_end(args);
}

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

gettimeofday(&tv, NULL);

if (!fd_log)
{
if (!fd_log) {
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

@@ -27,18 +27,18 @@ extern "C"

#ifdef DEBUG_ENABLED
#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);
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

#ifdef NO_VARIADIC_MACROS
#define SHOW(format) // VC6 doesn't allow "..."
#else
#define SHOW(format,...)
#define SHOW(format, ...)
#endif
#define SHOW_TIME(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

@@ -27,24 +27,22 @@

#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");
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;
}

a_text = malloc( size+1 );
if (!a_text)
{
a_text = malloc(size+1);
if (!a_text) {
goto text_error;
}
memcpy(a_text, text, size);
@@ -60,20 +58,17 @@ t_espeak_command* create_espeak_text(const void *text, size_t size, unsigned int
data->end_position = end_position;
data->flags = flags;
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);

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;
}
@@ -83,15 +78,14 @@ text_error:
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");
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;
}

@@ -100,16 +94,14 @@ t_espeak_command* create_espeak_terminated_msg(unsigned int unique_identifier, v
data = &(a_command->u.my_terminated_msg);
data->unique_identifier = unique_identifier;
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);

msg_error:
if (a_error)
{
if (a_command)
{
free (a_command);
if (a_error) {
if (a_command) {
free(a_command);
}
a_command = NULL;
}
@@ -120,28 +112,26 @@ msg_error:

}

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");
int a_error=1;
void* a_text = NULL;
int a_error = 1;
void *a_text = 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;
}

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

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

a_command->type = ET_MARK;
a_command->state = CS_UNDEFINED;
@@ -153,23 +143,19 @@ t_espeak_command* create_espeak_mark(const void *text, size_t size, const char *
data->end_position = end_position;
data->flags = flags;
data->user_data = user_data;
a_error=0;
a_error = 0;

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;
if (a_index_mark)
{
free (a_index_mark);
if (a_index_mark) {
free(a_index_mark);
}
}

@@ -178,14 +164,13 @@ mark_error:
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");
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;
}

@@ -193,15 +178,13 @@ t_espeak_command* create_espeak_key(const char *key_name, void *user_data)
a_command->state = CS_UNDEFINED;
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.key_name = strdup( key_name);
a_error=0;
a_command->u.my_key.key_name = strdup(key_name);
a_error = 0;

key_error:
if (a_error)
{
if (a_command)
{
free (a_command);
if (a_error) {
if (a_command) {
free(a_command);
}
a_command = NULL;
}
@@ -211,13 +194,12 @@ key_error:
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");
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;
}

@@ -226,14 +208,12 @@ t_espeak_command* create_espeak_char(wchar_t character, void* 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.character = character;
a_error=0;
a_error = 0;

char_error:
if (a_error)
{
if (a_command)
{
free (a_command);
if (a_error) {
if (a_command) {
free(a_command);
}
a_command = NULL;
}
@@ -243,14 +223,13 @@ char_error:
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");
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;
}

@@ -260,14 +239,12 @@ t_espeak_command* create_espeak_parameter(espeak_PARAMETER parameter, int value,
data->parameter = parameter;
data->value = value;
data->relative = relative;
a_error=0;
a_error = 0;

param_error:
if (a_error)
{
if (a_command)
{
free (a_command);
if (a_error) {
if (a_command) {
free(a_command);
}
a_command = NULL;
}
@@ -277,14 +254,13 @@ param_error:
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");
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;
}

@@ -293,19 +269,17 @@ t_espeak_command* create_espeak_punctuation_list(const wchar_t *punctlist)

{
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);
a_command->u.my_punctuation_list = a_list;
}

a_error=0;
a_error = 0;

list_error:
if (a_error)
{
if (a_command)
{
free (a_command);
if (a_error) {
if (a_command) {
free(a_command);
}
a_command = NULL;
}
@@ -315,29 +289,26 @@ list_error:
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");

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;
}

a_command->type = ET_VOICE_NAME;
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:
if (a_error)
{
if (a_command)
{
free (a_command);
if (a_error) {
if (a_command) {
free(a_command);
}
a_command = NULL;
}
@@ -347,47 +318,41 @@ name_error:
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");
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;
}

a_command->type = ET_VOICE_SPEC;
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));

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

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

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

a_error=0;
a_error = 0;
}

spec_error:
if (a_error)
{
if (a_command)
{
free (a_command);
if (a_error) {
if (a_command) {
free(a_command);
}
a_command = NULL;
}
@@ -397,30 +362,26 @@ spec_error:
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");
int a_status = 0;
if (the_command)
{
switch(the_command->type)
if (the_command) {
switch (the_command->type)
{
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);
free(the_command->u.my_text.text);
}
break;

case ET_MARK:
if (the_command->u.my_mark.text)
{
if (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;

@@ -430,20 +391,18 @@ int delete_espeak_command( t_espeak_command* the_command)
// it must be processed here for informing the calling program
// that its message is finished.
// 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;
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;

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;

@@ -453,35 +412,30 @@ int delete_espeak_command( t_espeak_command* the_command)
break;

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;

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;

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);
}

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

if (data->identifier)
{
if (data->identifier) {
free((void *)data->identifier);
}
}
@@ -497,49 +451,48 @@ int delete_espeak_command( t_espeak_command* the_command)
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");

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

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

the_command->state = CS_PROCESSED;

switch(the_command->type)
switch (the_command->type)
{
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;

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;

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;

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);
}
break;
@@ -547,34 +500,34 @@ void process_espeak_command( t_espeak_command* the_command)
case ET_CHAR:
{
const wchar_t data = the_command->u.my_char.character;
sync_espeak_Char( data);
sync_espeak_Char(data);
}
break;

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;

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;

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;

case ET_VOICE_SPEC:
{
espeak_VOICE* data = &(the_command->u.my_voice_spec);
espeak_VOICE *data = &(the_command->u.my_voice_spec);
SetVoiceByProperties(data);
}
break;
@@ -585,44 +538,43 @@ void process_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)
{
ENTER("display_espeak_command");
#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;
}

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:
{
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;

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;

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);
}
break;

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",
the_command, data->unique_identifier, data->user_data,
@@ -639,7 +591,7 @@ void display_espeak_command( t_espeak_command* the_command)

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",
the_command, data->parameter, data->value, data->relative);
}
@@ -647,15 +599,15 @@ void display_espeak_command( t_espeak_command* the_command)

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;

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);
}
break;

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

@@ -29,8 +29,7 @@ extern "C"
{
#endif

typedef enum
{
typedef enum {
ET_TEXT,
ET_MARK,
ET_KEY,
@@ -42,78 +41,69 @@ typedef enum
ET_TERMINATED_MSG
} t_espeak_type;

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

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

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

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


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


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

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

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

union command
{
union command {
t_espeak_text my_text;
t_espeak_mark my_mark;
t_espeak_key my_key;
t_espeak_character my_char;
t_espeak_parameter my_param;
const wchar_t* my_punctuation_list;
const wchar_t *my_punctuation_list;
const char *my_voice_name;
espeak_VOICE my_voice_spec;
t_espeak_terminated_msg my_terminated_msg;
@@ -121,37 +111,37 @@ typedef struct
} 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,
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,
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_Char(wchar_t character);
void sync_espeak_SetPunctuationList(const wchar_t *punctlist);
@@ -162,11 +152,11 @@ espeak_ERROR SetVoiceByName(const char *name);
espeak_ERROR SetVoiceByProperties(espeak_VOICE *voice_selector);
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
}
#endif

//>
// >
#endif

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

@@ -47,29 +47,28 @@ static sem_t my_sem_stop_is_acknowledged;
static pthread_t my_thread;
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;
} 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* 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;
}
@@ -78,10 +77,10 @@ void event_init(void)
{
ENTER("event_init");

my_event_is_running=0;
my_event_is_running = 0;

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

assert(-1 != sem_init(&my_sem_start_is_required, 0, 0));
@@ -90,30 +89,26 @@ void event_init(void)

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,
&a_attrib,
polling_thread,
(void*)NULL));
(void *)NULL));
}
assert(thread_inited);
pthread_attr_destroy(&a_attrib);
}

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

#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",
"WORD",
"SENTENCE",
@@ -126,38 +121,35 @@ static void event_display(espeak_EVENT* event)
"??"
};

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
}

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

if (event==NULL)
{
if (event == 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));

switch(event->type)
switch (event->type)
{
case espeakEVENT_MARK:
case espeakEVENT_PLAY:
if (event->id.name)
{
if (event->id.name) {
a_event->id.name = strdup(event->id.name);
}
break;
@@ -181,21 +173,20 @@ static espeak_EVENT* event_copy (espeak_EVENT* event)
// * Last call: event->type = espeakEVENT_MSG_TERMINATED
//

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

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

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

switch(event->type)
switch (event->type)
{
case espeakEVENT_SENTENCE:
my_callback(NULL, 0, events);
@@ -208,8 +199,7 @@ static void event_notify(espeak_EVENT* event)
case espeakEVENT_END:
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;
events[0].type = espeakEVENT_SENTENCE;
my_callback(NULL, 0, events);
@@ -229,18 +219,17 @@ static void event_notify(espeak_EVENT* event)
}
}

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

event_display(event);

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

switch(event->type)
switch (event->type)
{
case espeakEVENT_MSG_TERMINATED:
event_notify(event);
@@ -248,9 +237,8 @@ static int event_delete(espeak_EVENT* event)

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

@@ -262,27 +250,24 @@ static int event_delete(espeak_EVENT* event)
return 1;
}

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

event_display(event);

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

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

if (!a_status)
{
if (!a_status) {
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);
if (a_error != EE_OK)
{
if (a_error != EE_OK) {
event_delete(a_event);
}
SHOW_TIME("event_declare > unlocking\n");
@@ -292,15 +277,14 @@ espeak_ERROR event_declare (espeak_EVENT* event)
SHOW_TIME("event_declare > post my_sem_start_is_required\n");
sem_post(&my_sem_start_is_required);

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

return a_error;
}

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

@@ -308,33 +292,26 @@ espeak_ERROR event_clear_all ()
int a_event_is_running = 0;

SHOW_TIME("event_stop > locked\n");
if (a_status != 0)
{
if (a_status != 0) {
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");
sem_post(&my_sem_stop_is_required);
a_event_is_running = 1;
}
else
{
} else {
init(); // clear pending events
}
SHOW_TIME("event_stop > unlocking\n");
a_status = pthread_mutex_unlock(&my_mutex);
if (a_status != 0)
{
if (a_status != 0) {
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");
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
}
SHOW_TIME("event_stop > get my_sem_stop_is_acknowledged\n");
@@ -349,12 +326,12 @@ static int sleep_until_timeout_or_stop_request(uint32_t time_in_ms)
{
ENTER("sleep_until_timeout_or_stop_request");

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

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

#ifdef DEBUG_ENABLED
struct timespec to;
@@ -362,26 +339,24 @@ static int sleep_until_timeout_or_stop_request(uint32_t time_in_ms)
to.tv_nsec = ts.tv_nsec;
#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",
to.tv_sec, to.tv_nsec,
ts.tv_sec, ts.tv_nsec);

while ((err = sem_timedwait(&my_sem_stop_is_required, &ts)) == -1
&& errno == EINTR)
{
&& errno == EINTR) {
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",
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;
}
@@ -390,22 +365,20 @@ static int sleep_until_timeout_or_stop_request(uint32_t time_in_ms)
// If the stream is opened but the audio samples are not played,
// 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");

int err = 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;
}

@@ -422,19 +395,18 @@ static int get_remaining_time(uint32_t sample, uint32_t* time_in_ms, int* stop_i
//
// 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;
}

static void* polling_thread(void*p)
static void *polling_thread(void *p)
{
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");
int a_status = pthread_mutex_lock(&my_mutex);
@@ -445,8 +417,7 @@ static void* polling_thread(void*p)

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
}

@@ -458,29 +429,25 @@ static void* polling_thread(void*p)
pthread_mutex_unlock(&my_mutex);
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
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__);
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
while (head && (a_stop_is_required <= 0))
{
while (head && (a_stop_is_required <= 0)) {
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);

uint32_t time_in_ms = 0;
@@ -488,54 +455,43 @@ static void* polling_thread(void*p)
int err = get_remaining_time((uint32_t)event->sample,
&time_in_ms,
&a_stop_is_required);
if (a_stop_is_required > 0)
{
if (a_stop_is_required > 0) {
break;
}
else if (err != 0)
{
} else if (err != 0) {
// 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);
SHOW_TIME("polling_thread > locked\n");
event_delete( (espeak_EVENT*)pop());
event_delete((espeak_EVENT *)pop());
a_status = pthread_mutex_unlock(&my_mutex);
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);
// the user_data (and the type) are cleaned to be sure
// 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);
SHOW_TIME("polling_thread > locked\n");
event_delete( (espeak_EVENT*)pop());
event_delete((espeak_EVENT *)pop());
a_status = pthread_mutex_unlock(&my_mutex);
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);

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__);
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);
}
}
@@ -546,28 +502,23 @@ static void* polling_thread(void*p)
SHOW_TIME("polling_thread > my_event_is_running = 0\n");
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);
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__);
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);
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
// and waiting for my_sem_stop_is_acknowledged
init();
@@ -581,39 +532,33 @@ static void* polling_thread(void*p)
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");

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

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

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

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

if (head == NULL)
{
if (head == NULL) {
head = n;
tail = n;
}
else
{
} else {
tail->next = n;
tail = n;
}
@@ -622,30 +567,28 @@ static espeak_ERROR push(void* the_data)
tail->data = the_data;

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;
}

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

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

if (head != NULL)
{
node* n = head;
if (head != NULL) {
node *n = head;
the_data = n->data;
head = n->next;
free(n);
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;
}

@@ -657,8 +600,8 @@ static void init()
{
ENTER("event > init");

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

node_counter = 0;
}
@@ -667,10 +610,9 @@ void event_terminate()
{
ENTER("event_terminate");

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

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

@@ -51,13 +51,13 @@ extern "C"
// the callback will be called when the event actually occurs.
// The callback is detailled in speak_lib.h .
void event_init(void);
void event_set_callback(t_espeak_callback* cb);
void event_set_callback(t_espeak_callback *cb);

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

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

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

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

@@ -52,35 +52,34 @@ static pthread_t my_thread;
static sem_t my_sem_start_is_required;
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 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()
{
ENTER("fifo_init");

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

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

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_create( &my_thread,
&a_attrib,
say_thread,
(void*)NULL))
{
|| pthread_create(&my_thread,
&a_attrib,
say_thread,
(void *)NULL)) {
assert(0);
}

@@ -88,44 +87,39 @@ void fifo_init()

// leave once the thread is actually started
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
}
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");

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

if (!a_status)
{
if (!a_status) {
SHOW_TIME("fifo_add_command > locked\n");
a_error = push(the_command);
SHOW_TIME("fifo_add_command > unlocking\n");
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
// (for possible forthcoming 'end of command' checks)
SHOW_TIME("fifo_add_command > post my_sem_start_is_required\n");
sem_post(&my_sem_start_is_required);
int val=1;
while (val > 0)
{
int val = 1;
while (val > 0) {
usleep(50000); // TBD: event?
sem_getvalue(&my_sem_start_is_required, &val);
}
}

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

@@ -133,24 +127,20 @@ espeak_ERROR fifo_add_command (t_espeak_command* the_command)
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");

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

if (!a_status)
{
if (!a_status) {
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");
a_error = EE_BUFFER_FULL;
}
else
{
} else {
push(command1);
push(command2);
}
@@ -158,22 +148,19 @@ espeak_ERROR fifo_add_commands (t_espeak_command* command1, t_espeak_command* co
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
// (for possible forthcoming 'end of command' checks)
SHOW_TIME("fifo_add_command > post my_sem_start_is_required\n");
sem_post(&my_sem_start_is_required);
int val=1;
while (val > 0)
{
int val = 1;
while (val > 0) {
usleep(50000); // TBD: event?
sem_getvalue(&my_sem_start_is_required, &val);
}
}

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

@@ -181,36 +168,31 @@ espeak_ERROR fifo_add_commands (t_espeak_command* command1, t_espeak_command* co
return a_error;
}

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

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

if (my_command_is_running)
{
if (my_command_is_running) {
a_command_is_running = 1;
my_stop_is_required = 1;
SHOW_TIME("fifo_stop > my_stop_is_required = 1\n");
}
SHOW_TIME("fifo_stop > unlocking\n");
a_status = pthread_mutex_unlock(&my_mutex);
if (a_status != 0)
{
if (a_status != 0) {
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");
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
}
SHOW_TIME("fifo_stop > get my_sem_stop_is_acknowledged\n");
@@ -223,16 +205,16 @@ espeak_ERROR fifo_stop ()
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;
}

static int sleep_until_start_request_or_inactivity()
{
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).
// Besides this, if the audio stream is still busy,
@@ -240,23 +222,19 @@ static int sleep_until_start_request_or_inactivity()
// The end of the stream is confirmed by several checks
// 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;
}
else
{
} else {
i++;
}

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

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

#ifdef DEBUG_ENABLED
struct timespec to;
@@ -264,24 +242,22 @@ static int sleep_until_start_request_or_inactivity()
to.tv_nsec = ts.tv_nsec;
#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",
to.tv_sec, to.tv_nsec,
ts.tv_sec, ts.tv_nsec);

while ((err = sem_timedwait(&my_sem_start_is_required, &ts)) == -1
&& errno == EINTR)
{
&& errno == EINTR) {
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,
tv.tv_sec, tv.tv_usec*1000);

if (err==0)
{
if (err == 0) {
a_start_is_required = 1;
}
}
@@ -298,38 +274,35 @@ static void close_stream()
// my_stop_is_required = 1;

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

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

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

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

if (a_stop_is_required)
{
if (a_stop_is_required) {
// acknowledge the stop request
SHOW_TIME("fifo > close_stream > post my_sem_stop_is_acknowledged\n");
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");
}

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

@@ -338,27 +311,22 @@ static void* say_thread(void*p)
// announce that thread is started
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");

int a_start_is_required = 0;
if (look_for_inactivity)
{
if (look_for_inactivity) {
a_start_is_required = sleep_until_start_request_or_inactivity();
if (!a_start_is_required)
{
if (!a_start_is_required) {
close_stream();
}
}
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
}
}
@@ -367,62 +335,55 @@ static void* say_thread(void*p)
SHOW_TIME("say_thread > my_command_is_running = 1\n");
my_command_is_running = 1;

while( my_command_is_running)
{
while (my_command_is_running) {
SHOW_TIME("say_thread > locking\n");
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");
a_status = pthread_mutex_unlock(&my_mutex);
SHOW_TIME("say_thread > unlocked\n");
SHOW_TIME("say_thread > my_command_is_running = 0\n");
my_command_is_running = 0;
}
else
{
} else {
display_espeak_command(a_command);
// purge start semaphore
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");
my_command_is_running = 0;
}
SHOW_TIME("say_thread > unlocking\n");
a_status = pthread_mutex_unlock(&my_mutex);

if (my_command_is_running)
{
if (my_command_is_running) {
process_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
// and waiting for my_sem_stop_is_acknowledged
init(1);

// purge start semaphore
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
SHOW_TIME("say_thread > post my_sem_stop_is_acknowledged\n");
int a_status = sem_post(&my_sem_stop_is_acknowledged);
assert( a_status != -1);
assert(a_status != -1);
}
// and wait for the next start
SHOW_TIME("say_thread > wait for my_sem_start_is_required\n");
@@ -433,50 +394,43 @@ static void* say_thread(void*p)

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;
} 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");

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

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

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

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

if (head == NULL)
{
if (head == NULL) {
head = n;
tail = n;
}
else
{
} else {
tail->next = n;
tail = n;
}
@@ -485,7 +439,7 @@ static espeak_ERROR push(t_espeak_command* the_command)
tail->data = the_command;

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

the_command->state = CS_PENDING;
display_espeak_command(the_command);
@@ -493,25 +447,23 @@ static espeak_ERROR push(t_espeak_command* the_command)
return EE_OK;
}

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

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

if (head != NULL)
{
node* n = head;
if (head != NULL) {
node *n = head;
the_command = n->data;
head = n->next;
free(n);
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;
}

@@ -526,8 +478,7 @@ static void init(int process_parameters)
ENTER("fifo > init");
c = pop();
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);
}
delete_espeak_command(c);
@@ -541,7 +492,7 @@ void fifo_terminate()
ENTER("fifo_terminate");

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

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

@@ -43,7 +43,7 @@ void fifo_init();
// EE_BUFFER_FULL: the command can not be buffered;
// you may try after a while to call the function again.
// 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.
//
@@ -54,16 +54,16 @@ espeak_ERROR fifo_add_command (t_espeak_command* c);
// EE_BUFFER_FULL: at least one command can not be buffered;
// you may try after a while to call the function again.
// 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.
// Return: EE_OK: operation achieved
// EE_INTERNAL_ERROR.
espeak_ERROR fifo_stop ();
espeak_ERROR fifo_stop();

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

// Terminate the fifo component.
// 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

@@ -43,8 +43,7 @@ typedef long flag;

/* Resonator Structure */

typedef struct
{
typedef struct {
double a;
double b;
double c;
@@ -57,8 +56,7 @@ typedef struct

/* Structure for Klatt Globals */

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


typedef struct
{
typedef struct {
int F0hz10; /* Voicing fund freq in Hz */
int AVdb; /* Amp of voicing in dB, 0 to 70 */
int Fhz[10]; // formant Hz, F_NZ to F6 to F_NP
@@ -156,7 +153,7 @@ typedef struct
int AVpdb; /* Amp of voicing, par in dB, 0 to 70 */
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 Bhz_next[10];
} klatt_frame_t, *klatt_frame_ptr;

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

@@ -287,7 +287,7 @@ static int mbrola_has_errors(void)
char *buf_ptr, *lf;

buf_ptr = buffer;
for (;; ) {
for (;;) {
result = read(mbr_error_fd, buf_ptr,
sizeof(buffer) - (buf_ptr - buffer) - 1);
if (result == -1) {
@@ -381,7 +381,7 @@ static int mbrola_is_idle(void)
p = (char *)memchr(buffer, ')', sizeof(buffer));
if (!p || (unsigned)(p - buffer) >= sizeof(buffer) - 2)
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)
@@ -514,7 +514,7 @@ int init_MBR(const char *voice_path)
}
mbr_samplerate = wavhdr[24] + (wavhdr[25]<<8) +
(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() */
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

@@ -160,9 +160,9 @@ typedef struct {



#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 PhonemeCode(unsigned int mnem);


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

@@ -33,7 +33,7 @@
#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;
@@ -51,59 +51,54 @@ static int SubstitutePhonemes(Translator *tr, PHONEME_LIST *plist_out)
int n_plist_out = 0;
int word_end;
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];

// 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];

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

// 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;

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

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

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

// substitute the replacement phoneme
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
break;
}
}

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

// 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].type = plist_out[n_plist_out].ph->type;
n_plist_out++;
}
return(n_plist_out);
return n_plist_out;
}


@@ -111,7 +106,7 @@ static int SubstitutePhonemes(Translator *tr, PHONEME_LIST *plist_out)
void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
{

int ix=0;
int ix = 0;
int j;
int insert_ph = 0;
PHONEME_LIST *phlist;
@@ -146,26 +141,21 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)

// is the last word of the clause unstressed ?
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
if((plist2[j].stresslevel & 0x7f) > max_stress)
if ((plist2[j].stresslevel & 0x7f) > max_stress)
max_stress = plist2[j].stresslevel & 0x7f;
if(plist2[j].sourceix != 0)
if (plist2[j].sourceix != 0)
break;
}
if(max_stress < 4)
{
if (max_stress < 4) {
// 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
break;
}
if(plist2[j].stresslevel >= 4)
{
if (plist2[j].stresslevel >= 4) {
// found a stressed syllable, so stop looking
break;
}
@@ -175,32 +165,25 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
// look for switch of phoneme tables
delete_count = 0;
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;
}

if(delete_count > 0)
{
if (delete_count > 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 its followed by another phonSWITCH
delete_count++;
}
else
{
} else {
current_phoneme_tab = plist2[j].tone_ph;
}
}
@@ -208,95 +191,71 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
}
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
// Regressive
int type;
int stop_propagation = 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];
if(ph == NULL)
if (ph == NULL)
continue;

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

type = ph->type;

if(regression & 0x2)
{
if (regression & 0x2) {
// [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;
if(regression & 0x10)
if (regression & 0x10)
voicing = 0;
}
}

if((type==phSTOP) || type==(phFRICATIVE))
{
if((voicing==0) && (regression & 0xf))
{
if ((type == phSTOP) || type == (phFRICATIVE)) {
if ((voicing == 0) && (regression & 0xf)) {
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
}
}
else if((type==phVSTOP) || type==(phVFRICATIVE))
{
if((voicing==0) && (regression & 0xf))
{
} else if ((type == phVSTOP) || type == (phVFRICATIVE)) {
if ((voicing == 0) && (regression & 0xf)) {
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
}
}
else
{
if(regression & 0x8)
{
} else {
if (regression & 0x8) {
// LANG=Polish, propagate through liquids and nasals
if((type == phPAUSE) || (type == phVOWEL))
if ((type == phPAUSE) || (type == phVOWEL))
voicing = 0;
}
else
{
} else {
voicing = 0;
}
}
if(stop_propagation)
{
if (stop_propagation) {
voicing = 0;
stop_propagation = 0;
}

if(plist2[j].sourceix)
{
if(regression & 0x04)
{
if (plist2[j].sourceix) {
if (regression & 0x04) {
// stop propagation at a word boundary
voicing = 0;
}
if(regression & 0x100)
{
if (regression & 0x100) {
// devoice word-final consonants, unless propagating voiced
if(voicing == 0)
{
if (voicing == 0) {
voicing = 1;
}
}
@@ -304,35 +263,29 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
}
}

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
int k;
int nextw;
word_stress = 0;

// 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;

nextw++;
if(ph_list3[nextw].sourceix)
if (ph_list3[nextw].sourceix)
break; // start of the next word
}
for(k=j; k<nextw; k++)
{
for (k = j; k < nextw; k++) {
ph_list3[k].wordstress = word_stress;
}
j = nextw;
}
else
{
} else {
j++;
}
}
@@ -342,14 +295,12 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
ph_list3[0].ph = ph;
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];

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

@@ -357,20 +308,16 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
// That's OK because we don't look backwards from plist3 *** but CountVowelPosition() and isAfterStress does !!!
j--;
plist3 = plist3_inserted = &ph_list3[j];
if(j > 0)
{
if (j > 0) {
// move all previous phonemes in the word back one place
int k;
if(word_start > 0)
{
if (word_start > 0) {
k = word_start;
word_start--;
}
else
{
} else {
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));
}
memset(&plist3[0], 0, sizeof(*plist3));
@@ -379,18 +326,15 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
plist3->ph = ph;
insert_ph = 0;
inserted = 1; // don't insert the same phoneme repeatedly
}
else
{
} else {
// otherwise get the next phoneme from the list
if(plist3->sourceix != 0)
if (plist3->sourceix != 0)
word_start = j;

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

if(plist3->phcode == phonSWITCH)
{
if (plist3->phcode == phonSWITCH) {
// change phoneme table
SelectPhonemeTable(plist3->tone_ph);
}
@@ -398,20 +342,18 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
plist3[1].ph = next;
}

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

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].phcode = alternative;
ph_list3[j+1].type = phoneme_tab[alternative]->type;
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.
PHONEME_TAB *ph2;
ph2 = ph;
@@ -421,13 +363,11 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
plist3->ph = ph;
plist3->phcode = alternative;

if(ph->type == phVOWEL)
{
if (ph->type == phVOWEL) {
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
}
else
} else
plist3->synthflags &= ~SFLAG_SYLLABLE;

// re-interpret the changed phoneme
@@ -435,27 +375,21 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
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;
ph2 = ph;
ph = phoneme_tab[alternative];
plist3->ph = ph;
plist3->phcode = alternative;

if(alternative == 1)
{
if (alternative == 1) {
deleted = 1; // NULL phoneme, discard
}
else
{
if(ph->type == phVOWEL)
{
} else {
if (ph->type == phVOWEL) {
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
}
else
} else
plist3->synthflags &= ~SFLAG_SYLLABLE;

// re-interpret the changed phoneme
@@ -464,64 +398,48 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
}
}

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

// Check for consecutive unstressed syllables, even across word boundaries.
// Do this after changing phonemes according to stress level.
if(plist3->stresslevel <= 1)
{
if (plist3->stresslevel <= 1) {
// an unstressed vowel
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)
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;
if(p->wordstress < 4)
if (p->wordstress < 4)
p->stresslevel = 0;
}
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'
// 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
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'
}
}
}
}
else
{
} else {
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
// BUT, can't insert a phoneme at position plist3[0] because it crashes PrevPh()
insert_ph = next->code;
@@ -529,59 +447,48 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
}
}

if((plist3+1)->sourceix != 0)
{
if ((plist3+1)->sourceix != 0) {
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
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
if(x == 0xc)
if (x == 0xc)
insert_ph = phonPAUSE_NOLINK;
else
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
if(x == 2)
if (x == 2)
insert_ph = phonPAUSE_SHORT;
else
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
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
insert_ph = pause_phonemes[x];
}
}
if(option_wordgap > 0)
{
if (option_wordgap > 0) {
insert_ph = phonPAUSE_LONG;
}
}
@@ -590,13 +497,11 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
next2 = phoneme_tab[plist3[2].phcode];
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];
}

if(deleted == 0)
{
if (deleted == 0) {
phlist[ix].ph = ph;
phlist[ix].type = ph->type;
phlist[ix].env = PITCHfall; // default, can be changed in the "intonation" module
@@ -607,31 +512,25 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
phlist[ix].sourceix = 0;
phlist[ix].phcode = ph->code;

if(plist3->sourceix != 0)
{
if (plist3->sourceix != 0) {
phlist[ix].sourceix = plist3->sourceix;
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
start_sentence = 0;
}
}
else
{
} else {
phlist[ix].newword = 0;
}

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].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].env = PITCHfall;
}
@@ -655,7 +554,7 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
phlist[ix].phcode = phonPAUSE;
phlist[ix].type = phPAUSE;
phlist[ix].length = 0;
phlist[ix].sourceix=0;
phlist[ix].sourceix = 0;
phlist[ix].synthflags = 0;
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

@@ -102,9 +102,9 @@ static unsigned char speed_lookup[] = {

// speed_factor1 adjustments for speeds 350 to 374: pauses
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

// wav_factor adjustments for speeds 350 to 450
@@ -157,36 +157,31 @@ void SetSpeed(int control)
speed.min_pause = 5;

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

wpm_value = wpm;

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

if(control & 2)
{
if (control & 2) {
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;
wpm = 175;

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

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

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

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];

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

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

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

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

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

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
else
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];
}

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

@@ -274,30 +259,19 @@ void SetSpeed(int control)
speed.pause_factor = (256 * s1)/115; // full speed adjustment, used for pause length
speed.clause_pause_factor = 0;

if(wpm > 430)
{
if (wpm > 430) {
speed.pause_factor = 12;
}
else
if(wpm > 400)
{
} else if (wpm > 400) {
speed.pause_factor = 13;
}
else
if(wpm > 374)
{
} else if (wpm > 374) {
speed.pause_factor = 14;
}
else
if(wpm > 350)
{
} else if (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
if((speed.clause_pause_factor = speed.pause_factor) < 16)
if ((speed.clause_pause_factor = speed.pause_factor) < 16)
speed.clause_pause_factor = 16;
}
}
@@ -319,108 +293,86 @@ void SetSpeed(int control)
speed.lenmod2_factor = 100;

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

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

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

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];

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

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

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

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

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

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
else
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];
}

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

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

if(wpm > 430)
{
if (wpm > 430) {
speed.pause_factor = 12;
}
else
if(wpm > 400)
{
} else if (wpm > 400) {
speed.pause_factor = 13;
}
else
if(wpm > 374)
{
} else if (wpm > 374) {
speed.pause_factor = 14;
}
else
if(wpm > 350)
{
} else if (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
if((speed.clause_pause_factor = speed.pause_factor) < 16)
if ((speed.clause_pause_factor = speed.pause_factor) < 16)
speed.clause_pause_factor = 16;
}
}
@@ -437,10 +389,8 @@ void SetParameter(int parameter, int value, int relative)
int new_value = value;
int default_value;

if(relative)
{
if(parameter < 5)
{
if (relative) {
if (parameter < 5) {
default_value = param_defaults[parameter];
new_value = default_value + (default_value * value)/100;
}
@@ -448,7 +398,7 @@ void SetParameter(int parameter, int value, int relative)
param_stack[0].parameter[parameter] = new_value;
saved_parameters[parameter] = new_value;

switch(parameter)
switch (parameter)
{
case espeakRATE:
embedded_value[EMBED_S] = new_value;
@@ -462,13 +412,13 @@ void SetParameter(int parameter, int value, int relative)
break;

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;
break;

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

@@ -481,7 +431,7 @@ void SetParameter(int parameter, int value, int relative)
break;

case espeakINTONATION:
if((new_value & 0xff) != 0)
if ((new_value & 0xff) != 0)
translator->langopts.intonation_group = new_value & 0xff;
option_tone_flags = new_value;
break;
@@ -502,13 +452,12 @@ static void DoEmbedded2(int *embix)
do {
word = embedded_list[(*embix)++];

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


@@ -525,9 +474,9 @@ void CalcLengths(Translator *tr)

int stress;
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 pitch_start;
int length_mod;
@@ -540,11 +489,10 @@ void CalcLengths(Translator *tr)
int pitch1;
int emphasized;
int tone_mod;
unsigned char *pitch_env=NULL;
unsigned char *pitch_env = NULL;
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];
p = &phoneme_list[ix];
stress = p->stresslevel & 0x7;
@@ -552,16 +500,15 @@ void CalcLengths(Translator *tr)

next = &phoneme_list[ix+1];

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

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

switch(type)
switch (type)
{
case phPAUSE:
last_pitch = 0;
@@ -569,109 +516,91 @@ void CalcLengths(Translator *tr)

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

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

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

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

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

case phVFRICATIVE:
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;
}
}

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;

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

if((tr->langopts.word_gap & 0x10) && (p->newword))
if ((tr->langopts.word_gap & 0x10) && (p->newword))
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
else
p->length = 150;
}
else
} else
p->length = 256;

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

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;

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;

p->prepause = 40;

if(prev->type == phVOWEL)
{
if (prev->type == phVOWEL) {
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
if(prev->length < p->prepause)
if (prev->length < p->prepause)
p->prepause -= prev->length;
else
p->prepause = 0;
}
else
if(p->newword==0)
{
if(prev->type==phLIQUID)
} else if (p->newword == 0) {
if (prev->type == phLIQUID)
p->prepause = 20;
if(prev->type==phNASAL)
if (prev->type == phNASAL)
p->prepause = 12;

if(prev->type==phSTOP && !(prev->ph->phflags & phFORTIS))
if (prev->type == phSTOP && !(prev->ph->phflags & phFORTIS))
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;

break;
@@ -682,49 +611,36 @@ void CalcLengths(Translator *tr)
p->length = 256; // TEMPORARY
min_drop = 0;

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

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

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

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

if(next->type == phVSTOP)
{
if (next->type == phVSTOP) {
p->length = (p->length * 160)/100;
}
if(next->type == phVFRICATIVE)
{
if (next->type == phVFRICATIVE) {
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;
break;
}
@@ -732,8 +648,7 @@ void CalcLengths(Translator *tr)
}

p->pitch1 = p->pitch2-16;
if(p->pitch2 < 16)
{
if (p->pitch2 < 16) {
p->pitch1 = 0;
}
p->env = PITCHfall;
@@ -746,49 +661,44 @@ void CalcLengths(Translator *tr)
next2 = &phoneme_list[ix+2];
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)
}
if(pre_sonorant)
if (pre_sonorant)
p->amp = tr->stress_amps[stress]-1;
else
p->amp = tr->stress_amps[stress];

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

if(ix >= (n_phoneme_list-3))
{
if (ix >= (n_phoneme_list-3)) {
// 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];
}

// is the last syllable of a word ?
more_syllables=0;
more_syllables = 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++;

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

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

// 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
next = next2;
next2 = next3;
@@ -796,101 +706,84 @@ void CalcLengths(Translator *tr)
}

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
if(next2type != 1)
if (next2type != 1)
next2type = 0;
}

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
length_mod = (len + tr->langopts.length_mods0[next->ph->length_mod *10+ 1])/2;
}
else
} else
length_mod = len;
}
else
{
} else {
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;
}

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

length_mod = length_mod / 128;

if(length_mod < 8)
if (length_mod < 8)
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
length_mod += tr->langopts.lengthen_tonic;
if(emphasized)
if (emphasized)
length_mod += (tr->langopts.lengthen_tonic/2);
}
else
if(emphasized)
{
} else if (emphasized) {
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];

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
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
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;
}

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 = length_mod / 128;

if(p->type != phVOWEL)
{
if (p->type != phVOWEL) {
length_mod = 256; // syllabic consonant
min_drop = 16;
}
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;
}

@@ -898,73 +791,61 @@ void CalcLengths(Translator *tr)
// set last-pitch
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);
pitch_env = GetEnvelope(phdata_tone.pitch_env);
}
else
{
} else {
pitch_env = envelope_data[env2];
}

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
if(pitch_start == 255)
if (pitch_start == 255)
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;

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

prev->length = length_mod;

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

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

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

if(next2->type == phVOWEL)
{
if (next2->type == phVOWEL) {
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;
}
}
}

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;
if(pitch1 < 0)
if (pitch1 < 0)
pitch1 = 0;
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

@@ -48,54 +48,53 @@ int pk_select;
#define PEAKSHAPEW 256

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] =
{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] =
{89,90,140,260,260,260,500,500,500};
{ 89, 90, 140, 260, 260, 260, 500, 500, 500 };

static double read_double(FILE *stream)
{
unsigned char bytes[10];
fread(bytes,sizeof(char),10,stream);
fread(bytes, sizeof(char), 10, stream);
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]
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 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--]));
}
return(y);
return y;
}


@@ -115,8 +114,7 @@ static SpectFrame *SpectFrameCreate()
frame->amp_adjust = 100;
frame->length_adjust = 0;

for(ix=0; ix<N_PEAKS; ix++)
{
for (ix = 0; ix < N_PEAKS; ix++) {
frame->formants[ix].freq = 0;
frame->peaks[ix].pkfreq = default_freq[ix];
frame->peaks[ix].pkheight = 0;
@@ -136,7 +134,7 @@ static SpectFrame *SpectFrameCreate()

static void SpectFrameDestroy(SpectFrame *frame)
{
if(frame->spect != NULL)
if (frame->spect != NULL)
free(frame->spect);
free(frame);
}
@@ -153,61 +151,54 @@ int LoadFrame(SpectFrame *frame, FILE *stream, int file_format_type)
frame->pitch = read_double(stream);
frame->length = 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;

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);

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;
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;
if(x > frame->max_y) frame->max_y = x;
if (x > frame->max_y) frame->max_y = x;
}
frame->spect = spect_data;

return(0);
return 0;
}


@@ -215,14 +206,13 @@ int LoadFrame(SpectFrame *frame, FILE *stream, int file_format_type)
double GetFrameRms(SpectFrame *frame, int seq_amplitude)
{
int h;
float total=0;
float total = 0;
int maxh;
int height;
int htab[400];
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;
wpeaks[h].height = height << 8;

@@ -231,13 +221,12 @@ double GetFrameRms(SpectFrame *frame, int seq_amplitude)
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);
}
frame->rms = sqrt(total) / 7.25;
return(frame->rms);
return frame->rms;
}


@@ -266,11 +255,9 @@ SpectSeq *SpectSeqCreate()
void SpectSeqDestroy(SpectSeq *spect)
{
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]);
}
free(spect->frames);
@@ -283,16 +270,15 @@ void SpectSeqDestroy(SpectSeq *spect)
static float GetFrameLength(SpectSeq *spect, int frame)
{
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;
}
return ((spect->frames[ix]->time - spect->frames[frame]->time) * 1000.0 + adjust);
return (spect->frames[ix]->time - spect->frames[frame]->time) * 1000.0 + adjust;
}


@@ -302,65 +288,50 @@ int LoadSpectSeq(SpectSeq *spect, const char *filename)
short n, temp;
int ix;
uint32_t id1, id2, name_len;
int set_max_y=0;
int set_max_y = 0;
float time_offset;

FILE *stream = fopen(filename, "rb");
if(stream == NULL)
{
if (stream == NULL) {
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
}
else
if((id1 == FILEID1_SPECTSEQ) && (id2 == FILEID2_SPECTSEK))
{
} else if ((id1 == FILEID1_SPECTSEQ) && (id2 == FILEID2_SPECTSEK)) {
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
}
else
{
} else {
fprintf(stderr, "Unsupported spectral file format.\n");
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);
fread(spect->name,sizeof(char),name_len,stream);
}
else
fread(spect->name, sizeof(char), name_len, stream);
} else
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);
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]);
}
free(spect->frames);
@@ -369,52 +340,48 @@ int LoadSpectSeq(SpectSeq *spect, const char *filename)

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

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

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;
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

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
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->pitch1 = spect->pitchenv.pitch1;
spect->pitch2 = spect->pitchenv.pitch2;
spect->duration = (int)(spect->frames[spect->numframes-1]->time * 1000);

if(spect->max_y < 400)
if (spect->max_y < 400)
spect->max_y = 200;
else
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);
return(0);
return 0;
}

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

@@ -87,8 +87,7 @@ typedef struct {
} peak_t;


typedef struct
{
typedef struct {
int keyframe;
short amp_adjust;
float length_adjust;
@@ -111,8 +110,7 @@ typedef struct

double GetFrameRms(SpectFrame *frame, int amp);

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

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

@@ -86,7 +86,7 @@ int LookupMnem(MNEM_TAB *table, const char *string);

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);
char *Alloc(int size);
void Free(void *ptr);

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

@@ -54,8 +54,8 @@ typedef void (WINAPI *PROCVI)(int);
typedef void (WINAPI *PROCVF)(float);
typedef int (WINAPI *PROCIV)();
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 write_MBR;
@@ -76,31 +76,30 @@ HINSTANCE hinstDllMBR = NULL;

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

if ((hinstDllMBR=LoadLibraryA("mbrola.dll")) == 0)
if ((hinstDllMBR = LoadLibraryA("mbrola.dll")) == 0)
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;
}


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

@@ -125,79 +124,72 @@ espeak_ERROR LoadMbrolaTable(const char *mbrola_voice, const char *phtrans, int
mbrola_delay = 0;
mbr_name_prefix = 0;

if(mbrola_voice == NULL)
{
if (mbrola_voice == NULL) {
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
// if not found, then also look in
// 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();
#endif
#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");
return(EE_INTERNAL_ERROR);
return EE_INTERNAL_ERROR;
}
#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

// 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);
if((f_in = fopen(path,"rb")) == NULL) {
if ((f_in = fopen(path, "rb")) == NULL) {
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);
close_MBR();
return(EE_INTERNAL_ERROR);
return EE_INTERNAL_ERROR;
}

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

setVolumeRatio_MBR((float)(mbrola_control & 0xff) /16.0f);
samplerate = *srate = getFreq_MBR();
if(*srate == 22050)
SetParameter(espeakVOICETYPE,0,0);
if (*srate == 22050)
SetParameter(espeakVOICETYPE, 0, 0);
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
return(EE_OK);
return EE_OK;
}


@@ -219,60 +211,50 @@ static int GetMbrName(PHONEME_LIST *plist, PHONEME_TAB *ph, PHONEME_TAB *ph_prev
// bit 5 only in stressed syllable
// bit 6 only at the end of a word

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

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;
else
if((pr->next_phoneme == ':') && (plist->synthflags & SFLAG_LENGTHEN))
{
else if ((pr->next_phoneme == ':') && (plist->synthflags & SFLAG_LENGTHEN)) {
found = 1;
}
else
{
if(pr->control & 2)
} else {
if (pr->control & 2)
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
else
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;
}
}

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;

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;

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

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

if(pr->control & 0x10)
{
if (pr->control & 0x10) {
mbr_name_prefix = pr->mbr_name;
return(0);
return 0;
}
mnem = pr->mbr_name;
break;
@@ -282,12 +264,11 @@ static int GetMbrName(PHONEME_LIST *plist, PHONEME_TAB *ph, PHONEME_TAB *ph_prev
pr++;
}

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


@@ -298,12 +279,12 @@ static char *WritePitch(int env, int pitch1, int pitch2, int split, int final)
int ix;
int pitch_base;
int pitch_range;
int p1,p2,p_end;
int p1, p2, p_end;
unsigned char *pitch_env;
int max = -1;
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 y2;
int y[4];
@@ -319,19 +300,16 @@ static char *WritePitch(int env, int pitch1, int pitch2, int split, int final)


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

// 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];
y_max = x;
}
if(pitch_env[x] < min)
{
if (pitch_env[x] < min) {
min = pitch_env[x];
y_min = x;
}
@@ -339,12 +317,10 @@ static char *WritePitch(int env, int pitch1, int pitch2, int split, int final)
// set an additional pitch point half way through the phoneme.
// but look for a maximum or a minimum and use that instead
y[2] = 64;
if((y_max > 0) && (y_max < 127))
{
if ((y_max > 0) && (y_max < 127)) {
y[2] = y_max;
}
if((y_min > 0) && (y_min < 127))
{
if ((y_min > 0) && (y_min < 127)) {
y[2] = y_min;
}
y[1] = y[2] / 2;
@@ -355,56 +331,44 @@ static char *WritePitch(int env, int pitch1, int pitch2, int split, int final)
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
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;

if(split > 0)
{
if (split > 0) {
y2 = (y[ix] * env100)/env_split;
}
else
if(split < 0)
{
} else if (split < 0) {
y2 = ((y[ix]-env_split) * env100)/env_split;
}
else
{
} else {
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;
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;
}


@@ -441,8 +405,7 @@ int MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, int resume, FILE *f_mbr
word_count = 0;
}

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

@@ -454,47 +417,42 @@ int MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, int resume, FILE *f_mbr
ph_prev = 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);
}

if(p->newword & 4)
if (p->newword & 4)
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++);

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++;

if(name == 0) {
if (name == 0) {
phix++;
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
name = '_';
len = (p->length * speed.pause_factor)/256;
if(len == 0)
if (len == 0)
len = 1;
}
else
} else
len = (80 * speed.wav_factor)/256;

if(ph->code != phonEND_WORD)
{
if (ph->code != phonEND_WORD) {
char phoneme_name[16];
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);
}

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

if(name2 == '_')
{
if (name2 == '_') {
// add a pause after this phoneme
pause = len_percent;
name2 = 0;
@@ -503,48 +461,45 @@ int MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, int resume, FILE *f_mbr
done = 0;
final_pitch = "";

switch(ph->type)
switch (ph->type)
{
case phVOWEL:
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

if(ph_next->type == phPAUSE)
if (ph_next->type == phPAUSE)
len += 50; // lengthen vowels before a pause
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;

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;
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;
break;

case phSTOP:
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;
InterpretPhoneme(NULL, 0, p, &phdata, NULL);
len = DoSample3(&phdata, 0, -1);

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

case phVSTOP:
@@ -554,7 +509,7 @@ int MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, int resume, FILE *f_mbr
case phFRICATIVE:
len = 0;
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);

@@ -562,52 +517,44 @@ int MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, int resume, FILE *f_mbr
break;

case phNASAL:
if(next->type != phVOWEL)
{
if (next->type != phVOWEL) {
memset(&fmtp, 0, sizeof(fmtp));
InterpretPhoneme(NULL, 0, p, &phdata, NULL);
fmtp.fmt_addr = phdata.sound_addr[pd_FMT];
len = DoSpect2(p->ph, 0, &fmtp, p, -1);
len = (len * 1000)/samplerate;
if(next->type == phPAUSE)
if (next->type == phPAUSE)
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;

case phLIQUID:
if(next->type == phPAUSE)
{
if (next->type == phPAUSE) {
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;
}

if(!done)
{
if(name2 != 0)
{
if (!done) {
if (name2 != 0) {
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;
}
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;
}

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);
if (res < 0)
return 0; /* don't get stuck on error */
@@ -621,8 +568,7 @@ int MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, int resume, FILE *f_mbr
phix++;
}

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

// flush the mbrola output buffer
@@ -639,11 +585,10 @@ int MbrolaGenerate(PHONEME_LIST *phoneme_list, int *n_ph, int resume)
{
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
f_mbrola = f_trans;
}
@@ -675,14 +620,13 @@ int MbrolaFill(int length, int resume, int amplitude)
if (result <= 0)
return 0;

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

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)
{
return(0);
return 0;
}

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

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

@@ -490,7 +490,7 @@ int WavegenOpenSound();
int WavegenCloseSound();
int WavegenInitSound();
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);
void MarkerEvent(int type, unsigned int char_position, int value, int value2, unsigned char *out_ptr);

@@ -536,7 +536,7 @@ int SelectPhonemeTableName(const char *name);
void Write4Bytes(FILE *f, int value);
int Read4Bytes(FILE *f);
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
@@ -555,7 +555,7 @@ extern unsigned char *out_start;
extern unsigned char *out_end;
extern int event_list_ix;
extern espeak_EVENT *event_list;
extern t_espeak_callback* synth_callback;
extern t_espeak_callback *synth_callback;
extern const char *version_string;
extern const int version_phdata;
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

@@ -22,7 +22,7 @@ extern "C"
{
#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 REPLACED_E 'E' // 'e' replaced by silent e
@@ -252,7 +252,7 @@ extern "C"
// match 1 pre 2 post 0 - use common phoneme string
// match 1 pre 2 post 3 0 - empty phoneme string

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

typedef struct {
int points;
@@ -601,8 +601,7 @@ typedef struct {



typedef struct
{
typedef struct {

LANGUAGE_OPTIONS langopts;
int translator_name;
@@ -723,8 +722,8 @@ extern unsigned char *p_textinput;
extern wchar_t *p_wchar_input;
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);

void LoadConfig(void);
@@ -733,8 +732,8 @@ int utf8_in(int *c, const char *buf);
int utf8_in2(int *c, const char *buf, int backwards);
int utf8_out(unsigned int c, 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);
char *strchr_w(const char *s, 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

@@ -32,15 +32,15 @@ extern "C"
extern int option_device_number;

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 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
// (or 0 if the event has been already played).
@@ -48,12 +48,12 @@ extern uint32_t wave_get_write_position(void* theHandler);
// time: supplied value in ms
//
// 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.
// Helpful if a new sample is waiting for free space whereas sound must be stopped.
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

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

@@ -48,7 +48,7 @@
#include "wave.h"
#include "debug.h"

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

enum {
/* return value */
@@ -59,7 +59,7 @@ enum {

#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 ESPEAK_FORMAT PA_SAMPLE_S16LE
@@ -126,7 +126,7 @@ static int wave_samplerate;
SHOW("Connection died: %s\n", context ? pa_strerror(pa_context_errno(context)) : "NULL"); \
goto label; \
} \
} while(0);
} while (0);

#define CHECK_CONNECTED(retval) \
do { \
@@ -154,7 +154,8 @@ static void context_state_cb(pa_context *c, void *userdata) {
ENTER(__FUNCTION__);
assert(c);

switch (pa_context_get_state(c)) {
switch (pa_context_get_state(c))
{
case PA_CONTEXT_READY:
case PA_CONTEXT_TERMINATED:
case PA_CONTEXT_FAILED:
@@ -169,11 +170,12 @@ static void context_state_cb(pa_context *c, void *userdata) {
}
}

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

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

case PA_STREAM_READY:
case PA_STREAM_FAILED:
@@ -192,7 +194,7 @@ static void stream_success_cb(pa_stream *s, int success, void *userdata) {
assert(s);

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

pa_threaded_mainloop_signal(mainloop, 0);
}
@@ -202,7 +204,7 @@ static void context_success_cb(pa_context *c, int success, void *userdata) {
assert(c);

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

pa_threaded_mainloop_signal(mainloop, 0);
}
@@ -231,7 +233,7 @@ static int pulse_free(void) {
pa_threaded_mainloop_lock(mainloop);
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)));
l = 0;
goto fail;
@@ -271,7 +273,7 @@ fail:

do_trigger = !!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) {
@@ -285,11 +287,10 @@ static int pulse_playing(const pa_timing_info *the_timing_info) {

pa_threaded_mainloop_lock(mainloop);

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

if ((i = pa_stream_get_timing_info(stream)))
{
if ((i = pa_stream_get_timing_info(stream))) {
break;
}
if (pa_context_errno(context) != PA_ERR_NODATA) {
@@ -301,7 +302,7 @@ static int pulse_playing(const pa_timing_info *the_timing_info) {
}

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:
pa_threaded_mainloop_unlock(mainloop);
@@ -309,7 +310,7 @@ fail:
return r;
}

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


@@ -360,8 +361,7 @@ static int drain(void) {

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

@@ -420,7 +420,7 @@ static int pulse_open()
assert(!stream);
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.rate = wave_samplerate;
@@ -431,7 +431,7 @@ static int pulse_open()

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

@@ -439,7 +439,7 @@ static int pulse_open()

SHOW_TIME("pa_context_new (call)");
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;
}

@@ -455,7 +455,7 @@ static int pulse_open()

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

@@ -558,8 +558,7 @@ fail:
pa_threaded_mainloop_free(mainloop);
mainloop = NULL;
}
}
else {
} else {
pulse_close();
}

@@ -569,12 +568,12 @@ fail:

}

void wave_flush(void* theHandler)
void wave_flush(void *theHandler)
{
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;
}
@@ -589,52 +588,47 @@ int wave_init(int srate)
return pulse_open() == PULSE_OK;
}

void* wave_open(const char* the_api)
void *wave_open(const char *the_api)
{
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");
size_t bytes_to_write = theSize;
char* aBuffer=theMono16BitsWaveBuffer;
char *aBuffer = theMono16BitsWaveBuffer;

assert(stream);

size_t aTotalFreeMem=0;
size_t aTotalFreeMem = 0;

pthread_mutex_lock(&pulse_mutex);

while (1)
{
while (1) {
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!");
theSize=0;
theSize = 0;
goto terminate;
}

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);
break;
}

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

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
if (aTotalFreeMem>500)
{
if (aTotalFreeMem > 500) {
pulse_write(aBuffer, aTotalFreeMem);
bytes_to_write -= aTotalFreeMem;
aBuffer += aTotalFreeMem;
@@ -652,7 +646,7 @@ terminate:
return theSize;
}

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

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__);
aStopStreamCount = 0; // last action
return PULSE_ERROR;
@@ -683,13 +675,13 @@ int wave_close(void* theHandler)
return PULSE_OK;
}

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

pa_timing_info 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;
}

@@ -698,7 +690,7 @@ void wave_terminate()
ENTER("wave_terminate");

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

@@ -709,7 +701,7 @@ void wave_terminate()
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;
pulse_playing(&a_timing_info);
@@ -717,7 +709,7 @@ uint32_t wave_get_read_position(void* theHandler)
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;
pulse_playing(&a_timing_info);
@@ -725,27 +717,23 @@ uint32_t wave_get_write_position(void* theHandler)
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;
}

pa_timing_info 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
a_time = sample - a_timing_info.read_index;
a_time = 0.5 + (a_time * 1000.0) / wave_samplerate;
}
else
{
} else {
a_time = 0;
}

@@ -767,38 +755,38 @@ void *wave_test_get_write_buffer()

int wave_init(return 1; ) {
}
void* wave_open(const char* the_api) {
void *wave_open(const char *the_api) {
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;
}
int wave_close(void* theHandler) {
int wave_close(void *theHandler) {
return 0;
}
int wave_is_busy(void* theHandler) {
int wave_is_busy(void *theHandler) {
return 0;
}
void wave_terminate() {
}
uint32_t wave_get_read_position(void* theHandler) {
uint32_t wave_get_read_position(void *theHandler) {
return 0;
}
uint32_t wave_get_write_position(void* theHandler) {
uint32_t wave_get_write_position(void *theHandler) {
return 0;
}
void wave_flush(void* theHandler) {
void wave_flush(void *theHandler) {
}
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;
}

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;
return 0;
}
@@ -811,26 +799,23 @@ void clock_gettime2(struct timespec *ts)
{
struct timeval tv;

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

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

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

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);
ts->tv_sec += 1;
t_ns -= ONE_BILLION;

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

@@ -35,13 +35,13 @@
#include "wave.h"
#include "debug.h"

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

#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 int sun_audio_fd = -1;
@@ -59,7 +59,7 @@ static uint32_t total_samples_skipped;

// 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;

@@ -100,7 +100,7 @@ int wave_init(int srate) {
SHOW("wave_init() sun_audio_fd: %d\n", sun_audio_fd);

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

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

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

// wave_write
@@ -172,13 +172,13 @@ void* wave_open(const char* the_api)
//
// 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 num;
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!");
return 0;
}
@@ -191,8 +191,7 @@ size_t wave_write(void* theHandler,
char *out_end;
out_ptr = (char *)theMono16BitsWaveBuffer;
out_end = out_ptr + theSize;
while(out_ptr < out_end)
{
while (out_ptr < out_end) {
c = out_ptr[0];
out_ptr[0] = out_ptr[1];
out_ptr[1] = c;
@@ -201,7 +200,7 @@ size_t wave_write(void* theHandler,
}
#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
// wave_get_read_position and also use it to help calculate the
@@ -246,11 +245,11 @@ size_t wave_write(void* theHandler,
//
// The result of the ioctl call (non-0 means failure)
//
int wave_close(void* theHandler)
int wave_close(void *theHandler)
{
int ret;
audio_info_t ainfo;
int audio_fd = (int) theHandler;
int audio_fd = (int)theHandler;
if (!audio_fd) {
audio_fd = sun_audio_fd;
}
@@ -291,7 +290,7 @@ int wave_close(void* theHandler)
//
// A non-0 value if audio is being played
//
int wave_is_busy(void* theHandler)
int wave_is_busy(void *theHandler)
{
uint32_t time;
if (total_samples_sent >= 1) {
@@ -335,7 +334,7 @@ void wave_terminate()
//
// theHandler: the audio device file descriptor
//
void wave_flush(void* theHandler)
void wave_flush(void *theHandler)
{
ENTER("wave_flush");
SHOW_TIME("wave_flush > LEAVE");
@@ -353,7 +352,7 @@ void wave_flush(void* theHandler)
//
// 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;
}
@@ -393,11 +392,11 @@ void *wave_test_get_write_buffer()
// The total number of 16-bit samples played by the audio system
// so far.
//
uint32_t wave_get_read_position(void* theHandler)
uint32_t wave_get_read_position(void *theHandler)
{
audio_info_t ainfo;
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_TIME("wave_get_read_position > LEAVE");
return ainfo.play.samples;
@@ -429,7 +428,7 @@ uint32_t wave_get_read_position(void* theHandler)
// the index wraps back to 0. We don't handle that wrapping, so
// 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");
SHOW("wave_get_write_position: %d\n", total_samples_sent);
@@ -464,15 +463,15 @@ uint32_t wave_get_write_position(void* theHandler)
// Time in milliseconds before the sample is played or 0 if the sample
// 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;

audio_info_t ainfo;
ENTER("wave_get_remaining_time");
if (!time) {
return(-1);
return -1;
SHOW_TIME("wave_get_remaining_time > LEAVE");
}

@@ -487,7 +486,7 @@ int wave_get_remaining_time(uint32_t sample, uint32_t* time)
*time = 0;
} else {
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_TIME("wave_get_remaining_time > LEAVE");
@@ -499,38 +498,38 @@ int wave_get_remaining_time(uint32_t sample, uint32_t* time)
init wave_init() {
return 1;
}
void* wave_open(const char* the_api) {
void *wave_open(const char *the_api) {
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;
}
int wave_close(void* theHandler) {
int wave_close(void *theHandler) {
return 0;
}
int wave_is_busy(void* theHandler) {
int wave_is_busy(void *theHandler) {
return 0;
}
void wave_terminate() {
}
uint32_t wave_get_read_position(void* theHandler) {
uint32_t wave_get_read_position(void *theHandler) {
return 0;
}
uint32_t wave_get_write_position(void* theHandler) {
uint32_t wave_get_write_position(void *theHandler) {
return 0;
}
void wave_flush(void* theHandler) {
void wave_flush(void *theHandler) {
}
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;
}

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;
return 0;
}
@@ -541,26 +540,23 @@ void clock_gettime2(struct timespec *ts)
{
struct timeval tv;

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

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

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

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);
ts->tv_sec += 1;
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

@@ -145,59 +145,50 @@ void DisplayVoices(FILE *f_out, char *language)
const espeak_VOICE **voices;
espeak_VOICE voice_select;

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

if((language != NULL) && (language[0] != 0))
{
if ((language != NULL) && (language[0] != 0)) {
// display only voices for the specified language, in order of priority
voice_select.languages = language;
voice_select.age = 0;
voice_select.gender = 0;
voice_select.name = NULL;
voices = espeak_ListVoices(&voice_select);
}
else
{
} else {
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;
p = v->languages;
while(*p != 0)
{
while (*p != 0) {
len = strlen(p+1);
lang_name = p+1;

if(v->age == 0)
strcpy(age_buf," ");
if (v->age == 0)
strcpy(age_buf, " ");
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
if((c = v->name[j]) == ' ')
if ((c = v->name[j]) == ' ')
c = '_';
if((buf[j] = c) == 0)
if ((buf[j] = c) == 0)
break;
}
fprintf(f_out,"%2d %-12s%s%c %-20s %-13s ",
p[0],lang_name,age_buf,genders[v->gender],buf,v->identifier);
}
else
{
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++;
p += len+2;
}
fputc('\n',f_out);
fputc('\n', f_out);
}
}

@@ -207,40 +198,36 @@ static int OpenWaveFile(const char *path, int rate)
// Set the length of 0x7ffff000 for --stdout
// This will be changed to the correct length for -w (write to file)
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;
if(path[0] != 0)
{
if(strcmp(path,"stdout")==0)
{
if (path[0] != 0) {
if (strcmp(path, "stdout") == 0) {
#ifdef PLATFORM_WINDOWS
// prevent Windows adding 0x0d before 0x0a bytes
_setmode(_fileno(stdout), _O_BINARY);
#endif
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;
}


@@ -250,17 +237,17 @@ static void CloseWaveFile()
{
unsigned int pos;

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

fflush(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);
@@ -282,32 +269,28 @@ static int WavegenFile(void)

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;
if((samples_split > 0 ) && (samples_total > samples_split))
{
if ((samples_split > 0 ) && (samples_total > samples_split)) {
CloseWaveFile();
samples_total = 0;
}
}

if(f_wave != NULL)
{
if (f_wave != NULL) {
samples_total += (out_ptr - wav_outbuf)/2;
fwrite(wav_outbuf, 1, out_ptr - wav_outbuf, f_wave);
}
return(finished);
return finished;
}


@@ -315,9 +298,8 @@ static int WavegenFile(void)
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;
}

@@ -329,18 +311,16 @@ static void init_path(char *argv0, char *path_specified)
char *env;
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
}

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
}

@@ -351,23 +331,21 @@ static void init_path(char *argv0, char *path_specified)
var_type = REG_SZ;
RegQueryValueEx(RegKey, "path", 0, &var_type, buf, &size);

sprintf(path_home,"%s\\espeak-data",buf);
sprintf(path_home, "%s\\espeak-data", buf);
#else
#ifdef PLATFORM_DOS
strcpy(path_home,PATH_ESPEAK_DATA);
strcpy(path_home, PATH_ESPEAK_DATA);
#else
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
}

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
@@ -384,35 +362,31 @@ static int initialise(void)
// to something other than the default "C". Then, not only Latin1 but also the
// other characters give the correct results with iswalpha() etc.
#ifdef PLATFORM_RISCOS
setlocale(LC_CTYPE,"ISO8859-1");
setlocale(LC_CTYPE, "ISO8859-1");
#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


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);
}
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();
SetVoiceStack(NULL, "");
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];

return(0);
return 0;
}


@@ -427,44 +401,43 @@ struct option {
int optind;
static int optional_argument;
static const char *arg_opts = "abfgklpsvw"; // which options have arguments
static char *opt_string="";
static char *opt_string = "";
#define no_argument 0
#define required_argument 1
#define optional_argument 2
#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 ";

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

int option_index = 0;
int c;
int value;
int speed=175;
int speed = 175;
int ix;
char *optarg2;
int amp = 100; // default
@@ -495,15 +468,13 @@ int main (int argc, char **argv)
#ifdef NEED_GETOPT
optind = 1;
opt_string = "";
while(optind < argc)
{
while (optind < argc) {
int len;
char *p;

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

optind++;
@@ -513,45 +484,36 @@ int main (int argc, char **argv)
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

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;
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;
optarg2 = NULL;

if((long_options[ix].has_arg != 0) && (p[len]=='='))
{
if ((long_options[ix].has_arg != 0) && (p[len] == '=')) {
optarg2 = &p[len+1];
}
break;
}
}
}
else
if(strchr(arg_opts,c) != NULL)
{
opt_string="";
if(optarg2[0]==0)
{
} else if (strchr(arg_opts, c) != NULL) {
opt_string = "";
if (optarg2[0] == 0) {
// the option's value is in the next argument
optarg2 = argv[optind++];
}
}
#else
while(true)
{
c = getopt_long (argc, argv, "a:b:f:g:hk:l: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. */
if (c == -1)
@@ -564,13 +526,13 @@ int main (int argc, char **argv)
case 'b':
// input character encoding, 8bit, 16bit, UTF8
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;

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);

case 'k':
@@ -591,7 +553,7 @@ int main (int argc, char **argv)

case 'p':
pitch_adjustment = atoi(optarg2);
if(pitch_adjustment > 99) pitch_adjustment = 99;
if (pitch_adjustment > 99) pitch_adjustment = 99;
break;

case 'q':
@@ -599,7 +561,7 @@ int main (int argc, char **argv)
break;

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

case 'l':
@@ -621,12 +583,12 @@ int main (int argc, char **argv)
break;

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

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

case 'z':
@@ -639,34 +601,33 @@ int main (int argc, char **argv)

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

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

case 0x103: // --punct
option_punctuation = 1;
if(optarg2 != NULL)
{
if (optarg2 != NULL) {
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_punctuation = 2;
}
break;

case 0x104: // --voices
init_path(argv[0],data_path);
DisplayVoices(stdout,optarg2);
init_path(argv[0], data_path);
DisplayVoices(stdout, optarg2);
exit(0);

case 0x106: // -- split
if(optarg2 == NULL)
if (optarg2 == NULL)
samples_split = 30; // default 30 minutes
else
samples_split = atoi(optarg2);
@@ -677,9 +638,8 @@ int main (int argc, char **argv)
break;

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;
}
break;
@@ -690,10 +650,9 @@ int main (int argc, char **argv)

case 0x10a: // --ipa
phoneme_options |= espeakPHONEMES_IPA;
if(optarg2 != NULL)
{
if (optarg2 != NULL) {
// deprecated and obsolete
switch(atoi(optarg2))
switch (atoi(optarg2))
{
case 1:
phonemes_separator = '_';
@@ -712,27 +671,27 @@ int main (int argc, char **argv)
break;

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);

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

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

@@ -741,154 +700,127 @@ int main (int argc, char **argv)
}
}

init_path(argv[0],data_path);
init_path(argv[0], data_path);
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;
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);
}
}

if(flag_compile)
{
if (flag_compile) {
#ifdef PLATFORM_DOS
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
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
#ifdef PLATFORM_WINDOWS
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
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
CompileDictionary(NULL,dictionary_name,NULL,NULL, flag_compile & 0x1);
CompileDictionary(NULL, dictionary_name, NULL, NULL, flag_compile & 0x1);
#endif
#endif
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);

if(pitch_adjustment != 50)
{
SetParameter(espeakPITCH,pitch_adjustment,0);
if (pitch_adjustment != 50) {
SetParameter(espeakPITCH, pitch_adjustment, 0);
}
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
// use it as text
p_text = argv[optind];
}
else
{
} else {
f_text = stdin;
if(flag_stdin == 0)
if (flag_stdin == 0)
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);
}

if(option_waveout || quiet)
{
if(quiet)
{
if (option_waveout || quiet) {
if (quiet) {
// no sound output
OpenWaveFile(NULL,samplerate);
OpenWaveFile(NULL, samplerate);
option_waveout = 1;
}
else
{
} else {
// write sound output to a WAV file
samples_split = (samplerate * samples_split) * 60;

if(samples_split)
{
if (samples_split) {
// don't open the wav file until we start generating speech
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;
}
}
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);
}
}

InitText(0);
SpeakNextClause(f_text,p_text,0);
SpeakNextClause(f_text, p_text, 0);

ix = 1;
for(;; )
{
if(WavegenFile() != 0)
{
if(ix == 0)
for (;;) {
if (WavegenFile() != 0) {
if (ix == 0)
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();
}
else
{
} else {
WavegenInitSound();

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;
while(speaking)
{
while (speaking) {
// NOTE: if nanosleep() isn't recognised on your system, try replacing
// this by sleep(1);
#ifdef PLATFORM_WINDOWS
@@ -899,17 +831,17 @@ int main (int argc, char **argv)
struct timespec remaining;
period.tv_sec = 0;
period.tv_nsec = 300000000; // 0.3 sec
nanosleep(&period,&remaining);
nanosleep(&period, &remaining);
#else
sleep(1);
#endif
#endif
if(SynthOnTimer() != 0)
if (SynthOnTimer() != 0)
speaking = 0;
}
}

if((f_trans != stdout) && (f_trans != stderr))
if ((f_trans != stdout) && (f_trans != stderr))
fclose(f_trans); // needed for WinCe
return(0);
return 0;
}

Loading…
Cancel
Save