temperaments 1.0.2

Calculate frequency tables of a wide variety of musical temperaments and calculate cent offsets.
Documentation
use crate::{
    cent::Cent,
    pitch::{Pitch, PitchClass},
};

/// The number of cents each pitch class deviates from equal temperament. For equal temperament,
/// all values should be 0.
#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct OctaveOffsets {
    pub c: Cent,
    pub cs: Cent,
    pub d: Cent,
    pub eb: Cent,
    pub e: Cent,
    pub f: Cent,
    pub fs: Cent,
    pub g: Cent,
    pub ab: Cent,
    pub a: Cent,
    pub bb: Cent,
    pub b: Cent,
}

/// The number of cents each pitch class is above C. For example, in equal temperament, `d`
/// should equal 200.
#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct CentsTable {
    pub c: Cent,
    pub cs: Cent,
    pub d: Cent,
    pub eb: Cent,
    pub e: Cent,
    pub f: Cent,
    pub fs: Cent,
    pub g: Cent,
    pub ab: Cent,
    pub a: Cent,
    pub bb: Cent,
    pub b: Cent,
}

impl OctaveOffsets {
    /// Create an [`OctaveOffsets`] from a [`CentsTable`]
    pub fn new_from_cents_table(table: CentsTable) -> Self {
        Self {
            c: table.c,
            cs: table.cs - 100.0,
            d: table.d - 200.0,
            eb: table.eb - 300.0,
            e: table.e - 400.0,
            f: table.f - 500.0,
            fs: table.fs - 600.0,
            g: table.g - 700.0,
            ab: table.ab - 800.0,
            a: table.a - 900.0,
            bb: table.bb - 1000.0,
            b: table.b - 1100.0,
        }
    }

    /// Get the offset in cents for the given pitch.
    pub fn offset_for(&self, pitch: Pitch) -> Cent {
        match pitch.into() {
            PitchClass::A => self.a,
            PitchClass::Ab => self.ab,
            PitchClass::B => self.b,
            PitchClass::Bb => self.bb,
            PitchClass::C => self.c,
            PitchClass::Cs => self.cs,
            PitchClass::D => self.d,
            PitchClass::E => self.e,
            PitchClass::Eb => self.eb,
            PitchClass::F => self.f,
            PitchClass::Fs => self.fs,
            PitchClass::G => self.g,
        }
    }
}