pub mod desktop;
pub mod shell;
pub mod studio;
pub mod ch_strip;
pub mod reverb;
use super::{tcat::*, *};
const BASE_OFFSET: usize = 0x00a01000;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TcKonnektSegment<U> {
pub data: U,
raw: Vec<u8>,
}
pub trait TcKonnektSegmentSerdes<T> {
const NAME: &'static str;
const OFFSET: usize;
const SIZE: usize;
fn serialize(params: &T, raw: &mut [u8]) -> Result<(), String>;
fn deserialize(params: &mut T, raw: &[u8]) -> Result<(), String>;
}
fn generate_error(segment_name: &str, cause: &str, raw: &[u8]) -> Error {
let msg = format!(
"segment: {}, cause: '{}', raw: {:02x?}",
segment_name, cause, raw
);
Error::new(GeneralProtocolError::VendorDependent, &msg)
}
pub trait TcKonnektSegmentOperation<T>: TcatOperation + TcKonnektSegmentSerdes<T> {
fn cache_whole_segment(
req: &FwReq,
node: &FwNode,
segment: &mut TcKonnektSegment<T>,
timeout_ms: u32,
) -> Result<(), Error> {
assert_eq!(segment.raw.len(), Self::SIZE);
Self::read(
req,
node,
BASE_OFFSET + Self::OFFSET,
&mut segment.raw,
timeout_ms,
)?;
Self::deserialize(&mut segment.data, &segment.raw)
.map_err(|cause| generate_error(Self::NAME, &cause, &segment.raw))
}
}
impl<O: TcatOperation + TcKonnektSegmentSerdes<T>, T> TcKonnektSegmentOperation<T> for O {}
pub trait TcKonnektMutableSegmentOperation<T>: TcatOperation + TcKonnektSegmentSerdes<T> {
fn update_partial_segment(
req: &FwReq,
node: &FwNode,
params: &T,
segment: &mut TcKonnektSegment<T>,
timeout_ms: u32,
) -> Result<(), Error> {
assert_eq!(segment.raw.len(), Self::SIZE);
let mut raw = segment.raw.clone();
Self::serialize(params, &mut raw)
.map_err(|cause| generate_error(Self::NAME, &cause, &segment.raw))?;
(0..Self::SIZE).step_by(4).try_for_each(|pos| {
let new = &mut raw[pos..(pos + 4)];
if new != &segment.raw[pos..(pos + 4)] {
Self::write(req, node, BASE_OFFSET + Self::OFFSET + pos, new, timeout_ms)
.map(|_| segment.raw[pos..(pos + 4)].copy_from_slice(new))
} else {
Ok(())
}
})?;
Self::deserialize(&mut segment.data, &raw)
.map_err(|cause| generate_error(Self::NAME, &cause, &segment.raw))
}
fn update_whole_segment(
req: &FwReq,
node: &FwNode,
params: &T,
segment: &mut TcKonnektSegment<T>,
timeout_ms: u32,
) -> Result<(), Error> {
assert_eq!(segment.raw.len(), Self::SIZE);
let mut raw = segment.raw.clone();
Self::serialize(¶ms, &mut raw)
.map_err(|cause| generate_error(Self::NAME, &cause, &segment.raw))?;
Self::write(req, node, BASE_OFFSET + Self::OFFSET, &mut raw, timeout_ms)?;
segment.raw.copy_from_slice(&raw);
Self::deserialize(&mut segment.data, &segment.raw)
.map_err(|cause| generate_error(Self::NAME, &cause, &segment.raw))
}
}
pub trait TcKonnektNotifiedSegmentOperation<T> {
const NOTIFY_FLAG: u32;
fn is_notified_segment(_: &TcKonnektSegment<T>, msg: u32) -> bool {
msg & Self::NOTIFY_FLAG > 0
}
}
fn serialize_position<T: Eq + std::fmt::Debug>(
entries: &[T],
entry: &T,
raw: &mut [u8],
label: &str,
) -> Result<(), String> {
assert!(raw.len() >= 4);
entries
.iter()
.position(|t| entry.eq(t))
.ok_or_else(|| format!("{} {:?} is not supported", label, entry))
.map(|pos| serialize_usize(&pos, raw))
}
fn deserialize_position<T: Copy + Eq + std::fmt::Debug>(
entries: &[T],
entry: &mut T,
raw: &[u8],
label: &str,
) -> Result<(), String> {
assert!(raw.len() >= 4);
let mut val = 0usize;
deserialize_usize(&mut val, raw);
entries
.iter()
.nth(val as usize)
.ok_or_else(|| format!("{} not found for index {}", label, val))
.map(|&e| *entry = e)
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum FireWireLedState {
Off,
On,
BlinkFast,
BlinkSlow,
}
impl Default for FireWireLedState {
fn default() -> Self {
Self::Off
}
}
const FW_LED_STATES: &[FireWireLedState] = &[
FireWireLedState::Off,
FireWireLedState::On,
FireWireLedState::BlinkSlow,
FireWireLedState::BlinkFast,
];
const FW_LED_STATE_LABEL: &str = "FireWire LED state";
fn serialize_fw_led_state(state: &FireWireLedState, raw: &mut [u8]) -> Result<(), String> {
serialize_position(FW_LED_STATES, state, raw, FW_LED_STATE_LABEL)
}
fn deserialize_fw_led_state(state: &mut FireWireLedState, raw: &[u8]) -> Result<(), String> {
deserialize_position(FW_LED_STATES, state, raw, FW_LED_STATE_LABEL)
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum TcKonnektStandaloneClockRate {
R44100,
R48000,
R88200,
R96000,
}
impl Default for TcKonnektStandaloneClockRate {
fn default() -> Self {
Self::R44100
}
}
fn serialize_standalone_clock_rate(
rate: &TcKonnektStandaloneClockRate,
raw: &mut [u8],
) -> Result<(), String> {
assert!(raw.len() >= 4);
let val = match rate {
TcKonnektStandaloneClockRate::R96000 => 4,
TcKonnektStandaloneClockRate::R88200 => 3,
TcKonnektStandaloneClockRate::R48000 => 2,
TcKonnektStandaloneClockRate::R44100 => 1,
};
serialize_u32(&val, raw);
Ok(())
}
fn deserialize_standalone_clock_rate(
rate: &mut TcKonnektStandaloneClockRate,
raw: &[u8],
) -> Result<(), String> {
assert!(raw.len() >= 4);
let mut val = 0u32;
deserialize_u32(&mut val, raw);
*rate = match val {
4 => TcKonnektStandaloneClockRate::R96000,
3 => TcKonnektStandaloneClockRate::R88200,
2 => TcKonnektStandaloneClockRate::R48000,
1 => TcKonnektStandaloneClockRate::R44100,
_ => Err(format!(
"Unexpected value for standalone clock rate: {}",
val
))?,
};
Ok(())
}
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
pub struct TcKonnektMidiMsgParams {
pub ch: u8,
pub cc: u8,
}
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
pub struct TcKonnektMidiSender {
pub normal: TcKonnektMidiMsgParams,
pub pushed: TcKonnektMidiMsgParams,
pub send_to_port: bool,
pub send_to_stream: bool,
}
impl TcKonnektMidiSender {
pub(crate) const SIZE: usize = 36;
}
fn serialize_midi_sender(sender: &TcKonnektMidiSender, raw: &mut [u8]) -> Result<(), String> {
assert!(raw.len() >= TcKonnektMidiSender::SIZE);
serialize_u8(&sender.normal.ch, &mut raw[..4]);
serialize_u8(&sender.normal.cc, &mut raw[4..8]);
serialize_u8(&sender.pushed.ch, &mut raw[12..16]);
serialize_u8(&sender.pushed.cc, &mut raw[16..20]);
serialize_bool(&sender.send_to_port, &mut raw[24..28]);
serialize_bool(&sender.send_to_stream, &mut raw[28..32]);
Ok(())
}
fn deserialize_midi_sender(sender: &mut TcKonnektMidiSender, raw: &[u8]) -> Result<(), String> {
assert!(raw.len() >= TcKonnektMidiSender::SIZE);
deserialize_u8(&mut sender.normal.ch, &raw[..4]);
deserialize_u8(&mut sender.normal.cc, &raw[4..8]);
deserialize_u8(&mut sender.pushed.ch, &raw[12..16]);
deserialize_u8(&mut sender.pushed.cc, &raw[16..20]);
deserialize_bool(&mut sender.send_to_port, &raw[24..28]);
deserialize_bool(&mut sender.send_to_stream, &raw[28..32]);
Ok(())
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum TcKonnektLoadedProgram {
P0,
P1,
P2,
}
impl Default for TcKonnektLoadedProgram {
fn default() -> Self {
Self::P0
}
}
const LOADED_PROGRAMS: &[TcKonnektLoadedProgram] = &[
TcKonnektLoadedProgram::P0,
TcKonnektLoadedProgram::P1,
TcKonnektLoadedProgram::P2,
];
const LOADED_PROGRAM_LABEL: &str = "loaded program";
fn serialize_loaded_program(prog: &TcKonnektLoadedProgram, raw: &mut [u8]) -> Result<(), String> {
serialize_position(LOADED_PROGRAMS, prog, raw, LOADED_PROGRAM_LABEL)
}
fn deserialize_loaded_program(prog: &mut TcKonnektLoadedProgram, raw: &[u8]) -> Result<(), String> {
deserialize_position(LOADED_PROGRAMS, prog, raw, LOADED_PROGRAM_LABEL)
}