예제 #1
0
    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));
    }
예제 #2
0
    private void CreateUiRecordedNote(RecordedNote recordedNote, bool useRoundedMidiNote)
    {
        if (recordedNote.StartBeat == recordedNote.EndBeat)
        {
            return;
        }

        int midiNote = (useRoundedMidiNote) ? recordedNote.RoundedMidiNote : recordedNote.RecordedMidiNote;

        UiRecordedNote uiNote = Instantiate(uiRecordedNotePrefab, uiRecordedNotesContainer);

        if (micProfile != null)
        {
            uiNote.SetColorOfMicProfile(micProfile);
        }

        Text uiNoteText = uiNote.GetComponentInChildren <Text>();

        if (showPitchOfNotes)
        {
            string pitchName = MidiUtils.GetAbsoluteName(midiNote);
            uiNoteText.text = " (" + pitchName + ")";
        }
        else
        {
            uiNoteText.text = "";
        }

        RectTransform uiNoteRectTransform = uiNote.GetComponent <RectTransform>();

        PositionUiNote(uiNoteRectTransform, midiNote, recordedNote.StartBeat, recordedNote.EndBeat);
        recordedNoteToUiRecordedNoteMap[recordedNote] = uiNote;
    }
예제 #3
0
        private void GenerateMasterBar(MasterBar masterBar, MasterBar previousMasterBar, int currentTick)
        {
            // time signature
            if (previousMasterBar == null ||
                previousMasterBar.TimeSignatureDenominator != masterBar.TimeSignatureDenominator ||
                previousMasterBar.TimeSignatureNumerator != masterBar.TimeSignatureNumerator)
            {
                _handler.AddTimeSignature(currentTick, masterBar.TimeSignatureNumerator, masterBar.TimeSignatureDenominator);
            }

            // tempo
            if (previousMasterBar == null)
            {
                _handler.AddTempo(currentTick, masterBar.Score.Tempo);
                _currentTempo = masterBar.Score.Tempo;
            }
            else if (masterBar.TempoAutomation != null)
            {
                _handler.AddTempo(currentTick, (int)masterBar.TempoAutomation.Value);
                _currentTempo = (int)(masterBar.TempoAutomation.Value);
            }

            // metronome
            if (GenerateMetronome)
            {
                var start  = currentTick;
                var length = MidiUtils.ValueToTicks(masterBar.TimeSignatureDenominator);
                for (int i = 0; i < masterBar.TimeSignatureNumerator; i++)
                {
                    _handler.AddMetronome(start, length);
                    start += length;
                }
            }
        }
예제 #4
0
    private void TestPitchDetection(Func <int, IAudioSamplesAnalyzer> audioSamplesAnalyzerProvider)
    {
        MicProfile micProfile = CreateDummyMicProfile();

        string assetsPath      = Application.dataPath;
        string sineWaveToneDir = assetsPath + "/Common/Audio/SineWaveTones/";
        Dictionary <string, string> pathToExpectedMidiNoteNameMap = new();

        pathToExpectedMidiNoteNameMap.Add(sineWaveToneDir + "sine-wave-a3-220hz.ogg", "A3");
        pathToExpectedMidiNoteNameMap.Add(sineWaveToneDir + "sine-wave-a4-440hz.ogg", "A4");
        pathToExpectedMidiNoteNameMap.Add(sineWaveToneDir + "sine-wave-a5-880hz.ogg", "A5");
        pathToExpectedMidiNoteNameMap.Add(sineWaveToneDir + "sine-wave-c2-61,74hz.ogg", "C2");
        pathToExpectedMidiNoteNameMap.Add(sineWaveToneDir + "sine-wave-c4-261,64hz.ogg", "C4");
        pathToExpectedMidiNoteNameMap.Add(sineWaveToneDir + "sine-wave-c6-1046,50hz.ogg", "C6");

        foreach (KeyValuePair <string, string> pathAndNoteName in pathToExpectedMidiNoteNameMap)
        {
            // Load the audio clip
            string    uri       = "file://" + pathAndNoteName.Key;
            AudioClip audioClip = AudioUtils.GetAudioClipUncached(uri, false);
            float[]   samples   = new float[audioClip.samples];
            audioClip.GetData(samples, 0);

            // Analyze the samples
            IAudioSamplesAnalyzer audioSamplesAnalyzer = audioSamplesAnalyzerProvider(audioClip.frequency);
            PitchEvent            pitchEvent           = audioSamplesAnalyzer.ProcessAudioSamples(samples, 0, samples.Length - 1, micProfile);

            // Check result
            Assert.NotNull(pitchEvent, $"No pitch detected when analyzing audio resource {uri}");
            string expectedName = pathAndNoteName.Value;
            string analyzedName = MidiUtils.GetAbsoluteName(pitchEvent.MidiNote);
            Assert.AreEqual(expectedName, analyzedName,
                            $"Expected {expectedName} but was {analyzedName} when analyzing audio resource {uri}");
        }
    }
