11// Copyright (c) 2025 Ronan LE MEILLAT, SCTG Development
22// This file is part of the rust-photoacoustic project and is licensed under the
33// SCTG Development Non-Commercial License v1.0 (see LICENSE.md for details).
4- //! Differential processor utility
4+
5+ //! # Differential Processor Utility
6+ //!
7+ //! This binary tool processes WAV audio files to create differential signals for photoacoustic analysis.
8+ //! It supports several processing modes to help extract the relevant signal components from raw recordings.
9+ //!
10+ //! ## Features
11+ //!
12+ //! * Process stereo files and output the difference between channels (L-R or R-L)
13+ //! * Process two mono files and output their difference (file1-file2)
14+ //! * Apply gain adjustment to the resulting differential signal
15+ //!
16+ //! ## Usage
17+ //!
18+ //! ```
19+ //! differential --input input.wav --output output.wav --mode LeftMinusRight --gain 1.0
20+ //! ```
21+ //!
22+ //! For File1MinusFile2 mode:
23+ //!
24+ //! ```
25+ //! differential --input file1.wav --input2 file2.wav --output result.wav --mode File1MinusFile2
26+ //! ```
27+ //!
28+ //! ## Applications in Photoacoustic Analysis
29+ //!
30+ //! In photoacoustic spectroscopy, differential signals help isolate the actual acoustic response
31+ //! by removing common mode noise. This is particularly useful when:
532//!
6- //! This binary tool processes WAV files to create differential signals.
7- //! It can:
8- //! 1. Process a stereo file and output the difference between channels (L-R or R-L)
9- //! 2. Process two mono files and output their difference (file1-file2)
33+ //! 1. Using stereo recordings where one channel contains the signal+noise and the other contains just noise
34+ //! 2. Comparing before/after recordings to isolate the effect of a stimulus
1035
1136use clap:: { Parser , ValueEnum } ;
1237use hound:: { SampleFormat , WavReader , WavSpec , WavWriter } ;
1338use rust_photoacoustic:: preprocessing:: differential;
1439use std:: path:: PathBuf ;
1540
41+ /// Defines the different modes of differential signal processing.
42+ ///
43+ /// The mode determines which channels or files are subtracted from each other
44+ /// to create the output signal.
1645#[ derive( Debug , Copy , Clone , PartialEq , Eq , PartialOrd , Ord , ValueEnum ) ]
1746enum DifferentialMode {
18- /// Left minus Right (for stereo files)
47+ /// Left channel minus Right channel (for stereo files).
48+ ///
49+ /// This mode is useful when the left channel contains signal+noise and
50+ /// the right channel contains a reference noise recording.
1951 LeftMinusRight ,
20- /// Right minus Left (for stereo files)
52+
53+ /// Right channel minus Left channel (for stereo files).
54+ ///
55+ /// This mode is useful when the right channel contains signal+noise and
56+ /// the left channel contains a reference noise recording.
2157 RightMinusLeft ,
22- /// File1 minus File2 (for two mono files)
58+
59+ /// First file minus Second file (for two mono files).
60+ ///
61+ /// This mode allows processing two separate recordings, such as with/without
62+ /// stimulus or before/after a treatment.
2363 File1MinusFile2 ,
2464}
2565
66+ /// Command line arguments for the differential signal processor.
67+ ///
68+ /// This structure defines all the parameters that can be provided via command line
69+ /// to control the differential processing of WAV files.
2670#[ derive( Parser , Debug ) ]
2771#[ command( name = "differential" ) ]
28- #[ command( author = "Romain Lemeill " ) ]
72+ #[ command( author = "Ronan LE MEILLAT " ) ]
2973#[ command( version = "1.0" ) ]
3074#[ command( about = "Create differential signals from WAV files" , long_about = None ) ]
3175struct Args {
32- /// Input WAV file (stereo or mono)
76+ /// Input WAV file (stereo or mono).
77+ ///
78+ /// This is the primary input file. For LeftMinusRight and RightMinusLeft modes,
79+ /// this must be a stereo file. For File1MinusFile2 mode, this should be a mono file.
3380 #[ arg( short = 'i' , long) ]
3481 input : PathBuf ,
3582
36- /// Second input WAV file (only used in File1MinusFile2 mode)
83+ /// Second input WAV file (only used in File1MinusFile2 mode).
84+ ///
85+ /// This file is subtracted from the primary input file. It must be mono
86+ /// and have the same sample rate and bit depth as the primary input.
3787 #[ arg( short = '2' , long) ]
3888 input2 : Option < PathBuf > ,
3989
40- /// Output WAV file
90+ /// Output WAV file path where the differential signal will be saved.
91+ ///
92+ /// The output will always be a mono WAV file with the same sample rate
93+ /// and bit depth as the input.
4194 #[ arg( short, long) ]
4295 output : PathBuf ,
4396
44- /// Differential mode
97+ /// Differential mode determining how the signals are combined.
98+ ///
99+ /// Specifies which processing method to use: LeftMinusRight (default),
100+ /// RightMinusLeft, or File1MinusFile2.
45101 #[ arg( short, long, value_enum, default_value_t = DifferentialMode :: LeftMinusRight ) ]
46102 mode : DifferentialMode ,
47103
48- /// Gain to apply to the output (multiplier)
104+ /// Gain to apply to the output (multiplier).
105+ ///
106+ /// This value multiplies each sample of the differential signal.
107+ /// Values greater than 1.0 amplify the signal, values less than 1.0 attenuate it.
108+ /// The result is clamped to prevent digital clipping.
49109 #[ arg( short, long, default_value_t = 1.0 ) ]
50110 gain : f32 ,
51111}
52112
113+ /// Main entry point for the differential signal processing utility.
114+ ///
115+ /// Parses command line arguments and routes processing to the appropriate function
116+ /// based on the selected differential mode.
53117fn main ( ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
54118 let args = Args :: parse ( ) ;
55119
@@ -74,6 +138,26 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
74138 Ok ( ( ) )
75139}
76140
141+ /// Processes a stereo WAV file to create a differential signal.
142+ ///
143+ /// This function handles the LeftMinusRight and RightMinusLeft modes.
144+ /// It reads a stereo file, separates the channels, and creates a mono
145+ /// output file with the difference between the channels.
146+ ///
147+ /// # Arguments
148+ ///
149+ /// * `args` - Command line arguments containing input/output paths and processing parameters
150+ ///
151+ /// # Returns
152+ ///
153+ /// * `Result<(), Box<dyn std::error::Error>>` - Success or an error with description
154+ ///
155+ /// # Errors
156+ ///
157+ /// Will return an error if:
158+ /// - The input file cannot be read
159+ /// - The input file is not stereo
160+ /// - There is an issue writing the output file
77161fn process_stereo_file ( args : & Args ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
78162 println ! ( "Reading stereo file {:?}" , args. input) ;
79163
@@ -139,6 +223,26 @@ fn process_stereo_file(args: &Args) -> Result<(), Box<dyn std::error::Error>> {
139223 Ok ( ( ) )
140224}
141225
226+ /// Processes two mono WAV files to create a differential signal.
227+ ///
228+ /// This function handles the File1MinusFile2 mode. It reads two mono files,
229+ /// verifies their compatibility, and creates an output file with their difference.
230+ ///
231+ /// # Arguments
232+ ///
233+ /// * `args` - Command line arguments containing input/output paths and processing parameters
234+ ///
235+ /// # Returns
236+ ///
237+ /// * `Result<(), Box<dyn std::error::Error>>` - Success or an error with description
238+ ///
239+ /// # Errors
240+ ///
241+ /// Will return an error if:
242+ /// - Either input file cannot be read
243+ /// - Either input file is not mono
244+ /// - The input files have incompatible sample rates or bit depths
245+ /// - There is an issue writing the output file
142246fn process_two_mono_files ( args : & Args ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
143247 let input2 = args. input2 . as_ref ( ) . unwrap ( ) ; // Safe because we checked earlier
144248
0 commit comments