//! LocalVoiceMode v2 - Rust GUI Application
//!
//! High-fidelity voice interface with lightsaber waveform visualization.
// Hide console window on Windows in release builds
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
mod app;
mod audio;
mod ipc;
mod state;
mod ui;
use anyhow::Result;
use eframe::egui;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
fn main() -> Result<()> {
// Initialize logging (filter out noisy wgpu logs)
tracing_subscriber::registry()
.with(EnvFilter::try_from_default_env().unwrap_or_else(|_| {
EnvFilter::new("info,wgpu_core=warn,wgpu_hal=warn,naga=warn")
}))
.with(tracing_subscriber::fmt::layer())
.init();
tracing::info!("Starting LocalVoiceMode v2");
// Load saved config for window state
let config = state::AppConfig::load();
// Build viewport with saved or default size/position
let mut viewport = egui::ViewportBuilder::default()
.with_min_inner_size([300.0, 200.0])
.with_title("LocalVoiceMode")
.with_icon(load_icon());
// Apply saved window size
if let (Some(w), Some(h)) = (config.window_width, config.window_height) {
viewport = viewport.with_inner_size([w, h]);
} else {
viewport = viewport.with_inner_size([1200.0, 800.0]);
}
// Apply saved window position
if let (Some(x), Some(y)) = (config.window_x, config.window_y) {
viewport = viewport.with_position([x, y]);
}
// Configure eframe with wgpu backend
let options = eframe::NativeOptions {
viewport,
renderer: eframe::Renderer::Wgpu,
..Default::default()
};
// Run the application
eframe::run_native(
"LocalVoiceMode",
options,
Box::new(|cc| Ok(Box::new(app::VoiceModeApp::new(cc)))),
)
.map_err(|e| anyhow::anyhow!("Failed to run application: {}", e))?;
Ok(())
}
/// Load application icon from Microphone.ico
fn load_icon() -> egui::IconData {
let icon_bytes = include_bytes!("../assets/Microphone.ico");
// Load ICO and get the largest image
match image::load_from_memory_with_format(icon_bytes, image::ImageFormat::Ico) {
Ok(img) => {
let rgba = img.to_rgba8();
let (width, height) = rgba.dimensions();
egui::IconData {
rgba: rgba.into_raw(),
width,
height,
}
}
Err(e) => {
tracing::warn!("Failed to load icon: {}", e);
egui::IconData::default()
}
}
}