/// <summary> /// Validate compound rule file. /// </summary> /// <param name="filePath">Compound rule file path.</param> /// <param name="phoneset">TTS phone set.</param> /// <returns>ErrorSet.</returns> public static ErrorSet ValidateCompoundRule(string filePath, TtsPhoneSet phoneset) { // Validate parameter if (string.IsNullOrEmpty(filePath)) { throw new ArgumentNullException("filePath"); } if (!File.Exists(filePath)) { throw Helper.CreateException(typeof(FileNotFoundException), filePath); } ErrorSet errorSet = new ErrorSet(); using (XmlTextReader xmlTextReader = new XmlTextReader(filePath)) { while (xmlTextReader.Read()) { if (xmlTextReader.NodeType == XmlNodeType.Element && xmlTextReader.Name == "out") { if (xmlTextReader.Read() && xmlTextReader.NodeType == XmlNodeType.Text) { ValidateCompoundRuleNodePron(xmlTextReader.Value.Trim(), phoneset, xmlTextReader.LineNumber, errorSet); } } } } return errorSet; }
/// <summary> /// Initializes a new instance of the <see cref="PhoneMerger"/> class. /// </summary> /// <param name="phoneSet">Phone set.</param> /// <param name="sliceData">Slice data.</param> /// <param name="truncRule">Truncate rule data.</param> public PhoneMerger(TtsPhoneSet phoneSet, SliceData sliceData, TruncateRuleData truncRule) { if (phoneSet == null) { throw new ArgumentNullException("phoneSet"); } if (sliceData == null) { throw new ArgumentNullException("sliceData"); } if (truncRule == null) { throw new ArgumentNullException("truncRule"); } _phoneSet = phoneSet; _sliceData = sliceData; _truncateRuleData = truncRule; }
/// <summary> /// Compiler. /// </summary> /// <param name="phoneSet">Phone Set.</param> /// <param name="outputStream">OutputStream.</param> /// <returns>ErrorSet.</returns> public static ErrorSet Compile(TtsPhoneSet phoneSet, Stream outputStream) { if (phoneSet == null) { throw new ArgumentNullException("phoneSet"); } if (outputStream == null) { throw new ArgumentNullException("outputStream"); } phoneSet.Validate(); ErrorSet errorSet = phoneSet.ErrorSet; if (!errorSet.Contains(ErrorSeverity.MustFix)) { BinaryWriter bw = new BinaryWriter(outputStream); { // write the size of the structure for verification purchase bw.Write((uint)Marshal.SizeOf(typeof(PhoneData))); bw.Write((uint)phoneSet.Phones.Count); foreach (Phone phone in phoneSet.Phones) { // Skips those features whose id is greater than uint.MaxValue. uint feature = (uint)phone.FeatureId; PhoneData phoneData = new PhoneData(phone.CompilingName, Convert.ToUInt16(phone.Id), feature); bw.Write(Helper.ToBytes(phoneData)); } } } return errorSet; }
/// <summary> /// Parsing the syllable string to a script syllable /// Here we suppose syllable is a valid pronunciation string. /// </summary> /// <param name="syllable">Syllable string, doesn't include unit boundary.</param> /// <param name="phoneSet">TtsPhoneSet.</param> /// <returns>The constructed script syllable.</returns> public static ScriptSyllable ParseStringToSyllable(string syllable, TtsPhoneSet phoneSet) { if (string.IsNullOrEmpty(syllable)) { throw new ArgumentNullException("syllable"); } if (phoneSet == null) { throw new ArgumentNullException("phoneSet"); } ScriptSyllable scriptSyllable = new ScriptSyllable(phoneSet.Language); ErrorSet errors = new ErrorSet(); Phone[] phones = Pronunciation.SplitIntoPhones(syllable, phoneSet, errors); if (errors.Count > 0) { string message = Helper.NeutralFormat( "The syllable string [{0}] isn't valid : {1}{2}", syllable, Environment.NewLine, errors.ErrorsString()); throw new InvalidDataException(message); } Collection<ScriptPhone> scriptPhones = new Collection<ScriptPhone>(); foreach (Phone phone in phones) { if (phone.HasFeature(PhoneFeature.MainStress) || phone.HasFeature(PhoneFeature.SubStress)) { switch (phone.Name) { case "1": scriptSyllable.Stress = TtsStress.Primary; break; case "2": scriptSyllable.Stress = TtsStress.Secondary; break; case "3": scriptSyllable.Stress = TtsStress.Tertiary; break; } } else if (phone.HasFeature(PhoneFeature.Tone)) { scriptPhones[scriptPhones.Count - 1].Tone = phone.Name; } else { ScriptPhone scriptPhone = new ScriptPhone(phone.Name); scriptPhone.Syllable = scriptSyllable; scriptPhones.Add(scriptPhone); } } scriptSyllable.Phones.Clear(); Helper.AppendCollection(scriptSyllable.Phones, scriptPhones); return scriptSyllable; }
/// <summary> /// Whether the two tts phone sets are equal by nature. /// </summary> /// <param name="left">Left TtsPhoneSet.</param> /// <param name="right">Right TtsPhoneSet.</param> /// <param name="strict">Whether the comparison is strict.</param> /// <returns>True/false.</returns> public static bool Equals(TtsPhoneSet left, TtsPhoneSet right, bool strict) { if (!left.Version.Equals(right.Version)) { return false; } if (left.Phones.Count != right.Phones.Count) { return false; } else { foreach (var lphone in left.Phones) { bool found = false; foreach (var rphone in right.Phones) { if (!found && lphone.CompareTo(rphone) == 0) { found = true; } } if (!found) { return false; } } } if (strict) { if (left.IsShortPauseSupported != right.IsShortPauseSupported) { return false; } if (left.SyllableStructure.VowelCount.Max != right.SyllableStructure.VowelCount.Max || left.SyllableStructure.VowelCount.Min != right.SyllableStructure.VowelCount.Min || left.SyllableStructure.SonorantAndVowelCount.Max != right.SyllableStructure.SonorantAndVowelCount.Max || left.SyllableStructure.SonorantAndVowelCount.Min != right.SyllableStructure.SonorantAndVowelCount.Min) { return false; } } return true; }
/// <summary> /// Parse XML document for Phone Set File path. /// </summary> /// <param name="dom">XML configuration document.</param> /// <param name="nsmgr">Namespace.</param> private void ParsePhoneSet(XmlDocument dom, XmlNamespaceManager nsmgr) { PhoneSetFile = ParseFilePath(dom, nsmgr, PhoneSetFileItem); if (!Helper.FileValidExists(PhoneSetFile)) { throw new FileNotFoundException( string.Format(CultureInfo.InvariantCulture, "Phone set file \"{0}\" not found.", PhoneSetFile)); } PhoneSet = new TtsPhoneSet(); PhoneSet.Load(PhoneSetFile); }
/// <summary> /// Intiate phoneme with phoneset instance. /// </summary> /// <param name="phoneSet">Phone set.</param> private void ParseData(TtsPhoneSet phoneSet) { if (phoneSet.Language != Language) { string message = Helper.NeutralFormat("The language [{0}] of phoneset " + "does not match with that [{1}] of phoneme.", Localor.LanguageToString(phoneSet.Language), Localor.LanguageToString(Language)); throw new InvalidDataException(message); } _ttsPhoneSet = new Collection<string>(); _ttsSonorantPhoneSet = new Collection<string>(); _ttsVowelPhoneSet = new Collection<string>(); _ttsPhoneIds = new Dictionary<string, int>(); int toneCount = 0; foreach (Phone phone in phoneSet.Phones) { if (phone.IsNormal || phone.Features.Contains(PhoneFeature.Silence)) { _ttsPhoneSet.Add(phone.Name); } if (phone.IsVowel) { _ttsVowelPhoneSet.Add(phone.Name); } if (phone.IsSonorant) { _ttsSonorantPhoneSet.Add(phone.Name); } if (phone.HasFeature(PhoneFeature.Tone)) { _toneManager.Add(phone, ToneManager.ContextToneStartIndex + toneCount); toneCount++; } _ttsPhoneIds.Add(phone.Name, phone.Id); } }
/// <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> /// Compile the trunc rule into binary writer. /// </summary> /// <param name="truncRuleFileName">File path of trunc rule.</param> /// <param name="phoneSet">Phone set.</param> /// <param name="bw">Binary writer.</param> /// <returns>Error.</returns> private static ErrorSet CompTruncRuleData(string truncRuleFileName, TtsPhoneSet phoneSet, BinaryWriter bw) { // maximum truncate rule length is 5 phonmes currently const int MaxTruncRuleLength = 5; ErrorSet errorSet = new ErrorSet(); List<TruncateNucleusRule> rules = new List<TruncateNucleusRule>(); XmlDocument xmldoc = new XmlDocument(); xmldoc.Load(truncRuleFileName); XmlNamespaceManager nm = new XmlNamespaceManager(xmldoc.NameTable); nm.AddNamespace("tts", "http://schemas.microsoft.com/tts/toolsuite"); XmlNodeList nodeList = xmldoc.DocumentElement.SelectNodes( "/tts:offline/tts:truncateRules/tts:truncateRule", nm); if (nodeList != null) { foreach (XmlNode node in nodeList) { XmlNodeList phoneNodeList; XmlElement xmlNode = node as XmlElement; string side = xmlNode.GetAttribute("side"); int direction = 0; if (side.Equals("Right", StringComparison.OrdinalIgnoreCase)) { direction = 2; // TruncFromRight } else if (side.Equals("Left", StringComparison.OrdinalIgnoreCase)) { direction = 1; // TruncFromLeft } else { errorSet.Add(UnitGeneratorDataCompilerError.WrongRuleSide, side, xmlNode.InnerXml); } phoneNodeList = xmlNode.SelectNodes("tts:phone", nm); if (phoneNodeList.Count > MaxTruncRuleLength) { errorSet.Add(UnitGeneratorDataCompilerError.RuleLengthExceeded, MaxTruncRuleLength.ToString(CultureInfo.InvariantCulture), xmlNode.InnerXml); } else { int idx = 0; short[] ids = new short[MaxTruncRuleLength + 1]; foreach (XmlNode phoneNode in phoneNodeList) { XmlElement xmlPhoneNode = phoneNode as XmlElement; string phoneValue = xmlPhoneNode.GetAttribute("value"); Phone phone = phoneSet.GetPhone(phoneValue); if (phone != null) { ids[idx++] = (short)phone.Id; } else { errorSet.Add(UnitGeneratorDataCompilerError.InvalidPhone, phoneValue); } } ids[idx] = 0; TruncateNucleusRule rule = new TruncateNucleusRule(); rule.Ids = ids; rule.Direction = direction; rules.Add(rule); } } } // write the data bw.Write(rules.Count); foreach (TruncateNucleusRule ci in rules) { bw.Write(ci.Direction); for (int i = 0; i < ci.Ids.Length; i++) { bw.Write(BitConverter.GetBytes(ci.Ids[i])); } } return errorSet; }
/// <summary> /// Get the normal phones' names. /// </summary> /// <param name="phoneSet">Phone set.</param> /// <param name="errors">Errors is having.</param> /// <returns>The pohne names.</returns> public Collection<string> GetNormalPhoneNames(TtsPhoneSet phoneSet, ErrorSet errors) { if (phoneSet == null) { throw new ArgumentNullException("phoneSet"); } if (errors == null) { throw new ArgumentNullException("errors"); } errors.Clear(); Collection<Phone> phones = GetPhones(phoneSet, errors); Collection<string> names = new Collection<string>(); if (errors.Count == 0) { foreach (Phone phone in phones) { if (phone.IsNormal) { names.Add(phone.Name); } } } return names; }
/// <summary> /// Get the Phones of this word. /// </summary> /// <param name="phoneSet">Phone set.</param> /// <param name="errors">Errors if having invalid phone.</param> /// <returns>The phones.</returns> public Collection<Phone> GetPhones(TtsPhoneSet phoneSet, ErrorSet errors) { if (phoneSet == null) { throw new ArgumentNullException("phoneSet"); } if (errors == null) { throw new ArgumentNullException("errors"); } errors.Clear(); string pronunciation = GetPronunciation(phoneSet); Collection<Phone> phoneColl = new Collection<Phone>(); // Note: for punctucations should return empty phone collection if (WordType == WordType.Normal) { Phone[] phones = Core.Pronunciation.SplitIntoPhones(pronunciation, phoneSet, errors); if (phones != null) { phoneColl = new Collection<Phone>(phones); } } return phoneColl; }
/// <summary> /// Get the pronunciation /// If there exist syllable list, build pronunciation from it /// Otherwise, return the pronunciation of word's attribute without unit boundary. /// Note: return empty string if this word doesn't have pronunciation(e.g. punctuation). /// </summary> /// <param name="phoneSet">Phone set.</param> /// <returns>Pronunciation string.</returns> public string GetPronunciation(TtsPhoneSet phoneSet) { string pronunciation = string.Empty; // Build the pronunciation when syllables and phones exist if (Syllables.Count > 0 && Syllables.Any(syl => syl.Phones.Count > 0)) { StringBuilder sb = new StringBuilder(); foreach (ScriptSyllable syllable in Syllables) { if (sb.Length > 0) { sb.Append(Core.Pronunciation.SyllableBoundaryString); } sb.Append(syllable.BuildTextFromPhones(phoneSet)); } pronunciation = sb.ToString(); } else { // phoneSet can be null here if (!string.IsNullOrEmpty(_pronunciation)) { pronunciation = Core.Pronunciation.RemoveUnitBoundary(_pronunciation); } } return pronunciation; }
/// <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> /// Compiler. /// </summary> /// <param name="syllabifyRuleFileName">Path of syllabify rule.</param> /// <param name="phoneSet">Phone set.</param> /// <param name="outputStream">Output Stream.</param> /// <returns>ErrorSet.</returns> public static ErrorSet Compile(string syllabifyRuleFileName, TtsPhoneSet phoneSet, Stream outputStream) { if (string.IsNullOrEmpty(syllabifyRuleFileName)) { throw new ArgumentNullException("syllabifyRuleFileName"); } if (phoneSet == null) { throw new ArgumentNullException("phoneSet"); } if (outputStream == null) { throw new ArgumentNullException("outputStream"); } // maximum rule length is 3 phonmes currently const int MaxRuleLength = 3; ErrorSet errorSet = new ErrorSet(); phoneSet.Validate(); if (phoneSet.ErrorSet.Contains(ErrorSeverity.MustFix)) { errorSet.Add(SyllabifyRuleCompilerError.InvalidPhoneSet); } else { BinaryWriter bw = new BinaryWriter(outputStream); { List<ushort[]> rules = new List<ushort[]>(); XmlDocument xmldoc = new XmlDocument(); xmldoc.Load(syllabifyRuleFileName); XmlNamespaceManager nm = new XmlNamespaceManager(xmldoc.NameTable); nm.AddNamespace("tts", _ttsSchemaUri); XmlNodeList nodeList = xmldoc.DocumentElement.SelectNodes( "/tts:syllabifyRules/tts:initialConsonants", nm); if (nodeList != null) { foreach (XmlNode node in nodeList) { XmlNodeList phoneNodeList; XmlElement xmlNode = node as XmlElement; phoneNodeList = xmlNode.SelectNodes("tts:phone", nm); if (phoneNodeList.Count > MaxRuleLength) { errorSet.Add(SyllabifyRuleCompilerError.RuleLengthExceeded, MaxRuleLength.ToString(CultureInfo.InvariantCulture), xmlNode.InnerXml); } else { ushort[] rule = new ushort[MaxRuleLength + 1]; int idx = 0; foreach (XmlNode phoneNode in phoneNodeList) { XmlElement xmlPhoneNode = phoneNode as XmlElement; string phoneValue = xmlPhoneNode.GetAttribute("value"); Phone phone = phoneSet.GetPhone(phoneValue); if (phone != null) { rule[idx++] = (ushort)phone.Id; } else { errorSet.Add(SyllabifyRuleCompilerError.InvalidPhone, phoneValue); } } rule[idx] = 0; rules.Add(rule); } } bw.Write(rules.Count); foreach (ushort[] ci in rules) { for (int i = 0; i < ci.Length; i++) { bw.Write(BitConverter.GetBytes(ci[i])); } } } } } return errorSet; }
/// <summary> /// Compiler entrance. /// </summary> /// <param name="phoneSet">Phone set object.</param> /// <param name="phoneConverter">PhoneConverter.</param> /// <param name="outputStream">Output stream.</param> /// <returns>ErrorSet.</returns> public static ErrorSet Compile(TtsPhoneSet phoneSet, IPhoneConverter phoneConverter, Stream outputStream) { if (phoneSet == null) { throw new ArgumentNullException("phoneSet"); } if (outputStream == null) { throw new ArgumentNullException("outputStream"); } ErrorSet errorSet = new ErrorSet(); phoneSet.Validate(); if (phoneSet.ErrorSet.Contains(ErrorSeverity.MustFix)) { errorSet.Add(PhoneEventCompilerError.InvalidPhoneSet); } else { BinaryWriter bw = new BinaryWriter(outputStream); int inUpsCount = visemeMap.Length / 2; Dictionary<char, byte> dicVisemeMap = new Dictionary<char, byte>(inUpsCount); for (int i = 0; i < inUpsCount; i++) { dicVisemeMap.Add((char)visemeMap[i, 0], (byte)visemeMap[i, 1]); } foreach (Phone phm in phoneSet.Phones) { bw.Write((short)phm.Id); string strViseme = string.Empty; string ttsPhoneID = new string(Convert.ToChar(phm.Id), 1); char[] upsIds; try { upsIds = phoneConverter.TTS2UPS(ttsPhoneID).ToCharArray(); } catch (Exception ex) { upsIds = string.Empty.ToCharArray(); errorSet.Add(DataCompilerError.CompilingLog, string.Format("Failed to convert TTS phone to UPS, Id={0}. {1}", phm.Id, Helper.BuildExceptionMessage(ex))); } // check upsid's length if (upsIds.Length > MAX_UPS_PHONE_PER_TTS) { throw new NotSupportedException("Too many UPS phones for one TTS phone."); } // write viseme int k = 0; for (int j = 0; j < upsIds.Length; j++) { byte visemeVal = dicVisemeMap[upsIds[j]]; if (visemeVal != VISEME_0) { // ignore those silence viseme in-between one ups phone's viseme series since // it's not natural to close mouth in one phone. bw.Write(visemeVal); k++; } } // pad zero. If all viseme are silence, then save one silence viseme. // otherwise, zero represent the end of viseme id series. for (; k < MAX_UPS_PHONE_PER_TTS + 1; k++) { bw.Write((byte)0); } if (phoneConverter != null) { string sapiPhoneId = phoneConverter.TTS2SAPI(ttsPhoneID); if (sapiPhoneId.Length > MAX_SAPI_PHONE_PER_TTS) { throw new NotSupportedException("Too many SAPI phones for one TTS phone."); } char[] phoneIdArray = sapiPhoneId.ToCharArray(); int i = 0; for (i = 0; i < phoneIdArray.Length; i++) { bw.Write((ushort)phoneIdArray[i]); } for (; i < MAX_SAPI_PHONE_PER_TTS; i++) { bw.Write((ushort)0); } } else { for (int i = 0; i < MAX_SAPI_PHONE_PER_TTS; ++i) { bw.Write((ushort)0); } } bw.Write((ushort)0); } } return errorSet; }
/// <summary> /// Build the syllable's pronunciation. /// </summary> /// <param name="phoneSet">Phone set.</param> /// <returns>The built pronunciation string.</returns> public string BuildTextFromPhones(TtsPhoneSet phoneSet) { if (phoneSet == null) { throw new ArgumentNullException("phoneSet"); } StringBuilder sb = new StringBuilder(); foreach (ScriptPhone phone in _phones) { sb.AppendFormat("{0}{1}", phone.Name, " "); // append stress if (_stress != TtsStress.None) { Phone ttsPhone = phoneSet.GetPhone(phone.Name); if (ttsPhone != null && ttsPhone.IsVowel) { switch (_stress) { case TtsStress.Primary: sb.Append("1 "); break; case TtsStress.Secondary: sb.Append("2 "); break; case TtsStress.Tertiary: sb.Append("3 "); break; } } } // append tone if (!string.IsNullOrEmpty(phone.Tone)) { sb.AppendFormat("{0}{1}", phone.Tone, " "); } } return sb.ToString().Trim(); }
/// <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> /// Get the syllable strings this word has /// The syllable contains stress but doesn't contain unit boundaries. /// </summary> /// <param name="phoneSet">Phone set.</param> /// <returns>Syllable strings.</returns> public Collection<string> GetSyllables(TtsPhoneSet phoneSet) { if (phoneSet == null) { throw new ArgumentNullException("phoneSet"); } string[] syllables = Core.Pronunciation.SplitIntoSyllables(GetPronunciation(phoneSet)); return new Collection<string>(syllables); }
/// <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> /// Build script syllables from a word's pronunciation. /// </summary> /// <param name="pronunciation">The word's pronunciation.</param> /// <param name="phoneSet">TtsPhoneSet.</param> /// <returns>The built syllables.</returns> public static Collection<ScriptSyllable> ParsePronunciationToSyllables(string pronunciation, TtsPhoneSet phoneSet) { if (string.IsNullOrEmpty(pronunciation)) { throw new ArgumentNullException("pronunciation"); } if (phoneSet == null) { throw new ArgumentNullException("phoneSet"); } // check whether the pronunciation is valid // only need to throw exception for invalid pronunciation ErrorSet errors = Core.Pronunciation.Validate(pronunciation, phoneSet); if (errors.Count > 0) { string message = Helper.NeutralFormat("Invalid pronunciation."); throw new InvalidDataException(message); } string[] syllables = Core.Pronunciation.SplitIntoSyllables(pronunciation); Collection<ScriptSyllable> scriptSyllables = new Collection<ScriptSyllable>(); foreach (string syllable in syllables) { scriptSyllables.Add(ScriptSyllable.ParseStringToSyllable(syllable, phoneSet)); } return scriptSyllables; }
/// <summary> /// Compiler. /// </summary> /// <param name="truncRuleFileName">File path of trunc rule.</param> /// <param name="phoneSet">Phone set.</param> /// <param name="outputStream">Output Stream.</param> /// <returns>ErrorSet.</returns> public static ErrorSet Compile(string truncRuleFileName, TtsPhoneSet phoneSet, Stream outputStream) { if (string.IsNullOrEmpty(truncRuleFileName)) { throw new ArgumentNullException("truncRuleFileName"); } // pauseLengthFileName could be null if (phoneSet == null) { throw new ArgumentNullException("phoneSet"); } if (outputStream == null) { throw new ArgumentNullException("outputStream"); } ErrorSet errorSet = new ErrorSet(); phoneSet.Validate(); if (phoneSet.ErrorSet.Contains(ErrorSeverity.MustFix)) { errorSet.Add(UnitGeneratorDataCompilerError.InvalidPhoneSet); } else { BinaryWriter bw = new BinaryWriter(outputStream); { errorSet.Merge(CompTruncRuleData(truncRuleFileName, phoneSet, bw)); } } return errorSet; }
/// <summary> /// Get the Phones of this sentence. /// </summary> /// <param name="phoneSet">Phone set.</param> /// <param name="errors">Errors if having invalid phone.</param> /// <returns>The phones.</returns> public Collection<Phone> GetPhones(TtsPhoneSet phoneSet, ErrorSet errors) { if (phoneSet == null) { throw new ArgumentNullException("phoneSet"); } if (errors == null) { throw new ArgumentNullException("errors"); } errors.Clear(); Collection<Phone> phones = new Collection<Phone>(); foreach (ScriptWord word in Words) { ErrorSet wordErrors = new ErrorSet(); foreach (Phone phone in word.GetPhones(phoneSet, wordErrors)) { phones.Add(phone); } errors.Merge(wordErrors); } return phones; }
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> /// Get the Phones of this item. /// </summary> /// <param name="phoneSet">Phone set.</param> /// <param name="errors">Errors if having invalid phone.</param> /// <returns>The phones.</returns> public Collection<Phone> GetPhones(TtsPhoneSet phoneSet, ErrorSet errors) { if (phoneSet == null) { throw new ArgumentNullException("phoneSet"); } if (errors == null) { throw new ArgumentNullException("errors"); } errors.Clear(); Collection<Phone> phones = new Collection<Phone>(); foreach (ScriptSentence sentence in Sentences) { ErrorSet sentenceErrors = new ErrorSet(); foreach (Phone phone in sentence.GetPhones(phoneSet, sentenceErrors)) { phones.Add(phone); } errors.Merge(sentenceErrors); } return phones; }
/// <summary> /// Initialize the validator. /// </summary> public void EnsureInitialized() { Debug.Assert(LexiconFilePath != null || Lexicon != null); Debug.Assert(PhoneSetFilePath != null || PhoneSet != null); if (_lexicon == null) { _lexicon = new Lexicon(); _lexicon.Load(LexiconFilePath); } if (_phoneset == null) { _phoneset = new TtsPhoneSet(); _phoneset.Load(PhoneSetFilePath); } if (_phoneset.Language != _lexicon.Language) { string message = Utility.Helper.NeutralFormat( "phoneset and lexicon language should match"); throw new InvalidDataException(message); } _language = _lexicon.Language; }
/// <summary> /// Get the normal phones' names. /// </summary> /// <param name="phoneSet">Phone set.</param> /// <param name="errors">Errors is having.</param> /// <returns>The pohne names.</returns> public Collection<string> GetNormalPhoneNames(TtsPhoneSet phoneSet, ErrorSet errors) { if (phoneSet == null) { throw new ArgumentNullException("phoneSet"); } if (errors == null) { throw new ArgumentNullException("errors"); } errors.Clear(); Collection<string> names = new Collection<string>(); foreach (ScriptSentence sentence in Sentences) { ErrorSet sentenceErrors = new ErrorSet(); foreach (string name in sentence.GetNormalPhoneNames(phoneSet, sentenceErrors)) { names.Add(name); } errors.Merge(sentenceErrors); } return names; }
/// <summary> /// Load phone set from file. /// </summary> /// <param name="language">The language of phone set.</param> /// <param name="path">Path to load phone set.</param> /// <returns>Loaded phone set.</returns> public static TtsPhoneSet LoadFromFile(Language language, string path) { TtsPhoneSet phoneSet = new TtsPhoneSet(language); phoneSet.Load(path); return phoneSet; }
/// <summary> /// Get the syllable strings this item has /// The syllable contains stress but doesn't contain unit boundaries. /// </summary> /// <param name="phoneSet">Phone set.</param> /// <returns>Syllable strings.</returns> public Collection<string> GetSyllables(TtsPhoneSet phoneSet) { if (phoneSet == null) { throw new ArgumentNullException("phoneSet"); } Collection<string> syllables = new Collection<string>(); foreach (ScriptSentence sentence in Sentences) { foreach (string syllable in sentence.GetSyllables(phoneSet)) { syllables.Add(syllable); } } return syllables; }
/// <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; }
/// <summary> /// Load Phone set Data object. /// </summary> /// <param name="errorSet">ErrorSet.</param> /// <returns>Phone set Data object.</returns> internal override object LoadDataObject(ErrorSet errorSet) { if (errorSet == null) { throw new ArgumentNullException("errorSet"); } TtsPhoneSet phoneSet = new TtsPhoneSet(); phoneSet.Load(this.Path); phoneSet.Validate(); errorSet.Merge(phoneSet.ErrorSet); if (phoneSet.ErrorSet.Contains(ErrorSeverity.MustFix)) { phoneSet = null; } return phoneSet; }