diff options
Diffstat (limited to 'src/notes.rs')
-rw-r--r-- | src/notes.rs | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/src/notes.rs b/src/notes.rs new file mode 100644 index 0000000..41eb45e --- /dev/null +++ b/src/notes.rs @@ -0,0 +1,168 @@ +use derive_more::Display; +use std::fmt::{Debug, Write}; +use num_traits::{NumOps, ToPrimitive}; + +#[derive(Debug, Clone, Display, Copy, PartialEq)] +pub enum Notes { + #[display(fmt=" c")] + C, + #[display(fmt="c#")] + Cs, + #[display(fmt=" d")] + D, + #[display(fmt="d#")] + Ds, + #[display(fmt=" e")] + E, + #[display(fmt=" f")] + F, + #[display(fmt="f#")] + Fs, + #[display(fmt=" g")] + G, + #[display(fmt="g#")] + Gs, + #[display(fmt=" a")] + A, + #[display(fmt="a#")] + As, + #[display(fmt=" b")] + B, +} + +pub type BaseNote = (Notes, f64); + +const MIDDLE_A_VAL: f64 = 440.; +//const MIDDLE_A_LOWER: f64 = MIDDLE_A_VAL * (2f64).powf(-0.5f64 / 12f64); +//const MIDDLE_A_UPPER: f64 = MIDDLE_A_VAL * (2f64).powf(0.5f64 / 12f64); + +pub fn calc_freq_from_offset(offset: f64) -> f64 { + return MIDDLE_A_VAL * (2f64).powf(offset / 12f64); +} + +pub const NOTE_MA_OFFSETS: [BaseNote; 12] = [ + (Notes::C, -57.), (Notes::Cs, -56.), + (Notes::D, -55.), (Notes::Ds, -54.), (Notes::E, -53.), + (Notes::F, -52.), (Notes::Fs, -51.), + (Notes::G, -50.), (Notes::Gs, -49.), + (Notes::A, -48.), (Notes::As, -47.), + (Notes::B, -46.), +]; + +/*const NOTE_ORDER: [BaseNote; 12] = [ + (Notes::C, 16.352), (Notes::Cs, 17.324), + (Notes::D, 18.354), (Notes::Ds, 19.445), (Notes::E, 20.602), + (Notes::F, 21.827), (Notes::Fs, 23.125), + (Notes::G, 24.5), (Notes::Gs, 25.957), + (Notes::A, 27.5), (Notes::As, 29.135), + (Notes::B, 30.868) +];*/ + +#[derive(Debug, Display)] +#[display(fmt="{}{}", "note.0", octave)] +pub struct Note { + pub note: BaseNote, + pub low_freq: f64, + pub freq: f64, + pub high_freq: f64, + pub octave: i32, + //value: f64, +} + +pub trait NoteValue: Debug + PartialOrd + From<f32> + ToPrimitive + std::fmt::Display + Copy + NumOps {} +//where <Self as std::ops::Mul>::Output: std::fmt::Display {} + +//impl NoteValue for f32 {} +//impl NoteValue for f64 {} +impl<T> NoteValue for T +where T: Debug + PartialOrd + From<f32> + ToPrimitive + std::fmt::Display + Copy + NumOps {} + +// elements here are (Note, fft/proc data range for calculating the value, summed value, max value +// of each element in the bin) +#[derive(Debug, Display)] +//#[display(fmt="{}({:?}) {}", _0, _1 ,_2)] +//#[display(bound="I: From<f32> + std::ops::Mul + std::fmt::Display")] +#[display(fmt="{} {:.0} ", _0, "*_3*I::from(10000.0)")] +pub struct ProcerNote<'nl, I: NoteValue>(pub &'nl Note, pub core::ops::Range<usize>, pub I, pub I); +// .0 here is the notes data, .1 is the threshold for printing~ +#[derive(Debug)] +pub struct ProcerNotes<'nl, I: NoteValue>(pub Vec<ProcerNote<'nl, I>>, pub I); + +impl<'nl, I: NoteValue> std::fmt::Display for ProcerNotes<'nl, I> { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + //let threshold: I = I::from(0.00372314453125f32); + let threshold = self.1; + let mut tmp: String = String::with_capacity(1024); + for pn in self.0.iter().filter(|pn| pn.3 >= threshold) { + write!(tmp, "{pn}")?; + }; + fmt.pad(&tmp); + Ok(()) + } +} + + +/*impl<'nl, I: Debug + PartialOrd + From<f32>> Debug for ProcerNotes<'nl, I> { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + let threshold: I = I::from(122.0f32); + fmt.debug_list().entries(self.0.iter().filter(|pn| pn.2 > threshold)).finish() + } +}*/ + +pub trait Octavable { + fn get_octave(&self, octave: i32) -> Note; +} + +impl Octavable for BaseNote { + fn get_octave(&self, octave: i32) -> Note { + let offset = self.1 + ((12i32 * octave) as f64); + let low_offset = offset - 0.5; + let high_offset = offset + 0.5; + match octave { + 0 => Note { + note: *self, + low_freq: calc_freq_from_offset(self.1 - 0.5), + freq: calc_freq_from_offset(self.1), + high_freq: calc_freq_from_offset(self.1 + 0.5), + octave: 0//, value: 0. + }, + _ => Note { + note: *self, + low_freq: calc_freq_from_offset(low_offset), + freq: calc_freq_from_offset(offset), + high_freq: calc_freq_from_offset(high_offset), + octave: octave//, value: 0. + } + } + } +} + +// start and end should be tuples of (Note, octave) +pub fn note_range(start: (Notes, i32), end: (Notes, i32)) -> Vec<Note> { + let mut ret = Vec::with_capacity((end.1+3 - start.1) as usize *12); + let mut started: bool = false; + let start_note = start.0; + let (end_note, mut end_octave) = end; + end_octave += 2; + for octave in (start.1)..=end_octave { + for bnote in NOTE_MA_OFFSETS { + match (started, bnote.0, octave) { + (false, cur_note, _) if cur_note == start_note => { started = true; ret.push(bnote.get_octave(octave)) }, + (true, cur_note, _) if cur_note == end_note && octave == end_octave => { ret.push(bnote.get_octave(octave)); return ret; }, + (true, _, _) => { ret.push(bnote.get_octave(octave)) }, + (_, _, _) => {}, + } + } + } + return ret; +} + +/*impl Octavable for Note { + fn get_octave(&self, octave: i32) -> Self { + match octave { + 0 => Note {freq: self.note.1, octave: 0, value: 0., ..*self}, + _ => Note {freq: self.note.1 * ((1 << octave) as f64), octave: octave, value: 0., ..*self} + } + } +}*/ + |