Skip to content

Commit 03354d3

Browse files
committed
Optimize to_freq_f* functions
1 parent e1be1b0 commit 03354d3

1 file changed

Lines changed: 308 additions & 8 deletions

File tree

src/note.rs

Lines changed: 308 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,272 @@ use crate::Error;
22
use core::convert::TryFrom;
33
use core::fmt;
44

5+
/// Precomputed frequencies (Hz) for all 128 MIDI notes using standard A440 tuning.
6+
/// Formula: 2^((n + 36.37631656229591) / 12)
7+
const FREQ_F64: [f64; 128] = [
8+
8.175798915643707e+00, // 0 CMinus1
9+
8.661957218027251e+00, // 1 DbMinus1
10+
9.177023997418985e+00, // 2 DMinus1
11+
9.722718241315027e+00, // 3 EbMinus1
12+
1.030086115352718e+01, // 4 EMinus1
13+
1.091338223228137e+01, // 5 FMinus1
14+
1.156232570973857e+01, // 6 GbMinus1
15+
1.224985737442966e+01, // 7 GMinus1
16+
1.297827179937328e+01, // 8 AbMinus1
17+
1.375000000000000e+01, // 9 AMinus1
18+
1.456761754744030e+01, // 10 BbMinus1
19+
1.543385316425388e+01, // 11 BMinus1
20+
1.635159783128741e+01, // 12 C0
21+
1.732391443605450e+01, // 13 Db0
22+
1.835404799483797e+01, // 14 D0
23+
1.944543648263005e+01, // 15 Eb0
24+
2.060172230705437e+01, // 16 E0
25+
2.182676446456274e+01, // 17 F0
26+
2.312465141947714e+01, // 18 Gb0
27+
2.449971474885933e+01, // 19 G0
28+
2.595654359874657e+01, // 20 Ab0
29+
2.749999999999999e+01, // 21 A0
30+
2.913523509488062e+01, // 22 Bb0
31+
3.086770632850775e+01, // 23 B0
32+
3.270319566257481e+01, // 24 C1
33+
3.464782887210901e+01, // 25 Db1
34+
3.670809598967594e+01, // 26 D1
35+
3.889087296526010e+01, // 27 Eb1
36+
4.120344461410874e+01, // 28 E1
37+
4.365352892912548e+01, // 29 F1
38+
4.624930283895428e+01, // 30 Gb1
39+
4.899942949771867e+01, // 31 G1
40+
5.191308719749313e+01, // 32 Ab1
41+
5.499999999999998e+01, // 33 A1
42+
5.827047018976124e+01, // 34 Bb1
43+
6.173541265701550e+01, // 35 B1
44+
6.540639132514963e+01, // 36 C2
45+
6.929565774421802e+01, // 37 Db2
46+
7.341619197935188e+01, // 38 D2
47+
7.778174593052020e+01, // 39 Eb2
48+
8.240688922821748e+01, // 40 E2
49+
8.730705785825096e+01, // 41 F2
50+
9.249860567790856e+01, // 42 Gb2
51+
9.799885899543733e+01, // 43 G2
52+
1.038261743949863e+02, // 44 Ab2
53+
1.100000000000000e+02, // 45 A2
54+
1.165409403795225e+02, // 46 Bb2
55+
1.234708253140310e+02, // 47 B2
56+
1.308127826502993e+02, // 48 C3
57+
1.385913154884360e+02, // 49 Db3
58+
1.468323839587038e+02, // 50 D3
59+
1.555634918610404e+02, // 51 Eb3
60+
1.648137784564350e+02, // 52 E3
61+
1.746141157165019e+02, // 53 F3
62+
1.849972113558171e+02, // 54 Gb3
63+
1.959977179908747e+02, // 55 G3
64+
2.076523487899725e+02, // 56 Ab3
65+
2.199999999999999e+02, // 57 A3
66+
2.330818807590450e+02, // 58 Bb3
67+
2.469416506280620e+02, // 59 B3
68+
2.616255653005987e+02, // 60 C4
69+
2.771826309768719e+02, // 61 Db4
70+
2.936647679174075e+02, // 62 D4
71+
3.111269837220810e+02, // 63 Eb4
72+
3.296275569128697e+02, // 64 E4
73+
3.492282314330038e+02, // 65 F4
74+
3.699944227116345e+02, // 66 Gb4
75+
3.919954359817490e+02, // 67 G4
76+
4.153046975799451e+02, // 68 Ab4
77+
4.400000000000001e+02, // 69 A4
78+
4.661637615180896e+02, // 70 Bb4
79+
4.938833012561240e+02, // 71 B4
80+
5.232511306011974e+02, // 72 C5
81+
5.543652619537438e+02, // 73 Db5
82+
5.873295358348150e+02, // 74 D5
83+
6.222539674441620e+02, // 75 Eb5
84+
6.592551138257395e+02, // 76 E5
85+
6.984564628660077e+02, // 77 F5
86+
7.399888454232689e+02, // 78 Gb5
87+
7.839908719634981e+02, // 79 G5
88+
8.306093951598901e+02, // 80 Ab5
89+
8.800000000000002e+02, // 81 A5
90+
9.323275230361793e+02, // 82 Bb5
91+
9.877666025122480e+02, // 83 B5
92+
1.046502261202395e+03, // 84 C6
93+
1.108730523907488e+03, // 85 Db6
94+
1.174659071669630e+03, // 86 D6
95+
1.244507934888324e+03, // 87 Eb6
96+
1.318510227651479e+03, // 88 E6
97+
1.396912925732015e+03, // 89 F6
98+
1.479977690846538e+03, // 90 Gb6
99+
1.567981743926996e+03, // 91 G6
100+
1.661218790319782e+03, // 92 Ab6
101+
1.760000000000000e+03, // 93 A6
102+
1.864655046072361e+03, // 94 Bb6
103+
1.975533205024499e+03, // 95 B6
104+
2.093004522404789e+03, // 96 C7
105+
2.217461047814978e+03, // 97 Db7
106+
2.349318143339263e+03, // 98 D7
107+
2.489015869776648e+03, // 99 Eb7
108+
2.637020455302961e+03, // 100 E7
109+
2.793825851464034e+03, // 101 F7
110+
2.959955381693076e+03, // 102 Gb7
111+
3.135963487853996e+03, // 103 G7
112+
3.322437580639565e+03, // 104 Ab7
113+
3.520000000000001e+03, // 105 A7
114+
3.729310092144722e+03, // 106 Bb7
115+
3.951066410048997e+03, // 107 B7
116+
4.186009044809579e+03, // 108 C8
117+
4.434922095629956e+03, // 109 Db8
118+
4.698636286678526e+03, // 110 D8
119+
4.978031739553296e+03, // 111 Eb8
120+
5.274040910605922e+03, // 112 E8
121+
5.587651702928068e+03, // 113 F8
122+
5.919910763386151e+03, // 114 Gb8
123+
6.271926975707993e+03, // 115 G8
124+
6.644875161279129e+03, // 116 Ab8
125+
7.040000000000002e+03, // 117 A8
126+
7.458620184289443e+03, // 118 Bb8
127+
7.902132820097994e+03, // 119 B8
128+
8.372018089619158e+03, // 120 C9
129+
8.869844191259912e+03, // 121 Db9
130+
9.397272573357051e+03, // 122 D9
131+
9.956063479106591e+03, // 123 Eb9
132+
1.054808182121184e+04, // 124 E9
133+
1.117530340585614e+04, // 125 F9
134+
1.183982152677230e+04, // 126 Gb9
135+
1.254385395141599e+04, // 127 G9
136+
];
137+
138+
/// Precomputed frequencies (Hz) for all 128 MIDI notes using standard A440 tuning.
139+
/// Formula: 2^((n + 36.376316) / 12)
140+
const FREQ_F32: [f32; 128] = [
141+
8.1757987e+00_f32, // 0 CMinus1
142+
8.6619569e+00_f32, // 1 DbMinus1
143+
9.1770237e+00_f32, // 2 DMinus1
144+
9.7227179e+00_f32, // 3 EbMinus1
145+
1.0300861e+01_f32, // 4 EMinus1
146+
1.0913382e+01_f32, // 5 FMinus1
147+
1.1562325e+01_f32, // 6 GbMinus1
148+
1.2249857e+01_f32, // 7 GMinus1
149+
1.2978271e+01_f32, // 8 AbMinus1
150+
1.3750000e+01_f32, // 9 AMinus1
151+
1.4567617e+01_f32, // 10 BbMinus1
152+
1.5433853e+01_f32, // 11 BMinus1
153+
1.6351597e+01_f32, // 12 C0
154+
1.7323914e+01_f32, // 13 Db0
155+
1.8354047e+01_f32, // 14 D0
156+
1.9445436e+01_f32, // 15 Eb0
157+
2.0601722e+01_f32, // 16 E0
158+
2.1826764e+01_f32, // 17 F0
159+
2.3124651e+01_f32, // 18 Gb0
160+
2.4499714e+01_f32, // 19 G0
161+
2.5956543e+01_f32, // 20 Ab0
162+
2.7499999e+01_f32, // 21 A0
163+
2.9135234e+01_f32, // 22 Bb0
164+
3.0867705e+01_f32, // 23 B0
165+
3.2703195e+01_f32, // 24 C1
166+
3.4647828e+01_f32, // 25 Db1
167+
3.6708095e+01_f32, // 26 D1
168+
3.8890872e+01_f32, // 27 Eb1
169+
4.1203443e+01_f32, // 28 E1
170+
4.3653528e+01_f32, // 29 F1
171+
4.6249301e+01_f32, // 30 Gb1
172+
4.8999428e+01_f32, // 31 G1
173+
5.1913086e+01_f32, // 32 Ab1
174+
5.4999998e+01_f32, // 33 A1
175+
5.8270468e+01_f32, // 34 Bb1
176+
6.1735411e+01_f32, // 35 B1
177+
6.5406389e+01_f32, // 36 C2
178+
6.9295655e+01_f32, // 37 Db2
179+
7.3416190e+01_f32, // 38 D2
180+
7.7781743e+01_f32, // 39 Eb2
181+
8.2406887e+01_f32, // 40 E2
182+
8.7307055e+01_f32, // 41 F2
183+
9.2498603e+01_f32, // 42 Gb2
184+
9.7998856e+01_f32, // 43 G2
185+
1.0382617e+02_f32, // 44 Ab2
186+
1.1000000e+02_f32, // 45 A2
187+
1.1654094e+02_f32, // 46 Bb2
188+
1.2347082e+02_f32, // 47 B2
189+
1.3081278e+02_f32, // 48 C3
190+
1.3859131e+02_f32, // 49 Db3
191+
1.4683238e+02_f32, // 50 D3
192+
1.5556349e+02_f32, // 51 Eb3
193+
1.6481377e+02_f32, // 52 E3
194+
1.7461411e+02_f32, // 53 F3
195+
1.8499721e+02_f32, // 54 Gb3
196+
1.9599771e+02_f32, // 55 G3
197+
2.0765234e+02_f32, // 56 Ab3
198+
2.1999999e+02_f32, // 57 A3
199+
2.3308187e+02_f32, // 58 Bb3
200+
2.4694164e+02_f32, // 59 B3
201+
2.6162556e+02_f32, // 60 C4
202+
2.7718262e+02_f32, // 61 Db4
203+
2.9366476e+02_f32, // 62 D4
204+
3.1112697e+02_f32, // 63 Eb4
205+
3.2962755e+02_f32, // 64 E4
206+
3.4922822e+02_f32, // 65 F4
207+
3.6999441e+02_f32, // 66 Gb4
208+
3.9199542e+02_f32, // 67 G4
209+
4.1530468e+02_f32, // 68 Ab4
210+
4.3999999e+02_f32, // 69 A4
211+
4.6616375e+02_f32, // 70 Bb4
212+
4.9388329e+02_f32, // 71 B4
213+
5.2325111e+02_f32, // 72 C5
214+
5.5436524e+02_f32, // 73 Db5
215+
5.8732952e+02_f32, // 74 D5
216+
6.2225395e+02_f32, // 75 Eb5
217+
6.5925509e+02_f32, // 76 E5
218+
6.9845644e+02_f32, // 77 F5
219+
7.3998882e+02_f32, // 78 Gb5
220+
7.8399085e+02_f32, // 79 G5
221+
8.3060937e+02_f32, // 80 Ab5
222+
8.7999997e+02_f32, // 81 A5
223+
9.3232749e+02_f32, // 82 Bb5
224+
9.8776657e+02_f32, // 83 B5
225+
1.0465022e+03_f32, // 84 C6
226+
1.1087305e+03_f32, // 85 Db6
227+
1.1746590e+03_f32, // 86 D6
228+
1.2445079e+03_f32, // 87 Eb6
229+
1.3185102e+03_f32, // 88 E6
230+
1.3969129e+03_f32, // 89 F6
231+
1.4799776e+03_f32, // 90 Gb6
232+
1.5679817e+03_f32, // 91 G6
233+
1.6612187e+03_f32, // 92 Ab6
234+
1.7599999e+03_f32, // 93 A6
235+
1.8646550e+03_f32, // 94 Bb6
236+
1.9755331e+03_f32, // 95 B6
237+
2.0930045e+03_f32, // 96 C7
238+
2.2174610e+03_f32, // 97 Db7
239+
2.3493181e+03_f32, // 98 D7
240+
2.4890158e+03_f32, // 99 Eb7
241+
2.6370204e+03_f32, // 100 E7
242+
2.7938258e+03_f32, // 101 F7
243+
2.9599553e+03_f32, // 102 Gb7
244+
3.1359634e+03_f32, // 103 G7
245+
3.3224375e+03_f32, // 104 Ab7
246+
3.5199999e+03_f32, // 105 A7
247+
3.7293100e+03_f32, // 106 Bb7
248+
3.9510663e+03_f32, // 107 B7
249+
4.1860089e+03_f32, // 108 C8
250+
4.4349220e+03_f32, // 109 Db8
251+
4.6986361e+03_f32, // 110 D8
252+
4.9780316e+03_f32, // 111 Eb8
253+
5.2740407e+03_f32, // 112 E8
254+
5.5876515e+03_f32, // 113 F8
255+
5.9199106e+03_f32, // 114 Gb8
256+
6.2719268e+03_f32, // 115 G8
257+
6.6448749e+03_f32, // 116 Ab8
258+
7.0399998e+03_f32, // 117 A8
259+
7.4586199e+03_f32, // 118 Bb8
260+
7.9021326e+03_f32, // 119 B8
261+
8.3720178e+03_f32, // 120 C9
262+
8.8698439e+03_f32, // 121 Db9
263+
9.3972723e+03_f32, // 122 D9
264+
9.9560632e+03_f32, // 123 Eb9
265+
1.0548081e+04_f32, // 124 E9
266+
1.1175303e+04_f32, // 125 F9
267+
1.1839821e+04_f32, // 126 Gb9
268+
1.2543854e+04_f32, // 127 G9
269+
];
270+
5271
/// A midi note.
6272
///
7273
/// The format for the enum is `$NOTE` `$MODIFIER?` `$OCTAVE`. Note can be a note from `A` to `G`.
@@ -242,11 +508,9 @@ impl Note {
242508
/// let note = wmidi::Note::A3;
243509
/// sing(note.to_freq_f32());
244510
/// ```
245-
#[cfg(feature = "std")]
246511
#[inline(always)]
247512
pub fn to_freq_f32(self) -> f32 {
248-
let exp = (f32::from(self as u8) + 36.376_316) / 12.0;
249-
2_f32.powf(exp)
513+
FREQ_F32[self as usize]
250514
}
251515

252516
/// The frequency using the standard 440Hz tuning.
@@ -257,11 +521,9 @@ impl Note {
257521
/// let note = wmidi::Note::A3;
258522
/// sing(note.to_freq_f64());
259523
/// ```
260-
#[cfg(feature = "std")]
261524
#[inline(always)]
262525
pub fn to_freq_f64(self) -> f64 {
263-
let exp = (f64::from(self as u8) + 36.376_316_562_295_91) / 12.0;
264-
2_f64.powf(exp)
526+
FREQ_F64[self as usize]
265527
}
266528

267529
/// Get the note relative to `self`.
@@ -484,12 +746,50 @@ mod test {
484746

485747
#[cfg(feature = "std")]
486748
#[test]
487-
fn note_to_frequency() {
749+
fn note_to_frequency_a440() {
488750
let a440_f64 = Note::A4.to_freq_f64();
489751
assert!((a440_f64 - 440.0).abs() < 1E-10, "{} != 440", a440_f64);
490752

491753
let a440_f32 = Note::A4.to_freq_f32();
492-
assert!((a440_f32 - 440.0).abs() < 1E-10, "{} != 440", a440_f32);
754+
assert!((a440_f32 - 440.0).abs() < 1E-3, "{} != 440", a440_f32);
755+
}
756+
757+
#[cfg(feature = "std")]
758+
#[test]
759+
fn note_to_frequency_f64() {
760+
for midi in 0u8..=127 {
761+
let note = Note::from_u8_lossy(midi);
762+
let expected = {
763+
let exp = (f64::from(midi) + 36.376_316_562_295_91) / 12.0;
764+
2.0_f64.powf(exp)
765+
};
766+
let got = note.to_freq_f64();
767+
let rel_err = (got - expected).abs() / expected;
768+
assert!(
769+
rel_err < 1e-4,
770+
"note={}: got {} expected {} rel_err={}",
771+
midi, got, expected, rel_err
772+
);
773+
}
774+
}
775+
776+
#[cfg(feature = "std")]
777+
#[test]
778+
fn note_to_frequency_f32() {
779+
for midi in 0u8..=127 {
780+
let note = Note::from_u8_lossy(midi);
781+
let expected = {
782+
let exp = (f32::from(midi) + 36.376_316_f32) / 12.0;
783+
2.0_f32.powf(exp)
784+
};
785+
let got = note.to_freq_f32();
786+
let rel_err = (got - expected).abs() / expected;
787+
assert!(
788+
rel_err < 1e-4,
789+
"note={}: got {} expected {} rel_err={}",
790+
midi, got, expected, rel_err
791+
);
792+
}
493793
}
494794

495795
#[test]

0 commit comments

Comments
 (0)