TesseraBreath

Public facade for breath analysis — control score, phrase structure, and reference comparison.

What is Breath Analysis?

Breath analysis measures how a singer manages breath during a recording. It builds a "breath function" — a time series that rises during voiced segments and decays during pauses — then derives:

  • a control score in [0, 1) via a sigmoid on equivalent sustain time, and

  • a phrase summary: per-phrase durations, comfortable range, sing-vs-pause ratios, and longest phrase (with and without statistical-outlier filtering).

The breath function intermediate is also the basis for comparison: cross-correlate a reference and student function and match peaks to score phrasing similarity.

When to Use

ScenarioUse ThisWhy
Score breath + extract phrase structure from a recordingYesOne-shot analyze(contour)
Score + alignment vs. a reference recordingYesanalyze(studentContour, reference = referenceContour)
Just the alignment score, no full analysisYescompare(refContour, studentContour)
Multi-metric analysis (breath + agility + range)Use Tessera or TesseraSessionAvoids redundant contour handling

Quick Start

Kotlin

// One-shot analysis
val metrics = TesseraBreath.analyze(contour, config = BreathConfig.PRACTICE)
println("Control: ${metrics.controlScore}, Longest phrase: ${metrics.phrases?.longestDuration}")

// With reference recording — populates alignmentScore
val metricsVsRef = TesseraBreath.analyze(studentContour, reference = referenceContour)
println("Alignment: ${metricsVsRef.alignmentScore}")

// Composable — reuse breath function for score + comparison
val bf = TesseraBreath.computeBreathFunction(contour)
val metrics = TesseraBreath.analyze(bf)
val refBf = TesseraBreath.computeBreathFunction(referenceContour)
val alignment = TesseraBreath.compare(refBf, bf)

Swift

let metrics = TesseraBreath.analyze(contour: contour, config: .practice)
print("Control: \(metrics.controlScore ?? 0), Longest: \(metrics.phrases?.longestDuration ?? 0)")

Common Pitfalls

  1. Contour must have ≥ 2 samples: Throws per ADR-022.

  2. controlScore is nullable: Null when the recording has no detectable breath signal. Always check before scaling for display.

  3. phrases is nullable: Null when audio has insufficient phrase structure (no pauses detected, or fewer than two pauses). Check before using.

  4. alignmentScore is nullable: Populated only when analyze is called with a reference recording, and only when both recordings are long enough to align AND the reference itself has detectable breath peaks.

  5. Config presets matter: PRACTICE (faster decay, higher sigmoid midpoint) is appropriate for sustained alankaar/scales; SPEECH for spoken word.

See also

Presets: DEFAULT, SINGING, PRACTICE, SPEECH, CLINICAL

Result type — controlScore, phrases, alignmentScore

The composable intermediate

For multi-metric batch analysis

For streaming multi-metric analysis

Functions

Link copied to clipboard
fun analyze(breathFunction: BreathFunction, reference: BreathFunction? = null, config: BreathConfig = BreathConfig.DEFAULT): BreathMetrics

Analyze a recording: control score + phrase structure, optionally with reference alignment.

fun analyze(contour: PitchContour, reference: PitchContour? = null, config: BreathConfig = BreathConfig.DEFAULT): BreathMetrics

Analyze a recording directly from a pitch contour.

Link copied to clipboard
fun compare(reference: BreathFunction, student: BreathFunction, config: BreathConfig = BreathConfig.DEFAULT): Float?

Compare two breath functions and return the alignment score alone.

fun compare(reference: PitchContour, student: PitchContour, config: BreathConfig = BreathConfig.DEFAULT): Float?

Compare two pitch contours' breath patterns (convenience).

Link copied to clipboard
fun computeBreathFunction(contour: PitchContour, config: BreathConfig = BreathConfig.DEFAULT): BreathFunction

Compute the shared breath function intermediate.