use core::ops::RangeInclusive;
use libm::{roundf, sinf};
use crate::prelude::KnotValue;
#[inline(always)]
pub fn get_midi_note(octave: impl Into<i32>, note: impl Into<i32>) -> i32 {
let octave = wrap(octave.into(), 10);
let note = wrap(note.into(), 12);
((octave + 1) * 12) + note
}
#[inline(always)]
pub fn note_to_frequency(note: f32) -> f32 {
libm::powf(2.0, (note - 69.0) / 12.0) * 440.0
}
pub fn frequency_to_note(frequency: f32) -> f32 {
69.0 + 12.0 * libm::log2f(frequency / 440.0)
}
#[inline(always)]
pub(crate) fn lerp<T>(start: T, end: T, t: f32) -> f32
where T:KnotValue
{
let start:f32 = start.into();
let end:f32 = end.into();
start + t * (end - start)
}
#[inline(always)]
pub(crate) fn wrap(value: i32, modulus: i32) -> i32 {
((value % modulus) + modulus) % modulus
}
#[inline(always)]
pub(crate) fn compress_volume(input_vol:f32, max_vol:f32) -> f32 {
let mult = core::f32::consts::FRAC_2_PI;
sinf(input_vol/(max_vol*mult))
}
pub(crate) fn quantize_range(value: f32, steps: u16, range: RangeInclusive<f32>) -> f32 {
if steps == 0 {
return 0.0;
}
if steps == 1 {
return 1.0;
}
let steps = steps - 1;
let min = *range.start();
let max = *range.end();
let step_size = (max - min) / steps as f32;
let quantized_value = (roundf((value - min) / step_size) * step_size) + min;
quantized_value.clamp(min, max)
}
#[test]
fn quantization_test() {
let mut last_value = 0.0;
let mut value_count = 0;
let steps = 5;
for n in -10 ..= 10 {
let value = n as f32 / 10.0;
let result = quantize_range(value, steps, -1.0 ..= 1.0);
if result != last_value {
last_value = result;
value_count += 1;
}
}
assert_eq!(steps, value_count);
}
#[test]
fn test_wrapping() {
let a = wrap(55, 10);
assert_eq!(a, 5);
let b = wrap(-5,10);
assert_eq!(b, 5);
let c = -5 % 10;
assert_ne!(b, c);
}
#[test]
fn notes_and_frquencies() {
let note = 60.0;
let freq = 261.63;
let a = note_to_frequency(note);
assert!((a-freq).abs() < 0.01);
let b = frequency_to_note(freq);
assert!((b-note).abs() < 0.01);
for n in 1 .. 100 {
let a = n as f32 * 100.0;
let note = frequency_to_note(a);
let freq = note_to_frequency(note);
assert!((a - freq).abs() < 0.01);
}
}