Example #1
0
        /// <summary>
        /// Build units for syllbale pronunciation,
        /// And the units are concatenated together in the string and seperated by ".".
        /// </summary>
        /// <param name="phoneme">Phoneme of the language to process with.</param>
        /// <param name="sliceData">Slice data to process.</param>
        /// <param name="syllable">Syllables to process.</param>
        /// <returns>Best unit list.</returns>
        public static string[] BuildUnits(Phoneme phoneme,
            SliceData sliceData, string syllable)
        {
            if (phoneme == null)
            {
                throw new ArgumentNullException("phoneme");
            }

            if (phoneme.TtsSonorantPhones == null)
            {
                string message = Helper.NeutralFormat("phoneme.TtsSonorantPhones should not be null.");
                throw new ArgumentException(message);
            }

            if (string.IsNullOrEmpty(syllable))
            {
                throw new ArgumentNullException("syllable");
            }

            if (sliceData == null)
            {
                throw new ArgumentNullException("sliceData");
            }

            if (sliceData.OnsetSlices == null)
            {
                string message = Helper.NeutralFormat("sliceData.OnsetSlices should not be null.");
                throw new ArgumentException(message);
            }

            if (sliceData.NucleusSlices == null)
            {
                string message = Helper.NeutralFormat("sliceData.NucleusSlices should not be null.");
                throw new ArgumentException(message);
            }

            List<string> slicedUnits = new List<string>();

            string unstressedSyllable = Pronunciation.RemoveStress(syllable);

            ScriptItem scriptItem = new ScriptItem(phoneme.Language);

            // items contains phone and tone.
            string[] items = scriptItem.PronunciationSeparator.SplitPhones(unstressedSyllable);

            // Treate all syllable as one unit at first.
            TtsMetaUnit ttsMetaUnit = new TtsMetaUnit(phoneme.Language);
            ttsMetaUnit.Name = string.Join(" ", items);
            string[] phones = ttsMetaUnit.GetPhonesName();

            // Treat all phones in this syllable as a whole unit
            if (sliceData.NucleusSlices.IndexOf(ttsMetaUnit.Name) >= 0)
            {
                // If it is alread defined in the predefined unit collection, return it
                slicedUnits.Add(TtsUnit.NucleusPrefix + ttsMetaUnit.Name.Replace(" ", TtsUnit.PhoneDelimiter));
                return slicedUnits.ToArray();
            }

            int vowelIndex = phoneme.GetFirstVowelIndex(phones);
            if (vowelIndex < 0)
            {
                // If no vowel in the syllable, treat all phones in this syllable as a unit if it is in unit table
                if (sliceData.OnsetSlices.IndexOf(ttsMetaUnit.Name) >= 0)
                {
                    slicedUnits.Add(TtsUnit.OnsetPrefix + ttsMetaUnit.Name.Replace(" ", TtsUnit.PhoneDelimiter));
                }
                else if (sliceData.CodaSlices.IndexOf(ttsMetaUnit.Name) >= 0)
                {
                    slicedUnits.Add(TtsUnit.CodaPrefix + ttsMetaUnit.Name.Replace(" ", TtsUnit.PhoneDelimiter));
                }
                else
                {
                    // otherwise, treat each phone as a coda unit
                    foreach (string phone in phones)
                    {
                        slicedUnits.Add(TtsUnit.CodaPrefix + phone);
                    }
                }

                return slicedUnits.ToArray();
            }

            // Search first cosonant sonarant from the left side of the vowel font in the syllable
            int firstSonarantIndex = vowelIndex;
            for (int i = vowelIndex - 1; i >= 0; i--)
            {
                if (phoneme.TtsSonorantPhones.IndexOf(phones[i]) >= 0)
                {
                    firstSonarantIndex = i;
                }
            }

            // Search last cosonant sonarant from the right side of the vowel font in the syllable
            int lastSonarantIndex = vowelIndex;
            for (int i = vowelIndex + 1; i <= phones.Length - 1; i++)
            {
                if (phoneme.TtsSonorantPhones.IndexOf(phones[i]) >= 0)
                {
                    lastSonarantIndex = i;
                }
            }

            // Treat all vowel and surrounding sonarant consonants as the nucleus unit first
            string nucleus = TtsMetaPhone.Join(" ", ttsMetaUnit.Phones,
                firstSonarantIndex, lastSonarantIndex - firstSonarantIndex + 1);

            TruncateRuleData truncateRuleData = Localor.GetTruncateRuleData(phoneme.Language);

            // Refine nucleus according to the predefined unit table
            while (lastSonarantIndex - firstSonarantIndex > 0 && sliceData.NucleusSlices.IndexOf(nucleus) <= 0)
            {
                // If the unit candidate is not listed in the predefined unit list, try to truncate it
                string[] leftRight =
                    PhoneMerger.TruncateOnePhoneFromNucleus(phoneme, truncateRuleData.NucleusTruncateRules,
                    nucleus);

                if (phoneme.TtsPhones.IndexOf(leftRight[0]) >= 0)
                {
                    Debug.Assert(phoneme.TtsPhones.IndexOf(leftRight[0]) >= 0);
                    firstSonarantIndex++;
                }
                else
                {
                    Debug.Assert(phoneme.TtsPhones.IndexOf(leftRight[1]) >= 0);
                    lastSonarantIndex--;
                }

                // Re-define the remaining nucleus unit
                nucleus = TtsMetaPhone.Join(" ", ttsMetaUnit.Phones,
                    firstSonarantIndex, lastSonarantIndex - firstSonarantIndex + 1);
            }

            slicedUnits.Add(TtsUnit.NucleusPrefix + nucleus.Replace(" ", TtsUnit.PhoneDelimiter));

            // Refine onset
            for (int index = firstSonarantIndex - 1; index >= 0; index--)
            {
                string onset = TtsMetaPhone.Join(TtsUnit.PhoneDelimiter, ttsMetaUnit.Phones, 0, index + 1);
                if (sliceData.OnsetSlices.IndexOf(onset.Replace(TtsUnit.PhoneDelimiter, " ")) >= 0)
                {
                    slicedUnits.Insert(0, TtsUnit.OnsetPrefix + onset);

                    // Remove the number of added phones,
                    // except current phone itself which will be recuded by index--
                    index -= index;
                }
                else
                {
                    // Treat it as a single phone unit
                    slicedUnits.Insert(0,
                        TtsUnit.OnsetPrefix + TtsMetaPhone.Join(TtsUnit.PhoneDelimiter, ttsMetaUnit.Phones, index, 1));
                }
            }

            // Refine coda, matching from right to left
            BuildCodaUnits(sliceData, ttsMetaUnit.Phones, lastSonarantIndex + 1, slicedUnits);

            return slicedUnits.ToArray();
        }
