/// <summary> /// Build coda units from the phone list. /// </summary> /// <param name="sliceData">Slice data.</param> /// <param name="phones">Phones to process.</param> /// <param name="codaOffset">The offset of the first phone in coda group.</param> /// <param name="slicedUnits">Unit container to append result coda units.</param> private static void BuildCodaUnits(SliceData sliceData, TtsMetaPhone[] phones, int codaOffset, List<string> slicedUnits) { int remainPhoneCount = phones.Length - codaOffset; int codaUnitOffset = slicedUnits.Count; // t w ih 1 k s t if (remainPhoneCount > 0) { int codaStartCursor = codaOffset; while (remainPhoneCount > 0) { int phoneCount = remainPhoneCount - (codaStartCursor - codaOffset); string tentativeCoda = TtsMetaPhone.Join(TtsUnit.PhoneDelimiter, phones, codaStartCursor, phoneCount); if (remainPhoneCount != 1 && sliceData.CodaSlices.IndexOf(tentativeCoda.Replace(TtsUnit.PhoneDelimiter, " ")) < 0 && phoneCount != 1) { codaStartCursor++; } else { // Left single phone will be treated as coda unit slicedUnits.Insert(codaUnitOffset, TtsUnit.CodaPrefix + tentativeCoda); remainPhoneCount = codaStartCursor - codaOffset; codaStartCursor = codaOffset; } } } }
/// <summary> /// Build phone names array of the unit, not contain tone. /// </summary> /// <param name="phones">TtsMetaPhone array to be processed.</param> /// <returns>Phone name array, not contain tone.</returns> public static string[] BuildPhoneNames(TtsMetaPhone[] phones) { if (phones == null || phones.Length == 0) { throw new ArgumentNullException("phones"); } List<string> phonesString = new List<string>(); foreach (TtsMetaPhone phone in phones) { phonesString.Add(phone.Name); } return phonesString.ToArray(); }
/// <summary> /// Build a phone array from a slice string. /// </summary> /// <param name="language">Language of the unit.</param> /// <param name="unit">Slice string, the text should only contain phone and tone, /// but not contain stress.</param> /// <returns>Phone array.</returns> public static TtsMetaPhone[] BuildPhones(Language language, string unit) { // should use mapping table for zh-CN // this is for en-US if (string.IsNullOrEmpty(unit)) { throw new ArgumentNullException("unit"); } List<TtsMetaPhone> phones = new List<TtsMetaPhone>(); string[] elements = unit.Split(new char[] { ' ', '+' }, StringSplitOptions.RemoveEmptyEntries); ToneManager toneManager = Localor.GetPhoneme(language).ToneManager; for (int i = 0; i < elements.Length; i++) { TtsMetaPhone phone = new TtsMetaPhone(language); phone.Name = elements[i]; // Check the next element is tone. if (i + 1 < elements.Length) { Match match = Regex.Match(elements[i + 1], TtsMetaPhone.TtsToneRegex); if (match.Success) { string toneString = match.Groups["index"].Value; phone.Tone = toneManager.GetContextToneId(toneString); i++; } } phones.Add(phone); } if (phones.Count <= 0) { throw new InvalidDataException(Helper.NeutralFormat("Invalid unit format, can't extract " + "phone from unit [{0}]", unit)); } return phones.ToArray(); }
/// <summary> /// Get phone string of specified phones. /// </summary> /// <param name="separator">Separator for the joint phone.</param> /// <param name="phones">TtsPhones to be joint.</param> /// <param name="startIndex">Start index from where to join the phone.</param> /// <param name="count">Cont of the phone to be joint.</param> /// <returns>Full name of all the phones to be joint.</returns> public static string Join(string separator, TtsMetaPhone[] phones, int startIndex, int count) { if (string.IsNullOrEmpty(separator)) { throw new ArgumentNullException("separator"); } if (phones == null) { throw new ArgumentNullException("phones"); } if (startIndex >= phones.Length || count <= 0 || startIndex + count - 1 >= phones.Length) { throw new InvalidDataException(Helper.NeutralFormat("Invalid index/lenght parameter [phones.Length=" + "{0}, startIndex={1}, count={2}", phones.Length, startIndex, count)); } StringBuilder sb = new StringBuilder(); for (int i = startIndex; i < startIndex + count; i++) { if (sb.Length > 0) { sb.Append(separator); } sb.Append(phones[i].Name); if (phones[i].Tone != ToneManager.NoneContextTone) { sb.Append(string.Format(CultureInfo.InvariantCulture, "{0}{1}", separator, phones[i].ToneString)); } } return sb.ToString(); }