Browse Source

Create langopts.c for language option configuration (#1419)

Loading Voice and Language options is complicated. They are not
separated in the code.

This PR creates langopts.c for holding language option related
configuration. In the future:
1. all new language options should go to langopts.c
2. voice options should have a similar file
3. LoadVoice should know if it's loading a voice or a language.
master
Juho Hiltunen 2 years ago
parent
commit
74fc17bbf1
No account linked to committer's email address

+ 2
- 0
Makefile.am View File

src/libespeak-ng/espeak_api.c \ src/libespeak-ng/espeak_api.c \
src/libespeak-ng/ieee80.c \ src/libespeak-ng/ieee80.c \
src/libespeak-ng/intonation.c \ src/libespeak-ng/intonation.c \
src/libespeak-ng/langopts.c \
src/libespeak-ng/mnemonics.c \ src/libespeak-ng/mnemonics.c \
src/libespeak-ng/numbers.c \ src/libespeak-ng/numbers.c \
src/libespeak-ng/readclause.c \ src/libespeak-ng/readclause.c \
src/libespeak-ng/ieee80.h \ src/libespeak-ng/ieee80.h \
src/libespeak-ng/intonation.h \ src/libespeak-ng/intonation.h \
src/libespeak-ng/klatt.h \ src/libespeak-ng/klatt.h \
src/libespeak-ng/langopts.h \
src/libespeak-ng/mbrola.h \ src/libespeak-ng/mbrola.h \
src/libespeak-ng/mbrowrap.h \ src/libespeak-ng/mbrowrap.h \
src/libespeak-ng/mnemonics.h \ src/libespeak-ng/mnemonics.h \

+ 1
- 0
android/jni/Android.mk View File

src/libespeak-ng/ieee80.c \ src/libespeak-ng/ieee80.c \
src/libespeak-ng/intonation.c \ src/libespeak-ng/intonation.c \
src/libespeak-ng/klatt.c \ src/libespeak-ng/klatt.c \
src/libespeak-ng/langopts.c \
src/libespeak-ng/mnemonics.c \ src/libespeak-ng/mnemonics.c \
src/libespeak-ng/numbers.c \ src/libespeak-ng/numbers.c \
src/libespeak-ng/phoneme.c \ src/libespeak-ng/phoneme.c \

+ 0
- 3
src/libespeak-ng/intonation.c View File

{ PITCHfall, 70, 18, PITCHfall, 70, 24, NULL, 32, 20, 0 }, // 12 test { PITCHfall, 70, 18, PITCHfall, 70, 24, NULL, 32, 20, 0 }, // 12 test
}; };


int n_tunes = 0;
TUNE *tunes = NULL;

#define SECONDARY 3 #define SECONDARY 3
#define PRIMARY 4 #define PRIMARY 4
#define PRIMARY_STRESSED 6 #define PRIMARY_STRESSED 6

+ 199
- 0
src/libespeak-ng/langopts.c View File

/*
* Copyright (C) 2005 to 2015 by Jonathan Duddington
* email: [email protected]
* Copyright (C) 2015-2017 Reece H. Dunn
* Copyright (C) 2022 Juho Hiltunen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see: <http://www.gnu.org/licenses/>.
*/

#include "config.h"

#include <ctype.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <espeak-ng/espeak_ng.h>
#include <espeak-ng/speak_lib.h>
#include <espeak-ng/encoding.h>

#include "langopts.h"
#include "mnemonics.h" // for MNEM_TAB
#include "translate.h" // for Translator
#include "synthdata.h" // for n_tunes, tunes
#include "voice.h" // for ReadNumbers, Read8Numbers, ...

static int CheckTranslator(Translator *tr, const MNEM_TAB *keyword_tab, int key);
static int LookupTune(const char *name);

extern const MNEM_TAB langopts_tab[];