예제 #5
0
    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);
            }
        }
    }
예제 #6
0
    private void OnPitchDetected(PitchEvent pitchEvent)
    {
        if (pitchEvent == null || !isCalibrationInProgress || pauseTime > 0)
        {
            return;
        }

        string targetMidiNoteName = midiNoteNames[currentIteration];

        if (MidiUtils.GetAbsoluteName(pitchEvent.MidiNote) == targetMidiNoteName)
        {
            audioSource.Stop();
            float delayInSeconds = Time.time - startTimeInSeconds;
            int   delayInMillis  = (int)(delayInSeconds * 1000);
            delaysInMillis.Add(delayInMillis);
            Debug.Log($"Mic delay calibration - delay of iteration {currentIteration}: {delayInMillis}");

            currentIteration++;
            if (currentIteration >= midiNoteNames.Count)
            {
                OnEndCalibration();
            }
            else
            {
                // Wait a bit for silence before the next iteration.
                pauseTime = 0.5f;
            }
        }
        else
        {
            Debug.Log("Mic delay calibration - wrong pitch: " + MidiUtils.GetAbsoluteName(pitchEvent.MidiNote));
        }
    }
예제 #7
0
    public DywaAudioSamplesAnalyzer(int sampleRateHz, int maxSampleLength)
    {
        this.maxSampleLength = maxSampleLength;
        halftoneFrequencies  = MidiUtils.PrecalculateHalftoneFrequencies(MidiUtils.SingableNoteMin, MidiUtils.SingableNoteRange);

        // Create and configure Dynamic Wavelet Pitch Tracker.
        dywaPitchTracker = new DywaPitchTracker();
        dywaPitchTracker.SampleRateHz = sampleRateHz;
    }
예제 #8
0
        public void AddNote(int track, int start, int length, byte key, DynamicValue dynamicValue, byte channel)
        {
            var velocity = MidiUtils.DynamicToVelocity(dynamicValue);

            AddEvent(track, start,
                     new MidiMessage(new[] { MakeCommand(0x90, channel), FixValue(key), FixValue((byte)velocity) }));
            AddEvent(track, start + length,
                     new MidiMessage(new[] { MakeCommand(0x80, channel), FixValue(key), FixValue((byte)velocity) }));
        }
    protected void CreateUiRecordedNote(RecordedNote recordedNote, bool useRoundedMidiNote)
    {
        if (recordedNote.StartBeat == recordedNote.EndBeat)
        {
            return;
        }

        // Pitch detection algorithms often have issues finding the correct octave. However, the octave is irrelevant for scores.
        // When notes are drawn far away from the target note because the pitch detection got the wrong octave then it looks wrong.
        // Thus, only the relative pitch of the roundedMidiNote is used and drawn on the octave of the target note.
        int midiNote;

        if (useRoundedMidiNote &&
            recordedNote.TargetNote != null)
        {
            midiNote = MidiUtils.GetMidiNoteOnOctaveOfTargetMidiNote(recordedNote.RoundedMidiNote, recordedNote.TargetNote.MidiNote);
        }
        else
        {
            midiNote = recordedNote.RecordedMidiNote;
        }

        UiRecordedNote uiNote = Instantiate(uiRecordedNotePrefab, uiRecordedNotesContainer);

        uiNote.RecordedNote  = recordedNote;
        uiNote.StartBeat     = recordedNote.StartBeat;
        uiNote.TargetEndBeat = recordedNote.EndBeat;
        // Draw already a portion of the note
        uiNote.LifeTimeInSeconds = Time.deltaTime;
        uiNote.EndBeat           = recordedNote.StartBeat + (uiNote.LifeTimeInSeconds * beatsPerSecond);

        uiNote.MidiNote = midiNote;
        if (micProfile != null)
        {
            uiNote.SetColorOfMicProfile(micProfile);
        }

        Text uiNoteText = uiNote.lyricsUiText;

        if (showPitchOfNotes)
        {
            string pitchName = MidiUtils.GetAbsoluteName(midiNote);
            uiNoteText.text = " (" + pitchName + ")";
        }
        else
        {
            uiNoteText.text = "";
        }

        RectTransform uiNoteRectTransform = uiNote.RectTransform;

        PositionUiNote(uiNoteRectTransform, midiNote, uiNote.StartBeat, uiNote.EndBeat);

        uiRecordedNotes.Add(uiNote);
        recordedNoteToUiRecordedNotesMap.AddInsideList(recordedNote, uiNote);
    }
