Skip to main content

pitch-garden

pitch-garden provides a unified interface to various pitch (F0) trackers and integrates their outputs by voting. The outputs of all trackers are aligned on a common frame grid, so that they can be directly compared and voted.

Manual Downloads ClickPy Python Version PyPI License GitHub Actions Ruff

Features

  • Voting of multiple trackers
  • Two-pass tracking with an F0 search range estimated from the first pass
  • Parallel execution of the trackers

Requirements

  • Python 3.12+

Documentation

Installation

pip install "pitch-garden[all]"  # All trackers

# To avoid installing PyTorch, use the following instead.
# pip install "pitch-garden[lite]"  # Trackers not requiring PyTorch

Supported Algorithms

Name Neural F0 Range [Hz] Voicing Threshold Paper Source
crepe ✓ 32 – 2006 0.1 – 0.4 arXiv GitHub
dio 10 – Nyquist 0.2 – 0.02 AES E-Library GitHub
fcn-f0 ✓ 30 – 1000 0.2 – 0.6 ISCA Archive GitHub
fcpe ✓ 33 – 1975 0.0 – 0.1 arXiv GitHub
harmof0 ✓ 28 – 4371 0.5 – 0.9 arXiv GitHub
harvest 10 – Nyquist 0.2 – 0.0 ISCA Archive GitHub
pesto ✓ 28 – 3452 0.0 – 0.2 arXiv GitHub
pienet ✓ 50 – 500 0.5 – 1.0 IEEE Xplore GitHub
pyin 16 – 8000 IEEE Xplore GitHub
rapt 10 – Nyquist 0.7 – -0.6 EDU GitHub
reaper 10 – Nyquist 1.6 – -0.5 GitHub
rmvpe ✓ 32 – 2005 0.0 – 0.3 arXiv GitHub
straight 40 – Nyquist ISCA Archive GitHub
swift-f0 ✓ 47 – 2093 0.1 – 0.5 arXiv GitHub
swipe 10 – Nyquist 0.2 – 0.5 EDU GitHub
yaapt 10 – Nyquist 0.1 – 1.0 IEEE Xplore GitHub
yin 16 – 8000 0.3 – 0.6 JASA GitHub

The F0 range is the search range that can be specified. The voicing threshold is shown as a typical range, where moving it toward the right value gives more unvoiced frames. pesto is not available on Python 3.15 or later, because the pesto-pitch package requires torchaudio, which does not support those versions. dio, harvest, rapt, reaper, and swipe are based on the implementations in SPTK, and their outputs are compatible with the pitch command of SPTK.

Unsupported Algorithms

Name Neural Paper Source Reason
Basic Pitch ✓ arXiv GitHub Designed for polyphonic transcription
JDCNet ✓ MDPI GitHub PyTorch versions are unlicensed
Kaldi Pitch IEEE Xplore GitHub No maintained Python implementation
MPM EDU Similar to yin
PENN (FCNF0++) ✓ arXiv GitHub Did not outperform fcn-f0 in our evaluation
Praat (Parselmouth) EDU GitHub Licensed under GPL-3.0
SPICE ✓ arXiv Kaggle No PyTorch weights available

Usage

Input preparation

Audio files, headerless raw files, and NumPy arrays are accepted.

import numpy as np

import pitch_garden as pg

tracker = pg.Tracker("rapt")

# An audio file readable by soundfile, where multiple channels are averaged.
audio = pg.load_audio("speech.wav")
pitch = tracker(audio)

# A headerless raw file with a data type of SPTK x2x, e.g., 16-bit integers.
raw = pg.RawFormat(sample_rate=16000, data_type="s", num_channels=1)
audio = pg.load_audio("speech.raw", raw)
pitch = tracker(audio)

# A NumPy array with its sample rate.
sample_rate = 16000
waveform = np.sin(2 * np.pi * 220 * np.arange(sample_rate) / sample_rate)
pitch = tracker(waveform, sample_rate)

Single algorithm

A Tracker holds an algorithm and its own parameters. The F0 search range given by fmin and fmax at the creation is the default of the tracker, and can be overridden only for a call by giving fmin and/or fmax to the call, e.g., if the range is known for each file. The bound not given at the call is taken from the creation, and changing the range does not reload the algorithm. The trackers supporting GPUs, e.g., crepe, use a GPU if available, which is chosen when the tracker is created and can be changed by tracker.replace(device="cpu"). The output Pitch holds the F0 in Hz on a uniform frame grid regardless of the native frame period of the algorithm, and converts it to other formats on demand.

import pitch_garden as pg

audio = pg.load_audio("speech.wav")

tracker = pg.Tracker("rapt", voicing_threshold=0.0, fmin=60.0, fmax=800.0)
pitch = tracker(audio, frame_period=5.0)
print(pitch)
# Pitch(source='rapt', num_frames=100, num_voiced_frames=..., ...)
print(pitch.f0)  # The F0 in Hz as a NumPy array, where unvoiced frames are 0.

# The search range is overridden only for this call, i.e., 80-800 Hz.
pitch = tracker(audio, frame_period=5.0, fmin=80.0)

# The F0 is converted to a NumPy array of another format.
lf0 = pitch.to("log")  # log F0 (unvoiced: -1e10)
period = pitch.to("inverse")  # Fs/F0 in samples (unvoiced: 0)

# The F0 is converted and saved; the pitch object itself is unchanged.
pitch.tofile("speech.lf0", output_format="log", file_type="double")

Multiple algorithms and voting

