List <int> GetMidisFromClipStreaming(AudioClip clip, RAPTPitchDetector tracker)
    {
        float[] audioSamples = new float[clip.samples];
        clip.GetData(audioSamples, 0);
        int   frameSize = (int)(0.1f * (float)clip.frequency);
        var   r         = new List <float> ();
        int   start     = 0;
        int   end       = start + frameSize;
        float db        = 0f;

        while (end < audioSamples.Length)
        {
            int prevEnd = end;
            r.AddRange(tracker.getPitch(audioSamples, start, ref end, ref db, (float)clip.frequency, true, false));
            if (start == end)
            {
                end = prevEnd + frameSize;
            }
            else
            {
                start = end;
                end  += frameSize;
            }
        }

        if (audioSamples.Length - start > tracker.RequiredSampleCount((float)clip.frequency))
        {
            end = audioSamples.Length;
            r.AddRange(tracker.getPitch(audioSamples, start, ref end, ref db, (float)clip.frequency, true, true));
        }

        return(RAPTPitchDetectorExtensions.HerzToMidi(r));
    }
    List <int> GetMidisFromClip(AudioClip clip, RAPTPitchDetector tracker)
    {
        float[] audioSamples = new float[clip.samples];
        clip.GetData(audioSamples, 0);
        float db           = 0f;
        var   pitchContour = tracker.getPitch(audioSamples, ref db, (float)clip.frequency);

        return(RAPTPitchDetectorExtensions.HerzToMidi(pitchContour));
    }
    public void PitchTrackerTestFrequencySweep()
    {
        // 0.001 and 0.01 clip lengths are too small
        float[] clipLengths = new float[] { 0.001f, 0.01f, 0.1f, 1f };
        float   freqStep = 50f;
        float   freq = 50f;
        float   endFreq = 700f;
        float   sampleRate = 22050;
        var     pitchTracker = new RAPTPitchDetector(22050, 40f, 800f);
        float   min, max, mean, median;
        float   db = 0f;

        while (freq < endFreq)
        {
            foreach (var clipLen in clipLengths)
            {
                var inputSignal = GenerateWaveform(freq, clipLen, sampleRate);
                try {
                    var pitchContour = pitchTracker.getPitch(inputSignal, ref db, sampleRate);
                    if (pitchContour.Count > 0)
                    {
                        GetStats(pitchContour, out mean, out median, out min, out max);
                        Assert.Greater(0.05, (max - min) / max);                         // verify that pitch values are consistent
                        Debug.Log("input:" + freq + "Hz measured:" + max + "Hz delta:" + 100 * Mathf.Abs(freq - max) / freq + "%");
                        Assert.Greater(0.05, Mathf.Abs(freq - max) / freq);              // verify measured pitch is same as input
                    }
                    else
                    {
                        Debug.Log("Could not detect pitch. Clip length:" + clipLen + "s freq:" + freq + "Hz");
                        Assert.Fail();
                    }
                } catch (System.ArgumentException e) {
                    // do not assert here since this is expected for small clip Lengths
                    Debug.Log(e.Message);
                }
            }
            freq += freqStep;
        }
    }
    public IEnumerator PitchTrackerTestStreaming()
    {
        var pitchTracker = new RAPTPitchDetector();
        // audioclip name and midi notes that are played in each clip
        Dictionary <string, int[]> testClips = new Dictionary <string, int[]>()
        {
            { "piano", new int[] { 60, 62, 64, 65, 67, 69, 71, 72 } },                         // C Major
            { "childvoice", new int[] { 60, 62, 64, 65, 67, 69, 71, 72 } },                    // C Major
            { "violin", new int[] { 55, 57, 59, 60, 62, 64, 66, 67, 69, 71, 72, 74, 76, 78 } } // G Major (2 octaves)
        };

        foreach (var item in testClips)
        {
            var path = Path.Combine(Application.dataPath, "HumanVoicePitchDetector/TestData/" + item.Key + audioFilePostfix);
            using (WWW www = new WWW("file://" + path)) {
                Debug.Log("load clip:" + path);
                while (!www.isDone)
                {
                    yield return(null);
                }
                if (string.IsNullOrEmpty(www.error))
                {
                    var clip  = www.GetAudioClip(false, false, preferredAudioType);
                    var midis = GetMidisFromClipStreaming(clip, pitchTracker);
                    midis.RemoveGlitches(1, 2);
                    var mostCommonNotes = midis.GetDominantValues(item.Value.Length);
                    mostCommonNotes.Sort();
                    Debug.Log(mostCommonNotes.NoteString());
                    CollectionAssert.AreEqual(item.Value.ToList(), mostCommonNotes);
                }
                else
                {
                    Debug.LogError("Could not load file:" + path);
                }
            }
        }
    }