proteus_lib/peaks/mod.rs
1//! Peak extraction and binary peak-file utilities for waveform display.
2
3mod error;
4mod extract;
5mod format;
6
7pub use error::PeaksError;
8
9/// A single peak window with maximum and minimum sample amplitude.
10#[derive(Debug, Clone, Copy)]
11pub struct PeakWindow {
12 pub max: f32,
13 pub min: f32,
14}
15
16/// Peak data for all channels at a fixed window size.
17#[derive(Debug, Clone)]
18pub struct PeaksData {
19 pub sample_rate: u32,
20 pub window_size: u32,
21 pub channels: Vec<Vec<PeakWindow>>,
22}
23
24/// Query options for reading peaks from a binary peaks file.
25#[derive(Debug, Clone, Default)]
26pub struct GetPeaksOptions {
27 /// Start timestamp in seconds (inclusive). If omitted, reads from file start.
28 pub start_seconds: Option<f64>,
29 /// End timestamp in seconds (exclusive). If omitted, reads to file end.
30 pub end_seconds: Option<f64>,
31 /// Maximum number of peak windows to return per channel.
32 ///
33 /// When used with both `start_seconds` and `end_seconds`, returns exactly this
34 /// many windows aligned to the requested time range, zero-padding windows that
35 /// fall outside available audio. Otherwise, this acts as a maximum output size.
36 pub target_peaks: Option<usize>,
37 /// Maximum number of channels to return.
38 ///
39 /// Channels are selected from index 0 upward.
40 pub channels: Option<usize>,
41}
42
43/// Decode an audio file and write its peaks to a binary file.
44///
45/// # Arguments
46/// * `input_audio_file` - Source audio path.
47/// * `output_peaks_file` - Destination binary peaks file path.
48///
49/// # Errors
50/// Returns an error if audio decode fails or if writing the peaks file fails.
51pub fn write_peaks(input_audio_file: &str, output_peaks_file: &str) -> Result<(), PeaksError> {
52 let peaks = extract::extract_peaks_from_audio(input_audio_file, false)?;
53 format::write_peaks_file(output_peaks_file, &peaks)
54}
55
56/// Read all peaks from a binary peaks file.
57///
58/// # Arguments
59/// * `peaks_file` - Path to a binary peaks file previously written by [`write_peaks`].
60/// * `options` - Query options for range, peak count, and channel count.
61///
62/// # Returns
63/// Per-channel peak data after applying range/channel/downsample options.
64///
65/// # Errors
66/// Returns an error if the file cannot be read or has an invalid peaks format.
67pub fn get_peaks(peaks_file: &str, options: GetPeaksOptions) -> Result<PeaksData, PeaksError> {
68 format::read_peaks_with_options(peaks_file, &options)
69}
70
71/// Read all channels and all peaks from a binary peaks file.
72///
73/// # Arguments
74/// * `peaks_file` - Path to a binary peaks file previously written by [`write_peaks`].
75///
76/// # Returns
77/// Full per-channel peak data.
78///
79/// # Errors
80/// Returns an error if the file cannot be read or has an invalid peaks format.
81pub fn get_all_peaks(peaks_file: &str) -> Result<PeaksData, PeaksError> {
82 get_peaks(peaks_file, GetPeaksOptions::default())
83}
84
85/// Read peaks from a binary peaks file for a specific time range in seconds.
86///
87/// # Arguments
88/// * `peaks_file` - Path to a binary peaks file.
89/// * `start_seconds` - Start timestamp (inclusive).
90/// * `end_seconds` - End timestamp (exclusive).
91///
92/// # Returns
93/// Per-channel peak data for the requested time range.
94///
95/// # Errors
96/// Returns an error if timestamps are invalid, or if file IO/format parsing fails.
97pub fn get_peaks_in_range(
98 peaks_file: &str,
99 start_seconds: f64,
100 end_seconds: f64,
101) -> Result<PeaksData, PeaksError> {
102 get_peaks(
103 peaks_file,
104 GetPeaksOptions {
105 start_seconds: Some(start_seconds),
106 end_seconds: Some(end_seconds),
107 ..Default::default()
108 },
109 )
110}
111
112/// Decode an audio file directly into in-memory peaks.
113///
114/// # Arguments
115/// * `file_path` - Source audio path.
116/// * `limited` - If true, only channel 0 is processed.
117///
118/// # Returns
119/// In-memory per-channel peak data.
120///
121/// # Errors
122/// Returns an error if decoding fails.
123pub fn extract_peaks_from_audio(file_path: &str, limited: bool) -> Result<PeaksData, PeaksError> {
124 extract::extract_peaks_from_audio(file_path, limited)
125}