/* read in the headers */ void header_load(FILE *f) { char line[1024]; header_clear(); while (1) { char *p; if (!fgets_strip(line, sizeof(line)-1, f)) { errmsg("Failed to read header %d\n", num_headers); exit_cleanup(1); } /* it may be the end of the headers */ if (line[0] == 0) break; p = strchr(line,':'); if (!p) { errmsg("no colon in header?!? [%s]\n", line); exit_cleanup(1); } *p++ = 0; while (*p && isspace(*p)) p++; header_add(line, p); } }
voice_t *LoadVoice(const char *vname, int control) {//=============================================== // control, bit 0 1= no_default // bit 1 1 = change tone only, not language // bit 2 1 = don't report error on LoadDictionary // bit 4 1 = vname = full path FILE *f_voice = NULL; char *p; int key; int ix; int n; int value; int value2; int langix = 0; int tone_only = control & 2; int language_set = 0; int phonemes_set = 0; int stress_amps_set = 0; int stress_lengths_set = 0; int stress_add_set = 0; int conditional_rules = 0; LANGUAGE_OPTIONS *langopts = NULL; Translator *new_translator = NULL; char voicename[40]; char language_name[40]; char translator_name[40]; char new_dictionary[40]; char phonemes_name[40]; char option_name[40]; const char *language_type; char buf[sizeof(path_home)+30]; char path_voices[sizeof(path_home)+12]; int dict_min = 0; int stress_amps[8]; int stress_lengths[8]; int stress_add[8]; char names[8][40]; char name1[40]; char name2[80]; const char *voice_dir; int pitch1; int pitch2; static char voice_identifier[40]; // file name for current_voice_selected static char voice_name[40]; // voice name for current_voice_selected static char voice_languages[100]; // list of languages and priorities for current_voice_selected // which directory to look for a named voice. List of voice names, must end in a space. static const char *voices_asia = "az bn fa fa-pin gu hi hy hy-west id ka kn ku ml ms ne pa ta te tr vi vi-hue vi-sgn zh zh-yue "; static const char *voices_europe = "an bg bs ca cs cy da de el en en-us es et eu fi fr fr-be ga hr hu is it lt lv mk nl no pl pt-pt ro ru sk sq sr sv "; strncpy0(voicename, vname, sizeof(voicename)); if(control & 0x10) { strcpy(buf,vname); if(GetFileLength(buf) <= 0) return(NULL); } else { if(voicename[0]==0) strcpy(voicename,"default"); sprintf(path_voices,"%s%cvoices%c",path_home,PATHSEP,PATHSEP); sprintf(buf,"%s%s",path_voices,voicename); // first, look in the main voices directory if(GetFileLength(buf) <= 0) { // then look in the appropriate subdirectory if((voicename[0]=='m') && (voicename[1]=='b')) { voice_dir = "mb"; // mbrola voices } else { sprintf(name2, "%s ", voicename); if(strstr(voices_europe, voicename) != NULL) voice_dir = "europe"; else if(strstr(voices_asia, voicename) != NULL) voice_dir = "asia"; else voice_dir = "other"; sprintf(buf,"%s%s%c%s", path_voices,voice_dir,PATHSEP,voicename); if(GetFileLength(buf) <= 0) { // if not found, look in "test" sub-directory sprintf(buf,"%stest%c%s",path_voices,PATHSEP,voicename); } } } } f_voice = fopen(buf,"r"); language_type = "en"; // default if(f_voice == NULL) { if(control & 3) return(NULL); // can't open file if(SelectPhonemeTableName(voicename) >= 0) language_type = voicename; } if(!tone_only && (translator != NULL)) { DeleteTranslator(translator); translator = NULL; } strcpy(translator_name,language_type); strcpy(new_dictionary,language_type); strcpy(phonemes_name,language_type); if(!tone_only) { voice = &voicedata; strncpy0(voice_identifier,vname,sizeof(voice_identifier)); voice_name[0] = 0; voice_languages[0] = 0; current_voice_selected.identifier = voice_identifier; current_voice_selected.name = voice_name; current_voice_selected.languages = voice_languages; } else { // append the variant file name to the voice identifier if((p = strchr(voice_identifier,'+')) != NULL) *p = 0; // remove previous variant name sprintf(buf,"+%s",&vname[3]); // omit !v/ from the variant filename strcat(voice_identifier,buf); langopts = &translator->langopts; } VoiceReset(tone_only); if(!tone_only) SelectPhonemeTableName(phonemes_name); // set up phoneme_tab while((f_voice != NULL) && (fgets_strip(buf,sizeof(buf),f_voice) != NULL)) { // isolate the attribute name for(p=buf; (*p != 0) && !isspace(*p); p++); *p++ = 0; 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 == 0) { language_type = strtok(language_name,"-"); language_set = 1; strcpy(translator_name,language_type); strcpy(new_dictionary,language_type); strcpy(phonemes_name,language_type); SelectPhonemeTableName(phonemes_name); if(new_translator != NULL) DeleteTranslator(new_translator); new_translator = SelectTranslator(translator_name); langopts = &new_translator->langopts; 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_TRANSLATOR: if(tone_only) break; sscanf(p,"%s",translator_name); if(new_translator != NULL) DeleteTranslator(new_translator); new_translator = SelectTranslator(translator_name); langopts = &new_translator->langopts; 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: { double factor; // default is pitch 82 118 n = sscanf(p,"%d %d",&pitch1,&pitch2); voice->pitch_base = (pitch1 - 9) << 12; voice->pitch_range = (pitch2 - pitch1) * 108; 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 stress_lengths_set = Read8Numbers(p,stress_lengths); break; case V_STRESSAMP: // stressAmp stress_amps_set = Read8Numbers(p,stress_amps); break; case V_STRESSADD: // stressAdd stress_add_set = Read8Numbers(p,stress_add); break; case V_INTONATION: // intonation sscanf(p,"%d %d",&option_tone_flags,&option_tone2); if((option_tone_flags & 0xff) != 0) langopts->intonation_group = option_tone_flags & 0xff; break; case V_TUNES: n = sscanf(p,"%s %s %s %s %s %s",names[0],names[1],names[2],names[3],names[4],names[5]); 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 langopts->tunes[ix] = value; } break; case V_DICTRULES: // conditional dictionary rules and list entries case V_NUMBERS: case V_STRESSOPT: // expect a list of numbers while(*p != 0) { while(isspace(*p)) p++; n = -1; if((n = atoi(p)) > 0) { p++; if(n < 32) { if(key==V_DICTRULES) conditional_rules |= (1 << n); else if(key==V_NUMBERS) langopts->numbers |= (1 << n); else if(key==V_STRESSOPT) langopts->stress_flags |= (1 << n); } else { if((key==V_NUMBERS) && (n < 64)) langopts->numbers |= (1 << (n-32)); else fprintf(stderr,"Bad option number %d\n", n); } } while(isalnum(*p)) p++; } ProcessLanguageOptions(langopts); break; case V_REPLACE: if(phonemes_set == 0) { // must set up a phoneme table before we can lookup phoneme mnemonics SelectPhonemeTableName(phonemes_name); phonemes_set = 1; } PhonemeReplacement(key,p); break; case V_WORDGAP: // words sscanf(p,"%d %d",&langopts->word_gap, &langopts->vowel_pause); break; case V_STRESSRULE: sscanf(p,"%d %d %d %d",&langopts->stress_rule, &langopts->stress_flags, &langopts->unstressed_wd1, &langopts->unstressed_wd2); break; case V_CHARSET: if((sscanf(p,"%d",&value)==1) && (value < N_CHARSETS)) new_translator->charset_a0 = charsets[value]; break; case V_OPTION: value2 = 0; if(((sscanf(p,"%s %d %d",option_name,&value,&value2) >= 2) && ((ix = LookupMnem(options_tab, option_name)) >= 0)) || ((sscanf(p,"%d %d %d",&ix,&value,&value2) >= 2) && (ix < N_LOPTS))) { langopts->param[ix] = value; langopts->param2[ix] = value2; } else { fprintf(stderr,"Bad voice option: %s %s\n",buf,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); break; case V_MBROLA: { int srate = 16000; name2[0] = 0; sscanf(p,"%s %s %d",name1,name2,&srate); if(LoadMbrolaTable(name1,name2,srate) != EE_OK) { fprintf(stderr,"mbrola voice not found\n"); } 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: Read8Numbers(p,speed.fast_settings); SetSpeed(3); break; case V_DICTMIN: sscanf(p,"%d",&dict_min); break; case V_ALPHABET2: { ALPHABET *alphabet; name1[0] = name2[0] = 0; sscanf(p, "%s %s", name1, name2); if(strcmp(name1, "latin") == 0) { strncpy0(langopts->ascii_language,name2,sizeof(langopts->ascii_language)); } else if((alphabet = AlphabetFromName(name1)) != 0) { langopts->alt_alphabet = alphabet->offset; langopts->alt_alphabet_lang = StringToWord2(name2); } else { fprintf(stderr,"alphabet name '%s' not found\n", name1); } } break; case V_DICTDIALECT: // specify a dialect to use for foreign words, eg, en-us for _^_EN if(sscanf(p, "%s", name1) == 1) { if((ix = LookupMnem(dict_dialects, name1)) > 0) { langopts->dict_dialect |= (1 << ix); } else { fprintf(stderr, "dictdialect name '%s' not recognized\n", name1); } } break; default: if((key & 0xff00) == 0x100) { sscanf(p,"%d",&langopts->param[key &0xff]); } else { fprintf(stderr,"Bad voice attribute: %s\n",buf); } break; } } if(f_voice != NULL) fclose(f_voice); if((new_translator == NULL) && (!tone_only)) { // not set by language attribute new_translator = SelectTranslator(translator_name); } SetSpeed(3); // for speed_percent for(ix=0; ix<N_PEAKS; ix++) { voice->freq2[ix] = voice->freq[ix]; voice->height2[ix] = voice->height[ix]; voice->width2[ix] = voice->width[ix]; } if(tone_only) { new_translator = translator; } else { if((ix = SelectPhonemeTableName(phonemes_name)) < 0) { fprintf(stderr,"Unknown phoneme table: '%s'\n",phonemes_name); ix = 0; } voice->phoneme_tab_ix = ix; new_translator->phoneme_tab_ix = ix; new_translator->dict_min_size = dict_min; LoadDictionary(new_translator, new_dictionary, control & 4); if(dictionary_name[0]==0) return(NULL); // no dictionary loaded new_translator->dict_condition = conditional_rules; voice_languages[langix] = 0; } langopts = &new_translator->langopts; if((value = langopts->param[LOPT_LENGTH_MODS]) != 0) { SetLengthMods(new_translator,value); } voice->width[0] = (voice->width[0] * 105)/100; if(!tone_only) { translator = new_translator; } // relative lengths of different stress syllables for(ix=0; ix<stress_lengths_set; ix++) { translator->stress_lengths[ix] = stress_lengths[ix]; } for(ix=0; ix<stress_add_set; ix++) { translator->stress_lengths[ix] += stress_add[ix]; } for(ix=0; ix<stress_amps_set; ix++) { translator->stress_amps[ix] = stress_amps[ix]; translator->stress_amps_r[ix] = stress_amps[ix] -1; } return(voice); } // end of LoadVoice
static espeak_VOICE *ReadVoiceFile(FILE *f_in, const char *fname, const char*leafname) {//=================================================================================== // Read a Voice file, allocate a VOICE_DATA and set data from the // file's language, gender, name lines char linebuf[120]; char vname[80]; char vgender[80]; char vlanguage[80]; char languages[300]; // allow space for several alternate language names and priorities unsigned int len; int langix = 0; int n_languages = 0; char *p; espeak_VOICE *voice_data; int priority; int age; int n_variants = 4; // default, number of variants of this voice before using another voice int gender; #ifdef PLATFORM_WINDOWS char fname_buf[sizeof(path_home)+15]; if(memcmp(leafname,"mb-",3) == 0) { // check whether the mbrola speech data is present for this voice memcpy(vname,&leafname[3],3); vname[3] = 0; sprintf(fname_buf,"%s/mbrola/%s",path_home,vname); if(GetFileLength(fname_buf) <= 0) return(0); } #endif vname[0] = 0; vgender[0] = 0; age = 0; while(fgets_strip(linebuf,sizeof(linebuf),f_in) != NULL) { if(memcmp(linebuf,"name",4)==0) { p = &linebuf[4]; while(isspace(*p)) p++; strncpy0(vname,p,sizeof(vname)); } else if(memcmp(linebuf,"language",8)==0) { priority = DEFAULT_LANGUAGE_PRIORITY; vlanguage[0] = 0; sscanf(&linebuf[8],"%s %d",vlanguage,&priority); len = strlen(vlanguage) + 2; // check for space in languages[] if(len < (sizeof(languages)-langix-1)) { languages[langix] = priority; strcpy(&languages[langix+1],vlanguage); langix += len; n_languages++; } } else if(memcmp(linebuf,"gender",6)==0) { sscanf(&linebuf[6],"%s %d",vgender,&age); } else if(memcmp(linebuf,"variants",8)==0) { sscanf(&linebuf[8],"%d",&n_variants); } } languages[langix++] = 0; gender = LookupMnem(genders,vgender); if(n_languages == 0) { return(NULL); // no language lines in the voice file } p = (char *)calloc(sizeof(espeak_VOICE) + langix + strlen(fname) + strlen(vname) + 3, 1); voice_data = (espeak_VOICE *)p; p = &p[sizeof(espeak_VOICE)]; memcpy(p,languages,langix); voice_data->languages = p; strcpy(&p[langix],fname); voice_data->identifier = &p[langix]; voice_data->name = &p[langix]; if(vname[0] != 0) { langix += strlen(fname)+1; strcpy(&p[langix],vname); voice_data->name = &p[langix]; } voice_data->age = age; voice_data->gender = gender; voice_data->variant = 0; voice_data->xx1 = n_variants; return(voice_data); } // end of ReadVoiceFile
voice_t *LoadVoice(const char *vname, int control) {//=============================================== // control, bit 0 1= no_default // bit 1 1 = change tone only, not language // bit 2 1 = don't report error on LoadDictionary // bit 4 1 = vname = full path FILE *f_voice = NULL; keywtab_t *k; char *p; int key; int ix; int n; int value; int error = 0; int langix = 0; int tone_only = control & 2; int language_set = 0; int phonemes_set = 0; int stress_amps_set = 0; int stress_lengths_set = 0; int stress_add_set = 0; int conditional_rules = 0; LANGUAGE_OPTIONS *langopts = NULL; Translator *new_translator = NULL; char voicename[40]; char language_name[40]; char translator_name[40]; char new_dictionary[40]; char phonemes_name[40]; const char *language_type; char buf[200]; char path_voices[sizeof(path_home)+12]; char langname[4]; int stress_amps[8]; int stress_lengths[8]; int stress_add[8]; int pitch1; int pitch2; static char voice_identifier[40]; // file name for voice_selected static char voice_name[40]; // voice name for voice_selected static char voice_languages[100]; // list of languages and priorities for voice_selected strcpy(voicename,vname); if(voicename[0]==0) strcpy(voicename,"default"); if(control & 0x10) { strcpy(buf,vname); if(GetFileLength(buf) <= 0) return(NULL); } else { sprintf(path_voices,"%s%cvoices%c",path_home,PATHSEP,PATHSEP); sprintf(buf,"%s%s",path_voices,voicename); if(GetFileLength(buf) <= 0) { // look for the voice in a sub-directory of the language name langname[0] = voicename[0]; langname[1] = voicename[1]; langname[2] = 0; sprintf(buf,"%s%s%c%s",path_voices,langname,PATHSEP,voicename); if(GetFileLength(buf) <= 0) { // look in "test" sub-directory sprintf(buf,"%stest%c%s",path_voices,PATHSEP,voicename); } } } f_voice = fopen(buf,"r"); language_type = "en"; // default if(f_voice == NULL) { if(control & 3) return(NULL); // can't open file if(SelectPhonemeTableName(voicename) >= 0) language_type = voicename; } if(!tone_only && (translator != NULL)) { DeleteTranslator(translator); translator = NULL; } strcpy(translator_name,language_type); strcpy(new_dictionary,language_type); strcpy(phonemes_name,language_type); if(!tone_only) { voice = &voicedata; strncpy0(voice_identifier,vname,sizeof(voice_identifier)); voice_name[0] = 0; voice_languages[0] = 0; voice_selected.identifier = voice_identifier; voice_selected.name = voice_name; voice_selected.languages = voice_languages; } else { // append the variant file name to the voice identifier if((p = strchr(voice_identifier,'+')) != NULL) *p = 0; // remove previous variant name sprintf(buf,"+%s",&vname[3]); // omit !v/ from the variant filename strcat(voice_identifier,buf); langopts = &translator->langopts; } VoiceReset(tone_only); if(!tone_only) SelectPhonemeTableName(phonemes_name); // set up phoneme_tab while((f_voice != NULL) && (fgets_strip(buf,sizeof(buf),f_voice) != NULL)) { // isolate the attribute name for(p=buf; (*p != 0) && !isspace(*p); p++); *p++ = 0; if(buf[0] == 0) continue; key = 0; for(k=keyword_tab; k->mnem != NULL; k++) { if(strcmp(buf,k->mnem)==0) { key = k->data; break; } } 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 == 0) { language_type = strtok(language_name,"-"); language_set = 1; strcpy(translator_name,language_type); strcpy(new_dictionary,language_type); strcpy(phonemes_name,language_type); SelectPhonemeTableName(phonemes_name); if(new_translator != NULL) DeleteTranslator(new_translator); new_translator = SelectTranslator(translator_name); langopts = &new_translator->langopts; } } 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; char vgender[80]; sscanf(p,"%s %d",vgender,&age); voice_selected.gender = LookupMnem(genders,vgender); voice_selected.age = age; } break; case V_TRANSLATOR: if(tone_only) break; sscanf(p,"%s",translator_name); if(new_translator != NULL) DeleteTranslator(new_translator); new_translator = SelectTranslator(translator_name); langopts = &new_translator->langopts; 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: { double factor; // default is pitch 82 118 n = sscanf(p,"%d %d",&pitch1,&pitch2); voice->pitch_base = (pitch1 - 9) << 12; voice->pitch_range = (pitch2 - pitch1) * 108; 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 stress_lengths_set = Read8Numbers(p,stress_lengths); break; case V_STRESSAMP: // stressAmp stress_amps_set = Read8Numbers(p,stress_amps); break; case V_STRESSADD: // stressAdd stress_add_set = Read8Numbers(p,stress_add); break; case V_INTONATION: // intonation sscanf(p,"%d %d",&option_tone_flags,&option_tone2); if((option_tone_flags & 0xff) != 0) langopts->intonation_group = option_tone_flags & 0xff; break; case V_DICTRULES: // conditional dictionary rules and list entries while(*p != 0) { while(isspace(*p)) p++; n = -1; if(((n = atoi(p)) > 0) && (n < 32)) { p++; conditional_rules |= (1 << n); } while(isalnum(*p)) p++; } break; case V_REPLACE: if(phonemes_set == 0) { // must set up a phoneme table before we can lookup phoneme mnemonics SelectPhonemeTableName(phonemes_name); phonemes_set = 1; } PhonemeReplacement(key,p); break; case V_WORDGAP: // words sscanf(p,"%d %d",&langopts->word_gap, &langopts->vowel_pause); break; case V_STRESSRULE: sscanf(p,"%d %d %d %d",&langopts->stress_rule, &langopts->stress_flags, &langopts->unstressed_wd1, &langopts->unstressed_wd2); break; case V_CHARSET: if((sscanf(p,"%d",&value)==1) && (value < N_CHARSETS)) new_translator->charset_a0 = charsets[value]; break; case V_NUMBERS: sscanf(p,"%d %d",&langopts->numbers,&langopts->numbers2); break; case V_OPTION: if(sscanf(p,"%d %d",&ix,&value) == 2) { if((ix >= 0) && (ix < N_LOPTS)) langopts->param[ix] = value; } 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_MBROLA: { int srate = 16000; char name[40]; char phtrans[40]; phtrans[0] = 0; sscanf(p,"%s %s %d",name,phtrans,&srate); LoadMbrolaTable(name,phtrans,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: Read8Numbers(p,speed.fast_settings); SetSpeed(2); break; default: if((key & 0xff00) == 0x100) { sscanf(p,"%d",&langopts->param[key &0xff]); } else { fprintf(stderr,"Bad voice attribute: %s\n",buf); } break; } } if(f_voice != NULL) fclose(f_voice); if((new_translator == NULL) && (!tone_only)) { // not set by language attribute new_translator = SelectTranslator(translator_name); } for(ix=0; ix<N_PEAKS; ix++) { voice->freq2[ix] = voice->freq[ix]; voice->height2[ix] = voice->height[ix]; voice->width2[ix] = voice->width[ix]; } if(tone_only) { new_translator = translator; } else { if((ix = SelectPhonemeTableName(phonemes_name)) < 0) { fprintf(stderr,"Unknown phoneme table: '%s'\n",phonemes_name); } voice->phoneme_tab_ix = ix; error = LoadDictionary(new_translator, new_dictionary, control & 4); if(dictionary_name[0]==0) return(NULL); // no dictionary loaded new_translator->dict_condition = conditional_rules; voice_languages[langix] = 0; } langopts = &new_translator->langopts; if((value = langopts->param[LOPT_LENGTH_MODS]) != 0) { SetLengthMods(new_translator,value); } voice->width[0] = (voice->width[0] * 105)/100; if(!tone_only) { translator = new_translator; } // relative lengths of different stress syllables for(ix=0; ix<stress_lengths_set; ix++) { translator->stress_lengths[ix] = stress_lengths[ix]; } for(ix=0; ix<stress_add_set; ix++) { translator->stress_lengths[ix] += stress_add[ix]; } for(ix=0; ix<stress_amps_set; ix++) { translator->stress_amps[ix] = stress_amps[ix]; translator->stress_amps_r[ix] = stress_amps[ix] -1; } return(voice); } // end of LoadVoice
/* * Read the configuration file. * If parameter "all" == 0 then ignore everything except path info * Return -1 if any error. * Error messages generated. */ static int do_read(int all, char *force_ver, char *base_dir, char *conf_file, int depth) { #define MAX_LEVEL 20 FILE *fin; GLOB_LIST g; int i; int assgn; int drop_default_paths = 1; int lineno = 0; int ret = 0; int state[MAX_LEVEL + 1]; /* nested "if" */ int level = 0; int sizebuf; char *buf = NULL; char tmpline[PATH_MAX]; char **pathp; char *envpath; char *version; char *type; char **glb; char old_name[] = "/etc/conf.modules"; int conf_file_specified = 0; /* * The configuration file is optional. * No error is printed if it is missing. * If it is missing the following content is assumed. * * path[boot]=/lib/modules/boot * * path[toplevel]=/lib/modules/`uname -r` * * path[toplevel]=/lib/modules/`kernelversion` * (where kernelversion gives the major kernel version: "2.0", "2.2"...) * * path[toplevel]=/lib/modules/default * * path[kernel]=/lib/modules/kernel * path[fs]=/lib/modules/fs * path[net]=/lib/modules/net * path[scsi]=/lib/modules/scsi * path[block]=/lib/modules/block * path[cdrom]=/lib/modules/cdrom * path[ipv4]=/lib/modules/ipv4 * path[ipv6]=/lib/modules/ipv6 * path[sound]=/lib/modules/sound * path[fc4]=/lib/modules/fc4 * path[video]=/lib/modules/video * path[misc]=/lib/modules/misc * path[pcmcia]=/lib/modules/pcmcia * path[atm]=/lib/modules/atm * path[usb]=/lib/modules/usb * path[ide]=/lib/modules/ide * path[ieee1394]=/lib/modules/ieee1394 * path[mtd]=/lib/modules/mtd * * The idea is that modprobe will look first if the * modules are compiled for the current release of the kernel. * If not found, it will look for modules that fit for the * general kernelversion (2.0, 2.2 and so on). * If still not found, it will look into the default release. * And if still not found, it will look in the other directories. * * The strategy should be like this: * When you install a new linux kernel, the modules should go * into a directory related to the release (version) of the kernel. * Then you can do a symlink "default" to this directory. * * Each time you compile a new kernel, the make modules_install * will create a new directory, but it won't change thee default. * * When you get a module unrelated to the kernel distribution * you can place it in one of the last three directory types. * * This is the default strategy. Of course you can overide * this in /etc/modules.conf. * * 2.3.15 added a new file tree walk algorithm which made it possible to * point at a top level directory and get the same behaviour as earlier * versions of modutils. 2.3.16 takes this one stage further, it * removes all the individual directory names from most of the scans, * only pointing at the top level directory. The only exception is the * last ditch scan, scanning all of /lib/modules would be a bad idea(TM) * so the last ditch scan still runs individual directory names under * /lib/modules. * * Additional syntax: * * [add] above module module1 ... * Specify additional modules to pull in on top of a module * * [add] below module module1 ... * Specify additional modules needed to be able to load a module * * [add] prune filename ... * * [add] probe name module1 ... * When "name" is requested, modprobe tries to install each * module in the list until it succeeds. * * [add] probeall name module1 ... * When "name" is requested, modprobe tries to install all * modules in the list. * If any module is installed, the command has succeeded. * * [add] options module option_list * * For all of the above, the optional "add" prefix is used to * add to a list instead of replacing the contents. * * include FILE_TO_INCLUDE * This does what you expect. No limitation on include levels. * * persistdir=persist_directory * Name the directory to save persistent data from modules. * * In the following WORD is a sequence if non-white characters. * If ' " or ` is found in the string, all characters up to the * matching ' " or ` will also be included, even whitespace. * Every WORD will then be expanded w.r.t. meta-characters. * If the expanded result gives more than one word, then only * the first word of the result will be used. * * * define CODE WORD * Do a putenv("CODE=WORD") * * EXPRESSION below can be: * WORD compare_op WORD * where compare_op is one of == != < <= >= > * The string values of the WORDs are compared * or * -n WORD compare_op WORD * where compare_op is one of == != < <= >= > * The numeric values of the WORDs are compared * or * WORD * if the expansion of WORD fails, or if the * expansion is "0" (zero), "false" or "" (empty) * then the expansion has the value FALSE. * Otherwise the expansion has the value TRUE * or * -f FILENAME * Test if the file FILENAME exists * or * -k * Test if "autoclean" (i.e. called from the kernel) * or * ! EXPRESSION * A negated expression is also an expression * * if EXPRESSION * any config line * ... * elseif EXPRESSION * any config line * ... * else * any config line * ... * endif * * The else and elseif keywords are optional. * "if"-statements nest up to 20 levels. */ state[0] = 1; if (force_ver) version = force_ver; else version = uts_info.release; config_version = xstrdup(version); /* Only read the default entries on the first file */ if (depth == 0) { maxpath = 100; modpath = (struct PATH_TYPE *)xmalloc(maxpath * sizeof(struct PATH_TYPE)); nmodpath = 0; maxexecs = 10; execs = (struct EXEC_TYPE *)xmalloc(maxexecs * sizeof(struct EXEC_TYPE)); nexecs = 0; /* * Build predef options */ if (all && optlist[0]) n_opt_list = build_list(optlist, &opt_list, version, 1); /* * Build predef above */ if (all && above[0]) n_abovelist = build_list(above, &abovelist, version, 0); /* * Build predef below */ if (all && below[0]) n_belowlist = build_list(below, &belowlist, version, 0); /* * Build predef prune list */ if (prune[0]) n_prunelist = build_list(prune, &prunelist, version, 0); /* * Build predef aliases */ if (all && aliaslist[0]) n_aliases = build_list(aliaslist, &aliases, version, 0); /* Order and priority is now: (MODPATH + modules.conf) || (predefs + modules.conf) */ if ((envpath = getenv("MODPATH")) != NULL && !safemode) { size_t len; char *p; char *path; /* Make a copy so's we can mung it with strtok. */ len = strlen(envpath) + 1; p = alloca(len); memcpy(p, envpath, len); path = alloca(PATH_MAX); for (p = strtok(p, ":"); p != NULL; p = strtok(NULL, ":")) { len = snprintf(path, PATH_MAX, p, version); modpath[nmodpath].path = xstrdup(path); if ((type = strrchr(path, '/')) != NULL) type += 1; else type = "misc"; modpath[nmodpath].type = xstrdup(type); if (++nmodpath >= maxpath) { maxpath += 100; modpath = (struct PATH_TYPE *)xrealloc(modpath, maxpath * sizeof(struct PATH_TYPE)); } } } else { /* * Build the default "path[type]" configuration */ int n; char *k; /* The first entry in the path list */ modpath[nmodpath].type = xstrdup("boot"); snprintf(tmpline, sizeof(tmpline), "%s/lib/modules/boot", base_dir); modpath[nmodpath].path = xstrdup(tmpline); ++nmodpath; /* The second entry in the path list, `uname -r` */ modpath[nmodpath].type = xstrdup("toplevel"); snprintf(tmpline, sizeof(tmpline), "%s/lib/modules/%s", base_dir, version); modpath[nmodpath].path = xstrdup(tmpline); ++nmodpath; /* The third entry in the path list, `kernelversion` */ modpath[nmodpath].type = xstrdup("toplevel"); for (n = 0, k = version; *k; ++k) { if (*k == '.' && ++n == 2) break; } snprintf(tmpline, sizeof(tmpline), "%s/lib/modules/%.*s", base_dir, (/* typecast for Alpha */ int)(k - version), version); modpath[nmodpath].path = xstrdup(tmpline); ++nmodpath; /* The rest of the entries in the path list */ for (pathp = tbpath; *pathp; ++pathp) { char **type; for (type = tbtype; *type; ++type) { char path[PATH_MAX]; snprintf(path, sizeof(path), "%s%s/%s", base_dir, *pathp, *type); if (meta_expand(path, &g, NULL, version, ME_ALL)) { ret = -1; goto out; } for (glb = g.pathv; glb && *glb; ++glb) { modpath[nmodpath].type = xstrdup(*type); modpath[nmodpath].path = *glb; if (++nmodpath >= maxpath) { maxpath += 100; modpath = (struct PATH_TYPE *)xrealloc(modpath, maxpath * sizeof(struct PATH_TYPE)); } } } } } /* Environment overrides for testing only, undocumented */ for (i = 0; i < gen_file_count; ++i) gen_file_env(gen_file+i); } /* End of depth == 0 */ if (conf_file || ((conf_file = getenv("MODULECONFIG")) != NULL && *conf_file && !safemode)) { if (!(fin = fopen(conf_file, "r"))) { error("Can't open %s", conf_file); ret = -1; goto out; } conf_file_specified = 1; } else { if (!(fin = fopen((conf_file = ETC_MODULES_CONF), "r"))) { /* Fall back to non-standard name */ if ((fin = fopen((conf_file = old_name), "r"))) { fprintf(stderr, "Warning: modutils is reading from %s because\n" " %s does not exist. The use of %s is\n" " deprecated, please rename %s to %s\n" " as soon as possible. Command\n" " mv %s %s\n", old_name, ETC_MODULES_CONF, old_name, old_name, ETC_MODULES_CONF, old_name, ETC_MODULES_CONF); } /* So what... use the default configuration */ } } if (fin) { struct stat statbuf1, statbuf2; if (fstat(fileno(fin), &statbuf1) == 0) config_mtime = statbuf1.st_mtime; config_file = xstrdup(conf_file); /* Save name actually used */ if (!conf_file_specified && stat(ETC_MODULES_CONF, &statbuf1) == 0 && stat(old_name, &statbuf2) == 0) { /* Both /etc files exist */ if (statbuf1.st_dev == statbuf2.st_dev && statbuf1.st_ino == statbuf2.st_ino) { if (lstat(ETC_MODULES_CONF, &statbuf1) == 0 && S_ISLNK(statbuf1.st_mode)) fprintf(stderr, "Warning: You do not need a link from %s to\n" " %s. The use of %s is deprecated,\n" " please remove %s and rename %s\n" " to %s as soon as possible. Commands.\n" " rm %s\n" " mv %s %s\n", ETC_MODULES_CONF, old_name, old_name, ETC_MODULES_CONF, old_name, ETC_MODULES_CONF, ETC_MODULES_CONF, old_name, ETC_MODULES_CONF); else { #ifndef NO_WARN_ON_OLD_LINK fprintf(stderr, "Warning: You do not need a link from %s to\n" " %s. The use of %s is deprecated,\n" " please remove %s as soon as possible. Command\n" " rm %s\n", old_name, ETC_MODULES_CONF, old_name, old_name, old_name); #endif } } else fprintf(stderr, "Warning: modutils is reading from %s and\n" " ignoring %s. The use of %s is deprecated,\n" " please remove %s as soon as possible. Command\n" " rm %s\n", ETC_MODULES_CONF, old_name, old_name, old_name, old_name); } } /* * Finally, decode the file */ while (fin && fgets_strip(&buf, &sizebuf, fin, &lineno) != NULL) { char *arg2; char *parm = buf; char *arg; int one_err = 0; int adding; while (isspace(*parm)) parm++; if (strncmp(parm, "add", 3) == 0) { adding = 1; parm += 3; while (isspace(*parm)) parm++; } else adding = 0; arg = parm; if (*parm == '\0') continue; one_err = 1; while (*arg > ' ' && *arg != '=') arg++; if (*arg == '=') assgn = 1; else assgn = 0; *arg++ = '\0'; while (isspace(*arg)) arg++; /* * endif */ if (!assgn && strcmp(parm, "endif") == 0) { if (level > 0) --level; else { error("unmatched endif in line %d", lineno); ret = -1; goto out; } continue; } /* * else */ if (!assgn && strcmp(parm, "else") == 0) { if (level <= 0) { error("else without if in line %d", lineno); ret = -1; goto out; } state[level] = !state[level]; continue; } /* * elseif */ if (!assgn && strcmp(parm, "elseif") == 0) { if (level <= 0) { error("elseif without if in line %d", lineno); ret = -1; goto out; } if (state[level] != 0) { /* * We have already found a TRUE * if statement in this "chain". * That's what "2" means. */ state[level] = 2; continue; } /* else: No TRUE if has been found, cheat */ /* * The "if" handling increments level, * but this is the _same_ level as before. * So, compensate for it. */ --level; parm = "if"; /* Fallthru to "if" */ } /* * if */ if (strcmp(parm, "if") == 0) { char *cmp; int not = 0; int numeric = 0; if (level >= MAX_LEVEL) { error("Too many nested if's in line %d\n", lineno); ret = -1; goto out; } state[++level] = 0; /* default false */ if (*arg == '!') { not = 1; arg = next_word(arg); } if (strncmp(arg, "-k", 2) == 0) { state[level] = flag_autoclean; continue; } if (strncmp(arg, "-f", 2) == 0) { char *file = next_word(arg); meta_expand(file, &g, NULL, version, ME_ALL); if (access(g.pathc ? g.pathv[0] : file, R_OK) == 0) state[level] = !not; else state[level] = not; continue; } if (strncmp(arg, "-n", 2) == 0) { numeric = 1; arg = next_word(arg); } cmp = next_word(arg); if (*cmp) { GLOB_LIST g2; long n1 = 0; long n2 = 0; char *w1 = ""; char *w2 = ""; arg2 = next_word(cmp); meta_expand(arg, &g, NULL, version, ME_ALL); if (g.pathc && g.pathv[0]) w1 = g.pathv[0]; meta_expand(arg2, &g2, NULL, version, ME_ALL); if (g2.pathc && g2.pathv[0]) w2 = g2.pathv[0]; if (numeric) { n1 = strtol(w1, NULL, 0); n2 = strtol(w2, NULL, 0); } if (strcmp(cmp, "==") == 0 || strcmp(cmp, "=") == 0) { if (numeric) state[level] = (n1 == n2); else state[level] = strcmp(w1, w2) == 0; } else if (strcmp(cmp, "!=") == 0) { if (numeric) state[level] = (n1 != n2); else state[level] = strcmp(w1, w2) != 0; } else if (strcmp(cmp, ">=") == 0) { if (numeric) state[level] = (n1 >= n2); else state[level] = strcmp(w1, w2) >= 0; } else if (strcmp(cmp, "<=") == 0) { if (numeric) state[level] = (n1 <= n2); else state[level] = strcmp(w1, w2) <= 0; } else if (strcmp(cmp, ">") == 0) { if (numeric) state[level] = (n1 > n2); else state[level] = strcmp(w1, w2) > 0; } else if (strcmp(cmp, "<") == 0) { if (numeric) state[level] = (n1 < n2); else state[level] = strcmp(w1, w2) < 0; } } else { /* Check defined value, if any */ /* undef or defined as * "" or "0" or "false" => false * defined => true */ if (!meta_expand(arg, &g, NULL, version, ME_ALL) && g.pathc > 0 && strcmp(g.pathv[0], "0") != 0 && strcmp(g.pathv[0], "false") != 0 && strlen(g.pathv[0]) != 0) state[level] = 1; /* true */ } if (not) state[level] = !state[level]; continue; } /* * Should we bother? */ if (state[level] != 1) continue; /* * define */ if (!assgn && strcmp(parm, "define") == 0) { char env[PATH_MAX]; arg2 = next_word(arg); meta_expand(arg2, &g, NULL, version, ME_ALL); snprintf(env, sizeof(env), "%s=%s", arg, (g.pathc ? g.pathv[0] : "")); putenv(xstrdup(env)); one_err = 0; } /* * include */ if (!assgn && strcmp(parm, "include") == 0) { int inc_idx = 0; while (*arg) { arg2=next_word(arg); meta_expand(arg, &g, NULL, version, ME_ALL); if (g.pathc>0) { for ( ; inc_idx<g.pathc; inc_idx++) { if (!do_read(all, version, base_dir, g.pathv[inc_idx], depth+1)) one_err = 0; else error("include %s failed\n", g.pathv[inc_idx]); } } else { if (!do_read(all, version, base_dir, g.pathc ? g.pathv[0] : arg, depth+1)) one_err = 0; else error("include %s failed\n", arg); } arg = arg2; } } /* * above */ else if (all && !assgn && strcmp(parm, "above") == 0) { decode_list(&n_abovelist, &abovelist, arg, adding, version, 0); one_err = 0; } /* * below */ else if (all && !assgn && strcmp(parm, "below") == 0) { decode_list(&n_belowlist, &belowlist, arg, adding, version, 0); one_err = 0; } /* * prune */ else if (!assgn && strcmp(parm, "prune") == 0) { decode_list(&n_prunelist, &prunelist, arg, adding, version, 0); one_err = 0; } /* * probe */ else if (all && !assgn && strcmp(parm, "probe") == 0) { decode_list(&n_probe_list, &probe_list, arg, adding, version, 0); one_err = 0; } /* * probeall */ else if (all && !assgn && strcmp(parm, "probeall") == 0) { decode_list(&n_probeall_list, &probeall_list, arg, adding, version, 0); one_err = 0; } /* * options */ else if (all && !assgn && strcmp(parm, "options") == 0) { decode_list(&n_opt_list, &opt_list, arg, adding, version, 1); one_err = 0; } /* * alias */ else if (all && !assgn && strcmp(parm, "alias") == 0) { /* * Replace any previous (default) definitions * for the same module */ decode_list(&n_aliases, &aliases, arg, 0, version, 0); one_err = 0; } /* * Specification: /etc/modules.conf * The format of the commands in /etc/modules.conf are: * * pre-install module command * install module command * post-install module command * pre-remove module command * remove module command * post-remove module command * * The different words are separated by tabs or spaces. */ /* * pre-install */ else if (all && !assgn && (strcmp(parm, "pre-install") == 0)) { decode_exec(arg, EXEC_PRE_INSTALL); one_err = 0; } /* * install */ else if (all && !assgn && (strcmp(parm, "install") == 0)) { decode_exec(arg, EXEC_INSTALL); one_err = 0; } /* * post-install */ else if (all && !assgn && (strcmp(parm, "post-install") == 0)) { decode_exec(arg, EXEC_POST_INSTALL); one_err = 0; } /* * pre-remove */ else if (all && !assgn && (strcmp(parm, "pre-remove") == 0)) { decode_exec(arg, EXEC_PRE_REMOVE); one_err = 0; } /* * remove */ else if (all && !assgn && (strcmp(parm, "remove") == 0)) { decode_exec(arg, EXEC_REMOVE); one_err = 0; } /* * post-remove */ else if (all && !assgn && (strcmp(parm, "post-remove") == 0)) { decode_exec(arg, EXEC_POST_REMOVE); one_err = 0; } /* * insmod_opt= */ else if (assgn && (strcmp(parm, "insmod_opt") == 0)) { insmod_opt = xstrdup(arg); one_err = 0; } /* * keep */ else if (!assgn && (strcmp(parm, "keep") == 0)) { drop_default_paths = 0; one_err = 0; } /* * path...= */ else if (assgn && strncmp(parm, "path", 4) == 0) { /* * Specification: config file / path parameter * The path parameter specifies a directory to * search for modules. * This parameter may be repeated multiple times. * * Note that the actual path may be defined using * wildcards and other shell meta-chars, such as "*?`". * For example: * path[misc]=/lib/modules/1.1.5?/misc * * Optionally the path keyword carries a tag. * This tells us a little more about the purpose of * this directory and allows some automated operations. * A path is marked with a tag by adding the tag, * enclosed in square brackets, to the path keyword: * # * path[boot]=/lib/modules/boot * # * This case identifies the path a of directory * holding modules loadable a boot time. */ if (drop_default_paths) { int n; /* * Specification: config file / path / default * * Whenever there is a path[] specification * in the config file, all the default * path are reset. * * If one instead wants to _add_ to the default * set of paths, one has to have the option * keep * before the first path[]-specification line * in the configuration file. */ drop_default_paths = 0; for (n = 0; n < nmodpath; n++) { free(modpath[n].path); free(modpath[n].type); } nmodpath = 0; } /* * Get (the optional) tag * If the tag is missing, the word "misc" * is assumed. */ type = "misc"; if (parm[4] == '[') { char *pt_type = parm + 5; while (*pt_type != '\0' && *pt_type != ']') pt_type++; if (*pt_type == ']' && pt_type[1] == '\0') { *pt_type = '\0'; type = parm + 5; } /* else CHECKME */ } /* * Handle the actual path description */ if (meta_expand(arg, &g, base_dir, version, ME_ALL)) { ret = -1; goto out; } for (glb = g.pathv; glb && *glb; ++glb) { modpath[nmodpath].type = xstrdup(type); modpath[nmodpath].path = *glb; if (++nmodpath >= maxpath) { maxpath += 100; modpath = (struct PATH_TYPE *)xrealloc(modpath, maxpath * sizeof(struct PATH_TYPE)); } } one_err = 0; } /* * persistdir */ else if (assgn && strcmp(parm, "persistdir") == 0) { meta_expand(arg, &g, NULL, version, ME_ALL); persistdir = xstrdup(g.pathc ? g.pathv[0] : arg); one_err = 0; } /* Names for generated files in config file */ for (i = 0; one_err && i < gen_file_count; ++i) one_err = gen_file_conf(gen_file+i, assgn, parm, arg); /* * any errors so far? */ if (all == 0) one_err = 0; else if (one_err) { error("Invalid line %d in %s\n\t%s", lineno, conf_file, buf); ret = -1; } } if (fin) fclose(fin); if (level) { error("missing endif at %s EOF", conf_file); ret = -1; } if (ret) goto out; /* else */ if (depth == 0) { /* Check we have names for generated files */ for (i = 0; !ret && i < gen_file_count; ++i) ret = gen_file_check(gen_file+i, &g, base_dir, version); } out: return ret; }