/// <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. /// </summary> /// <param name="filePath">FilePath.</param> /// <param name="phoneSet">PhoneSet.</param> /// <returns>ErrorSet.</returns> public ErrorSet Load(string filePath, TtsPhoneSet phoneSet) { // This validation is needed by Fxcop checking parameters. if (phoneSet == null) { phoneSet = null; } if (string.IsNullOrEmpty(filePath)) { throw new ArgumentNullException("filePath"); } if (!File.Exists(filePath)) { throw Helper.CreateException(typeof(FileNotFoundException), filePath); } if (!Helper.IsUnicodeFile(filePath)) { throw new InvalidDataException(Helper.NeutralFormat( "Polyphony rule file [{0}] is not unicode.", filePath)); } ErrorSet errorSet = new ErrorSet(); _keyTypes.Clear(); bool finishReadHead = false; bool firstKeyString = true; PolyphonyRule polyphonyWord = null; int lineNum = 0; string domain = DomainItem.GeneralDomain; foreach (string line in Helper.FileLines(filePath, Encoding.Unicode, false)) { lineNum++; string trimedLine = line.Trim(); if (string.IsNullOrEmpty(trimedLine)) { continue; } if (IsComment(trimedLine)) { continue; } if (IsDomainTag(trimedLine)) { ParseDomainKey(trimedLine, ref domain); continue; } ErrorSet parseErrorSet = new ErrorSet(); if (!finishReadHead) { bool isKeyDeclear = TryParseKeyDeclear(trimedLine, ref firstKeyString, parseErrorSet); AddParseError(errorSet, lineNum, parseErrorSet); if (isKeyDeclear) { continue; } else { finishReadHead = true; } } PolyruleKeys.Instance.KeyTypes = _keyTypes; parseErrorSet.Clear(); bool isKeyLine = TryParseKeyLine(trimedLine, ref polyphonyWord, parseErrorSet, domain); domain = DomainItem.GeneralDomain; AddParseError(errorSet, lineNum, parseErrorSet); if (isKeyLine) { continue; } parseErrorSet.Clear(); bool isConditionLine = TryParseConditionLine(trimedLine, phoneSet, polyphonyWord, parseErrorSet); AddParseError(errorSet, lineNum, parseErrorSet); if (isConditionLine) { continue; } errorSet.Add(PolyRuleError.InvalidLineFormat, lineNum.ToString(CultureInfo.InvariantCulture), trimedLine); } if (polyphonyWord != null) { _polyphonyWords.Add(polyphonyWord); } if (string.IsNullOrEmpty(_keyString)) { errorSet.Add(PolyRuleError.MissPrimaryKey, filePath); } errorSet.AddRange(CheckDupWordDefinitions()); foreach (PolyphonyRule rule in _polyphonyWords) { errorSet.AddRange(rule.CheckDupRuleConditions()); } return errorSet; }
/// <summary> /// Check whether a script item is valid /// We don't check schema here /// Validation conditions: /// 1. Normal word should have pronunciation /// 2. Pronunciation should be good /// 3. POS should be in POS set /// We could use some flag to control the validation conditions /// When we need flexible control. /// </summary> /// <param name="item">The item to be checked.</param> /// <param name="errors">Errors if item is invalid.</param> /// <param name="validateSetting">Validation data set.</param> /// <returns>True is valid.</returns> public static bool IsValidItem(ScriptItem item, ErrorSet errors, XmlScriptValidateSetting validateSetting) { if (item == null) { throw new ArgumentNullException("item"); } if (errors == null) { throw new ArgumentNullException("errors"); } if (validateSetting == null) { throw new ArgumentNullException("validateSetting"); } validateSetting.VerifySetting(); XmlScriptValidationScope scope = validateSetting.ValidationScope; bool valid = true; errors.Clear(); int sentIndex = 0; foreach (ScriptSentence sentence in item.Sentences) { int wordIndex = 0; foreach (ScriptWord word in sentence.Words) { if ((scope & XmlScriptValidationScope.Pronunciation) == XmlScriptValidationScope.Pronunciation) { // check pronunciation string pron = null; if (word.WordType == WordType.Normal) { pron = word.GetPronunciation(validateSetting.PhoneSet); } if (!string.IsNullOrEmpty(pron)) { ErrorSet pronErrors = Core.Pronunciation.Validate(pron, validateSetting.PhoneSet); foreach (Error error in pronErrors.Errors) { errors.Add(ScriptError.PronunciationError, error, item.Id, word.Grapheme); } } else if (word.WordType == WordType.Normal) { // Pronunciation is optional for normal word, will give warning if empty pronunciation for normal word. errors.Add(ScriptError.EmptyPronInNormalWord, item.Id, word.Grapheme); } } if ((scope & XmlScriptValidationScope.POS) == XmlScriptValidationScope.POS) { // check pos name if (!string.IsNullOrEmpty(word.PosString) && !validateSetting.PosSet.Items.ContainsKey(word.PosString)) { errors.Add(ScriptError.UnrecognizedPos, item.Id, word.Grapheme, word.Pronunciation, word.PosString); } } string nodePath = string.Format(CultureInfo.InvariantCulture, "Sentence[{0}].Word[{1}]", sentIndex, wordIndex); word.IsValid(item.Id, nodePath, scope, errors); wordIndex++; } sentIndex++; } if ((scope & XmlScriptValidationScope.SegmentSequence) == XmlScriptValidationScope.SegmentSequence) { CheckSegments(item, errors); } if (errors.Count > 0) { valid = false; } return valid; }
/// <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> /// 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; }
/// <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> /// Add one item to script file. /// This method will check whether the item is balid before adding. /// </summary> /// <param name="item">The item to be added.</param> /// <param name="errors">The errors if failed to add.</param> /// <param name="validate">Whether validate schema and content.</param> /// <param name="sort">Whether insert the script item in the sort position.</param> /// <returns>True if successfully added.</returns> public bool Add(ScriptItem item, ErrorSet errors, bool validate, bool sort) { if (item == null) { throw new ArgumentNullException("item"); } if (errors == null) { throw new ArgumentNullException("errors"); } // check schema, should throw exception if invalid CheckSchema(item); bool added = true; errors.Clear(); // content checking, should add to errors if invalid if (_itemDic.ContainsKey(item.Id)) { errors.Add(ScriptError.DuplicateItemId, item.Id); } if (validate) { ErrorSet contentErrors = new ErrorSet(); XmlScriptValidateSetting validateSetting = new XmlScriptValidateSetting(PhoneSet, PosSet); ScriptItem.IsValidItem(item, contentErrors, validateSetting); errors.Merge(contentErrors); } if (errors.Count > 0) { added = false; } if (added) { _itemDic.Add(item.Id, item); if (sort) { bool inserted = false; for (int i = 0; i < _items.Count; i++) { if (string.Compare(item.Id, _items[i].Id, StringComparison.OrdinalIgnoreCase) < 0) { _items.Insert(i, item); inserted = true; break; } } if (!inserted) { _items.Add(item); } } else { _items.Add(item); } } return added; }
private ErrorSet CompileLexicon(Stream outputStream) { if (outputStream == null) { throw new ArgumentNullException("outputStream"); } ErrorSet errorSet = new ErrorSet(); ErrorSet subErrorSet = new ErrorSet(); LexicalAttributeSchema schema = (LexicalAttributeSchema)GetObject( RawDataName.LexicalAttributeSchema, subErrorSet); MergeDependencyError(errorSet, subErrorSet, _schemaFullName); subErrorSet.Clear(); TtsPhoneSet phoneSet = (TtsPhoneSet)GetObject(RawDataName.PhoneSet, subErrorSet); MergeDependencyError(errorSet, subErrorSet, RawDataName.PhoneSet); if (!errorSet.Contains(ErrorSeverity.MustFix)) { Microsoft.Tts.Offline.Core.Lexicon lexicon = (Microsoft.Tts.Offline.Core.Lexicon)GetObject(RawDataName.Lexicon, errorSet); errorSet.Merge(lexicon.ErrorSet); // Change to case insensitive lexicon MemoryStream lexiconStream = new MemoryStream(); using (XmlWriter xmlWriter = XmlWriter.Create(lexiconStream)) { Microsoft.Tts.Offline.Core.Lexicon.ContentControler lexiconControler = new Microsoft.Tts.Offline.Core.Lexicon.ContentControler(); lexiconControler.IsCaseSensitive = true; lexicon.Save(xmlWriter, lexiconControler); } lexiconStream.Seek(0, SeekOrigin.Begin); Microsoft.Tts.Offline.Core.Lexicon caseInsensitiveLexicon = new Microsoft.Tts.Offline.Core.Lexicon(); using (StreamReader sr = new StreamReader(lexiconStream)) { caseInsensitiveLexicon.Load(sr); } if (caseInsensitiveLexicon != null && !errorSet.Contains(ErrorSeverity.MustFix)) { caseInsensitiveLexicon.LexicalAttributeSchema = schema; caseInsensitiveLexicon.PhoneSet = phoneSet; caseInsensitiveLexicon.Validate(); // Set severity of errors only in case-insensitive lexicon to NoError for they're not treated as real error caseInsensitiveLexicon.ErrorSet.SetSeverity(ErrorSeverity.NoError); string vendorLexiconPath = Helper.GetTempFileName(); caseInsensitiveLexicon.SaveToVendorLexicon(vendorLexiconPath); string toolFileName = ToolName.BldVendor2; string binaryLexiconPath = Helper.GetTempFileName(); string compilingArguments = Helper.NeutralFormat("-v {0} V2 \"{1}\" \"{2}\" \"{3}\" TTS", (int)_language, _dataHandlerList.Datas[RawDataName.LexicalAttributeSchema].Path, vendorLexiconPath, binaryLexiconPath); string toolPath = Path.Combine(ToolDir, toolFileName); CheckToolExists(toolPath, errorSet); if (!errorSet.Contains(ErrorSeverity.MustFix)) { HandleCommandLine(ModuleDataName.Lexicon, toolPath, compilingArguments, binaryLexiconPath, outputStream, errorSet); } File.Delete(vendorLexiconPath); errorSet.Merge(caseInsensitiveLexicon.ErrorSet); } else if (lexicon == null) { errorSet.Add(DataCompilerError.RawDataError, "Lexicon"); } else { errorSet.Merge(caseInsensitiveLexicon.ErrorSet); } } return errorSet; }