public void GetRelativePitchDistanceTest() { // The distance must be computed on relative notes, i.e., the pitch must be taken modulo 12. Assert.AreEqual(0, MidiUtils.GetRelativePitchDistance(24, 48)); // Shortest distance via 7 to 8 = 2 Assert.AreEqual(2, MidiUtils.GetRelativePitchDistance(6, 8)); // Shortest distance via 1, 0, 11, 10 = 4 Assert.AreEqual(4, MidiUtils.GetRelativePitchDistance(2, 10)); // No distance Assert.AreEqual(0, MidiUtils.GetRelativePitchDistanceSigned(5, 5)); // Shortest signed distance from F to A -> 4 Assert.AreEqual(4, MidiUtils.GetRelativePitchDistanceSigned(53, 69)); // Shortest signed distance via 11, 0, 1, 2 -> 4 Assert.AreEqual(4, MidiUtils.GetRelativePitchDistanceSigned(10, 2)); // Shortest signed distance via 1, 0, 11, 10 -> -4 Assert.AreEqual(-4, MidiUtils.GetRelativePitchDistanceSigned(2, 10)); // Shortest signed distance via 5, 6, 7, 8 -> 4 Assert.AreEqual(4, MidiUtils.GetRelativePitchDistanceSigned(4, 8)); // Shortest signed distance via 7, 6, 5, 4 -> -4 Assert.AreEqual(-4, MidiUtils.GetRelativePitchDistanceSigned(8, 4)); // Shortest signed distance via 0 -> 1 Assert.AreEqual(1, MidiUtils.GetRelativePitchDistanceSigned(11, 0)); // Shortest signed distance via 11 -> -1 Assert.AreEqual(-1, MidiUtils.GetRelativePitchDistanceSigned(0, 11)); // Shortest signed distance from F to B -> 6 or -6 Assert.IsTrue(MidiUtils.GetRelativePitchDistanceSigned(77, 59) is - 6 or 6); // Shortest signed distance from A to D -> 5 Assert.AreEqual(5, MidiUtils.GetRelativePitchDistanceSigned(45, 74)); // Shortest signed distance from D to A -> -5 Assert.AreEqual(-5, MidiUtils.GetRelativePitchDistanceSigned(74, 45)); }
private void HandlePitchEvent(PitchEvent pitchEvent, double currentBeat) { if (pitchEvent == null || pitchEvent.MidiNote <= 0) { if (lastRecordedNote != null) { HandleRecordedNoteEnded(currentBeat); } } else { if (lastRecordedNote != null) { if (MidiUtils.GetRelativePitchDistance(lastRecordedNote.RoundedMidiNote, pitchEvent.MidiNote) <= roundingDistance) { // Continue singing on same pitch HandleRecordedNoteContinued(currentBeat); } else { // Continue singing on different pitch. Finish the last recorded note. HandleRecordedNoteEnded(currentBeat); } } // The lastRecordedNote could be ended above, so the following null check is not redundant. if (lastRecordedNote == null && currentBeat >= nextNoteStartBeat) { // Start singing of a new note HandleRecordedNoteStarted(pitchEvent.MidiNote, currentBeat); } } }
private int GetRoundedMidiNote(int recordedMidiNote, int targetMidiNote, int roundingDistance) { int distance = MidiUtils.GetRelativePitchDistance(recordedMidiNote, targetMidiNote); if (distance <= roundingDistance) { return(targetMidiNote); } else { return(recordedMidiNote); } }
public void GetRelativePitchDistanceTest() { // The distance must be computed on relative notes, i.e., the pitch must be taken modulo 12. int distanceSamePitchDifferentOctaves = MidiUtils.GetRelativePitchDistance(24, 48); Assert.AreEqual(0, distanceSamePitchDifferentOctaves); // Shortest distance via 7 to 8 = 2 int distance1 = MidiUtils.GetRelativePitchDistance(6, 8); Assert.AreEqual(2, distance1); // Shortest distance via 1, 0, 11, 10 = 4 int distance2 = MidiUtils.GetRelativePitchDistance(2, 10); Assert.AreEqual(4, distance2); }
private void HandlePitchEvent(PitchEvent pitchEvent, double currentBeat, bool updateUi) { // Stop recording if (pitchEvent == null || pitchEvent.MidiNote <= 0) { if (lastRecordedNote != null) { HandleRecordedNoteEnded(currentBeat); } return; } // Start new recorded note if (lastRecordedNote == null) { HandleRecordedNoteStarted(pitchEvent.MidiNote, currentBeat, updateUi); return; } // Continue or finish existing recorded note. Possibly starting new note to change pitch. bool isTargetNoteHitNow = MidiUtils.GetRelativePitchDistance(lastRecordedNote.TargetNote.MidiNote, pitchEvent.MidiNote) <= roundingDistance; if (isTargetNoteHitNow && !IsTargetNoteHit(lastRecordedNote)) { // Jump from a wrong pitch to correct pitch. // Otherwise, the rounding could tend towards the wrong pitch // when the player starts a note with the wrong pitch. HandleRecordedNoteEnded(currentBeat); HandleRecordedNoteStarted(pitchEvent.MidiNote, currentBeat, updateUi); } else if (MidiUtils.GetRelativePitchDistance(lastRecordedNote.RoundedMidiNote, pitchEvent.MidiNote) <= roundingDistance) { // Earned a joker for continued correct singing. if (IsTargetNoteHit(lastRecordedNote) && availableJokerCount < MaxJokerCount) { availableJokerCount++; } // Continue singing on same pitch HandleRecordedNoteContinued(pitchEvent.MidiNote, currentBeat, updateUi); } else { // Changed pitch while singing. if (!isTargetNoteHitNow && IsTargetNoteHit(lastRecordedNote) && availableJokerCount > 0) { // Because of the joker, this beat is still counted as correct although it is not. The joker is gone. availableJokerCount--; usedJokerCount++; HandleRecordedNoteContinued(lastRecordedNote.RecordedMidiNote, currentBeat, updateUi); } else { // Continue singing on different pitch. HandleRecordedNoteEnded(currentBeat); HandleRecordedNoteStarted(pitchEvent.MidiNote, currentBeat, updateUi); } } }