Ejemplo n.º 1
0
        private static Func <PitchHmmEmission, double> NoteProbability(UtauNote note)
        {
            if (note == null)
            {
                throw new ArgumentNullException(nameof(note));
            }
            if (note.IsRestNote)
            {
                throw new ArgumentException();
            }

            // 正規分布
            const double stdDev = 0.6;
            var          mean   = note.NoteNumber % 12;

            return(e =>
            {
                if (e.IsSilent)
                {
                    return double.NegativeInfinity;
                }

                var p = Math.Max(
                    Math.Max(
                        NormalDistribution(mean, stdDev, e.NormalizedPitch),
                        NormalDistribution(mean - 12, stdDev, e.NormalizedPitch)
                        ),
                    NormalDistribution(mean + 12, stdDev, e.NormalizedPitch)
                    );
                return Math.Log(p);
            });
        }
Ejemplo n.º 2
0
        /// <summary>
        /// <paramref name="restNote"/> を通過するときに無音状態になる確率
        /// </summary>
        private static double ProbabilityOfNoSoundWhenRestNote(UtauNote restNote)
        {
            if (!restNote.IsRestNote)
            {
                throw new ArgumentException();
            }

            // 長さ 720 程度で 0.65 に到達するくらいの確率
            const int    maxLength      = 720;
            const double minProbability = 0.3;
            const double maxProbability = 0.65;

            return(Math.Min(
                       minProbability + ((maxProbability - minProbability) / maxLength) * restNote.Length,
                       maxProbability
                       ));
        }
Ejemplo n.º 3
0
        /// <summary>
        /// <paramref name="prevNote"/> のあとに無音状態になる確率
        /// </summary>
        private static double ProbabilityOfNoSoundAfter(UtauNote prevNote)
        {
            // ノートが長いほど、そのあとは休みがち
            const int    minLength      = 480;
            const double minProbability = 0.05;
            const double maxProbability = 0.2;

            // 短いときはほとんど休まない
            if (prevNote.Length <= minLength)
            {
                return(minProbability);
            }

            // 長いほど確率が上がり、全音符なら 0.2
            return(Math.Min(
                       minProbability + (prevNote.Length - minLength) * ((maxProbability - minProbability) / (1920 - minLength)),
                       maxProbability
                       ));
        }
Ejemplo n.º 4
0
 public static PitchHmmState CreateNoSoundState(UtauNote reportingNote)
 {
     return(new PitchHmmState(reportingNote, true));
 }
Ejemplo n.º 5
0
 public static PitchHmmState CreateEmittingSoundState(UtauNote reportingNote)
 {
     return(new PitchHmmState(reportingNote, false));
 }
Ejemplo n.º 6
0
 protected PitchHmmState(UtauNote reportingNote, bool isSilentState)
 {
     this.ReportingNote = reportingNote;
     this.IsSilentState = isSilentState;
 }
Ejemplo n.º 7
0
        public void InputObservation(PitchHmmEmission observation)
        {
            var states = this._model.States;

            var maxLogProbabilities = new double[states.Count];

            for (var i = 0; i < maxLogProbabilities.Length; i++)
            {
                maxLogProbabilities[i] = double.NegativeInfinity;
            }

            // 初期状態確率 * 遷移確率 * 生成確率 を計算する
            foreach (var(fromStateIndex, stateLogProbability) in this._stateLogProbabilities)
            {
                foreach (var(toStateIndex, transitionLogProbability) in states[fromStateIndex].LogProbabilitiesByOutgoingStateIndexes)
                {
                    var lp = stateLogProbability + transitionLogProbability + states[toStateIndex].EmissionLogProbability(observation);

                    if (!(lp <= 0.0))
                    {
                        throw new Exception("確率が不正な値になりました。");               // NaN チェックも含めるため not <=
                    }
                    if (lp > maxLogProbabilities[toStateIndex])
                    {
                        maxLogProbabilities[toStateIndex] = lp;
                    }
                }
            }

            var stateLogProbabilities = this._stateLogProbabilities;

            stateLogProbabilities.Clear();

            var logSum  = double.NegativeInfinity;
            var maxP    = double.NegativeInfinity; // 最大の確率
            var argmaxP = 0;                       // 最大の確率のときの状態

            for (var stateIndex = 0; stateIndex < maxLogProbabilities.Length; stateIndex++)
            {
                var lp = maxLogProbabilities[stateIndex];
                if (double.IsNegativeInfinity(lp))
                {
                    continue;
                }

                logSum = Special.LogSum(logSum, lp);
                stateLogProbabilities.Add(new KeyValuePair <int, double>(stateIndex, lp));

                if (lp > maxP)
                {
                    maxP    = lp;
                    argmaxP = stateIndex;
                }
            }

            if (stateLogProbabilities.Count == 0)
            {
                throw new Exception("すべての状態の確率が 0 になりました。");
            }

            // 確率が最も高い状態を現在のノートとして認識
            this.CurrentNote = states[argmaxP].Value.ReportingNote;

            // 次の計算のために確率を均しておく
            // 新しい確率 = 確率 / 確率の合計
            for (var i = 0; i < stateLogProbabilities.Count; i++)
            {
                var(stateIndex, lp)      = stateLogProbabilities[i];
                stateLogProbabilities[i] = new KeyValuePair <int, double>(stateIndex, lp - logSum);
            }
        }