Inputs#

Backward-compatible re-export of the HarmonicInput descriptor.

HarmonicInput originally lived in this submodule because biotuner.harmonic_geometry was its only consumer. As of the cross-module HarmonicInput promotion, the canonical home is biotuner.harmonic_input at the top level — so unrelated modules (harmonic_timbre, the engine backend, exporters) can consume the descriptor without pulling in geometry as a transitive dependency.

This file remains so that the ~24 internal call sites and any external code still doing from biotuner.harmonic_geometry.inputs import HarmonicInput keep working unchanged. New code should prefer:

from biotuner.harmonic_input import HarmonicInput, HarmonicSequence
class HarmonicInput(ratios: ~typing.List[~fractions.Fraction | float] | None = None, peaks: ~typing.List[float] | None = None, amplitudes: ~typing.List[float] | None = None, phases: ~typing.List[float] | None = None, damping: ~typing.List[float] | None = None, base_freq: float = 1.0, equave: float = 2.0, metadata: ~typing.Dict[str, ~typing.Any] = <factory>, linewidths: ~typing.List[float] | None = None, freqs: ~typing.List[float] | None = None, psd: ~typing.List[float] | None = None, spectrum_method: str | None = None, aperiodic_exponent: float | None = None, spectral_flatness: float | None = None, ratios_source: str = 'peaks', ratios_alternates: ~typing.Dict[str, ~typing.List[float]] = <factory>)[source]#

Bases: object

Unified harmonic input.

At least one of ratios or peaks must be provided. All list-typed optional fields, if given, must have lengths matching the number of components (len(ratios) or len(peaks)).

Parameters:
  • ratios (list of Fraction or float, optional) – Frequency ratios. Coerced to Fraction when a rational approximation within DEFAULT_MAX_DENOMINATOR exists.

  • peaks (list of float, optional) – Peak frequencies in Hz.

  • amplitudes (list of float, optional) – Linear (not dB) amplitudes per component. Defaults to uniform.

  • phases (list of float, optional) – Phase per component, in radians. Defaults to zeros.

  • damping (list of float, optional) – Decay rate (1/s) per component. Defaults to zeros.

  • base_freq (float, default=1.0) – Reference frequency in Hz. Used when ratios are given without peaks to recover absolute frequencies.

  • equave (float, default=2.0) – Equave width: 2.0 for octaves, 3.0 for tritaves, etc. Must be greater than 1.

  • metadata (dict) – Free-form annotations preserved across constructors and validation.

Notes

Validation is invoked by __post_init__(); constructing an inconsistent HarmonicInput raises ValueError.

ratios: List[Fraction | float] | None = None#
peaks: List[float] | None = None#
amplitudes: List[float] | None = None#
phases: List[float] | None = None#
damping: List[float] | None = None#
base_freq: float = 1.0#
equave: float = 2.0#
metadata: Dict[str, Any]#
linewidths: List[float] | None = None#
freqs: List[float] | None = None#
psd: List[float] | None = None#
spectrum_method: str | None = None#
aperiodic_exponent: float | None = None#
spectral_flatness: float | None = None#
ratios_source: str = 'peaks'#
ratios_alternates: Dict[str, List[float]]#
n_components() int[source]#

Return the number of harmonic components.

Resolved from ratios first, then peaks. At least one of the two is guaranteed to be present after validate().

to_peaks() ndarray[source]#

Return absolute peak frequencies in Hz as a 1-D float64 array.

If peaks is set, those values are returned directly. Otherwise peaks are reconstructed as base_freq * ratios.

to_ratios() List[Fraction | float][source]#

Return ratios.

If ratios is set, those values are returned. Otherwise ratios are derived as peaks / base_freq and coerced to Fraction.

normalized_amplitudes() ndarray[source]#

Return amplitudes scaled to sum to 1.

If amplitudes is None, returns a uniform distribution over the components.

validate() None[source]#

Raise ValueError if the input is internally inconsistent.

Checked invariants:

  • at least one of ratios / peaks is given,

  • equave > 1 and base_freq > 0,

  • all list-typed fields have matching lengths,

  • all amplitudes are non-negative,

  • all peaks are positive,

  • if both ratios and peaks are given, they agree up to base_freq within a small relative tolerance.

classmethod from_ratios(ratios: Iterable[Fraction | int | float | tuple], base_freq: float = 1.0, amplitudes: Sequence[float] | None = None, phases: Sequence[float] | None = None, damping: Sequence[float] | None = None, equave: float = 2.0, metadata: Dict[str, Any] | None = None) HarmonicInput[source]#

Build from a sequence of ratios.

classmethod from_peaks(peaks: Iterable[float], base_freq: float | None = None, amplitudes: Sequence[float] | None = None, phases: Sequence[float] | None = None, damping: Sequence[float] | None = None, equave: float = 2.0, metadata: Dict[str, Any] | None = None) HarmonicInput[source]#

