use super::{Note, Octave, PitchClass, Steps};
use crate::types::interval::PerfectQuality::{Augmented, Diminished};
use crate::types::{Interval, Matrix, Tone};
use std::ops;
pub enum Tuning {
A4_432Hz = 0,
A4_434Hz = 1,
A4_436Hz = 2,
A4_438Hz = 3,
A4_440Hz = 4,
A4_442Hz = 5,
A4_444Hz = 6,
A4_446Hz = 7,
}
#[derive(Copy, Clone, Debug, Hash, PartialEq)]
pub struct Pitch(u8);
impl Pitch {
pub(crate) const fn from_index(index: u8) -> Pitch {
Pitch(index)
}
pub(crate) const fn to_index(&self) -> u8 {
self.0
}
pub fn note(&self) -> Note {
Matrix::natural(&self.pitch_class(), &self.pitch_class().group())
.unwrap()
}
pub fn tone(&self) -> Tone {
Tone::from_parts(self.octave(), self.note())
}
pub fn names(&self) -> &'static [Note] {
self.pitch_class().names()
}
pub fn pitch_class(&self) -> PitchClass {
PitchClass::from_index(self.0 % 12)
}
pub fn octave(&self) -> Octave {
Octave::from_index(self.0 / 12).unwrap()
}
pub fn distance(&self, other: &Pitch) -> Steps {
let l = self.to_index() as u16;
let r = other.to_index() as u16;
Steps::from(if r > l { r - l } else { l - r })
}
pub fn frequency(&self, tuning: Tuning) -> f32 {
FREQUENCIES[self.0 as usize][tuning as usize]
}
}
impl From<u8> for Pitch {
fn from(index: u8) -> Pitch {
Pitch(index)
}
}
impl ops::Add<Interval> for Pitch {
type Output = Option<Self>;
fn add(self, interval: Interval) -> Self::Output {
if interval == Interval::First(Diminished) {
self - Steps::from(1)
} else {
self + interval.steps()
}
}
}
impl ops::Add<Steps> for Pitch {
type Output = Option<Self>;
fn add(self, steps: Steps) -> Self::Output {
let new_pitch_index = self.to_index() as i32 + steps.value() as i32;
if 0 <= new_pitch_index && new_pitch_index < 144 {
Some(Pitch::from_index(new_pitch_index as u8))
} else {
None
}
}
}
impl std::ops::Sub<Interval> for Pitch {
type Output = Option<Self>;
fn sub(self, interval: Interval) -> Self::Output {
if interval == Interval::First(Diminished) {
self + Steps::from(1)
} else {
self - interval.steps()
}
}
}
impl std::ops::Sub<Steps> for Pitch {
type Output = Option<Self>;
fn sub(self, steps: Steps) -> Self::Output {
let new_pitch_index = self.to_index() as i32 - steps.value() as i32;
if 0 <= new_pitch_index && new_pitch_index < 144 {
Some(Pitch::from_index(new_pitch_index as u8))
} else {
None
}
}
}
#[test]
fn test_addition() {
use crate::types::{
Accidental, Interval, MajorQuality, Note, Octave, PerfectQuality, Tone,
};
fn test(pitch: Pitch, steps: Steps, expect: Option<Pitch>) {
let result = pitch + steps;
assert_eq!(
result, expect,
"{:?} + {} = {:?} Expected: {:?}",
pitch, steps, result, expect
);
}
test(
Pitch::from_index(69),
Steps::from(13),
Some(Pitch::from_index(82)),
);
test(
Pitch::from_index(69),
Steps::from(0),
Some(Pitch::from_index(69)),
);
test(Pitch::from_index(140), Steps::from(10), None);
}
#[cfg(test)]
mod tests {
use super::{Interval, Pitch};
#[test]
fn test_subtraction() {
use crate::types::{Accidental, Interval, Note, Octave, Steps, Tone};
fn test(pitch: Pitch, steps: Steps, expect: Option<Pitch>) {
let result = pitch - steps;
assert_eq!(
result, expect,
"{:?} - {} = {:?} Expected: {:?}",
pitch, steps, result, expect
);
}
test(
Pitch::from_index(69),
Steps::from(0),
Some(Pitch::from_index(69)),
);
test(
Pitch::from_index(69),
Steps::from(20),
Some(Pitch::from_index(49)),
);
test(Pitch::from_index(29), Steps::from(30), None);
}
}
#[rustfmt::skip]
const FREQUENCIES: [[f32; 8]; 144] = [
[ 8.025, 8.065, 8.100, 8.140, 8.175, 8.215, 8.250, 8.285],
[ 8.505, 8.545, 8.585, 8.625, 8.660, 8.700, 8.740, 8.780],
[ 9.010, 9.050, 9.095, 9.135, 9.175, 9.220, 9.260, 9.300],
[ 9.545, 9.590, 9.635, 9.680, 9.725, 9.765, 9.810, 9.855],
[ 10.115, 10.160, 10.205, 10.255, 10.300, 10.350, 10.395, 10.440],
[ 10.715, 10.765, 10.815, 10.865, 10.915, 10.965, 11.015, 11.060],
[ 11.350, 11.405, 11.455, 11.510, 11.560, 11.615, 11.665, 11.720],
[ 12.025, 12.085, 12.140, 12.195, 12.250, 12.305, 12.360, 12.415],
[ 12.740, 12.800, 12.860, 12.920, 12.980, 13.035, 13.095, 13.155],
[ 13.500, 13.560, 13.625, 13.690, 13.750, 13.810, 13.875, 13.940],
[ 14.305, 14.370, 14.435, 14.500, 14.570, 14.635, 14.700, 14.765],
[ 15.155, 15.225, 15.295, 15.365, 15.435, 15.505, 15.575, 15.645],
[ 16.050, 16.130, 16.200, 16.280, 16.350, 16.430, 16.500, 16.570],
[ 17.010, 17.090, 17.170, 17.250, 17.320, 17.400, 17.480, 17.560],
[ 18.020, 18.100, 18.190, 18.270, 18.350, 18.440, 18.520, 18.600],
[ 19.090, 19.180, 19.270, 19.360, 19.450, 19.530, 19.620, 19.710],
[ 20.230, 20.320, 20.410, 20.510, 20.600, 20.700, 20.790, 20.880],
[ 21.430, 21.530, 21.630, 21.730, 21.830, 21.930, 22.030, 22.120],
[ 22.700, 22.810, 22.910, 23.020, 23.120, 23.230, 23.330, 23.440],
[ 24.050, 24.170, 24.280, 24.390, 24.500, 24.610, 24.720, 24.830],
[ 25.480, 25.600, 25.720, 25.840, 25.960, 26.070, 26.190, 26.310],
[ 27.000, 27.120, 27.250, 27.380, 27.500, 27.620, 27.750, 27.880],
[ 28.610, 28.740, 28.870, 29.000, 29.140, 29.270, 29.400, 29.530],
[ 30.310, 30.450, 30.590, 30.730, 30.870, 31.010, 31.150, 31.290],
[ 32.110, 32.260, 32.410, 32.550, 32.700, 32.850, 33.000, 33.150],
[ 34.020, 34.180, 34.330, 34.490, 34.650, 34.810, 34.960, 35.120],
[ 36.040, 36.210, 36.370, 36.540, 36.710, 36.870, 37.040, 37.210],
[ 38.180, 38.360, 38.540, 38.710, 38.890, 39.070, 39.240, 39.420],
[ 40.450, 40.640, 40.830, 41.020, 41.200, 41.390, 41.580, 41.770],
[ 42.860, 43.060, 43.260, 43.460, 43.650, 43.850, 44.050, 44.250],
[ 45.410, 45.620, 45.830, 46.040, 46.250, 46.460, 46.670, 46.880],
[ 48.110, 48.330, 48.550, 48.780, 49.000, 49.220, 49.440, 49.670],
[ 50.970, 51.210, 51.440, 51.680, 51.910, 52.150, 52.390, 52.620],
[ 54.000, 54.250, 54.500, 54.750, 55.000, 55.250, 55.500, 55.750],
[ 57.210, 57.480, 57.740, 58.010, 58.270, 58.540, 58.800, 59.070],
[ 60.610, 60.890, 61.170, 61.450, 61.740, 62.020, 62.300, 62.580],
[ 64.220, 64.510, 64.810, 65.110, 65.410, 65.700, 66.000, 66.300],
[ 68.040, 68.350, 68.670, 68.980, 69.300, 69.610, 69.930, 70.240],
[ 72.080, 72.420, 72.750, 73.080, 73.420, 73.750, 74.080, 74.420],
[ 76.370, 76.720, 77.070, 77.430, 77.780, 78.140, 78.490, 78.840],
[ 80.910, 81.280, 81.660, 82.030, 82.410, 82.780, 83.160, 83.530],
[ 85.720, 86.120, 86.510, 86.910, 87.310, 87.700, 88.100, 88.500],
[ 90.820, 91.240, 91.660, 92.080, 92.500, 92.920, 93.340, 93.760],
[ 96.220, 96.660, 97.110, 97.550, 98.000, 98.440, 98.890, 99.340],
[ 101.940, 102.410, 102.880, 103.350, 103.830, 104.300, 104.770, 105.240],
[ 108.000, 108.500, 109.000, 109.500, 110.000, 110.500, 111.000, 111.500],
[ 114.420, 114.950, 115.480, 116.010, 116.540, 117.070, 117.600, 118.130],
[ 121.230, 121.790, 122.350, 122.910, 123.470, 124.030, 124.590, 125.150],
[ 128.430, 129.030, 129.620, 130.220, 130.810, 131.410, 132.000, 132.600],
[ 136.070, 136.700, 137.330, 137.960, 138.590, 139.220, 139.850, 140.480],
[ 144.160, 144.830, 145.500, 146.160, 146.830, 147.500, 148.170, 148.830],
[ 152.740, 153.440, 154.150, 154.860, 155.560, 156.270, 156.980, 157.680],
[ 161.820, 162.570, 163.320, 164.060, 164.810, 165.560, 166.310, 167.060],
[ 171.440, 172.230, 173.030, 173.820, 174.610, 175.410, 176.200, 177.000],
[ 181.630, 182.470, 183.320, 184.160, 185.000, 185.840, 186.680, 187.520],
[ 192.430, 193.320, 194.220, 195.110, 196.000, 196.890, 197.780, 198.670],
[ 203.880, 204.820, 205.760, 206.710, 207.650, 208.600, 209.540, 210.480],
[ 216.000, 217.000, 218.000, 219.000, 220.000, 221.000, 222.000, 223.000],
[ 228.840, 229.900, 230.960, 232.020, 233.080, 234.140, 235.200, 236.260],
[ 242.450, 243.570, 244.700, 245.820, 246.940, 248.060, 249.190, 250.310],
[ 256.870, 258.060, 259.250, 260.440, 261.630, 262.810, 264.000, 265.190],
[ 272.140, 273.400, 274.660, 275.920, 277.180, 278.440, 279.700, 280.960],
[ 288.330, 289.660, 290.990, 292.330, 293.660, 295.000, 296.330, 297.670],
[ 305.470, 306.880, 308.300, 309.710, 311.130, 312.540, 313.960, 315.370],
[ 323.630, 325.130, 326.630, 328.130, 329.630, 331.130, 332.620, 334.120],
[ 342.880, 344.470, 346.050, 347.640, 349.230, 350.820, 352.400, 353.990],
[ 363.270, 364.950, 366.630, 368.310, 369.990, 371.680, 373.360, 375.040],
[ 384.870, 386.650, 388.430, 390.210, 392.000, 393.780, 395.560, 397.340],
[ 407.750, 409.640, 411.530, 413.420, 415.300, 417.190, 419.080, 420.970],
[ 432.000, 434.000, 436.000, 438.000, 440.000, 442.000, 444.000, 446.000],
[ 457.690, 459.810, 461.930, 464.040, 466.160, 468.280, 470.400, 472.520],
[ 484.900, 487.150, 489.390, 491.640, 493.880, 496.130, 498.370, 500.620],
[ 513.740, 516.120, 518.490, 520.870, 523.250, 525.630, 528.010, 530.390],
[ 544.290, 546.810, 549.330, 551.850, 554.370, 556.880, 559.400, 561.920],
[ 576.650, 579.320, 581.990, 584.660, 587.330, 590.000, 592.670, 595.340],
[ 610.940, 613.770, 616.600, 619.430, 622.250, 625.080, 627.910, 630.740],
[ 647.270, 650.270, 653.260, 656.260, 659.250, 662.250, 665.250, 668.240],
[ 685.760, 688.930, 692.110, 695.280, 698.460, 701.630, 704.810, 707.980],
[ 726.530, 729.900, 733.260, 736.630, 739.990, 743.350, 746.720, 750.080],
[ 769.740, 773.300, 776.860, 780.430, 783.990, 787.550, 791.120, 794.680],
[ 815.510, 819.280, 823.060, 826.830, 830.610, 834.380, 838.160, 841.940],
[ 864.000, 868.000, 872.000, 876.000, 880.000, 884.000, 888.000, 892.000],
[ 915.380, 919.610, 923.850, 928.090, 932.330, 936.570, 940.800, 945.040],
[ 969.810, 974.300, 978.790, 983.280, 987.770, 992.260, 996.750, 1001.240],
[ 1027.470, 1032.230, 1036.990, 1041.740, 1046.500, 1051.260, 1056.020, 1060.770],
[ 1088.570, 1093.610, 1098.650, 1103.690, 1108.730, 1113.770, 1118.810, 1123.850],
[ 1153.300, 1158.640, 1163.980, 1169.320, 1174.660, 1180.000, 1185.340, 1190.680],
[ 1221.880, 1227.540, 1233.190, 1238.850, 1244.510, 1250.160, 1255.820, 1261.480],
[ 1294.540, 1300.530, 1306.520, 1312.520, 1318.510, 1324.500, 1330.500, 1336.490],
[ 1371.510, 1377.860, 1384.210, 1390.560, 1396.910, 1403.260, 1409.610, 1415.960],
[ 1453.070, 1459.800, 1466.520, 1473.250, 1479.980, 1486.700, 1493.430, 1500.160],
[ 1539.470, 1546.600, 1553.730, 1560.850, 1567.980, 1575.110, 1582.240, 1589.360],
[ 1631.010, 1638.570, 1646.120, 1653.670, 1661.220, 1668.770, 1676.320, 1683.870],
[ 1728.000, 1736.000, 1744.000, 1752.000, 1760.000, 1768.000, 1776.000, 1784.000],
[ 1830.750, 1839.230, 1847.700, 1856.180, 1864.660, 1873.130, 1881.610, 1890.080],
[ 1939.610, 1948.590, 1957.570, 1966.550, 1975.530, 1984.510, 1993.490, 2002.470],
[ 2054.950, 2064.460, 2073.980, 2083.490, 2093.000, 2102.520, 2112.030, 2121.540],
[ 2177.140, 2187.220, 2197.300, 2207.380, 2217.460, 2227.540, 2237.620, 2247.700],
[ 2306.600, 2317.280, 2327.960, 2338.640, 2349.320, 2360.000, 2370.670, 2381.350],
[ 2443.760, 2455.070, 2466.390, 2477.700, 2489.020, 2500.330, 2511.640, 2522.960],
[ 2589.070, 2601.060, 2613.050, 2625.030, 2637.020, 2649.010, 2660.990, 2672.980],
[ 2743.030, 2755.730, 2768.430, 2781.130, 2793.830, 2806.520, 2819.220, 2831.920],
[ 2906.140, 2919.590, 2933.050, 2946.500, 2959.960, 2973.410, 2986.860, 3000.320],
[ 3078.950, 3093.200, 3107.450, 3121.710, 3135.960, 3150.220, 3164.470, 3178.730],
[ 3262.030, 3277.130, 3292.230, 3307.340, 3322.440, 3337.540, 3352.640, 3367.740],
[ 3456.000, 3472.000, 3488.000, 3504.000, 3520.000, 3536.000, 3552.000, 3568.000],
[ 3661.500, 3678.460, 3695.410, 3712.360, 3729.310, 3746.260, 3763.210, 3780.160],
[ 3879.230, 3897.190, 3915.150, 3933.110, 3951.070, 3969.030, 3986.990, 4004.950],
[ 4109.900, 4128.930, 4147.950, 4166.980, 4186.010, 4205.030, 4224.060, 4243.090],
[ 4354.290, 4374.440, 4394.600, 4414.760, 4434.920, 4455.080, 4475.240, 4495.400],
[ 4613.210, 4634.560, 4655.920, 4677.280, 4698.630, 4719.990, 4741.350, 4762.710],
[ 4887.520, 4910.150, 4932.780, 4955.400, 4978.030, 5000.660, 5023.290, 5045.910],
[ 5178.150, 5202.120, 5226.090, 5250.070, 5274.040, 5298.010, 5321.990, 5345.960],
[ 5486.060, 5511.460, 5536.850, 5562.250, 5587.650, 5613.050, 5638.450, 5663.850],
[ 5812.280, 5839.180, 5866.090, 5893.000, 5919.910, 5946.820, 5973.730, 6000.640],
[ 6157.890, 6186.400, 6214.910, 6243.420, 6271.930, 6300.440, 6328.940, 6357.450],
[ 6524.060, 6554.260, 6584.470, 6614.670, 6644.880, 6675.080, 6705.280, 6735.490],
[ 6912.000, 6944.000, 6976.000, 7008.000, 7040.000, 7072.000, 7104.000, 7136.000],
[ 7323.010, 7356.910, 7390.810, 7424.720, 7458.620, 7492.520, 7526.430, 7560.330],
[ 7758.460, 7794.380, 7830.300, 7866.210, 7902.130, 7938.050, 7973.970, 8009.890],
[ 8219.800, 8257.860, 8295.900, 8333.960, 8372.020, 8410.060, 8448.120, 8486.180],
[ 8708.580, 8748.880, 8789.200, 8829.520, 8869.840, 8910.160, 8950.480, 8990.800],
[ 9226.420, 9269.120, 9311.840, 9354.560, 9397.260, 9439.980, 9482.700, 9525.420],
[ 9775.040, 9820.300, 9865.560, 9910.800, 9956.060, 10001.320, 10046.580, 10091.820],
[10356.300, 10404.240, 10452.180, 10500.140, 10548.080, 10596.020, 10643.980, 10691.920],
[10972.120, 11022.920, 11073.700, 11124.500, 11175.300, 11226.100, 11276.900, 11327.700],
[11624.560, 11678.360, 11732.180, 11786.000, 11839.820, 11893.640, 11947.460, 12001.280],
[12315.780, 12372.800, 12429.820, 12486.840, 12543.860, 12600.880, 12657.880, 12714.900],
[13048.120, 13108.520, 13168.940, 13229.340, 13289.760, 13350.160, 13410.560, 13470.980],
[13824.000, 13888.000, 13952.000, 14016.000, 14080.000, 14144.000, 14208.000, 14272.000],
[14646.020, 14713.820, 14781.620, 14849.440, 14917.240, 14985.040, 15052.860, 15120.660],
[15516.920, 15588.760, 15660.600, 15732.420, 15804.260, 15876.100, 15947.940, 16019.780],
[16439.600, 16515.720, 16591.800, 16667.920, 16744.040, 16820.120, 16896.240, 16972.360],
[17417.160, 17497.760, 17578.400, 17659.040, 17739.680, 17820.320, 17900.960, 17981.600],
[18452.840, 18538.240, 18623.680, 18709.120, 18794.520, 18879.960, 18965.400, 19050.840],
[19550.080, 19640.600, 19731.120, 19821.600, 19912.120, 20002.640, 20093.160, 20183.640],
[20712.600, 20808.480, 20904.360, 21000.280, 21096.160, 21192.040, 21287.960, 21383.840],
[21944.240, 22045.840, 22147.400, 22249.000, 22350.600, 22452.200, 22553.800, 22655.400],
[23249.120, 23356.720, 23464.360, 23572.000, 23679.640, 23787.280, 23894.920, 24002.560],
[24631.560, 24745.600, 24859.640, 24973.680, 25087.720, 25201.760, 25315.760, 25429.800],
[26096.240, 26217.040, 26337.880, 26458.680, 26579.520, 26700.320, 26821.120, 26941.960],
[27648.000, 27776.000, 27904.000, 28032.000, 28160.000, 28288.000, 28416.000, 28544.000],
[29292.040, 29427.640, 29563.240, 29698.880, 29834.480, 29970.080, 30105.720, 30241.320],
[31033.840, 31177.520, 31321.200, 31464.840, 31608.520, 31752.200, 31895.880, 32039.560],
];