pitch_garden#

Tracking#

class pitch_garden.Tracker(algorithm: str | type[BaseAlgorithm], *, name: str | None = None, two_pass_policy: TwoPassPolicy | None = None, **params: Any)[source]#

A class for tracking pitch with an algorithm and its own parameters.

__call__(source: ndarray | Audio, sample_rate: int | None = None, *, frame_period: float = 5.0, fmin: float | None = None, fmax: float | None = None) → Pitch[source]#

Track the pitch of the input audio.

Parameters:
sourcenp.ndarray | Audio

The input waveform with shape (T,) or an Audio object.

sample_rateint | None, optional

The sample rate of the input waveform.

frame_periodfloat, optional

The frame period of the output in milliseconds.

fminfloat | None, optional

The lower bound of the F0 search range in Hz overriding the one given at the creation only for this call. If None, the one given at the creation is used. The range is clipped to the limits of the algorithm, and changing it does not reload the algorithm.

fmaxfloat | None, optional

The upper bound of the F0 search range in Hz, which is given in the same way as fmin.

Returns:
outPitch

The estimated F0 contour.

Raises:
ValueError

If the frame period is invalid, or the search range is invalid or not supported by the algorithm.

Examples

>>> import numpy as np
>>> import pitch_garden as pg
>>> sr = 16000
>>> x = np.sin(2 * np.pi * 220 * np.arange(sr) / sr)
>>> tracker = pg.Tracker("swift-f0", voicing_threshold=0.5)
>>> pitch = tracker(x, sr, frame_period=5.0)
>>> pitch.length
200
property f0_range: tuple[float, float]#

Get the effective F0 search range.

Returns:
outtuple[float, float]

The lower and upper bounds of the F0 search range in Hz.

load() → BaseAlgorithm[source]#

Load the algorithm if it is not loaded yet.

Returns:
outBaseAlgorithm

The loaded algorithm.

property parallel_safe: bool#

Get whether the tracker can be run in a worker process.

Returns:
outbool

True if the tracker can be run in a worker process.

replace(**params: Any) → Tracker[source]#

Create a new tracker with some parameters replaced.

Parameters:
**paramsAny

The parameters to be replaced, including two_pass_policy.

Returns:
outTracker

The new tracker with the same name.

property supports_f0_range: bool#

Get whether the F0 search range can be specified.

Returns:
outbool

True if the F0 search range can be specified.

property two_pass_policy: TwoPassPolicy#

Get the settings of the two-pass tracking.

Returns:
outTwoPassPolicy

The given settings, or the recommended settings of the algorithm.

class pitch_garden.Pipeline(trackers: Sequence[Tracker], voter: BaseVoter | str | None = 'median', *, num_workers: int | None = None, two_pass: TwoPass | None = None, on_error: Literal['skip', 'raise'] = 'skip', mp_context: str = 'spawn')[source]#

A class for the pipeline of tracking, voting, and two-pass tracking.

The pipeline runs one or more trackers, votes their outputs if a voter is given, and reruns them with an estimated F0 search range if the two-pass tracking is enabled. The trackers that can be run in worker processes (CPU-only ones) are run in parallel, and the others are run sequentially in the main process.

__call__(source: ndarray | Audio, sample_rate: int | None = None, *, frame_period: float = 5.0, fmin: float | None = None, fmax: float | None = None) → PipelineResult[source]#

Run the trackers and vote their outputs.

Parameters:
sourcenp.ndarray | Audio

The input waveform with shape (T,) or an Audio object.

sample_rateint | None, optional

The sample rate of the input waveform.

frame_periodfloat, optional

The frame period of the outputs in milliseconds.

fminfloat | None, optional

The lower bound of the F0 search range in Hz overriding the range used first only for this call, i.e., the ranges of the trackers, or the first-pass range of the two-pass tracking. If None, the bound of the overridden range is kept. The trackers not supporting the search range are not affected.

fmaxfloat | None, optional

The upper bound of the F0 search range in Hz, which is given in the same way as fmin.

Returns:
outPipelineResult

The final contour and the outputs of the trackers.

Raises:
ValueError

If the search range is invalid.

close() → None[source]#

Shut down the worker processes.

estimate_f0_range(results: Sequence[PipelineResult]) → F0Range[source]#

Estimate the F0 search range from the results of the first pass.

Parameters:
resultsSequence[PipelineResult]

