PitchConverter.java (6787B)
1 /* 2 * _______ _____ _____ _____ 3 * |__ __| | __ \ / ____| __ \ 4 * | | __ _ _ __ ___ ___ ___| | | | (___ | |__) | 5 * | |/ _` | '__/ __|/ _ \/ __| | | |\___ \| ___/ 6 * | | (_| | | \__ \ (_) \__ \ |__| |____) | | 7 * |_|\__,_|_| |___/\___/|___/_____/|_____/|_| 8 * 9 * ------------------------------------------------------------- 10 * 11 * TarsosDSP is developed by Joren Six at IPEM, University Ghent 12 * 13 * ------------------------------------------------------------- 14 * 15 * Info: http://0110.be/tag/TarsosDSP 16 * Github: https://github.com/JorenSix/TarsosDSP 17 * Releases: http://0110.be/releases/TarsosDSP/ 18 * 19 * TarsosDSP includes modified source code by various authors, 20 * for credits and info, see README. 21 * 22 */ 23 24 25 package be.tarsos.dsp.util; 26 27 28 /** 29 * Converts pitch from one unit to another (and back (and back (and back ...))). 30 * 31 * @author Joren Six 32 */ 33 public final class PitchConverter { 34 35 /** 36 * Hide the default constructor. 37 */ 38 private PitchConverter() { 39 } 40 41 /** 42 * C-1 = 16.35 / 2 Hz. 43 */ 44 private static final double REF_FREQ = 8.17579892; 45 46 /** 47 * Cache LOG 2 calculation. 48 */ 49 private static final double LOG_TWO = Math.log(2.0); 50 51 /** 52 * A MIDI key is an integer between 0 and 127, inclusive. Within a certain 53 * range every pitch is mapped to a MIDI key. If a value outside the range 54 * is given an IllegalArugmentException is thrown. 55 * 56 * @param hertzValue 57 * The pitch in Hertz. 58 * @return An integer representing the closest midi key. 59 * @exception IllegalArgumentException 60 * if the hertzValue does not fall within the range of valid 61 * MIDI key frequencies. 62 */ 63 public static int hertzToMidiKey(final Double hertzValue) { 64 final int midiKey = (int) Math.round(hertzToMidiCent(hertzValue)); 65 if (midiKey < 0 || midiKey > 127) { 66 // TODO 67 // LOG.warning("MIDI is only defined between [" + midiKeyToHertz(0) 68 // + "," 69 // + midiKeyToHertz(127) + "] " + hertzValue + 70 // "does not map to a MIDI key."); 71 } 72 return midiKey; 73 } 74 75 /** 76 * Calculates the frequency (Hz) for a MIDI key. 77 * 78 * @param midiKey 79 * The MIDI key. A MIDI key is an integer between 0 and 127, 80 * inclusive. 81 * @return A frequency in Hz corresponding to the MIDI key. 82 * @exception IllegalArgumentException 83 * If midiKey is not in the valid range between 0 and 127, 84 * inclusive. 85 */ 86 public static double midiKeyToHertz(final int midiKey) { 87 if (midiKey < 0 || midiKey > 127) { 88 throw new IllegalArgumentException("MIDI keys are values from 0 to 127, inclusive " + midiKey 89 + " is invalid."); 90 } 91 return midiCentToHertz(midiKey); 92 } 93 94 /** 95 * Converts a Hertz value to relative cents. E.g. 440Hz is converted to 900 96 * if the reference is a C. 97 * 98 * @param hertzValue 99 * A value in hertz. 100 * @return A value in relative cents. 101 */ 102 public static double hertzToRelativeCent(final double hertzValue) { 103 double absoluteCentValue = hertzToAbsoluteCent(hertzValue); 104 // make absoluteCentValue positive. E.g. -2410 => 1210 105 if (absoluteCentValue < 0) { 106 absoluteCentValue = Math.abs(1200 + absoluteCentValue); 107 } 108 // so it can be folded to one octave. E.g. 1210 => 10 109 return absoluteCentValue % 1200.0; 110 } 111 112 /** 113 * This method is not really practical. Maybe I will need it someday. 114 * 115 * @param relativeCent 116 * @return public static double relativeCentToHertz(double relativeCent){ if 117 * (relativeCent < 0 || relativeCent >= 1200) throw new 118 * IllegalArgumentException 119 * ("Relative cent values are values from 0 to 1199, inclusive " + 120 * relativeCent + " is invalid."); int defaultOctave = 5; int offset 121 * = defaultOctave * 1200; return absoluteCentToHertz(relativeCent + 122 * offset); } 123 */ 124 125 /** 126 * The reference frequency is configured. The default reference frequency is 127 * 16.35Hz. This is C0 on a piano keyboard with A4 tuned to 440 Hz. This 128 * means that 0 cents is C0; 1200 is C1; 2400 is C2; ... also -1200 cents is 129 * C-1 130 * 131 * @param hertzValue 132 * The pitch in Hertz. 133 * @return The value in absolute cents using the configured reference 134 * frequency 135 */ 136 public static double hertzToAbsoluteCent(final double hertzValue) { 137 double pitchInAbsCent = 0.0; 138 if (hertzValue > 0) { 139 pitchInAbsCent = 1200 * Math.log(hertzValue / REF_FREQ) / LOG_TWO; 140 } else { 141 throw new IllegalArgumentException("Pitch in Hz schould be greater than zero, is " + hertzValue); 142 } 143 return pitchInAbsCent; 144 } 145 146 /** 147 * Returns the frequency (Hz) of an absolute cent value. This calculation 148 * uses a configured reference frequency. 149 * 150 * @param absoluteCent 151 * The pitch in absolute cent. 152 * @return A pitch in Hz. 153 */ 154 public static double absoluteCentToHertz(final double absoluteCent) { 155 return REF_FREQ * Math.pow(2, absoluteCent / 1200.0); 156 } 157 158 /** 159 * Converts a frequency in Hz to a MIDI CENT value using 160 * <code>(12 * log2 (f / 440)) + 69</code> <br> 161 * E.g.<br> 162 * <code>69.168 MIDI CENTS = MIDI NOTE 69 + 16,8 cents</code><br> 163 * <code>69.168 MIDI CENTS = 440Hz + x Hz</code> 164 * 165 * @param hertzValue 166 * The pitch in Hertz. 167 * @return The pitch in MIDI cent. 168 */ 169 public static double hertzToMidiCent(final double hertzValue) { 170 double pitchInMidiCent = 0.0; 171 if (hertzValue != 0) { 172 pitchInMidiCent = 12 * Math.log(hertzValue / 440) / LOG_TWO + 69; 173 } 174 return pitchInMidiCent; 175 } 176 177 /** 178 * Converts a MIDI CENT frequency to a frequency in Hz. 179 * 180 * @param midiCent 181 * The pitch in MIDI CENT. 182 * @return The pitch in Hertz. 183 */ 184 public static double midiCentToHertz(final double midiCent) { 185 return 440 * Math.pow(2, (midiCent - 69) / 12d); 186 } 187 188 /** 189 * Converts cent values to ratios. See 190 * "Ratios Make Cents: Conversions from ratios to cents and back again" in 191 * the book "Tuning Timbre Spectrum Scale" William A. Sethares. 192 * 193 * @param cent 194 * A cent value 195 * @return A ratio containing the same information. 196 */ 197 public static double centToRatio(final double cent) { 198 final double ratio; 199 ratio = Math.pow(10, Math.log10(2) * cent / 1200.0); 200 return ratio; 201 } 202 203 /** 204 * Converts a ratio to cents. 205 * "Ratios Make Cents: Conversions from ratios to cents and back again" in 206 * the book "Tuning Timbre Spectrum Scale" William A. Sethares 207 * 208 * @param ratio 209 * A cent value 210 * @return A ratio containing the same information. 211 */ 212 public static double ratioToCent(final double ratio) { 213 final double cent; 214 cent = 1200 / Math.log10(2) * Math.log10(ratio); 215 return cent; 216 } 217 }