use dsp_thomann::dsp408::types::DelayUnit; use tauri::State; use crate::state::{AppState, DSPDevice}; use dsp_thomann::dsp408::{DSP408, types}; use std::{net::IpAddr, str::FromStr}; use std::sync::{Arc, Mutex}; impl AppState { pub fn with_device_mut( &self, id: u64, f: F, ) -> Result where F: FnOnce(&mut DSPDevice) -> Result, { let device = { let devices = self .devices .lock() .map_err(|e| e.to_string())?; devices .get(&id) .cloned() .ok_or_else(|| "DSP not found".to_string())? }; let mut device = device .lock() .map_err(|e| e.to_string())?; f(&mut device) } pub fn remove_device( &self, id: u64, ) -> Result<(), String> { let device = { let mut devices = self.devices .lock() .map_err(|e| e.to_string())?; devices .remove(&id) .ok_or_else(|| format!("DSP {} not found", id))? }; // Drop happens here. // DSPDevice owns DSP408. drop(device); Ok(()) } } #[tauri::command] pub fn create_dsp408( state: State, ip: String, port: u16, device_id: u8, ) -> Result { let ip = IpAddr::from_str(&ip) .map_err(|e| e.to_string())?; let dsp = DSP408::new(ip, port, device_id) .map_err(|e| e.to_string())?; let mut next_id = state .next_id .lock() .map_err(|e| e.to_string())?; let id = *next_id; *next_id += 1; let device = DSPDevice { dsp, }; let mut devices = state .devices .lock() .map_err(|e| e.to_string())?; devices.insert( id, Arc::new(Mutex::new(device)), ); Ok(id) } #[tauri::command] pub async fn remove_dsp408( state: State<'_, AppState>, id: u64, ) -> Result<(), String> { state.with_device_mut(id, |device| { if device.dsp.connected() { device.dsp .disconnect() .map_err(|e| e.to_string())?; } Ok(()) })?; state.remove_device(id)?; Ok(()) } #[tauri::command] pub async fn connect_dsp408( state: State<'_, AppState>, id: u64, ) -> Result<(), String> { state.with_device_mut(id, |device| { device.dsp .connect() .map_err(|e| e.to_string()) }) } #[tauri::command] pub async fn disconnect_dsp408( state: State<'_, AppState>, id: u64, ) -> Result<(), String> { state.with_device_mut(id, |device| { device.dsp .disconnect() .map_err(|e| e.to_string()) }) } #[tauri::command] pub async fn get_dsp_state( state: State<'_, AppState>, id: u64, ) -> Result { state.with_device_mut(id, |device| { let dsp_state = device.dsp .state() .map_err(|e| e.to_string())?; Ok(dsp_state.clone()) }) } #[tauri::command] pub async fn set_channel_gain( state: State<'_, AppState>, id: u64, channel: dsp_thomann::dsp408::types::Channel, db: f32, ) -> Result { state.with_device_mut(id, |device| { let r = device.dsp .set_channel_gain(channel, db) .map_err(|e| e.to_string())?; Ok(r) }) } #[tauri::command] pub async fn set_mute( state: State<'_, AppState>, id: u64, channel: dsp_thomann::dsp408::types::Channel, muted: bool, ) -> Result { state.with_device_mut(id, |device| { let r = device.dsp .set_mute(channel, muted) .map_err(|e| e.to_string())?; Ok(r) }) } #[tauri::command] pub async fn set_channel_inverse_gain( state: State<'_, AppState>, id: u64, channel: dsp_thomann::dsp408::types::Channel, inverted: bool, ) -> Result { state.with_device_mut(id, |device| { let r = device.dsp .set_channel_inverse_gain(channel, inverted) .map_err(|e| e.to_string())?; Ok(r) }) } #[tauri::command] pub async fn recall_preset( state: State<'_, AppState>, id: u64, preset_index: usize, ) -> Result { state.with_device_mut(id, |device| { let success = device .dsp .recall_preset(preset_index) .map_err(|e| e.to_string())?; Ok(success) }) } #[tauri::command] pub async fn get_meter_levels( state: State<'_, AppState>, id: u64, ) -> Result { state.with_device_mut(id, |device| { device .dsp .get_meter_levels() .map_err(|e| e.to_string()) }) } #[tauri::command] pub async fn set_current_preset_name( state: State<'_, AppState>, id: u64, name: String, ) -> Result { state.with_device_mut(id, |device| { device .dsp .set_current_preset_name(&name) .map_err(|e| e.to_string()) }) } #[tauri::command] pub async fn set_gate( state: State<'_, AppState>, id: u64, channel: types::InputChannel, threshold: f32, attack: u16, hold: u16, release: u16, ) -> Result { state.with_device_mut(id, |device| { device .dsp .set_gate(channel, threshold, attack, hold, release) .map_err(|e| e.to_string()) }) } #[tauri::command] pub async fn set_compressor( state: State<'_, AppState>, id: u64, channel: types::OutputChannel, ratio: types::Ratio, attack: u16, release: u16, knee: u16, threshold: f32, ) -> Result { state.with_device_mut(id, |device| { device .dsp .set_compressor( channel, ratio, attack, release, knee, threshold, ) .map_err(|e| e.to_string()) }) } #[tauri::command] pub async fn set_limiter( state: State<'_, AppState>, id: u64, channel: types::OutputChannel, threshold: f32, attack: u16, release: u16, ) -> Result { state.with_device_mut(id, |device| { device .dsp .set_limiter(channel, threshold, attack, release) .map_err(|e| e.to_string()) }) } #[tauri::command] pub async fn set_delay_unit( state: State<'_, AppState>, id: u64, unit: types::DelayUnit, ) -> Result { state.with_device_mut(id, |device| { device .dsp .set_delay_unit(unit) .map_err(|e| e.to_string()) }) } #[tauri::command] pub async fn set_delay( state: State<'_, AppState>, id: u64, channel: types::Channel, delay: f32, unit: DelayUnit ) -> Result { state.with_device_mut(id, |device| { device .dsp .set_delay(channel, delay, unit) .map_err(|e| e.to_string()) }) } #[tauri::command] pub async fn set_matrix_routing( state: State<'_, AppState>, id: u64, output: types::OutputChannel, inputs: Vec, ) -> Result { state.with_device_mut(id, |device| { device .dsp .set_matrix_routing(output, inputs) .map_err(|e| e.to_string()) }) } #[tauri::command] pub async fn set_matrix_gain( state: State<'_, AppState>, id: u64, input_channel: types::InputChannel, output_channel: types::OutputChannel, gain: f32, ) -> Result { state.with_device_mut(id, |device| { device .dsp .set_matrix_gain(input_channel, output_channel, gain) .map_err(|e| e.to_string()) }) } #[tauri::command] pub async fn set_geq_band( state: State<'_, AppState>, id: u64, input_channel: types::InputChannel, frequency_band: types::DiscreteFrequency, gain: f32, ) -> Result { state.with_device_mut(id, |device| { device .dsp .set_geq_band(input_channel, frequency_band, gain) .map_err(|e| e.to_string()) }) } #[tauri::command] pub async fn set_geq_bypass( state: State<'_, AppState>, id: u64, input_channel: types::InputChannel, bypass: bool, ) -> Result { state.with_device_mut(id, |device| { device .dsp .set_geq_bypass(input_channel, bypass) .map_err(|e| e.to_string()) }) }