TreeNode(TreeNode parent_, int choiceIndex_) { parent = parent_; choiceIndex = choiceIndex_; Choice choice = s_ChoiceSequence[Index][choiceIndex]; fingerChord = choice.chord; staticCost = choice.staticCost; wrists = choice.wrists; note = s_NoteSeq[Index]; startTime = note.start; timeUnit = choice.deltaTime / s_BenchmarkDuration; leftFingers = generateFingerStates(parent.leftFingers, -1, fingerChord, note, Index); rightFingers = generateFingerStates(parent.rightFingers, 1, fingerChord, note, Index); }
Choice evaluateChordChoice(FingerChord chord, int index) { float deltaTime = index > 0 ? NoteSeq[index].start - NoteSeq[index - 1].start : 0; NoteChord note = NoteSeq[index]; HandConfig.RangePair wrists = Config.getFingerChordWristRange(chord); double cost = 0; // wrist position naturality reward if (wrists.left != null) { float distance = Math.Abs(wrists.left.middle - -HandConfig.WristNaturePosition); cost = Math.Pow(distance / 14, 4) * CostCoeff.WRIST_POSITION_NATURALITY_REWARD; } if (wrists.right != null) { float distance = Math.Abs(wrists.right.middle - HandConfig.WristNaturePosition); cost = Math.Pow(distance / 14, 4) * CostCoeff.WRIST_POSITION_NATURALITY_REWARD; } // wrist crowd punish if (wrists.left != null && wrists.right != null) { float distance = Math.Max(Math.Abs(wrists.left.high - wrists.right.low), Math.Abs(wrists.right.high - wrists.left.low)); if (distance < 5) { cost += CostCoeff.WRIST_CROWD_PUNISH * (5f - distance) / 5f; } } foreach (Finger f in chord.Values) { // shift fingers punish if (Math.Abs((int)f) > 10) { cost += CostCoeff.SHIFT_FINGERS_PUNISH; } } int leftFingerCount = 0; int rightFingerCount = 0; foreach (var pair in chord) { if (pair.Value != Finger.EMPTY) { // black key short punish if (Piano.isBlackKey(pair.Key)) { int finger = Math.Abs((int)pair.Value); int first = (int)Math.Floor(finger / 10f) - 1; int second = finger % 10 - 1; float sh = HandConfig.BlackKeyShort[second]; if (first >= 0) { sh = Math.Max(HandConfig.BlackKeyShort[first], sh); } cost += sh * CostCoeff.BLACK_KEY_SHORT_PUNISH; } if (pair.Value > Finger.EMPTY) { ++rightFingerCount; } else if (pair.Value < Finger.EMPTY) { ++leftFingerCount; } } else { // omit key punish float importance = NotationUtils.getNoteImportanceInChord(note, pair.Key); cost += CostCoeff.OMIT_KEY_PUNISH * importance; } } // multiple fingers punish if (leftFingerCount > 0) { float value = leftFingerCount / 5f; cost += CostCoeff.MULTIPLE_FINGERS_PUNISH * value * value; } if (rightFingerCount > 0) { float value = rightFingerCount / 5f; cost += CostCoeff.MULTIPLE_FINGERS_PUNISH * value * value; } return(new Choice { chord = chord, staticCost = cost, wrists = wrists, deltaTime = deltaTime, node = new TreeNodeChoice() }); }