diff --git a/src/parselmouth.cpp b/src/parselmouth.cpp
index 44c60a0d..be30880e 100644
--- a/src/parselmouth.cpp
+++ b/src/parselmouth.cpp
@@ -35,7 +35,6 @@ Thing_declare(Daata);
Thing_declare(Formant);
Thing_declare(Function);
Thing_declare(Harmonicity);
-Thing_declare(Harmonicity);
Thing_declare(Intensity);
Thing_declare(Matrix);
Thing_declare(MFCC);
@@ -119,6 +118,7 @@ using PraatBindings = Bindings
*/
+#include
+#include
+
+#include
+
#include "Parselmouth.h"
+#include "Harmonicity_docstrings.h"
#include "TimeClassAspects.h"
#include
@@ -31,13 +37,147 @@ namespace parselmouth {
PRAAT_CLASS_BINDING(Harmonicity) {
addTimeFrameSampledMixin(*this);
- // TODO Get value in frame
+ doc() = HARMONICITY_CLASS_DOCSTRING;
+
+ // TODO Mixins (or something else?) for TimeFrameSampled, TimeFunction, and
+ // TimeVector functionality
+
+ def(py::init([](std::vector data, std::optional T,
+ double tmin, double tmax, std::optional t1) {
+ // set domain and sample interval
+ auto n = data.size();
+ auto tfirst = t1 ? *t1 : tmin;
+ if (tmax <= tfirst && (!T || *T <= 0))
+ throw std::invalid_argument("Neither positive dt is defined nor "
+ "end_time > t1");
+
+ if (tmax <= tfirst) tmax = tmin + *T * n;
+ double dt = T ? *T : (tmax - tmin) / double(n);
+
+ // create Praat object & copy the data
+ auto self = Harmonicity_create(tmin, tmax, n, dt, tfirst);
+ std::copy(data.begin(), data.end(), self->z.cells);
+ return self;
+ }),
+ "data"_a, "time_step"_a = nullptr, "start_time"_a = 0.0,
+ "end_time"_a = 0.0, "t1"_a = nullptr);
+
+ // Make PointProcess class a s sequence-like Python class
+ def(
+ "__getitem__",
+ [](Harmonicity self, long i) {
+ if (i < 0) i += self->nx;
+ if (i < 0 || i >= self->nx)
+ throw std::out_of_range("index out of range");
+ return self->z[1][i + 1];
+ },
+ "i"_a);
+
+ def("__len__", [](Harmonicity self) { return self->nx; });
+
+ def(
+ "__iter__",
+ [](Harmonicity self) {
+ return py::make_iterator(self->z.cells, self->z.cells + self->nx);
+ },
+ py::keep_alive<0, 1>());
+
+ // Harmonicity: Get value at time...
+ def(
+ "get_value",// TODO Should be part of Vector class
+ [](Harmonicity self, double time,
+ kVector_valueInterpolation interpolation) {
+ return Vector_getValueAtX(self, time, 1, interpolation);
+ },
+ "time"_a, "interpolation"_a = kVector_valueInterpolation::CUBIC,
+ GET_VALUE_DOCSTRING);
+
+ // Harmonicity: Get value in frame...
+ def(
+ "get_value_in_frame",
+ [](Harmonicity self, int frameNumber) {
+ return (frameNumber < 1 || frameNumber > self->nx
+ ? undefined
+ : self->z[1][frameNumber]);
+ },
+ "frame_number"_a, GET_VALUE_IN_FRAME_DOCSTRING);
+
+ // Harmonicity: Formula...
+ // def(
+ // "formula",
+ // [](Harmonicity self, conststring32 formula) {
+ // Interpreter interpreter;
+ // return Matrix_formula(self, formula, interpreter, nullptr);
+ // },
+ // "formula"_a);
+
+ // Harmonicity: Get maximum...
+ def(
+ "get_maximum",
+ [](Harmonicity self, double fromTime, double toTime,
+ kVector_peakInterpolation interpolation) {
+ return Vector_getMaximum(self, fromTime, toTime, interpolation);
+ },
+ "from_time"_a = 0.0, "to_time"_a = 0.0,
+ "interpolation"_a = kVector_peakInterpolation::PARABOLIC,
+ GET_MAXIMUM_DOCSTRING);
+
+ // Harmonicity: Get mean...
+ def(
+ "get_mean",
+ [](Harmonicity self, double fromTime, double toTime) {
+ return Harmonicity_getMean(self, fromTime, toTime);
+ },
+ "from_time"_a = 0.0, "to_time"_a = 0.0, GET_MEAN_DOCSTRING);
+
+ // Harmonicity: Get minimum...
+ def(
+ "get_minimum",
+ [](Harmonicity self, double fromTime, double toTime,
+ kVector_peakInterpolation interpolation) {
+ return Vector_getMinimum(self, fromTime, toTime, interpolation);
+ },
+ "from_time"_a = 0.0, "to_time"_a = 0.0,
+ "interpolation"_a = kVector_peakInterpolation::PARABOLIC,
+ GET_MINIMUM_DOCSTRING);
+
+ // Harmonicity: Get standard deviation...
+ def(
+ "get_standard_deviation",
+ [](Harmonicity self, double fromTime, double toTime) {
+ return Harmonicity_getStandardDeviation(self, fromTime, toTime);
+ },
+ "from_time"_a = 0.0, "to_time"_a = 0.0, GET_STANDARD_DEVIATION_DOCSTRING);
+
+ // Harmonicity: Get time of maximum...
+ def(
+ "get_time_of_maximum",
+ [](Harmonicity self, double fromTime, double toTime,
+ kVector_peakInterpolation interpolation) {
+ return Vector_getXOfMaximum(self, fromTime, toTime, interpolation);
+ },
+ "from_time"_a = 0.0, "to_time"_a = 0.0,
+ "interpolation"_a = kVector_peakInterpolation::PARABOLIC,
+ GET_TIME_OF_MAXIMUM_DOCSTRING);
- // TODO Mixins (or something else?) for TimeFrameSampled, TimeFunction, and TimeVector functionality
+ // Harmonicity: Get time of minimum...
+ def(
+ "get_time_of_minimum",
+ [](Harmonicity self, double fromTime, double toTime,
+ kVector_peakInterpolation interpolation) {
+ return Vector_getXOfMinimum(self, fromTime, toTime, interpolation);
+ },
+ "from_time"_a = 0.0, "to_time"_a = 0.0,
+ "interpolation"_a = kVector_peakInterpolation::PARABOLIC,
+ GET_TIME_OF_MINIMUM_DOCSTRING);
- def("get_value", // TODO Should be part of Vector class
- [](Harmonicity self, double time, kVector_valueInterpolation interpolation) { return Vector_getValueAtX(self, time, 1, interpolation); },
- "time"_a, "interpolation"_a = kVector_valueInterpolation::CUBIC);
+ // double Harmonicity_getQuantile (Harmonicity me, double quantile) {
+ def(
+ "get_quantile",
+ [](Harmonicity self, double quantile) {
+ return Harmonicity_getQuantile(self, quantile);
+ },
+ "quantile"_a, GET_QUANTILE_DOCSTRING);
}
-} // namespace parselmouth
+}// namespace parselmouth
diff --git a/src/parselmouth/Harmonicity_docstrings.h b/src/parselmouth/Harmonicity_docstrings.h
new file mode 100644
index 00000000..2f3bb45e
--- /dev/null
+++ b/src/parselmouth/Harmonicity_docstrings.h
@@ -0,0 +1,257 @@
+namespace parselmouth {
+
+
+constexpr auto HARMONICITY_CLASS_DOCSTRING = R"(Praat Harmonicity.
+
+A sequence object contain measures of the degree of acoustic periodicity,
+also called Harmonics-to-Noise Ratio (HNR). Harmonicity is expressed in dB.
+
+In the most use cases, `parselmouth.Harmonicity` objects are generated from
+`parselmouth.Sound` objects with the `parselmouth.Sound.to_harmonicity()`
+method. To constuct manually, use the following parameters.
+
+Parameters
+----------
+data : array_like of float
+ Harmonicity measure samples
+
+time_step : float, optional
+ Time increment between two successive samples in seconds. If omitted,
+ a valid `end_time` must be specified.
+
+start_time : float, default=0.0
+ Starting time of the analysis domain in seconds
+
+end_time : float, default=0.0
+ Ending time of the analysis domain in seconds. If <= `t1`, it is set to
+ cover all the samples in `data.
+
+t1 : float, optional
+ Time of the first harmonicity sample in seconds. If omitted, it is set
+ to `start_time`.
+
+Attributes
+----------
+t1 : float, readonly
+ Time of the first harmonicity sample in seconds
+time_step : float, readonly
+ Time increment between two successive samples in seconds
+start_time : float, readonly
+ Starting time of the analysis domain in seconds
+end_time : float, readonly
+ Ending time of the analysis domain in seconds
+
+Methods
+-------
+get_value(time, interpolation="CUBIC")
+ Get (interpolated) harmonicity value at the specified `time`
+
+get_value_in_frame(frame_number)
+ Get harmonicity value at the specified analysis (1-based) frame number
+
+formula(formula)
+ Modify the harmonicity data according to Praat script command
+
+get_maximum(from_time=0.0, to_time=0.0, interpolation="PARABOLIC")
+ Get maximum harmonicity value in the specified time range
+
+get_mean(from_time=0.0, to_time=0.0)
+ Get mean harmonicity value in the specified time range
+
+get_minimum(from_time=0.0, to_time=0.0, interpolation="PARABOLIC")
+ Get minimum harmonicity value in the specified time range
+
+get_standard_deviation(from_time=0.0, to_time=0.0)
+ Get standard deviation of the harmonicity values in the specified time
+ range
+
+get_time_of_maximum(from_time=0.0, to_time=0.0, interpolation="PARABOLIC")
+ Get the time when the maximum value is observed in the time range
+
+get_time_of_minimum(from_time=0.0, to_time=0.0, interpolation="PARABOLIC")
+ Get the time when the minimum value is observed in the time range
+
+get_quantile(quantile)
+ Get the quantile of the harmonicity samples, expressed in dB
+
+See Also
+--------
+:praat:`Harmonicity`
+)";
+
+constexpr auto GET_VALUE_DOCSTRING = R"(Get estimated local HNR
+
+Returns the HNR estimate (in dB) at a specified time. If this time is
+outside the time domain or outside the samples of the Harmonicity, the
+result is undefined.
+
+Parameters
+----------
+time : double
+ The time at which the value is evaluated
+
+interpolation : {'NEAREST', 'LINEAR', 'CUBIC', 'SINC70', 'SINC700'},
+ default='CUBIC'
+ The interpolation method.
+
+See Also
+--------
+:praat:`Harmonicity: Get value at time...`
+)";
+
+constexpr auto GET_VALUE_IN_FRAME_DOCSTRING = R"(Get local HNR
+
+Returns the HNR in dB. If the index is less than 1 or greater than the
+number of frames, the result is undefined.
+
+Parameters
+----------
+frame_number : int
+ The 1-base index of the target frame
+
+See Also
+--------
+:praat:`Harmonicity: Get value in frame...`
+)";
+
+constexpr auto GET_MAXIMUM_DOCSTRING = R"(Get maximum HNR
+
+Returns the maximum HNR, expressed in dB.
+
+Parameters
+----------
+from_time : double=0.0
+ The starting time of the analysis time domain.
+
+to_time : double=0.0
+ The ending time of the analysis time domain. Values outside this domain
+ are ignored. If `to_time` is not greater than `from_time`, the entire
+ time domain of the Harmonicity object is considered.
+
+interpolation : {'NONE', 'PARABOLIC', 'CUBIC', 'SINC70', 'SINC700'},
+ default='PARABOLIC'
+ The method of vector peak interpolation.
+
+See Also
+--------
+:praat:`Harmonicity: Get maximum...`
+)";
+
+constexpr auto GET_MEAN_DOCSTRING = R"(Get mean HNR
+
+Returns the mean HNR, expressed in dB.
+
+Parameters
+----------
+from_time : double=0.0
+ The starting time of the analysis time domain.
+
+to_time : double=0.0
+ The ending time of the analysis time domain. Values outside this domain
+ are ignored. If `to_time` is not greater than `from_time`, the entire
+ time domain of the Harmonicity object is considered.
+
+See Also
+--------
+:praat:`Harmonicity: Get mean...`
+)";
+
+constexpr auto GET_MINIMUM_DOCSTRING = R"(Get minimum HNR
+
+Returns the minimum HNR, expressed in dB.
+
+Parameters
+----------
+from_time : double=0.0
+ The starting time of the analysis time domain.
+
+to_time : double=0.0
+ The ending time of the analysis time domain. Values outside this domain
+ are ignored. If `to_time` is not greater than `from_time`, the entire
+ time domain of the Harmonicity object is considered.
+
+interpolation : {'NONE', 'PARABOLIC', 'CUBIC', 'SINC70', 'SINC700'},
+ default='PARABOLIC'
+ The method of vector peak interpolation.
+
+See Also
+--------
+:praat:`Harmonicity: Get minimum...`
+)";
+
+constexpr auto GET_STANDARD_DEVIATION_DOCSTRING = R"(Get HNR standard deviation
+
+Returns the standard deviation of the HNR samples, expressed in dB.
+
+Parameters
+----------
+from_time : double=0.0
+ The starting time of the analysis time domain.
+
+to_time : double=0.0
+ The ending time of the analysis time domain. Values outside this domain
+ are ignored. If `to_time` is not greater than `from_time`, the entire
+ time domain of the Harmonicity object is considered.
+
+See Also
+--------
+:praat:`Harmonicity: Get standard deviation...`
+)";
+
+constexpr auto GET_TIME_OF_MAXIMUM_DOCSTRING = R"(Get time of maximum HNR
+
+Returns the time (in seconds) associated with the maximum HNR value.
+
+Parameters
+----------
+from_time : double=0.0
+ The starting time of the analysis time domain.
+
+to_time : double=0.0
+ The ending time of the analysis time domain. Values outside this domain
+ are ignored. If `to_time` is not greater than `from_time`, the entire
+ time domain of the Harmonicity object is considered.
+
+interpolation : {'NONE', 'PARABOLIC', 'CUBIC', 'SINC70', 'SINC700'},
+ default='PARABOLIC'
+ The method of vector peak interpolation.
+
+See Also
+--------
+:praat:`Harmonicity: Get time of maximum...`
+)";
+
+constexpr auto GET_TIME_OF_MINIMUM_DOCSTRING = R"(Get time of minimum HNR
+
+Returns the time (in seconds) associated with the minimum HNR value.
+
+Parameters
+----------
+from_time : double=0.0
+ The starting time of the analysis time domain.
+
+to_time : double=0.0
+ The ending time of the analysis time domain. Values outside this domain
+ are ignored. If `to_time` is not greater than `from_time`, the entire
+ time domain of the Harmonicity object is considered.
+
+interpolation : {'NONE', 'PARABOLIC', 'CUBIC', 'SINC70', 'SINC700'},
+ default='PARABOLIC'
+ The method of vector peak interpolation.
+
+See Also
+--------
+:praat:`Harmonicity: Get time of minimum...`
+)";
+
+constexpr auto GET_QUANTILE_DOCSTRING = R"(Get quantile of HNR samples
+
+Returns the quantile of the HNR samples, expressed in dB.
+
+Parameters
+----------
+quantile : double
+ Quantile to compute, which must be between 0 and 1 inclusive.
+)";
+
+}// namespace parselmouth
diff --git a/src/parselmouth/Parselmouth.h b/src/parselmouth/Parselmouth.h
index 1cb7f18d..ae804ece 100644
--- a/src/parselmouth/Parselmouth.h
+++ b/src/parselmouth/Parselmouth.h
@@ -34,6 +34,7 @@ enum class kSound_windowShape;
enum class kSounds_convolve_scaling;
enum class kSounds_convolve_signalOutsideTimeDomain;
enum class kVector_valueInterpolation;
+enum class kVector_peakInterpolation;
namespace parselmouth::detail {
@@ -94,6 +95,7 @@ namespace parselmouth {
enum class SoundFileFormat;
using ValueInterpolation = kVector_valueInterpolation;
+using PeakInterpolation = kVector_peakInterpolation;
using WindowShape = kSound_windowShape;
using AmplitudeScaling = kSounds_convolve_scaling;
using SignalOutsideTimeDomain = kSounds_convolve_signalOutsideTimeDomain;
diff --git a/src/parselmouth/Pitch.cpp b/src/parselmouth/Pitch.cpp
index 00195485..d847fc49 100644
--- a/src/parselmouth/Pitch.cpp
+++ b/src/parselmouth/Pitch.cpp
@@ -21,6 +21,10 @@
#include "TimeClassAspects.h"
+// Added by @hokiedsp on 2/17/21
+#include "Pitch_docstrings.h"
+// End added by @hokiedsp on 2/17/21
+
#include "utils/praat/MelderUtils.h"
#include "utils/pybind11/ImplicitStringToEnumConversion.h"
#include "utils/pybind11/NumericPredicates.h"
@@ -148,7 +152,7 @@ PRAAT_CLASS_BINDING(Pitch) {
"from_time"_a = std::nullopt, "to_time"_a = std::nullopt, "sampling_frequency"_a = 44100.0, "round_to_nearest_zero_crossing"_a = true);
def("count_voiced_frames",
- &Pitch_countVoicedFrames);
+ &Pitch_countVoicedFrames);
def("get_value_at_time",
[](Pitch self, double time, kPitch_unit unit, kVector_valueInterpolation interpolation) {
@@ -228,15 +232,15 @@ PRAAT_CLASS_BINDING(Pitch) {
&Pitch_interpolate);
def("smooth",
- args_cast<_, Positive<_>>(Pitch_smooth),
- "bandwidth"_a = 10.0);
+ args_cast<_, Positive<_>>(Pitch_smooth),
+ "bandwidth"_a = 10.0);
def("subtract_linear_fit",
&Pitch_subtractLinearFit,
- "unit"_a = kPitch_unit::HERTZ);
+ "unit"_a = kPitch_unit::HERTZ);
def("kill_octave_jumps",
- &Pitch_killOctaveJumps);
+ &Pitch_killOctaveJumps);
// TODO To PitchTier: depends on PitchTier
@@ -368,6 +372,59 @@ PRAAT_CLASS_BINDING(Pitch) {
},
"from_time"_a = std::nullopt, "to_time"_a = std::nullopt);
+ // Added by @hokiedsp on 2/17/21
+ def(
+ "get_mean", &Pitch_getMean,
+ "from_time"_a = 0.0, "to_time"_a = 0.0, "unit"_a = "HERTZ",
+ GET_MEAN_DOCSTRING);
+
+ def(
+ "get_mean_strength", [](Pitch self, std::string type, double tmin, double tmax) {
+ const int strengthUnit =
+ (type == "ac") ? Pitch_STRENGTH_UNIT_AUTOCORRELATION :
+ (type == "nhr") ? Pitch_STRENGTH_UNIT_NOISE_HARMONICS_RATIO :
+ (type == "hnr_db") ? Pitch_STRENGTH_UNIT_HARMONICS_NOISE_DB : -1;
+
+ if (strengthUnit < 0)
+ throw py::value_error("Invalid mean strength measure type specified.");
+
+ return Pitch_getMeanStrength(self, tmin, tmax, strengthUnit);
+ },
+ "type"_a = "hnr_db", "from_time"_a = 0.0, "to_time"_a = 0.0,
+ GET_MEAN_STRENGTH_DOCSTRING);
+
+ def(
+ "get_quantile", [](Pitch self, double quantile, double tmin, double tmax, kPitch_unit unit) {
+ return Pitch_getQuantile(self, tmin, tmax, quantile, unit);
+ },
+ "quantile"_a, "from_time"_a = 0.0, "to_time"_a = 0.0, "unit"_a = "HERTZ", GET_QUANTILE_DOCSTRING);
+
+ def(
+ "get_standard_deviation", &Pitch_getStandardDeviation, "from_time"_a = 0.0, "to_time"_a = 0.0, "unit"_a = "HERTZ",
+ GET_STANDARD_DEVIATION_DOCSTRING);
+
+ def(
+ "get_minimum", &Pitch_getMinimum, "from_time"_a = 0.0, "to_time"_a = 0.0, "unit"_a = "HERTZ", "interpolate"_a = true,
+ GET_MINIMUM_DOCSTRING);
+
+ def(
+ "get_maximum", &Pitch_getMaximum, "from_time"_a = 0.0, "to_time"_a = 0.0, "unit"_a = "HERTZ", "interpolate"_a = true,
+ GET_MAXIMUM_DOCSTRING);
+
+ def(
+ "get_fraction_of_locally_unvoiced_frames",
+ [](Pitch self, double tmin, double tmax, double ceiling,
+ double silenceThreshold, double voicingThreshold) {
+ MelderFraction out = Pitch_getFractionOfLocallyUnvoicedFrames(self, tmin, tmax, ceiling,
+ silenceThreshold, voicingThreshold);
+
+ return std::make_tuple(out.numerator / out.denominator, out.numerator, out.denominator);
+ },
+ "from_time"_a = 0.0, "to_time"_a = 0.0, "to_pitch"_a = 600.0, "silence_threshold"_a = 0.03,
+ "voicing_threshold"_a = 0.45, GET_FRACTION_OF_LOCALLY_UNVOICED_FRAMES_DOCSTRING);
+
+ // End added by @hokiedsp on 2/17/21
+
// TODO Pitch_Intensity_getMean & Pitch_Intensity_getMeanAbsoluteSlope ? (cfr. Intensity)
}
diff --git a/src/parselmouth/Pitch_docstrings.h b/src/parselmouth/Pitch_docstrings.h
new file mode 100644
index 00000000..23a85675
--- /dev/null
+++ b/src/parselmouth/Pitch_docstrings.h
@@ -0,0 +1,187 @@
+namespace parselmouth
+{
+
+constexpr auto GET_MEAN_STRENGTH_DOCSTRING = R"(Get mean pitch strength measure
+
+Returns the value of user-selected measure of the periodicity strength.
+
+Parameters
+----------
+type : {'ac', 'nhr', 'hnr_db'}, default="hnr_db"
+ Type of strength measure to compute
+
+from_time : double, default=0.0
+ The start time of the compuation. Use 0.0 to start with the first
+ available frame
+
+end_time : double, default=0.0
+ The end time of the compuation. Use 0.0 to end with the last available
+ frame
+
+See Also
+--------
+:praat:`Voice report`
+)";
+
+
+constexpr auto GET_MEAN_DOCSTRING = R"(Get mean frequency
+
+Returns the mean of periodicity frequency in the specified unit.
+
+Parameters
+----------
+from_time : double, default=0.0
+ The start time of the compuation. Use 0.0 to start with the first
+ available frame
+
+end_time : double, default=0.0
+ The end time of the compuation. Use 0.0 to end with the last available
+ frame
+
+unit : {'HERTZ','HERTZ_LOGARITHMIC','MEL','LOG_HERTZ','SEMITONES_1',
+ 'SEMITONES_100','SEMITONES_200','SEMITONES_440','ERB'},
+ default=HERTZ
+ Frequency unit
+
+See Also
+--------
+:praat:`Voice report`
+)";
+
+constexpr auto GET_MAXIMUM_DOCSTRING = R"(Get maximum frequency
+
+Returns the maximum frequency in the specified unit
+
+Parameters
+----------
+from_time : double=0.0
+ The starting time of the analysis time domain.
+
+to_time : double=0.0
+ The ending time of the analysis time domain. Values outside this domain
+ are ignored. If `to_time` is not greater than `from_time`, the entire
+ time domain of the Pitch object is considered.
+
+unit : {'HERTZ','HERTZ_LOGARITHMIC','MEL','LOG_HERTZ','SEMITONES_1',
+ 'SEMITONES_100','SEMITONES_200','SEMITONES_440','ERB'},
+ default=HERTZ
+ Frequency unit
+
+interpolate : bool, default=True
+ True to evalaute parabolically interpolated pitch peaks; False to
+ select the raw frequency samples.
+
+See Also
+--------
+:praat:`Voice report`
+)";
+
+constexpr auto GET_MINIMUM_DOCSTRING = R"(Get minimum frequency
+
+Returns the minimum frequency in the specified unit
+
+Parameters
+----------
+from_time : double=0.0
+ The starting time of the analysis time domain.
+
+to_time : double=0.0
+ The ending time of the analysis time domain. Values outside this domain
+ are ignored. If `to_time` is not greater than `from_time`, the entire
+ time domain of the Pitch object is considered.
+
+unit : {'HERTZ','HERTZ_LOGARITHMIC','MEL','LOG_HERTZ','SEMITONES_1',
+ 'SEMITONES_100','SEMITONES_200','SEMITONES_440','ERB'},
+ default=HERTZ
+ Frequency unit
+
+interpolate : bool, default=True
+ True to evalaute parabolically interpolated pitch peaks; False to
+ select the raw frequency samples.
+
+See Also
+--------
+:praat:`Voice report`
+)";
+
+constexpr auto GET_STANDARD_DEVIATION_DOCSTRING = R"(Get standard deviation of frequency
+
+Returns the standard deviation of frequency samples in the specified unit
+
+Parameters
+----------
+from_time : double=0.0
+ The starting time of the analysis time domain.
+
+to_time : double=0.0
+ The ending time of the analysis time domain. Values outside this domain
+ are ignored. If `to_time` is not greater than `from_time`, the entire
+ time domain of the Pitch object is considered.
+
+unit : {'HERTZ','HERTZ_LOGARITHMIC','MEL','LOG_HERTZ','SEMITONES_1',
+ 'SEMITONES_100','SEMITONES_200','SEMITONES_440','ERB'},
+ default=HERTZ
+ Frequency unit
+
+See Also
+--------
+:praat:`Voice report`
+)";
+
+
+constexpr auto GET_QUANTILE_DOCSTRING = R"(Get quantile of frequency samples
+
+Returns the quantile of the frequency samples in the specified unit
+
+Parameters
+----------
+quantile : double
+ Quantile to compute, which must be between 0 and 1 inclusive.
+
+from_time : double=0.0
+ The starting time of the analysis time domain.
+
+to_time : double=0.0
+ The ending time of the analysis time domain. Values outside this domain
+ are ignored. If `to_time` is not greater than `from_time`, the entire
+ time domain of the Pitch object is considered.
+
+unit : {'HERTZ','HERTZ_LOGARITHMIC','MEL','LOG_HERTZ','SEMITONES_1',
+ 'SEMITONES_100','SEMITONES_200','SEMITONES_440','ERB'},
+ default=HERTZ
+ Frequency unit
+
+See Also
+--------
+:praat:`Voice report`
+)";
+
+constexpr auto GET_FRACTION_OF_LOCALLY_UNVOICED_FRAMES_DOCSTRING = R"(Get unvoiced statistics
+
+Returns the statistics related to the unvoiced periods
+
+Parameters
+----------
+from_time : double=0.0
+ The starting time of the analysis time domain.
+
+to_time : double=0.0
+ The ending time of the analysis time domain. Values outside this domain
+ are ignored. If `to_time` is not greater than `from_time`, the entire
+ time domain of the Pitch object is considered.
+
+to_pitch : double=600.0
+ The maximum voice frequency
+
+silence_threshold : double=0.03
+ The upper pitch strength limit of silent period
+
+voicing_threshold : double 0.45
+ The lower pitch strength limit of voicing period
+
+See Also
+--------
+:praat:`Voice report`
+)";
+
+}// namespace parselmouth
diff --git a/src/parselmouth/Vector.cpp b/src/parselmouth/Vector.cpp
index 542d1071..29be8473 100644
--- a/src/parselmouth/Vector.cpp
+++ b/src/parselmouth/Vector.cpp
@@ -42,6 +42,18 @@ PRAAT_ENUM_BINDING(ValueInterpolation) {
make_implicitly_convertible_from_string(*this);
}
+
+PRAAT_ENUM_BINDING(PeakInterpolation)
+{
+ value("NONE", kVector_peakInterpolation::NONE);
+ value("PARABOLIC", kVector_peakInterpolation::PARABOLIC);
+ value("CUBIC", kVector_peakInterpolation::CUBIC);
+ value("SINC70", kVector_peakInterpolation::SINC70);
+ value("SINC700", kVector_peakInterpolation::SINC700);
+
+ make_implicitly_convertible_from_string(*this);
+}
+
PRAAT_CLASS_BINDING(Vector) {
using signature_cast_placeholder::_;
diff --git a/tests/resource_fixtures.py b/tests/resource_fixtures.py
index 82c733b5..3befd080 100644
--- a/tests/resource_fixtures.py
+++ b/tests/resource_fixtures.py
@@ -73,3 +73,8 @@ def text_grid(text_grid_path):
@pytest.fixture
def script_path(resources):
yield resources["script.praat"]
+
+@pytest.fixture
+def harmonicity(sound):
+ return sound.to_harmonicity("CC") # "AC", "GNE"
+
diff --git a/tests/test_harmonicity.py b/tests/test_harmonicity.py
new file mode 100644
index 00000000..81d3a366
--- /dev/null
+++ b/tests/test_harmonicity.py
@@ -0,0 +1,100 @@
+import pytest
+import numpy as np
+
+import parselmouth
+
+
+@pytest.fixture
+def rand_data():
+ return np.random.rand(10)
+
+
+@pytest.fixture
+def rand_harmonicity(rand_data):
+ return parselmouth.Harmonicity(rand_data, 0.1)
+
+
+def test_sequence(rand_data, rand_harmonicity):
+ """test compatibility with various sequence operations"""
+ N = len(rand_harmonicity)
+ assert N == rand_data.size
+ for i in range(N):
+ assert rand_harmonicity[i] == rand_data[i]
+ assert np.allclose(rand_harmonicity, rand_data)
+
+
+def test_constructor(rand_data):
+ data = rand_data
+ T = 0.1
+ start_time = 1.2
+ end_time = 10.0
+ t1 = 1.3
+ h = parselmouth.Harmonicity(data, T, start_time, end_time, t1)
+ assert np.allclose(h, data)
+ assert h.xmin == start_time
+ assert h.xmax == end_time
+ assert h.dx == T
+ assert h.t1 == t1
+
+ h = parselmouth.Harmonicity(data, T, start_time, end_time)
+ assert h.t1 == start_time
+
+ h = parselmouth.Harmonicity(data, T, start_time)
+ assert h.xmax == start_time + T * data.size
+
+ h = parselmouth.Harmonicity(data, T)
+ assert h.xmin == 0.0
+ assert h.xmax == T * data.size
+
+ h = parselmouth.Harmonicity(data, start_time=start_time, end_time=end_time)
+ assert h.dx == (end_time - start_time) / data.size
+
+ h = parselmouth.Harmonicity(data, end_time=end_time)
+ assert h.dx == end_time / data.size
+
+
+def test_get_value(harmonicity):
+ t = (harmonicity.tmin + harmonicity.tmax) / 2.0
+ harmonicity.get_value(t)
+
+
+def test_get_value_in_frame(harmonicity):
+ harmonicity.get_value_in_frame(len(harmonicity) // 2 + 1)
+
+
+# def test_formula(harmonicity):
+# harmonicity.formula("")
+
+
+def test_get_maximum(harmonicity):
+
+ harmonicity.get_maximum()
+ # from_time=0.0, to_time=0.0, interpolation"PARABOLIC"
+
+
+def test_get_mean(harmonicity):
+ harmonicity.get_mean()
+ # from_time=0.0, to_time=0.0
+
+
+def test_get_minimum(harmonicity):
+ harmonicity.get_minimum()
+ # from_time=0.0, to_time=0.0,interpolation="PARABOLIC"
+
+
+def test_get_standard_deviation(harmonicity):
+ harmonicity.get_standard_deviation()
+ # from_time=0.0, to_time=0.0
+
+
+def test_get_time_of_maximum(harmonicity):
+ harmonicity.get_time_of_maximum()
+ # from_time=0.0, to_time=0.0,interpolation="PARABOLIC"
+
+
+def test_get_time_of_minimum(harmonicity):
+ harmonicity.get_time_of_minimum()
+ # from_time=0.0,to_time=0.0,interpolation="PARABOLIC"
+
+def test_get_quantile(harmonicity):
+ harmonicity.get_quantile(0.5)
diff --git a/tests/test_pitch.py b/tests/test_pitch.py
new file mode 100644
index 00000000..3e99b69a
--- /dev/null
+++ b/tests/test_pitch.py
@@ -0,0 +1,25 @@
+import pytest
+
+def test_get_mean_strength(pitch):
+ print(f"Mean autocorrelation={pitch.get_mean_strength(type='ac')}")
+ print(f"Mean noise-to-harmonics ratio={pitch.get_mean_strength(type='nhr')}")
+ print(f"Mean harmonics-to-noise ratio={pitch.get_mean_strength(type='hnr_db')} dB")
+ print(f"default={pitch.get_mean_strength()}")
+
+def test_get_mean(pitch):
+ print(f"Mean frequency={pitch.get_mean()}")
+
+def test_get_standard_deviation(pitch):
+ print(f"Standard_deviation={pitch.get_standard_deviation()}")
+
+def test_get_minimum(pitch):
+ print(f"Minimum={pitch.get_minimum()}")
+
+def test_get_maximum(pitch):
+ print(f"Maximum={pitch.get_maximum()}")
+
+def test_get_quantile(pitch):
+ print(f"10% Quantile={pitch.get_quantile(0.1)}")
+
+def test_get_fraction_of_locally_unvoiced_frames(pitch):
+ print(pitch.get_fraction_of_locally_unvoiced_frames())