/// <summary>
 /// Write out string pool with encrypt.
 /// </summary>
 /// <param name="stringPool">String pool.</param>
 /// <param name="writer">Binary data writer.</param>
 /// <returns>Size of bytes written out.</returns>
 public static uint Write(StringPool stringPool, DataWriter writer)
 {
     Helper.ThrowIfNull(stringPool);
     Helper.ThrowIfNull(writer);
     byte[] encryptedStringPool = new byte[stringPool.Length];
     Microsoft.Tts.ServiceProvider.HTSVoiceDataEncrypt.EncryptStringPool(
         stringPool.ToArray(), encryptedStringPool);
     return writer.Write(encryptedStringPool);
 }
        /// <summary>
        /// Write preselection node data.
        /// </summary>
        /// <param name="writer">The writer object.</param>
        /// <returns>Bytes written.</returns>
        public int Write(DataWriter writer)
        {
            int size = 0;
            size += (int)writer.Write(_candidateGroup.Id);

            var candidateIds = _candidateGroup.Candidates.Select(c => c.Id);

            Debug.Assert(
                !candidateIds.Any(x => x < 0),
                "Unsupported negative candiate Id.");

            bool[] values = new bool[candidateIds.Max() + 1];

            foreach (var id in candidateIds)
            {
                values[id] = true;
            }

            BitArray bitArray = new BitArray(values);

            size += SetUtil.Write(SetType.IndexSet, bitArray, writer);

            return size;
        }