예제 #10
0
 public CamdAudioSamplesAnalyzer(int sampleRateHz, int maxSampleLength)
 {
     this.maxSampleLength = maxSampleLength;
     float[] halftoneFrequencies = MidiUtils.PrecalculateHalftoneFrequencies(MinNote, NumHalftones);
     halftoneDelays = MidiUtils.PrecalculateHalftoneDelays(sampleRateHz, halftoneFrequencies);
     for (int i = 0; i < currentCandidates.Length; i++)
     {
         currentCandidates[i] = new CamdPitchCandidate();
     }
 }
예제 #11
0
 private void OnPitchDetected(int midiNote)
 {
     // Show the note that has been detected
     if (midiNote > 0)
     {
         currentNoteLabel.text = "Note: " + MidiUtils.GetAbsoluteName(midiNote);
     }
     else
     {
         currentNoteLabel.text = "Note: unkown";
     }
 }
        /// <inheritdoc />
        public void AddNote(int track, int start, int length, byte key, DynamicValue dynamicValue, byte channel)
        {
            var velocity = MidiUtils.DynamicToVelocity(dynamicValue);

            var noteOn = new MidiEvent(start, MakeCommand((byte)MidiEventType.NoteOn, channel), FixValue(key), FixValue((byte)velocity));

            _midiFile.AddEvent(noteOn);

            var noteOff = new MidiEvent(start + length, MakeCommand((byte)MidiEventType.NoteOff, channel), FixValue(key), FixValue((byte)velocity));

            _midiFile.AddEvent(noteOff);
        }
예제 #13
0
 private void OnPitchDetected(PitchEvent pitchEvent)
 {
     // Show the note that has been detected
     if (pitchEvent != null && pitchEvent.MidiNote > 0)
     {
         currentNoteLabel.text = "Note: " + MidiUtils.GetAbsoluteName(pitchEvent.MidiNote);
     }
     else
     {
         currentNoteLabel.text = "Note: ?";
     }
 }
예제 #14
0
 private void UpdateLastMidiNoteFields(PitchEvent pitchEvent)
 {
     if (pitchEvent == null)
     {
         lastMidiNoteName = "";
         lastMidiNote     = 0;
     }
     else
     {
         lastMidiNoteName = MidiUtils.GetAbsoluteName(pitchEvent.MidiNote);
         lastMidiNote     = pitchEvent.MidiNote;
     }
 }
예제 #15
0
        public void TestMethod()
        {
            for (int i = 0; i < 128; i++)
            {
                float freq  = MidiUtils.MidiNoteToPitch(i);
                int   note  = 0;
                int   cents = 0;
                MidiUtils.PitchToMidiNote(freq, out note, out cents);
                string noteName = MidiUtils.GetNoteName(note, false, true);

                Console.Out.WriteLine("Midi Key: {0}, Frequency: {1:0.0000} (note: {2} {3} cents - {4})", i, freq, note, cents, noteName);
            }
        }
예제 #16
0
 /// <summary>
 /// Encodes a Note On short message.
 /// </summary>
 /// <param name="channel">MIDI channel.</param>
 /// <param name="noteId">Note ID.</param>
 /// <param name="velocity">Note velocity.</param>
 /// <returns>A value that can be passed to midiOutShortMsg.</returns>
 /// <exception cref="ArgumentOutOfRangeException">noteId is not in MIDI range.</exception>
 public static uint EncodeNoteOn(Channel channel, int noteId, int velocity)
 {
     channel.Validate();
     if (!MidiUtils.IsInMidiRange(noteId))
     {
         throw new ArgumentOutOfRangeException("Pitch out of MIDI range.");
     }
     if (velocity < 0 || velocity > 127)
     {
         throw new ArgumentOutOfRangeException("Velocity is out of range.");
     }
     return((uint)(0x90 | ((int)channel) | (noteId << 8) | (velocity << 16)));
 }
