Beispiel #1
0
        public static string getFingerChordJsonDump(FingerChord fc)
        {
            string list = "";

            foreach (Finger f in fc.Values)
            {
                list += (list.Length > 0 ? "," : "") + ((int)f).ToString();
            }

            return("\"" + list + "\"");
        }
        void tryFingerChoice(int[] pitches, ref List <FingerChord> choices, FingerChord constrait, FingerChord fc, int currentNoteIndex, int emptyQuota)
        {
            if (currentNoteIndex >= pitches.Length)
            {
                choices.Add(new FingerChord(fc));

                /*Finger[] fa = new Finger[fc.Values.Count];
                 * fc.Values.CopyTo(fa, 0);
                 * UnityEngine.Debug.Log("fc: " + String.Join(",", Array.ConvertAll(fa, x => ((int)x).ToString())));*/
            }
            else
            {
                int currentPitch = pitches[currentNoteIndex];

                if (constrait != null && constrait.ContainsKey(currentPitch) && constrait[currentPitch] != Finger.EMPTY)
                {
                    fc[currentPitch] = constrait[currentPitch];
                    tryFingerChoice(pitches, ref choices, constrait, fc, currentNoteIndex + 1, emptyQuota);
                }
                else
                {
                    foreach (Finger f in FingerConstants.SolveTypeFingers[HandType])
                    {
                        bool pass = true;
                        for (int index = currentNoteIndex - 1; index >= 0; --index)
                        {
                            int    pitch  = pitches[index];
                            Finger finger = fc[pitch];

                            float distance = Piano.pitchPairDistance(pitch, currentPitch);

                            pass = FingerConstants.testFingerDistance(finger, f, Config, distance);
                            if (!pass)
                            {
                                break;
                            }
                        }

                        if (pass)
                        {
                            fc[currentPitch] = f;
                            tryFingerChoice(pitches, ref choices, constrait, fc, currentNoteIndex + 1, emptyQuota);
                        }
                    }

                    if (emptyQuota > 0)
                    {
                        fc[currentPitch] = Finger.EMPTY;
                        tryFingerChoice(pitches, ref choices, constrait, fc, currentNoteIndex + 1, emptyQuota - 1);
                    }
                }
            }
        }
        FingerMap getTreeNodeFingerMap(TreeNode node)
        {
            FingerMap map = node.parent != null?getTreeNodeFingerMap(node.parent) : new FingerMap();

            if (node.Choice >= 0)
            {
                FingerChord fc = ChoiceSequence[node.Index][node.Choice].chord;
                NoteChord   nc = NoteSeq[node.Index];
                map[nc.tick] = fc;
            }

            return(map);
        }
            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[] getFingerChoices(NoteChord nc, int index)
        {
            if (nc.notes.Count == 0)
            {
                return(new Choice[0]);
            }

            List <FingerChord> choices = new List <FingerChord>();

            int[] pitches = new int[nc.notes.Count];
            nc.notes.Keys.CopyTo(pitches, 0);

            FingerChord constrait = null;

            if (KeepConstraints)
            {
                constrait = new FingerChord();
                foreach (var pair in nc.notes)
                {
                    if (pair.Value.finger != Finger.EMPTY)
                    {
                        constrait[pair.Key] = pair.Value.finger;
                        UnityEngine.Debug.Log("pair.Value.finger: " + pair.Value.finger.ToString());
                    }
                }
            }

            int fingerCount = HandType == SolveHandType.MIX ? 10 : 5;

            int         emptyQuota = Math.Max(pitches.Length - fingerCount, 0);
            FingerChord fc         = new FingerChord();

            while (choices.Count == 0)
            {
                tryFingerChoice(pitches, ref choices, constrait, fc, 0, emptyQuota++);
            }

            Choice[] choiceArray = new Choice[choices.Count];
            for (int i = 0; i < choices.Count; ++i)
            {
                FingerChord chord = choices[i];
                choiceArray[i] = evaluateChordChoice(chord, index);
            }

            return(choiceArray);
        }
Beispiel #6
0
        public RangePair getFingerChordWristRange(FingerChord fc)
        {
            RangePair rp = new RangePair();

            foreach (var pair in fc)
            {
                if (pair.Value != Finger.EMPTY)
                {
                    float keyPosition = Piano.KeyPositions[pair.Key];
                    Range range       = getFingerRange(pair.Value);
                    range = new Range {
                        low = keyPosition + range.low, high = keyPosition + range.high
                    };

                    if (pair.Value > Finger.EMPTY)
                    {
                        if (rp.right == null)
                        {
                            rp.right = range;
                        }
                        else
                        {
                            rp.right.low  = Math.Max(rp.right.low, keyPosition + range.low);
                            rp.right.high = Math.Min(rp.right.high, keyPosition + range.high);
                        }
                    }
                    else
                    {
                        if (rp.left == null)
                        {
                            rp.left = range;
                        }
                        else
                        {
                            rp.left.low  = Math.Max(rp.left.low, keyPosition + range.low);
                            rp.left.high = Math.Min(rp.left.high, keyPosition + range.high);
                        }
                    }
                }
            }

            return(rp);
        }
        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()
            });
        }
            static FingerState[] generateFingerStates(FingerState[] parentStates, int hand, FingerChord chord, NoteChord nc, int index)
            {
                FingerState[] states = null;

                if (parentStates != null)
                {
                    states = new FingerState[parentStates.Length];
                    Array.Copy(parentStates, states, states.Length);
                }

                foreach (var pair in chord)
                {
                    int finger = (int)pair.Value * hand;
                    if (finger > 0)
                    {
                        if (states == null)
                        {
                            states = Enumerable.Repeat(new FingerState {
                                Press = -10000f, Release = -10000f, Index = -1, Height = 0
                            }, 5).ToArray();
                            for (int i = 0; i < states.Length; ++i)
                            {
                                states[i].Position = (HandConfig.WristNaturePosition + i - 2) * hand;
                            }
                        }

                        Note note = nc.notes[pair.Key];
                        UnityEngine.Debug.Assert(note != null, "note and finger chord mismatch");

                        float position = Piano.KeyPositions[pair.Key];
                        int   height   = Piano.getKeyHeight(pair.Key);

                        int first  = (int)Math.Floor(finger / 10f) - 1;
                        int second = finger % 10 - 1;

                        if (first >= 0)
                        {
                            states[first].Press    = note.start;
                            states[first].Release  = note.start;
                            states[first].Pitch    = pair.Key;
                            states[first].Position = position;
                            states[first].Height   = height;
                            states[first].Index    = index;
                        }

                        UnityEngine.Debug.Assert(second >= 0 && second < 5, "invalid finger value");
                        {
                            states[second].Press    = note.start;
                            states[second].Release  = note.start + note.duration;
                            states[second].Pitch    = pair.Key;
                            states[second].Position = position;
                            states[second].Height   = height;
                            states[second].Index    = index;

                            //fixFingerStatesObstacle(ref states, hand, second);
                        }
                    }
                }

                return(states);
            }