PitchDetector

abstract class PitchDetector : AutoCloseable

Abstract realtime pitch detector — feed audio buffers, get pitch per frame.

What is a PitchDetector?

A stateful object that accumulates audio samples and produces PitchPoint results at each detection frame. Handles variable buffer sizes by internally accumulating until enough samples are available (important because iOS delivers audio at hardware sample rate in variable-sized chunks, which after resampling may be smaller than the required frame size).

Also maintains pitchContour — a lossless, append-only record of the detected contour, readable whole (scoring) or windowed (visualization).

When to Use

ScenarioUse ThisWhy
Live singing feedback (karaoke, practice)YesFrame-by-frame with live contour
Offline extraction from a complete recordingNoUse PitchContourExtractor via PitchDetection.createContourExtractor

Construct instances via PitchDetection.createDetector — do not subclass.

Quick Start (Swift)

let detector = PitchDetection.createDetector()

// Feed audio from recorder (ADR-017: pass hardware rate, resampling internal)
let point = detector.detect(samples: audioBuffer, sampleRate: 48000)
let amplitude = detector.getAmplitude(samples: audioBuffer, sampleRate: 48000)

// Cleanup
detector.close()

Common Pitfalls

  1. Call close() when done: Detectors hold native resources.

  2. Call clearPitchContour() between segments: pitchContour accumulates across calls. Reset it when starting a new recording.

See also

PitchDetection.createDetector

Factory method

Configuration (BALANCED, PRECISE, RELAXED)

For batch extraction instead of realtime

The per-frame result

The accumulated session contour

Constructors

Link copied to clipboard
constructor()

Properties

Link copied to clipboard

The configuration used to create this detector

Link copied to clipboard
abstract val hasProcessing: Boolean

Check if post-processing is active

Link copied to clipboard
abstract val latencyMs: Float

Detection latency in milliseconds.

Link copied to clipboard
abstract val livePitch: SharedFlow<PitchPoint>

Per-emission pitch stream — same source and rate as pitchContour, but as individual events instead of an accumulating record. Each new pitch point fed into the contour is also emitted here.

Link copied to clipboard

The session's pitch contour — every detected frame, in detection order, recorded losslessly. Filled by feedContour; each frame is back-spread from the supplied anchor by the detector's hop, so the latest frame lands at anchorTime and earlier ones at anchorTime - K*hopSec.

Link copied to clipboard

Whether post-processing is currently enabled. Set to enable/disable at runtime.

Functions

Link copied to clipboard
abstract fun clearPitchContour()

Clear the accumulated pitch contour.

Link copied to clipboard
abstract fun clearPitchContourFrom(timeSeconds: Float)

Drop all contour points with timestamp >= timeSeconds, keep everything before.

Link copied to clipboard
open override fun close()

AutoCloseable implementation - delegates to release()

Link copied to clipboard
abstract fun detect(samples: FloatArray, sampleRate: Int): PitchPoint

Single-shot pitch detection. Returns the latest pitch the detector can compute from the supplied audio.

Link copied to clipboard
abstract fun duplicate(): PitchDetector

Create a duplicate detector with the same configuration.

Link copied to clipboard
abstract fun feedContour(samples: FloatArray, sampleRate: Int, anchorTime: Float)

Stream raw audio into pitchContour.

Link copied to clipboard
abstract fun getAmplitude(samples: FloatArray, sampleRate: Int): Float

Get the amplitude (RMS) of the audio samples.

Link copied to clipboard
abstract fun pitchAt(timeSeconds: Float): PitchPoint?

Look up the contour point closest to timeSeconds.

Link copied to clipboard
abstract fun release()

Release all resources. Must be called when done.

Link copied to clipboard
abstract fun reset()

Reset state and internal buffer. Call when starting a new audio stream.