Mozzi  version v2.0
sound synthesis library for Arduino
mozzi_midi.h
1 /*
2  * mozzi_midi.h
3  *
4  * This file is part of Mozzi.
5  *
6  * Copyright 2012-2024 Tim Barrass and the Mozzi Team
7  *
8  * Mozzi is licensed under the GNU Lesser General Public Licence (LGPL) Version 2.1 or later.
9  *
10  */
11 
12 #ifndef MOZZI_MIDI_H_
13 #define MOZZI_MIDI_H_
14 
15 #include "mozzi_fixmath.h"
16 #include "FixMath.h"
17 
18 #include "mozzi_pgmspace.h"
19 
20 /** @brief Internal. Do not use in your sketches.
21 
22 Internal helper class. Not intended for use in your sketches, and details may change without notic. */
24 private:
25  friend int mtof(uint8_t);
26  friend int mtof(int);
27  friend Q16n16 Q16n16_mtof(Q16n16);
28  template<int8_t NI, uint64_t RANGE>
29  friend UFix<16,16> mtof(UFix<NI,0,RANGE>);
30 
31  template<int8_t NI, uint64_t RANGE>
32  friend UFix<16,16> mtof(SFix<NI,0,RANGE>);
33 
35 };
36 
37 
38 CONSTTABLE_STORAGE(uint32_t) MidiToFreqPrivate::midiToFreq[128] =
39  {
40  0, 567670, 601425, 637188, 675077, 715219, 757748, 802806, 850544, 901120,
41  954703, 1011473, 1071618, 1135340, 1202851, 1274376, 1350154, 1430438, 1515497,
42  1605613, 1701088, 1802240, 1909406, 2022946, 2143236, 2270680, 2405702, 2548752,
43  2700309, 2860877, 3030994, 3211226, 3402176, 3604479, 3818813, 4045892, 4286472,
44  4541359, 4811404, 5097504, 5400618, 5721756, 6061988, 6422452, 6804352, 7208959,
45  7637627, 8091785, 8572945, 9082719, 9622808, 10195009, 10801235, 11443507,
46  12123974, 12844905, 13608704, 14417917, 15275252, 16183563, 17145888, 18165438,
47  19245616, 20390018, 21602470, 22887014, 24247948, 25689810, 27217408, 28835834,
48  30550514, 32367136, 34291776, 36330876, 38491212, 40780036, 43204940, 45774028,
49  48495912, 51379620, 54434816, 57671668, 61101028, 64734272, 68583552, 72661752,
50  76982424, 81560072, 86409880, 91548056, 96991792, 102759240, 108869632,
51  115343336, 122202056, 129468544, 137167104, 145323504, 153964848, 163120144,
52  172819760, 183096224, 193983648, 205518336, 217739200, 230686576, 244403840,
53  258937008, 274334112, 290647008, 307929696, 326240288, 345639520, 366192448,
54  387967040, 411036672, 435478400, 461373152, 488807680, 517874016, 548668224,
55  581294016, 615859392, 652480576, 691279040, 732384896, 775934592, 822073344
56  };
57 
58 
59 /** @defgroup midi Midi note number to frequency conversions
60 
61 Useful if you like playing notes in tune.
62 */
63 
64 /** @ingroup midi
65 Converts midi note number to frequency. Caution: this can take up to 400
66 microseconds to run. It can seriously mess up the audio output if you use it in
67 updateControl() or updateAudio(). This is a good choice in setup(), or where you
68 need precise midi-pitch conversion and aren't doing much other audio
69 calculation.
70 @note Beware this returns an invalid result for midi note 0.
71 @note Timing: ~350 us
72 @param midival a midi note number, 1.0 or greater. Like the mtof object in Pd, midi values can have fractions.
73 @return the frequency represented by the input midi note number..
74  */
75 inline float mtof(float midival)
76 {
77  // http://en.wikipedia.org/wiki/Note
78  // f = pow(2,(p-69/12) * 440Hz
79  // return pow(2.0,(midival-69.0/12.0) * 440.0;
80 
81  // code from AF_precision_synthesis sketch, copyright 2009, Adrian Freed.
82  float f = 0.0;
83  if(midival) f = 8.1757989156 * pow(2.0, midival/12.0);
84  return f;
85 };
86 
87 
88 /** @ingroup midi
89 A good choice if you're using whole note values, want speed and simplicity, and accuracy isn't important.
90 @param midi_note a midi note number.
91 @return an integer approximation of the midi note's frequency.
92 */
93 inline int mtof(uint8_t midi_note){
94  return (FLASH_OR_RAM_READ<const uint32_t>(MidiToFreqPrivate::midiToFreq + midi_note) >> 16);
95 };
96 
97 /** @ingroup midi
98 A good choice if you're using whole note values, want speed and simplicity, and accuracy isn't important.
99 @param midi_note a midi note number.
100 @return an integer approximation of the midi note's frequency.
101 */
102 inline int mtof(int midi_note){
103  return (FLASH_OR_RAM_READ<const uint32_t>(MidiToFreqPrivate::midiToFreq + midi_note) >> 16);
104 };
105 
106 
107 /** @ingroup midi
108 Converts midi note number to frequency with speed and accuracy. Q16n16_mtofLookup() is a fast
109 alternative to (float) mtof(), and more accurate than (uint8_t) mtof(),
110 using Q16n16 fixed-point format instead of floats or uint8_t values. Q16n16_mtof()
111 uses cheap linear interpolation between whole midi-note frequency equivalents
112 stored in a lookup table, so is less accurate than the float version, mtof(),
113 for non-whole midi values.
114 @note Timing: ~8 us.
115 @param midival_fractional a midi note number in Q16n16 format, for fractional values.
116 @return the frequency represented by the input midi note number, in Q16n16
117 fixed point fractional integer format, where the lower word is a fractional value.
118 */
119 inline Q16n16 Q16n16_mtof(Q16n16 midival_fractional)
120 {
121  Q16n16 diff_fraction;
122  uint8_t index = midival_fractional >> 16;
123  uint16_t fraction = (uint16_t) midival_fractional; // keeps low word
124  Q16n16 freq1 = (Q16n16) FLASH_OR_RAM_READ<const uint32_t>(MidiToFreqPrivate::midiToFreq + index);
125  Q16n16 freq2 = (Q16n16) FLASH_OR_RAM_READ<const uint32_t>((MidiToFreqPrivate::midiToFreq + 1) + index);
126  Q16n16 difference = freq2 - freq1;
127  if (difference>=65536)
128  {
129  diff_fraction = ((difference>>8) * fraction) >> 8;
130  }
131  else
132  {
133  diff_fraction = (difference * fraction) >> 16;
134  }
135  return (Q16n16) (freq1+ diff_fraction);
136 };
137 
138 /** @ingroup midi
139 Converts midi note number with speed and accuracy from a UFix<16,16>.
140 Uses Q16n16_mtof internally.
141 */
142 template <uint64_t RANGE>
143 inline UFix<16,16> mtof(UFix<16,16,RANGE> midival)
144 {
145  return UFix<16,16>::fromRaw(Q16n16_mtof(midival.asRaw()));
146 };
147 
148 /** @ingroup midi
149 Converts midi note number with speed and accuracy from any UFix.
150 Uses Q16n16_mtof internally.
151 */
152 template<int8_t NI, int8_t NF, uint64_t RANGE>
153 inline UFix<16,16> mtof(UFix<NI,NF,RANGE> midival)
154 {
155  return UFix<16,16>::fromRaw(Q16n16_mtof(UFix<16,16>(midival).asRaw()));
156 };
157 
158 /** @ingroup midi
159 Converts midi note number with speed and accuracy from any SFix.
160 Uses Q16n16_mtof internally.
161 */
162 template<int8_t NI, int8_t NF, uint64_t RANGE>
163 inline UFix<16,16> mtof(SFix<NI,NF,RANGE> midival)
164 {
165  return UFix<16,16>::fromRaw(Q16n16_mtof(UFix<16,16>(midival).asRaw()));
166 };
167 
168 /** @ingroup midi
169 Converts *whole* midi note number with speed and accuracy (more accurate that mtof(uint8_t))
170 */
171 template<int8_t NI, uint64_t RANGE>
172 inline UFix<16,16> mtof(UFix<NI,0,RANGE> midival)
173 {
174  return UFix<16,16>::fromRaw((FLASH_OR_RAM_READ<const uint32_t>(MidiToFreqPrivate::midiToFreq + midival.asRaw())));
175 };
176 
177 /** @ingroup midi
178 Converts *whole* midi note number with speed and accuracy (more accurate that mtof(uint8_t))
179 */
180 template<int8_t NI, uint64_t RANGE>
181 inline UFix<16,16> mtof(SFix<NI,0,RANGE> midival)
182 {
183  return UFix<16,16>::fromRaw((FLASH_OR_RAM_READ<const uint32_t>(MidiToFreqPrivate::midiToFreq + midival.asUFix().asRaw())));
184 };
185 
186 #endif /* MOZZI_MIDI_H_ */