use std::collections::{HashMap, HashSet};
use crate::tec::TranslationalEquivalence;
const PITCH_BITS: u32 = 14;
const OFFSET: u32 = 1200;
pub fn notes_to_points(
notes: &Vec<(usize, usize, usize, usize, usize, i64, i64)>,
) -> (
Vec<(u32, u32)>,
HashMap<(u32, u32), Vec<(usize, usize, usize, usize, usize, i64, i64)>>,
) {
let mut points = Vec::new();
let mut mapping = HashMap::new();
for &(tick, layer, instrument, key, velocity, panning, pitch) in notes {
let pitch_cents = ((key * 100) as i64 + pitch) as u32;
let pitch_off = pitch_cents + OFFSET;
let encoded_y = ((instrument as u32) << PITCH_BITS) | pitch_off;
let point = (tick as u32, encoded_y);
points.push(point);
mapping
.entry(point)
.or_insert_with(Vec::new)
.push((tick, layer, instrument, key, velocity, panning, pitch));
}
(points, mapping)
}
pub fn merge_tecs(
tecs: Vec<TranslationalEquivalence>,
filter: fn(&TranslationalEquivalence) -> bool
) -> Vec<TranslationalEquivalence> {
let mut to_merge = Vec::new();
let mut to_keep = Vec::new();
for tec in tecs {
if filter(&tec) {
to_merge.push(tec);
} else {
to_keep.push(tec);
}
}
if to_merge.is_empty() {
return to_keep;
}
let mut merged_points = HashSet::new();
for tec in to_merge {
merged_points.extend(tec.coverage());
}
if merged_points.is_empty() {
return vec![]
}
let mut sorted_points = Vec::from_iter(merged_points);
sorted_points.sort();
let merged_tec = TranslationalEquivalence::new(
sorted_points,
HashSet::new(),
None
);
to_keep.push(merged_tec);
to_keep
}
pub fn compression_stats(
tecs: &Vec<TranslationalEquivalence>,
original_points: &Vec<(u32, u32)>
) -> (usize, usize, f64) {
fn _count_units(tecs: &Vec<TranslationalEquivalence>) -> usize {
let mut units = 0usize;
for tec in tecs {
units += tec.translators.len();
units += if tec.sub_tecs.is_empty() {
tec.pattern.len()
} else {
_count_units(&tec.sub_tecs)
};
}
units
}
let original = original_points.len();
let encoded = _count_units(tecs);
let ratio = if encoded > 0 {
original as f64 / encoded as f64
} else {
0.0
};
(original, encoded, ratio)
}
pub fn points_to_notes(
tecs: &Vec<TranslationalEquivalence>,
mapping: &HashMap<(u32, u32), Vec<(usize, usize, usize, usize, usize, i64, i64)>>,
) -> Vec<(usize, usize, usize, usize, usize, i64, i64)> {
let mut all_points = HashSet::new();
for tec in tecs {
all_points.extend(tec.coverage());
}
let mut result = Vec::new();
for point in all_points {
if let Some(notes_at_point) = mapping.get(&point) {
result.extend(notes_at_point.iter().cloned());
}
}
result.sort();
result
}