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