/// <summary> /// Start the pruning. /// </summary> /// <param name="fontPath">Voice font path, like .\1033 .</param> /// <param name="configFile">Config file which will tell how many sentence will be include in each sub wve.</param> /// <param name="bFillData">Whether fill data if the sub WVE can't be exact division.</param> /// <param name="outputFolder">Target directory.</param> /// <returns>New WVE File path List.</returns> public static List<string> InventorySplit(string fontPath, string configFile, bool bFillData, string outputFolder) { string unitfile = fontPath + ".unt"; string wihFile = fontPath + ".wih"; string wveFile = fontPath + ".wve"; string outputUnit = Path.Combine(outputFolder, Path.GetFileNameWithoutExtension(unitfile) + ".Splited.unt"); PrintLog("Start to update split the WVE file...", true); // spliet the file. List<string> newWVEFileList = new List<string>(); // Load the WIH file. WaveInfoHeader header = new WaveInfoHeader(); header.Load(wihFile); const uint CompressFrameSize = 640; Dictionary<string, uint> untFrameUpdateList = new Dictionary<string, uint>(); Dictionary<string, uint> acdFrameUpdateList = new Dictionary<string, uint>(); uint curFillFrameCount = 0; Dictionary<string, int> namedUnitTypeId = new Dictionary<string, int>(); Dictionary<int, WaveCandidateInfo> updatedCandidates = new Dictionary<int, WaveCandidateInfo>(); using (UnitIndexingFile indexFile = new UnitIndexingFile(namedUnitTypeId)) { indexFile.Load(unitfile); uint bytesPerFrame = indexFile.SamplePerFrame * header.BytesPerSample; uint compressFrameCount = CompressFrameSize / bytesPerFrame; // Get all sentence id information from the index file canidate, and save them in a sorted dictionary. // Because the sentece is sorted by a sorted dictionary in Font traing process. List<string> sentencIDs = indexFile.WaveCandidates.SelectMany(c => c.Value.Select(k => k.Value.SentenceId).Distinct()).Distinct().ToList(); Dictionary<string, int> dic = sentencIDs.Select((v, i) => new { Value = v, Index = i }).ToDictionary(p => p.Value, p => p.Index); SortedDictionary<string, int> sortedSentenceDic = new SortedDictionary<string, int>(dic); List<string> orderedSentenceIDs = sortedSentenceDic.Select(e => e.Key).ToList(); // Get the confing data. List<uint> sentencCountList = ReadConfigFile(configFile, (uint)orderedSentenceIDs.Count); using (FileStream readerStream = File.Open(wveFile, FileMode.Open)) { BinaryReader reader = new BinaryReader(readerStream); // load header VoiceFontHeader fontHeader = new VoiceFontHeader(); fontHeader.Load(reader); PrintLog("[Totoal Frame in each new VWF file.]", true); // the data offset from the header long dataOffSet = reader.BaseStream.Position; uint outputFileSuffix = 0; uint readFrameNumber = 0; int curSplitSegmentIndex = 0; for (int index = 0; index <= orderedSentenceIDs.Count; index++) { if (index < sentencCountList[curSplitSegmentIndex]) { untFrameUpdateList.Add(orderedSentenceIDs[index], curFillFrameCount); continue; } curSplitSegmentIndex++; string newWVEFileName = Path.Combine(outputFolder, Path.GetFileNameWithoutExtension(wveFile) + "_" + outputFileSuffix.ToString() + ".wve"); PrintLog(string.Format("{0} Frame Update Count: {1}", Path.GetFileName(newWVEFileName), curFillFrameCount), true); using (FileStream wveFileStream = File.Open(newWVEFileName, FileMode.Create)) { BinaryWriter wveWriter = new BinaryWriter(wveFileStream); fontHeader.Save(wveWriter); long writerOffSet = wveWriter.BaseStream.Position; // calculate lenth long length = 0; uint frameCount = 0; if (index == orderedSentenceIDs.Count) { length = reader.BaseStream.Length - reader.BaseStream.Position; frameCount = (uint)(length / bytesPerFrame); } else { // Get all candidate which are got from the specfied sentenc and sorted by frame index. string endSentenceID = orderedSentenceIDs[index]; List<WaveCandidateInfo> endSenteceWaveInfo = indexFile.WaveCandidates.SelectMany(c => c.Value.Where(p => p.Value.SentenceId == endSentenceID)) .Select(i => i.Value).SortBy(k => k.FrameIndexInSentence).ToList(); // Get the end candiate in the specifid sentence. WaveCandidateInfo firstWaveCandidate = endSenteceWaveInfo[0]; frameCount = firstWaveCandidate.FrameIndex - firstWaveCandidate.FrameIndexInSentence - readFrameNumber; length = bytesPerFrame * frameCount; readFrameNumber = firstWaveCandidate.FrameIndex - firstWaveCandidate.FrameIndexInSentence; } // we need calculate how many bit will be filled into the WVE when it will be commpressed. // 640 bit will be used in the compress tool, so we will reference this. uint byteGap = (uint)((CompressFrameSize - (length % CompressFrameSize)) % CompressFrameSize); uint updateFrameCount = (byteGap / bytesPerFrame) % compressFrameCount; curFillFrameCount += updateFrameCount; reader.BaseStream.Seek(dataOffSet, SeekOrigin.Begin); byte[] data = reader.ReadBytes((int)length); wveWriter.Write(data); // fill data if the length can't be exact division. if (bFillData) { FillSilenceData(wveWriter, byteGap); } // save the header file fontHeader.DataSize = (ulong)(wveWriter.BaseStream.Position - writerOffSet); SaveFontHeader(fontHeader, wveWriter); dataOffSet = reader.BaseStream.Position; PrintLog(string.Format("{0} Total Frame Count: {1} + {2}", Path.GetFileName(newWVEFileName), frameCount, updateFrameCount.ToString()), true); PrintLog(string.Empty, true); // recode the new file path. newWVEFileList.Add(newWVEFileName); if (index != orderedSentenceIDs.Count) { acdFrameUpdateList.Add(orderedSentenceIDs[index], curFillFrameCount); } } header.Save(Path.ChangeExtension(newWVEFileName, "wih")); outputFileSuffix++; if (index != orderedSentenceIDs.Count) { index--; } } } // update ACD file. PrintLog("Update ACD file!", true); UpdateACDFile(indexFile, acdFrameUpdateList, fontPath + ".acd", Path.ChangeExtension(outputUnit, "acd")); // update index file PrintLog("Update UNT file!", true); UpdateIndexingFile(indexFile, untFrameUpdateList); indexFile.Save(outputUnit); } PrintLog("Split successfully!", true); return newWVEFileList; }
/// <summary> /// Compares two UNT files by ignoring builder number. /// </summary> /// <param name="left">The left file name of UNT file.</param> /// <param name="right">The right file name of UNT file.</param> /// <returns>True if the two UNT file is equal, otherwise false.</returns> public static bool Compare(string left, string right) { using (UnitIndexingFile leftFile = new UnitIndexingFile(null)) { leftFile.Load(left); using (UnitIndexingFile rightFile = new UnitIndexingFile(null)) { rightFile.Load(right); leftFile.BuildNumber = rightFile.BuildNumber; string tempFile = left + Path.GetRandomFileName(); try { leftFile.Save(tempFile); return Helper.CompareBinary(tempFile, right); } finally { Helper.SafeDelete(tempFile); } } } }