summaryrefslogtreecommitdiff
path: root/src/notes.rs
diff options
context:
space:
mode:
authorWavy Harp <wavyharp@gmail.com>2023-05-07 23:04:53 -0600
committerKyle McFarland <tfkyle@gmail.com>2023-05-07 23:04:53 -0600
commit991849b32acf83dd14a5096540bb053d2572502a (patch)
tree279b59d75d4ad6081f5242cf77d843ae6b37fc3d /src/notes.rs
downloadrustynotes-master.zip
rustynotes-master.tar.gz
rustynotes-master.tar.bz2
initial importHEADmaster
currently everything is very tied to alsa and my system, for the moment you'll need to manually change the device names and maybe channels/period_size in src/main.rs, src/bin/smolguitar.rs and src/bin/loopbacker.rs, i'll fix that and add runtime period size/updater allocation soon, (and probably make a cpal backend as well so it can work on other platforms), but doing this initial commit to play around with stereo for now~
Diffstat (limited to 'src/notes.rs')
-rw-r--r--src/notes.rs168
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}
+ }
+ }
+}*/
+