void LoadLanguageOptions(Translator *translator, int key, char *keyValue ) {
if (CheckTranslator(translator, langopts_tab, key) != 0) {
return;
}

int ix;
int n;

switch (key) {
case V_DICTMIN: {


if (sscanf(keyValue, "%d", &n) == 1)
translator->dict_min_size = n;

break;
}

case V_DICTRULES: { // conditional dictionary rules and list entries
ReadNumbers(keyValue, &translator->dict_condition, 32, langopts_tab, key);
break;
}
case V_INTONATION: {
sscanf(keyValue, "%d", &option_tone_flags);
if ((option_tone_flags & 0xff) != 0) {
translator->langopts.intonation_group = option_tone_flags & 0xff;
}
break;
}
case V_NUMBERS: {
// expect a list of numbers
while (*keyValue != 0) {
while (isspace(*keyValue)) keyValue++;
if ((n = atoi(keyValue)) > 0) {
keyValue++;
if (n < 32) {
translator->langopts.numbers |= (1 << n);
} else {
if (n < 64)
translator->langopts.numbers2 |= (1 << (n-32));
else
fprintf(stderr, "numbers: Bad option number %d\n", n); }
}
while (isalnum(*keyValue)) keyValue++;
}
ProcessLanguageOptions(&(translator->langopts));

break;
}
case V_LOWERCASE_SENTENCE: {
translator->langopts.lowercase_sentence = true;
break;
}
case V_STRESSADD: { // stressAdd
int stress_add_set = 0;
int stress_add[8];

stress_add_set = Read8Numbers(keyValue, stress_add);

for (ix = 0; ix < stress_add_set; ix++) {
translator->stress_lengths[ix] += stress_add[ix];
}

break;
}
case V_STRESSAMP: {

int stress_amps_set = 0;
int stress_amps[8];

stress_amps_set = Read8Numbers(keyValue, stress_amps);

for (ix = 0; ix < stress_amps_set; ix++) {
translator->stress_amps[ix] = stress_amps[ix];
}

break;
}
case V_STRESSLENGTH: {
//printf("parsing: %s", keyValue);
int stress_lengths_set = 0;
int stress_lengths[8];
stress_lengths_set = Read8Numbers(keyValue, stress_lengths);

for (ix = 0; ix < stress_lengths_set; ix++) {
translator->stress_lengths[ix] = stress_lengths[ix];
}
break;
}
case V_STRESSOPT: {
ReadNumbers(keyValue, &translator->langopts.stress_flags, 32, langopts_tab, key);
break;
}
case V_STRESSRULE: {
sscanf(keyValue, "%d %d %d", &translator->langopts.stress_rule,
&translator->langopts.unstressed_wd1,
&translator->langopts.unstressed_wd2);

break;
}
case V_TUNES: {
char names[6][40] = { 0, 0, 0, 0, 0, 0 };
n = sscanf(keyValue, "%s %s %s %s %s %s", names[0], names[1], names[2], names[3], names[4], names[5]);
translator->langopts.intonation_group = 0;

for (ix = 0; ix < n; ix++) {
if (strcmp(names[ix], "NULL") == 0)
continue;

if ((n = LookupTune(names[ix])) < 0)
fprintf(stderr, "Unknown tune '%s'\n", names[ix]);
else
translator->langopts.tunes[ix] = n;
}
break;
}
case V_WORDGAP: {
sscanf(keyValue, "%d %d", &translator->langopts.word_gap, &translator->langopts.vowel_pause);
break;
}


case V_MAINTAINER:
case V_STATUS:
break;
default: {
if ((key & 0xff00) == 0x100) {
sscanf(keyValue, "%d", &translator->langopts.param[key &0xff]);
}
break;
}
}
}

static int LookupTune(const char *name) {
int ix;

for (ix = 0; ix < n_tunes; ix++) {
if (strcmp(name, tunes[ix].name) == 0)
return ix;
}
return -1;
}

int CheckTranslator(Translator *tr, const MNEM_TAB *keyword_tab, int key)
{
// Return 0 if translator is set.
// Return 1 and print an error message for specified key if not
// used for parsing language options
if (tr)
return 0;

fprintf(stderr, "Cannot set %s: language not set, or is invalid.\n", LookupMnemName(keyword_tab, key));
return 1;
}

+ 37
- 0
src/libespeak-ng/langopts.h View File

/*
* Copyright (C) 2005 to 2007 by Jonathan Duddington
* email: [email protected]
* Copyright (C) 2015 Reece H. Dunn
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see: <http://www.gnu.org/licenses/>.
*/

#ifndef ESPEAK_NG_LANGOPTS_H
#define ESPEAK_NG_LANGOPTS_H

#include <espeak-ng/espeak_ng.h>
#include "translate.h"

#ifdef __cplusplus
extern "C"
{
#endif

void LoadLanguageOptions(Translator *translator, int key, char *keyValue);

#ifdef __cplusplus
}
#endif

#endif

+ 3
- 0
src/libespeak-ng/synthdata.c View File

#include "translate.h" // for Translator, LANGUAGE_OPTIONS #include "translate.h" // for Translator, LANGUAGE_OPTIONS
#include "voice.h" // for ReadTonePoints, tone_points, voice #include "voice.h" // for ReadTonePoints, tone_points, voice


int n_tunes = 0;
TUNE *tunes = NULL;

const int version_phdata = 0x014801; const int version_phdata = 0x014801;


// copy the current phoneme table into here // copy the current phoneme table into here

+ 3
- 0
src/libespeak-ng/synthdata.h View File

void SelectPhonemeTable(int number); void SelectPhonemeTable(int number);
int SelectPhonemeTableName(const char *name); int SelectPhonemeTableName(const char *name);


extern int n_tunes;
extern TUNE *tunes;

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

+ 1
- 2
src/libespeak-ng/synthesize.h View File

int spare2; // the struct length should be a multiple of 4 bytes int spare2; // the struct length should be a multiple of 4 bytes
} TUNE; } TUNE;


extern int n_tunes;
extern TUNE *tunes;



// phoneme table // phoneme table
extern PHONEME_TAB *phoneme_tab[N_PHONEME_TAB]; extern PHONEME_TAB *phoneme_tab[N_PHONEME_TAB];

+ 1
- 1
src/libespeak-ng/tr_languages.c View File

