551 lines
13 KiB
Rust
551 lines
13 KiB
Rust
use crate::state::{AppState, DSPDevice};
|
|
use dsp_thomann::dsp408::types::DelayUnit;
|
|
use dsp_thomann::dsp408::{types, DSP408};
|
|
use std::sync::{Arc, Mutex};
|
|
use std::{net::IpAddr, str::FromStr};
|
|
use tauri::State;
|
|
|
|
impl AppState {
|
|
pub fn with_device_mut<F, R>(&self, id: u64, f: F) -> Result<R, String>
|
|
where
|
|
F: FnOnce(&mut DSPDevice) -> Result<R, String>,
|
|
{
|
|
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(())
|
|
}
|
|
}
|
|
|
|
#[derive(serde::Serialize)]
|
|
pub struct DSP408Snapshot {
|
|
pub state: types::DSPState,
|
|
pub input_meters: types::InputMeters,
|
|
pub output_meters: types::OutputMeters,
|
|
pub mode: types::DSPMode,
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub fn create_dsp408(
|
|
state: State<AppState>,
|
|
ip: String,
|
|
port: u16,
|
|
device_id: u8,
|
|
demo: bool,
|
|
) -> Result<u64, String> {
|
|
let ip = IpAddr::from_str(&ip).map_err(|e| e.to_string())?;
|
|
|
|
let dsp = if demo {
|
|
DSP408::new_demo()
|
|
} else {
|
|
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 get_dsp_snapshot(
|
|
state: State<'_, AppState>,
|
|
id: u64,
|
|
) -> Result<DSP408Snapshot, String> {
|
|
state.with_device_mut(id, |device| {
|
|
Ok(DSP408Snapshot {
|
|
state: device.dsp.state().clone(),
|
|
input_meters: device.dsp.input_meters().clone(),
|
|
output_meters: device.dsp.output_meters().clone(),
|
|
mode: device.dsp.mode(),
|
|
})
|
|
})
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub async fn get_dsp_state(
|
|
state: State<'_, AppState>,
|
|
id: u64,
|
|
) -> Result<dsp_thomann::dsp408::types::DSPState, String> {
|
|
state.with_device_mut(id, |device| {
|
|
let dsp_state = device.dsp.state();
|
|
|
|
Ok(dsp_state.clone())
|
|
})
|
|
}
|
|
|
|
// Commands
|
|
#[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()))
|
|
}
|
|
|
|
// Command `0x11`
|
|
#[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())
|
|
})
|
|
}
|
|
|
|
// Command `0x15`
|
|
#[tauri::command]
|
|
pub async fn set_delay_unit(
|
|
state: State<'_, AppState>,
|
|
id: u64,
|
|
unit: types::DelayUnit,
|
|
) -> Result<bool, String> {
|
|
state.with_device_mut(id, |device| {
|
|
device.dsp.set_delay_unit(unit).map_err(|e| e.to_string())
|
|
})
|
|
}
|
|
|
|
// Command `0x20`
|
|
#[tauri::command]
|
|
pub async fn recall_preset(
|
|
state: State<'_, AppState>,
|
|
id: u64,
|
|
preset_index: usize,
|
|
) -> Result<bool, String> {
|
|
state.with_device_mut(id, |device| {
|
|
let success = device
|
|
.dsp
|
|
.recall_preset(preset_index)
|
|
.map_err(|e| e.to_string())?;
|
|
|
|
Ok(success)
|
|
})
|
|
}
|
|
|
|
// Command `0x21`
|
|
#[tauri::command]
|
|
pub async fn store_current_configuration(
|
|
state: State<'_, AppState>,
|
|
id: u64,
|
|
preset_index: usize,
|
|
force: bool,
|
|
) -> Result<bool, String> {
|
|
state.with_device_mut(id, |device| {
|
|
device
|
|
.dsp
|
|
.store_current_configuration(preset_index, force)
|
|
.map_err(|e| e.to_string())
|
|
})
|
|
}
|
|
|
|
// Command `0x23`
|
|
#[tauri::command]
|
|
pub async fn factory_reset(
|
|
state: State<'_, AppState>,
|
|
id: u64,
|
|
force: bool,
|
|
) -> Result<bool, String> {
|
|
state.with_device_mut(id, |device| {
|
|
device.dsp.factory_reset(force).map_err(|e| e.to_string())
|
|
})
|
|
}
|
|
|
|
// Command `0x26`
|
|
#[tauri::command]
|
|
pub async fn set_current_preset_name(
|
|
state: State<'_, AppState>,
|
|
id: u64,
|
|
name: String,
|
|
) -> Result<bool, String> {
|
|
state.with_device_mut(id, |device| {
|
|
device
|
|
.dsp
|
|
.set_current_preset_name(&name)
|
|
.map_err(|e| e.to_string())
|
|
})
|
|
}
|
|
|
|
// Command `0x2A`
|
|
#[tauri::command]
|
|
pub async fn copy_channel(
|
|
state: State<'_, AppState>,
|
|
id: u64,
|
|
channel_1: types::Channel,
|
|
channel_2: types::Channel,
|
|
) -> Result<bool, String> {
|
|
state.with_device_mut(id, |device| {
|
|
device
|
|
.dsp
|
|
.copy_channel(channel_1, channel_2)
|
|
.map_err(|e| e.to_string())
|
|
})
|
|
}
|
|
|
|
// Command `0x2D`
|
|
// Command `0x2F`
|
|
|
|
// Command `0x30`
|
|
#[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<bool, String> {
|
|
state.with_device_mut(id, |device| {
|
|
device
|
|
.dsp
|
|
.set_compressor(channel, ratio, attack, release, knee, threshold)
|
|
.map_err(|e| e.to_string())
|
|
})
|
|
}
|
|
|
|
// Command `0x31`
|
|
#[tauri::command]
|
|
pub async fn set_low_pass(
|
|
state: State<'_, AppState>,
|
|
id: u64,
|
|
channel: types::Channel,
|
|
freq: f32,
|
|
filter_type: types::CrossoverFilter,
|
|
) -> Result<bool, String> {
|
|
state.with_device_mut(id, |device| {
|
|
device
|
|
.dsp
|
|
.set_low_pass(channel, freq, filter_type)
|
|
.map_err(|e| e.to_string())
|
|
})
|
|
}
|
|
|
|
// Command `0x32`
|
|
#[tauri::command]
|
|
pub async fn set_high_pass(
|
|
state: State<'_, AppState>,
|
|
id: u64,
|
|
channel: types::Channel,
|
|
freq: f32,
|
|
filter_type: types::CrossoverFilter,
|
|
) -> Result<bool, String> {
|
|
state.with_device_mut(id, |device| {
|
|
device
|
|
.dsp
|
|
.set_high_pass(channel, freq, filter_type)
|
|
.map_err(|e| e.to_string())
|
|
})
|
|
}
|
|
|
|
// Command `0x33`
|
|
#[tauri::command]
|
|
pub async fn set_peq_band(
|
|
state: State<'_, AppState>,
|
|
id: u64,
|
|
channel: types::Channel,
|
|
band: types::PEQBand,
|
|
gain_db: f32,
|
|
freq_hz: f32,
|
|
q: f32,
|
|
filter_type: types::PEQFilter,
|
|
bypass: bool,
|
|
) -> Result<bool, String> {
|
|
state.with_device_mut(id, |device| {
|
|
device
|
|
.dsp
|
|
.set_peq_band(channel, band, gain_db, freq_hz, q, filter_type, bypass)
|
|
.map_err(|e| e.to_string())
|
|
})
|
|
}
|
|
|
|
// Command `0x34`
|
|
#[tauri::command]
|
|
pub async fn set_channel_gain(
|
|
state: State<'_, AppState>,
|
|
id: u64,
|
|
channel: dsp_thomann::dsp408::types::Channel,
|
|
db: f32,
|
|
) -> Result<bool, String> {
|
|
state.with_device_mut(id, |device| {
|
|
let r = device
|
|
.dsp
|
|
.set_channel_gain(channel, db)
|
|
.map_err(|e| e.to_string())?;
|
|
|
|
Ok(r)
|
|
})
|
|
}
|
|
|
|
// Command `0x35`
|
|
#[tauri::command]
|
|
pub async fn set_mute(
|
|
state: State<'_, AppState>,
|
|
id: u64,
|
|
channel: dsp_thomann::dsp408::types::Channel,
|
|
muted: bool,
|
|
) -> Result<bool, String> {
|
|
state.with_device_mut(id, |device| {
|
|
let r = device
|
|
.dsp
|
|
.set_mute(channel, muted)
|
|
.map_err(|e| e.to_string())?;
|
|
|
|
Ok(r)
|
|
})
|
|
}
|
|
|
|
// Command `0x36`
|
|
#[tauri::command]
|
|
pub async fn set_channel_inverse_gain(
|
|
state: State<'_, AppState>,
|
|
id: u64,
|
|
channel: dsp_thomann::dsp408::types::Channel,
|
|
inverted: bool,
|
|
) -> Result<bool, String> {
|
|
state.with_device_mut(id, |device| {
|
|
let r = device
|
|
.dsp
|
|
.set_channel_inverse_gain(channel, inverted)
|
|
.map_err(|e| e.to_string())?;
|
|
|
|
Ok(r)
|
|
})
|
|
}
|
|
|
|
// Command `0x38`
|
|
#[tauri::command]
|
|
pub async fn set_delay(
|
|
state: State<'_, AppState>,
|
|
id: u64,
|
|
channel: types::Channel,
|
|
delay: f32,
|
|
unit: DelayUnit,
|
|
) -> Result<bool, String> {
|
|
state.with_device_mut(id, |device| {
|
|
device
|
|
.dsp
|
|
.set_delay(channel, delay, unit)
|
|
.map_err(|e| e.to_string())
|
|
})
|
|
}
|
|
|
|
// Command `0x39`
|
|
#[tauri::command]
|
|
pub async fn set_input_source(
|
|
state: State<'_, AppState>,
|
|
id: u64,
|
|
input_source: types::InputSource,
|
|
) -> Result<bool, String> {
|
|
state.with_device_mut(id, |device| {
|
|
device
|
|
.dsp
|
|
.set_input_source(input_source)
|
|
.map_err(|e| e.to_string())
|
|
})
|
|
}
|
|
|
|
// Command `0x3A`
|
|
#[tauri::command]
|
|
pub async fn set_matrix_routing(
|
|
state: State<'_, AppState>,
|
|
id: u64,
|
|
output: types::OutputChannel,
|
|
inputs: Vec<types::InputChannel>,
|
|
) -> Result<bool, String> {
|
|
state.with_device_mut(id, |device| {
|
|
device
|
|
.dsp
|
|
.set_matrix_routing(output, inputs)
|
|
.map_err(|e| e.to_string())
|
|
})
|
|
}
|
|
|
|
// Command `0x3B`
|
|
#[tauri::command]
|
|
pub async fn link_channels(
|
|
state: State<'_, AppState>,
|
|
id: u64,
|
|
source: types::Channel,
|
|
destinations: Vec<types::Channel>,
|
|
) -> Result<bool, String> {
|
|
state.with_device_mut(id, |device| {
|
|
device
|
|
.dsp
|
|
.link_channels(source, destinations)
|
|
.map_err(|e| e.to_string())
|
|
})
|
|
}
|
|
|
|
// Command `0x3C`
|
|
#[tauri::command]
|
|
pub async fn set_bypass_peq(
|
|
state: State<'_, AppState>,
|
|
id: u64,
|
|
channel: types::Channel,
|
|
bypass: bool,
|
|
) -> Result<bool, String> {
|
|
state.with_device_mut(id, |device| {
|
|
device
|
|
.dsp
|
|
.set_bypass_peq(channel, bypass)
|
|
.map_err(|e| e.to_string())
|
|
})
|
|
}
|
|
|
|
// Command `0x3D`
|
|
#[tauri::command]
|
|
pub async fn set_channel_name(
|
|
state: State<'_, AppState>,
|
|
id: u64,
|
|
channel: types::Channel,
|
|
name: String,
|
|
) -> Result<bool, String> {
|
|
state.with_device_mut(id, |device| {
|
|
device
|
|
.dsp
|
|
.set_channel_name(channel, &name)
|
|
.map_err(|e| e.to_string())
|
|
})
|
|
}
|
|
|
|
// Command `0x3E`
|
|
#[tauri::command]
|
|
pub async fn set_gate(
|
|
state: State<'_, AppState>,
|
|
id: u64,
|
|
channel: types::InputChannel,
|
|
threshold: f32,
|
|
attack: u16,
|
|
hold: u16,
|
|
release: u16,
|
|
) -> Result<bool, String> {
|
|
state.with_device_mut(id, |device| {
|
|
device
|
|
.dsp
|
|
.set_gate(channel, threshold, attack, hold, release)
|
|
.map_err(|e| e.to_string())
|
|
})
|
|
}
|
|
|
|
// Command `0x3F`
|
|
#[tauri::command]
|
|
pub async fn set_limiter(
|
|
state: State<'_, AppState>,
|
|
id: u64,
|
|
channel: types::OutputChannel,
|
|
threshold: f32,
|
|
attack: u16,
|
|
release: u16,
|
|
) -> Result<bool, String> {
|
|
state.with_device_mut(id, |device| {
|
|
device
|
|
.dsp
|
|
.set_limiter(channel, threshold, attack, release)
|
|
.map_err(|e| e.to_string())
|
|
})
|
|
}
|
|
|
|
// Command `0x40`
|
|
#[tauri::command]
|
|
pub async fn get_meter_levels(
|
|
state: State<'_, AppState>,
|
|
id: u64,
|
|
) -> Result<(types::InputMeters, types::OutputMeters), String> {
|
|
state.with_device_mut(id, |device| {
|
|
device.dsp.get_meter_levels().map_err(|e| e.to_string())
|
|
})
|
|
}
|
|
|
|
// Command `0x41`
|
|
#[tauri::command]
|
|
pub async fn set_matrix_gain(
|
|
state: State<'_, AppState>,
|
|
id: u64,
|
|
input_channel: types::InputChannel,
|
|
output_channel: types::OutputChannel,
|
|
gain: f32,
|
|
) -> Result<bool, String> {
|
|
state.with_device_mut(id, |device| {
|
|
device
|
|
.dsp
|
|
.set_matrix_gain(input_channel, output_channel, gain)
|
|
.map_err(|e| e.to_string())
|
|
})
|
|
}
|
|
|
|
// Command `0x48`
|
|
#[tauri::command]
|
|
pub async fn set_geq_band(
|
|
state: State<'_, AppState>,
|
|
id: u64,
|
|
input_channel: types::InputChannel,
|
|
frequency_band: types::DiscreteFrequency,
|
|
gain: f32,
|
|
) -> Result<bool, String> {
|
|
state.with_device_mut(id, |device| {
|
|
device
|
|
.dsp
|
|
.set_geq_band(input_channel, frequency_band, gain)
|
|
.map_err(|e| e.to_string())
|
|
})
|
|
}
|
|
|
|
// Command `0x49`
|
|
#[tauri::command]
|
|
pub async fn set_geq_bypass(
|
|
state: State<'_, AppState>,
|
|
id: u64,
|
|
input_channel: types::InputChannel,
|
|
bypass: bool,
|
|
) -> Result<bool, String> {
|
|
state.with_device_mut(id, |device| {
|
|
device
|
|
.dsp
|
|
.set_geq_bypass(input_channel, bypass)
|
|
.map_err(|e| e.to_string())
|
|
})
|
|
}
|