示例#1
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));
        }
    }
示例#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;
    }
    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}");
        }
    }
    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);
    }
 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";
     }
 }
示例#6
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: ?";
     }
 }
示例#7
0
 private void UpdateLastMidiNoteFields(PitchEvent pitchEvent)
 {
     if (pitchEvent == null)
     {
         lastMidiNoteName = "";
         lastMidiNote     = 0;
     }
     else
     {
         lastMidiNoteName = MidiUtils.GetAbsoluteName(pitchEvent.MidiNote);
         lastMidiNote     = pitchEvent.MidiNote;
     }
 }
示例#8
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);
        }
    }
 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", "?");
     }
 }
示例#10
0
    public void GetAbsoluteNameTest()
    {
        Dictionary <int, string> midiNoteToAbsoluteNameMap = new Dictionary <int, string>();

        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);
        }
    }
示例#11
0
    private void DisplayNote(Sentence sentence, Note note)
    {
        UiNote uiNote = Instantiate(uiNotePrefab);

        uiNote.transform.SetParent(transform);
        uiNote.Note     = note;
        uiNote.isGolden = note.IsGolden;

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

        uiNoteText.text = note.Text + " (" + MidiUtils.GetAbsoluteName(note.MidiNote) + ")";

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

        PositionUiNote(uiNoteRectTransform, note.MidiNote, note.StartBeat, note.EndBeat);
    }
示例#12
0
    private void CreateLabelForMidiNote(int midiNote)
    {
        Text          uiText = Instantiate(labelPrefab, labelContainer);
        RectTransform label  = uiText.GetComponent <RectTransform>();

        float y            = (float)noteArea.GetVerticalPositionForMidiNote(midiNote);
        float anchorHeight = noteArea.HeightForSingleNote;

        label.anchorMin        = new Vector2(0, y - (anchorHeight / 2f));
        label.anchorMax        = new Vector2(1, y + (anchorHeight / 2f));
        label.anchoredPosition = Vector2.zero;
        label.sizeDelta        = new Vector2(0, 0);

        string midiNoteName = MidiUtils.GetAbsoluteName(midiNote);

        uiText.text = midiNoteName;
    }
示例#13
0
    private void DisplayRecordedNote(RecordedNote recordedNote, bool useRoundedNote = true)
    {
        int midiNote = (useRoundedNote) ? recordedNote.RoundedMidiNote : recordedNote.RecordedMidiNote;

        UiRecordedNote uiNote = Instantiate(uiRecordedNotePrefab);

        uiNote.transform.SetParent(transform);

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

        uiNoteText.text = (useRoundedNote) ? MidiUtils.GetAbsoluteName(recordedNote.RoundedMidiNote)
                                           : MidiUtils.GetAbsoluteName(recordedNote.RecordedMidiNote);

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

        PositionUiNote(uiNoteRectTransform, midiNote, recordedNote.StartBeat, recordedNote.EndBeat);
    }
    protected virtual UiNote CreateUiNote(Note note)
    {
        if (note.StartBeat == note.EndBeat)
        {
            return(null);
        }

        UiNote uiNote = Instantiate(uiNotePrefab, uiNotesContainer);

        uiNote.Init(note, uiEffectsContainer);
        if (micProfile != null)
        {
            uiNote.SetColorOfMicProfile(micProfile);
        }

        Text   uiNoteText = uiNote.lyricsUiText;
        string pitchName  = MidiUtils.GetAbsoluteName(note.MidiNote);

        if (settings.GraphicSettings.showLyricsOnNotes && showPitchOfNotes)
        {
            uiNoteText.text = GetDisplayText(note) + " (" + pitchName + ")";
        }
        else if (settings.GraphicSettings.showLyricsOnNotes)
        {
            uiNoteText.text = GetDisplayText(note);
        }
        else if (showPitchOfNotes)
        {
            uiNoteText.text = pitchName;
        }
        else
        {
            uiNoteText.text = "";
        }

        RectTransform uiNoteRectTransform = uiNote.RectTransform;

        PositionUiNote(uiNoteRectTransform, note.MidiNote, note.StartBeat, note.EndBeat);

        noteToUiNoteMap[note] = uiNote;

        return(uiNote);
    }
    private Label CreateLabelForMidiNote(int midiNote)
    {
        Label label = new();

        label.AddToClassList("tinyFont");
        label.enableRichText       = false;
        label.style.position       = new StyleEnum <Position>(Position.Absolute);
        label.style.unityTextAlign = new StyleEnum <TextAnchor>(TextAnchor.MiddleCenter);
        label.style.left           = 0;

        string midiNoteName = MidiUtils.GetAbsoluteName(midiNote);

        label.text = midiNoteName;

        UpdateMidiNoteLabelPosition(label, midiNote);

        horizontalGridLabelContainer.Add(label);

        return(label);
    }
