/// <summary>
        /// Initializes a new instance of the CustomizedFeatureExtraction class.
        /// </summary>
        /// <param name="serviceProvider">Service provider.</param>
        /// <param name="customizedFeaturePluginManager">Plugin manager.</param>
        public CustomizedFeatureExtraction(ServiceProvider serviceProvider,
            CustomizedFeaturePluginManager customizedFeaturePluginManager)
        {
            if (serviceProvider == null)
            {
                throw new ArgumentNullException("serviceProvider");
            }

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

            _customizedFeaturePluginManager = customizedFeaturePluginManager;

            List<PluginInfo> pluginInfos = _customizedFeaturePluginManager.GetPlugins(
                CustomizedFeaturePluginManager.AttachBeforeExtraction);
            if (pluginInfos != null)
            {
                _utteranceExtenders = UtteranceExtenderFinder.LoadUtteranceExtenders(pluginInfos);
            }

            _serviceProvider = serviceProvider;

            _serviceProvider.Engine.AcousticProsodyTagger.Processing += new EventHandler<TtsModuleEventArgs>(OnAcousticProcessing);
        }
        /// <summary>
        /// Initializes a new instance of the ScriptSynthesizer class.
        /// </summary>
        /// <param name="serviceProvider">Service provider.</param>
        /// <param name="commonConfig">Common config of script synthesizer.</param>
        /// <param name="scriptFeatureImportConfig">Config of script feature import.</param>
        /// <param name="customizedFeaturePluginManager">Plugin manager of customized feature extraction.</param>
        public ScriptSynthesizer(ServiceProvider serviceProvider,
            ScriptSynthesizerCommonConfig commonConfig,
            ScriptFeatureImportConfig scriptFeatureImportConfig,
            CustomizedFeaturePluginManager customizedFeaturePluginManager)
        {
            if (serviceProvider == null)
            {
                throw new ArgumentNullException("serviceProvider");
            }

            // commonConfig can be null.
            // scriptFeatureImportConfig can be null.
            // customizedFeaturePluginManager can be null.
            _serviceProvider = serviceProvider;

            _scriptFeatureImportConfig = scriptFeatureImportConfig;

            if (commonConfig != null)
            {
                _logger = new TextLogger(commonConfig.TraceLogFile);
                _logger.Reset();
            }

            if (_scriptFeatureImportConfig != null)
            {
                _scriptFeatureImport = new ScriptFeatureImport(commonConfig,
                    _scriptFeatureImportConfig, _serviceProvider, _logger);
            }

            if (customizedFeaturePluginManager != null)
            {
                _customizedFeatureExtraction = new CustomizedFeatureExtraction(_serviceProvider,
                    customizedFeaturePluginManager);
            }
        }
        /// <summary>
        /// Parse config snippet and create the manager.
        /// </summary>
        /// <param name="nsmgr">Namespace manager.</param>
        /// <param name="configNode">Xml node containing the config.</param>
        /// <returns>The config object.</returns>
        public static CustomizedFeaturePluginManager ParseConfig(XmlNamespaceManager nsmgr, XmlNode configNode)
        {
            CustomizedFeaturePluginManager manager = null;
            if (nsmgr != null && configNode != null)
            {
                manager = new CustomizedFeaturePluginManager();
                manager.ParsePluginSettings(nsmgr, configNode);
            }

            return manager;
        }
        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());
            }
        }