aboutsummaryrefslogtreecommitdiff
path: root/src/args.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/args.rs')
-rw-r--r--src/args.rs120
1 files changed, 100 insertions, 20 deletions
diff --git a/src/args.rs b/src/args.rs
index fcf224c..52dddfc 100644
--- a/src/args.rs
+++ b/src/args.rs
@@ -1,12 +1,51 @@
use std::path::PathBuf;
+/// Whether verbose debug output is enabled.
+/// Set by `DMVOPArguments::verbose`.
+pub static VERBOSE: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
+
+/// Print a debug message only when `--verbose` is set.
+#[macro_export]
+macro_rules! debug_log {
+ ($($arg:tt)*) => {
+ if $crate::args::VERBOSE.load(std::sync::atomic::Ordering::Relaxed) {
+ eprintln!($($arg)*);
+ }
+ };
+}
+
#[derive(clap::Parser)]
-#[command(
- no_binary_name = true,
- disable_help_flag = true,
- disable_version_flag = true
-)]
+#[command(name = "dmvop", disable_help_flag = true, disable_version_flag = true)]
pub struct DMVOPArguments {
+ // Verbose output (show debug messages)
+ #[arg(long = "verbose", short = 'V')]
+ pub verbose: bool,
+
+ // List all available input devices and exit
+ #[arg(long = "list-devices", alias = "list", short = 'L')]
+ pub list_devices: bool,
+
+ // List all available Whisper models and exit
+ #[arg(long = "list-models")]
+ pub list_models: bool,
+
+ // Download a specific Whisper model and exit
+ #[arg(long = "download-model", alias = "get-model", require_equals = true)]
+ pub download_model: Option<String>,
+
+ // Language hint for Whisper (e.g. en, zh, ja). Auto-detects if not set.
+ #[arg(long = "lang", require_equals = true)]
+ pub lang: Option<String>,
+
+ // Whisper model to use (e.g. tiny, base, small, medium, large-v3)
+ #[arg(
+ long = "model",
+ short = 'm',
+ default_value = "base_en",
+ require_equals = true
+ )]
+ pub model: String,
+
// Devices (unix/linux device or WASAPI name)
#[arg(
long = "device",
@@ -14,7 +53,7 @@ pub struct DMVOPArguments {
allow_hyphen_values = true,
require_equals = true
)]
- device_name: String,
+ pub device_name: Option<String>,
// Format
// Use %{param} to represent a parameter
@@ -30,24 +69,25 @@ pub struct DMVOPArguments {
default_value = "%{vol},%{word}",
require_equals = true
)]
- format_pattern: Option<String>,
+ pub format_pattern: Option<String>,
+
+ #[arg(long = "format-file", short = 'S', require_equals = true)]
+ pub format_file: Option<PathBuf>,
+ // Output (can be specified multiple times)
#[arg(
- long = "format-file",
- short = 'S',
- alias = "fmt",
- require_equals = true
+ long,
+ short = 'O',
+ require_equals = true,
+ default_value = "stdout",
+ num_args = 1
)]
- format_file: Option<PathBuf>,
-
- // Output
- #[arg(long, short = 'O', require_equals = true, default_value = "stdout")]
- output: OutputMode,
+ pub output: Vec<OutputMode>,
// MISC
// Port (default: 5117)
#[arg(long, short = 'p', default_value_t = 5117, require_equals = true)]
- port: u16,
+ pub port: u16,
// Socket file (default: ./dmvop.sock in current directory)
#[arg(
@@ -56,7 +96,7 @@ pub struct DMVOPArguments {
default_value = "./dmvop.sock",
require_equals = true
)]
- socket_file: PathBuf,
+ pub socket_file: PathBuf,
// Subnet mask for UDP broadcast (default: only last octet, e.g., "255.255.255.0")
#[arg(
@@ -65,10 +105,10 @@ pub struct DMVOPArguments {
default_value = "255.255.255.0",
require_equals = true
)]
- subnet_mask: String,
+ pub subnet_mask: String,
}
-#[derive(Clone)]
+#[derive(Clone, Debug)]
#[allow(non_camel_case_types)]
pub enum OutputMode {
/// Establish a basic TCP service, broadcasting output to all connected sockets
@@ -103,3 +143,43 @@ impl std::str::FromStr for OutputMode {
}
}
}
+
+/// Parse a format pattern string and produce a formatted output string
+/// from the provided values.
+///
+/// Supported placeholders:
+/// - `%{vol}` — volume 0–100
+/// - `%{word}` — transcribed word/text
+/// - `%{confid}` / `%{confidence}` — confidence score
+pub fn format_output(pattern: &str, word: &str, confidence: f32, volume: f32) -> String {
+ let mut result = pattern.to_string();
+
+ // Volume: clamp dB range (~-60 to 0) to 0–100 scale
+ // Typical speech is around -30 dB to -12 dB
+ let vol_normalized = ((volume + 60.0).clamp(0.0, 60.0) / 60.0 * 100.0) as u32;
+
+ // Replace known placeholders
+ result = result.replace("%{vol}", &vol_normalized.to_string());
+ result = result.replace("%{word}", word);
+ result = result.replace("%{confid}", &format!("{:.1}", confidence));
+ result = result.replace("%{confidence}", &format!("{:.1}", confidence));
+
+ result
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_format_output() {
+ let s = format_output("%{vol},%{word},%{confid}", "hello", 95.0, -12.0);
+ assert_eq!(s, "80,hello,95.0");
+ }
+
+ #[test]
+ fn test_format_output_no_volume() {
+ let s = format_output("text: %{word}", "world", 0.0, -60.0);
+ assert_eq!(s, "text: world");
+ }
+}