#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(transparent)]
pub struct Key(i32);
impl Key {
pub const A4: Self = Self(96 * 256);
pub const C4: Self = Self(87 * 256);
pub const A6: Self = Self::from_basic(0x2D00);
pub const BASIC: i32 = 0x4500;
pub const fn as_value(&self) -> i32 {
self.0
}
pub const fn from_a4_offset(a4_offset: i32) -> Self {
Self(Self::A4.as_value() + a4_offset)
}
pub const fn as_a4_offset(&self) -> i32 {
self.as_value() - Self::A4.as_value()
}
pub const fn from_a6_offset(a6_offset: i32) -> Self {
Self(Self::A6.as_value() + a6_offset)
}
pub const fn as_a6_offset(&self) -> i32 {
self.as_value() - Self::A6.as_value()
}
pub const fn from_basic(basic: i32) -> Self {
Self::from_a4_offset(Self::BASIC - basic)
}
pub const fn as_basic(&self) -> i32 {
Self::BASIC - self.as_a4_offset()
}
pub fn approx_from_semis(semis: f32) -> Self {
Self::from((semis * 256.) as i32)
}
pub fn as_semis(&self) -> f32 {
(self.as_value() as f32) / 256.
}
pub fn approx_from_a4_semis(a4_semis: f32) -> Self {
Self::approx_from_semis(Self::A4.as_semis() + a4_semis)
}
pub fn as_a4_semis(&self) -> f32 {
(self.as_a4_offset() as f32) / 256.
}
pub fn approx_from_a6_semis(a6_semis: f32) -> Self {
Self::approx_from_semis(Self::A6.as_semis() + a6_semis)
}
pub fn as_a6_semis(&self) -> f32 {
(self.as_a6_offset() as f32) / 256.
}
pub fn approx_from_basic_semis(basic_semis: f32) -> Self {
Self::from_basic((basic_semis * 256.) as i32)
}
pub fn as_basic_semis(&self) -> f32 {
(self.as_basic() as f32) / 256.
}
pub fn approx_from_hertz(frequency: f32) -> Self {
Self::approx_from_a4_semis((frequency / Self::A4.as_hertz()).log2() * 12.)
}
pub fn as_hertz(&self) -> f32 {
(self.as_a4_semis() / 12.).exp2() * 440.
}
}
impl From<i32> for Key {
fn from(value: i32) -> Self {
Self(value)
}
}
impl Default for Key {
fn default() -> Self {
Self::A4
}
}