/// <summary> /// Compiler. /// </summary> /// <param name="posSet">POS set.</param> /// <param name="outputStream">Output Stream.</param> /// <returns>ErrorSet.</returns> public static ErrorSet Compile(TtsPosSet posSet, Stream outputStream) { if (posSet == null) { throw new ArgumentNullException("posSet"); } if (outputStream == null) { throw new ArgumentNullException("outputStream"); } posSet.Validate(); ErrorSet errorSet = posSet.ErrorSet; if (!errorSet.Contains(ErrorSeverity.MustFix)) { SortedDictionary<uint, string> sortedPosSet = new SortedDictionary<uint, string>(); foreach (KeyValuePair<uint, string> pair in posSet.IdItems) { sortedPosSet.Add(pair.Key, pair.Value); } BinaryWriter bw = new BinaryWriter(outputStream); { // write the size of the structure for verification purchase bw.Write(((uint)Marshal.SizeOf(typeof(PosData)))); // write the phoneme count bw.Write((uint)posSet.IdItems.Count); // write phonemes array foreach (KeyValuePair<uint, string> pair in sortedPosSet) { PosData posData = new PosData(pair.Value, pair.Key); bw.Write(Helper.ToBytes(posData)); } } } return errorSet; }
/// <summary> /// Initializes a new instance of the HtsFont class. /// </summary> /// <param name="phoneSet">Phone set.</param> /// <param name="posSet">Part of speech.</param> public HtsFont(TtsPhoneSet phoneSet, TtsPosSet posSet) { Helper.ThrowIfNull(phoneSet); Helper.ThrowIfNull(posSet); _phoneSet = phoneSet; _posSet = posSet; }
public LinguistciFeatureExtractor(IEnumerable<LinguisticFeatureInfo> featureInfos, TtsPhoneSet phoneSet, TtsPosSet posSet, CustomizedFeaturePluginManager manager, ILogger logger) { if (featureInfos == null) { throw new ArgumentNullException("featureInfos"); } if (phoneSet == null) { throw new ArgumentNullException("phoneSet"); } if (posSet == null) { throw new ArgumentNullException("posSet"); } Logger = logger ?? new NullLogger(); PhoneSet = phoneSet; PosSet = posSet; // Builds the name of feature name set. FeatureNameSetName = Helper.NeutralFormat("VoiceModelTrainer.{0}", PhoneSet.Language.ToString()); try { // Creates a feature extration engine. ExtractionEngine = new FeatureExtractionEngine(); // Creates the feature meta data. FeatureMetas = ExtractionEngine.Convert(LabelFeatureNameSet.MandatoryFeatureNames.ToList()); FeatureInfos = new List<LinguisticFeatureInfo>(); FeatureValueRecords = new List<FeatureValueRecord>(); for (int i = 0; i < LabelFeatureNameSet.MandatoryFeatureNames.Length; ++i) { FeatureInfos.Add(null); FeatureValueRecords.Add(new FeatureValueRecord()); } foreach (LinguisticFeatureInfo info in featureInfos) { FeatureValueRecords.Add(new FeatureValueRecord()); int index = Array.IndexOf(LabelFeatureNameSet.MandatoryFeatureNames, info.Name); if (index < 0) { FeatureMetas.Add(ExtractionEngine.Convert(info.Name, info.ExtendedProperty)); FeatureInfos.Add(info); } else { FeatureInfos[index] = info; } } } catch (EspException e) { throw new InvalidDataException("Feature extraction engine error", e); } // Checks whether need pos and ToBI accent. for (int i = 0; i < FeatureMetas.Count; ++i) { if (!NeedPos && (FeatureMetas[i].Property == TtsFeatureProperty.TTS_FEATURE_PROPERTY_POS || FeatureMetas[i].Property == TtsFeatureProperty.TTS_FEATURE_PROPERTY_POSTAGGER_POS)) { NeedPos = true; } if (!NeedToBI && (FeatureMetas[i].Property == TtsFeatureProperty.TTS_FEATURE_PROPERTY_PRIMARY_ACCENT_POSITION || FeatureMetas[i].Property == TtsFeatureProperty.TTS_FEATURE_PROPERTY_SYLL_NUM_FROM_LEFT_ACCENT || FeatureMetas[i].Property == TtsFeatureProperty.TTS_FEATURE_PROPERTY_SYLL_NUM_TO_RIGHT_ACCENT || FeatureMetas[i].Property == TtsFeatureProperty.TTS_FEATURE_PROPERTY_ACCENTED_SYLL_NUM_BEFORE_CURR_SYLL || FeatureMetas[i].Property == TtsFeatureProperty.TTS_FEATURE_PROPERTY_ACCENTED_SYLL_NUM_AFTER_CURR_SYLL || FeatureMetas[i].Property == TtsFeatureProperty.TTS_FEATURE_PROPERTY_ACCENT || FeatureMetas[i].Property == TtsFeatureProperty.TTS_FEATURE_PROPERTY_TOBI_ACCENT || FeatureMetas[i].Property == TtsFeatureProperty.TTS_FEATURE_PROPERTY_IS_ACCENTED || FeatureMetas[i].Property == TtsFeatureProperty.TTS_FEATURE_PROPERTY_TOBI_FINAL_BOUNDARY_TONE)) { NeedToBI = true; } } // Gets Phoneme according to phone set. MemoryStream phoneStream = new MemoryStream(); ErrorSet errorSet = PhoneSetCompiler.Compile(phoneSet, phoneStream); if (errorSet.Count > 0) { foreach (Error error in errorSet.Errors) { Logger.LogLine(error.ToString()); } if (errorSet.Contains(ErrorSeverity.MustFix)) { throw new InvalidDataException("Error happens in tts phone set compiling"); } } phoneStream.Seek(0, SeekOrigin.Begin); Phoneme = new Phoneme(phoneStream, (Language)phoneSet.Language); // Gets the utterance extenders. if (manager != null) { List<PluginInfo> pluginInfos = manager.GetPlugins(CustomizedFeaturePluginManager.AttachBeforeExtraction); if (pluginInfos != null) { UtteranceExtenders = UtteranceExtenderFinder.LoadUtteranceExtenders(pluginInfos); } } // Initialize ZhToneIndexPlugin if the language is zh-CN if (Language.ZhCN == (Language)phoneSet.Language) { ChineseToneIndexExtractor = new ChineseToneIndexExtractor(); ChineseToneIndexExtractor.Initialize(Phoneme); } // Creates feature name set. if (LabelFeatureNameSet.Exist(FeatureNameSetName)) { FeatureNameSet = LabelFeatureNameSet.Query(FeatureNameSetName); } else { FeatureNameSet = LabelFeatureNameSet.Create(FeatureNameSetName, FeatureMetas.Select(o => o.Name).ToList()); } }
/// <summary> /// Initializes a new instance of the <see cref="UtteranceBuilder"/> class. /// </summary> /// <param name="phoneSet"> /// The phone set. /// </param> /// <param name="posSet"> /// The pos set. /// </param> /// <param name="phoneme"> /// The phoneme. /// </param> /// <exception cref="ArgumentNullException"> /// Exception. /// </exception> public UtteranceBuilder(TtsPhoneSet phoneSet, TtsPosSet posSet, Phoneme phoneme) { if (phoneSet == null) { throw new ArgumentNullException("phoneSet"); } if (posSet == null) { throw new ArgumentNullException("posSet"); } if (phoneme == null) { throw new ArgumentNullException("phoneme"); } PhoneSet = phoneSet; PosSet = posSet; Phoneme = phoneme; NeedPunctuation = false; }
/// <summary> /// Validate Lexicon according to pos set and phone set. /// </summary> /// <param name="ttsPhoneSet">TTS phone set.</param> /// <param name="ttsPosSet">TTS POS set.</param> public void Validate(TtsPhoneSet ttsPhoneSet, TtsPosSet ttsPosSet) { if (ttsPosSet == null) { throw new ArgumentNullException("ttsPosSet"); } if (ttsPhoneSet == null) { throw new ArgumentNullException("ttsPhoneSet"); } if (!ttsPosSet.Language.Equals(Language)) { throw new InvalidDataException(Error.BuildMessage(CommonError.NotConsistentLanguage, Language.ToString(), "lexicon", ttsPosSet.Language.ToString(), "pos set")); } if (!ttsPhoneSet.Language.Equals(Language)) { throw new InvalidDataException(Error.BuildMessage(CommonError.NotConsistentLanguage, Language.ToString(), "lexicon", ttsPhoneSet.Language.ToString(), "phone set")); } Validate(ttsPhoneSet, ttsPosSet, null); }
/// <summary> /// Validate Lexicon according to TTS phone set and pos set or lexical attribute schema. /// </summary> /// <param name="ttsPhoneSet">TTS phone set.</param> /// <param name="ttsPosSet">TTS POS set.</param> /// <param name="attributeSchema">Lexical attribute Schema.</param> private void Validate(TtsPhoneSet ttsPhoneSet, TtsPosSet ttsPosSet, LexicalAttributeSchema attributeSchema) { Debug.Assert(ttsPhoneSet != null); Debug.Assert(ttsPosSet != null || attributeSchema != null); bool dependentDataValid = true; ttsPhoneSet.Validate(); if (ttsPhoneSet.ErrorSet.Contains(ErrorSeverity.MustFix)) { ErrorSet.Add(LexiconError.InvalidDependentData, "Phone set"); dependentDataValid = false; } if (ttsPosSet != null) { ttsPosSet.Validate(); if (ttsPosSet.ErrorSet.Contains(ErrorSeverity.MustFix)) { ErrorSet.Add(LexiconError.InvalidDependentData, "POS set"); dependentDataValid = false; } } if (attributeSchema != null) { attributeSchema.Validate(); if (attributeSchema.ErrorSet.Contains(ErrorSeverity.MustFix)) { ErrorSet.Add(LexiconError.InvalidDependentData, "Lexical Attribute Schema"); dependentDataValid = false; } } if (dependentDataValid) { bool containValidItem = false; foreach (LexicalItem lexItem in Items.Values) { ErrorSet errorSet = lexItem.Validate(ttsPhoneSet, ttsPosSet, attributeSchema); ErrorSet.Merge(errorSet); containValidItem = containValidItem || lexItem.Valid; } if (!containValidItem) { ErrorSet.Add(LexiconError.EmptyLexicon); } } validated = true; }
/// <summary> /// Write the pst data. /// </summary> /// <param name="pstFile">The pst file name to be stored.</param> /// <param name="data">The pst data to be write.</param> /// <param name="ttsPhoneSet">The tts Phone set.</param> /// <param name="ttsPosSet">The tts pst set.</param> public void WritePSTData(string pstFile, PSTData data, TtsPhoneSet ttsPhoneSet, TtsPosSet ttsPosSet) { foreach (Question question in data.DecisionForest.QuestionList) { question.Language = ttsPhoneSet.Language; question.ValueSetToCodeValueSet(ttsPosSet, ttsPhoneSet, data.CustomFeatures); } FileStream file = new FileStream(pstFile, FileMode.Create); try { using (DataWriter writer = new DataWriter(file)) { file = null; uint position = 0; // Write header section place holder PreselectionFileHeader header = new PreselectionFileHeader(); position += (uint)header.Write(writer); HtsFontSerializer serializer = new HtsFontSerializer(); using (StringPool stringPool = new StringPool()) { Dictionary<string, uint> questionIndexes = new Dictionary<string, uint>(); header.QuestionOffset = position; header.QuestionSize = serializer.Write( data.QuestionSet, writer, stringPool, questionIndexes, data.CustomFeatures); position += header.QuestionSize; // Write leaf referenced data to buffer List<CandidateSetData> dataNodes = data.CadidateSets; int val = data.CadidateSets.Sum(c => c.Candidates.Count); using (MemoryStream candidateSetBuffer = new MemoryStream()) { Dictionary<string, int> namedSetOffset = new Dictionary<string, int>(); int candidateSetSize = HtsFontSerializer.Write( dataNodes, new DataWriter(candidateSetBuffer), namedSetOffset); // Write decision forest Dictionary<string, uint[]> namedOffsets = namedSetOffset.ToDictionary(p => p.Key, p => new[] { (uint)p.Value }); header.DecisionTreeSectionOffset = position; header.DecisionTreeSectionSize = (uint)Write(data.DecisionForest, data.TreeIndexes, questionIndexes, data.QuestionSet, namedOffsets, new DecisionForestSerializer(), writer); position += header.DecisionTreeSectionSize; // Write string pool header.StringPoolOffset = position; header.StringPoolSize = HtsFontSerializer.Write(stringPool, writer); position += header.StringPoolSize; // Write leaf referenced data header.CandidateSetSectionOffset = position; header.CandidateSetSectionSize = writer.Write(candidateSetBuffer.ToArray()); position += header.CandidateSetSectionSize; } // Write header section place holder using (PositionRecover recover = new PositionRecover(writer, 0)) { header.Write(writer); } } } } finally { if (null != file) { file.Dispose(); } } }
/// <summary> /// Compile the POS set into PosTaggerPos binary. /// </summary> /// <param name="posSet">POS set.</param> /// <param name="outputStream">Output stream.</param> /// <returns>Error set.</returns> public static ErrorSet CompilePosTaggerPos(TtsPosSet posSet, Stream outputStream) { if (posSet == null) { throw new ArgumentNullException("posSet"); } if (outputStream == null) { throw new ArgumentNullException("outputStream"); } posSet.Validate(); ErrorSet errorSet = posSet.ErrorSet; if (!errorSet.Contains(ErrorSeverity.MustFix)) { BinaryWriter bw = new BinaryWriter(outputStream); if (bw != null) { bw.Write(Convert.ToUInt32(posSet.Items.Count)); foreach (KeyValuePair<string, uint> pair in posSet.Items) { // Warning: do not check the value whether larger than maximal of 16bit. Debug.Assert(pair.Value <= 0xFFFE); bw.Write(Convert.ToUInt16(pair.Value)); } } } return errorSet; }
/// <summary> /// Initializes a new instance of the <see cref="XmlScriptValidateSetting"/> class. /// </summary> /// <param name="phoneSet">Phone set.</param> /// <param name="posSet">POS set.</param> public XmlScriptValidateSetting(TtsPhoneSet phoneSet, TtsPosSet posSet) { _scope = XmlScriptValidationScope.None; if (phoneSet != null) { _scope |= XmlScriptValidationScope.Pronunciation; } if (posSet != null) { _scope |= XmlScriptValidationScope.POS; } _phoneSet = phoneSet; _posSet = posSet; }
/// <summary> /// Load POS Set Data object. /// </summary> /// <param name="errorSet">ErrorSet.</param> /// <returns>POS Set Data object.</returns> internal override object LoadDataObject(ErrorSet errorSet) { if (errorSet == null) { throw new ArgumentNullException("errorSet"); } TtsPosSet posSet = new TtsPosSet(); posSet.Load(this.Path); return posSet; }
/// <summary> /// Initializes a new instance of the PreSelectionSerializer class. /// </summary> /// <param name="phoneSet">Phone set object.</param> /// <param name="posSet">POS set object.</param> public PreSelectionSerializer(TtsPhoneSet phoneSet, TtsPosSet posSet) { _phoneSet = phoneSet; _posSet = posSet; }
/// <summary> /// Validate lexicon item. /// </summary> /// <param name="ttsPhoneSet">Phone set to validate lexicon item's pronunciation.</param> /// <param name="ttsPosSet">Pos set of the lexicon item.</param> /// <param name="attributeSchema">Attribute schema.</param> /// <returns>Error set of the validation.</returns> public ErrorSet Validate(TtsPhoneSet ttsPhoneSet, TtsPosSet ttsPosSet, LexicalAttributeSchema attributeSchema) { Debug.Assert(ttsPhoneSet != null); Debug.Assert(ttsPosSet != null || attributeSchema != null); ErrorSet errorSet = new ErrorSet(); // Merge duplicate pronunciation node Collection<LexiconPronunciation> distinctPronunciations = new Collection<LexiconPronunciation>(); Dictionary<string, int> pronunciationIndex = new Dictionary<string, int>(); int pronunciationCount = 0; foreach (LexiconPronunciation lexPron in Pronunciations) { // Validate duplicate pronunciation node if (pronunciationIndex.ContainsKey(lexPron.Symbolic)) { errorSet.Add(LexiconError.DuplicatePronunciationNode, Grapheme, lexPron.Symbolic); lexPron.Valid = false; foreach (LexiconItemProperty property in lexPron.Properties) { Collection<LexiconItemProperty> targetProperties = distinctPronunciations[pronunciationIndex[lexPron.Symbolic]].Properties; if (!targetProperties.Contains(property)) { targetProperties.Add(property); } else { errorSet.Add(LexiconError.DuplicateProperty, Grapheme, lexPron.Symbolic); } } } else { distinctPronunciations.Add(lexPron); pronunciationIndex[lexPron.Symbolic] = pronunciationCount; pronunciationCount++; } } _pronunciations = distinctPronunciations; int invalidPronNodeNum = 0; foreach (LexiconPronunciation lexPron in Pronunciations) { // lexPron.Valid will be false if contains error. ValidatePronunciation(Grapheme, lexPron, ttsPhoneSet, errorSet); // Validate the POS information int invalidPropertyNum = 0; foreach (LexiconItemProperty property in lexPron.Properties) { // Lexicon schema ensures that the POS property is existed Debug.Assert(property.PartOfSpeech != null); if (PosItem.Validate(property.PartOfSpeech.Value, ttsPosSet, attributeSchema).Count > 0) { errorSet.Add(LexiconError.UnrecognizedPos, Grapheme, lexPron.Symbolic, property.PartOfSpeech.Value); property.Valid = false; } if (attributeSchema != null) { ErrorSet attributeErrorSet = ValidateAttributeSet(property, attributeSchema); foreach (Error error in attributeErrorSet.Errors) { errorSet.Add(LexiconError.AttributeError, error, Grapheme, lexPron.Symbolic); } if (attributeErrorSet.Contains(ErrorSeverity.MustFix)) { property.Valid = false; } } if (property.AttributeSet.Count > 0 && (property.Case != null || property.Gender != null || property.Number != null)) { errorSet.Add(LexiconError.MixedPropertyDefinition, Grapheme, lexPron.Symbolic); property.Valid = false; } else { ValidateCase(Grapheme, property, errorSet); ValidateGender(Grapheme, property, errorSet); ValidateNumber(Grapheme, property, errorSet); } if (!property.Valid) { invalidPropertyNum++; } } if (lexPron.Properties.Count == invalidPropertyNum) { lexPron.Valid = false; } if (!lexPron.Valid) { invalidPronNodeNum++; } } if (Pronunciations.Count == invalidPronNodeNum) { Valid = false; } return errorSet; }
/// <summary> /// Validate pos string. /// </summary> /// <param name="posStr">Pos string to be validated.</param> /// <param name="ttsPosSet">Tts pos set for validation.</param> /// <param name="attributeSchema">Lexicon attribute schema for validation.</param> /// <returns>Validate result.</returns> public static ErrorSet Validate(string posStr, TtsPosSet ttsPosSet, LexicalAttributeSchema attributeSchema) { ErrorSet errorSet = new ErrorSet(); if ((attributeSchema != null && string.IsNullOrEmpty(attributeSchema.GenerateString( LexicalAttributeSchema.PosCategoryName, posStr))) || (ttsPosSet != null && !ttsPosSet.Items.ContainsKey(posStr))) { errorSet.Add(PosError.UnrecognizedPos, posStr); } return errorSet; }