use core::ops::{Div, Mul};
#[cfg(target_arch = "arm")]
use num_traits::float::Float;
#[cfg(all(feature = "vpo_fastmaths", target_arch = "arm"))]
use super::fastmaths::FastFloat as _;
use cfg_if::cfg_if;
#[cfg(all(not(feature = "vpo_fastmaths"), target_arch = "arm"))]
use num_traits::Float as _;
#[derive(Clone, Copy, Debug, PartialEq, Default)]
pub struct VoltsPerSample {
scalar: f32,
offset: f32,
}
impl VoltsPerSample {
pub fn new(scalar: f32, offset: f32) -> Self {
Self { scalar, offset }
}
pub fn sample_to_freq(self, sample: f32) -> Frequency {
(self * sample).into()
}
pub fn freq_to_sample(self, freq: impl Into<Frequency>) -> f32 {
let volts: Volts = freq.into().into();
volts / self
}
pub fn sample_to_note(self, sample: f32) -> Note {
(self * sample).into()
}
pub fn note_to_sample(self, note: impl Into<Note>) -> f32 {
let volts: Volts = note.into().into();
volts / self
}
pub fn sample_to_volts(self, sample: f32) -> Volts {
self * sample
}
pub fn volts_to_sample(self, volts: impl Into<Volts>) -> f32 {
volts.into() / self
}
}
impl Mul<f32> for VoltsPerSample {
type Output = Volts;
fn mul(self, sample: f32) -> Self::Output {
Volts((sample - self.offset) * self.scalar)
}
}
impl Mul<VoltsPerSample> for f32 {
type Output = Volts;
fn mul(self, vps: VoltsPerSample) -> Self::Output {
vps.mul(self)
}
}
impl Div<VoltsPerSample> for Volts {
type Output = f32;
fn div(self, vps: VoltsPerSample) -> Self::Output {
(self.0 / vps.scalar) + vps.offset
}
}
#[derive(Clone, Copy, Debug, PartialEq, Default, PartialOrd)]
pub struct Volts(pub f32);
impl From<f32> for Volts {
fn from(value: f32) -> Self {
Volts(value)
}
}
impl From<Volts> for f32 {
fn from(volts: Volts) -> Self {
volts.0
}
}
impl From<Frequency> for Volts {
fn from(freq: Frequency) -> Self {
cfg_if! {
if #[cfg(all(feature = "vpo_fastmaths", target_arch = "arm"))] {
(freq.0 / 440.0).fast_log2().into()
} else {
(freq.0 / 440.0).log2().into()
}
}
}
}
impl From<Note> for Volts {
fn from(note: Note) -> Self {
((note.0 as f32 - 69.0) / 12.0).into()
}
}
impl From<NoteWithBend> for Volts {
fn from(note_with_bend: NoteWithBend) -> Self {
((note_with_bend.note.0 as f32 - 69.0 + (note_with_bend.bend as f32 / 128.0)) / 12.0).into()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, PartialOrd, Ord)]
pub struct Note(pub u8);
impl From<u8> for Note {
fn from(value: u8) -> Self {
Note(value)
}
}
impl From<Note> for u8 {
fn from(val: Note) -> Self {
val.0
}
}
impl From<Volts> for Note {
fn from(volts: Volts) -> Self {
((12.0 * volts.0 + 69.0) as u8).into()
}
}
impl From<Frequency> for Note {
fn from(freq: Frequency) -> Self {
let volts: Volts = freq.into();
volts.into()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, PartialOrd, Ord)]
pub struct NoteWithBend{
pub note: Note,
pub bend: i8,
}
impl From<Note> for NoteWithBend {
fn from(note: Note) -> Self {
NoteWithBend{note, bend: 0}
}
}
impl From<Volts> for NoteWithBend {
fn from(volts: Volts) -> Self {
let value = 12.0 * volts.0 + 69.0;
let note_number = value.round();
let bend = ((value - note_number) * 128.0) as i8;
Self {
note: (note_number as u8).into(),
bend
}
}
}
impl From<Frequency> for NoteWithBend {
fn from(freq: Frequency) -> Self {
let volts: Volts = freq.into();
volts.into()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Default, PartialOrd)]
pub struct Frequency(pub f32);
impl From<f32> for Frequency {
fn from(value: f32) -> Self {
Frequency(value)
}
}
impl From<Frequency> for f32 {
fn from(freq: Frequency) -> Self {
freq.0
}
}
impl From<Volts> for Frequency {
fn from(volts: Volts) -> Self {
cfg_if! {
if #[cfg(all(feature = "vpo_fastmaths", target_arch = "arm"))] {
(440.0 * volts.0.fast_exp2()).into()
} else {
(440.0 * volts.0.exp2()).into()
}
}
}
}
impl From<Note> for Frequency {
fn from(note: Note) -> Self {
let volts: Volts = note.into();
volts.into()
}
}
impl From<NoteWithBend> for Frequency {
fn from(note_with_bend: NoteWithBend) -> Self {
let volts: Volts = note_with_bend.into();
volts.into()
}
}