/// <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> /// 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> /// 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> /// 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; }
/// <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; }