pitch_detector/
note.rs

1mod note_detection_result;
2
3#[cfg(feature = "hinted")]
4pub mod hinted;
5
6use std::ops::Range;
7
8use crate::pitch::PitchDetector;
9
10pub use self::note_detection_result::NoteDetectionResult;
11
12/// Returns the predominant note of the given signal. It will detect within a conventional
13/// range of frequencies (20Hz to nyquist). If you want to detect a note in a specific range,
14/// use the [detect_note_in_range] method
15/// ## Examples
16/// ```rust
17/// use pitch_detector::{
18///     core::{utils::sine_wave_signal, NoteName},
19///     note::{detect_note},
20///     pitch::{HannedFftDetector, PitchDetector},
21/// };
22/// # fn example_detect_note() -> Option<()> {
23/// # const NUM_SAMPLES: usize = 16384;
24/// # const SAMPLE_RATE: f64 = 44100.0;
25//
26/// let mut detector = HannedFftDetector::default();
27/// let slightly_sharp_a = 448.;
28/// let signal = sine_wave_signal(NUM_SAMPLES, slightly_sharp_a, SAMPLE_RATE);
29/// let note = detect_note(
30///     &signal,
31///     &mut detector,
32///     SAMPLE_RATE,
33/// )?;
34//
35/// assert_eq!(note.note_name, NoteName::A);
36/// assert!(note.cents_offset > 0.);
37/// # None
38/// # }
39/// ```
40pub fn detect_note<D: PitchDetector>(
41    signal: &[f64],
42    freq_detector: &mut D,
43    sample_rate: f64,
44) -> Option<NoteDetectionResult> {
45    let nyquist_freq = sample_rate / 2.;
46    let min_freq = 20.; // Conventional minimum frequency for human hearing
47    detect_note_in_range(signal, freq_detector, sample_rate, min_freq..nyquist_freq)
48}
49
50/// Returns the predominant note of the given signal within the specified range.
51/// ## Examples
52/// ```rust
53/// use pitch_detector::{
54///     core::{utils::sine_wave_signal, NoteName},
55///     note::{detect_note_in_range},
56///     pitch::{HannedFftDetector, PitchDetector},
57/// };
58/// # fn example_detect_note() -> Option<()> {
59/// # const NUM_SAMPLES: usize = 16384;
60/// # const SAMPLE_RATE: f64 = 44100.0;
61/// const MAX_FREQ: f64 = 1046.50; // C6
62/// const MIN_FREQ: f64 = 32.7; // C1
63///
64/// let mut detector = HannedFftDetector::default();
65/// let slightly_sharp_a = 448.;
66/// let signal = sine_wave_signal(NUM_SAMPLES, slightly_sharp_a, SAMPLE_RATE);
67/// let note = detect_note_in_range(
68///     &signal,
69///     &mut detector,
70///     SAMPLE_RATE,
71///     MIN_FREQ..MAX_FREQ,
72/// )?;
73//
74/// assert_eq!(note.note_name, NoteName::A);
75/// assert!(note.cents_offset > 0.);
76///
77/// let high_pitch = sine_wave_signal(NUM_SAMPLES, 2000., SAMPLE_RATE);
78/// let note = detect_note_in_range(
79///     &signal,
80///     &mut detector,
81///     SAMPLE_RATE,
82///     MIN_FREQ..MAX_FREQ,
83/// );
84/// assert!(note.is_none());
85/// # None
86/// # }
87/// ```
88pub fn detect_note_in_range<D: PitchDetector>(
89    signal: &[f64],
90    freq_detector: &mut D,
91    sample_rate: f64,
92    freq_range: Range<f64>,
93) -> Option<NoteDetectionResult> {
94    freq_detector
95        .detect_pitch_in_range(signal, sample_rate, freq_range)
96        .and_then(|f| f.try_into().ok())
97}