The results of the first pass, e.g., of all utterances of a speaker.

Returns:
outF0Range

The estimated F0 search range.

Raises:
RuntimeError

If the two-pass tracking is disabled.

ValueError

If the contour giving the range is not found in the results.

first_pass(audio: Audio, *, frame_period: float = 5.0, fmin: float | None = None, fmax: float | None = None) → PipelineResult[source]#

Run the trackers with the first-pass search range and vote their outputs.

If the two-pass tracking is disabled, the trackers are run with their own search ranges.

Parameters:
audioAudio

The input audio.

frame_periodfloat, optional

The frame period of the outputs in milliseconds.

fminfloat | None, optional

The lower bound of the F0 search range in Hz overriding the range used first only for this call, which is given in the same way as in __call__.

fmaxfloat | None, optional

The upper bound of the F0 search range in Hz overriding the range used first only for this call.

Returns:
outPipelineResult

The result of the first pass.

Raises:
ValueError

If the search range is invalid.

second_pass(audio: Audio, first: PipelineResult, f0_range: F0Range, *, frame_period: float = 5.0) → PipelineResult[source]#

Rerun the trackers with the estimated search range and vote the outputs.

Parameters:
audioAudio

The input audio.

firstPipelineResult

The result of the first pass of the same audio.

f0_rangeF0Range

The estimated F0 search range.

frame_periodfloat, optional

The frame period of the outputs in milliseconds.

Returns:
outPipelineResult

The result of the second pass with the estimated range and the result of the first pass.

Raises:
RuntimeError

If the two-pass tracking is disabled.

track(audio: Audio, *, frame_period: float = 5.0, trackers: Sequence[Tracker] | None = None, f0_ranges: Mapping[str, tuple[float, float]] | None = None) → dict[str, Pitch][source]#

Run the trackers.

Parameters:
audioAudio

The input audio.

frame_periodfloat, optional

The frame period of the outputs in milliseconds.

trackersSequence[Tracker] | None, optional

The trackers to be run. If None, all trackers of the pipeline are run.

f0_rangesMapping[str, tuple[float, float]] | None, optional

The F0 search ranges in Hz keyed by the tracker names. The trackers not included or not supporting the search range use their own ranges.

Returns:
outdict[str, Pitch]

The outputs of the trackers keyed by their names, in the given order.

Raises:
Exception

The error of the first failed tracker, regardless of on_error.

class pitch_garden.PipelineResult(pitch: ~pitch_garden.interfaces.types.Pitch | None, each: dict[str, ~pitch_garden.interfaces.types.Pitch], f0_range: ~pitch_garden.ranges.base.F0Range | None = None, pass1: ~pitch_garden.interfaces.pipeline.PipelineResult | None = None, errors: dict[str, str] = <factory>)[source]#

Dataclass to hold the result of the pipeline.

class pitch_garden.TwoPass(estimator: BaseRangeEstimator = <factory>, range_from: str | None = None, fmin: float = 40.0, fmax: float = 2000.0, clip_out_of_range: bool = True)[source]#

Settings of the two-pass tracking with an estimated F0 search range.

In the first pass, the trackers supporting the search range are run with the wide range [fmin, fmax]. The range is then estimated from the distribution of voiced F0 of range_from. In the second pass, the trackers supporting the search range are rerun with the estimated range if their two_pass_policy enables it, and the outputs of the other trackers are reused. Whether each tracker is rerun and which pass gives its voicing decisions are given by Tracker.two_pass_policy. The out-of-range frames of the trackers not supporting the search range, i.e., supports_f0_range=False, are unvoiced if clip_out_of_range, which does not affect the built-in algorithms since all of them support the range.

check_trackers(names: Sequence[str], has_voter: bool) → None[source]#

Check that the settings can be used with the trackers.

Parameters:
namesSequence[str]

The names of the trackers.

has_voterbool

Whether a voter is used.

Raises:
ValueError

If the contour giving the range is unavailable.

class pitch_garden.TwoPassPolicy(enabled: bool = True, voicing_from: Literal['1st', '2nd'] = '2nd')[source]#

The settings of the two-pass tracking for an algorithm or a tracker.

If the voicing is taken from the first pass, the F0 values of the second pass are used for the frames voiced in both passes, and those of the first pass for the frames voiced only in the first pass.

Data#

class pitch_garden.Audio(data: ndarray, sample_rate: int)[source]#

