← back to jeffrydegrande__voicevo

Function bodies 463 total

All specs Real LLM only Function bodies
does_not_bridge_breathing_pause function · rust · L117-L139 (23 LOC)
core/src/dsp/mpt.rs
    fn does_not_bridge_breathing_pause() {
        // A 600ms gap (> 500ms) indicates the patient stopped to breathe.
        // This should NOT be bridged — it's two separate phonation attempts.
        let mut contour: Vec<PitchFrame> = Vec::new();
        // 5s voiced
        for i in 0..500 {
            contour.push(frame(i as f32 * 0.01, Some(100.0)));
        }
        // 600ms gap (60 frames) — breathing pause
        for i in 500..560 {
            contour.push(frame(i as f32 * 0.01, None));
        }
        // 3s voiced
        for i in 560..860 {
            contour.push(frame(i as f32 * 0.01, Some(100.0)));
        }

        let mpt = max_phonation_time_secs(&contour, 10.0, 250.0);
        assert!(
            (mpt - 5.0).abs() < 0.1,
            "Breathing pause (>500ms) should not be bridged, expected ~5.0s, got {mpt:.3}s"
        );
    }
does_not_bridge_300ms_gap function · rust · L142-L161 (20 LOC)
core/src/dsp/mpt.rs
    fn does_not_bridge_300ms_gap() {
        // 300ms > 250ms threshold — should NOT bridge
        let mut contour: Vec<PitchFrame> = Vec::new();
        for i in 0..500 {
            contour.push(frame(i as f32 * 0.01, Some(100.0)));
        }
        // 300ms gap (30 frames)
        for i in 500..530 {
            contour.push(frame(i as f32 * 0.01, None));
        }
        for i in 530..830 {
            contour.push(frame(i as f32 * 0.01, Some(100.0)));
        }

        let mpt = max_phonation_time_secs(&contour, 10.0, 250.0);
        assert!(
            (mpt - 5.0).abs() < 0.1,
            "300ms gap should NOT be bridged at 250ms threshold, expected ~5.0s, got {mpt:.3}s"
        );
    }
bridges_200ms_gap function · rust · L164-L183 (20 LOC)
core/src/dsp/mpt.rs
    fn bridges_200ms_gap() {
        // 200ms < 250ms threshold — should bridge
        let mut contour: Vec<PitchFrame> = Vec::new();
        for i in 0..500 {
            contour.push(frame(i as f32 * 0.01, Some(100.0)));
        }
        // 200ms gap (20 frames)
        for i in 500..520 {
            contour.push(frame(i as f32 * 0.01, None));
        }
        for i in 520..820 {
            contour.push(frame(i as f32 * 0.01, Some(100.0)));
        }

        let mpt = max_phonation_time_secs(&contour, 10.0, 250.0);
        assert!(
            mpt > 8.0,
            "200ms gap should be bridged at 250ms threshold, got {mpt:.3}s"
        );
    }
all_unvoiced function · rust · L186-L189 (4 LOC)
core/src/dsp/mpt.rs
    fn all_unvoiced() {
        let contour = vec![frame(0.0, None), frame(0.01, None)];
        assert_eq!(max_phonation_time_secs(&contour, 10.0, 250.0), 0.0);
    }
empty_contour function · rust · L192-L194 (3 LOC)
core/src/dsp/mpt.rs
    fn empty_contour() {
        assert_eq!(max_phonation_time_secs(&[], 10.0, 250.0), 0.0);
    }