Example #2
0
        /// <summary>
        /// Set nucleus vowel stress mark.
        /// </summary>
        /// <param name="phoneme">Phoneme of the language to process.</param>
        /// <param name="pronunciation">Pronunciation to set pronunciation.</param>
        /// <param name="stress">Stress mark to set for the vowel in the pronunciation.</param>
        /// <returns>Pronunciation with stress.</returns>
        public static string SetVowelStress(Phoneme phoneme, string pronunciation, TtsStress stress)
        {
            if (phoneme == null)
            {
                throw new ArgumentNullException("phoneme");
            }

            if (string.IsNullOrEmpty(pronunciation))
            {
                return null;
            }

            if (stress > TtsStress.None)
            {
                string[] phones = pronunciation.Split(new char[] { ' ' },
                    StringSplitOptions.RemoveEmptyEntries);
                int vowelIndex = phoneme.GetFirstVowelIndex(phones);
                if (vowelIndex < 0)
                {
                    string message = string.Format(CultureInfo.InvariantCulture,
                        "There is no vowel found in the syllable pronunciation [{0}]",
                        phones);
                    throw new InvalidDataException(message);
                }

                phones[vowelIndex] = string.Format(CultureInfo.InvariantCulture,
                    "{0} {1}", phones[vowelIndex], (int)stress);

                return string.Join(" ", phones);
            }
            else
            {
                return pronunciation;
            }
        }