tr->langopts.param[LOPT_IT_DOUBLING] = 1; tr->langopts.param[LOPT_IT_DOUBLING] = 1;
tr->langopts.long_stop = 130; tr->langopts.long_stop = 130;


tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_ALLOW_SPACE | NUM_DFRACTION_2 | NUM_ORDINAL_DOT;
// tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_ALLOW_SPACE | NUM_DFRACTION_2 | NUM_ORDINAL_DOT;
SetLetterVowel(tr, 'y'); SetLetterVowel(tr, 'y');
tr->langopts.spelling_stress = 1; tr->langopts.spelling_stress = 1;
tr->langopts.intonation_group = 3; // less intonation, don't raise pitch at comma tr->langopts.intonation_group = 3; // less intonation, don't raise pitch at comma

+ 109
- 0
src/libespeak-ng/voice.h View File



#include <espeak-ng/espeak_ng.h> #include <espeak-ng/espeak_ng.h>


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

#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C"
{ {
extern voice_t *voice; extern voice_t *voice;
extern int tone_points[12]; extern int tone_points[12];


typedef enum {
V_NAME = 1,
V_LANGUAGE,
V_GENDER,
V_PHONEMES,
V_DICTIONARY,
V_VARIANTS,

V_MAINTAINER,
V_STATUS,

// these affect voice quality, are independent of language
V_FORMANT,
V_PITCH,
V_ECHO,
V_FLUTTER,
V_ROUGHNESS,
V_CLARITY,
V_TONE,
V_VOICING,
V_BREATH,
V_BREATHW,

// these override defaults set by the translator
V_LOWERCASE_SENTENCE,
V_WORDGAP,
V_INTONATION,
V_TUNES,
V_STRESSLENGTH,
V_STRESSAMP,
V_STRESSADD,
V_DICTRULES,
V_STRESSRULE,
V_STRESSOPT,
V_NUMBERS,

V_MBROLA,
V_KLATT,
V_FAST,
V_SPEED,
V_DICTMIN,

// these need a phoneme table to have been specified
V_REPLACE,
V_CONSONANTS
} VOICELANGATTRIBUTES;

static const MNEM_TAB langopts_tab[] = {
{ "dictrules", V_DICTRULES },
{ "intonation", V_INTONATION },
{ "l_dieresis", 0x100+LOPT_DIERESES },
{ "l_prefix", 0x100+LOPT_PREFIXES },
{ "l_regressive_v", 0x100+LOPT_REGRESSIVE_VOICING },
{ "l_unpronouncable", 0x100+LOPT_UNPRONOUNCABLE },
{ "l_sonorant_min", 0x100+LOPT_SONORANT_MIN },
{ "lowercaseSentence", V_LOWERCASE_SENTENCE },
{ "numbers", V_NUMBERS },
{ "stressAdd", V_STRESSADD },
{ "stressAmp", V_STRESSAMP },
{ "stressLength", V_STRESSLENGTH },
{ "stressOpt", V_STRESSOPT },
{ "stressRule", V_STRESSRULE },
{ "tunes", V_TUNES },
{ "words", V_WORDGAP },

{ "maintainer", V_MAINTAINER },
{ "status", V_STATUS },

{ NULL, 0 }
};

static const MNEM_TAB keyword_tab[] = {
{ "name", V_NAME },
{ "language", V_LANGUAGE },
{ "gender", V_GENDER },
{ "variants", V_VARIANTS },
{ "formant", V_FORMANT },
{ "pitch", V_PITCH },
{ "phonemes", V_PHONEMES },
{ "dictionary", V_DICTIONARY },
{ "replace", V_REPLACE },
{ "echo", V_ECHO },
{ "flutter", V_FLUTTER },
{ "roughness", V_ROUGHNESS },
{ "clarity", V_CLARITY },
{ "tone", V_TONE },
{ "voicing", V_VOICING },
{ "breath", V_BREATH },
{ "breathw", V_BREATHW },
{ "mbrola", V_MBROLA },
{ "consonants", V_CONSONANTS },
{ "klatt", V_KLATT },
{ "fast_test2", V_FAST },
{ "speed", V_SPEED },
{ "dict_min", V_DICTMIN },


{ "apostrophe", 0x100+LOPT_APOSTROPHE },
{ "brackets", 0x100+LOPT_BRACKET_PAUSE },
{ "bracketsAnnounced", 0x100+LOPT_BRACKET_PAUSE_ANNOUNCED },

{ NULL, 0 }
};

const char *SelectVoice(espeak_VOICE *voice_select, int *found); const char *SelectVoice(espeak_VOICE *voice_select, int *found);
espeak_VOICE *SelectVoiceByName(espeak_VOICE **voices, const char *name); espeak_VOICE *SelectVoiceByName(espeak_VOICE **voices, const char *name);
voice_t *LoadVoice(const char *voice_name, int control); voice_t *LoadVoice(const char *voice_name, int control);
voice_t *LoadVoiceVariant(const char *voice_name, int variant); voice_t *LoadVoiceVariant(const char *voice_name, int variant);
espeak_ng_STATUS DoVoiceChange(voice_t *v); espeak_ng_STATUS DoVoiceChange(voice_t *v);
void WavegenSetVoice(voice_t *v); void WavegenSetVoice(voice_t *v);
void ReadNumbers(char *p, int *flags, int maxValue, const MNEM_TAB *keyword_tab, int key);
int Read8Numbers(char *data_in, int data[8]);
void ReadTonePoints(char *string, int *tone_pts); void ReadTonePoints(char *string, int *tone_pts);
void VoiceReset(int control); void VoiceReset(int control);
void FreeVoiceList(void); void FreeVoiceList(void);

+ 185
- 435
src/libespeak-ng/voices.c View File


/* /*
* Copyright (C) 2005 to 2015 by Jonathan Duddington * Copyright (C) 2005 to 2015 by Jonathan Duddington
* email: [email protected] * email: [email protected]
#include "voice.h" // for voice_t, DoVoiceChange, N_PEAKS #include "voice.h" // for voice_t, DoVoiceChange, N_PEAKS
#include "common.h" // for GetFileLength, strncpy0 #include "common.h" // for GetFileLength, strncpy0
#include "dictionary.h" // for LoadDictionary #include "dictionary.h" // for LoadDictionary
#include "langopts.h" // for LoadLanguageOptions
#include "mnemonics.h" // for LookupMnemName, MNEM_TAB #include "mnemonics.h" // for LookupMnemName, MNEM_TAB
#include "phoneme.h" // for REPLACE_PHONEMES, n_replace_pho... #include "phoneme.h" // for REPLACE_PHONEMES, n_replace_pho...
#include "speech.h" // for PATHSEP #include "speech.h" // for PATHSEP
#include "translate.h" // for LANGUAGE_OPTIONS, DeleteTranslator #include "translate.h" // for LANGUAGE_OPTIONS, DeleteTranslator
#include "wavegen.h" // for InitBreath #include "wavegen.h" // for InitBreath




static const MNEM_TAB genders[] = { static const MNEM_TAB genders[] = {
{ "male", ENGENDER_MALE }, { "male", ENGENDER_MALE },
{ "female", ENGENDER_FEMALE }, { "female", ENGENDER_FEMALE },


espeak_VOICE current_voice_selected; espeak_VOICE current_voice_selected;


enum {
V_NAME = 1,
V_LANGUAGE,
V_GENDER,
V_PHONEMES,
V_DICTIONARY,
V_VARIANTS,

V_MAINTAINER,
V_STATUS,

// these affect voice quality, are independent of language
V_FORMANT,
V_PITCH,
V_ECHO,
V_FLUTTER,
V_ROUGHNESS,
V_CLARITY,
V_TONE,
V_VOICING,
V_BREATH,
V_BREATHW,

// these override defaults set by the translator
V_LOWERCASE_SENTENCE,
V_WORDGAP,
V_INTONATION,
V_TUNES,
V_STRESSLENGTH,
V_STRESSAMP,
V_STRESSADD,
V_DICTRULES,
V_STRESSRULE,
V_STRESSOPT,
V_NUMBERS,

V_MBROLA,
V_KLATT,
V_FAST,
V_SPEED,
V_DICTMIN,

// these need a phoneme table to have been specified
V_REPLACE,
V_CONSONANTS
};

static const MNEM_TAB keyword_tab[] = {
{ "name", V_NAME },
{ "language", V_LANGUAGE },
{ "gender", V_GENDER },

{ "maintainer", V_MAINTAINER },
{ "status", V_STATUS },


{ "lowercaseSentence", V_LOWERCASE_SENTENCE },
{ "variants", V_VARIANTS },
{ "formant", V_FORMANT },
{ "pitch", V_PITCH },
{ "phonemes", V_PHONEMES },
{ "dictionary", V_DICTIONARY },
{ "stressLength", V_STRESSLENGTH },
{ "stressAmp", V_STRESSAMP },
{ "stressAdd", V_STRESSADD },
{ "intonation", V_INTONATION },
{ "tunes", V_TUNES },
{ "dictrules", V_DICTRULES },
{ "stressRule", V_STRESSRULE },
{ "stressOpt", V_STRESSOPT },
{ "replace", V_REPLACE },
{ "words", V_WORDGAP },
{ "echo", V_ECHO },
{ "flutter", V_FLUTTER },
{ "roughness", V_ROUGHNESS },
{ "clarity", V_CLARITY },
{ "tone", V_TONE },
{ "voicing", V_VOICING },
{ "breath", V_BREATH },
{ "breathw", V_BREATHW },
{ "numbers", V_NUMBERS },
{ "mbrola", V_MBROLA },
{ "consonants", V_CONSONANTS },
{ "klatt", V_KLATT },
{ "fast_test2", V_FAST },
{ "speed", V_SPEED },
{ "dict_min", V_DICTMIN },

// these just set a value in langopts.param[]
{ "l_dieresis", 0x100+LOPT_DIERESES },
{ "l_prefix", 0x100+LOPT_PREFIXES },
{ "l_regressive_v", 0x100+LOPT_REGRESSIVE_VOICING },
{ "l_unpronouncable", 0x100+LOPT_UNPRONOUNCABLE },
{ "l_sonorant_min", 0x100+LOPT_SONORANT_MIN },
{ "apostrophe", 0x100+LOPT_APOSTROPHE },
{ "brackets", 0x100+LOPT_BRACKET_PAUSE },
{ "bracketsAnnounced", 0x100+LOPT_BRACKET_PAUSE_ANNOUNCED },

{ NULL, 0 }
};

#define N_VOICE_VARIANTS 12 #define N_VOICE_VARIANTS 12
const char variants_either[N_VOICE_VARIANTS] = { 1, 2, 12, 3, 13, 4, 14, 5, 11, 0 }; const char variants_either[N_VOICE_VARIANTS] = { 1, 2, 12, 3, 13, 4, 14, 5, 11, 0 };
const char variants_male[N_VOICE_VARIANTS] = { 1, 2, 3, 4, 5, 6, 0 }; const char variants_male[N_VOICE_VARIANTS] = { 1, 2, 3, 4, 5, 6, 0 };
return buf; return buf;
} }


static int LookupTune(const char *name)
{
int ix;

for (ix = 0; ix < n_tunes; ix++) {
if (strcmp(name, tunes[ix].name) == 0)
return ix;
}
return -1;
}

static void SetToneAdjust(voice_t *voice, int *tone_pts) static void SetToneAdjust(voice_t *voice, int *tone_pts)
{ {
int ix; int ix;
replace_phonemes[n_replace_phonemes++].type = flags; replace_phonemes[n_replace_phonemes++].type = flags;
} }


static int Read8Numbers(char *data_in, int data[8])
int Read8Numbers(char *data_in, int data[8])
{ {
// Read 8 integer numbers // Read 8 integer numbers
memset(data, 0, 8*sizeof(int)); memset(data, 0, 8*sizeof(int));
&data[0], &data[1], &data[2], &data[3], &data[4], &data[5], &data[6], &data[7]); &data[0], &data[1], &data[2], &data[3], &data[4], &data[5], &data[6], &data[7]);
} }


static void ReadNumbers(char *p, int *flags, int maxValue, const MNEM_TAB *keyword_tab, int key) {
void ReadNumbers(char *p, int *flags, int maxValue, const MNEM_TAB *keyword_tab, int key) {
// read a list of numbers from string p // read a list of numbers from string p
// store them as flags in *flags // store them as flags in *flags
// the meaning of the numbers is bit ordinals, not integer values // the meaning of the numbers is bit ordinals, not integer values
} }
} }


static int CheckTranslator(Translator *tr, const MNEM_TAB *keyword_tab, int key)
{
// Return 0 if translator is set.
// Return 1 and print an error message for specified key if not
// used for parsing language options
if (tr)
return 0;

fprintf(stderr, "Cannot set %s: language not set, or is invalid.\n", LookupMnemName(keyword_tab, key));
return 1;
}

voice_t *LoadVoice(const char *vname, int control) voice_t *LoadVoice(const char *vname, int control)
{ {
// control, bit 0 1= no_default // control, bit 0 1= no_default
char *p; char *p;
int key; int key;
int ix; int ix;
int n;
int value; int value;
int langix = 0; int langix = 0;
int tone_only = control & 2; int tone_only = control & 2;
char buf[sizeof(path_home)+30]; char buf[sizeof(path_home)+30];
char path_voices[sizeof(path_home)+12]; char path_voices[sizeof(path_home)+12];


int stress_add[8];
char names[8][40];

char name1[40]; char name1[40];
char name2[80]; char name2[80];




if (buf[0] == 0) continue; if (buf[0] == 0) continue;


key = LookupMnem(keyword_tab, buf);

switch (key)
{
case V_LANGUAGE:
{
unsigned int len;
int priority;

if (tone_only)
break;

priority = DEFAULT_LANGUAGE_PRIORITY;
language_name[0] = 0;

sscanf(p, "%s %d", language_name, &priority);
if (strcmp(language_name, "variant") == 0)
break;

len = strlen(language_name) + 2;
// check for space in languages[]
if (len < (sizeof(voice_languages)-langix-1)) {
voice_languages[langix] = priority;

strcpy(&voice_languages[langix+1], language_name);
langix += len;
}

// only act on the first language line
if (language_set == false) {
language_type = strtok(language_name, "-");
language_set = true;
strcpy(translator_name, language_type);
strcpy(new_dictionary, language_type);
strcpy(phonemes_name, language_type);
SelectPhonemeTableName(phonemes_name);

translator = SelectTranslator(translator_name);
strncpy0(voice->language_name, language_name, sizeof(voice->language_name));
}
}
break;
case V_NAME:
if (tone_only == 0) {
while (isspace(*p)) p++;
strncpy0(voice_name, p, sizeof(voice_name));
}
break;
case V_GENDER:
{
int age = 0;
char vgender[80];
sscanf(p, "%s %d", vgender, &age);
current_voice_selected.gender = LookupMnem(genders, vgender);
current_voice_selected.age = age;
}
break;
case V_DICTIONARY: // dictionary
sscanf(p, "%s", new_dictionary);
break;
case V_PHONEMES: // phoneme table
sscanf(p, "%s", phonemes_name);
break;
case V_FORMANT:
VoiceFormant(p);
break;
case V_LOWERCASE_SENTENCE: {
if (CheckTranslator(translator, keyword_tab, key) != 0)
break;

translator->langopts.lowercase_sentence = true;
break;
}

case V_PITCH:
// default is pitch 82 118
if (sscanf(p, "%d %d", &pitch1, &pitch2) == 2) {
voice->pitch_base = (pitch1 - 9) << 12;
voice->pitch_range = (pitch2 - pitch1) * 108;
double factor = (double)(pitch1 - 82)/82;
voice->formant_factor = (int)((1+factor/4) * 256); // nominal formant shift for a different voice pitch
}
break;
case V_STRESSLENGTH: {// stressLength
if (CheckTranslator(translator, keyword_tab, key) != 0)
break;

int stress_lengths_set = 0;
int stress_lengths[8];
stress_lengths_set = Read8Numbers(p, stress_lengths);

for (ix = 0; ix < stress_lengths_set; ix++) {
translator->stress_lengths[ix] = stress_lengths[ix];
}

break;
}
case V_STRESSAMP: { // stressAmp
if (CheckTranslator(translator, keyword_tab, key) != 0)
break;

int stress_amps_set = 0;
int stress_amps[8];
stress_amps_set = Read8Numbers(p, stress_amps);
for (ix = 0; ix < stress_amps_set; ix++) {
translator->stress_amps[ix] = stress_amps[ix];
}

break;
}
case V_STRESSADD: { // stressAdd
if (CheckTranslator(translator, keyword_tab, key) != 0)
break;

int stress_add_set = 0;
stress_add_set = Read8Numbers(p, stress_add);

for (ix = 0; ix < stress_add_set; ix++) {
translator->stress_lengths[ix] += stress_add[ix];
}

break;
}
case V_INTONATION: // intonation
sscanf(p, "%d", &option_tone_flags);
if ((option_tone_flags & 0xff) != 0) {
if (CheckTranslator(translator, keyword_tab, key) != 0)
break;

translator->langopts.intonation_group = option_tone_flags & 0xff;
}
break;
case V_TUNES:
if (CheckTranslator(translator, keyword_tab, key) != 0)
break;

n = sscanf(p, "%s %s %s %s %s %s", names[0], names[1], names[2], names[3], names[4], names[5]);
translator->langopts.intonation_group = 0;

for (ix = 0; ix < n; ix++) {
if (strcmp(names[ix], "NULL") == 0)
continue;

if ((value = LookupTune(names[ix])) < 0)
fprintf(stderr, "Unknown tune '%s'\n", names[ix]);
else
translator->langopts.tunes[ix] = value;
}
break;

case V_DICTRULES: // conditional dictionary rules and list entries
if (CheckTranslator(translator, keyword_tab, key) != 0)
break;

ReadNumbers(p, &translator->dict_condition, 32, keyword_tab, key);
break;
case V_STRESSOPT:
if (CheckTranslator(translator, keyword_tab, key) != 0)
break;

ReadNumbers(p, &translator->langopts.stress_flags, 32, keyword_tab, key);
break;

case V_NUMBERS:
if (CheckTranslator(translator, keyword_tab, key) != 0)
break;

// expect a list of numbers
while (*p != 0) {
while (isspace(*p)) p++;
if ((n = atoi(p)) > 0) {
p++;
if (n < 32) {
translator->langopts.numbers |= (1 << n);
} else {
if (n < 64)
translator->langopts.numbers2 |= (1 << (n-32));
else
fprintf(stderr, "numbers: Bad option number %d\n", n); }
}
while (isalnum(*p)) p++;
}
ProcessLanguageOptions(&(translator->langopts));

break;
case V_REPLACE:
if (phonemes_set == false) {
// must set up a phoneme table before we can lookup phoneme mnemonics
SelectPhonemeTableName(phonemes_name);
phonemes_set = true;
}
PhonemeReplacement(p);
break;
case V_WORDGAP: // words
if (CheckTranslator(translator, keyword_tab, key) != 0)
break;

sscanf(p, "%d %d", &translator->langopts.word_gap, &translator->langopts.vowel_pause);
break;
case V_STRESSRULE:
if (CheckTranslator(translator, keyword_tab, key) != 0)
break;

sscanf(p, "%d %d %d", &translator->langopts.stress_rule,
&translator->langopts.unstressed_wd1,
&translator->langopts.unstressed_wd2);

break;
case V_ECHO:
// echo. suggest: 135mS 11%
value = 0;
voice->echo_amp = 0;
sscanf(p, "%d %d", &voice->echo_delay, &voice->echo_amp);
break;
case V_FLUTTER: // flutter
if (sscanf(p, "%d", &value) == 1)
voice->flutter = value * 32;
break;
case V_ROUGHNESS: // roughness
if (sscanf(p, "%d", &value) == 1)
voice->roughness = value;
break;
case V_CLARITY: // formantshape
if (sscanf(p, "%d", &value) == 1) {
if (value > 4) {
voice->peak_shape = 1; // squarer formant peaks
value = 4;
}
voice->n_harmonic_peaks = 1+value;
}
break;
case V_TONE:
{
int tone_data[12];
ReadTonePoints(p, tone_data);
SetToneAdjust(voice, tone_data);
}
break;
case V_VOICING:
if (sscanf(p, "%d", &value) == 1)
voice->voicing = (value * 64)/100;
break;
case V_BREATH:
voice->breath[0] = Read8Numbers(p, &voice->breath[1]);
for (ix = 1; ix < 8; ix++) {
if (ix % 2)
voice->breath[ix] = -voice->breath[ix];
}
break;
case V_BREATHW:
voice->breathw[0] = Read8Numbers(p, &voice->breathw[1]);
break;
case V_CONSONANTS:
value = sscanf(p, "%d %d", &voice->consonant_amp, &voice->consonant_ampv);
break;
case V_SPEED:
sscanf(p, "%d", &voice->speed_percent);
SetSpeed(3);
break;
case V_MBROLA:
{
int srate = 16000;

name2[0] = 0;
sscanf(p, "%s %s %d", name1, name2, &srate);
espeak_ng_STATUS status = LoadMbrolaTable(name1, name2, &srate);
if (status != ENS_OK) {
espeak_ng_PrintStatusCodeMessage(status, stderr, NULL);
fclose(f_voice);
return NULL;
}
else
voice->samplerate = srate;
}
break;
case V_KLATT:
voice->klattv[0] = 1; // default source: IMPULSIVE
Read8Numbers(p, voice->klattv);
voice->klattv[KLATT_Kopen] -= 40;
break;
case V_FAST:
sscanf(p, "%d", &speed.fast_settings);
SetSpeed(3);
break;
case V_DICTMIN: {
if (CheckTranslator(translator, keyword_tab, key) != 0)
break;

if (sscanf(p, "%d", &value) == 1)
translator->dict_min_size = value;
break;
}

break;
case V_MAINTAINER:
case V_STATUS:
break;
default:
if ((key & 0xff00) == 0x100) {
if (CheckTranslator(translator, keyword_tab, key) != 0)
break;
sscanf(p, "%d", &translator->langopts.param[key &0xff]);
} else
fprintf(stderr, "Bad voice attribute: %s\n", buf);
break;
}
key = LookupMnem(langopts_tab, buf);

if (key != 0) {
LoadLanguageOptions(translator, key, p);
} else {
key = LookupMnem(keyword_tab, buf);
switch (key)
{
case V_LANGUAGE:
{
unsigned int len;
int priority;

if (tone_only)
break;

priority = DEFAULT_LANGUAGE_PRIORITY;
language_name[0] = 0;

sscanf(p, "%s %d", language_name, &priority);
if (strcmp(language_name, "variant") == 0)
break;

len = strlen(language_name) + 2;
// check for space in languages[]
if (len < (sizeof(voice_languages)-langix-1)) {
voice_languages[langix] = priority;

strcpy(&voice_languages[langix+1], language_name);
langix += len;
}

// only act on the first language line
if (language_set == false) {
language_type = strtok(language_name, "-");
language_set = true;
strcpy(translator_name, language_type);
strcpy(new_dictionary, language_type);
strcpy(phonemes_name, language_type);
SelectPhonemeTableName(phonemes_name);

translator = SelectTranslator(translator_name);
strncpy0(voice->language_name, language_name, sizeof(voice->language_name));
}
}
break;
case V_NAME:
if (tone_only == 0) {
while (isspace(*p)) p++;
strncpy0(voice_name, p, sizeof(voice_name));
}
break;
case V_GENDER:
{
int age = 0;
char vgender[80];
sscanf(p, "%s %d", vgender, &age);
current_voice_selected.gender = LookupMnem(genders, vgender);
current_voice_selected.age = age;
}
break;
case V_DICTIONARY: // dictionary
sscanf(p, "%s", new_dictionary);
break;
case V_PHONEMES: // phoneme table
sscanf(p, "%s", phonemes_name);
break;
case V_FORMANT:
VoiceFormant(p);
break;
case V_PITCH:
// default is pitch 82 118
if (sscanf(p, "%d %d", &pitch1, &pitch2) == 2) {
voice->pitch_base = (pitch1 - 9) << 12;
voice->pitch_range = (pitch2 - pitch1) * 108;
double factor = (double)(pitch1 - 82)/82;
voice->formant_factor = (int)((1+factor/4) * 256); // nominal formant shift for a different voice pitch
}
break;





case V_REPLACE:
if (phonemes_set == false) {
// must set up a phoneme table before we can lookup phoneme mnemonics
SelectPhonemeTableName(phonemes_name);
phonemes_set = true;
}
PhonemeReplacement(p);
break;

case V_ECHO:
// echo. suggest: 135mS 11%
value = 0;
voice->echo_amp = 0;
sscanf(p, "%d %d", &voice->echo_delay, &voice->echo_amp);
break;
case V_FLUTTER: // flutter
if (sscanf(p, "%d", &value) == 1)
voice->flutter = value * 32;
break;
case V_ROUGHNESS: // roughness
if (sscanf(p, "%d", &value) == 1)
voice->roughness = value;
break;
case V_CLARITY: // formantshape
if (sscanf(p, "%d", &value) == 1) {
if (value > 4) {
voice->peak_shape = 1; // squarer formant peaks
value = 4;
}
voice->n_harmonic_peaks = 1+value;
}
break;
case V_TONE:
{
int tone_data[12];
ReadTonePoints(p, tone_data);
SetToneAdjust(voice, tone_data);
}
break;
case V_VOICING:
if (sscanf(p, "%d", &value) == 1)
voice->voicing = (value * 64)/100;
break;
case V_BREATH:
voice->breath[0] = Read8Numbers(p, &voice->breath[1]);
for (ix = 1; ix < 8; ix++) {
if (ix % 2)
voice->breath[ix] = -voice->breath[ix];
}
break;
case V_BREATHW:
voice->breathw[0] = Read8Numbers(p, &voice->breathw[1]);
break;
case V_CONSONANTS:
value = sscanf(p, "%d %d", &voice->consonant_amp, &voice->consonant_ampv);
break;
case V_SPEED:
sscanf(p, "%d", &voice->speed_percent);
SetSpeed(3);
break;
case V_MBROLA:
{
int srate = 16000;

name2[0] = 0;
sscanf(p, "%s %s %d", name1, name2, &srate);
espeak_ng_STATUS status = LoadMbrolaTable(name1, name2, &srate);
if (status != ENS_OK) {
espeak_ng_PrintStatusCodeMessage(status, stderr, NULL);
fclose(f_voice);
return NULL;
}
else
voice->samplerate = srate;
}
break;
case V_KLATT:
voice->klattv[0] = 1; // default source: IMPULSIVE
Read8Numbers(p, voice->klattv);
voice->klattv[KLATT_Kopen] -= 40;
break;
case V_FAST:
sscanf(p, "%d", &speed.fast_settings);
SetSpeed(3);
break;

case V_MAINTAINER:
case V_STATUS:
break;
default:
fprintf(stderr, "Bad voice attribute: %s\n", buf);
break;
}
}
} }
if (f_voice != NULL) if (f_voice != NULL)
fclose(f_voice); fclose(f_voice);

+ 3
- 1
src/windows/libespeak-ng.vcxproj View File

<ClCompile Include="..\libespeak-ng\ieee80.c" /> <ClCompile Include="..\libespeak-ng\ieee80.c" />
<ClCompile Include="..\libespeak-ng\intonation.c" /> <ClCompile Include="..\libespeak-ng\intonation.c" />
<ClCompile Include="..\libespeak-ng\klatt.c" /> <ClCompile Include="..\libespeak-ng\klatt.c" />
<ClCompile Include="..\libespeak-ng\langopts.c" />
<ClCompile Include="..\libespeak-ng\mbrowrap.c" /> <ClCompile Include="..\libespeak-ng\mbrowrap.c" />
<ClCompile Include="..\libespeak-ng\mnemonics.c" /> <ClCompile Include="..\libespeak-ng\mnemonics.c" />
<ClCompile Include="..\libespeak-ng\numbers.c" /> <ClCompile Include="..\libespeak-ng\numbers.c" />
<ClInclude Include="..\libespeak-ng\common.h" /> <ClInclude Include="..\libespeak-ng\common.h" />
<ClInclude Include="..\libespeak-ng\error.h" /> <ClInclude Include="..\libespeak-ng\error.h" />
<ClInclude Include="..\libespeak-ng\klatt.h" /> <ClInclude Include="..\libespeak-ng\klatt.h" />
<ClInclude Include="..\libespeak-ng\langopts.h" />
<ClInclude Include="..\libespeak-ng\mbrowrap.h" /> <ClInclude Include="..\libespeak-ng\mbrowrap.h" />
<ClInclude Include="..\libespeak-ng\phoneme.h" /> <ClInclude Include="..\libespeak-ng\phoneme.h" />
<ClInclude Include="..\libespeak-ng\sintab.h" /> <ClInclude Include="..\libespeak-ng\sintab.h" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
</ImportGroup> </ImportGroup>
</Project>
</Project>

+ 7
- 1
src/windows/libespeak-ng.vcxproj.filters View File

<ClCompile Include="..\libespeak-ng\klatt.c"> <ClCompile Include="..\libespeak-ng\klatt.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\libespeak-ng\langopts.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\libespeak-ng\mbrowrap.c"> <ClCompile Include="..\libespeak-ng\mbrowrap.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClInclude Include="..\libespeak-ng\klatt.h"> <ClInclude Include="..\libespeak-ng\klatt.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\libespeak-ng\langopts.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\libespeak-ng\mbrowrap.h"> <ClInclude Include="..\libespeak-ng\mbrowrap.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</None> </None>
</ItemGroup> </ItemGroup>
</Project>
</Project>

Loading…
Cancel
Save