示例#16
0
    private void CreateUiNote(Note note)
    {
        if (note.StartBeat == note.EndBeat)
        {
            return;
        }

        UiNote uiNote = Instantiate(uiNotePrefab, uiNotesContainer);

        uiNote.Init(note, uiEffectsContainer);
        if (micProfile != null)
        {
            uiNote.SetColorOfMicProfile(micProfile);
        }

        Text   uiNoteText = uiNote.GetComponentInChildren <Text>();
        string pitchName  = MidiUtils.GetAbsoluteName(note.MidiNote);

        if (showLyricsOfNotes && showPitchOfNotes)
        {
            uiNoteText.text = note.Text + " (" + pitchName + ")";
        }
        else if (showLyricsOfNotes)
        {
            uiNoteText.text = note.Text;
        }
        else if (showPitchOfNotes)
        {
            uiNoteText.text = pitchName;
        }
        else
        {
            uiNoteText.text = "";
        }

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

        PositionUiNote(uiNoteRectTransform, note.MidiNote, note.StartBeat, note.EndBeat);
    }
示例#17
0
    public void TestPitchDetection()
    {
        MicProfile micProfile = CreateDummyMicProfile();

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

        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    path      = pathAndNoteName.Key;
            AudioClip audioClip = AudioUtils.GetAudioClip(path);
            float[]   samples   = new float[audioClip.samples];
            audioClip.GetData(samples, 0);

            // Analyze the samples
            IAudioSamplesAnalyzer audioSamplesAnalyzer = new CamdAudioSamplesAnalyzer(audioClip.frequency);
            audioSamplesAnalyzer.Enable();
            PitchEvent pitchEvent = audioSamplesAnalyzer.ProcessAudioSamples(samples, samples.Length, micProfile);

            // Check result
            Assert.NotNull(pitchEvent, $"No pitch detected when analyzing {path}");
            string expectedName = pathAndNoteName.Value;
            string analyzedName = MidiUtils.GetAbsoluteName(pitchEvent.MidiNote);
            Assert.AreEqual(expectedName, analyzedName,
                            $"Expected {expectedName} but was {analyzedName} when analyzing {path}");
        }
    }
示例#18
0
    private void HandleEndOfNote(MidiEvent midiEvent, Dictionary <int, Note> midiPitchToNoteUnderConstruction, List <Note> loadedNotes)
    {
        int midiPitch         = midiEvent.parameter1;
        int deltaTimeInMillis = GetDeltaTimeInMillis(midiEvent);
        int endBeat           = (int)Math.Round(BpmUtils.MillisecondInSongToBeat(songMeta, deltaTimeInMillis));

        if (midiPitchToNoteUnderConstruction.TryGetValue(midiPitch, out Note existingNote))
        {
            if (endBeat > existingNote.StartBeat)
            {
                existingNote.SetEndBeat(endBeat);
                loadedNotes.Add(existingNote);
            }
            else
            {
                Debug.LogWarning($"End beat {endBeat} is not after start beat {existingNote.StartBeat}. Skipping this note.");
            }
            midiPitchToNoteUnderConstruction.Remove(midiPitch);
        }
        else
        {
            Debug.LogWarning($"No Note for pitch {MidiUtils.GetAbsoluteName(midiPitch)} is being constructed. Ignoring this Note_Off event at {deltaTimeInMillis} ms.");
        }
    }