コード例 #1
0
        // These work by shifting the signal until it seems to correlate with itself.
        // In other words if the signal looks very similar to (signal shifted 200 samples) than the fundamental period is probably 200 samples
        // Note that the algorithm only works well when there's only one prominent fundamental.
        // This could be optimized by looking at the rate of change to determine a maximum without testing all periods.
        private static double[] detectPitchCalculation(WaveAudio w, double minHz, double maxHz, int nCandidates, int nResolution, PitchDetectAlgorithm algorithm)
        {
            // note that higher frequency means lower period
            int nLowPeriodInSamples = hzToPeriodInSamples(maxHz, w.getSampleRate());
            int nHiPeriodInSamples = hzToPeriodInSamples(minHz, w.getSampleRate());
            if (nHiPeriodInSamples <= nLowPeriodInSamples) throw new Exception("Bad range for pitch detection.");
            if (w.getNumChannels() != 1) throw new Exception("Only mono supported.");
            double[] samples = w.data[0];
            if (samples.Length < nHiPeriodInSamples) throw new Exception("Not enough samples.");

            // both algorithms work in a similar way
            // they yield an array of data, and then we find the index at which the value is highest.
            double[] results = new double[nHiPeriodInSamples - nLowPeriodInSamples];

            if (algorithm == PitchDetectAlgorithm.Amdf)
            {
                for (int period = nLowPeriodInSamples; period < nHiPeriodInSamples; period += nResolution)
                {
                    double sum = 0;
                    // for each sample, see how close it is to a sample n away. Then sum these.
                    for (int i = 0; i < samples.Length - period; i++)
                        sum += Math.Abs(samples[i] - samples[i + period]);

                    double mean = sum / (double)samples.Length;
                    mean *= -1; //somewhat of a hack. We are trying to find the minimum value, but our findBestCandidates finds the max. value.
                    results[period - nLowPeriodInSamples] = mean;
                }
            }
            else if (algorithm == PitchDetectAlgorithm.Autocorrelation)
            {
                for (int period = nLowPeriodInSamples; period < nHiPeriodInSamples; period += nResolution)
                {
                    double sum = 0;
                    // for each sample, find correlation. (If they are far apart, small)
                    for (int i = 0; i < samples.Length - period; i++)
                        sum += samples[i] * samples[i + period];

                    double mean = sum / (double)samples.Length;
                    results[period - nLowPeriodInSamples] = mean;
                }
            }

            // find the best indices
            int[] bestIndices = findBestCandidates(nCandidates, ref results); //note findBestCandidates modifies parameter
            // convert back to Hz
            double[] res = new double[nCandidates];
            for (int i=0; i<nCandidates;i++)
                res[i] = periodInSamplesToHz(bestIndices[i]+nLowPeriodInSamples, w.getSampleRate());
            return res;
        }
コード例 #2
0
 /// <param name="nCandidates">Number of results to return</param>
 public static double[] DetectPitchCandidates(WaveAudio w, double minHz, double maxHz, int nCandidates, PitchDetectAlgorithm algorithm)
 {
     return detectPitchCalculation(w, minHz, maxHz, nCandidates, 1, algorithm);
 }
コード例 #3
0
 /// <param name="nCandidates">Number of results to return</param>
 /// <param name="nResolution">Resolution. A value of 1, default, is slowest but most precise.</param>
 public static double[] DetectPitchCandidates(WaveAudio w, double minHz, double maxHz, int nCandidates, PitchDetectAlgorithm algorithm, int nResolution)
 {
     if (nResolution < 1) throw new Exception("Resultion must be >= 1");
     return detectPitchCalculation(w, minHz, maxHz, nCandidates, nResolution, algorithm);
 }
コード例 #4
0
 public static double DetectPitch(WaveAudio w, double minHz, double maxHz, PitchDetectAlgorithm algorithm)
 {
     return detectPitchCalculation(w, minHz, maxHz, 1, 1, algorithm)[0];
 }