compute_periodicity function · rust · L18-L66 (49 LOC)
core/src/dsp/periodicity.rs
pub fn compute_periodicity(
    samples: &[f32],
    sample_rate: u32,
    contour: &[PitchFrame],
    active_frames: &[bool],
    hop_size_ms: f32,
) -> Option<f32> {
    let sr = sample_rate as f32;
    let hop_samples = (hop_size_ms / 1000.0 * sr) as usize;

    let mut values: Vec<f32> = Vec::new();

    for (i, frame) in contour.iter().enumerate() {
        let Some(f0) = frame.frequency else {
            continue;
        };

        // Only use frames that are also active (have energy)
        if i < active_frames.len() && !active_frames[i] {
            continue;
        }

        let period_samples = (sr / f0).round() as usize;
        if period_samples == 0 {
            continue;
        }

        // Need at least 2 periods of audio for autocorrelation
        let center = i * hop_samples;
        let window_size = period_samples * 3;
        let start = center.saturating_sub(window_size / 2);
        let end = (start + window_size).min(samples.len());

        if end - s
frame function · rust · L72-L78 (7 LOC)
core/src/dsp/periodicity.rs
    fn frame(time: f32, freq: Option<f32>) -> PitchFrame {
        PitchFrame {
            time,
            frequency: freq,
        }
    }
Repobility · MCP-ready · https://repobility.com
sine_wave function · rust · L79-L85 (7 LOC)
core/src/dsp/periodicity.rs
    fn sine_wave(freq: f32, sample_rate: u32, duration: f32) -> Vec<f32> {
        let n = (sample_rate as f32 * duration) as usize;
        (0..n)
            .map(|i| (2.0 * PI * freq * i as f32 / sample_rate as f32).sin())
            .collect()
    }
sine_high_periodicity function · rust · L88-L103 (16 LOC)
core/src/dsp/periodicity.rs
    fn sine_high_periodicity() {
        let sr = 44100;
        let samples = sine_wave(100.0, sr, 1.0);
        let hop_ms = 10.0;
        let num_frames = 80;
        let contour: Vec<_> = (0..num_frames)
            .map(|i| frame(i as f32 * hop_ms / 1000.0, Some(100.0)))
            .collect();
        let active = vec![true; num_frames];

        let p = compute_periodicity(&samples, sr, &contour, &active, hop_ms).unwrap();
        assert!(
            p > 0.95,
            "Pure sine should have periodicity near 1.0, got {p:.3}"
        );
    }
noise_low_periodicity function · rust · L106-L129 (24 LOC)
core/src/dsp/periodicity.rs
    fn noise_low_periodicity() {
        let sr = 44100;
        let n = (sr as f32 * 1.0) as usize;
        let mut rng_state: u32 = 42;
        let samples: Vec<f32> = (0..n)
            .map(|_| {
                rng_state = rng_state.wrapping_mul(1103515245).wrapping_add(12345);
                (rng_state as f32 / u32::MAX as f32) * 2.0 - 1.0
            })
            .collect();

        let hop_ms = 10.0;
        let num_frames = 80;
        let contour: Vec<_> = (0..num_frames)
            .map(|i| frame(i as f32 * hop_ms / 1000.0, Some(100.0)))
            .collect();
        let active = vec![true; num_frames];

        let p = compute_periodicity(&samples, sr, &contour, &active, hop_ms).unwrap();
        assert!(
            p < 0.3,
            "Pure noise should have low periodicity, got {p:.3}"
        );
    }
no_voiced_frames function · rust · L132-L136 (5 LOC)
core/src/dsp/periodicity.rs
    fn no_voiced_frames() {
        let contour = vec![frame(0.0, None), frame(0.01, None)];
        let active = vec![true; 2];
        assert!(compute_periodicity(&[0.0; 44100], 44100, &contour, &active, 10.0).is_none());
    }
inactive_frames_skipped function · rust · L139-L151 (13 LOC)
core/src/dsp/periodicity.rs
    fn inactive_frames_skipped() {
        let sr = 44100;
        let samples = sine_wave(100.0, sr, 1.0);
        let hop_ms = 10.0;
        let num_frames = 80;
        let contour: Vec<_> = (0..num_frames)
            .map(|i| frame(i as f32 * hop_ms / 1000.0, Some(100.0)))
            .collect();
        // All frames inactive
        let active = vec![false; num_frames];

        assert!(compute_periodicity(&samples, sr, &contour, &active, hop_ms).is_none());
    }
default function · rust · L60-L74 (15 LOC)
core/src/dsp/pitch.rs
    fn default() -> Self {
        Self {
            pitch_floor_hz: 30.0,
            // 1000 Hz covers falsetto, head voice, and the elevated pitch
            // common in vocal cord paralysis recovery.
            pitch_ceiling_hz: 1000.0,
            frame_size_ms: 30.0,
            hop_size_ms: 10.0,
            // Low power threshold to handle quiet/breathy voices typical
            // in vocal cord paralysis — these signals are often 20-30 dB
            // below normal speech levels.
            power_threshold: 0.2,
            clarity_threshold: 0.2,
        }
    }
energy_based_contour function · rust · L100-L142 (43 LOC)
core/src/dsp/pitch.rs
pub fn energy_based_contour(
    samples: &[f32],
    sample_rate: u32,
    config: &PitchConfig,
    estimated_f0: f32,
    rms_threshold_db: f32,
) -> Vec<PitchFrame> {
    let sr = sample_rate as f32;
    let frame_size = (config.frame_size_ms / 1000.0 * sr) as usize;
    let hop_size = (config.hop_size_ms / 1000.0 * sr) as usize;

    // Match the same stepping as extract_pitch_contour so frame indices
    // map to the same audio positions for shimmer/HNR.
    let min_buffer = (2.0 * sr / config.pitch_floor_hz).ceil() as usize;
    let detector_size = min_buffer.next_power_of_two().max(frame_size);

    let mut contour = Vec::new();
    let mut pos = 0;

    while pos + detector_size <= samples.len() {
        let time = pos as f32 / sr;
        let end = (pos + frame_size).min(samples.len());
        let frame = &samples[pos..end];

        let rms = frame_rms(frame);
        let rms_db = if rms > 0.0 {
            20.0 * rms.log10()
        } else {
            f32::NEG_INFINITY
frame_rms function · rust · L145-L151 (7 LOC)
core/src/dsp/pitch.rs
fn frame_rms(samples: &[f32]) -> f32 {
    if samples.is_empty() {
        return 0.0;
    }
    let sum_sq: f32 = samples.iter().map(|&s| s * s).sum();
    (sum_sq / samples.len() as f32).sqrt()
}
About: code-quality intelligence by Repobility · https://repobility.com
extract_contour_with_fallback function · rust · L160-L243 (84 LOC)
core/src/dsp/pitch.rs
pub fn extract_contour_with_fallback(
    samples: &[f32],
    sample_rate: u32,
    config: &PitchConfig,
) -> ContourResult {
    // Tier 1: Standard pitch detection
    let tier1_contour = extract_pitch_contour(samples, sample_rate, config);
    let voiced_frac = voiced_fraction(&tier1_contour);

    // Tier 2: Relaxed thresholds (always computed for tier tracking)
    let relaxed = PitchConfig {
        pitch_floor_hz: config.pitch_floor_hz,
        pitch_ceiling_hz: config.pitch_ceiling_hz,
        frame_size_ms: config.frame_size_ms,
        hop_size_ms: config.hop_size_ms,
        power_threshold: 0.01,
        clarity_threshold: 0.05,
    };
    let tier2_contour = extract_pitch_contour(samples, sample_rate, &relaxed);
    let relaxed_frac = voiced_fraction(&tier2_contour);

    // Build per-frame tier tracking
    let n_frames = tier1_contour.len();
    let mut frame_tiers = vec![3u8; n_frames]; // default to tier 3
    let mut tier_counts = [0usize; 3];

    for i in 0..n_fra
extract_pitch_contour function · rust · L254-L313 (60 LOC)
core/src/dsp/pitch.rs
pub fn extract_pitch_contour(
    samples: &[f32],
    sample_rate: u32,
    config: &PitchConfig,
) -> Vec<PitchFrame> {
    let sr = sample_rate as f32;

    // Convert milliseconds to samples.
    // e.g., 30ms at 44100 Hz = 1323 samples
    let frame_size = (config.frame_size_ms / 1000.0 * sr) as usize;
    let hop_size = (config.hop_size_ms / 1000.0 * sr) as usize;

    // The McLeod detector needs a buffer large enough to capture at least
    // 2 full cycles of the lowest frequency we want to detect.
    // At 30 Hz and 44100 Hz sample rate: period = 44100/30 = 1470 samples.
    // We need 2x that = 2940. Round up to next power of 2 for FFT efficiency.
    let min_buffer = (2.0 * sr / config.pitch_floor_hz).ceil() as usize;
    let detector_size = min_buffer.next_power_of_two().max(frame_size);

    // Padding helps with edge effects in the autocorrelation.
    // Half the detector size is standard.
    let padding = detector_size / 2;

    let mut contour = Vec::new();
    let 
detect_pitch_frame function · rust · L320-L337 (18 LOC)
core/src/dsp/pitch.rs
pub fn detect_pitch_frame(samples: &[f32], sample_rate: u32) -> Option<f32> {
    let size = samples.len();
    let padding = size / 2;
    let windowed = windowing::hanning(samples);
    let padded: Vec<f64> = windowed.iter().map(|&s| s as f64).collect();

    let mut detector = McLeodDetector::new(size, padding);
    let pitch = detector.get_pitch(
        &padded,
        sample_rate as usize,
        0.2,  // power threshold
        0.2,  // clarity threshold
    );

    pitch
        .map(|p| p.frequency as f32)
        .filter(|&f| f >= 50.0 && f <= 1000.0)
}
freq_to_note function · rust · L343-L359 (17 LOC)
core/src/dsp/pitch.rs
pub fn freq_to_note(freq_hz: f32) -> (&'static str, i32, f32) {
    const NOTE_NAMES: [&str; 12] = [
        "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B",
    ];

    // Semitones from A4 (440 Hz)
    let semitones_from_a4 = 12.0 * (freq_hz / 440.0).log2();
    let nearest_semitone = semitones_from_a4.round() as i32;
    let cents = (semitones_from_a4 - nearest_semitone as f32) * 100.0;

    // A4 is MIDI note 69 → note index 9 in octave 4
    let midi = 69 + nearest_semitone;
    let note_index = ((midi % 12) + 12) % 12; // handle negatives
    let octave = (midi / 12) - 1;

    (NOTE_NAMES[note_index as usize], octave, cents)
}
voiced_frequencies function · rust · L364-L369 (6 LOC)
core/src/dsp/pitch.rs
pub fn voiced_frequencies(contour: &[PitchFrame]) -> Vec<f32> {
    contour
        .iter()
        .filter_map(|frame| frame.frequency)
        .collect()
}
voiced_fraction function · rust · L373-L379 (7 LOC)
core/src/dsp/pitch.rs
pub fn voiced_fraction(contour: &[PitchFrame]) -> f32 {
    if contour.is_empty() {
        return 0.0;
    }
    let voiced = contour.iter().filter(|f| f.frequency.is_some()).count();
    voiced as f32 / contour.len() as f32
}
sine_wave function · rust · L388-L396 (9 LOC)
core/src/dsp/pitch.rs
    fn sine_wave(freq_hz: f32, sample_rate: u32, duration_secs: f32) -> Vec<f32> {
        let num_samples = (sample_rate as f32 * duration_secs) as usize;
        (0..num_samples)
            .map(|i| {
                let t = i as f32 / sample_rate as f32;
                (2.0 * PI * freq_hz * t).sin()
            })
            .collect()
    }
detects_100hz_sine function · rust · L399-L415 (17 LOC)
core/src/dsp/pitch.rs
    fn detects_100hz_sine() {
        let samples = sine_wave(100.0, 44100, 0.5);
        let config = PitchConfig::default();
        let contour = extract_pitch_contour(&samples, 44100, &config);

        let frequencies = voiced_frequencies(&contour);
        assert!(
            !frequencies.is_empty(),
            "Should detect pitch in a pure sine wave"
        );

        let mean: f32 = frequencies.iter().sum::<f32>() / frequencies.len() as f32;
        assert!(
            (mean - 100.0).abs() < 5.0,
            "Mean pitch should be ~100 Hz, got {mean:.1} Hz"
        );
    }
Repobility · severity-and-effort ranking · https://repobility.com
detects_low_pitch_50hz function · rust · L418-L435 (18 LOC)
core/src/dsp/pitch.rs
    fn detects_low_pitch_50hz() {
        // This tests our 30 Hz floor — most detectors would miss this
        let samples = sine_wave(50.0, 44100, 1.0);
        let config = PitchConfig::default();
        let contour = extract_pitch_contour(&samples, 44100, &config);

        let frequencies = voiced_frequencies(&contour);
        assert!(
            !frequencies.is_empty(),
            "Should detect 50 Hz with our low floor"
        );

        let mean: f32 = frequencies.iter().sum::<f32>() / frequencies.len() as f32;
        assert!(
            (mean - 50.0).abs() < 5.0,
            "Mean pitch should be ~50 Hz, got {mean:.1} Hz"
        );
    }
silence_is_unvoiced function · rust · L438-L448 (11 LOC)
core/src/dsp/pitch.rs
    fn silence_is_unvoiced() {
        let samples = vec![0.0; 44100]; // 1 second of silence
        let config = PitchConfig::default();
        let contour = extract_pitch_contour(&samples, 44100, &config);

        let vf = voiced_fraction(&contour);
        assert!(
            vf < 0.1,
            "Silence should be mostly unvoiced, got {vf:.2}"
        );
    }
voiced_fraction_empty function · rust · L451-L453 (3 LOC)
core/src/dsp/pitch.rs
    fn voiced_fraction_empty() {
        assert_eq!(voiced_fraction(&[]), 0.0);
    }
contour_timestamps_increase function · rust · L456-L467 (12 LOC)
core/src/dsp/pitch.rs
    fn contour_timestamps_increase() {
        let samples = sine_wave(100.0, 44100, 0.5);
        let config = PitchConfig::default();
        let contour = extract_pitch_contour(&samples, 44100, &config);

        for pair in contour.windows(2) {
            assert!(
                pair[1].time > pair[0].time,
                "Timestamps should be strictly increasing"
            );
        }
    }
energy_contour_detects_signal function · rust · L470-L480 (11 LOC)
core/src/dsp/pitch.rs
    fn energy_contour_detects_signal() {
        let samples = sine_wave(100.0, 44100, 0.5);
        let config = PitchConfig::default();
        let contour = energy_based_contour(&samples, 44100, &config, 100.0, -45.0);

        let vf = voiced_fraction(&contour);
        assert!(
            vf > 0.8,
            "Energy detector should find most of a sine wave, got {vf:.2}"
        );
    }
energy_contour_rejects_silence function · rust · L483-L493 (11 LOC)
core/src/dsp/pitch.rs
    fn energy_contour_rejects_silence() {
        let samples = vec![0.0; 44100];
        let config = PitchConfig::default();
        let contour = energy_based_contour(&samples, 44100, &config, 100.0, -45.0);

        let vf = voiced_fraction(&contour);
        assert!(
            vf < 0.01,
            "Energy detector should reject silence, got {vf:.2}"
        );
    }
energy_contour_matches_pitch_contour_length function · rust · L496-L507 (12 LOC)
core/src/dsp/pitch.rs
    fn energy_contour_matches_pitch_contour_length() {
        let samples = sine_wave(100.0, 44100, 1.0);
        let config = PitchConfig::default();
        let pitch_contour = extract_pitch_contour(&samples, 44100, &config);
        let energy_contour = energy_based_contour(&samples, 44100, &config, 100.0, -45.0);

        assert_eq!(
            pitch_contour.len(),
            energy_contour.len(),
            "Energy and pitch contours should have the same number of frames"
        );
    }
fallback_uses_tier1_for_clean_signal function · rust · L510-L522 (13 LOC)
core/src/dsp/pitch.rs
    fn fallback_uses_tier1_for_clean_signal() {
        // A strong sine wave should be detected by tier 1 — no energy fallback.
        let samples = sine_wave(100.0, 44100, 1.0);
        let config = PitchConfig::default();
        let result = extract_contour_with_fallback(&samples, 44100, &config);

        assert!(
            !result.used_energy_fallback,
            "Clean sine wave should not trigger energy fallback"
        );
        let vf = voiced_fraction(&result.contour);
        assert!(vf > 0.5, "Should detect most frames, got {vf:.2}");
    }
Open data scored by Repobility · https://repobility.com
fallback_uses_energy_for_silence function · rust · L525-L537 (13 LOC)
core/src/dsp/pitch.rs
    fn fallback_uses_energy_for_silence() {
        // Near-silence should exhaust tiers 1+2 and land on energy fallback.
        // With all-zero samples the energy detector also finds nothing,
        // so used_energy_fallback=true but voiced fraction is ~0.
        let samples = vec![0.0; 44100];
        let config = PitchConfig::default();
        let result = extract_contour_with_fallback(&samples, 44100, &config);

        assert!(
            result.used_energy_fallback,
            "Silence should trigger energy fallback"
        );
    }
detect_pitch_frame_sine function · rust · L540-L549 (10 LOC)
core/src/dsp/pitch.rs
    fn detect_pitch_frame_sine() {
        let samples = sine_wave(220.0, 44100, 0.1);
        let hz = detect_pitch_frame(&samples[..2048], 44100);
        assert!(hz.is_some(), "Should detect pitch from a sine frame");
        let freq = hz.unwrap();
        assert!(
            (freq - 220.0).abs() < 10.0,
            "Expected ~220 Hz, got {freq:.1} Hz"
        );
    }
detect_pitch_frame_silence function · rust · L552-L555 (4 LOC)
core/src/dsp/pitch.rs
    fn detect_pitch_frame_silence() {
        let samples = vec![0.0; 2048];
        assert!(detect_pitch_frame(&samples, 44100).is_none());
    }
freq_to_note_a4 function · rust · L558-L563 (6 LOC)
core/src/dsp/pitch.rs
    fn freq_to_note_a4() {
        let (note, octave, cents) = freq_to_note(440.0);
        assert_eq!(note, "A");
        assert_eq!(octave, 4);
        assert!(cents.abs() < 1.0, "440 Hz should be in tune, got {cents:.1} cents");
    }
freq_to_note_c4 function · rust · L566-L572 (7 LOC)
core/src/dsp/pitch.rs
    fn freq_to_note_c4() {
        // C4 = 261.63 Hz
        let (note, octave, cents) = freq_to_note(261.63);
        assert_eq!(note, "C");
        assert_eq!(octave, 4);
        assert!(cents.abs() < 2.0);
    }
freq_to_note_sharp function · rust · L575-L581 (7 LOC)
core/src/dsp/pitch.rs
    fn freq_to_note_sharp() {
        // Slightly above A4 — should be A4 with positive cents
        let (note, octave, cents) = freq_to_note(445.0);
        assert_eq!(note, "A");
        assert_eq!(octave, 4);
        assert!(cents > 0.0, "445 Hz should be sharp");
    }
freq_to_note_flat function · rust · L584-L590 (7 LOC)
core/src/dsp/pitch.rs
    fn freq_to_note_flat() {
        // Slightly below A4 — should be A4 with negative cents
        let (note, octave, cents) = freq_to_note(435.0);
        assert_eq!(note, "A");
        assert_eq!(octave, 4);
        assert!(cents < 0.0, "435 Hz should be flat");
    }
local_shimmer_percent function · rust · L19-L81 (63 LOC)
core/src/dsp/shimmer.rs
pub fn local_shimmer_percent(
    samples: &[f32],
    sample_rate: u32,
    contour: &[PitchFrame],
    hop_size_ms: f32,
) -> Option<f32> {
    let sr = sample_rate as f32;
    let hop_samples = (hop_size_ms / 1000.0 * sr) as usize;

    // For each voiced frame, compute the peak amplitude over one pitch period.
    // We pair up the amplitude with whether this frame is consecutive to the
    // previous voiced frame (no unvoiced gap in between).
    let mut amplitudes: Vec<f32> = Vec::new();
    let mut perturbations: Vec<f32> = Vec::new();
    let mut prev_amp: Option<f32> = None;

    for (i, frame) in contour.iter().enumerate() {
        match frame.frequency {
            Some(f0) => {
                // One pitch period in samples: at 100 Hz and 44100 Hz SR, that's 441 samples
                let period_samples = (sr / f0).round() as usize;

                // Position of this frame in the audio buffer
                let start = i * hop_samples;
                let end = (star
Repobility · MCP-ready · https://repobility.com
local_shimmer_percent_gated function · rust · L93-L168 (76 LOC)
core/src/dsp/shimmer.rs
pub fn local_shimmer_percent_gated(
    samples: &[f32],
    sample_rate: u32,
    contour: &[PitchFrame],
    frame_tiers: &[u8],
    hop_size_ms: f32,
) -> Option<f32> {
    if contour.len() != frame_tiers.len() {
        return None;
    }

    let sr = sample_rate as f32;
    let hop_samples = (hop_size_ms / 1000.0 * sr) as usize;

    let mut amplitudes: Vec<f32> = Vec::new();
    let mut perturbations: Vec<f32> = Vec::new();
    let mut prev_amp: Option<f32> = None;
    let mut consecutive = 0_usize;
    let mut max_consecutive = 0_usize;
    let mut total_gated_frames = 0_usize;

    for (i, (frame, &tier)) in contour.iter().zip(frame_tiers.iter()).enumerate() {
        match frame.frequency {
            Some(f0) if tier <= 2 => {
                let period_samples = (sr / f0).round() as usize;
                let start = i * hop_samples;
                let end = (start + period_samples).min(samples.len());

                if start >= samples.len() || start >= end {
         
frame function · rust · L174-L180 (7 LOC)
core/src/dsp/shimmer.rs
    fn frame(time: f32, freq: Option<f32>) -> PitchFrame {
        PitchFrame {
            time,
            frequency: freq,
        }
    }
sine_wave function · rust · L183-L188 (6 LOC)
core/src/dsp/shimmer.rs
    fn sine_wave(freq: f32, sample_rate: u32, duration: f32) -> Vec<f32> {
        let n = (sample_rate as f32 * duration) as usize;
        (0..n)
            .map(|i| (2.0 * PI * freq * i as f32 / sample_rate as f32).sin())
            .collect()
    }
constant_amplitude_low_shimmer function · rust · L191-L207 (17 LOC)
core/src/dsp/shimmer.rs
    fn constant_amplitude_low_shimmer() {
        let sr = 44100;
        let samples = sine_wave(100.0, sr, 0.5);

        // Build contour: all frames at 100 Hz, 10ms hop
        let hop_ms = 10.0;
        let num_frames = (500.0 / hop_ms) as usize;
        let contour: Vec<_> = (0..num_frames)
            .map(|i| frame(i as f32 * hop_ms / 1000.0, Some(100.0)))
            .collect();

        let shimmer = local_shimmer_percent(&samples, sr, &contour, hop_ms).unwrap();
        assert!(
            shimmer < 5.0,
            "Constant-amplitude sine should have low shimmer, got {shimmer:.2}%"
        );
    }
amplitude_modulated_high_shimmer function · rust · L210-L235 (26 LOC)
core/src/dsp/shimmer.rs
    fn amplitude_modulated_high_shimmer() {
        let sr = 44100;
        // Create a signal where amplitude alternates between 0.5 and 1.0
        let n = (sr as f32 * 0.5) as usize;
        let hop_ms = 10.0;
        let hop_samples = (hop_ms / 1000.0 * sr as f32) as usize;

        let samples: Vec<f32> = (0..n)
            .map(|i| {
                let frame_idx = i / hop_samples;
                let amp = if frame_idx % 2 == 0 { 1.0 } else { 0.5 };
                amp * (2.0 * PI * 100.0 * i as f32 / sr as f32).sin()
            })
            .collect();

        let num_frames = n / hop_samples;
        let contour: Vec<_> = (0..num_frames)
            .map(|i| frame(i as f32 * hop_ms / 1000.0, Some(100.0)))
            .collect();

        let shimmer = local_shimmer_percent(&samples, sr, &contour, hop_ms).unwrap();
        assert!(
            shimmer > 20.0,
            "Alternating amplitude should show high shimmer, got {shimmer:.2}%"
        );
    }
insufficient_data function · rust · L238-L241 (4 LOC)
core/src/dsp/shimmer.rs
    fn insufficient_data() {
        let contour = vec![frame(0.0, Some(100.0))];
        assert!(local_shimmer_percent(&[0.0; 1000], 44100, &contour, 10.0).is_none());
    }
count_voice_breaks function · rust · L18-L47 (30 LOC)
core/src/dsp/voice_breaks.rs
pub fn count_voice_breaks(contour: &[PitchFrame], hop_size_ms: f32, max_break_ms: f32) -> usize {
    let runs = contour::voiced_runs(contour);

    if runs.len() < 2 {
        return 0;
    }

    let min_gap_ms = 50.0;
    let max_gap_ms = max_break_ms;

    let mut breaks = 0;

    // Look at the gaps between consecutive voiced runs.
    // Each gap is the space between one run ending and the next one starting.
    for pair in runs.windows(2) {
        let (_, end_of_prev) = pair[0];
        let (start_of_next, _) = pair[1];

        // Gap in frames: from the frame after the previous run ends
        // to the frame before the next run starts
        let gap_frames = start_of_next - end_of_prev - 1;
        let gap_ms = gap_frames as f32 * hop_size_ms;

        if gap_ms >= min_gap_ms && gap_ms <= max_gap_ms {
            breaks += 1;
        }
    }

    breaks
}
frame function · rust · L52-L58 (7 LOC)
core/src/dsp/voice_breaks.rs
    fn frame(time: f32, freq: Option<f32>) -> PitchFrame {
        PitchFrame {
            time,
            frequency: freq,
        }
    }
About: code-quality intelligence by Repobility · https://repobility.com
no_breaks_continuous_voicing function · rust · L75-L78 (4 LOC)
core/src/dsp/voice_breaks.rs
    fn no_breaks_continuous_voicing() {
        let contour = make_contour(&[(100, true)], 10.0);
        assert_eq!(count_voice_breaks(&contour, 10.0, 250.0), 0);
    }
one_break_80ms_gap function · rust · L81-L85 (5 LOC)
core/src/dsp/voice_breaks.rs
    fn one_break_80ms_gap() {
        // voiced (20 frames) → 80ms gap (8 frames) → voiced (20 frames)
        let contour = make_contour(&[(20, true), (8, false), (20, true)], 10.0);
        assert_eq!(count_voice_breaks(&contour, 10.0, 250.0), 1);
    }
short_gap_not_a_break function · rust · L88-L92 (5 LOC)
core/src/dsp/voice_breaks.rs
    fn short_gap_not_a_break() {
        // 30ms gap (3 frames at 10ms) — normal consonant, not a break
        let contour = make_contour(&[(20, true), (3, false), (20, true)], 10.0);
        assert_eq!(count_voice_breaks(&contour, 10.0, 250.0), 0);
    }
‹ prevpage 3 / 10next ›