/// <summary>
        /// Traverse script directory.
        /// </summary>
        /// <param name="visitor">Script item processor interface.</param>
        /// <param name="importDataPathList">File list for validation.</param>
        /// <param name="inScriptDir">Input script directory.</param>
        /// <param name="outScriptDir">Output script directory.</param>
        /// <param name="logger">Text logger.</param>
        /// <param name="parameters">Parameters.</param>
        public static void TraverseScriptDir(IScriptItemProcessor visitor, Dictionary<string, string> importDataPathList, 
            string inScriptDir, string outScriptDir, TextLogger logger,  
            object parameters)
        {
            if (string.IsNullOrEmpty(inScriptDir))
            {
                throw new ArgumentNullException("inScriptDir");
            }

            if (!Directory.Exists(inScriptDir))
            {
                throw new DirectoryNotFoundException(inScriptDir);
            }
           
            string pattern = @"*" + XmlScriptFile.Extension;
            foreach (string relativeFilePath in Helper.GetSubFilesRelativePath(
                inScriptDir, pattern))
            {
                string sourcePath = Path.Combine(inScriptDir, relativeFilePath);
                string targetFilePath = string.Empty;
                if (!string.IsNullOrEmpty(outScriptDir))
                {
                    targetFilePath = Path.Combine(outScriptDir, relativeFilePath);
                }

                TraverseScriptFile(visitor, importDataPathList, sourcePath, targetFilePath, logger, 
                    parameters);
            }
        }
        /// <summary>
        /// Traverse script file.
        /// </summary>
        /// <param name="visitor">Script item processor interface.</param>
        /// <param name="importDataPathList">File list for importing data model.</param>
        /// <param name="inScriptFile">Input script file.</param>
        /// <param name="outScriptFile">Output script file.</param>
        /// <param name="logger">Text logger.</param>
        /// <param name="parameters">Parameters.</param>
        public static void TraverseScriptFile(IScriptItemProcessor visitor, Dictionary<string, string> importDataPathList, 
            string inScriptFile, string outScriptFile, TextLogger logger,
            object parameters)
        {
            if (string.IsNullOrEmpty(inScriptFile))
            {
                throw new ArgumentNullException("inScriptFile");
            }

            if (!File.Exists(inScriptFile))
            {
                throw new FileNotFoundException(inScriptFile);
            }

            XmlScriptFile script = new XmlScriptFile();
            string message = Helper.NeutralFormat("Processing file : {0}", inScriptFile);
            Console.WriteLine(message);
            string fileName = Path.GetFileName(inScriptFile);

            try
            {
                script.Load(inScriptFile);
                List<string> listDiscard = new List<string>();

                foreach (ScriptItem scriptItem in script.Items)
                {
                    try
                    {
                        // When the mode is "Import F0/Power/Segment", the importDataPathList will not be null.
                        if (importDataPathList == null || importDataPathList.ContainsKey(scriptItem.Id))
                        {
                            visitor.ProcessItem(scriptItem, parameters);
                        }
                        else
                        {
                            listDiscard.Add(scriptItem.Id);
                        }
                    }
                    catch (InvalidDataException exception)
                    {
                        if (logger != null)
                        {
                            logger.LogLine("ERROR : [File {0}][Item {1}]{2}", fileName,
                                scriptItem.Id, exception.Message);
                        }
                    }
                }

                foreach (string id in listDiscard)
                {
                    script.Remove(id);
                }

                if (!string.IsNullOrEmpty(outScriptFile))
                {
                    Helper.TestWritable(outScriptFile);
                    script.Save(outScriptFile, Encoding.Unicode);
                }
            }
            catch (InvalidDataException exception)
            {
                if (logger != null)
                {
                    logger.LogLine("ERROR : [File {0}]{1}", fileName, exception.Message);
                }
            }
        }
 /// <summary>
 /// Append log information to log writer.
 /// </summary>
 /// <param name="logger">Log writer object.</param>
 /// <param name="newLine">Flag of whether add a new line.</param>
 /// <param name="format">Format of the output.</param>
 /// <param name="list">Argument list of the output.</param>
 private static void TraceLog(TextLogger logger, bool newLine,
     string format, params object[] list)
 {
     if (logger != null)
     {
         if (newLine)
         {
             logger.LogLine(format, list);
         }
         else
         {
             logger.Log(format, list);
         }
     }
 }
        /// <summary>
        /// Update silence words.
        /// </summary>
        /// <param name="utt">Engine TtsUtterance.</param>
        /// <param name="scriptSentence">Script sentence.</param>
        /// <param name="engine">Tts engine.</param>
        /// <param name="logger">Log writer object.</param>
        private static void UpdateSilenceWords(SP.TtsUtterance utt, ScriptSentence scriptSentence,
            TtsEngine engine, TextLogger logger)
        {
            // Gets phone set.
            TtsPhoneSet phoneSet = null;
            if (scriptSentence.ScriptItem != null && scriptSentence.ScriptItem.ScriptFile != null)
            {
                phoneSet = scriptSentence.ScriptItem.ScriptFile.PhoneSet;
            }

            if (phoneSet == null)
            {
                phoneSet = Localor.GetPhoneSet(scriptSentence.Language);
            }

            if (scriptSentence.ScriptItem != null && scriptSentence.ScriptItem.ScriptFile != null)
            {
                scriptSentence.ScriptItem.ScriptFile.PhoneSet = phoneSet;
            }

            int extWordIndex = 0;
            if (scriptSentence.Words[extWordIndex].WordType == WordType.Silence &&
                utt.Words[0].WordType != TtsWordType.WT_SILENCE)
            {
                string phone = scriptSentence.Words[extWordIndex].GetPronunciation(phoneSet);
                Debug.Assert(
                    Offline.Phoneme.IsSilenceFeature(phone), 
                    "Silence word should have only one phoneme - silence or short pause.");

                TtsWord silenceWord = utt.AddNewWord(utt.Words[0], InsertOptions.Before);
                ConfigSilenceWord(
                    engine.Phoneme.PronunciationToPhoneIds(Offline.Phoneme.ToRuntime(phone)),
                    silenceWord,
                    utt.Words[0].BreakLevel);
            }

            for (int uttWordIndex = 0; uttWordIndex < utt.Words.Count; uttWordIndex++)
            {
                TtsWord uttWord = utt.Words[uttWordIndex];
                if (uttWord.IsPronounceable)
                {
                    for (; extWordIndex < scriptSentence.Words.Count; extWordIndex++)
                    {
                        if (scriptSentence.Words[extWordIndex].IsPronounced)
                        {
                            extWordIndex++;
                            if (uttWord.BreakLevel < TtsBreakLevel.BK_IDX_INTERM_PHRASE)
                            {
                                if (extWordIndex < scriptSentence.Words.Count &&
                                    scriptSentence.Words[extWordIndex].WordType == WordType.Silence)
                                {
                                    string str1 = "Warning: Script xml has a silence word, ";
                                    string str2 = "but corresponding word[{0}] in engine has a break level ";
                                    string str3 = "less than BK_IDX_INTERM_PHRASE";
                                    TraceLog(logger, true, str1 + str2 + str3, uttWord.WordText);
                                }

                                if (uttWord.Next != null && uttWord.Next.WordType == TtsWordType.WT_SILENCE)
                                {
                                    utt.Delete(uttWord.Next);
                                }
                            }
                            else
                            {
                                if (extWordIndex < scriptSentence.Words.Count &&
                                    scriptSentence.Words[extWordIndex].WordType == WordType.Silence && 
                                    uttWord.Next.WordType != TtsWordType.WT_SILENCE)
                                {
                                    string phone = scriptSentence.Words[extWordIndex].GetPronunciation(phoneSet);
                                    Debug.Assert(
                                        Offline.Phoneme.IsSilenceFeature(phone),
                                        "Silence word should have only one phoneme - silence or short pause.");

                                    TtsWord silenceWord = utt.AddNewWord(uttWord, InsertOptions.After);
                                    ConfigSilenceWord(
                                        engine.Phoneme.PronunciationToPhoneIds(Offline.Phoneme.ToRuntime(phone)),
                                        silenceWord,
                                        uttWord.BreakLevel);
                                }
                                else if (uttWord.Next != null && uttWord.Next.WordType == TtsWordType.WT_SILENCE)
                                {
                                    utt.Delete(uttWord.Next);
                                }
                            }

                            break;
                        }
                    }
                }
            }
        }
 /// <summary>
 /// Add line in log writer.
 /// </summary>
 /// <param name="logger">Log writer object.</param>
 private static void TraceLogLine(TextLogger logger)
 {
     if (logger != null)
     {
         logger.LogLine();
     }
 }
 /// <summary>
 /// Trace log message to log file.
 /// </summary>
 /// <param name="acousticUpdated">Whether updated acoustic.</param>
 /// <param name="wordIndex">Word index.</param>
 /// <param name="syllableIndex">Syllable index.</param>
 /// <param name="phoneIndex">Phone index.</param>
 /// <param name="stateIndex">State index.</param>
 /// <param name="acousticTypeString">String of updated acoustic type.</param>
 /// <param name="logger">Text logger.</param>
 public void LogMessage(bool acousticUpdated, int wordIndex, int syllableIndex,
     int phoneIndex, int stateIndex, string acousticTypeString, TextLogger logger)
 {
     if (acousticUpdated)
     {
         if (stateIndex == NotUpdateState)
         {
             TraceLog(logger, false, "(sil){0},{1},{2}\t", wordIndex,
                 syllableIndex, phoneIndex);
         }
         else
         {
             TraceLog(logger, false, "(sil){0},{1},{2},{3}\t", wordIndex,
                 syllableIndex, phoneIndex, stateIndex);
         }
     }
     else
     {
         string message = Helper.NeutralFormat("Error update " +
             "PronouncedWords[{0}]'s silence word's {1}", wordIndex,
             acousticTypeString);
         throw new InvalidDataException(message);
     }
 }
        /// <summary>
        /// Initializes a new instance of the ScriptFeatureImport class.
        /// </summary>
        /// <param name="commonConfig">Common config of script synthesizer.</param>
        /// <param name="config">Config of script feature import.</param>
        /// <param name="serviceProvider">Service provider.</param>
        /// <param name="logger">Log writer.</param>
        public ScriptFeatureImport(ScriptSynthesizerCommonConfig commonConfig,
            ScriptFeatureImportConfig config, ServiceProvider serviceProvider,
            TextLogger logger)
        {
            //// commonConfig can be null.

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

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

            _commonConfig = commonConfig;
            _config = config;

            if (_config.UpdateSilenceWord && _config.UpdateFixedSilenceDuration)
            {
                throw new InvalidDataException("Cannot implement updating script silence word and fixed silence duration together.");
            }

            if (!_config.UpdateSilenceWord && _config.UpdateScriptSilenceDuration)
            {
                throw new InvalidDataException("Cannot update script silence duration without update silence word.");
            }

            _serviceProvider = serviceProvider;
            if (_config.UpdateSilenceWord || _config.UpdateFixedSilenceDuration)
            {
                UpdateSilenceDurationsConfig();
            }

            _logger = logger;

            _serviceProvider.Engine.LinguisticProsodyTagger.Processing += new EventHandler<TtsModuleEventArgs>(OnLinguisticProcessing);
            _serviceProvider.Engine.LinguisticProsodyTagger.Processed += new EventHandler<TtsModuleEventArgs>(OnLinguisticProcessed);

            _serviceProvider.Engine.Processed += new EventHandler<TtsModuleEventArgs>(OnProcessed);
            _serviceProvider.Engine.AcousticProsodyTagger.Processed += new EventHandler<TtsModuleEventArgs>(OnAcousticProcessed);

            if (_commonConfig != null)
            {
                Helper.EnsureFolderExist(_commonConfig.OutputWaveDir);
            }
        }
        /// <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>
        /// Initializes a new instance of the MixedVoiceSynthesizer class.
        /// </summary>
        /// <param name="donator">Service provider the donator.</param>
        /// <param name="receiver">Service provider the receiver.</param>
        /// <param name="config">Config object.</param>
        public MixedVoiceSynthesizer(ServiceProvider donator, ServiceProvider receiver,
            MixedVoiceSynthesizerConfig config)
        {
            if (donator == null)
            {
                throw new ArgumentNullException("donator");
            }

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

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

            _donator = donator;
            _receiver = receiver;

            _config = config;

            _donator.Engine.AcousticProsodyTagger.Processed +=
                new EventHandler<TtsModuleEventArgs>(OnDonatorAcousticProcessed);

            _receiver.Engine.AcousticProsodyTagger.Processed +=
                new EventHandler<TtsModuleEventArgs>(OnReceiverAcousticProcessed);

            if (!string.IsNullOrEmpty(config.LogFile))
            {
                _logger = new TextLogger(config.LogFile);
                _logger.Reset();
            }
        }