use std::cmp::Ordering;
use std::collections::HashMap;
use std::f64::consts::PI;
use std::fmt;
use maplit::hashmap;
pub type InstrArgs = HashMap<String, f64>;
#[derive(Clone, PartialEq)]
pub enum InstrType {
CONST,
SINE,
}
impl fmt::Display for InstrType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}",
match self {
InstrType::CONST => "CONST",
InstrType::SINE => "SINE",
}
)
}
}
#[derive(Clone, PartialEq)]
pub struct Instruction {
pub instr_type: InstrType,
pub args: InstrArgs,
}
impl Instruction {
pub fn new(instr_type: InstrType, args: InstrArgs) -> Self {
let panic_no_key = |key| {
if !args.contains_key(key) {
panic!("Expected instr type {} to contain key {}", instr_type, key)
}
};
match instr_type {
InstrType::CONST => panic_no_key("value"),
InstrType::SINE => panic_no_key("freq"),
};
Instruction { instr_type, args }
}
pub fn eval_inplace(&self, t_arr: &mut ndarray::ArrayViewMut1<f64>) {
match self.instr_type {
InstrType::CONST => {
let value = *self.args.get("value").unwrap();
t_arr.fill(value);
}
InstrType::SINE => {
let freq = *self.args.get("freq").unwrap();
let amplitude = *self.args.get("amplitude").unwrap_or(&1.0);
let offset = *self.args.get("offset").unwrap_or(&0.0);
let phase = *self.args.get("phase").unwrap_or(&0.0);
t_arr.map_inplace(|t| {
*t = (2.0 * PI * freq * (*t) + phase).sin() * amplitude + offset
});
}
}
}
pub fn new_const(value: f64) -> Instruction {
Instruction::new(InstrType::CONST, hashmap! {String::from("value") => value})
}
pub fn new_sine(
freq: f64,
amplitude: Option<f64>,
phase: Option<f64>,
dc_offset: Option<f64>,
) -> Instruction {
let mut instr_args: InstrArgs = hashmap! {"freq".to_string() => freq};
[
("amplitude", amplitude),
("phase", phase),
("offset", dc_offset),
]
.iter()
.for_each(|(key, opt_value)| {
if let Some(value) = *opt_value {
instr_args.insert(key.to_string(), value);
}
});
Instruction::new(InstrType::SINE, instr_args)
}
}
impl fmt::Display for Instruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let args_string = self
.args
.iter()
.map(|(k, v)| format!("{}: {}", k, v))
.collect::<Vec<String>>()
.join(", ");
write!(f, "[{}, {{{}}}]", self.instr_type, args_string)
}
}
pub struct InstrBook {
pub start_pos: usize,
pub end_pos: usize,
pub keep_val: bool,
pub instr: Instruction,
}
impl InstrBook {
pub fn new(start_pos: usize, end_pos: usize, keep_val: bool, instr: Instruction) -> Self {
assert!(
end_pos > start_pos,
"Instruction {} end_pos {} should be strictly greater than start_pos {}",
instr,
end_pos,
start_pos
);
InstrBook {
start_pos,
end_pos,
keep_val,
instr,
}
}
}
impl Ord for InstrBook {
fn cmp(&self, other: &Self) -> Ordering {
self.start_pos.cmp(&other.start_pos)
}
}
impl PartialOrd for InstrBook {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl PartialEq for InstrBook {
fn eq(&self, other: &Self) -> bool {
self.start_pos == other.start_pos
}
}
impl fmt::Display for InstrBook {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"InstrBook({}, {}-{}, {})",
self.instr, self.start_pos, self.end_pos, self.keep_val
)
}
}
impl Eq for InstrBook {}