コード例 #5
0
        // These work by shifting the signal until it seems to correlate with itself.
        // In other words if the signal looks very similar to (signal shifted 200 samples) than the fundamental period is probably 200 samples
        // Note that the algorithm only works well when there's only one prominent fundamental.
        // This could be optimized by looking at the rate of change to determine a maximum without testing all periods.
        private static double[] detectPitchCalculation(WaveAudio w, double minHz, double maxHz, int nCandidates, int nResolution, PitchDetectAlgorithm algorithm)
        {
            // note that higher frequency means lower period
            int nLowPeriodInSamples = hzToPeriodInSamples(maxHz, w.getSampleRate());
            int nHiPeriodInSamples  = hzToPeriodInSamples(minHz, w.getSampleRate());

            if (nHiPeriodInSamples <= nLowPeriodInSamples)
            {
                throw new Exception("Bad range for pitch detection.");
            }
            if (w.getNumChannels() != 1)
            {
                throw new Exception("Only mono supported.");
            }
            double[] samples = w.data[0];
            if (samples.Length < nHiPeriodInSamples)
            {
                throw new Exception("Not enough samples.");
            }

            // both algorithms work in a similar way
            // they yield an array of data, and then we find the index at which the value is highest.
            double[] results = new double[nHiPeriodInSamples - nLowPeriodInSamples];

            if (algorithm == PitchDetectAlgorithm.Amdf)
            {
                for (int period = nLowPeriodInSamples; period < nHiPeriodInSamples; period += nResolution)
                {
                    double sum = 0;
                    // for each sample, see how close it is to a sample n away. Then sum these.
                    for (int i = 0; i < samples.Length - period; i++)
                    {
                        sum += Math.Abs(samples[i] - samples[i + period]);
                    }

                    double mean = sum / (double)samples.Length;
                    mean *= -1; //somewhat of a hack. We are trying to find the minimum value, but our findBestCandidates finds the max. value.
                    results[period - nLowPeriodInSamples] = mean;
                }
            }
            else if (algorithm == PitchDetectAlgorithm.Autocorrelation)
            {
                for (int period = nLowPeriodInSamples; period < nHiPeriodInSamples; period += nResolution)
                {
                    double sum = 0;
                    // for each sample, find correlation. (If they are far apart, small)
                    for (int i = 0; i < samples.Length - period; i++)
                    {
                        sum += samples[i] * samples[i + period];
                    }

                    double mean = sum / (double)samples.Length;
                    results[period - nLowPeriodInSamples] = mean;
                }
            }

            // find the best indices
            int[] bestIndices = findBestCandidates(nCandidates, ref results); //note findBestCandidates modifies parameter
            // convert back to Hz
            double[] res = new double[nCandidates];
            for (int i = 0; i < nCandidates; i++)
            {
                res[i] = periodInSamplesToHz(bestIndices[i] + nLowPeriodInSamples, w.getSampleRate());
            }
            return(res);
        }
コード例 #6
0
 /// <param name="nCandidates">Number of results to return</param>
 /// <param name="nResolution">Resolution. A value of 1, default, is slowest but most precise.</param>
 public static double[] DetectPitchCandidates(WaveAudio w, double minHz, double maxHz, int nCandidates, PitchDetectAlgorithm algorithm, int nResolution)
 {
     if (nResolution < 1)
     {
         throw new Exception("Resultion must be >= 1");
     }
     return(detectPitchCalculation(w, minHz, maxHz, nCandidates, nResolution, algorithm));
 }
コード例 #7
0
 /// <param name="nCandidates">Number of results to return</param>
 public static double[] DetectPitchCandidates(WaveAudio w, double minHz, double maxHz, int nCandidates, PitchDetectAlgorithm algorithm)
 {
     return(detectPitchCalculation(w, minHz, maxHz, nCandidates, 1, algorithm));
 }
コード例 #8
0
 public static double DetectPitch(WaveAudio w, double minHz, double maxHz, PitchDetectAlgorithm algorithm)
 {
     return(detectPitchCalculation(w, minHz, maxHz, 1, 1, algorithm)[0]);
 }