/// <summary> /// 歌唱をやめてスタートに戻る確率 /// </summary> public static IEnumerable <ProbabilityGenerationResult> StopSinging(ProbabilityGenerationContext context) { if (context.TargetNoteNode?.Next == null) { yield break; // 最後のノートからスタートへの移動は後で } yield return(ProbabilityGenerationResult.CreateToStartState(0.05, false)); }
/// <summary> /// 自己ループの確率(音程変化の判定が過剰に反応してしまった場合) /// </summary> public static IEnumerable <ProbabilityGenerationResult> SelfLoop(ProbabilityGenerationContext context) { if (context.TargetNoteNode == null) { // スタート状態 yield return(ProbabilityGenerationResult.CreateToStartState(0.8, false)); } else { yield return(new ProbabilityGenerationResult(context.TargetNoteNode.Value.Index, 0.33, false)); } }
/// <summary> /// 先のノートに移動する確率 /// </summary> public static IEnumerable <ProbabilityGenerationResult> MoveToForwardNotes(ProbabilityGenerationContext context) { var next = context.TargetNoteNode == null ? context.Notes.First : context.TargetNoteNode.Next; if (next == null) { yield break; } // 2分音符の長さまでの範囲のノートに移動する const int maxSkipLength = 960; var targetNote = context.TargetNoteNode?.Value; var maxSkipPosition = targetNote != null ? targetNote.Position + targetNote.Length + maxSkipLength : next.Value.Position + maxSkipLength; // スタート状態からの場合は最初のノートの開始位置から var sentinel = next.Next; while (sentinel != null && sentinel.Value.Position < maxSkipPosition) { sentinel = sentinel.Next; } var totalLength = 0.0; var node = next; while (node != sentinel) { if (!node.Value.IsRestNote) { totalLength += VirtualLength(node); } node = node.Next; } node = next; while (node != sentinel) { var n = node.Value; if (!n.IsRestNote) { var p = context.RemainingProbability * VirtualLength(node) / totalLength; if (context.TargetNoteNode == null) { // スタート状態からの遷移なら、無音状態を経由することはない yield return(new ProbabilityGenerationResult(n.Index, p, false)); } else { var viaNoSoundProbability = node.Previous?.Value is UtauNote prevNote && prevNote.IsRestNote ? ProbabilityOfNoSoundWhenRestNote(prevNote) : ProbabilityOfNoSoundAfter(n); yield return(new ProbabilityGenerationResult(n.Index, (1.0 - viaNoSoundProbability) * p, false)); yield return(new ProbabilityGenerationResult(n.Index, viaNoSoundProbability * p, true)); } } node = node.Next; } double VirtualLength(LinkedListNode <UtauNote> noteNode) { double l = Math.Min(noteNode.Value.Position + noteNode.Value.Length, maxSkipPosition) - noteNode.Value.Position; // 前のノートと同じ高さなら、認識しにくいので、本来よりも短いものとして認識する if (noteNode.Previous?.Value.NoteNumber == noteNode.Value.NoteNumber) { l *= 0.8; } // next から離れているほど確率を下げる var n = next; while (n != noteNode) { l *= 0.5; n = n.Next; } return(l); } }
/// <summary> /// 1 小節前の最初に戻る確率 /// </summary> public static IEnumerable <ProbabilityGenerationResult> MoveToFirstNoteInPreviousMeasure(ProbabilityGenerationContext context) { if (context.TargetNoteNode?.Next == null) { yield break; // スタート状態または最後のノートならいらない } var note = context.TargetNoteNode.Value; var measureStartPosition = note.Position - note.Position % 1920; var previousMeasureStartPosition = measureStartPosition - 1920; var n = context.TargetNoteNode; var firstStateInPreviousMeasure = n; while ((n = n.Previous)?.Value.Position >= measureStartPosition) { if (!n.Value.IsRestNote) { firstStateInPreviousMeasure = n; } } if (firstStateInPreviousMeasure.Value.Position < measureStartPosition) { yield return(new ProbabilityGenerationResult(firstStateInPreviousMeasure.Value.Index, 0.05, true)); } }
public static IEnumerable <ProbabilityGenerationResult> MoveToStartFromLastNote(ProbabilityGenerationContext context) { if (context.TargetNoteNode == null || context.TargetNoteNode.Next != null) { yield break; } yield return(ProbabilityGenerationResult.CreateToStartState(context.RemainingProbability, false)); }