예제 #17
0
    private int GetRoundedMidiNote(int recordedMidiNote, int targetMidiNote, int roundingDistance)
    {
        int distance = MidiUtils.GetRelativePitchDistance(recordedMidiNote, targetMidiNote);

        if (distance <= roundingDistance)
        {
            return(targetMidiNote);
        }
        else
        {
            return(recordedMidiNote);
        }
    }
예제 #18
0
        public void AddMacro(string note, Macro macro)
        {
            if (!MidiUtils.IsNoteNameValid(note))
            {
                throw new ArgumentException($"'{note}' is not a valid note name");
            }

            if (_macros.Contains(note))
            {
                throw new ArgumentException($"Macro in note '{note}' already exists");
            }

            _macros.Add(note, macro);
        }
예제 #19
0
    public void SyncWithNote()
    {
        bool isSelected = selectionController.IsSelected(Note);

        goldenNoteImageOverlay.gameObject.SetActive(Note.IsGolden);
        SetLyrics(Note.Text);
        SetSelected(isSelected);
        pitchLabel.text = MidiUtils.GetAbsoluteName(Note.MidiNote);
        if (Note.Sentence != null && Note.Sentence.Voice != null)
        {
            Color color = songEditorSceneController.GetColorForVoice(Note.Sentence.Voice);
            SetColor(color);
        }
    }
예제 #20
0
    private void UpdatePosition(VirtualPianoKeyControl keyControl)
    {
        float heightPercent = noteAreaControl.HeightForSingleNote * 0.8f;
        float yPercent      = (float)noteAreaControl.GetVerticalPositionForMidiNote(keyControl.MidiNote) - heightPercent / 2;
        float widthPercent  = MidiUtils.IsWhitePianoKey(keyControl.MidiNote) ? 0.9f : 0.7f;

        VisualElement visualElement = keyControl.VisualElement;

        visualElement.style.position = new StyleEnum <Position>(Position.Absolute);
        visualElement.style.top      = new StyleLength(new Length(yPercent * 100, LengthUnit.Percent));
        visualElement.style.height   = new StyleLength(new Length(heightPercent * 100, LengthUnit.Percent));
        visualElement.style.left     = 0;
        visualElement.style.width    = new StyleLength(new Length(widthPercent * 100, LengthUnit.Percent));
    }
예제 #21
0
        public override void RunSuite()
        {
            ///// Export midi.
            StepCollection steps = new StepCollection();

            Dictionary <int, string> channels = new Dictionary <int, string>();

            new List <int>()
            {
                1, 2, 3
            }.ForEach(i => channels.Add(i, $"CHANNEL_{i}"));

            MidiUtils.ExportMidi(steps, "midiFileName", channels, 1.0, "string info");
        }
