diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index 3ff9ad3..3437679 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -1,24 +1,17 @@ -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 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( - &self, - id: u64, - f: F, - ) -> Result + 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())?; + let devices = self.devices.lock().map_err(|e| e.to_string())?; devices .get(&id) @@ -26,22 +19,14 @@ impl AppState { .ok_or_else(|| "DSP not found".to_string())? }; - let mut device = device - .lock() - .map_err(|e| e.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> { - + pub fn remove_device(&self, id: u64) -> Result<(), String> { let device = { - let mut devices = self.devices - .lock() - .map_err(|e| e.to_string())?; + let mut devices = self.devices.lock().map_err(|e| e.to_string())?; devices .remove(&id) @@ -63,50 +48,29 @@ pub fn create_dsp408( port: u16, device_id: u8, ) -> Result { + let ip = IpAddr::from_str(&ip).map_err(|e| e.to_string())?; - 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 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 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 device = DSPDevice { dsp }; - let mut devices = state - .devices - .lock() - .map_err(|e| e.to_string())?; + let mut devices = state.devices.lock().map_err(|e| e.to_string())?; - devices.insert( - id, - Arc::new(Mutex::new(device)), - ); + devices.insert(id, Arc::new(Mutex::new(device))); Ok(id) } #[tauri::command] -pub async fn remove_dsp408( - state: State<'_, AppState>, - id: u64, -) -> Result<(), String> { - +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())?; + device.dsp.disconnect().map_err(|e| e.to_string())?; } Ok(()) @@ -118,28 +82,14 @@ pub async fn remove_dsp408( } #[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()) - }) +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> { - +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()) + device.dsp.disconnect().map_err(|e| e.to_string()) }) } @@ -148,11 +98,8 @@ 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())?; + let dsp_state = device.dsp.state().map_err(|e| e.to_string())?; Ok(dsp_state.clone()) }) @@ -166,7 +113,8 @@ pub async fn set_channel_gain( db: f32, ) -> Result { state.with_device_mut(id, |device| { - let r = device.dsp + let r = device + .dsp .set_channel_gain(channel, db) .map_err(|e| e.to_string())?; @@ -182,7 +130,8 @@ pub async fn set_mute( muted: bool, ) -> Result { state.with_device_mut(id, |device| { - let r = device.dsp + let r = device + .dsp .set_mute(channel, muted) .map_err(|e| e.to_string())?; @@ -198,7 +147,8 @@ pub async fn set_channel_inverse_gain( inverted: bool, ) -> Result { state.with_device_mut(id, |device| { - let r = device.dsp + let r = device + .dsp .set_channel_inverse_gain(channel, inverted) .map_err(|e| e.to_string())?; @@ -228,10 +178,7 @@ pub async fn get_meter_levels( id: u64, ) -> Result { state.with_device_mut(id, |device| { - device - .dsp - .get_meter_levels() - .map_err(|e| e.to_string()) + device.dsp.get_meter_levels().map_err(|e| e.to_string()) }) } @@ -281,14 +228,7 @@ pub async fn set_compressor( state.with_device_mut(id, |device| { device .dsp - .set_compressor( - channel, - ratio, - attack, - release, - knee, - threshold, - ) + .set_compressor(channel, ratio, attack, release, knee, threshold) .map_err(|e| e.to_string()) }) } @@ -317,10 +257,7 @@ pub async fn set_delay_unit( unit: types::DelayUnit, ) -> Result { state.with_device_mut(id, |device| { - device - .dsp - .set_delay_unit(unit) - .map_err(|e| e.to_string()) + device.dsp.set_delay_unit(unit).map_err(|e| e.to_string()) }) } @@ -330,7 +267,7 @@ pub async fn set_delay( id: u64, channel: types::Channel, delay: f32, - unit: DelayUnit + unit: DelayUnit, ) -> Result { state.with_device_mut(id, |device| { device @@ -449,15 +386,7 @@ pub async fn set_peq_band( state.with_device_mut(id, |device| { device .dsp - .set_peq_band( - channel, - band, - gain_db, - freq_hz, - q, - filter_type, - bypass, - ) + .set_peq_band(channel, band, gain_db, freq_hz, q, filter_type, bypass) .map_err(|e| e.to_string()) }) } @@ -484,10 +413,7 @@ pub async fn factory_reset( force: bool, ) -> Result { state.with_device_mut(id, |device| { - device - .dsp - .factory_reset(force) - .map_err(|e| e.to_string()) + device.dsp.factory_reset(force).map_err(|e| e.to_string()) }) } @@ -563,4 +489,4 @@ pub async fn set_channel_name( .set_channel_name(channel, &name) .map_err(|e| e.to_string()) }) -} \ No newline at end of file +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 207eaa9..2488b1b 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,5 +1,5 @@ -mod state; mod commands; +mod state; use state::AppState; @@ -9,42 +9,37 @@ pub fn run() { .plugin(tauri_plugin_opener::init()) .manage(AppState::new()) .invoke_handler(tauri::generate_handler![ - commands::create_dsp408, - commands::remove_dsp408, - commands::get_dsp_state, - - commands::connect_dsp408, // 0x10 - commands::disconnect_dsp408, // 0x11 - commands::set_delay_unit, // 0x15 - - commands::recall_preset, // 0x20 - commands::store_current_configuration, // 0x21 - commands::factory_reset, // 0x23 - commands::set_current_preset_name, // 0x26 - commands::copy_channel, // 0x2A - - commands::set_compressor, // 0x30 - commands::set_low_pass, // 0x31 - commands::set_high_pass, // 0x32 - commands::set_peq_band, // 0x33 - commands::set_channel_gain, // 0x34 - commands::set_mute, // 0x35 - commands::set_channel_inverse_gain, // 0x36 - commands::set_delay, // 0x38 - commands::set_input_source, // 0x39 - commands::set_matrix_routing, // 0x3A - commands::link_channels, // 0x3B - commands::set_bypass_peq, // 0x3C - commands::set_channel_name, // 0x3D - commands::set_gate, // 0x3E - commands::set_limiter, // 0x3F - - commands::get_meter_levels, // 0x40 - commands::set_matrix_gain, // 0x41 - commands::set_geq_band, // 0x48 - commands::set_geq_bypass, // 0x49 - ] - ) + commands::create_dsp408, + commands::remove_dsp408, + commands::get_dsp_state, + commands::connect_dsp408, // 0x10 + commands::disconnect_dsp408, // 0x11 + commands::set_delay_unit, // 0x15 + commands::recall_preset, // 0x20 + commands::store_current_configuration, // 0x21 + commands::factory_reset, // 0x23 + commands::set_current_preset_name, // 0x26 + commands::copy_channel, // 0x2A + commands::set_compressor, // 0x30 + commands::set_low_pass, // 0x31 + commands::set_high_pass, // 0x32 + commands::set_peq_band, // 0x33 + commands::set_channel_gain, // 0x34 + commands::set_mute, // 0x35 + commands::set_channel_inverse_gain, // 0x36 + commands::set_delay, // 0x38 + commands::set_input_source, // 0x39 + commands::set_matrix_routing, // 0x3A + commands::link_channels, // 0x3B + commands::set_bypass_peq, // 0x3C + commands::set_channel_name, // 0x3D + commands::set_gate, // 0x3E + commands::set_limiter, // 0x3F + commands::get_meter_levels, // 0x40 + commands::set_matrix_gain, // 0x41 + commands::set_geq_band, // 0x48 + commands::set_geq_bypass, // 0x49 + ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); } diff --git a/src-tauri/src/state.rs b/src-tauri/src/state.rs index ab1e5d5..6f12b2b 100644 --- a/src-tauri/src/state.rs +++ b/src-tauri/src/state.rs @@ -1,6 +1,6 @@ -use std::sync::{Mutex, Arc}; -use std::collections::HashMap; use dsp_thomann::dsp408::DSP408; +use std::collections::HashMap; +use std::sync::{Arc, Mutex}; pub struct DSPDevice { pub dsp: DSP408, @@ -18,4 +18,4 @@ impl AppState { next_id: Mutex::new(1), } } -} \ No newline at end of file +} diff --git a/src/App.tsx b/src/App.tsx index d1a61c7..aadd01e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,6 +1,6 @@ -import { useState, useEffect, useRef, useMemo } from 'react'; +import { useState, useEffect, useRef } from 'react'; import './App.css'; -import { DSP, AppPage } from './types/types'; +import { DSP, AppPage } from './types'; import TopBar from './components/Topbar/Topbar'; import DSPPage from './pages/DspPage/DspPage'; import AddDSPForm from './pages/AddDspPage/AddDspPage'; diff --git a/src/components/Notifications/Notifications.tsx b/src/components/Notifications/Notifications.tsx index dbd2e7b..a1900fc 100644 --- a/src/components/Notifications/Notifications.tsx +++ b/src/components/Notifications/Notifications.tsx @@ -1,4 +1,4 @@ -import type { Notification } from '../../types/types'; +import type { Notification } from '../../types'; import './Notifications.css'; type Props = { diff --git a/src/components/topbar/Topbar.tsx b/src/components/topbar/Topbar.tsx index 008eb6f..57a9a52 100644 --- a/src/components/topbar/Topbar.tsx +++ b/src/components/topbar/Topbar.tsx @@ -1,5 +1,5 @@ import { useEffect, useRef } from 'react'; -import { DSP, AppPage } from '../../types/types'; +import { DSP, AppPage } from '../../types'; import AnimatedLogo from '../../assets/icons/AnimatedLogo'; import { PlusIcon } from '../../assets/icons/PlusIcon'; import { CrownIcon } from '../../assets/icons/CrownIcon'; diff --git a/src/dsp/dspApi.ts b/src/dsp/dspApi.ts index 67eea53..2cf5e9a 100644 --- a/src/dsp/dspApi.ts +++ b/src/dsp/dspApi.ts @@ -1,7 +1,7 @@ -import { DSP, DSPTypes, AppPage } from '../types/types'; +import { DSP, DSPTypes, AppPage } from '../types'; import { SetDsps, NotifyFn } from './dspShared'; -import { forDSP408, create as createDSP408 } from './dsp408'; -import { DSP408Api } from './dsp408'; +import { forDSP408, create as createDSP408 } from '../features/dsp408/dsp408'; +import { DSP408Api } from '../features/dsp408/dsp408'; // import { forDSP204 } from './dsp204'; export type DSPInstance = { dsp: Extract; api: DSP408Api }; diff --git a/src/dsp/dspShared.ts b/src/dsp/dspShared.ts index ba32c84..2b36004 100644 --- a/src/dsp/dspShared.ts +++ b/src/dsp/dspShared.ts @@ -1,4 +1,4 @@ -import { DSP, DSPTypes } from '../types/types'; +import { DSP, DSPTypes } from '../types'; import { stopPollingFor } from './pollRegistry'; export type SetDsps = React.Dispatch>; diff --git a/src/dsp/pollRegistry.ts b/src/dsp/pollRegistry.ts index 67b701e..e79b448 100644 --- a/src/dsp/pollRegistry.ts +++ b/src/dsp/pollRegistry.ts @@ -1,4 +1,4 @@ -import { DSPTypes } from '../types/types'; +import { DSPTypes } from '../types'; const stoppers = new Map void>(); diff --git a/src/components/dsp408/CompressorSection/CompressorSection.css b/src/features/dsp408/components/CompressorSection/CompressorSection.css similarity index 100% rename from src/components/dsp408/CompressorSection/CompressorSection.css rename to src/features/dsp408/components/CompressorSection/CompressorSection.css diff --git a/src/components/dsp408/CompressorSection/CompressorSection.tsx b/src/features/dsp408/components/CompressorSection/CompressorSection.tsx similarity index 95% rename from src/components/dsp408/CompressorSection/CompressorSection.tsx rename to src/features/dsp408/components/CompressorSection/CompressorSection.tsx index 0ccc5be..ee24b1d 100644 --- a/src/components/dsp408/CompressorSection/CompressorSection.tsx +++ b/src/features/dsp408/components/CompressorSection/CompressorSection.tsx @@ -1,13 +1,13 @@ // CompressorSection.tsx -import VerticalSlider from '../../VerticalSlider/VerticalSlider'; -import { OutputChannel, Ratio } from '../../../types/dsp408'; -import { DSP408 as DSP } from '../../../types/types'; -import Button from '../../Button/Button'; -import ChannelGroup from '../../ChannelGroup/ChannelGroup'; -import { LinearGraph } from '../../LinearGraph/LinearGraph'; -import MeterBar from '../../MeterBar/MeterBar'; +import VerticalSlider from '../../../../components/VerticalSlider/VerticalSlider'; +import { OutputChannel, Ratio } from '../../types'; +import { DSP408 as DSP } from '../../../../types'; +import Button from '../../../../components/Button/Button'; +import ChannelGroup from '../../../../components/ChannelGroup/ChannelGroup'; +import { LinearGraph } from '../../../../components/LinearGraph/LinearGraph'; +import MeterBar from '../../../../components/MeterBar/MeterBar'; import { useMemo, useState, useEffect } from 'react'; -import { TriangleUpIcon, TriangleDownIcon } from '../../../assets/icons/Triangle'; +import { TriangleUpIcon, TriangleDownIcon } from '../../../../assets/icons/Triangle'; import './CompressorSection.css'; // Enum order defines stepper order (1:1 -> Limit). diff --git a/src/components/dsp408/ConnectionSection/ConnectionSection.css b/src/features/dsp408/components/ConnectionSection/ConnectionSection.css similarity index 100% rename from src/components/dsp408/ConnectionSection/ConnectionSection.css rename to src/features/dsp408/components/ConnectionSection/ConnectionSection.css diff --git a/src/components/dsp408/ConnectionSection/ConnectionSection.tsx b/src/features/dsp408/components/ConnectionSection/ConnectionSection.tsx similarity index 91% rename from src/components/dsp408/ConnectionSection/ConnectionSection.tsx rename to src/features/dsp408/components/ConnectionSection/ConnectionSection.tsx index 29b2569..c5a6271 100644 --- a/src/components/dsp408/ConnectionSection/ConnectionSection.tsx +++ b/src/features/dsp408/components/ConnectionSection/ConnectionSection.tsx @@ -1,7 +1,7 @@ -import { DSP } from '../../../types/types'; -import Button from '../../Button/Button'; -import Card from '../../Card/Card'; -import Led from '../../Led/Led'; +import { DSP } from '../../../../types'; +import Button from '../../../../components/Button/Button'; +import Card from '../../../../components/Card/Card'; +import Led from '../../../../components/Led/Led'; import './ConnectionSection.css'; diff --git a/src/pages/DspPage/DspPage.css b/src/features/dsp408/components/DSP408Panel/DSP408Panel.css similarity index 100% rename from src/pages/DspPage/DspPage.css rename to src/features/dsp408/components/DSP408Panel/DSP408Panel.css diff --git a/src/pages/DSP408Panel/DSP408Panel.tsx b/src/features/dsp408/components/DSP408Panel/DSP408Panel.tsx similarity index 80% rename from src/pages/DSP408Panel/DSP408Panel.tsx rename to src/features/dsp408/components/DSP408Panel/DSP408Panel.tsx index e95975d..8fd6bf0 100644 --- a/src/pages/DSP408Panel/DSP408Panel.tsx +++ b/src/features/dsp408/components/DSP408Panel/DSP408Panel.tsx @@ -1,20 +1,20 @@ import { useState } from 'react'; -import { DSP } from '../../types/types'; -import Sidebar from '../../components/Sidebar/Sidebar'; -import { InfoIcon, KnobGainIcon, TextIcon } from '../../assets/icons/AudioIcons'; -import ConnectionPanel from '../../components/dsp408/ConnectionSection/ConnectionSection'; -import GainSection from '../../components/dsp408/GainSection/GainSection'; -import CompressorSection from '../../components/dsp408/CompressorSection/CompressorSection'; -import GateSection from '../../components/dsp408/GateSection/GateSection'; -import LimiterSection from '../../components/dsp408/LimiterSection/LimiterSection'; -import DelaySection from '../../components/dsp408/DelaySection/DelaySection'; -import LoadingOverlay from '../../components/LoadingOverlay/LoadingOverlay'; -import { InputChannel, OutputChannel } from '../../types/dsp408'; -import MatrixSection from '../../components/dsp408/Matrixsection/Matrixsection'; -import GeqSection from '../../components/dsp408/GeqSection/GeqSection'; -import InputSection from '../../components/dsp408/InputSection/InputSection'; -import { DSP408Api } from '../../dsp/dsp408'; -import '../DspPage/DspPage.css'; +import { DSP } from '../../../../types'; +import Sidebar from '../../../../components/Sidebar/Sidebar'; +import { InfoIcon, KnobGainIcon, TextIcon } from '../../../../assets/icons/AudioIcons'; +import ConnectionPanel from '../ConnectionSection/ConnectionSection'; +import GainSection from '../GainSection/GainSection'; +import CompressorSection from '../CompressorSection/CompressorSection'; +import GateSection from '../GateSection/GateSection'; +import LimiterSection from '../LimiterSection/LimiterSection'; +import DelaySection from '../DelaySection/DelaySection'; +import LoadingOverlay from '../../../../components/LoadingOverlay/LoadingOverlay'; +import { InputChannel, OutputChannel } from '../../types'; +import MatrixSection from '../Matrixsection/Matrixsection'; +import GeqSection from '../GeqSection/GeqSection'; +import InputSection from '../InputSection/InputSection'; +import { DSP408Api } from '../../dsp408'; +import './DSP408Panel.css'; type DSP408 = Extract; @@ -132,15 +132,8 @@ function DSP408Panel({ dsp, api }: { dsp: DSP408; api: DSP408Api }) { case 'limiter': return ; - // case 'delay': - // return ( - // - // ); + case 'delay': + return ; case 'ina': return ( diff --git a/src/components/dsp408/DelaySection/DelaySection.css b/src/features/dsp408/components/DelaySection/DelaySection.css similarity index 100% rename from src/components/dsp408/DelaySection/DelaySection.css rename to src/features/dsp408/components/DelaySection/DelaySection.css diff --git a/src/components/dsp408/DelaySection/DelaySection.tsx b/src/features/dsp408/components/DelaySection/DelaySection.tsx similarity index 70% rename from src/components/dsp408/DelaySection/DelaySection.tsx rename to src/features/dsp408/components/DelaySection/DelaySection.tsx index d32585a..7a60282 100644 --- a/src/components/dsp408/DelaySection/DelaySection.tsx +++ b/src/features/dsp408/components/DelaySection/DelaySection.tsx @@ -1,17 +1,12 @@ -import VerticalSlider from '../../VerticalSlider/VerticalSlider'; -import { InputChannel, Channel, OutputChannel, DelayUnit } from '../../../types/dsp408'; -import { DSP408 as DSP } from '../../../types/types'; -import Button from '../../Button/Button'; -import ChannelGroup from '../../ChannelGroup/ChannelGroup'; -import { LinearGraph } from '../../LinearGraph/LinearGraph'; +import VerticalSlider from '../../../../components/VerticalSlider/VerticalSlider'; +import { InputChannel, Channel, OutputChannel, DelayUnit } from '../../types'; +import { DSP408 as DSP } from '../../../../types'; +import Button from '../../../../components/Button/Button'; +import ChannelGroup from '../../../../components/ChannelGroup/ChannelGroup'; +import { LinearGraph } from '../../../../components/LinearGraph/LinearGraph'; import { useMemo, useState } from 'react'; import './DelaySection.css'; - -const DELAY_RANGES: Record = { - [DelayUnit.Millisecond]: [0, 680.0], - [DelayUnit.Meter]: [0, 233.58], - [DelayUnit.Feet]: [0, 766.329], -}; +import { DELAY_RANGES } from '../../types'; const UNIT_LABEL: Record = { [DelayUnit.Millisecond]: 'ms', @@ -155,12 +150,10 @@ function DelaySection({ dsp, setDelay, setDelayUnit, - setDSPState, }: { dsp: DSP; setDelay: SetDelayFn; setDelayUnit: (unit: DelayUnit) => Promise; - setDSPState: (updater: (dsp: DSP) => DSP) => void; }) { const unit = dsp.state?.current_config.delay_unit ?? DelayUnit.Millisecond; @@ -224,93 +217,10 @@ function DelaySection({ return committedDelay(channel); }; - function convertDelayUnit(value: number, from: DelayUnit, to: DelayUnit): number { - const [, fromMax] = DELAY_RANGES[from]; - const [, toMax] = DELAY_RANGES[to]; - - if (fromMax === 0) return 0; - - const ratio = value / fromMax; - - return ratio * toMax; - } - const handleUnitChange = async (newUnit: DelayUnit) => { if (newUnit === unit) return; - const success = await setDelayUnit(newUnit); - - if (!success) return; - - setDSPState((d) => { - if (!d.state) return d; - - const currentConfig = d.state.current_config; - - return { - ...d, - state: { - ...d.state, - current_config: { - ...currentConfig, - delay_unit: newUnit, - - input_states: { - ...currentConfig.input_states, - [InputChannel.InA]: { - ...currentConfig.input_states[InputChannel.InA], - delay: convertDelayUnit( - currentConfig.input_states[InputChannel.InA].delay, - unit, - newUnit - ), - }, - [InputChannel.InB]: { - ...currentConfig.input_states[InputChannel.InB], - delay: convertDelayUnit( - currentConfig.input_states[InputChannel.InB].delay, - unit, - newUnit - ), - }, - [InputChannel.InC]: { - ...currentConfig.input_states[InputChannel.InC], - delay: convertDelayUnit( - currentConfig.input_states[InputChannel.InC].delay, - unit, - newUnit - ), - }, - [InputChannel.InD]: { - ...currentConfig.input_states[InputChannel.InD], - delay: convertDelayUnit( - currentConfig.input_states[InputChannel.InD].delay, - unit, - newUnit - ), - }, - }, - - output_states: { - ...currentConfig.output_states, - ...Object.fromEntries( - Object.values(OutputChannel).map((channel) => [ - channel, - { - ...currentConfig.output_states[channel], - delay: convertDelayUnit( - currentConfig.output_states[channel].delay, - unit, - newUnit - ), - }, - ]) - ), - }, - }, - }, - }; - }); + await setDelayUnit(newUnit); }; const inputRows = inputs.map((channel) => ({ diff --git a/src/components/dsp408/GainSection/GainSection.css b/src/features/dsp408/components/GainSection/GainSection.css similarity index 100% rename from src/components/dsp408/GainSection/GainSection.css rename to src/features/dsp408/components/GainSection/GainSection.css diff --git a/src/components/dsp408/GainSection/GainSection.tsx b/src/features/dsp408/components/GainSection/GainSection.tsx similarity index 92% rename from src/components/dsp408/GainSection/GainSection.tsx rename to src/features/dsp408/components/GainSection/GainSection.tsx index ccd0133..fa1991d 100644 --- a/src/components/dsp408/GainSection/GainSection.tsx +++ b/src/features/dsp408/components/GainSection/GainSection.tsx @@ -1,9 +1,9 @@ -import VerticalSlider from '../../VerticalSlider/VerticalSlider'; -import { InputChannel, Channel, OutputChannel } from '../../../types/dsp408'; -import { DSP408 as DSP } from '../../../types/types'; -import Button from '../../Button/Button'; -import ChannelGroup from '../../ChannelGroup/ChannelGroup'; -import { LinearGraph } from '../../LinearGraph/LinearGraph'; +import VerticalSlider from '../../../../components/VerticalSlider/VerticalSlider'; +import { InputChannel, Channel, OutputChannel } from '../../types'; +import { DSP408 as DSP } from '../../../../types'; +import Button from '../../../../components/Button/Button'; +import ChannelGroup from '../../../../components/ChannelGroup/ChannelGroup'; +import { LinearGraph } from '../../../../components/LinearGraph/LinearGraph'; import './GainSection.css'; function GainPanel({ diff --git a/src/components/dsp408/GateSection/GateSection.css b/src/features/dsp408/components/GateSection/GateSection.css similarity index 100% rename from src/components/dsp408/GateSection/GateSection.css rename to src/features/dsp408/components/GateSection/GateSection.css diff --git a/src/components/dsp408/GateSection/GateSection.tsx b/src/features/dsp408/components/GateSection/GateSection.tsx similarity index 94% rename from src/components/dsp408/GateSection/GateSection.tsx rename to src/features/dsp408/components/GateSection/GateSection.tsx index 8f0cfa6..dbedd65 100644 --- a/src/components/dsp408/GateSection/GateSection.tsx +++ b/src/features/dsp408/components/GateSection/GateSection.tsx @@ -1,10 +1,10 @@ // GateSection.tsx -import VerticalSlider from '../../VerticalSlider/VerticalSlider'; -import { InputChannel } from '../../../types/dsp408'; -import { DSP408 as DSP } from '../../../types/types'; -import ChannelGroup from '../../ChannelGroup/ChannelGroup'; -import { LinearGraph } from '../../LinearGraph/LinearGraph'; -import MeterBar from '../../MeterBar/MeterBar'; +import VerticalSlider from '../../../../components/VerticalSlider/VerticalSlider'; +import { InputChannel } from '../../types'; +import { DSP408 as DSP } from '../../../../types'; +import ChannelGroup from '../../../../components/ChannelGroup/ChannelGroup'; +import { LinearGraph } from '../../../../components/LinearGraph/LinearGraph'; +import MeterBar from '../../../../components/MeterBar/MeterBar'; import { useMemo, useState } from 'react'; import './GateSection.css'; diff --git a/src/components/dsp408/GeqSection/GeqSection.css b/src/features/dsp408/components/GeqSection/GeqSection.css similarity index 100% rename from src/components/dsp408/GeqSection/GeqSection.css rename to src/features/dsp408/components/GeqSection/GeqSection.css diff --git a/src/components/dsp408/GeqSection/GeqSection.tsx b/src/features/dsp408/components/GeqSection/GeqSection.tsx similarity index 95% rename from src/components/dsp408/GeqSection/GeqSection.tsx rename to src/features/dsp408/components/GeqSection/GeqSection.tsx index d34be83..a09ef16 100644 --- a/src/components/dsp408/GeqSection/GeqSection.tsx +++ b/src/features/dsp408/components/GeqSection/GeqSection.tsx @@ -1,9 +1,9 @@ -import VerticalSlider from '../../VerticalSlider/VerticalSlider'; -import { InputChannel, DiscreteFrequency } from '../../../types/dsp408'; -import { DSP408 as DSP } from '../../../types/types'; -import Button from '../../Button/Button'; -import ChannelGroup from '../../ChannelGroup/ChannelGroup'; -import { LinearGraph } from '../../LinearGraph/LinearGraph'; +import VerticalSlider from '../../../../components/VerticalSlider/VerticalSlider'; +import { InputChannel, DiscreteFrequency } from '../../types'; +import { DSP408 as DSP } from '../../../../types'; +import Button from '../../../../components/Button/Button'; +import ChannelGroup from '../../../../components/ChannelGroup/ChannelGroup'; +import { LinearGraph } from '../../../../components/LinearGraph/LinearGraph'; import { useMemo, useState } from 'react'; import './GeqSection.css'; diff --git a/src/components/dsp408/InputSection/InputSection.css b/src/features/dsp408/components/InputSection/InputSection.css similarity index 100% rename from src/components/dsp408/InputSection/InputSection.css rename to src/features/dsp408/components/InputSection/InputSection.css diff --git a/src/components/dsp408/InputSection/InputSection.tsx b/src/features/dsp408/components/InputSection/InputSection.tsx similarity index 96% rename from src/components/dsp408/InputSection/InputSection.tsx rename to src/features/dsp408/components/InputSection/InputSection.tsx index 0b0c1e1..baa37fa 100644 --- a/src/components/dsp408/InputSection/InputSection.tsx +++ b/src/features/dsp408/components/InputSection/InputSection.tsx @@ -1,17 +1,17 @@ // InputSection.tsx -import VerticalSlider from '../../VerticalSlider/VerticalSlider'; +import VerticalSlider from '../../../../components/VerticalSlider/VerticalSlider'; // ASSUMPTION: an InputChannel enum exists alongside OutputChannel, mapping // input pages 1-8 similarly (In1 -> 0, In2 -> 1, ...). Adjust import/values // if the actual enum differs. -import { InputChannel, Channel, PEQBand, PEQFilter, PEQ, Meter } from '../../../types/dsp408'; -import { DSP408 as DSP } from '../../../types/types'; -import { CrossoverFilter } from '../../../types/dsp408'; -import { LinearGraph } from '../../LinearGraph/LinearGraph'; +import { InputChannel, Channel, PEQBand, PEQFilter, PEQ, Meter } from '../../types'; +import { DSP408 as DSP } from '../../../../types'; +import { CrossoverFilter } from '../../types'; +import { LinearGraph } from '../../../../components/LinearGraph/LinearGraph'; import { useRef, useState } from 'react'; import './InputSection.css'; -import ChannelGroup from '../../ChannelGroup/ChannelGroup'; -import Button from '../../Button/Button'; -import MeterBar from '../../MeterBar/MeterBar'; +import ChannelGroup from '../../../../components/ChannelGroup/ChannelGroup'; +import Button from '../../../../components/Button/Button'; +import MeterBar from '../../../../components/MeterBar/MeterBar'; const FREQ_MIN = 20; const FREQ_MAX = 20000; diff --git a/src/components/dsp408/LimiterSection/LimiterSection.css b/src/features/dsp408/components/LimiterSection/LimiterSection.css similarity index 100% rename from src/components/dsp408/LimiterSection/LimiterSection.css rename to src/features/dsp408/components/LimiterSection/LimiterSection.css diff --git a/src/components/dsp408/LimiterSection/LimiterSection.tsx b/src/features/dsp408/components/LimiterSection/LimiterSection.tsx similarity index 94% rename from src/components/dsp408/LimiterSection/LimiterSection.tsx rename to src/features/dsp408/components/LimiterSection/LimiterSection.tsx index 3c003fd..2fb33f4 100644 --- a/src/components/dsp408/LimiterSection/LimiterSection.tsx +++ b/src/features/dsp408/components/LimiterSection/LimiterSection.tsx @@ -1,10 +1,10 @@ // LimiterSection.tsx -import VerticalSlider from '../../VerticalSlider/VerticalSlider'; -import { OutputChannel } from '../../../types/dsp408'; -import { DSP408 as DSP } from '../../../types/types'; -import ChannelGroup from '../../ChannelGroup/ChannelGroup'; -import { LinearGraph } from '../../LinearGraph/LinearGraph'; -import MeterBar from '../../MeterBar/MeterBar'; +import VerticalSlider from '../../../../components/VerticalSlider/VerticalSlider'; +import { OutputChannel } from '../../types'; +import { DSP408 as DSP } from '../../../../types'; +import ChannelGroup from '../../../../components/ChannelGroup/ChannelGroup'; +import { LinearGraph } from '../../../../components/LinearGraph/LinearGraph'; +import MeterBar from '../../../../components/MeterBar/MeterBar'; import { useMemo, useState } from 'react'; import './LimiterSection.css'; diff --git a/src/components/dsp408/Matrixsection/Matrixsection.css b/src/features/dsp408/components/Matrixsection/Matrixsection.css similarity index 100% rename from src/components/dsp408/Matrixsection/Matrixsection.css rename to src/features/dsp408/components/Matrixsection/Matrixsection.css diff --git a/src/components/dsp408/Matrixsection/Matrixsection.tsx b/src/features/dsp408/components/Matrixsection/Matrixsection.tsx similarity index 98% rename from src/components/dsp408/Matrixsection/Matrixsection.tsx rename to src/features/dsp408/components/Matrixsection/Matrixsection.tsx index b447af1..fdb518f 100644 --- a/src/components/dsp408/Matrixsection/Matrixsection.tsx +++ b/src/features/dsp408/components/Matrixsection/Matrixsection.tsx @@ -1,7 +1,7 @@ // MatrixSection.tsx import { Fragment, useRef, useState } from 'react'; -import { InputChannel, OutputChannel } from '../../../types/dsp408'; -import { DSP408 as DSP } from '../../../types/types'; +import { InputChannel, OutputChannel } from '../../types'; +import { DSP408 as DSP } from '../../../../types'; import './MatrixSection.css'; // ASSUMPTION: an InputChannel enum exists alongside OutputChannel in diff --git a/src/dsp/dsp408.ts b/src/features/dsp408/dsp408.ts similarity index 97% rename from src/dsp/dsp408.ts rename to src/features/dsp408/dsp408.ts index ef31dd3..5cc4085 100644 --- a/src/dsp/dsp408.ts +++ b/src/features/dsp408/dsp408.ts @@ -1,5 +1,5 @@ import { invoke } from '@tauri-apps/api/core'; -import { DSP } from '../types/types'; +import { DSP } from '../../types'; import { Channel, InputChannel, @@ -11,10 +11,11 @@ import { PEQFilter, PEQBand, InputSource, -} from '../types/dsp408'; -import { SetDsps, NotifyFn, updateDSP, setPollingPaused } from './dspShared'; -import { registerPollStopper } from './pollRegistry'; -import { defaultDSPState, defaultMeters } from '../types/dsp408'; +} from './types'; +import { SetDsps, NotifyFn, updateDSP, setPollingPaused } from '../../dsp/dspShared'; +import { registerPollStopper } from '../../dsp/pollRegistry'; +import { defaultDSPState, defaultMeters } from './types'; +import { DELAY_RANGES } from './types'; type DSP408 = Extract; @@ -737,16 +738,42 @@ export function forDSP408(dsp: DSP408, setDsps: SetDsps, notify: NotifyFn) { async setDelayUnit(unit: DelayUnit): Promise { const updateDelayUnit = () => { + function convertDelayUnit(value: number, from: DelayUnit, to: DelayUnit): number { + if (from === to) return value; + + const [, fromMax] = DELAY_RANGES[from]; + const [, toMax] = DELAY_RANGES[to]; + + if (fromMax === 0) return 0; + + const ratio = value / fromMax; + + return ratio * toMax; + } + updateDSP(setDsps, dsp.id, (d) => { if (!d.state) return d; + const currentConfig = d.state.current_config; + const oldUnit = currentConfig.delay_unit; + + const convertAll = >(states: T): T => + Object.fromEntries( + Object.entries(states).map(([channel, s]) => [ + channel, + { ...s, delay: convertDelayUnit(s.delay, oldUnit, unit) }, + ]) + ) as T; + return { ...d, state: { ...d.state, current_config: { - ...d.state.current_config, + ...currentConfig, delay_unit: unit, + input_states: convertAll(currentConfig.input_states), + output_states: convertAll(currentConfig.output_states), }, }, }; diff --git a/src/types/dsp408.ts b/src/features/dsp408/types.ts similarity index 97% rename from src/types/dsp408.ts rename to src/features/dsp408/types.ts index b5cf1a5..da252ed 100644 --- a/src/types/dsp408.ts +++ b/src/features/dsp408/types.ts @@ -420,3 +420,9 @@ const createDefaultMeter = (): Meter => ({ export const defaultMeters: Meters = { channels: Array.from({ length: 12 }, createDefaultMeter), }; + +export const DELAY_RANGES: Record = { + [DelayUnit.Millisecond]: [0, 680.0], + [DelayUnit.Meter]: [0, 233.58], + [DelayUnit.Feet]: [0, 766.329], +}; diff --git a/src/hooks/useNotifications.tsx b/src/hooks/useNotifications.tsx index edbd653..abdc53d 100644 --- a/src/hooks/useNotifications.tsx +++ b/src/hooks/useNotifications.tsx @@ -1,5 +1,5 @@ import { useState, useCallback, useRef } from 'react'; -import { NotificationType, Notification } from '../types/types'; +import { NotificationType, Notification } from '../types'; export function useNotifications() { const [notifications, setNotifications] = useState([]); diff --git a/src/pages/AddDspPage/AddDspPage.tsx b/src/pages/AddDspPage/AddDspPage.tsx index bf2fe52..d3fce1b 100644 --- a/src/pages/AddDspPage/AddDspPage.tsx +++ b/src/pages/AddDspPage/AddDspPage.tsx @@ -1,5 +1,5 @@ import { useState } from 'react'; -import { DSP, DSP_DEFAULT_PARAMETERS, DSPTypes } from '../../types/types'; +import { DSP, DSP_DEFAULT_PARAMETERS, DSPTypes } from '../../types'; import Button from '../../components/Button/Button'; import Card from '../../components/Card/Card'; diff --git a/src/pages/DspPage/DspPage.tsx b/src/pages/DspPage/DspPage.tsx index ff9fd63..09d6ed8 100644 --- a/src/pages/DspPage/DspPage.tsx +++ b/src/pages/DspPage/DspPage.tsx @@ -1,5 +1,5 @@ import { DSPInstance } from '../../dsp/dspApi'; -import DSP408Panel from '../DSP408Panel/DSP408Panel'; +import DSP408Panel from '../../features/dsp408/components/DSP408Panel/DSP408Panel'; function DSPPage({ instance }: { instance: DSPInstance }) { if (instance.dsp.type === 'DSP408') { diff --git a/src/types/types.ts b/src/types.ts similarity index 97% rename from src/types/types.ts rename to src/types.ts index 4864421..59b7758 100644 --- a/src/types/types.ts +++ b/src/types.ts @@ -1,4 +1,4 @@ -import { DSPState as DSP408State, Meters as DSP408Meters } from './dsp408'; +import { DSPState as DSP408State, Meters as DSP408Meters } from './features/dsp408/types'; export type DSPStatus = 'connected' | 'connecting' | 'disconnected';