wave-roll
Version:
JavaScript Library for Comparative MIDI Piano-Roll Visualization
93 lines • 4.93 kB
TypeScript
/**
* Note-level transcription matching utilities.
*
* This implementation is designed for logical equivalence with
* mir_eval.transcription note matching (onset/pitch/offset gating with unique
* assignment). We do not copy code from mir_eval; instead we document the
* intended behaviour and provide our own TypeScript implementation.
*
* Reference: https://github.com/mir-evaluation/mir_eval
*/
import { TranscriptionToleranceOptions, VelocityToleranceOptions } from "./constants";
import { ParsedMidi } from "@/lib/midi/types";
import type { MatchEntry } from "./types";
/**
* Result of a note-level matching operation.
*/
export interface NoteMatchResult {
/** Pairs of matched reference-estimated indices */
matches: MatchEntry[];
/** Indices of unmatched reference notes */
falseNegatives: number[];
/** Indices of unmatched estimated notes */
falsePositives: number[];
}
/**
* Options for BPM-aware note matching.
*/
export interface BpmScalingOptions {
/**
* When true, scales the estimated MIDI's time intervals to match
* the reference MIDI's BPM. This is useful when comparing MIDI files
* with different tempos but the same musical content.
*
* Formula: scaledEstTime = estTime * (refBpm / estBpm)
*
* @default false
*/
scaleBpmToReference?: boolean;
}
/**
* Match notes between reference and estimated MIDI representations following
* the criteria used by `mir_eval.transcription.match_notes`.
*
* A reference and estimated note are considered a match when:
* - their onsets differ by at most `onsetTolerance` seconds.
* - their pitches (in MIDI) differ by at most `pitchTolerance`.
* - their offsets differ by at most `max(offsetMinTolerance, offsetRatioTolerance x referenceDuration)`.
*
* Each reference (estimated) note can be matched to at most one estimated
* (reference) note. We compute the maximum bipartite matching subject to the
* above constraints (Hopcroft-Karp), which mirrors the behavior of mir_eval's
* unique assignment policy.
*
* @param reference - The reference (ground truth) MIDI data
* @param estimated - The estimated (model output) MIDI data
* @param options - Tolerance options for matching
* @param bpmOptions - BPM scaling options for tempo-aware matching
*/
export declare function matchNotes(reference: ParsedMidi, estimated: ParsedMidi, options?: Partial<TranscriptionToleranceOptions>, bpmOptions?: BpmScalingOptions): NoteMatchResult;
/**
* Velocity-aware matching.
*
* This function mirrors `matchNotes` (onset/pitch/offset gating) and optionally
* adds a velocity gate to the adjacency when `velocity.includeInMatching` is true.
* It preserves the same 1:1 matching policy via Hopcroft-Karp and enriches
* matches with per-pair diagnostics (diffs, overlap, velocities).
*
* @param reference - The reference (ground truth) MIDI data
* @param estimated - The estimated (model output) MIDI data
* @param options - Tolerance options for matching
* @param velocity - Velocity tolerance options
* @param bpmOptions - BPM scaling options for tempo-aware matching
*/
export declare function matchNotesWithVelocity(reference: ParsedMidi, estimated: ParsedMidi, options?: Partial<TranscriptionToleranceOptions>, velocity?: Partial<VelocityToleranceOptions>, bpmOptions?: BpmScalingOptions): NoteMatchResult;
/**
* mir_eval-style function signature using explicit arrays.
* Provided for parity with `mir_eval.transcription.match_notes`.
*/
export declare function match_notes(reference_intervals: [number, number][], reference_pitches: number[], estimated_intervals: [number, number][], estimated_pitches: number[], onset_tolerance?: number, pitch_tolerance?: number): NoteMatchResult;
/**
* mir_eval-style match with onset+pitch+offset tolerance.
*/
export declare function match_notes_with_offset(reference_intervals: [number, number][], reference_pitches: number[], estimated_intervals: [number, number][], estimated_pitches: number[], onset_tolerance?: number, pitch_tolerance?: number, offset_ratio_tolerance?: number, offset_min_tolerance?: number): NoteMatchResult;
/**
* Chroma version of match_notes where pitch is compared mod 12.
*/
export declare function match_notes_chroma(reference_intervals: [number, number][], reference_pitches: number[], estimated_intervals: [number, number][], estimated_pitches: number[], onset_tolerance?: number, pitch_tolerance?: number, offset_ratio_tolerance?: number, offset_min_tolerance?: number): NoteMatchResult;
/**
* Chroma match with onset+pitch only (no offset gating). Useful for
* chroma_precision_recall_f1.
*/
export declare function match_notes_chroma_onset(reference_intervals: [number, number][], reference_pitches: number[], estimated_intervals: [number, number][], estimated_pitches: number[], onset_tolerance?: number, pitch_tolerance?: number): NoteMatchResult;
//# sourceMappingURL=matchNotes.d.ts.map