Author
Affiliation

Cam

Anauseam

Published

2026-03-31

Harmonic Sparsity & Capture (NINOS2)

Once the Gatekeeper has waited out the chaotic broadband noise of a hammer strike (States 1 & 2), it must mathematically prove that the remaining audio is a stable, ringing tone rather than sustained environmental noise. This is handled in State 3 (HARMONIC DECAY) and State 4 (RELEASE).

The Acoustic Problem: Sustained Noise vs. Tonal Stability

Acoustic pianos produce sound via standing waves on physical strings, which generate a distinct harmonic series (a fundamental frequency f_0 and its overtones). In the frequency domain, a stable piano note appears as sharp, distinct peaks of energy surrounded by relatively empty bins. In contrast, white noise or room ambience spreads energy evenly across the entire spectrum.

To determine if the signal is ready for high-precision pitch and inharmonicity analysis, the pipeline needs a metric that quantifies this “peakiness” versus “flatness.”

The Mathematical Solution: NINOS2 Sparsity Metric

The pipeline utilizes the NINOS2 (Normalized Inverse Norm of the Orthogonalized Spectrum) algorithm to measure spectral sparsity.

While the exact mathematical implementation resides in the algorithms::power module, its operational behavior in the Gatekeeper is strictly threshold-based. The metric outputs a continuous sparsity score:

  • A score near 1.0 indicates mathematically flat white noise (energy is evenly distributed).
  • A higher score N indicates high sparsity (energy is tightly concentrated into distinct harmonic peaks).

State Machine Execution (States 3 & 4)

The final two states evaluate this sparsity score and orchestrate the actual data capture:

State 3: HARMONIC DECAY (Stability Gating)

For every frame that clears the transient bypass delay, the Gatekeeper calculates the NINOS2 score of the current_spectrum.

  1. Threshold Comparison: The score is compared against the ninos2_stability_threshold, which defaults to 10.0.
  2. The Golden Window: If the score exceeds this threshold, an internal stable_counter is incremented. If the score drops below the threshold, the counter resets to zero and the state reverts to SignalState::Unstable.
  3. Validation: The signal must maintain this high sparsity score for required_stable_frames consecutive frames (defaulting to 4 frames, or \sim 185\text{ms}). Once this condition is met, the Gatekeeper officially evaluates to SignalState::Stable.

State 4: RELEASE (Capture & Dispatch)

Once the signal is mathematically proven to be stable, the Gatekeeper checks if capture_mode_enabled is true. If so, it initiates a time-windowed capture sequence:

  1. Windowing: A capture_counter increments for every subsequent frame.
  2. Termination & Reset: Once the counter reaches capture_max_frames (defaulting to 32 frames, which represents roughly 1.5\text{ seconds} of audio), the time window officially closes. The Gatekeeper then fires the reset_capture_state() method to zero out all stability and delay counters, preparing the pipeline for the next note.
  3. Worker Dispatch: At this exact moment of termination, the buffered audio is ready. The pipeline is designed to extract a 66,150-sample array from the lock-free AudioPool and dispatch it to a background Worker thread for heavy DSP analysis (such as inharmonicity mapping).