Exemple #3
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>
        /// Writes font models out into binary stream.
        /// </summary>
        /// <param name="font">NN font to write.</param>
        /// <param name="writer">Binary data writer.</param>
        /// <returns>Size of bytes written out.</returns>
        private uint WriteModels(NNFont font, DataWriter writer)
        {
            Helper.ThrowIfNull(font);
            Helper.ThrowIfNull(writer);

            uint size = 0;

            // write positions.
            size += writer.Write(font.Models.Count);
            foreach (HmmModelType type in font.Models.Keys)
            {
                size += writer.Write((int)type);
                size += font.Models[type].Position.Save(writer);
            }

            // write windows.
            size += writer.Write(font.Models.Count - 1);
            foreach (HmmModelType type in font.Models.Keys)
            {
                if (type != HmmModelType.VoicedUnvoiced)
                {
                    size += writer.Write((int)type);
                    size += font.Models[type].WindowSet.Save(writer);
                }
            }

            return size;
        }
        /// <summary>
        /// Write out locations.
        /// </summary>
        /// <param name="locations">Locations to write.</param>
        /// <param name="writer">Binary data writer.</param>
        /// <returns>Size of bytes written.</returns>
        private static uint Write(Location[] locations, DataWriter writer)
        {
            Helper.ThrowIfNull(locations);
            Helper.ThrowIfNull(writer);

            uint size = writer.Write(locations.Length);

            for (int i = 0; i < locations.Length; i++)
            {
                size += writer.Write(locations[i].Offset);
                size += writer.Write(locations[i].Length);
            }

            return size;
        }
        /// <summary>
        /// Save acoustic feakture variacne.
        /// </summary>
        /// <param name="outVarFile">Acoustic variance file.</param>
        /// <param name="writer">Binary data writer.</param>
        /// <returns>Size of bytes written out.</returns>
        public uint WriteOutVariance(string outVarFile, DataWriter writer)
        {
            Helper.ThrowIfFileNotExist(outVarFile);
            Helper.ThrowIfNull(writer);

            uint size = 0;

            IEnumerable<string> allLines = Helper.AllFileLines(outVarFile);

            size += writer.Write((uint)allLines.Count());
            foreach (string line in allLines)
            {
                size += writer.Write(float.Parse(line));
            }

            Debug.Assert(size % sizeof(uint) == 0, "Data must be 4-byte aligned.");

            return size;
        }
        /// <summary>
        /// Save schema (with feature set and it's value group, mean, variance).
        /// </summary>
        /// <param name="language">The language.</param>
        /// <param name="schemaFile">The schema File.</param>
        /// <param name="phoneToIdIndexes">Phone To Id Indexes.</param>
        /// <param name="writer">Writer.</param>
        /// <param name="stringPool">String pool.</param>
        /// <returns>Size of bytes written out.</returns>
        public uint WriteSchema(Language language, string schemaFile, Dictionary<string, string> phoneToIdIndexes, DataWriter writer, StringPool stringPool)
        {
            Helper.ThrowIfFileNotExist(schemaFile);
            Helper.ThrowIfNull(phoneToIdIndexes);
            Helper.ThrowIfNull(writer);
            Helper.ThrowIfNull(stringPool);
            Helper.ThrowIfNull(language);

            uint size = 0;

            LexicalAttributeSchema schema = new LexicalAttributeSchema(language);
            schema.Load(schemaFile);

            List<string> stateFeatureList = new List<string>();
            List<string> featureList = new List<string>();

            int stateFeatureCount = 0;

            for (int i = 0; i < schema.Categories.Count; i++)
            {
                string name = schema.Categories[i].Name.ToLower();

                if (name.IndexOf("state") >= 0)
                {
                    stateFeatureCount++;

                    if (!stateFeatureList.Contains(name))
                    {
                        stateFeatureList.Add(name);
                    }
                }

                if (!featureList.Contains(name))
                {
                    featureList.Add(name);
                }
            }

            // write state feature count.
            size += writer.Write((uint)stateFeatureList.Count);
            size += writer.Write((uint)stateFeatureCount);

            // write total feature count.
            size += writer.Write((uint)featureList.Count());

            Dictionary<string, uint> featureIndex = new Dictionary<string, uint>();

            uint index = 0;
            foreach (string feature in featureList)
            {
                size += writer.Write((uint)stringPool.Length);

                stringPool.PutString(feature);
                featureIndex.Add(feature, index++);
            }

            // write feature category
            size += writer.Write((uint)schema.Categories.Count);
            for (int i = 0; i < schema.Categories.Count; i++)
            {
                string featureName = schema.Categories[i].Name.ToLower();

                // feature index
                size += writer.Write((uint)featureIndex[featureName]);

                // mean
                size += writer.Write(schema.Categories[i].Mean);

                // invStdDev
                size += writer.Write(schema.Categories[i].InvStdDev);

                // value count
                size += writer.Write((uint)schema.Categories[i].Values.Count);
                for (int k = 0; k < schema.Categories[i].Values.Count; k++)
                {
                    string valueName = schema.Categories[i].Values[k].Name.ToLower();
                    string id = string.Empty;

                    if (phoneToIdIndexes.ContainsKey(valueName) && featureName.IndexOf("phoneidentity") >= 0)
                    {
                        id = phoneToIdIndexes[valueName];
                    }
                    else
                    {
                        id = valueName;
                    }

                    try
                    {
                        size += writer.Write(uint.Parse(id));
                    }
                    catch (System.FormatException)
                    {
                        continue;
                    }
                }
            }

            Debug.Assert(size % sizeof(uint) == 0, "Data must be 4-byte aligned.");

            return size;
        }
        /// <summary>
        /// Write out one linear transform to be 4-byte aligned.
        /// </summary>
        /// <param name="writer">Binary writer.</param>
        /// <param name="linXform">Linear transform to write out.</param>
        /// <param name="streamOrder">Dynamic order of the stream of current linear transform.</param>
        /// <param name="hasBias">Indicate transform whether has bias info.</param>
        /// <param name="bandWidth">Band width of linear transform matrix.</param>
        /// <returns>Number of bytes written out.</returns>
        protected uint WriteFourBytesAlignedLinXform(DataWriter writer, LinXForm linXform, DynamicOrder streamOrder, bool hasBias, uint bandWidth = 0)
        {
            Helper.ThrowIfNull(writer);
            Helper.ThrowIfNull(linXform);
            uint size = Write(writer, linXform, streamOrder, hasBias, bandWidth);

            if (size == 0)
            {
                throw new InvalidDataException(Helper.NeutralFormat("Zero length of linXform is not allowed."));
            }

            // Pad zero bytes if needed to align with 4-bytes
            if (size % sizeof(uint) > 0)
            {
                size += writer.Write(new byte[sizeof(uint) - (size % sizeof(uint))]);
            }

            Debug.Assert(size % sizeof(uint) == 0, "Data should be 4-byte aligned.");
            return size;
        }
        /// <summary>
        /// Write out Gaussian.
        /// </summary>
        /// <param name="writer">Binary writer.</param>
        /// <param name="gaussian">Gaussian.</param>
        /// <param name="streamOrder">The dynamic order of stream, to which the Gaussian belongs.</param>
        /// <returns>Size of bytes written.</returns>
        protected override uint Write(DataWriter writer, Gaussian gaussian, DynamicOrder streamOrder)
        {
            Helper.ThrowIfNull(writer);
            Helper.ThrowIfNull(gaussian);
            uint size = 0;

            Gaussian quantized = gaussian;
            if (IsNeedQuantize)
            {
                quantized = Quantize(gaussian, streamOrder);
                QuantizedStatistic.Put(quantized, streamOrder);
            }

            if (Config.HasWeight)
            {
                if (quantized.Weight == 0.0f)
                {
                    throw new InvalidDataException(Helper.NeutralFormat("Zero weight of LogF0 is found."));
                }

                size += writer.Write((float)quantized.Weight);
            }

            Debug.Assert(Config.MeanBits == sizeof(short) * 8, "Only 16-bit short value is supported here");
            for (int i = 0; Config.HasMean && i < gaussian.Length; i++)
            {
                size += writer.Write((short)quantized.Mean[i]);
            }

            Debug.Assert(Config.VarianceBits == sizeof(byte) * 8, "Only 8-bit byte value is supported here");
            for (int i = 0; Config.HasVariance && i < gaussian.Length; i++)
            {
                size += writer.Write((byte)quantized.Variance[i]);
            }

            return size;
        }
        /// <summary>
        /// Write out one Gaussian distribution to be 4-byte aligned.
        /// </summary>
        /// <param name="writer">Binary writer.</param>
        /// <param name="gaussian">Gaussian distribution to write out.</param>
        /// <param name="streamOrder">Dynamic order of the stream of current Gaussian distribution.</param>
        /// <returns>Number of bytes written out.</returns>
        protected uint WriteFourBytesAlignedGaussian(DataWriter writer, Gaussian gaussian, DynamicOrder streamOrder)
        {
            Helper.ThrowIfNull(writer);
            Helper.ThrowIfNull(gaussian);
            uint size = Write(writer, gaussian, streamOrder);

            if (size == 0)
            {
                throw new InvalidDataException(Helper.NeutralFormat("Zero length of Gaussian is not allowed."));
            }

            // Pad zero bytes if needed to align with 4-bytes
            if (size % sizeof(uint) > 0)
            {
                size += writer.Write(new byte[sizeof(uint) - (size % sizeof(uint))]);
            }

            Debug.Assert(size % sizeof(uint) == 0, "Data should be 4-byte aligned.");
            return size;
        }
        /// <summary>
        /// Write out Gaussian distribution.
        /// </summary>
        /// <param name="writer">Binary writer.</param>
        /// <param name="gaussian">Gaussian.</param>
        /// <param name="streamOrder">The dynamic order of stream, to which the Gaussian belongs.</param>
        /// <returns>Size of bytes written.</returns>
        protected virtual uint Write(DataWriter writer, Gaussian gaussian, DynamicOrder streamOrder)
        {
            Helper.ThrowIfNull(writer);
            Helper.ThrowIfNull(gaussian);

            uint size = 0;
            if (Config.HasWeight)
            {
                size += writer.Write((float)gaussian.Weight);
            }

            Debug.Assert(Config.MeanBits == sizeof(float) * 8, "Only 32-bit float value is supported here");
            Debug.Assert(Config.VarianceBits == sizeof(float) * 8, "Only 32-bit float value is supported here");

            for (int i = 0; Config.HasMean && i < gaussian.Length; i++)
            {
                Debug.Assert(Config.HasVariance, "Variance is needed to encode mean for runtime.");

                double invVar = CalculateInvertedVariance(gaussian.Variance[i], DefaultVarianceFloor);
                double mean = gaussian.Mean[i] * invVar;
                size += writer.Write((float)mean);
            }

            for (int i = 0; Config.HasVariance && i < gaussian.Length; i++)
            {
                double invVar = CalculateInvertedVariance(gaussian.Variance[i], DefaultVarianceFloor);
                size += writer.Write((float)invVar);
            }

            return size;
        }
        /// <summary>
        /// Write out Gaussian.
        /// </summary>
        /// <param name="writer">Binary writer.</param>
        /// <param name="gaussian">Gaussian.</param>
        /// <param name="streamOrder">The dynamic order of stream, to which the Gaussian belongs.</param>
        /// <returns>Size of bytes written.</returns>
        protected override uint Write(DataWriter writer, Gaussian gaussian, DynamicOrder streamOrder)
        {
            Helper.ThrowIfNull(writer);
            Helper.ThrowIfNull(gaussian);
            uint size = 0;

            Gaussian quantized = gaussian;
            if (IsNeedQuantize)
            {
                quantized = Quantize(gaussian, streamOrder);
                QuantizedStatistic.Put(quantized, streamOrder);
            }

            Debug.Assert(Config.MeanBits == sizeof(short) * 8, "Only 16-bit short value is supported here");
            for (int i = 0; Config.HasMean && i < gaussian.Length; i++)
            {
                size += writer.Write((short)quantized.Mean[i]);
            }

            Debug.Assert(Config.VarianceBits == sizeof(byte) * 8, "Only 8-bit byte value is supported here");
            for (int i = 0; Config.HasVariance && i < gaussian.Length; i++)
            {
                size += writer.Write((byte)quantized.Variance[i]);
            }

            return size;
        }
        /// <summary>
        /// Save pre-selection forest.
        /// </summary>
        /// <param name="decisionForest">The forest with each tree corresponding to a unit.</param>
        /// <param name="candidateGroups">The candidate group collection.</param>
        /// <param name="unitCandidateNameIds">Given candidate idx.</param>
        /// <param name="customFeatures">Cusotmized linguistic feature list.</param>
        /// <param name="outputPath">The output path.</param>
        public void Write(DecisionForest decisionForest,
            ICollection<CandidateGroup> candidateGroups, 
            IDictionary<string, int> unitCandidateNameIds,
            HashSet<string> customFeatures,
            string outputPath)
        {
            foreach (Question question in decisionForest.QuestionList)
            {
                question.Language = _phoneSet.Language;
                question.ValueSetToCodeValueSet(_posSet, _phoneSet, customFeatures);
            }

            FileStream file = new FileStream(outputPath, 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();

                    // Write feature, question and prepare string pool
                    HtsQuestionSet questionSet = new HtsQuestionSet
                    {
                        Items = decisionForest.QuestionList,
                        Header = new HtsQuestionSetHeader { HasQuestionName = false },
                        CustomFeatures = customFeatures,
                    };

                    using (StringPool stringPool = new StringPool())
                    {
                        Dictionary<string, uint> questionIndexes = new Dictionary<string, uint>();

                        header.QuestionOffset = position;
                        header.QuestionSize = serializer.Write(
                            questionSet, writer, stringPool, questionIndexes, customFeatures);
                        position += header.QuestionSize;

                        // Write leaf referenced data to buffer
                        IEnumerable<INodeData> dataNodes = GetCandidateNodes(candidateGroups);
                        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(decisionForest, unitCandidateNameIds,
                                questionIndexes, 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();
                }
            }
        }
Exemple #14
0
        /// <summary>
        /// Write tree indexes.
        /// </summary>
        /// <param name="writer">The writer object.</param>
        /// <param name="treeIndexes">The tree index array.</param>
        /// <returns>Bytes written.</returns>
        private uint WriteTreeIndexes(DataWriter writer, TreeIndex[] treeIndexes)
        {
            uint size = 0;

            // Write tree count
            size += writer.Write((uint)treeIndexes.Length);

            foreach (TreeIndex index in treeIndexes)
            {
                size += writer.Write(index.Id);
                size += writer.Write(index.Offset);
                size += writer.Write(index.Size);
            }

            return size;
        }
        /// <summary>
        /// Write out Gaussian.
        /// </summary>
        /// <param name="writer">Binary writer.</param>
        /// <param name="gaussian">Gaussian.</param>
        /// <param name="streamOrder">The dynamic order of stream, to which the Gaussian belongs.</param>
        /// <returns>Size of bytes written.</returns>
        protected override uint Write(DataWriter writer, Gaussian gaussian, DynamicOrder streamOrder)
        {
            Helper.ThrowIfNull(writer);
            Helper.ThrowIfNull(gaussian);
            uint size = 0;

            Gaussian quantized = gaussian;
            if (IsNeedQuantize)
            {
                quantized = Quantize(gaussian);
                QuantizedStatistic.Put(quantized, streamOrder);
            }

            if (Config.HasWeight)
            {
                size += writer.Write((float)quantized.Weight);
            }

            if (!Config.HasMean || !Config.HasVariance)
            {
                throw new InvalidDataException("Needs both mean and variance.");
            }

            for (int i = 0; i < quantized.Length; i++)
            {
                if ((i + 1) % Config.StaticVectorSize == 0)
                {
                    size += writer.Write((short)quantized.Mean[i]);
                }
                else if (i < Config.StaticVectorSize)
                {
                    size += writer.Write((byte)quantized.Mean[i]);
                }
                else
                {
                    size += writer.Write((sbyte)quantized.Mean[i]);
                }
            }

            for (int i = 0; i < gaussian.Length; i++)
            {
                size += writer.Write((byte)quantized.Variance[i]);
            }

            return size;
        }
Exemple #16
0
        /// <summary>
        /// Writes HTS font header into binary stream.
        /// </summary>
        /// <param name="writer">Binary writer.</param>
        /// <returns>Size of bytes written.</returns>
        public uint Write(DataWriter writer)
        {
            Helper.ThrowIfNull(writer);
            byte[] buff = ToBytes();
            uint size = writer.Write(buff);

#if SERIALIZATION_CHECKING
            ConsistencyChecker.Check(this, Read(writer.BaseStream.Excerpt(size)));
#endif

            return size;
        }
        /// <summary>
        /// Write out linear transform.
        /// </summary>
        /// <param name="writer">Binary writer.</param>
        /// <param name="linXform">Linear transform.</param>
        /// <param name="streamOrder">The dynamic order of stream, to which the linear transform belongs.</param>
        /// <param name="hasBias">Indicate transform whether has bias info.</param>
        /// <param name="bandWidth">Band width of linear transform matrix.</param>
        /// <returns>Size of bytes written.</returns>
        protected virtual uint Write(DataWriter writer, LinXForm linXform, DynamicOrder streamOrder, bool hasBias, uint bandWidth)
        {
            Helper.ThrowIfNull(writer);
            Helper.ThrowIfNull(linXform);

            uint size = 0;

            Debug.Assert(Config.BiasBits == sizeof(float) * 8, "Only 32-bit float value is supported here");
            Debug.Assert(Config.MatrixBits == sizeof(float) * 8, "Only 32-bit float value is supported here");

            for (int i = 0; hasBias && i < linXform.VecSize; i++)
            {
                size += writer.Write(linXform.Bias[i]);
            }

            for (int i = 0; i < linXform.Blocks.Count; i++)
            {
                for (int j = 0; j < linXform.Blocks[i].GetLength(0); j++)
                {
                    for (int k = 0; k < linXform.Blocks[i].GetLength(1); k++)
                    {
                        if (k >= j - bandWidth && k <= j + bandWidth)
                        {
                            size += writer.Write(linXform.Blocks[i][j, k]);
                        }
                    }
                }
            }

            return size;
        }