For each token, replaces the native pitch-frame grid with n points
equally spaced between the token's first and last frame time, so every
token contributes the same number of samples at the same proportional
positions (with n = 21, one point every 5% of the token's duration;
with n = 11, every 10%). Intended for monosyllabic (single-contour)
tokens; for multisyllabic data, TextGrid landmark axes (see
normalise_time_landmarks()) are usually the better route.
Usage
resample_f0_equal(
df,
n = 21,
token = "token",
time = "time",
f0 = "f0",
intensity = "intensity",
method = c("linear", "nearest")
)Arguments
- df
Long-format f0 data frame.
- n
Number of points per token (at least 2). Default
21.- token, time, f0
Column names. Defaults
"token","time","f0".- intensity
Name of the optional intensity column; used only when present in
df. Default"intensity".- method
How each point takes its value, mirroring the two interpolation choices Praat offers in
Pitch: Get value at time...:"linear"(default, and Praat's own default) applies the rule in Details;"nearest"always takes the value of the frame the point falls in, and isNAwhen that frame is unvoiced, so nothing is ever computed.
Value
A data frame with the token, point (measurement number,
1...n), time (seconds, on the new grid), time_prop
(proportional position 0-1 within the token), and f0 columns, plus
intensity (when present) and any carried token-constant columns.
Input columns named point or time_prop are dropped, since those
names are computed here. Rows are sorted by time within each token;
tokens keep their order of first appearance. The attribute
dropped_columns names any columns that could not be carried.
Details
f0 at each new point follows Praat's own rule for
Pitch: Get value at time... Linear (Sampled_getValueAtX() in
Praat's source), so a contour resampled here matches one extracted by
a Praat script querying the same times. Of the two native frames
bracketing the point, call the closer one near and the other far:
both voiced: the value is linearly interpolated between them;
far unvoiced: the point takes the near frame's measured value, so no value is blended across an unvoiced frame while a usable measurement at the edge of one is not thrown away;
near unvoiced: the point is
NA, since nothing was measured there.
A point landing exactly on a frame has a phase of 0 and therefore takes that frame's value exactly. At a point falling exactly midway between two frames the choice of near is a floating-point tie and may fall either way; it only changes the answer when exactly one of the two is unvoiced.
This rests on unvoiced frames being present as NA (or 0 Hz) rows,
which is how the wrassp and .Pitch paths deliver them. Sparse input
carries no such rows: a .PitchTier, or a CSV listing only voiced
samples, represents an unvoiced stretch as nothing more than a wide gap
between two voiced anchors, so both bracketing frames are voiced and the
point is interpolated straight across. Praat does the same on a PitchTier.
Add explicit NA rows if such stretches should read as unvoiced.
With method = "nearest" (Praat's other option) the middle case goes
away: a point always takes the nearer frame's measured value, or NA
when that frame is unvoiced. Every exported value is then a number the
tracker produced, at the cost of a timing error of up to half a frame
step.
If an intensity column is present, it is linearly interpolated
across all frames with finite intensity (ends extended, matching how
the extraction aligns the intensity track to the f0 frames).
Any other column is carried through when it is constant within every
token (metadata, token_dropped, and similar token-level columns);
per-frame columns that vary within a token cannot survive a change of
grid and are dropped — their names are recorded in the
dropped_columns attribute of the result.
Rows with a missing time are dropped, and rows sharing a frame time
are collapsed to the first of them, so interpolation has strictly
increasing anchors. A token left with fewer than two distinct frame
times cannot be resampled and keeps its single remaining row, with
time_prop = 0.5.
See also
normalise_time_token() for adding a proportional time
column without changing the sampling grid.
