Skip to main content

RIN (Relative Interval Networks)

This is the reference implementation accompanying the paper Pitch Smoothing Using Relative Interval Networks, submitted to ICASSP 2027. We propose a method for smoothing pitch estimates by combining absolute pitch measurements with multi-hop relative pitch differences, using a network-flow linear program for optimal fusion. Specifically, we solve the following objective function:

\min_{\mathbf{f}} \mathbf{w}^\top \lvert \mathbf{B}^\top \mathbf{f} - \mathbf{\Delta} \rvert,

where $\mathbf{f}$ is the vector of smoothed pitch estimates, $\mathbf{\Delta}$ is the vector of observed absolute pitch and relative pitch differences, $\mathbf{B}$ is the incidence matrix encoding the absolute and relative edges, and $\mathbf{w}$ is a vector of weights.

Install

With pixi (recommended):

pixi install

Or with pip:

pip install rin-pitch

Quickstart

import numpy as np
from rin import smooth_pitch

# x: mono waveform, sr: sample rate
# f0: (M,) absolute pitch in cents on a 20 ms grid, NaN = unvoiced
# strength: (M,) voicing confidence in [0, 1]
hop_length = int(0.02 * sr)

# the paper's pipeline in one call: VQT relative diffs -> dual LP fusion
# -> voicing, with the paper's fixed settings (hops 1,2,3,5; Pearson xcorr;
# arcsin x peak2mean weighting)
f0_smooth, voicing = smooth_pitch(x, f0, strength, sr, hop_length)

The package never converts pitch units: absolute and relative estimates must share one pitch domain (the built-in estimator outputs cents), and converting to or from your own domain (Hz, MIDI, ...) is your responsibility.

If your tracker reports Hz, convert before calling; smooth_pitch expects cents and will not convert for you:

voiced = np.isfinite(f0_hz)
f0_cents = np.where(voiced, 1200 * np.log2(np.where(voiced, f0_hz, 1.0)), np.nan)
f0_smooth, voicing = smooth_pitch(x, f0_cents, strength, sr, hop_length)

Arrays in, arrays out: the package does no file loading and no caching.

API

One high-level function plus three cores:

  • rin.smooth_pitch(x, f0, strength, sr, hop_length, hops=(1, 2, 3, 5), ...) runs the paper's pipeline in one call: VQT relative diffs, dual LP fusion, and voicing. f0 in cents with NaN = unvoiced; returns (f0_smooth, voicing) in cents. f0 must sit on the same hop_length grid as the audio, and smooth_pitch raises if it does not. Each stage is swappable via difference_estimator, solver, and voicing_estimator keyword arguments (any callable obeying the rin.interfaces contracts); configure a stage with functools.partial, e.g. difference_estimator=partial(vqt_diff_calculator, max_diff_cents=500.0).

Three core functions (for custom wiring):

  • rin.vqt_diff_calculator(x, sr, hop_length, hops=(1,), ...) returns multi-hop relative pitch differences (cents) with confidences. Uses the paper's fixed estimation path: Pearson (mean-subtracted) normalized cross-correlation of VQT magnitude slices with the arcsin x peak2mean confidence weighting. max_diff_cents (600), bins_per_octave (36), n_bins (252), and other VQT options are plain kwargs, so pass your own. max_diff_cents must stay inside the VQT's range: it has to buy at least one bin of search and fewer than n_bins of it, or the correlation window runs off the spectrogram.
  • rin.lp_smoother(abs_estimates, abs_confidences, rel_edges, rel_estimates, rel_confidences) does network-flow LP fusion (dual min-cost circulation, HiGHS); absolute and relative estimates must share one pitch domain (caller's choice, e.g. cents).
  • rin.estimate_voicing(abs_confidences, rel_edges, rel_confidences) returns per-frame voicing probabilities from the two confidence streams.

Plugins

Each core is a plain function obeying a contract in rin.interfaces (DifferenceEstimator, Solver, and VoicingEstimator are Callable type aliases). Implement your own function with the same signature and pass it to smooth_pitch, or call it directly in your own wiring. No classes or inheritance needed; any callable (function, lambda, functools.partial, callable object) works:

from functools import partial

from rin import smooth_pitch, vqt_diff_calculator


def my_estimator(x, sr, hop_length, hops):
    # -> (edges (E,2) int, estimates (E,) cents, confidences (E,) in [0,1])
    ...


def my_solver(abs_estimates, abs_confidences, rel_edges, rel_estimates, rel_confidences):
    # -> smooth_pitch (M,) cents
    ...


def my_voicing(abs_confidences, rel_edges, rel_confidences):
    # -> voicing (M,) in [0,1]
    ...


# One call, custom stages (tune a stage via functools.partial):
f0_smooth, voicing = smooth_pitch(
    x,
    f0,
    strength,
    sr,
    hop_length,
    difference_estimator=partial(vqt_diff_calculator, max_diff_cents=500.0),
    solver=my_solver,
    voicing_estimator=my_voicing,
)

# ...or wire them by hand:
edges, estimates, confidences = my_estimator(x, sr, hop_length, hops=(1, 2, 3, 5))
smooth_cents = my_solver(f0_cents, abs_conf, edges, estimates, confidences)
voicing = my_voicing(abs_conf, edges, confidences)

Development

pixi run test        # pytest with branch coverage
pixi run lint        # ruff check
pixi run docstrings  # numpydoc validation of the public API
pixi run format      # ruff format
pixi run build       # sdist + wheel
pixi run smoke       # install the built wheel in a clean venv and check its version

CI runs lint and docstrings once, and test on Linux, macOS and Windows across Python 3.10-3.13 (pixi run -e py310 test reproduces one cell locally).

The version comes from the git tag (no file in the repo declares one), so a release is git tag v1.1.0 && git push --tags, which builds and publishes to PyPI.

License

MIT

Metadata

Release files for rin-pitch 1.0.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 rin-pitch 1.0.0
File Size Uploaded
rin_pitch-1.0.0.tar.gz 162.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for rin-pitch 1.0.0
File Interpreter ABI Platform
rin_pitch-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 178.0 kB

Release files / rin_pitch-1.0.0.tar.gz

Download URL rin_pitch-1.0.0.tar.gz
Size 162.5 kB
Tags Source
SHA-256 checksum
How to use checksums
ab86ae8edea3b1fc64123b866b4c1550014512fad25955a520e594dee112f719
BLAKE2b-256 checksum
How to use checksums
a442ce616e4301b9b4921f27246ac6430bde124f48f9c91ca9210c47fff28853
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 1, 2026.

Transparency log

Release files / rin_pitch-1.0.0-py3-none-any.whl

Download URL rin_pitch-1.0.0-py3-none-any.whl
Size 15.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
10984bea784fdffec8c6f85e46944534e95fe9560037d8d3ac7879b04544e393
BLAKE2b-256 checksum
How to use checksums
2163010954ccce412e3fdafc28801524b03df9d1de1bd55f6cce139b3a97e232
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 1, 2026.

Transparency log

Release history Release notifications | RSS feed

1.0.2

2 release files

1.0.1

2 release files

This release

1.0.0 This release

2 release files

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