This commit is contained in:
+1126
-636
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,272 @@
|
||||
use std::collections::HashMap;
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use super::types::{
|
||||
Compressor, Crossover, CrossoverFilter, CrossoverFilters, DSPConfigState, DSPState, DelayUnit,
|
||||
DeviceFlags, DiscreteFrequency, Gate, GraphicEQ, InputChannel, InputChannelState, InputMeters,
|
||||
InputSource, InputType, Limiter, MatrixRoutes, Meter, OutputChannel, OutputChannelState,
|
||||
OutputMeters, PEQ, PEQBand, PEQChain, PEQFilter, PresetBank, Ratio,
|
||||
};
|
||||
|
||||
const FREQUENCY_MIN: f32 = 19.7;
|
||||
const FREQUENCY_MAX: f32 = 20160.0;
|
||||
|
||||
const PRESET_COUNT: usize = 20;
|
||||
|
||||
pub fn default_dsp_state() -> DSPState {
|
||||
DSPState {
|
||||
name: "Default".to_string(),
|
||||
|
||||
flags: DeviceFlags { is_locked: false },
|
||||
|
||||
presets: default_preset_bank(),
|
||||
|
||||
current_config: default_config(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn default_input_meters() -> InputMeters {
|
||||
InputMeters {
|
||||
meters: InputChannel::iter().map(|c| (c, default_meter())).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn default_output_meters() -> OutputMeters {
|
||||
OutputMeters {
|
||||
meters: OutputChannel::iter()
|
||||
.map(|c| (c, default_meter()))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Presets
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
fn default_preset_bank() -> PresetBank {
|
||||
PresetBank {
|
||||
current_index: 0,
|
||||
names: vec!["Default".to_string(); PRESET_COUNT],
|
||||
modified: vec![false; PRESET_COUNT],
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// DSP config
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
fn default_config() -> DSPConfigState {
|
||||
DSPConfigState {
|
||||
input_source: InputSource {
|
||||
r#type: InputType::Analog,
|
||||
frequency: DiscreteFrequency::F20000,
|
||||
},
|
||||
|
||||
delay_unit: DelayUnit::Millisecond,
|
||||
|
||||
input_states: default_input_states(),
|
||||
output_states: default_output_states(),
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Input channels
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
fn default_input_states() -> HashMap<InputChannel, InputChannelState> {
|
||||
[
|
||||
(InputChannel::InA, default_input_channel_state("In A")),
|
||||
(InputChannel::InB, default_input_channel_state("In B")),
|
||||
(InputChannel::InC, default_input_channel_state("In C")),
|
||||
(InputChannel::InD, default_input_channel_state("In D")),
|
||||
]
|
||||
.into_iter()
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn default_input_channel_state(name: &str) -> InputChannelState {
|
||||
InputChannelState {
|
||||
name: name.to_string(),
|
||||
|
||||
gain: 0.0,
|
||||
phase_inverted: false,
|
||||
delay: 0.0,
|
||||
|
||||
gate: default_gate(),
|
||||
geq: default_graphic_eq(),
|
||||
peq_chain: default_peq_chain(),
|
||||
crossover: default_crossover_filters(),
|
||||
|
||||
linked_channels: Vec::new(),
|
||||
|
||||
mute: false,
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Output channels
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
fn default_output_states() -> HashMap<OutputChannel, OutputChannelState> {
|
||||
[
|
||||
(OutputChannel::Out1, default_output_channel_state("Out 1")),
|
||||
(OutputChannel::Out2, default_output_channel_state("Out 2")),
|
||||
(OutputChannel::Out3, default_output_channel_state("Out 3")),
|
||||
(OutputChannel::Out4, default_output_channel_state("Out 4")),
|
||||
(OutputChannel::Out5, default_output_channel_state("Out 5")),
|
||||
(OutputChannel::Out6, default_output_channel_state("Out 6")),
|
||||
(OutputChannel::Out7, default_output_channel_state("Out 7")),
|
||||
(OutputChannel::Out8, default_output_channel_state("Out 8")),
|
||||
]
|
||||
.into_iter()
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn default_output_channel_state(name: &str) -> OutputChannelState {
|
||||
OutputChannelState {
|
||||
name: name.to_string(),
|
||||
|
||||
matrix_routes: default_matrix_routes(),
|
||||
|
||||
crossover: default_crossover_filters(),
|
||||
peq_chain: default_peq_chain(),
|
||||
|
||||
compressor: default_compressor(),
|
||||
limiter: default_limiter(),
|
||||
|
||||
gain: 0.0,
|
||||
phase_inverted: false,
|
||||
delay: 0.0,
|
||||
|
||||
linked_channels: Vec::new(),
|
||||
|
||||
mute: false,
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Gate
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
fn default_gate() -> Gate {
|
||||
Gate {
|
||||
attack: 10,
|
||||
release: 10,
|
||||
hold: 10,
|
||||
threshold: 0.0,
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Graphic EQ
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
fn default_graphic_eq() -> GraphicEQ {
|
||||
let gains = DiscreteFrequency::iter()
|
||||
.map(|frequency| (frequency, 0.0))
|
||||
.collect();
|
||||
|
||||
GraphicEQ {
|
||||
gains,
|
||||
bypass: false,
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// PEQ
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
fn default_peq() -> PEQ {
|
||||
PEQ {
|
||||
gain: 0.0,
|
||||
frequency: 1000.0,
|
||||
q: 1.0,
|
||||
filter_type: PEQFilter::Peak,
|
||||
bypass: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn default_peq_chain() -> PEQChain {
|
||||
let bands = PEQBand::iter().map(|band| (band, default_peq())).collect();
|
||||
|
||||
PEQChain {
|
||||
bands,
|
||||
bypass: false,
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Crossover
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
fn default_crossover(frequency: f32) -> Crossover {
|
||||
Crossover {
|
||||
frequency,
|
||||
slope: CrossoverFilter::Bypass,
|
||||
}
|
||||
}
|
||||
|
||||
fn default_crossover_filters() -> CrossoverFilters {
|
||||
CrossoverFilters {
|
||||
high_pass: default_crossover(FREQUENCY_MIN),
|
||||
low_pass: default_crossover(FREQUENCY_MAX),
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Matrix
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
fn default_matrix_routes() -> MatrixRoutes {
|
||||
let gains = [
|
||||
(InputChannel::InA, 0.0),
|
||||
(InputChannel::InB, 0.0),
|
||||
(InputChannel::InC, 0.0),
|
||||
(InputChannel::InD, 0.0),
|
||||
]
|
||||
.into_iter()
|
||||
.collect();
|
||||
|
||||
MatrixRoutes {
|
||||
connected: vec![InputChannel::InA],
|
||||
gains,
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Compressor
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
fn default_compressor() -> Compressor {
|
||||
Compressor {
|
||||
threshold: -90.0,
|
||||
ratio: Ratio::Ratio1_1,
|
||||
attack: 1,
|
||||
release: 10,
|
||||
knee: 0,
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Limiter
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
fn default_limiter() -> Limiter {
|
||||
Limiter {
|
||||
threshold: -90.0,
|
||||
attack: 1,
|
||||
release: 10,
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Meters
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
fn default_meter() -> Meter {
|
||||
Meter {
|
||||
rms: -60.0,
|
||||
peak: -60.0,
|
||||
clip: false,
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,16 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use crate::{
|
||||
common::errors::ProtocolError,
|
||||
dsp408::{
|
||||
protocol::frame::Frame,
|
||||
types::{
|
||||
Acknowledgement, AuthenticationResult, ConfigChunk, CurrentPreset, DeviceFlags,
|
||||
DeviceInfo, DeviceResponseType, HandshakeAck, Meter, Meters, ModifiedPreset,
|
||||
NotImplemented, PresetName, UnknownResponse,
|
||||
DeviceInfo, DeviceResponseType, HandshakeAck, InputChannel, InputMeters, Meter,
|
||||
ModifiedPreset, NotImplemented, OutputChannel, OutputMeters, PresetName,
|
||||
UnknownResponse,
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -173,8 +178,6 @@ pub fn map_response(frame: &Frame) -> Result<DeviceResponseType, ProtocolError>
|
||||
} else {
|
||||
X0 + (raw - Y0) / K2
|
||||
};
|
||||
// Clamping naturally absorbs noise-floor outliers (e.g. raw ≈ 0.385
|
||||
// resolves to well below -60 dB here, so it correctly floors to -60).
|
||||
db.clamp(MIN_DB, MAX_DB)
|
||||
}
|
||||
|
||||
@@ -182,7 +185,7 @@ pub fn map_response(frame: &Frame) -> Result<DeviceResponseType, ProtocolError>
|
||||
return Err(ProtocolError::new("Not enough bytes for meter levels"));
|
||||
}
|
||||
|
||||
let channels: Vec<Meter> = (0..36)
|
||||
let raw_meters: Vec<Meter> = (0..36)
|
||||
.step_by(3)
|
||||
.enumerate()
|
||||
.map(|(index, i)| {
|
||||
@@ -206,7 +209,30 @@ pub fn map_response(frame: &Frame) -> Result<DeviceResponseType, ProtocolError>
|
||||
})
|
||||
.collect();
|
||||
|
||||
return Ok(DeviceResponseType::Meters(Meters { channels }));
|
||||
let mut input_iter = InputChannel::iter();
|
||||
let mut output_iter = OutputChannel::iter();
|
||||
|
||||
let mut input_meters = HashMap::new();
|
||||
let mut output_meters = HashMap::new();
|
||||
|
||||
for (index, meter) in raw_meters.into_iter().enumerate() {
|
||||
if index < 4 {
|
||||
if let Some(channel) = input_iter.next() {
|
||||
input_meters.insert(channel, meter);
|
||||
}
|
||||
} else if let Some(channel) = output_iter.next() {
|
||||
output_meters.insert(channel, meter);
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(DeviceResponseType::Meters(
|
||||
InputMeters {
|
||||
meters: input_meters,
|
||||
},
|
||||
OutputMeters {
|
||||
meters: output_meters,
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
Ok(DeviceResponseType::UnknownResponse(UnknownResponse {
|
||||
@@ -421,8 +447,6 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn meters_decode() {
|
||||
// 38 bytes required.
|
||||
// First 36 bytes are meter values, remaining 2 bytes ignored.
|
||||
let mut payload = vec![0; 38];
|
||||
|
||||
// half float 1.0 = 0x3c00
|
||||
@@ -434,11 +458,12 @@ mod tests {
|
||||
let result = map_response(&frame(0x40, payload)).unwrap();
|
||||
|
||||
match result {
|
||||
DeviceResponseType::Meters(m) => {
|
||||
assert_eq!(m.channels.len(), 12);
|
||||
DeviceResponseType::Meters(inputs, outputs) => {
|
||||
assert_eq!(inputs.meters.len(), 4);
|
||||
assert_eq!(outputs.meters.len(), 8);
|
||||
|
||||
for channel in m.channels {
|
||||
assert!(channel.rms.is_finite());
|
||||
for meter in inputs.meters.values().chain(outputs.meters.values()) {
|
||||
assert!(meter.rms.is_finite());
|
||||
}
|
||||
}
|
||||
other => panic!("unexpected {:?}", other),
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
mod client;
|
||||
mod default;
|
||||
mod mapper;
|
||||
mod protocol;
|
||||
|
||||
pub mod types;
|
||||
|
||||
pub use client::DSP408;
|
||||
pub(crate) use default::default_dsp_state;
|
||||
|
||||
+21
-7
@@ -227,12 +227,6 @@ pub struct Meter {
|
||||
pub clip: bool,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Meters {
|
||||
pub channels: Vec<Meter>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ConfigChunk {
|
||||
pub sub_index: u8,
|
||||
@@ -254,7 +248,7 @@ pub enum DeviceResponseType {
|
||||
PresetName(PresetName),
|
||||
DeviceFlags(DeviceFlags),
|
||||
AuthenticationResult(AuthenticationResult),
|
||||
Meters(Meters),
|
||||
Meters(InputMeters, OutputMeters),
|
||||
CurrentPreset(CurrentPreset),
|
||||
ModifiedPreset(ModifiedPreset),
|
||||
ConfigChunk(ConfigChunk),
|
||||
@@ -412,3 +406,23 @@ pub struct DSPState {
|
||||
pub(crate) presets: PresetBank,
|
||||
pub(crate) current_config: DSPConfigState,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum DSPMode {
|
||||
Demo,
|
||||
Disconnected,
|
||||
Connected,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
|
||||
#[derive(Debug, Clone, PartialEq, Default)]
|
||||
pub struct InputMeters {
|
||||
pub meters: HashMap<InputChannel, Meter>,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
|
||||
#[derive(Debug, Clone, PartialEq, Default)]
|
||||
pub struct OutputMeters {
|
||||
pub meters: HashMap<OutputChannel, Meter>,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user