예제 #22
0
        private static Macro ParseMacro(string serializedMacro, int lineNumber, out string note)
        {
            string[] parameters = serializedMacro.Split(Macro.SerializeDelimiter);
            if (parameters.Length != Macro.SerializeParamsCount)
            {
                throw new ParseProfileFileException(GetErrorMessage($"Macro needs to have exactly {Macro.SerializeParamsCount} parameters", lineNumber));
            }

            // Parse and validate macro name
            string macroName = parameters[Macro.SerializeNameIndex];

            if (string.IsNullOrWhiteSpace(macroName) || macroName.Length > Macro.MaxMacroNameSize)
            {
                throw new ParseProfileFileException(GetErrorMessage(
                                                        $"Macro name size needs to be between 1-{Macro.MaxMacroNameSize} characters", lineNumber, Macro.SerializeNameIndex + 1)
                                                    );
            }

            // Parse and validate note name
            note = parameters[Macro.SerializeNoteIndex];
            if (!MidiUtils.IsNoteNameValid(note))
            {
                throw new ParseProfileFileException(GetErrorMessage("Invalid note name", lineNumber, Macro.SerializeNoteIndex + 1));
            }

            // Parse and validate macro type
            string typeName = parameters[Macro.SerializeTypeIndex].Replace("_", "");

            if (!Enum.TryParse(typeName, true, out Macro.MacroType type))
            {
                throw new ParseProfileFileException(GetErrorMessage("Invalid macro type", lineNumber, Macro.SerializeTypeIndex + 1));
            }

            // Parse and validate macro options
            string macroOptions = parameters[Macro.SerializeOptionsIndex];

            if (string.IsNullOrWhiteSpace(macroOptions))
            {
                throw new ParseProfileFileException(GetErrorMessage("Macro options must not be empty", lineNumber, Macro.SerializeOptionsIndex + 1));
            }

            try
            {
                // Deserialize macro
                return(Macro.DeserializeMacro(macroName, note, type, macroOptions));
            } catch (DeserializeMacroException ex)
            {
                throw new ParseProfileFileException(GetErrorMessage(ex.Message, lineNumber, Macro.SerializeOptionsIndex + 1));
            }
        }
 private void OnPitchDetected(PitchEvent pitchEvent)
 {
     // Show the note that has been detected
     if (pitchEvent != null && pitchEvent.MidiNote > 0)
     {
         currentNoteLabel.text = TranslationManager.GetTranslation(R.Messages.options_note,
                                                                   "value", MidiUtils.GetAbsoluteName(pitchEvent.MidiNote));
     }
     else
     {
         currentNoteLabel.text = TranslationManager.GetTranslation(R.Messages.options_note,
                                                                   "value", "?");
     }
 }
예제 #24
0
    private void OnBeatAnalyzed(PlayerPitchTracker.BeatAnalyzedEvent beatAnalyzedEvent)
    {
        // Check if pitch was detected where a note is expected in the song
        if (beatAnalyzedEvent.PitchEvent == null ||
            beatAnalyzedEvent.NoteAtBeat == null)
        {
            return;
        }

        if (beatAnalyzedEvent.Beat < NextBeatToScore)
        {
            return;
        }

        Note analyzedNote = beatAnalyzedEvent.NoteAtBeat;

        // Check if note was hit
        if (MidiUtils.GetRelativePitch(beatAnalyzedEvent.RoundedRecordedMidiNote) != MidiUtils.GetRelativePitch(analyzedNote.MidiNote))
        {
            return;
        }

        // The beat was sung correctly.
        if (!ScoreData.NoteToNoteScoreMap.TryGetValue(analyzedNote, out NoteScore noteScore))
        {
            noteScore = new NoteScore(analyzedNote);
            ScoreData.NoteToNoteScoreMap.Add(analyzedNote, noteScore);
        }
        noteScore.CorrectlySungBeats++;

        Sentence analyzedSentence = beatAnalyzedEvent.NoteAtBeat.Sentence;

        if (!ScoreData.SentenceToSentenceScoreMap.TryGetValue(analyzedSentence, out SentenceScore sentenceScore))
        {
            sentenceScore = CreateSentenceScore(analyzedSentence);
            ScoreData.SentenceToSentenceScoreMap.Add(analyzedSentence, sentenceScore);
        }

        if (IsPerfectHit(beatAnalyzedEvent))
        {
            ScoreData.GetBeatData(analyzedNote).IfNotNull(it => it.PerfectBeats++);
            sentenceScore.GetBeatData(analyzedNote).IfNotNull(it => it.PerfectBeats++);
        }
        else if (IsGoodHit(beatAnalyzedEvent))
        {
            ScoreData.GetBeatData(analyzedNote).IfNotNull(it => it.GoodBeats++);
            sentenceScore.GetBeatData(analyzedNote).IfNotNull(it => it.GoodBeats++);
        }
    }