A Pipeline runs the trackers in parallel where possible and votes their outputs. The same algorithm can be used with different parameters by giving different names. The F0 search range can be given at a call as with Tracker, which overrides the ranges of all trackers supporting it only for the call.

import pitch_garden as pg

audio = pg.load_audio("speech.wav")

trackers = [pg.Tracker("rapt"), pg.Tracker("swift-f0")]
with pg.Pipeline(trackers, voter="median") as pipeline:
    result = pipeline(audio, frame_period=5.0)

# The final contour voted from the trackers as a Pitch object
print(result.pitch)
# Pitch(source='median', num_frames=100, num_voiced_frames=..., ...)

# The outputs of the trackers as Pitch objects keyed by the tracker names
for name, pitch in result.each.items():
    print(name, pitch)
# rapt Pitch(source='rapt', num_frames=100, ...)
# swift-f0 Pitch(source='swift-f0', num_frames=100, ...)

Two-pass tracking

If the F0 range of the speaker is unknown, the trackers are first run with a wide search range, and then rerun with the range estimated from the distribution of the F0 of the first pass. This works with a single tracker as well as multiple ones, where the estimated range is shared by all trackers. The first-pass range is given by TwoPass, and can be overridden only for a call by giving fmin and/or fmax to the call, e.g., if a rough range is known for each file. Each algorithm has its recommended settings chosen in examples/pitch_benchmark, i.e., whether it is rerun and which pass gives the voicing decisions, which can be overridden by two_pass_policy of each tracker.

import pitch_garden as pg
from pitch_garden.ranges.log_normal import LogNormalRangeEstimator

audio = pg.load_audio("speech.wav")

two_pass = pg.TwoPass(estimator=LogNormalRangeEstimator(), fmin=40.0, fmax=2000.0)
with pg.Pipeline([pg.Tracker("rapt")], two_pass=two_pass) as pipeline:
    result = pipeline(audio)

# The estimated range
print(result.f0_range)
# F0Range(fmin=111.96..., fmax=224.08..., num_voiced_frames=..., ...)

# The final contour of the second pass, i.e., the output of the single tracker
print(result.pitch)
# Pitch(source='rapt', num_frames=100, num_voiced_frames=..., ...)

# The result of the first pass, which is of the same type as the final result
print(result.pass1.pitch)
# Pitch(source='rapt', num_frames=100, num_voiced_frames=..., ...)

Command-line interface

The settings are given by a YAML file, and the input and the output directory are given by the command line. The input is an audio file, a directory searched recursively, or a text file listing audio files line by line. See configs/single.yaml for all settings, configs/multiple.yaml for multiple trackers, and configs/two-pass.yaml for the two-pass tracking.

pitch-garden configs/multiple.yaml data/wav -o exp/f0

The main settings for the above use cases are as follows:

trackers:
  - algorithm: rapt
  - algorithm: swift-f0
voter:
  type: median

two_pass:
  scope: group # The unit to estimate the range: utterance, group, or global.
  group_by: {type: dirname, level: 1}

With scope: group, the range is estimated for each group of files, e.g., each speaker. The groups are defined by group_by in either of the following ways:

  • {type: dirname, level: 1} groups the files by their directory level levels above, where level: 1 is the directory containing the files. For example, the files below are grouped into spk1 and spk2 with level: 1, and into a single group data/wav with level: 2.

    data/wav/spk1/a.wav
    data/wav/spk1/b.wav
    data/wav/spk2/c.wav
    
  • {type: map, path: data/speaker.map} groups the files by a text file, where each line is the file name without the extension followed by the group name.

    a spk1
    b spk1
    c spk2
    

With scope: utterance and scope: global, the range is estimated for each file and for all files, respectively.

The final contours are saved under <output_dir>/pitch, which are the voted ones for multiple trackers. For multiple trackers, their outputs are also saved under <output_dir>/trackers/<name> if save_each is enabled or voting is disabled. For the two-pass tracking, the estimated ranges are saved in <output_dir>/f0_range.yaml.

License

This software is released under the Apache License 2.0.

Metadata

Release files for pitch-garden 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pitch-garden 0.1.0
File Size Uploaded Provenance Actions
pitch_garden-0.1.0.tar.gz 73.1 kB With provenance Details for pitch_garden-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for pitch-garden 0.1.0
File Interpreter ABI Platform Actions
pitch_garden-0.1.0-py3-none-any.whl Python 3 none any Details for pitch_garden-0.1.0-py3-none-any.whl

Total release size: 184.6 kB

Release files / pitch_garden-0.1.0.tar.gz

Download URL pitch_garden-0.1.0.tar.gz
Size 73.1 kB
Tags Source
SHA-256 checksum
How to use checksums
1d7bffa113d992c6be5a9035674464b071c41e24458f7ea61330f7c30a412031
BLAKE2b-256 checksum
How to use checksums
5cfc2558b7b8b8bba8312a3b5e6e9a888bae13683c5d960a02d2907f59b02810
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 21, 2026.

Transparency log

Release files / pitch_garden-0.1.0-py3-none-any.whl

Download URL pitch_garden-0.1.0-py3-none-any.whl
Size 111.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
480207770ab82d7299690865457379b2b897e290d20d69a633ffa29a315e16b7
BLAKE2b-256 checksum
How to use checksums
7626ee662f8b41a46a4817964e4e4f6768f92d44a74b585e1599ca91850c85aa
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 21, 2026.

Transparency log

Security for pitch-garden 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for pitch_garden-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 21, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page