pitchfinder

repository·master·Indexed 19 days ago

https://github.com/peterkhayes/pitchfinder

A pitch-detection library for Node.js and the browser that provides a collection of algorithms to balance speed and accuracy. It includes implementations such as YIN, McLeod, AMDF, ACF2+, and Dynamic Wavelet. All algorithms operate on Float32Array inputs and can be configured with parameters like sampleRate to detect frequencies in Hz.

Tokens
5.2K
Snippets
22
Records
24
Agent score
67%

What's inside pitchfinder

  1. Available pitch-finding algorithms

    master

    Pitchfinder provides several algorithms with different trade-offs:

    • YIN: Best balance of accuracy and speed. Occasionally provides incorrect values.
    • Mcleod: Good performance, particularly effective on lower frequencies.
    • AMDF: Consistent frequency detection, but slow and accuracy is limited to approximately +/- 2%.
    • Dynamic Wavelet: Very fast, but struggles with lower frequencies.
    • YIN w/ FFT: (Coming soon)
    • Goertzel: (Coming soon)
  2. Find the pitch of a wav file in Node.js

    master

    To detect the pitch of a .wav file in a Node.js environment, use the wav-decoder library to convert the file buffer into a Float32Array. All pitchfinder algorithms operate on Float32Array inputs. The detector returns the pitch in Hz, or null if the pitch cannot be identified.

    const fs = require("fs");
    const WavDecoder = require("wav-decoder");
    const Pitchfinder = require("pitchfinder");
    
    // Initialize a detector (e.g., YIN)
    const detectPitch = Pitchfinder.YIN();
    
    const buffer = fs.readFileSync(PATH_TO_FILE);
    const decoded = WavDecoder.decode.sync(buffer); // get audio data from file using `wav-decoder`
    const float32Array = decoded.channelData[0]; // get a single channel of sound
    const pitch = detectPitch(float32Array); // null if pitch cannot be identified
  3. Find the pitch of a WebAudio AudioBuffer in the browser

    master

    In the browser, you can extract a Float32Array from a WebAudio AudioBuffer using getChannelData(0) and pass it to a pitchfinder detector.

    import * as Pitchfinder from "pitchfinder";
    
    const myAudioBuffer = getAudioBuffer(); // assume this returns a WebAudio AudioBuffer object
    const float32Array = myAudioBuffer.getChannelData(0); // get a single channel of sound
    
    const detectPitch = Pitchfinder.AMDF();
    const pitch = detectPitch(float32Array); // null if pitch cannot be identified
  4. Configure pitch detection algorithms

    master

    Each detector can be initialized with specific configuration options. All detectors support a global sampleRate option (defaults to 44100).

    YIN

    • threshold: Algorithm-specific threshold.
    • probabilityThreshold: Prevents returning a pitch if the probability estimate is below this value.

    McLeod

    • bufferSize: Expected buffer size in samples (defaults to 1024).
    • cutoff: Relative size of the chosen peak (e.g., 0.93 chooses the first peak higher than 93% of the highest peak). Defaults to 0.93.

    AMDF

    • minFrequency: Lowest detectable frequency.
    • maxFrequency: Highest detectable frequency.
    • sensitivity: Sensitivity setting.
    • ratio: Ratio setting.

    Dynamic Wavelet

    • No special configuration available.
  5. Find a series of pitches using Pitchfinder.frequencies()

    master

    Use Pitchfinder.frequencies() to analyze an entire audio buffer and return an array of pitches at specific intervals based on a tempo and quantization.

    Parameters:

    • detectors: A single detector function or an array of detector functions (using multiple detectors can improve accuracy at the cost of speed).
    • float32Array: The audio data.
    • options: An object containing:
      • tempo: BPM (defaults to 120).
      • quantization: Samples per beat (defaults to 4, i.e., 16th notes).
    const Pitchfinder = require("pitchfinder");
    const detectPitch = Pitchfinder.YIN();
    
    // Single detector
    const frequencies = Pitchfinder.frequencies(detectPitch, float32Array, {
      tempo: 130, // in BPM, defaults to 120
      quantization: 4, // samples per beat, defaults to 4 (i.e. 16th notes),
    });
    
    // Multiple detectors for better accuracy
    const detectors = [detectPitch, Pitchfinder.AMDF()];
    const moreAccurateFrequencies = Pitchfinder.frequencies(
      detectors,
      float32Array,
      {
        tempo: 130,
        quantization: 4,
      }
    );
  6. Configure MacleodConfig parameters

    master

    When initializing the Macleod detector, you can provide a MacleodConfig object to tune the algorithm's sensitivity and accuracy.

    KeyTypeDescription
    bufferSizenumberThe expected size of the input audio buffer in samples.
    cutoffnumberDefines the relative size of the chosen peak. A value of 0.93 means the algorithm chooses the first peak that is higher than 93% of the highest peak detected. (Default is 0.97).
    sampleRatenumberThe sample rate of the audio being processed (e.g., 44100 or 48000).
    interface MacleodConfig {
      bufferSize: number;
      cutoff: number;
      sampleRate: number;
    }
  7. Configure the AMDF detector

    master

    The AMDF function accepts a Partial<AMDFConfig> object. If parameters are omitted, the following defaults are used:

    KeyTypeDefaultDescription
    sampleRatenumber44100The sampling rate of the input audio buffer.
    minFrequencynumber82The lower bound of the frequency range to search.
    maxFrequencynumber1000The upper bound of the frequency range to search.
    rationumber5A threshold factor used to validate the detected pitch against the maximum difference value.
    sensitivitynumber0.1A factor used to calculate the cutoff threshold for the AMDF values.
    export interface AMDFConfig {
      sampleRate: number;
      minFrequency: number;
      maxFrequency: number;
      sensitivity: number;
      ratio: number;
    }
  8. Configure parameters for the `frequencies` function

    master

    When using the frequencies function to analyze a series of pitches, you can provide an options object to override the default configuration. The configuration determines how the audio buffer is chunked based on tempo and quantization.

    Available options:

    • tempo: The tempo in BPM (default: 120).
    • quantization: The quantization factor (default: 4).
    • sampleRate: The sample rate of the audio in Hz (default: 44100).
    const options = {
      tempo: 120,
      quantization: 4,
      sampleRate: 44100
    };
  9. Configure the DynamicWavelet detector

    master

    The DynamicWavelet detector accepts a DynamicWaveletConfig object to specify the audio properties of the input signal.

    KeyTypeDefaultDescription
    sampleRatenumber44100The sampling rate of the audio buffer being analyzed. This is required for accurate frequency calculation.

    Note: The algorithm uses internal constants for MAX_FLWT_LEVELS, MAX_F, DIFFERENCE_LEVELS_N, and MAXIMA_THRESHOLD_RATIO which are not currently exposed via the configuration object.

    export interface DynamicWaveletConfig {
      sampleRate: number;
    }
  10. Configure ACF2+ with sampleRate

    master

    When initializing the ACF2PLUS detector, you can provide a configuration object of type ACF2Config to specify the audio sample rate. This is required to correctly calculate the frequency from the detected period.

    Config Options:

    • sampleRate (number): The sample rate of the input audio buffer (e.g., 44100).
    const config = {
      sampleRate: 44100
    };
    
    const detector = ACF2PLUS(config);
  11. Use the ACF2+ pitch detection algorithm

    master

    The ACF2PLUS function implements the ACF2+ algorithm for pitch detection. It returns a PitchDetector function that accepts a Float32Array of audio samples and returns the detected pitch in Hz. If the signal is too weak (RMS < 0.01), it returns -1.

    To use it, call ACF2PLUS with a configuration object specifying the sampleRate of your audio data.

    import { ACF2PLUS } from 'pitchfinder'; // Note: Import path depends on your project setup
    
    const detector = ACF2PLUS({ sampleRate: 44100 });
    const pitch = detector(new Float32Array([0.1, 0.2, ...]));