Dataclass to hold monaural audio data.

property duration: float#

Get the duration in seconds.

Returns:
outfloat

The duration in seconds.

property length: int#

Get the number of samples.

Returns:
outint

The number of samples.

class pitch_garden.Pitch(f0: ndarray, frame_period: float, sample_rate: int, source: str, score: ndarray | None = None, native: NativeContour | None = None)[source]#

Dataclass to hold an F0 contour on a uniform frame grid.

The center of the n-th frame is located at n * frame_period milliseconds.

property length: int#

Get the number of frames.

Returns:
outint

The number of frames.

to(output_format: Literal['linear', 'log', 'inverse'] | str) → ndarray[source]#

Convert the F0 contour to the specified format.

Parameters:
output_format[‘linear’, ‘log’, ‘inverse’]

The output format. ‘linear’ is F0 in Hz (unvoiced: 0), ‘log’ is log F0 (unvoiced: -1e10), and ‘inverse’ is the pitch period in samples, i.e., Fs/F0 (unvoiced: 0), where Fs is the sample rate of the source audio. These are compatible with SPTK.

Returns:
outnp.ndarray

The converted contour.

Raises:
ValueError

If the output format is not supported.

to_grid(num_frames: int, frame_period: float) → Pitch[source]#

Put the F0 contour on another uniform frame grid.

The F0 and the score are resampled in the same way as the native contours of trackers, and the frames beyond the last frame of the contour are unvoiced. The native contour is dropped because it is no longer consistent.

Parameters:
num_framesint

The number of frames of the new grid.

frame_periodfloat

The frame period of the new grid in milliseconds.

Returns:
outPitch

The new pitch object.

tofile(path: str, output_format: Literal['linear', 'log', 'inverse'] | str = 'linear', file_type: Literal['npz', 'float', 'double'] | str = 'npz') → None[source]#

Save the F0 contour to a file.

Parameters:
pathstr

The path to the output file.

output_format[‘linear’, ‘log’, ‘inverse’]

The output format.

file_type[‘npz’, ‘float’, ‘double’]

The file type. ‘float’ and ‘double’ are headerless binary files that can be directly processed by SPTK.

Raises:
ValueError

If the output format or the file type is not supported.

property voiced: ndarray#

Get the voiced flags.

Returns:
outnp.ndarray

The boolean array that is True for voiced frames.

with_f0(f0: ndarray, source: str | None = None) → Pitch[source]#

Create a new pitch object with the given F0 contour.

The native contour is dropped because it is no longer consistent.

Parameters:
f0np.ndarray

The new F0 contour in Hz.

sourcestr | None, optional

The new source name. If None, the current one is kept.

Returns:
outPitch

The new pitch object.

with_threshold(threshold: float) → Pitch[source]#

Redo the voicing decision with a new threshold on the voicing score.

The threshold is applied on the native frame grid of the tracker, and the result is resampled onto the frame grid, so that the result is identical to re-extraction with the threshold.

This is available only for the trackers providing the voicing score, e.g., the confidence of neural networks. The voicing decision of the other trackers is made inside their algorithms, and thus requires re-extraction with different parameters.

Parameters:
thresholdfloat

The frames whose score is greater than or equal to the threshold are regarded as voiced.

Returns:
outPitch

The new pitch object.

Raises:
ValueError

If the voicing score is not available.

Input#

pitch_garden.load_audio(path: str, raw: RawFormat | None = None) → Audio[source]#

Load an audio file as monaural audio.

Parameters:
pathstr

The path to the audio file.

rawRawFormat | None, optional

The format of raw files. The files with its extensions are read as raw. If None, no file is read as raw.

Returns:
outAudio

The loaded audio, where multiple channels are averaged.

Raises:
FileNotFoundError

If the file does not exist.

ValueError

If the file cannot be read as audio without the format of raw files.

class pitch_garden.RawFormat(sample_rate: int, data_type: Literal['c', 'C', 's', 'S', 'h', 'H', 'i', 'I', 'l', 'L', 'f', 'd']='s', num_channels: int = 1, extensions: list[str] = <factory>)[source]#

The format of headerless raw audio files.

is_raw(path: str) → bool[source]#

Check whether the file is regarded as raw by its extension.

Parameters:
pathstr

The path to the file.

Returns:
outbool

True if the file is regarded as raw.