/// <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);
        }
Exemple #7
0
        /// <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);
        }
Exemple #19
0
        /// <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;
        }
Exemple #25
0
        /// <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;
        }
Exemple #29
0
 /// <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;
        }