use super::{tcat::tcd22xx_spec::*, *};
#[derive(Default, Debug)]
pub struct SPro24DspProtocol;
impl TcatOperation for SPro24DspProtocol {}
impl TcatGlobalSectionSpecification for SPro24DspProtocol {}
impl TcatExtensionOperation for SPro24DspProtocol {}
impl Tcd22xxSpecification for SPro24DspProtocol {
const INPUTS: &'static [Input] = &[
Input {
id: SrcBlkId::Ins0,
offset: 2,
count: 2,
label: Some("Mic"),
},
Input {
id: SrcBlkId::Ins0,
offset: 0,
count: 2,
label: Some("Line"),
},
Input {
id: SrcBlkId::Ins0,
offset: 8,
count: 2,
label: Some("Ch-strip"),
},
Input {
id: SrcBlkId::Ins0,
offset: 14,
count: 2,
label: Some("Reverb"),
},
Input {
id: SrcBlkId::Aes,
offset: 6,
count: 2,
label: Some("S/PDIF-coax"),
},
Input {
id: SrcBlkId::Adat,
offset: 0,
count: 8,
label: None,
},
Input {
id: SrcBlkId::Aes,
offset: 4,
count: 2,
label: Some("S/PDIF-opt"),
},
];
const OUTPUTS: &'static [Output] = &[
Output {
id: DstBlkId::Ins0,
offset: 0,
count: 6,
label: None,
},
Output {
id: DstBlkId::Aes,
offset: 6,
count: 2,
label: Some("S/PDIF-coax"),
},
Output {
id: DstBlkId::Ins0,
offset: 8,
count: 2,
label: Some("Ch-strip"),
},
Output {
id: DstBlkId::Ins0,
offset: 14,
count: 2,
label: Some("Reverb"),
},
];
const FIXED: &'static [SrcBlk] = &[
SrcBlk {
id: SrcBlkId::Ins0,
ch: 2,
},
SrcBlk {
id: SrcBlkId::Ins0,
ch: 3,
},
SrcBlk {
id: SrcBlkId::Ins0,
ch: 0,
},
SrcBlk {
id: SrcBlkId::Ins0,
ch: 1,
},
];
}
impl SaffireproSwNoticeOperation for SPro24DspProtocol {
const SW_NOTICE_OFFSET: usize = 0x05ec;
}
impl SaffireproOutGroupSpecification for SPro24DspProtocol {
const OUT_GROUP_STATE_OFFSET: usize = 0x000c;
const ENTRY_COUNT: usize = 6;
const HAS_VOL_HWCTL: bool = false;
const SRC_NOTICE: u32 = 0x00000001;
const DIM_MUTE_NOTICE: u32 = 0x00000002;
}
impl SaffireproInputSpecification for SPro24DspProtocol {
const INPUT_PARAMS_OFFSET: usize = 0x0058;
}
#[allow(dead_code)]
const DSP_ENABLE_OFFSET: usize = 0x0070; const CH_STRIP_FLAG_OFFSET: usize = 0x0078;
const CH_STRIP_FLAG_EQ_ENABLE: u16 = 0x0001;
const CH_STRIP_FLAG_COMP_ENABLE: u16 = 0x0002;
const CH_STRIP_FLAG_EQ_AFTER_COMP: u16 = 0x0004;
const CH_STRIP_FLAG_SW_NOTICE: u32 = 0x00000005;
const COEF_OFFSET: usize = 0x0190;
const COEF_BLOCK_SIZE: usize = 0x88;
const EQ_COEF_COUNT: usize = 5;
const COMP_OUTPUT_OFFSET: usize = 0x04;
const COMP_THRESHOLD_OFFSET: usize = 0x08;
const COMP_RATIO_OFFSET: usize = 0x0c;
const COMP_ATTACK_OFFSET: usize = 0x10;
const COMP_RELEASE_OFFSET: usize = 0x14;
const COMP_CH0_SW_NOTICE: u32 = 0x00000006;
const COMP_CH1_SW_NOTICE: u32 = 0x00000007;
const EQ_OUTPUT_OFFSET: usize = 0x18;
const EQ_LOW_FREQ_OFFSET: usize = 0x20;
const EQ_OUTPUT_CH0_SW_NOTICE: u32 = 0x09;
const EQ_OUTPUT_CH1_SW_NOTICE: u32 = 0x0a;
const EQ_LOW_FREQ_CH0_SW_NOTICE: u32 = 0x0c;
const EQ_LOW_FREQ_CH1_SW_NOTICE: u32 = 0x0c;
const EQ_LOW_MIDDLE_FREQ_CH0_SW_NOTICE: u32 = 0x0f;
const EQ_LOW_MIDDLE_FREQ_CH1_SW_NOTICE: u32 = 0x10;
const EQ_HIGH_MIDDLE_FREQ_CH0_SW_NOTICE: u32 = 0x12;
const EQ_HIGH_MIDDLE_FREQ_CH1_SW_NOTICE: u32 = 0x13;
const EQ_HIGH_FREQ_CH0_SW_NOTICE: u32 = 0x15;
const EQ_HIGH_FREQ_CH1_SW_NOTICE: u32 = 0x16;
const REVERB_SIZE_OFFSET: usize = 0x70;
const REVERB_AIR_OFFSET: usize = 0x74;
const REVERB_ENABLE_OFFSET: usize = 0x78;
const REVERB_DISABLE_OFFSET: usize = 0x7c;
const REVERB_PRE_FILTER_VALUE_OFFSET: usize = 0x80;
const REVERB_PRE_FILTER_SIGN_OFFSET: usize = 0x84;
const REVERB_SW_NOTICE: u32 = 0x0000001a;
fn serialize_f32(val: &f32, raw: &mut [u8]) -> Result<(), String> {
assert!(raw.len() >= 4);
raw[..4].copy_from_slice(&val.to_be_bytes());
Ok(())
}
fn deserialize_f32(val: &mut f32, raw: &[u8]) -> Result<(), String> {
assert!(raw.len() >= 4);
let mut quadlet = [0; 4];
quadlet.copy_from_slice(&raw[..4]);
*val = f32::from_be_bytes(quadlet);
Ok(())
}
#[derive(Default, Debug, Copy, Clone, PartialEq)]
pub struct Spro24DspCompressorState {
pub output: [f32; 2],
pub threshold: [f32; 2],
pub ratio: [f32; 2],
pub attack: [f32; 2],
pub release: [f32; 2],
}
#[derive(Default, Debug, Copy, Clone, PartialEq)]
pub struct Spro24DspEqualizerFrequencyBandState([f32; EQ_COEF_COUNT]);
#[derive(Default, Debug, Copy, Clone, PartialEq)]
pub struct Spro24DspEqualizerState {
pub output: [f32; 2],
pub low_coef: [Spro24DspEqualizerFrequencyBandState; 2],
pub low_middle_coef: [Spro24DspEqualizerFrequencyBandState; 2],
pub high_middle_coef: [Spro24DspEqualizerFrequencyBandState; 2],
pub high_coef: [Spro24DspEqualizerFrequencyBandState; 2],
}
#[derive(Default, Debug, Copy, Clone, PartialEq)]
pub struct Spro24DspReverbState {
pub size: f32,
pub air: f32,
pub enabled: bool,
pub pre_filter: f32,
}
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
pub struct Spro24DspEffectGeneralParams {
pub eq_after_comp: [bool; 2],
pub comp_enable: [bool; 2],
pub eq_enable: [bool; 2],
}
const COEF_BLOCK_COMP: usize = 2;
const COEF_BLOCK_EQ: usize = 2;
const COEF_BLOCK_REVERB: usize = 3;
fn serialize_compressor_state(
state: &Spro24DspCompressorState,
raw: &mut [u8],
) -> Result<(), String> {
assert!(raw.len() >= COEF_BLOCK_SIZE * 2);
(0..2).try_for_each(|ch| {
let base_offset = COEF_BLOCK_SIZE * ch;
let pos = base_offset + COMP_OUTPUT_OFFSET;
serialize_f32(&state.output[ch], &mut raw[pos..(pos + 4)])?;
let pos = base_offset + COMP_THRESHOLD_OFFSET;
serialize_f32(&state.threshold[ch], &mut raw[pos..(pos + 4)])?;
let pos = base_offset + COMP_RATIO_OFFSET;
serialize_f32(&state.ratio[ch], &mut raw[pos..(pos + 4)])?;
let pos = base_offset + COMP_ATTACK_OFFSET;
serialize_f32(&state.attack[ch], &mut raw[pos..(pos + 4)])?;
let pos = base_offset + COMP_RELEASE_OFFSET;
serialize_f32(&state.release[ch], &mut raw[pos..(pos + 4)])
})
}
fn deserialize_compressor_state(
state: &mut Spro24DspCompressorState,
raw: &[u8],
) -> Result<(), String> {
assert!(raw.len() >= COEF_BLOCK_SIZE * 2);
(0..2).try_for_each(|ch| {
let base_offset = COEF_BLOCK_SIZE * ch;
let pos = base_offset + COMP_OUTPUT_OFFSET;
deserialize_f32(&mut state.output[ch], &raw[pos..(pos + 4)])?;
let pos = base_offset + COMP_THRESHOLD_OFFSET;
deserialize_f32(&mut state.threshold[ch], &raw[pos..(pos + 4)])?;
let pos = base_offset + COMP_RATIO_OFFSET;
deserialize_f32(&mut state.ratio[ch], &raw[pos..(pos + 4)])?;
let pos = base_offset + COMP_ATTACK_OFFSET;
deserialize_f32(&mut state.attack[ch], &raw[pos..(pos + 4)])?;
let pos = base_offset + COMP_RELEASE_OFFSET;
deserialize_f32(&mut state.release[ch], &raw[pos..(pos + 4)])
})
}
fn serialize_equalizer_state(
state: &Spro24DspEqualizerState,
raw: &mut [u8],
) -> Result<(), String> {
assert!(raw.len() >= COEF_BLOCK_SIZE * 2);
(0..2).try_for_each(|ch| {
let base_offset = COEF_BLOCK_SIZE * ch;
let pos = base_offset + EQ_OUTPUT_OFFSET;
serialize_f32(&state.output[ch], &mut raw[pos..(pos + 4)])?;
state.low_coef[ch]
.0
.iter()
.chain(state.low_middle_coef[ch].0.iter())
.chain(state.high_middle_coef[ch].0.iter())
.chain(state.high_coef[ch].0.iter())
.enumerate()
.try_for_each(|(i, coef)| {
let pos = base_offset + EQ_LOW_FREQ_OFFSET + i * 4;
serialize_f32(coef, &mut raw[pos..(pos + 4)])
})
})
}
fn deserialize_equalizer_state(
state: &mut Spro24DspEqualizerState,
raw: &[u8],
) -> Result<(), String> {
assert!(raw.len() >= COEF_BLOCK_SIZE * 2);
(0..2).try_for_each(|ch| {
let base_offset = COEF_BLOCK_SIZE * ch;
let pos = base_offset + EQ_OUTPUT_OFFSET;
deserialize_f32(&mut state.output[ch], &raw[pos..(pos + 4)])?;
state.low_coef[ch]
.0
.iter_mut()
.chain(state.low_middle_coef[ch].0.iter_mut())
.chain(state.high_middle_coef[ch].0.iter_mut())
.chain(state.high_coef[ch].0.iter_mut())
.enumerate()
.try_for_each(|(i, coef)| {
let pos = base_offset + EQ_LOW_FREQ_OFFSET + i * 4;
deserialize_f32(coef, &raw[pos..(pos + 4)])
})
})
}
fn serialize_reverb_state(state: &Spro24DspReverbState, raw: &mut [u8]) -> Result<(), String> {
assert!(raw.len() >= COEF_BLOCK_SIZE);
let pos = REVERB_SIZE_OFFSET;
serialize_f32(&state.size, &mut raw[pos..(pos + 4)])?;
let pos = REVERB_AIR_OFFSET;
serialize_f32(&state.air, &mut raw[pos..(pos + 4)])?;
let enabled_pos = REVERB_ENABLE_OFFSET;
let disabled_pos = REVERB_DISABLE_OFFSET;
let vals = if state.enabled {
[1.0, 0.0]
} else {
[0.0, 1.0]
};
serialize_f32(&vals[0], &mut raw[enabled_pos..(enabled_pos + 4)])?;
serialize_f32(&vals[1], &mut raw[disabled_pos..(disabled_pos + 4)])?;
let pos = REVERB_ENABLE_OFFSET;
let val = if state.enabled { 1.0 } else { 0.0 };
serialize_f32(&val, &mut raw[pos..(pos + 4)])?;
let pos = REVERB_PRE_FILTER_VALUE_OFFSET;
let val = state.pre_filter.abs();
serialize_f32(&val, &mut raw[pos..(pos + 4)])?;
let pos = REVERB_PRE_FILTER_SIGN_OFFSET;
let sign = if state.pre_filter > 0.0 { 1.0 } else { 0.0 };
serialize_f32(&sign, &mut raw[pos..(pos + 4)])?;
Ok(())
}
fn deserialize_reverb_state(state: &mut Spro24DspReverbState, raw: &[u8]) -> Result<(), String> {
assert!(raw.len() >= COEF_BLOCK_SIZE);
let pos = REVERB_SIZE_OFFSET;
deserialize_f32(&mut state.size, &raw[pos..(pos + 4)])?;
let pos = REVERB_AIR_OFFSET;
deserialize_f32(&mut state.air, &raw[pos..(pos + 4)])?;
let mut val = 0.0;
let pos = REVERB_ENABLE_OFFSET;
deserialize_f32(&mut val, &raw[pos..(pos + 4)])?;
state.enabled = val > 0.0;
let mut val = 0.0;
let pos = REVERB_PRE_FILTER_VALUE_OFFSET;
deserialize_f32(&mut val, &raw[pos..(pos + 4)])?;
let mut sign = 0.0;
let pos = REVERB_PRE_FILTER_SIGN_OFFSET;
deserialize_f32(&mut sign, &raw[pos..(pos + 4)])?;
if sign == 0.0 {
val *= -1.0;
}
state.pre_filter = val;
Ok(())
}
fn serialize_effect_general_params(
params: &Spro24DspEffectGeneralParams,
raw: &mut [u8],
) -> Result<(), String> {
assert!(raw.len() >= 4);
let mut val = 0u32;
(0..2).for_each(|i| {
let mut flags = 0u16;
if params.eq_after_comp[i] {
flags |= CH_STRIP_FLAG_EQ_AFTER_COMP;
}
if params.comp_enable[i] {
flags |= CH_STRIP_FLAG_COMP_ENABLE;
}
if params.eq_enable[i] {
flags |= CH_STRIP_FLAG_EQ_ENABLE;
}
val |= (flags as u32) << (16 * i);
});
serialize_u32(&val, raw);
Ok(())
}
fn deserialize_effect_general_params(
params: &mut Spro24DspEffectGeneralParams,
raw: &[u8],
) -> Result<(), String> {
assert!(raw.len() >= 4);
let mut val = 0u32;
deserialize_u32(&mut val, raw);
(0..2).for_each(|i| {
let flags = (val >> (i * 16)) as u16;
params.eq_after_comp[i] = flags & CH_STRIP_FLAG_EQ_AFTER_COMP > 0;
params.comp_enable[i] = flags & CH_STRIP_FLAG_COMP_ENABLE > 0;
params.eq_enable[i] = flags & CH_STRIP_FLAG_EQ_ENABLE > 0;
});
Ok(())
}
impl TcatExtensionSectionParamsOperation<Spro24DspEffectGeneralParams> for SPro24DspProtocol {
fn cache_extension_whole_params(
req: &FwReq,
node: &FwNode,
sections: &ExtensionSections,
_: &ExtensionCaps,
params: &mut Spro24DspEffectGeneralParams,
timeout_ms: u32,
) -> Result<(), Error> {
let mut raw = vec![0u8; 4];
Self::read_extension(
req,
node,
§ions.application,
CH_STRIP_FLAG_OFFSET,
&mut raw,
timeout_ms,
)?;
deserialize_effect_general_params(params, &raw)
.map_err(|cause| Error::new(ProtocolExtensionError::Appl, &cause))
}
}
impl TcatExtensionSectionPartialMutableParamsOperation<Spro24DspEffectGeneralParams>
for SPro24DspProtocol
{
fn update_extension_partial_params(
req: &FwReq,
node: &FwNode,
sections: &ExtensionSections,
_: &ExtensionCaps,
params: &Spro24DspEffectGeneralParams,
prev: &mut Spro24DspEffectGeneralParams,
timeout_ms: u32,
) -> Result<(), Error> {
let mut new = vec![0u8; 4];
serialize_effect_general_params(params, &mut new)
.map_err(|cause| Error::new(ProtocolExtensionError::Appl, &cause))?;
let mut old = vec![0u8; 4];
serialize_effect_general_params(prev, &mut old)
.map_err(|cause| Error::new(ProtocolExtensionError::Appl, &cause))?;
if new != old {
Self::write_extension(
req,
node,
§ions.application,
CH_STRIP_FLAG_OFFSET,
&mut new,
timeout_ms,
)?;
Self::write_sw_notice(req, node, sections, CH_STRIP_FLAG_SW_NOTICE, timeout_ms)?;
}
deserialize_effect_general_params(prev, &new)
.map_err(|cause| Error::new(ProtocolExtensionError::Appl, &cause))
}
}
impl TcatExtensionSectionParamsOperation<Spro24DspCompressorState> for SPro24DspProtocol {
fn cache_extension_whole_params(
req: &FwReq,
node: &FwNode,
sections: &ExtensionSections,
_: &ExtensionCaps,
params: &mut Spro24DspCompressorState,
timeout_ms: u32,
) -> Result<(), Error> {
let mut raw = vec![0u8; COEF_BLOCK_SIZE * 2];
Self::read_extension(
req,
node,
§ions.application,
COEF_OFFSET + COEF_BLOCK_SIZE * COEF_BLOCK_COMP,
&mut raw,
timeout_ms,
)?;
deserialize_compressor_state(params, &raw)
.map_err(|cause| Error::new(ProtocolExtensionError::Appl, &cause))
}
}
impl TcatExtensionSectionPartialMutableParamsOperation<Spro24DspCompressorState>
for SPro24DspProtocol
{
fn update_extension_partial_params(
req: &FwReq,
node: &FwNode,
sections: &ExtensionSections,
_: &ExtensionCaps,
params: &Spro24DspCompressorState,
prev: &mut Spro24DspCompressorState,
timeout_ms: u32,
) -> Result<(), Error> {
let mut new = vec![0u8; COEF_BLOCK_SIZE * 2];
serialize_compressor_state(params, &mut new)
.map_err(|cause| Error::new(ProtocolExtensionError::Appl, &cause))?;
let mut old = vec![0u8; COEF_BLOCK_SIZE * 2];
serialize_compressor_state(prev, &mut old)
.map_err(|cause| Error::new(ProtocolExtensionError::Appl, &cause))?;
(0..(COEF_BLOCK_SIZE * 2)).step_by(4).try_for_each(|pos| {
if new[pos..(pos + 4)] != old[pos..(pos + 4)] {
Self::write_extension(
req,
node,
§ions.application,
COEF_OFFSET + COEF_BLOCK_SIZE * COEF_BLOCK_COMP + pos,
&mut new[pos..(pos + 4)],
timeout_ms,
)
} else {
Ok(())
}
})?;
Self::write_sw_notice(req, node, sections, COMP_CH0_SW_NOTICE, timeout_ms)?;
Self::write_sw_notice(req, node, sections, COMP_CH1_SW_NOTICE, timeout_ms)?;
deserialize_compressor_state(prev, &new)
.map_err(|cause| Error::new(ProtocolExtensionError::Appl, &cause))
}
}
impl TcatExtensionSectionParamsOperation<Spro24DspEqualizerState> for SPro24DspProtocol {
fn cache_extension_whole_params(
req: &FwReq,
node: &FwNode,
sections: &ExtensionSections,
_: &ExtensionCaps,
params: &mut Spro24DspEqualizerState,
timeout_ms: u32,
) -> Result<(), Error> {
let mut raw = vec![0u8; COEF_BLOCK_SIZE * 2];
Self::read_extension(
req,
node,
§ions.application,
COEF_OFFSET + COEF_BLOCK_SIZE * COEF_BLOCK_EQ,
&mut raw,
timeout_ms,
)?;
deserialize_equalizer_state(params, &raw)
.map_err(|cause| Error::new(ProtocolExtensionError::Appl, &cause))
}
}
impl TcatExtensionSectionPartialMutableParamsOperation<Spro24DspEqualizerState>
for SPro24DspProtocol
{
fn update_extension_partial_params(
req: &FwReq,
node: &FwNode,
sections: &ExtensionSections,
_: &ExtensionCaps,
params: &Spro24DspEqualizerState,
prev: &mut Spro24DspEqualizerState,
timeout_ms: u32,
) -> Result<(), Error> {
let mut new = vec![0u8; COEF_BLOCK_SIZE * 2];
serialize_equalizer_state(params, &mut new)
.map_err(|cause| Error::new(ProtocolExtensionError::Appl, &cause))?;
let mut old = vec![0u8; COEF_BLOCK_SIZE * 2];
serialize_equalizer_state(prev, &mut old)
.map_err(|cause| Error::new(ProtocolExtensionError::Appl, &cause))?;
(0..(COEF_BLOCK_SIZE * 2)).step_by(4).try_for_each(|pos| {
if new[pos..(pos + 4)] != old[pos..(pos + 4)] {
Self::write_extension(
req,
node,
§ions.application,
COEF_OFFSET + COEF_BLOCK_SIZE * COEF_BLOCK_EQ + pos,
&mut new[pos..(pos + 4)],
timeout_ms,
)
} else {
Ok(())
}
})?;
Self::write_sw_notice(req, node, sections, EQ_OUTPUT_CH0_SW_NOTICE, timeout_ms)?;
Self::write_sw_notice(req, node, sections, EQ_OUTPUT_CH1_SW_NOTICE, timeout_ms)?;
Self::write_sw_notice(req, node, sections, EQ_LOW_FREQ_CH0_SW_NOTICE, timeout_ms)?;
Self::write_sw_notice(req, node, sections, EQ_LOW_FREQ_CH1_SW_NOTICE, timeout_ms)?;
Self::write_sw_notice(
req,
node,
sections,
EQ_LOW_MIDDLE_FREQ_CH0_SW_NOTICE,
timeout_ms,
)?;
Self::write_sw_notice(
req,
node,
sections,
EQ_LOW_MIDDLE_FREQ_CH1_SW_NOTICE,
timeout_ms,
)?;
Self::write_sw_notice(
req,
node,
sections,
EQ_HIGH_MIDDLE_FREQ_CH0_SW_NOTICE,
timeout_ms,
)?;
Self::write_sw_notice(
req,
node,
sections,
EQ_HIGH_MIDDLE_FREQ_CH1_SW_NOTICE,
timeout_ms,
)?;
Self::write_sw_notice(req, node, sections, EQ_HIGH_FREQ_CH0_SW_NOTICE, timeout_ms)?;
Self::write_sw_notice(req, node, sections, EQ_HIGH_FREQ_CH1_SW_NOTICE, timeout_ms)?;
deserialize_equalizer_state(prev, &new)
.map_err(|cause| Error::new(ProtocolExtensionError::Appl, &cause))
}
}
impl TcatExtensionSectionParamsOperation<Spro24DspReverbState> for SPro24DspProtocol {
fn cache_extension_whole_params(
req: &FwReq,
node: &FwNode,
sections: &ExtensionSections,
_: &ExtensionCaps,
params: &mut Spro24DspReverbState,
timeout_ms: u32,
) -> Result<(), Error> {
let mut raw = vec![0u8; COEF_BLOCK_SIZE];
Self::read_extension(
req,
node,
§ions.application,
COEF_OFFSET + COEF_BLOCK_SIZE * COEF_BLOCK_REVERB,
&mut raw,
timeout_ms,
)?;
deserialize_reverb_state(params, &raw)
.map_err(|cause| Error::new(ProtocolExtensionError::Appl, &cause))
}
}
impl TcatExtensionSectionPartialMutableParamsOperation<Spro24DspReverbState> for SPro24DspProtocol {
fn update_extension_partial_params(
req: &FwReq,
node: &FwNode,
sections: &ExtensionSections,
_: &ExtensionCaps,
params: &Spro24DspReverbState,
prev: &mut Spro24DspReverbState,
timeout_ms: u32,
) -> Result<(), Error> {
let mut new = vec![0u8; COEF_BLOCK_SIZE];
serialize_reverb_state(params, &mut new)
.map_err(|cause| Error::new(ProtocolExtensionError::Appl, &cause))?;
let mut old = vec![0u8; COEF_BLOCK_SIZE];
serialize_reverb_state(prev, &mut old)
.map_err(|cause| Error::new(ProtocolExtensionError::Appl, &cause))?;
(0..(COEF_BLOCK_SIZE * 2)).step_by(4).try_for_each(|pos| {
if new[pos..(pos + 4)] != old[pos..(pos + 4)] {
Self::write_extension(
req,
node,
§ions.application,
COEF_OFFSET + COEF_BLOCK_SIZE * COEF_BLOCK_REVERB + pos,
&mut new[pos..(pos + 4)],
timeout_ms,
)
} else {
Ok(())
}
})?;
Self::write_sw_notice(req, node, sections, REVERB_SW_NOTICE, timeout_ms)?;
deserialize_reverb_state(prev, &new)
.map_err(|cause| Error::new(ProtocolExtensionError::Appl, &cause))
}
}
impl SPro24DspProtocol {
pub const COMPRESSOR_OUTPUT_MIN: f32 = 0.0;
pub const COMPRESSOR_OUTPUT_MAX: f32 = 64.0;
pub const COMPRESSOR_THRESHOLD_MIN: f32 = -1.25;
pub const COMPRESSOR_THRESHOLD_MAX: f32 = 0.0;
pub const COMPRESSOR_RATIO_MIN: f32 = 0.03125;
pub const COMPRESSOR_RATIO_MAX: f32 = 0.5;
pub const COMPRESSOR_ATTACK_MIN: f32 = -1.0;
pub const COMPRESSOR_ATTACK_MAX: f32 = -0.9375;
pub const COMPRESSOR_RELEASE_MIN: f32 = 0.9375;
pub const COMPRESSOR_RELEASE_MAX: f32 = 1.0;
pub const EQUALIZER_OUTPUT_MIN: f32 = 0.0;
pub const EQUALIZER_OUTPUT_MAX: f32 = 1.0;
pub const REVERB_SIZE_MIN: f32 = 0.0;
pub const REVERB_SIZE_MAX: f32 = 1.0;
pub const REVERB_AIR_MIN: f32 = 0.0;
pub const REVERB_AIR_MAX: f32 = 1.0;
pub const REVERB_PRE_FILTER_MIN: f32 = -1.0;
pub const REVERB_PRE_FILTER_MAX: f32 = 1.0;
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn compressor_state_serdes() {
let state = Spro24DspCompressorState {
output: [0.04, 0.05],
threshold: [0.16, 0.17],
ratio: [0.20, 0.21],
attack: [0.32, 0.33],
release: [0.44, 0.45],
};
let mut raw = [0u8; COEF_BLOCK_SIZE * 2];
serialize_compressor_state(&state, &mut raw).unwrap();
let mut s = Spro24DspCompressorState::default();
deserialize_compressor_state(&mut s, &raw).unwrap();
assert_eq!(state, s);
}
#[test]
fn equalizer_state_serdes() {
let state = Spro24DspEqualizerState {
output: [0.06, 0.07],
low_coef: [
Spro24DspEqualizerFrequencyBandState([0.00, 0.01, 0.02, 0.03, 0.04]),
Spro24DspEqualizerFrequencyBandState([0.10, 0.11, 0.12, 0.13, 0.14]),
],
low_middle_coef: [
Spro24DspEqualizerFrequencyBandState([0.20, 0.21, 0.22, 0.23, 0.24]),
Spro24DspEqualizerFrequencyBandState([0.30, 0.31, 0.32, 0.33, 0.34]),
],
high_middle_coef: [
Spro24DspEqualizerFrequencyBandState([0.40, 0.41, 0.42, 0.43, 0.44]),
Spro24DspEqualizerFrequencyBandState([0.50, 0.51, 0.52, 0.53, 0.54]),
],
high_coef: [
Spro24DspEqualizerFrequencyBandState([0.60, 0.61, 0.62, 0.63, 0.64]),
Spro24DspEqualizerFrequencyBandState([0.70, 0.71, 0.72, 0.73, 0.74]),
],
};
let mut raw = [0u8; COEF_BLOCK_SIZE * 2];
serialize_equalizer_state(&state, &mut raw).unwrap();
let mut s = Spro24DspEqualizerState::default();
deserialize_equalizer_state(&mut s, &raw).unwrap();
assert_eq!(state, s);
}
#[test]
fn reverb_state_serdes() {
let state = Spro24DspReverbState {
size: 0.04,
air: 0.14,
enabled: false,
pre_filter: -0.1,
};
let mut raw = [0u8; COEF_BLOCK_SIZE];
serialize_reverb_state(&state, &mut raw).unwrap();
let mut s = Spro24DspReverbState::default();
deserialize_reverb_state(&mut s, &raw).unwrap();
assert_eq!(state, s);
}
#[test]
fn effect_general_params_serdes() {
let params = Spro24DspEffectGeneralParams {
eq_after_comp: [false, true],
comp_enable: [true, false],
eq_enable: [false, true],
};
let mut raw = [0u8; 4];
serialize_effect_general_params(¶ms, &mut raw).unwrap();
let mut p = Spro24DspEffectGeneralParams::default();
deserialize_effect_general_params(&mut p, &raw).unwrap();
assert_eq!(params, p);
}
}