예제 #25
0
    private void OnBeatAnalyzed(PlayerPitchTracker.BeatAnalyzedEvent beatAnalyzedEvent)
    {
        // Check if pitch was detected where a note is expected in the song
        if (beatAnalyzedEvent.PitchEvent == null ||
            beatAnalyzedEvent.NoteAtBeat == null)
        {
            return;
        }

        if (beatAnalyzedEvent.Beat < NextBeatToScore)
        {
            return;
        }

        Note analyzedNote = beatAnalyzedEvent.NoteAtBeat;

        // Check if note was hit
        if (MidiUtils.GetRelativePitch(beatAnalyzedEvent.RoundedMidiNote) != MidiUtils.GetRelativePitch(analyzedNote.MidiNote))
        {
            return;
        }

        // The beat was sung correctly.
        if (!ScoreData.NoteToNoteScoreMap.TryGetValue(analyzedNote, out NoteScore noteScore))
        {
            noteScore = new NoteScore(analyzedNote);
            ScoreData.NoteToNoteScoreMap.Add(analyzedNote, noteScore);
        }
        noteScore.CorrectlySungBeats++;

        Sentence analyzedSentence = beatAnalyzedEvent.NoteAtBeat.Sentence;

        if (!ScoreData.SentenceToSentenceScoreMap.TryGetValue(analyzedSentence, out SentenceScore sentenceScore))
        {
            sentenceScore = new SentenceScore(analyzedSentence);
            ScoreData.SentenceToSentenceScoreMap.Add(analyzedSentence, sentenceScore);
        }

        if (analyzedNote.IsNormal)
        {
            ScoreData.CorrectNormalNoteLengthTotal++;
            sentenceScore.CorrectlySungNormalBeats++;
        }
        else if (analyzedNote.IsGolden)
        {
            ScoreData.CorrectGoldenNoteLengthTotal++;
            sentenceScore.CorrectlySungGoldenBeats++;
        }
    }
예제 #26
0
        protected Macro(string macroName, string note)
        {
            if (!MidiUtils.IsNoteNameValid(note))
            {
                throw new ArgumentException($"'{note}' is not a valid note name");
            }

            if (macroName.Length > MaxMacroNameSize)
            {
                throw new ArgumentException($"Macro must not exceed {MaxMacroNameSize} characters");
            }

            MacroName = macroName;
            Note      = note;
        }
예제 #27
0
        /// <summary>
        /// Constructs a note message.
        /// </summary>
        public NoteMessage(Channel channel, bool noteOn, int noteId, int velocity)
            : base(channel)
        {
            if (!MidiUtils.IsInMidiRange(noteId))
            {
                throw new ArgumentOutOfRangeException("note ID is out of MIDI range.");
            }

            if (velocity < 0 || velocity > 127)
            {
                throw new ArgumentOutOfRangeException("velocity");
            }
            this.NoteOn   = noteOn;
            this.NoteId   = noteId;
            this.Velocity = velocity;
        }
예제 #28
0
    private int GetCorrectlySungNoteLength(RecordedNote recordedNote)
    {
        if (recordedNote.TargetNote == null)
        {
            return(0);
        }

        if (MidiUtils.GetRelativePitch(recordedNote.TargetNote.MidiNote) != MidiUtils.GetRelativePitch(recordedNote.RoundedMidiNote))
        {
            return(0);
        }

        int correctlySungNoteLength = (int)(recordedNote.EndBeat - recordedNote.StartBeat);

        return(correctlySungNoteLength);
    }
예제 #29
0
    public void GetAbsoluteNameTest()
    {
        Dictionary <int, string> midiNoteToAbsoluteNameMap = new();

        midiNoteToAbsoluteNameMap.Add(36, "C2");
        midiNoteToAbsoluteNameMap.Add(57, "A3");
        midiNoteToAbsoluteNameMap.Add(60, "C4");
        midiNoteToAbsoluteNameMap.Add(69, "A4");
        midiNoteToAbsoluteNameMap.Add(81, "A5");
        midiNoteToAbsoluteNameMap.Add(84, "C6");
        foreach (KeyValuePair <int, string> midiNoteAndName in midiNoteToAbsoluteNameMap)
        {
            string noteName = MidiUtils.GetAbsoluteName(midiNoteAndName.Key);
            Assert.AreEqual(midiNoteAndName.Value, noteName);
        }
    }
예제 #30
0
    public void GetRelativeNameTest()
    {
        Dictionary <int, string> midiNoteToRelativeNameMap = new Dictionary <int, string>();

        midiNoteToRelativeNameMap.Add(36, "C");
        midiNoteToRelativeNameMap.Add(57, "A");
        midiNoteToRelativeNameMap.Add(60, "C");
        midiNoteToRelativeNameMap.Add(69, "A");
        midiNoteToRelativeNameMap.Add(81, "A");
        midiNoteToRelativeNameMap.Add(84, "C");
        foreach (KeyValuePair <int, string> midiNoteAndName in midiNoteToRelativeNameMap)
        {
            string noteName = MidiUtils.GetRelativeName(midiNoteAndName.Key);
            Assert.AreEqual(midiNoteAndName.Value, noteName);
        }
    }