audiofp/fp.rs
1//! Fingerprinter traits.
2//!
3//! Two traits cover the two ways `audiofp` produces fingerprints:
4//!
5//! - [`Fingerprinter`] — feed a whole [`AudioBuffer`] and get its full
6//! output. Suited to enrolment / batch jobs.
7//! - [`StreamingFingerprinter`] — push samples as they arrive and receive
8//! fingerprints whenever the algorithm has enough material. Suited to
9//! live capture.
10//!
11//! Concrete implementations live in feature-gated modules
12//! (`fp_classical::Wang`, `neural::ResonaFp`, …).
13//!
14//! [`AudioBuffer`]: crate::AudioBuffer
15
16use alloc::vec::Vec;
17
18use crate::{AudioBuffer, Result, TimestampMs};
19
20/// Offline (whole-buffer) fingerprinter.
21///
22/// Implementations are stateful between calls only insofar as they may
23/// cache scratch buffers — the fingerprint of `extract(a)` does not depend
24/// on any previous call.
25///
26/// # Example
27///
28/// ```
29/// use audiofp::{AudioBuffer, Fingerprinter, Result, SampleRate};
30///
31/// /// A toy fingerprinter that just sums absolute samples.
32/// struct Energy;
33///
34/// impl Fingerprinter for Energy {
35/// type Output = f32;
36/// type Config = ();
37///
38/// fn name(&self) -> &'static str { "energy-v0" }
39/// fn config(&self) -> &Self::Config { &() }
40/// fn required_sample_rate(&self) -> u32 { 16_000 }
41/// fn min_samples(&self) -> usize { 16_000 }
42/// fn extract(&mut self, audio: AudioBuffer<'_>) -> Result<Self::Output> {
43/// Ok(audio.samples.iter().map(|s| s.abs()).sum())
44/// }
45/// }
46///
47/// let mut fp = Energy;
48/// let samples = vec![0.0_f32; 16_000];
49/// let buf = AudioBuffer { samples: &samples, rate: SampleRate::HZ_16000 };
50/// assert_eq!(fp.extract(buf).unwrap(), 0.0);
51/// ```
52pub trait Fingerprinter {
53 /// The fingerprint produced by this extractor (e.g. `Vec<WangHash>`).
54 type Output;
55
56 /// Per-instance configuration this fingerprinter exposes to callers.
57 type Config: Clone + Send + Sync;
58
59 /// Stable identifier for the algorithm and version, e.g. `"wang-v1"`.
60 /// Useful when persisting fingerprints alongside the producer name.
61 fn name(&self) -> &'static str;
62
63 /// Borrow the configuration this instance was built with.
64 fn config(&self) -> &Self::Config;
65
66 /// Sample rate, in hertz, the fingerprinter expects its input at.
67 /// Resampling is the caller's responsibility.
68 fn required_sample_rate(&self) -> u32;
69
70 /// Minimum buffer length, in samples, required to extract anything.
71 /// Calls with shorter inputs return [`AfpError::AudioTooShort`].
72 ///
73 /// [`AfpError::AudioTooShort`]: crate::AfpError::AudioTooShort
74 fn min_samples(&self) -> usize;
75
76 /// Compute the fingerprint of `audio`.
77 fn extract(&mut self, audio: AudioBuffer<'_>) -> Result<Self::Output>;
78}
79
80/// Streaming fingerprinter that emits zero-or-more frames per push.
81///
82/// Implementations must be **non-blocking** and **bounded-allocation**:
83/// any buffers needed for sustained operation are allocated at construction,
84/// not inside [`StreamingFingerprinter::push`]. This makes them suitable
85/// for invocation from realtime audio callbacks (when invoked through
86/// `audiofp`'s streaming orchestrator).
87///
88/// # Example
89///
90/// ```
91/// use audiofp::{StreamingFingerprinter, TimestampMs};
92///
93/// struct EveryThird { count: usize }
94///
95/// impl StreamingFingerprinter for EveryThird {
96/// type Frame = u32;
97/// fn push(&mut self, samples: &[f32]) -> Vec<(TimestampMs, u32)> {
98/// let mut out = Vec::new();
99/// for s in samples {
100/// self.count += 1;
101/// if self.count % 3 == 0 {
102/// out.push((TimestampMs(self.count as u64), s.to_bits()));
103/// }
104/// }
105/// out
106/// }
107/// fn flush(&mut self) -> Vec<(TimestampMs, u32)> { Vec::new() }
108/// fn latency_ms(&self) -> u32 { 0 }
109/// }
110///
111/// let mut fp = EveryThird { count: 0 };
112/// assert_eq!(fp.push(&[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]).len(), 2);
113/// ```
114pub trait StreamingFingerprinter {
115 /// One unit of fingerprint material the stream emits.
116 type Frame;
117
118 /// Feed PCM samples and return any fingerprints that became available
119 /// during this push.
120 ///
121 /// Must not block and must not allocate beyond the per-instance
122 /// budget set at construction.
123 fn push(&mut self, samples: &[f32]) -> Vec<(TimestampMs, Self::Frame)>;
124
125 /// Drain any pending fingerprint material at end-of-stream.
126 fn flush(&mut self) -> Vec<(TimestampMs, Self::Frame)>;
127
128 /// Conservative upper bound on emission latency: from the time a
129 /// sample enters [`push`] to the time the fingerprint covering it
130 /// is returned.
131 ///
132 /// [`push`]: StreamingFingerprinter::push
133 fn latency_ms(&self) -> u32;
134}