Build from a sequence of peak frequencies in Hz.

If base_freq is None it is set to the smallest peak so that the implied ratio of the lowest component is exactly 1.

classmethod from_biotuner(bt: Any, equave: float = 2.0, *, scale_priority: Sequence[str] | None = None, include_alternates: bool = True, include_spectrum: bool = True, include_fooof: bool = True) HarmonicInput[source]#

Build from a fitted compute_biotuner instance.

Two selection modes for the canonical ratios:

  • Legacy mode (scale_priority is None, the default) — reproduces the historical behaviour exactly: pulls peaks (required), amps when length-aligned, and uses peaks_ratios as the canonical ratios when it’s 1:1 aligned with peaks. ratios_source is set to "peaks" and ratios_alternates is left empty so existing callers see no schema change.

  • Scale-priority mode (scale_priority provided) — walks the priority list in order (using the canonical names from SCALE_KEYS), picks the first non-empty scale as ratios, records its label in ratios_source. When include_alternates=True (default), every other non-empty scale found on bt is stored in ratios_alternates under the same canonical name. Amplitudes / linewidths are populated only if their lengths align with the chosen scale.

Tier-A spectral context is populated regardless of mode:

  • freqs / psd / spectrum_method (when include_spectrum)

  • aperiodic_exponent / linewidths (when include_fooof)

  • spectral_flatness (always, if available)

Parameters:
  • bt (compute_biotuner) – A fitted biotuner object on which peaks_extraction has been called.

  • equave (float, default=2.0)

  • scale_priority (sequence of str, optional) – Ordered preference for ratios. Values must come from SCALE_KEYS. Unknown keys raise ValueError.

  • include_alternates (bool, default=True) – In scale-priority mode, populate ratios_alternates with every other non-empty scale found on bt. Ignored in legacy mode.

  • include_spectrum (bool, default=True) – Copy bt.freqs / bt.psd / bt.spectrum_method if available.

  • include_fooof (bool, default=True) – Copy bt.aperiodic_exponent and a length-aligned bt.linewidth if available.

Raises:
  • AttributeError – If bt lacks a peaks attribute.

  • ValueError – If bt.peaks is empty, or scale_priority contains an unknown key.

class HarmonicSequence(frames: List[HarmonicInput], times: ndarray | None = None)[source]#

Bases: object

Time-resolved sequence of HarmonicInput frames.

Pairs naturally with the output of biotuner.transitional_harmony and biotuner.harmonic_sequence: each window’s peaks become a frame here, and downstream geometry functions can be applied frame-by-frame via transformations.geometry_sequence.

Parameters:
  • frames (list of HarmonicInput) – At least one frame is required.

  • times (ndarray, optional) – Time of each frame in seconds. If None, frames are assumed to be uniformly spaced at unit intervals.

frames: List[HarmonicInput]#
times: ndarray | None = None#
n_frames() int[source]#

Number of frames in the sequence.

at(t: float) HarmonicInput[source]#

Return the frame nearest to time t.

interpolate(t: float, mode: str = 'log') HarmonicInput[source]#

Return a HarmonicInput interpolated to time t.

Currently supports two-frame interpolation between the bracketing frames. mode selects the space in which ratios / peaks are blended:

  • 'log' (default) — logarithmic, musically correct,

  • 'linear' — straight linear interpolation,

  • 'nearest' — return the nearest frame (no blending).

Frames must have equal n_components; if they do not, this raises ValueError. Richer interpolation (mismatched component counts, phase wrapping, etc.) is the job of transformations.interpolate_input in Phase 6.

classmethod from_biotuner_list(bt_list: Sequence[Any], times: Sequence[float] | None = None, equave: float = 2.0) HarmonicSequence[source]#

Build from a sequence of fitted compute_biotuner objects.

Each biotuner object becomes one frame. Objects with no peaks are skipped; if every object is empty, ValueError is raised.

Parameters:
  • bt_list (sequence of compute_biotuner) – Fitted biotuner objects (peaks_extraction already called).

  • times (sequence of float, optional) – One time per kept frame. If None, frames are uniformly spaced. If provided, must match the number of non-empty biotuner objects.

  • equave (float, default=2.0)

classmethod from_biotuner_group(btg: Any, times: Sequence[float] | None = None, equave: float = 2.0) HarmonicSequence[source]#

Build from a biotuner.biotuner_group.BiotunerGroup instance.

Uses btg.objects (the per-series compute_biotuner instances). BiotunerGroup must have been constructed with store_objects=True (the default).

Parameters:
  • btg (BiotunerGroup) – A group whose compute_peaks has been run.

  • times (sequence of float, optional) – One time per non-empty frame; see from_biotuner_list().

  • equave (float, default=2.0)

Raises:

AttributeError – If btg has no objects attribute, or it is None (e.g. store_objects=False was used).